Raffaele

Raffaele Rialdi weblog

September 2009 - Posts

Programmatically creating the WCF certificate identity tag

SvcUtil let you automatically create the client configuration for a WCF service.

When you use a certificate on the server side, its public key is encoded in Base64 in the client web.config.

   1: <identity>
   2:      <certificate encodedValue="AwAAAA ...." />
   3: </identity>

Obviously SvcUtil create this information from metadata (wsdl).

Unfortunately there are cases where the service configuration is complex and you cannot enable mex endpoint easily. I had this problem when moving a WCF project from the desktop PC to the notebook and finally deploying.

The solution seems very simple:

   1: private static string GetEncoded(X509Certificate2 cert)
   2: {
   3:     byte[] export = cert.Export(X509ContentType.SerializedCert);
   4:     string encoded = Convert.ToBase64String(export);
   5:     return encoded;
   6: }

Please don't do this at home :) ... this value is correct in many cases but for many other has a very dangerous side-effect. Export method exports a certificate in its whole. This means that if the certificate was installed with the private key, the export method write it too! For the sake of completeness, when you install a certificate you can choose to install the private key or not.

Certainly the private key should never go on a client machine, it would be like giving away your home keys to a stranger. GetEncoded method is correct but it writes too much information. We have to strip the certificate from the private key before exporting it.

So I digged the best way to strip the private key from the certificate. After some tests, I asked to a dear friend Mario Fontana (some CAPICOM stuff comes from his fingers) that remembered me that the DER format (the one that contains only the public key) can be obtained simply exporting the certificate with the parameter "X509ContentType.Cert".

   1: byte[] der = certRaf.Export(X509ContentType.Cert); // solo public key

This is not sufficient since we absolutely need to export with SerializedCert parameter. The solution is easy: re-import the certificate.

   1: private static X509Certificate2 ImportFromBlob(byte[] certBlob)
   2: {
   3:     X509Certificate2Collection certs = new X509Certificate2Collection();
   4:     certs.Import(certBlob);
   5:     X509Certificate2 imported = certs[0];
   6:     return imported;
   7: }

The final step is obvious. Export the certificate obtained from the "ImportFromBlob" method using "GetEncoded" at the top of this post.
We now have the magic string used in the client WCF configuration.

Pay attention, this procedure is not "optional". Giving away a private key is the worst thing in security you can do.