October 09, 2013

For an SSL Client Certificate to get sent with SslStream, the PrivateKey member must be set.

MongoDB is implementing x509 authentication. This is great for enterprises who issue users certificates or for trusted servers communicating over SSL already. When the server adds support, it means all the drivers also need to add support for it. As we already built in Kerberos support, we made the system trivial to add other authentication systems and it took all of about 15 minutes to include x509 support. However, testing it took hours of my time.

Enabling ssl can be completely done via a connection string, but to add in a client certificate for authentication requires some code. 1

var cert = new X509Certificate2("client.pem");

var settings = new MongoClientSettings
{
    Credentials = new[] 
    {
        MongoCredential.CreateMongoX509Credential("CN=client,OU=kerneluser,O=10Gen,L=New York City,ST=New York,C=US")
    },
    SslSettings = new SslSettings
    {
        ClientCertificates = new[] { cert },
    },
    UseSsl = true
};

var client = new MongoClient(settings);

As you can see, I had a .pem file. It included both the certificate and the private key, but the client was sending the certificate, even though it’s obvious I included it. Finally I checked the PrivateKey property on the X509Certificate2 instance and it was null. Hmmm. What is wrong with .NET?

I split the pem file into client.crt and client.key with the intention of loading client.crt and then assigning the private key. Apparently, that is non-trivial. In fact, I found no good examples of this. However, a number of people had success on StackOverflow using BouncyCastle, an open-source crypto API (ported from Java I think). I obviously have nothing wrong with this, but how can the .NET framework not support this?

It turns out openssl can create something that .NET does understand that includes both the certificate and the private key in one file and, when loaded, will have the PrivateKey already applied. Running the below openssl command will generate client.pfx. You’ll need to set a password which we’ll use when we construct the X509Certificate2.

openssl pkcs12 -export -out client.pfx -inkey client.key -in client.crt

At this point, passing this certificate into the SslStream’s AuthenticateAsClient method will send the certicate along for the ride.

var cert = new X509Certificate2("client.pfx", "mySuperSecretPassword");
  1. The string in the CreateMongoX509Credential is the RFC2253 format for the subject. It can be found using openssl x509 -in client.pem -inform PEM -subject -nameopt RFC2253

MongoDB Drivers - Wire Protocol Part 2

How drivers talk to MongoDB using the Wire Protocol - Part 2. Continue reading

MongoDB Drivers - Wire Protocol Part 1

Published on December 10, 2013

MongoDB Drivers - Bson

Published on December 02, 2013