Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to get private key from PEM file?

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?

like image 542
losingsleeep Avatar asked Sep 13 '11 10:09

losingsleeep


People also ask

Does a PEM file have a private key?

The typical PEM files are: key. pem contains the private encryption key. cert.


2 Answers

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.

like image 155
Marnix van Valen Avatar answered Sep 23 '22 00:09

Marnix van Valen


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

like image 35
poupou Avatar answered Sep 24 '22 00:09

poupou