Jump to navigation

Poupou's Corner of the Web

Looking for perfect security? Try a wireless brick.
Otherwise you may find some unperfect stuff here...


TMW#1 - PEM encoded X.509 certificates

Sometimes, well often enough, people will warn you about P/Invoking. This mostly can be resumed to "we will limit ourselves to an absolute minimum". This is a great advice but it's rarely found in the companion sample code ;-) but sometimes it's true!

There is a lot of interesting, but mostly unmanaged, stuff in the MSDN article "EncryptTo/DecryptTo: Encryption in .NET with CryptoAPI Certificate Stores". It's also a very good example of the P/Invoke portability problem. CryptoAPI has a lot to offer, both in cryptography and in certificate creation/management but it is a Windows-only API.

In some aspects, like cryptography, the current .NET framework (1.1) as more to offer than CryptoAPI, but certificate-wise you won't be impressed by the framework support (thanksfully this is gonna get alot better when the v2 of the framework becomes available).

Anyway let's start with an easy (code wise) sample. X.509 certificates can be encoded in many formats. The most common encoding, on Windows, is the ASN.1 DER binary encoding. It is also the only format supported by the .NET framework (unless you work with Authenticode). However PEM (a.k.a base64) encoded X.509 certificates are quite common - at least outside Windows.

PEM stands for Privacy Enhanced Mail which is a set of RFC (1421, 1422, 1423 and 1424) published in the early '90 to secure email. Most of it is now history and has been superseded by S/MIME or PGP but it's 7-bits ASCII format to encode certificates (and other objects like CRL and private keys) is still around.

I bet you can find a lot of old code, in fact I guess all certificate libraries must include it, to convert from PEM to DER. At least you could do it with CryptoAPI (but you will then be limited to Windows), OpenSSL... In fact it's so simple that you could not bother googling and roll your own in managed code like this.

static byte[] PEM (string type, byte[] data) { string pem = Encoding.ASCII.GetString (data); string header = String.Format ("-----BEGIN {0}-----", type); string footer = String.Format ("-----END {0}-----", type); int start = pem.IndexOf (header) + header.Length; int end = pem.IndexOf (footer, start); string base64 = pem.Substring (start, (end - start)); return Convert.FromBase64String (base64); } static X509Certificate LoadCertificateFile (string filename) { X509Certificate x509 = null; using (FileStream fs = File.OpenRead (filename)) { byte[] data = new byte [fs.Length]; fs.Read (data, 0, data.Length); if (data [0] != 0x30) { // maybe it's ASCII PEM base64 encoded ? data = PEM ("CERTIFICATE", data); } if (data != null) x509 = new X509Certificate (data); } return x509; }

Note: the source code has been extracted from the certmgr.exe tool in Mono.

Sometimes it can easier and faster to read a specification and code it yourself than to find the right library to P/Invoke. PEM-encoded certificates are a good example of this but PKCS#7 certificates, or certificate chains and PKCS#12 are better left to ASN.1 fans ;-)

8/12/2004 20:16:18 | Comments

The views expressed on this website/weblog are mine alone and do not necessarily reflect the views of my employer.