Search code examples
c#encryptioncryptographyx509certificate2

Store and retrieve private key in database


I'm having difficulty loading an X509Certificate2 from XML, using the FromXmlString method. The exception I'm getting is m_safeCertContext is an invalid handle.

System.Security.Cryptography.CryptographicException occurred
  HResult=-2146233296
  Message=m_safeCertContext is an invalid handle.
  Source=System
  StackTrace:
       at System.Security.Cryptography.X509Certificates.X509Certificate2.get_HasPrivateKey()
       at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
...

To create the XML, I'm loading the .pfx file and using ToXmlString;

var certificate = new X509Certificate2(
    @"D:\public_privatekey.pfx",
    (string)null,
    X509KeyStorageFlags.Exportable
    );

var exportedPrivate = certificate.PrivateKey.ToXmlString(true);

This generate XML which starts like this...

<RSAKeyValue><Modulus>y0iuejYHYajI...

To recreate the certificate, I'm using...

var certificate = new X509Certificate2();
certificate.PrivateKey.FromXmlString(xml); 

Where xml is a string containing the XML content.

The exception is thrown on the FromXmlString call.

I'm new to using certificates, but my best guess is that the .pfx contains both public and private keys, and possibly some other important data, and that I need all of that in order to have a valid X509 certificate.

However I couldn't find ToXmlString and FromXmlString on the X509Certificate2 directly. How should I do this? Thanks for any advice.


Solution

  • An X.509 certificate is described in a structured binary format called ASN.1/DER encoding. ASN.1 is a language to describe the contents of the certificate and DER is the encoding of the contents that comply with that ASN.1 structure.

    Encoding your in-memory certificate separately from the private key can be done using the Export method using the content type X509ContentType.Cert. You can also export the certificate and private key back into a "pfx" by specifying Pfx or Pkcs12. If you require XML then you can encode the byte array result using base 64. You can then store it into an XML CDATA element.


    Usually a private key is also stored in a binary PKCS#8 container format, also defined using ASN.1 / DER. Microsoft has however chosen to store the key into a Microsoft-proprietary XML format by default.