Google Cloud Playing certificate authority: Using Cloud KMS to sign certificate signing requests

Last time, we looked at how we can use a Cloud KMS asymmetric signing key to create a self-signed X.509 certificate. But we’re not limited to self-signed certificates: we can use Cloud KMS to sign other certificate signing requests too, just like a certificate authority (CA).

Trusting the issuer

If we want to act like a CA, we first need to establish trust. That is, we have to obtain the certificate authority’s certificate and register it as a trusted authority on other machines.

A CA root certificate is essentially nothing else than a self-signed certificate and we already know how to create that. All that’s left to do is to add this certificate to the list of trusted CAs. On Windows, that’s done by importing the certificate to the Trusted Root Certification Authorities container. On Linux, we can place the certificate in /etc/pki/ca-trust/source/anchors/ (in PEM format) and run update-ca-trust (that’s the process for CentOS/RHEL, other distributions differ).

Issuing a certificate

Now let’s see how we can use our newfound CA to issue a certificate.

First, we create a local RSA key pair. We can use CNG for that:

var keyParams = new CngKeyCreationParameters
{
  // Do not overwrite, store in user profile.
  KeyCreationOptions = CngKeyCreationOptions.None,

  // Do not allow exporting.
  ExportPolicy = CngExportPolicies.None,

  Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider,
  KeyUsage = CngKeyUsages.AllUsages
};

keyParams.Parameters.Add(
  new CngProperty(
    "Length",
    BitConverter.GetBytes(2048),
    CngPropertyOptions.None));

var keyPair = new RSACng(CngKey.Create(
  CngAlgorithm.Rsa,
  "Bob's key",
  keyParams));

Next, we create a certificate signing request (CSR). Remember, a CSR is

[...] like an unsigned contract: It has all the necessary details that the client wants to have included in the certificate, but lacks the final, crucial bit, the CA’s signature. Specifically, a certificate signing request can include:
  • The client’s public key.
  • The distinguished name of the client.
  • Any number of extension attributes.
  • A digital signature, which is the hash of the request, encrypted with the client’s private key.
  • The hashing algorithm used for the creation of the digital signature.

Let’s say the certificate is for Bob:

  //
  // (1) Create a certificate signing request.
  //
  var csr = new CertificateRequest(
    new X500DistinguishedName("Bob's key"),     // Bob's DN
    keyPair,                                    // Bob's key pair
    HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1);

After creating a CSR, we’d typically send it to the CA to have it signed. To keep things simple, let’s assume we have direct access to the Cloud KMS signing key. We can then reuse the KmsSignatureGenerator class from the last post and sign the CSR:

  //
  // (2) Sign the certificate signing request.
  //
  var signatureGenerator = new KmsSignatureGenerator(
    kmsService, 
    kmsKeyName);

  var signedCertificate = csr.Create(
    new X500DistinguishedName("CN=My KMS key"), // DN of our CA
    signatureGenerator,                         // Use KMS to sign
    DateTime.UtcNow,                            // Validity of cert
    DateTime.UtcNow.AddDays(30),
    new byte[] { 1 });                          // Serial number

signedCertificate now contains a certificate that’s issued to Bob and signed by our CA.

If we save the certificate to a file that uses the .cer file extension, we can use the Windows certificate viewer to verify that the certificate uses the subject Bob’s cert, and that the issuer is My KMS key – just like we’d expect from a CA-issued certificate:

Certificate

And because the CA certificate is trusted, the Certificate Path tab also shows the relationship between the two certificates and confirms that Bob’s certificate is ok:

Certification oath

Just because we can…

As the example above shows, it’s not too difficult to use Cloud KMS to sign certificates, effectively acting as a certificate authority. But in reality, there’s typically more to running a CA than being able to sign a CSR – so you might be better off using a managed service like Certificate Authority Service.

Any opinions expressed on this blog are Johannes' own. Refer to the respective vendor’s product documentation for authoritative information.
« Back to home