I need to be able to import PEM certificates into Azure KeyVault. Here is how.

First, the KeyVault is picky about PEM certificates. Very picky.

The following conditions must be met in order to import a PEM certificate.

  • The private key must be in PKCS#8 format.
  • The public key must be an X509 certificate.
  • The line endings must be Linux style (\n, or newline only).

I was fighting this most of the day, trying to get a PEM certificate to import. All I was getting back was the following error messages:

The specified PEM X.509 certificate content is in an unexpected format. Please check if certificate is in valid PEM format.

The specified PEM X.509 certificate content can not be read. Please check if certificate is in valid PEM format. Accepted formats: PEM content or Base64 encoded PEM content.

The private key specified in the X.509 PEM certificate content has bad encoding. Please check if private key is valid.

In .NET Core 5.0 you can use the following code to export an X509Certificate2 object to a valid PEM file that Azure KeyVault will import.

using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;

namespace Vecc.KeyVault.Sandbox
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var cert = File.ReadAllText("c:\\data\\privatekey.bin");
            var bytes = Convert.FromBase64String(cert);
            var certificate = new X509Certificate2(bytes, string.Empty,
                X509KeyStorageFlags.Exportable);
            var x = certificate.GetRSAPrivateKey();
            var privateKey = x.ExportPkcs8PrivateKey();
            var publicKey = certificate.Export(X509ContentType.Cert);

            var result =
                $"-----BEGIN PRIVATE KEY-----\n" +
                $"{Convert.ToBase64String(privateKey)}\n" +
                $"-----END PRIVATE KEY-----\n"+
                $"-----BEGIN CERTIFICATE-----\n" +
                $"{Convert.ToBase64String(publicKey)}\n" +
                $"-----END CERTIFICATE-----\n";

            File.WriteAllText("c:\\data\\newcert.pem", result);
       }
    }
}

You can create the X509Certificate2 object any way that you want, importing a PFX file, DER files, whatever.

Conclusion

This was a pain to figure out and annoying to have to deal with. Hopefully Microsoft makes it more supportive of standard PEM certificates in the future, like supporting PKCS#1 so standard openssl commands work.

Based on how picky Azure KeyVault is when importing certificates I will be making the secure data transfer site I am building allow uploading files to a blob storage account. It will be easier for the users in the long run with more flexibility.