The X509Certificate2 method is used to load cryptography signatures most often in my experience taking the the form of a p12 file. Normally I just store this certificate in my project and then have the password for the file in a secret storage location like Azure secret store. However the admin at my Current client did not want the certificate on the file share. So his sugestion was that we export the certificate into a pem file.
PEM or Privacy Enhanced Mail is a Base64 encoded DER certificate. PEM certificates are frequently used for web servers as they can easily be translated into readable data using a simple text editor. Generally when a PEM encoded file is opened in a text editor, it contains very distinct headers and footers.
what is PEM format?
How NOT to load PEM with X509Certificate2.
When I normally load the p12 file it is done as follows. I pass it the path to the file followed by its password. I can also see that it is loading the private key.
// Load the cert as string
var certificate2 = new X509Certificate2(p12Export, certPassword,
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
var certHasPrivateKey = certificate2 .HasPrivateKey;
When i tried to do this same with the PEM file the result was a rather impressive error message.
System.IO.IOException: The read operation failed, see inner exception.
---> System.ComponentModel.Win32Exception (0x8009030E): No credentials are available in the security package
I tried everything and was able to get it to load partially by removing the headers and footers from the pem file
—–BEGIN CERTIFICATE REQUEST—–
When I ran my unit tests I found that my code did not work with this certificate that was being generated. I am using it to generate a kid value for a JWT. As follows:
var key = certificate.GetRSAPrivateKey();
var pubKeyBytes = key.ExportSubjectPublicKeyInfo();
After some extensive debugging I found the issue was with the private key. certificate2 .HasPrivateKey was returning false. Which meant that the PEM file was loading only part of the certificate and not the part I actually need.
How to really load a PEM X509Certificate2.
After more then a day of debugging searching online and wracking my brain. I finally did what I always do and asked a question on Stack Overflow Load X509Certificate2 using prem and not .p12. With in less then a day we had results.
A very kind developer shed some light on my issue. There is actually an extension method which allows for loading it from a pem file.
X509Certificate2.CreateFromPemFile(prem)
This method loads the PEM perfectly (almost). it now has the private key and I was able to create my kid.
Certificate with HTTPClient
One of the calls that I make to the gateway i am connecting to requires that a certificate be added to each call. This is how I normally do it using the P12 file.
var clientCertificate = new X509Certificate2(pathToP12File, password);
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(clientCertificate );
As before we load the path to the certificate and apply it to our client. However this resulted in a error from the gateway. It did not like this new certificate.
System.IO.IOException: The read operation failed, see inner exception.
---> System.ComponentModel.Win32Exception (0x8009030E): No credentials are available in the security package
Well back to the drawing board. I started looking for what could cause this error and it seamed to be unrelated to the pem file. So again another question on stack overflow Loading X509Certificate2 from pem file. Results in No credentials are available when used as a ClientCertificates. The same user answered this question as well, a bit of cyber stalking and I quickly found out the person answering my questions was a Developer at Microsoft working on the .net framework. What amazing luck to find him answering Stack overflow questions, I really think this is something every company should expect of their developers. Help others, and you help yourself.
He was able to tell me the exact issue, apparently the extension method just loads the first cert and thats not the one i need. The one needed by the gateway is the PFX cert.
var clientCertificate = X509Certificate2.CreateFromPemFile(purePrem); // load from pem
clientCertificate = new X509Certificate2(clientCertificate.Export(X509ContentType.Pfx)); //export the cert+key to a PFX, then import it again immediately
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(clientCertificate);
The trick her is to load the cert as above. Then export just the PFX and load it again with this. Apparently the result is that it will written to the disk for a bit for a short time. I need to see if this will be an issue when the system is running in docker or not.
Another option will be to have the system admin to split the certs into their own secrets. I need to have a chat with him about that.
Conclusion
Im not sure really how I feel about loading the cert as a pem vs a p12. I feel that the fact that the p12 has a password would make it safe enough. Anyone who took it would need the password that is in Azure secret store. However if the pem files are sitting there they are not encrypted. However again they are in azure secrete store so maybe its a non issue.
Either way this appears to be working quite nicely.
Hi, I’m trying to use this method CreateFromPemFile but in Net 4.6 but..not exists 🙁
For you, is it possibile to use a PEM file?
Sorry I dont support older versions of .net anymore. I cant be of much help.