This is a second part of the article, if you missed the previous post you can find it here:
Certificates to DB and Back – Part 1
Table of contents
- Loading the Certificate
- Decoding RSA Private Key
- Creating the X509Certificate2
- Demo Application
- Further Improvements
Loading the Certificate
If only a certificate is a problem, X509Certificate2 class will do the job. With the following code, you can simply load the certificate:
string certificatePath = @"public.cer"; X509Certificate2 clientCertificate = new X509Certificate2(certificatePath);
Or if you want to load it directly from the string:
string publicCertString = "-----BEGIN CERTIFICATE----- MCIISFSDFEESd etc. example"; X509Certificate2 clientCertificate = new X509Certificate2(Encoding.UTF8.GetBytes(publicCertString));
Now, the framework offers already much. But this is not enough. If we want to load a certificate from a certificate file, we can do it. Otherwise, if we want to load the certificate and private key from the pfx or pkcs12 container, we can do it. But what if we want to load dynamically the certificate and private key, choose the encryption password and use our object? The X509Certificate2 doesn’t offer an overload of constructor like X509Certificate2(string certFileName, string privateKeyFile, string password) or the similar overload that will accept a byte array in order to correctly initialize this object. In this case, we need to do some dirty work. So let’s do it.
Decoding RSA Private Key
I will not get into details on how the RSA key is decoded, you have the source code plain of comments, so if interested, read it, it says more than a thousand words. In order to decode the private key, we will use DecodeRsaPrivateKey method which will return RSACryptoServiceProvider instance representing our private key.
Creating the X509Certificate2
As described in the previous chapters, I will use the default X509Certificate2 constructor in order to create the certificate. Afterwards, I will assign the decoded RSA private key as RSACryptoServiceProvider to the X509Certificate2 instance property PrivateKey. If everything went well, we will have the proper instance of X509Certificate2 certificate container, containing both, the certificate and the key, encoded with chosen password. Here is the code sample:
byte certBuffer = Helpers.GetBytesFromPEM(publicCert, PemStringType.Certificate); byte keyBuffer = Helpers.GetBytesFromPEM(privateKey, PemStringType.RsaPrivateKey); X509Certificate2 certificate = new X509Certificate2(certBuffer, password); RSACryptoServiceProvider prov = Crypto.DecodeRsaPrivateKey(keyBuffer); certificate.PrivateKey = prov;
I forgot to mention the helper method GetBytesFromPEM, which “cleans” the string from header and footer information.
In the demo application, you can see how to load the described components, create the X509 certificate, persist and reload everything. The interface is just an example, because that is rudimental, simple and incomplete. But hey, this is a demo, and for a demo is already too much! The important stuff is under the hood, that’s in what you should be interested.
How to improve this code? Well test it, I have some doubts about creating Key Containers, and I will test it too. Any new discovery will be promptly noticed and the article will be updated.
Other things that are on my mind are creating the extension methods to the X509Certificate2 in order to make code look simpler and cleaner.
Perhaps including these methods in your applications’ framework cryptography library? Any idea is welcome so if you have any, feel free to contact me or to post the comment.
The idea and realisation are made completely by the author. The method DecodeRsaPrivateKey and all the code used inside were kindly provided by Mr Dan Maser; Dan, thanks for providing the code and for all the support. The way that RSACryptoServiceProvider is initialized is code written by me in order to overcome the encountered problems with .NET 4.0, all the traits-based size stuff and byte alignment are written by Dan Maser, but, speaking with Dan, we came to the following. The core of the ASN.1 parsing code came from a stackoverflow.com article. After analysing the code and after doing further research, I came across what I believe to be its original source, which is http://www.jensign.com/opensslkey/opensslkey.cs. The top of that file does include a standard copyright line “Copyright (C) 2008 JavaScience Consulting”. I didn’t knowingly use any copyrighted information when I originally wrote the code, but now it’s kind of fuzzy. There’s no direct indication I can find about any limitations on using or modifying the code directly on that website. At the bottom of http://www.jensign.com/JavaScience/cryptoutils/index.html, it does say “NOTE: These utilities and sample code are made available as-is with no support or guarantee of performance. They are intended to demonstrate specific technical implementation details with minimal error checking. Use at your own risk.” which does seem to directly suggest that one can use the published utilities, at albeit one’s own risk.
However, I think it is ok, but I guess you never know with the lawyers. If you find out that this code breaks the law, please contact me promptly and all code, as well as the article, will be removed.
If this is not the case, the article, along with any associated source code and files, is licensed under Microsoft Public License (MS-PL).