OPCFoundation / UA-.NETStandard-Samples

Other
245 stars 179 forks source link

CertificateFactory.CreateCertificateWithPrivateKey(newCert, OldCertificate) returns error in private key #606

Open sveinfolkeson opened 2 months ago

sveinfolkeson commented 2 months ago

Type of issue

Current Behavior

I am using GlobalDiscoveryServer and GlobalDiscoveryClient ver 1.4.374. When I create a Certificate for an UA Server everything seems to work well using new X509Certificate2(privateKeyPFX, string.Empty, X509KeyStorageFlags.Exportable);. When I try to recreate the certificate using CertificateFactory.CreateCertificateWithPrivateKey(newCert, oldCertificate); the property PrivateKey reports the exception 'newCert.PrivateKey' threw an exception of type 'System.Security.Cryptography.CryptographicException'

Expected Behavior

No response

Steps To Reproduce

Using the sample software from https://github.com/OPCFoundation/UA-.NETStandard-Samples ver 1.4.374:

  1. Start Global Discovery Server
  2. Start Global Discovery Client
  3. Remove any certificates from the Certificate Store LocalMachine/UA Applications
  4. Register and create a new certificate
  5. Click on the Create Certificate button once more to recreate the Certificate.

Environment

- OS: Win11
- Environment: Visual Studio 2022
- Runtime: .NET 4.8
- Nuget Version: 1.4.374
- Component: Opc.Ua
- Server: UA Global Discovery Server (https://github.com/OPCFoundation/UA-.NETStandard-Samples)
- Client: UA Global Discovery Agent (https://github.com/OPCFoundation/UA-.NETStandard-Samples)

Anything else?

No response

romanett commented 2 months ago

Please try again with the changes from #598 this may fix the issue, if not please inform us

sveinfolkeson commented 2 months ago

The problem with private key is still present. When I debug I can see that already when I create the certificate for the first time it seems to be OK when I watch it in the certificate store, but the statements:

                            newCert = new

X509Certificate2(privateKeyPFX, string.Empty, X509KeyStorageFlags.Exportable); newCert = CertificateFactory.Load(newCert, true);

Returns newCert with 'newCert.PrivateKey' threw an exception of type 'System.Security.Cryptography.CryptographicException'

man. 6. mai 2024 kl. 13:29 skrev romanett @.***>:

Please try again with the changes from #598 https://github.com/OPCFoundation/UA-.NETStandard-Samples/pull/598 this may fix the issue, if not please inform us

— Reply to this email directly, view it on GitHub https://github.com/OPCFoundation/UA-.NETStandard-Samples/issues/606#issuecomment-2095797011, or unsubscribe https://github.com/notifications/unsubscribe-auth/AE4LACV5YFQ6YYVNMYF2A5TZA5SRJAVCNFSM6AAAAABHI3K64OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAOJVG44TOMBRGE . You are receiving this because you authored the thread.Message ID: @.***>

-- Best regards / Vennlig hilsen Svein Folkeson

mobile +47 932 19905

romanett commented 2 months ago

@sveinfolkeson I can reproduce the issue when creating a certificate into a local X509 store. The first time it works the second time an Exception is thrown, when it tries to reuse the private Key.

Issue is the following: -> The key is marked as "non exportable"

This happens because the X509 Store implementation creates a copy of the Cert with Flag X509KeyStorageFlags.PersistKeySet

https://github.com/OPCFoundation/UA-.NETStandard/blob/663ed10285153955bc009e464fb35f162512aaa7/Stack/Opc.Ua.Core/Security/Certificates/X509CertificateStore.cs#L146

as a workaround just use a directory Certificate store

sveinfolkeson commented 2 months ago

Even though there is no exception thrown the first time i am pretty sure that the fact that when the certificate is created the first time it returns an invalid value in the certificates private key, and that this is the reason why the exception is thrown the second time when the renewal of the certificate, based on the certificate made the first time, is done. -SveinF

tir. 7. mai 2024 kl. 16:54 skrev romanett @.***>:

@sveinfolkeson https://github.com/sveinfolkeson I can reproduce the issue when creating a certificate into a local store. The first time it works the second time an Exception is thrown:

at System.Security.Cryptography.NCryptNative.ExportKey(SafeNCryptKeyHandle key, String format) at System.Security.Cryptography.CngKey.Export(CngKeyBlobFormat format) at System.Security.Cryptography.RSACng.ExportParameters(Boolean includePrivateParameters) at System.Security.Cryptography.X509Certificates.RSACertificateExtensions.CopyWithPrivateKey(X509Certificate2 certificate, RSA privateKey) ApplicationCertificateControl.cs:line 333.

— Reply to this email directly, view it on GitHub https://github.com/OPCFoundation/UA-.NETStandard-Samples/issues/606#issuecomment-2098602208, or unsubscribe https://github.com/notifications/unsubscribe-auth/AE4LACUVRM2DTITHLZQFDPDZBDTMFAVCNFSM6AAAAABHI3K64OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAOJYGYYDEMRQHA . You are receiving this because you were mentioned.Message ID: @.***>

-- Best regards / Vennlig hilsen Svein Folkeson

mobile +47 932 19905

romanett commented 2 months ago

@sveinfolkeson the certificate is created correctly with private key, but the private key is marked as "non exportable" however to get the old private key into the new cert created by the certificate signing request an export is needed, this fails however with X509stores in the current implementation. A workaround would be to use a diretory certificate store

at System.Security.Cryptography.NCryptNative.ExportKey(SafeNCryptKeyHandle key, String format) at System.Security.Cryptography.CngKey.Export(CngKeyBlobFormat format) at System.Security.Cryptography.RSACng.ExportParameters(Boolean includePrivateParameters) at System.Security.Cryptography.X509Certificates.RSACertificateExtensions.CopyWithPrivateKey(X509Certificate2 certificate, RSA privateKey) at Opc.Ua.Gds.Client.ApplicationCertificateControl.d__11.MoveNext() in C:\Users\roman\source\repos\romanett\UA-.NETStandard-Samples\Samples\GDS\Client\Controls\ApplicationCertificateControl.cs:line 333

sveinfolkeson commented 2 months ago

Ok, thanks. The workaround works so I will do that until the bug is fixed.

-SveinF

ons. 8. mai 2024, 16:48 skrev romanett @.***>:

@sveinfolkeson https://github.com/sveinfolkeson the certificate is created correctly with private key, but the private key is marked as "non exportable" however to get the old private key into the new cert created by the certificate signing request an export is needed, this fails however with X509stores in the current implementation. A workaround would be to use a diretory certificate store

at System.Security.Cryptography.NCryptNative.ExportKey(SafeNCryptKeyHandle key, String format) at System.Security.Cryptography.CngKey.Export(CngKeyBlobFormat format) at System.Security.Cryptography.RSACng.ExportParameters(Boolean includePrivateParameters) at System.Security.Cryptography.X509Certificates.RSACertificateExtensions.CopyWithPrivateKey(X509Certificate2 certificate, RSA privateKey) at Opc.Ua.Gds.Client.ApplicationCertificateControl.d__11.MoveNext() in C:\Users\roman\source\repos\romanett\UA-.NETStandard-Samples\Samples\GDS\Client\Controls\ApplicationCertificateControl.cs:line 333

— Reply to this email directly, view it on GitHub https://github.com/OPCFoundation/UA-.NETStandard-Samples/issues/606#issuecomment-2100763233, or unsubscribe https://github.com/notifications/unsubscribe-auth/AE4LACU5TXRYVYQDYEDM473ZBI3K3AVCNFSM6AAAAABHI3K64OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMBQG43DGMRTGM . You are receiving this because you were mentioned.Message ID: @.***>

sveinfolkeson commented 1 month ago

607 Fixes the problem, but I think it will be good practice to delete the old certificate before a new one is created to avoid ending up with more than one certificate in the store.