Home About

Adding an Authority Key Identifier in .NET Core

September 01, 2021

When creating a certificate request to create an intermediate CA, you generally want to add an Authority Key Identifier to the request so that there is clarity as to which issuing key was used to sign the intermediate CA cert. .NET Core currently lacks a native extension for this, so I hacked something together, allowing a similar experience to when adding a Subject Key Identifier to the request.

CertificateRequest intermediateRequest = new CertificateRequest(
    "CN=Experimental Intermediate Issuing Authority",
    intermediateKey,
    HashAlgorithmName.SHA256);

intermediateRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.CrlSign, true));
intermediateRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, true, 0, true));
intermediateRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(intermediateRequest.PublicKey, false));
intermediateRequest.CertificateExtensions.Add(new X509AuthorityKeyIdentifierExtension(rootCertificate, false));
public class X509AuthorityKeyIdentifierExtension : X509Extension
{
    private static Oid AuthorityKeyIdentifierOid => new Oid("2.5.29.35");
    private static Oid SubjectKeyIdentifierOid => new Oid("2.5.29.14");

    public X509AuthorityKeyIdentifierExtension(X509Certificate2 certificateAuthority, bool critical)
        : base(AuthorityKeyIdentifierOid, EncodeExtension(certificateAuthority), critical)
    {
    }

    private static byte[] EncodeExtension(X509Certificate2 certificateAuthority)
    {
        var subjectKeyIdentifier= certificateAuthority.Extensions.Cast<X509Extension>().FirstOrDefault(p => p.Oid?.Value == SubjectKeyIdentifierOid.Value);
        if (subjectKeyIdentifier == null)
            return null;
        var rawData = subjectKeyIdentifier.RawData;
        var segment = new ArraySegment<byte>(rawData, 2, rawData.Length - 2);
        var authorityKeyIdentifier = new byte[segment.Count + 4];
        // KeyID of the AuthorityKeyIdentifier
        authorityKeyIdentifier[0] = 0x30;
        authorityKeyIdentifier[1] = 0x16;
        authorityKeyIdentifier[2] = 0x80;
        authorityKeyIdentifier[3] = 0x14;
        segment.CopyTo(authorityKeyIdentifier, 4);
        return authorityKeyIdentifier;
    }
}