Using an X.509 (pfx) certificate in Windows 8 Metro-style application for encryption, decryption and signing

One of the things that you need to live with if you are creating a metro-style application is that you are in a sandbox and consequently you don’t have the full .NET runtime available to you. Thus, when I wanted to do some signing using a pfx certificate in my Windows 8 application I was sad, but not surprised to see that the awesome System.Security namespace isn’t available. Instead you need to deal with the Windows.Security namespace, which is a cut-down set of cryptographic functionality with a completely different API to what you might be used to!

Most of the code samples I could find were demonstrating how to create a new public/private keypair and then use that to perform the signing etc., but that wasn’t useful for me in this instance because I wanted to use a private key we already had (and trusted).

The trick of course was to try and load our certificate in, and looking through all of the classes and methods in the namespace it wasn’t immediately clear how to do that. I originally tried using the CertificateEnrollmentManager.ImportPfxDataAsync method, but apart from the fact I wasn’t able to figure out how to get my pfx file data into a format that method would select I eventually realised this wouldn’t help me. This method imports the certificate into the sandboxed certificate store the app has, but this isn’t helpful because:

  1. There is no way to use the certificates in the store programmatically
  2. I managed to figure out the store is just for using HTTP client certificates rather than as a general certificate store

The solution

Firstly you need to grab your pfx and convert it to CSP format (I did this in LinqPad):

var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(@"c:pathtomypfx_file.pfx", "password", System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable);
var privateKey = cert.PrivateKey as System.Security.Cryptography.RSACryptoServiceProvider;
var cspBlob = privateKey.ExportCspBlob(true);
Console.WriteLine(Convert.ToBase64String(cspBlob));

Then put the resultant text in a .txt file in your metro app and mark the file as content and the following code should work (this example for signing, but the same applies for using the CryptographicEngine to decrypt, encrypt etc.):

    public async Task<IBuffer> Sign(IBuffer toSign)
    {
        var file = await (StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///path/to/my/csp_key.txt")));
        var contents = await FileIO.ReadBufferAsync(file);
        var contentsAsArray = contents.ToArray();
        var base64Contents = Encoding.UTF8.GetString(contentsAsArray.ToArray(), 0, contentsAsArray.ToArray().Length);

        var algorithm = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaSignPkcs1Sha1);
        var key = algorithm.ImportKeyPair(Convert.FromBase64String(base64Contents).AsBuffer(), CryptographicPrivateKeyBlobType.Capi1PrivateKey);

        return CryptographicEngine.Sign(key, toSign);
    }

If doing this you should note that you are storing the private key in a non-encrypted form inside your app package, which isn’t secure if you don’t trust the machine that the app will be deployed to.

10 Replies to “Using an X.509 (pfx) certificate in Windows 8 Metro-style application for encryption, decryption and signing”

  1. I tried to use the namespace “System.Security.Cryptography.X509Certificates” in my metro app for validating the x509 certificate but “x509” class does not exist,i am using vs 2012 ultimate,kindly tel me do I need to include any additional reference?

    1. Hi,

      As I said in my post you can’t use the System.Security namespace in metro-style applications. Instead you need to use Windows.Security.

      The code in my post should give an initial idea of how you can interact with that namespace.

      There are no additional references you need to add for a metro-style application for core .NET namespaces (obviously any libraries you need to include will need to be added); the default reference automatically includes all the namespaces.

  2. hi Rob,

    I am calling a WCF Service.
    Need to validate the thumbprint of a client certificate with that of a server.

    Earlier we used to do the following:

    ServicePointManager.ServerCertificateValidationCallback+=customXertificateValidation;

    public static bool customXertificateValidation(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
    {
    X509Certificate2 certificate = (X509Certificate2)cert;
    if (!string.IsNullOrEmpty(certificate.Thumbprint) && certificate.Thumbprint.ToLower() == serverThumbprint)
    {
    return true;
    }
    else
    return false;
    }
    How can the above be done in WinRT.

    1. You certainly could do, but it’s pretty easy to decompile the dll so it’s not really any more secure, plus managing big blobs of text in code files is gross 😛

  3. Hi Rob,

    I want to know how will you link a Certificate to a WCF Service as we did in the old WCF services. Earlier we used to do:

    client.ClientCredentials.ClientCertificate.SetCertificate(…);
    or
    client.ClientCredentials.ClientCertificate=…;

    But now, ClientCredentials do not support ClientCertificate at all. Instead, it asks for UserName and Password, which is not I want to use for Authentication. Is there a workaround for it?

    I tried with CertificateEnrollmentManager.ImportPfxDataAsync(…) and the certificate gets imported. But what after it? How do I link it with my WCF client?

    Regards,
    Gopi

  4. Hi,

    On WinRT platform, I want to read a certificate and print the url of CA.
    Can you please tell me the steps I need to follow (using C++)?

    Regards,
    Narendra

    1. I’m not entirely sure, but I suspect it’s not possible since there are no classes in WinRT to deal with manipulating or reading metadata for x509 certs.

Leave a Reply to mahadeva Swamy Cancel reply

Your email address will not be published. Required fields are marked *