Bouncy Castle - Missing Certificate Attributes

20 Mar 2013 14:52 bouncy-castle

Over the last couple of days, we’ve seen how to use Bouncy Castle to generate certificates from C#. However, if you compare the certificates we’ve been generating with those generated by (e.g.) makecert, you’ll see that we’re missing a few things.

What’s missing?

To generate a self-signed certificate using makecert, you can just run the following command from a command prompt (make sure that makecert is in your path):

makecert -r -pe -n "CN=makecert" -ss My -sr CurrentUser -a sha256 -cy end -sky signature

This creates and installs a certificate. If you compare it to the certificates we’ve been generating with Bouncy Castle, you’ll see that we’re missing the following attributes:

  • “Basic Constraints”
  • “Authority Key Identifier”

Authority Key Identifier

According to this page, the “Authority Key Identifier” is used to identify “the public key to be used to verify the signature on this certificate”. That is: it should basically be the issuer’s public key.

The Bouncy Castle documentation, here, shows how to create this attribute in Java. To do the same in .NET, we need something like the following:

var authorityKeyIdentifier = new AuthorityKeyIdentifierStructure(issuerCertificate);
certificateGenerator.AddExtension(
	X509Extensions.AuthorityKeyIdentifier.Id, false, authorityKeyIdentifier);

..but, unfortunately, this is a self-signed certificate, so we don’t have issuerCertificate. By looking at the source code (or by using Reflector), we can see that this does (more-or-less) the following:

var issuerPublicKeyInfo =
    SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issuerCertificate.GetPublicKey());
var issuerGeneralNames =
    new GeneralNames(issuerCertificate.IssuerDN);
var issuerSerialNumber =
    issuerCertificate.SerialNumber;

var authorityKeyIdentifier = new AuthorityKeyIdentifier(issuerPublicKeyInfo, issuerGeneralNames, issuerSerialNumber);

But: we don’t have an issuer certificate, remember. We’re creating a self-signed certificate here. We need something like the following:

// Self-signed, so it's all the same.
var issuerKeyPair = subjectKeyPair;
var issuerDN = subjectDN;
var issuerSerialNumber = serialNumber;

var authorityKeyIdentifier =
    new AuthorityKeyIdentifier(
        SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issuerKeyPair.Public),
        new GeneralNames(new GeneralName(issuerDN)),
        issuerSerialNumber);
certificateGenerator.AddExtension(
	X509Extensions.AuthorityKeyIdentifier.Id, false, authorityKeyIdentifier);

Subject Key Identifier

If you look at a certificate issued by Active Directory, it also has a “Subject Key Identifier” (see here). We might as well add this attribute as well.

This is simpler:

var subjectKeyIdentifier =
    new SubjectKeyIdentifier(
        SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public));
certificateGenerator.AddExtension(
    X509Extensions.SubjectKeyIdentifier.Id, false, subjectKeyIdentifier);

Basic Constraints

The “Basic Constraints” attribute corresponds to the -cy end or -cy authority switch passed to makecert. To add it:

certificateGenerator.AddExtension(
    X509Extensions.BasicConstraints.Id, true, new BasicConstraints(false));

The boolean value (false here) corresponds to whether this is a CA certificate or not. false corresponds to -cy end, and true to -cy authority.

Critical Extensions

For the “Authority Key Identifier” and “Subject Key Identifier” extensions, we passed false as the second parameter to AddExtension. For the “Basic Constraints” extension, we passed true. What’s that all about?

This boolean controls whether the extension is considered “critical” or not. According to RFC 5280:

A certificate-using system MUST reject the certificate if it encounters a critical extension it does not recognize or a critical extension that contains information that it cannot process. A non-critical extension MAY be ignored if it is not recognized, but MUST be processed if it is recognized.

That’s it for now. In my next article, I’ll show how to add extended key usage (EKU) flags.