There are all sorts of great classes for manipulating X509 Certificates.
Back in .NET 1.1, you could pull in the WSE 1.0/2.0 libraries, and get access to X509Certificate. Later, in .Net 2.0 + WSE 3.0, you got access to X509Certificate2.
Now, with .NET 3.0 we have WCF (codename: Indigo) and I was expecting a still newer, richer, set of classes for manipulating X509 Certificates (I was also expecting deep UDDI support, but alas, nothing...).
Creating self signed certificates has always been problematic in .Net, and it's (sadly) something that everyone dealing with security and testing has to do frequently. Managed code provides no way to create these certificates. The X509Certificate2 class provies a very rich infrastructure for manipulating existing X509 certs, but doesn't provide any mechanism for creating them.
After a signifigant amount of plugging away looking for a purely managed solution for creating an X509Certificate, I gave up. There appeared to be a few options if I wanted to use CAPICOM, but I have moral issues with COM interop, so I didn't go down that path.
The only good answer I could come up with was to shell out to MakeCert, and then read the resulting certificate. I know, I know. I don't like it much either - but it works.
There are a number of optimizations that could be made on the code below, not the least of which involve Code Address Security, cleaning up the file after we're done with it, providing a nice options wrapper around MakeCert, importing the certificate into the Certificate Store using CertMgr, and lots of other good things. If anyone modifies this code to do any of that, let me know! :)
Here's the code that I used to create the certificates:
using System;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography.X509Certificates;
public static X509Certificate2 CreateCertificate()
{
// makecert -r -pe -n "CN=TestUser" -ss my -sr currentuser
// -sky exchange .\TestUser.cer
const string MakeCert =
"C:\\Program Files\\Microsoft Visual Studio 8\\" +
"Common7\\Tools\\Bin\\makecert.exe";
string fileName = Path.ChangeExtension(Path.GetTempFileName(), "cer");
string userName = Guid.NewGuid().ToString();
string arguments =
string.Format("-r -pe -n \"CN={0}\" -ss my -sr currentuser -sky exchange \"{1}\"",
userName, fileName);
Process p = Process.Start(MakeCert, arguments);
p.WaitForExit();
byte[] certBytes = ReadFile(fileName);
X509Certificate2 cert = new X509Certificate2(certBytes);
return cert;
}
internal static byte[] ReadFile(string fileName)
{
using (FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
int size = (int)f.Length;
byte[] data = new byte[size];
size = f.Read(data, 0, size);
return data;
}
}
This code is intended to be used mostly in Unit Tests where creating new certificates happens very frequently, and I know our SoapBox Server installer classes do something very similar during install to create Self-Signed certificates for XMPP domains.
There are all sorts of potential issues with this, not the least of which is verifying MakeCert is really at that path (it usually is!), verifing write-access to the temp directory, permission to create a new process, etc.