Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can constructing an X509Certificate2 from a PKCS#12 byte array throw CryptographicException("The system cannot find the file specified.")?

I'm trying to construct an X509Certificate2 from a PKCS#12 blob in a byte array and getting a rather puzzling error. This code is running in a desktop application with administrator rights on Windows XP.

The stack trace is as follows, but I got lost trying to troubleshoot because _LoadCertFromBlob is marked [MethodImpl(MethodImplOptions.InternalCall)].

System.Security.Cryptography.CryptographicException: The system cannot find the file specified.   at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)   at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)   at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)   at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags) 

EDIT: The blob is a true PKCS#12 generated by BouncyCastle for C# containing a RSA private key and certificate (either self-signed or recently enrolled with a CA) -- what I'm trying to do is convert the private key and certificate from the BouncyCastle library to the System.Security.Cryptography library by exporting from one and importing to the other. This code works on the vast majority of systems it's been tried on; I've just never seen that particular error thrown from that constructor. It may be some sort of environmental weirdness on that one box.

EDIT 2: The error is occurring in a different environment in a different city, and I'm unable to reproduce it locally, so I may end up having to chalk it up to a broken XP installation.

Since you asked, though, here is the fragment in question. The code takes a private key and certificate in BouncyCastle representation, deletes any previous certificates for the same Distinguished Name from the personal key store, and imports the new private key and certificate into the personal key store via an intermediate PKCS#12 blob.

// open the personal keystore var msMyStore = new X509Store(StoreName.My); msMyStore.Open(OpenFlags.MaxAllowed);  // remove any certs previously issued for the same DN var oldCerts =     msMyStore.Certificates.Cast<X509Certificate2>()         .Where(c => X509Name                         .GetInstance(Asn1Object.FromByteArray(c.SubjectName.RawData))                         .Equivalent(CurrentCertificate.SubjectDN))         .ToArray(); if (oldCerts.Length > 0) msMyStore.RemoveRange(new X509Certificate2Collection(oldCerts));  // build a PKCS#12 blob from the private key and certificate var pkcs12store = new Pkcs12StoreBuilder().Build(); pkcs12store.SetKeyEntry(_Pkcs12KeyName,                         new AsymmetricKeyEntry(KeyPair.Private),                         new[] {new X509CertificateEntry(CurrentCertificate)}); var pkcs12data = new MemoryStream(); pkcs12store.Save(pkcs12data, _Pkcs12Password.ToCharArray(), Random);  // and import it.  this constructor call blows up _MyCertificate2 = new X509Certificate2(pkcs12data.ToArray(),                                        _Pkcs12Password,                                        X509KeyStorageFlags.Exportable); msMyStore.Add(_MyCertificate2); msMyStore.Close(); 
like image 563
Jeffrey Hantin Avatar asked Sep 29 '10 22:09

Jeffrey Hantin


People also ask

What is X509Certificate2?

X509Certificate2(String, String, X509KeyStorageFlags) Initializes a new instance of the X509Certificate2 class using a certificate file name, a password used to access the certificate, and a key storage flag. X509Certificate2(String, SecureString, X509KeyStorageFlags)

What is X509KeyStorageFlags?

Defines where and how to import the private key of an X.

What is X509Store?

X509Store(StoreLocation) Initializes a new instance of the X509Store class using the personal certificate store from the specified store location value. X509Store(StoreName) Initializes a new instance of the X509Store class using the specified store name from the current user's certificate stores.


2 Answers

Do you have PKCS#12 or just PFX-file? In the Microsoft world it is the same, but other think another (see this archived page).

You can try just following

X509Certificate2 cert = X509Certificate2(byte[] rawData, "password"); X509Certificate2 cert2 = X509Certificate2(byte[] rawData, "password",               X509KeyStorageFlags.MachineKeySet |               X509KeyStorageFlags.PersistKeySet |               X509KeyStorageFlags.Exportable); 

(X509Certificate2(Byte[])) or

X509Certificate2 cert = X509Certificate2("C:\Path\my.pfx", "password"); 

(see X509Certificate2(String, String) and Import(String, String, X509KeyStorageFlags) on Microsoft Docs if you need use some flags)

UPDATED: It would be helpful if you insert a code fragment and not only the exception stack trace.

Which X509KeyStorageFlags do you use? You can use Process Monitor to find out which file could not find the X509Certificate2 constructor. It can be for example that there are no default key container for the current user on the Windows XP having the problem. You can create it and retry the import.

like image 89
Oleg Avatar answered Sep 19 '22 03:09

Oleg


I ran into the same issue.

According to this old KB article the problem was that the constructor tries to load the cert into the current user's profile, but the .Net code I was impersonating the user and so it had not loaded the user profile. The constructor requires the loaded user profile to work properly.

From the article:

The X509Certificate2 class constructors attempt to import the certificate into the user profile of the user account that the application runs in. Many times, ASP.NET and COM+ applications impersonate clients. When they do, they do not load the user profiles for the impersonated user for performance reasons. So, they cannot access the "User" certificate store for the impersonated user.

Loading the user profile fixed the error.

like image 36
Zain Rizvi Avatar answered Sep 23 '22 03:09

Zain Rizvi