So you have an instance of an
X509Certificate) that you want to export as a byte array – and you want to exclude the private key – and encrypt the output using a password.
You have found the
Export method of the certificate class which takes one of the
X509ContentType enum values and an optional password. The MSDN help informs that you must choose between
X509ContentType.Pkcs12 for the export to work. You also find out (by experimenting or googling) that exporting using
X509ContentType.Cert produces a serialized certificate without the private key – just what you want! Hooray!
Now you specify a password and think you’re OK.
Fail. You are not. The password is actually ignored.
If you try this:
byte a = cert.Export(X509ContentType.Cert);
byte b = cert.Export(X509ContentType.Cert, "P@ssw0rd #1");
byte c = cert.Export(X509ContentType.Cert, "P@ssw0rd #2");
The resulting byte arrays
c will have the exact same content, even though you specified different passwords! (And it behaves the same if you use the
Personally I would expect the
Export method to throw an exception when specifying
X509ContentType.Cert together with a password (other than null). That would give me, as a developer, a clear sign that I am trying to use an unsupported parameter combination which gives me a chance to try to figure out a work-around. As it is now I am lead to believe that the output content is in fact encrypted.
It is also possible to recreate the certificate again from the byte array giving any password:
var certX = new X509Certificate2(a, "P@ssw0rd #2");
var certY = new X509Certificate2(b, "correct horse battery staple");
certY above will be correctly reconstructed.
Here is a simple solution you can use to export a certificate without its private key and encrypt the exported bytes:
byte ExportCertificate(X509Certificate certificate, string password, bool includePrivateKey)
// Export the certificate (temporarily) using the content type "Cert".
// The exported cert will NOT include the private key -- but it will not
// be encrypted (the given password will be ignored). So we are not there yet.
byte exportedWithoutPrivateKey = certificate.Export(X509ContentType.Cert, "");
// Now recreate the certificate again from the exported bytes.
// The recreated certificate will not contain a private key.
certificate = new X509Certificate2(
"", // The (ignored) password
X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
// Export the certificate using the PKCS #12 format.
// This content type will include the private key among the exported bytes (if there is one).
return certificate.Export(X509ContentType.Pkcs12, password);
Now calling this method, specifying two different passwords and asking not to include the private key…
byte d = ExportCertificate(cert, "P@ssw0rd #1", false);
byte e = ExportCertificate(cert, "P@ssw0rd #2", false);
…generates two byte arrays
e that are different. Further on, if you try to recreate it you must specify the correct password.
var certZ = new X509Certificate2(d, "P@ssw0rd #1");
var fails = new X509Certificate2(d, "correct horse battery staple");
certZ will be correctly reconstructed, but the second try (with wrong password) will throw a
CryptographicException with the message “
The specified network password is not correct.”