i have a .PEM file that includes public key and a private key for SSL data transfer like this:
-----BEGIN RSA PRIVATE KEY----- private key data -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- public key data -----END CERTIFICATE-----
when i want to load the .PEM file by the following code:
X509Certificate2 xx = new X509Certificate2("c:\\myKey.pem");
i get an exception that says: "Cannot find the requested object." , with full stack:
System.Security.Cryptography.CryptographicException was unhandled Message=Cannot find the requested object. Source=mscorlib StackTrace: at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) at System.Security.Cryptography.X509Certificates.X509Utils._QueryCertFileType(String fileName) at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromFile(String fileName, Object password, X509KeyStorageFlags keyStorageFlags) at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName) at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String fileName) at DLLTest.SSL_Test.test() in E:\Projects\DLLTest\DLLTest\SSL_Test.cs:line 165 at DLLTest.SSL_Test.Run() in E:\Projects\DLLTest\DLLTest\SSL_Test.cs:line 21 at DLLTest.Program.Main(String[] args) in E:\Projects\DLLTest\DLLTest\Program.cs:line 21 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:
if i swap place of private key section and public key section, the code works and load data, and i can get just public key info from the object, eg. IssuerName, and its HasPrivateKey is false. why? am i misunderstood and doing wrong something?
The typical PEM files are: key. pem contains the private encryption key. cert.
There's an article on the Code Project that has all the code you need to do this. It's just a couple of classes so it's a light-weight solution.
To get the bytes for either a certificate or a key from the PEM file the following method will work, regardless of the order of the key and certificate in the file.
byte[] GetBytesFromPEM( string pemString, string section ) { var header = String.Format("-----BEGIN {0}-----", section); var footer = String.Format("-----END {0}-----", section); var start= pemString.IndexOf(header, StringComparison.Ordinal); if( start < 0 ) return null; start += header.Length; var end = pemString.IndexOf(footer, start, StringComparison.Ordinal) - start; if( end < 0 ) return null; return Convert.FromBase64String( pemString.Substring( start, end ) ); }
Load the PEM file into a string and call the method above to get the bytes that represent the certificate. Next you pass the obtained bytes to the constructor of an X509Certificate2 :
var pem = System.IO.File.ReadAllText( "c:\\myKey.pem" ); byte[] certBuffer = GetBytesFromPEM( pem, "CERTIFICATE" ); var certificate = new X509Certificate2( certBuffer );
Loading the (RSA) private key from the PEM file is a bit more complicated but you'll find support for that in the above mentioned article as well using the Crypto.DecodeRsaPrivateKey
method.
AFAIK the .NET framework does not support PEM anywhere.
You can hack around this easily for the X509Certificate
part since you can extract the base64 string between the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- lines, convert it into a byte[]
and create the X509Certificate
from it.
An easy solution is to copy-paste code from Mono.Security's X509Certificate.cs to do this.
Getting the private key is a bit tricky since getting the byte[]
won't be of much help to reconstruct the RSA instance (which we can assume since the PEM header states it's RSA).
This time you better copy-paste from Mono.Security's PKCS8.cs file and sioply call the decode method.
Disclaimer: I'm the main author of the Mono code discussed above and it is all available under the MIT.X11 license
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With