It’s not often that you’ll be creating your own X.509 certificates for a web server, since any certificates that you create (self-signed or signed by your own CA) will not be trusted by most browsers (IE, Firefox, etc.) since they were not signed by one of the many Certificate Authorities (CAs) that have been automatically trusted by the browser. If you do decide to use one of these certificates on your web server, you’ll have to navigate through a Byzantine series of screens to “confirm” that you trust the server’s certificate. (Though this is annoying, it may be ultimately beneficial in today’s era of phishing and other malicious behaviour.)

A bit of background

However, what I want to discuss today relates to certificate chains. At the top of every certificate chain is a root CA, whose certificate is self-signed. This sort of certificate can be considered a “God certificate” because it essentially says, “Trust me, because I say so”. As you can imagine, that’s not much of an argument for trusting someone, so that is why your browser has a list of default root CAs that it automatically trusts.



Some default trusted CAs in Firefox.

These root CAs are owned and operated by companies that are in the business of issuing certificates to other people for use on their servers. They have been added to the default trusted list of most browsers so that an end user doesn’t need to manually add all of them; doing so would be a usability nightmare. Essentially, these root CAs provide a trust anchor point, as not only are they trusted, but any certificates they issue will also be automatically trusted by the browser. Attempting to visit a HTTPS/SSL website that does not have a trusted certificates results in a nasty warning from modern browsers.

Rarely is the root CA certificate directly used for a web server, but instead it is used to sign or issue other certificates that are then used on a web server to confirm its identity and provide for secure end-to-end communication.

As you can imagine, operating a CA is an immense responsibility, so that is why these default lists have been setup: Essentially these companies have to vet entities that purchase certificates from them, to make sure they actually own the domain that they are trying to buy a certificate for, otherwise phishing would become too easy! Even so, these companies sometimes still have lapses due to use of outdated technologies and poor security practices, but that is another complicated issue for another day.

Issuing a certificate – An example

The act of issuing a certificate essential entails a CA using its public-private key pair to sign the contents of the certificate that is being issued. This ties the identity information in the certificate to its key pair and provides confirmation that the CA has affirmed the authenticity of the certificate, I.E., that it has truly issued this certificate and that it has not been forged.

Going back to a certificate chains, it was previously mentioned that the root CA certificate is at the top of the chain. Any certificates it issues are directly below it, so if these certificates are directly used on a web server, then the chain is of length two. However, certificate chains can be longer. If a certificate chain is longer than two, then this indicates the presence of an intermediate CA.

An intermediate CA is a CA that does not have a self-signed certificate but still has the capability to issue certificates that are trusted. For an example of the root CA to intermediate CA relationship, we can look at the certificate chain returned from https://mail.google.com:



The Root CA certificate from VeriSign, an X.509 v1 certificate.

Above we see the root CA certificate, a self-signed certificate created/issued by VeriSign. I’ve highlighted the fact that it is an X.509 version 1 certificate, which also means it doesn’t have any certificate extensions. This may not mean much right now, but we’ll get back to it soon.



The Intermediate CA certificate from Thawte, an X.509 v3 certificate.

This next shot shows the intermediate CA certificate that was issued by the root CA. This certificate has been issued to Thawte, a company coincidentally founded by Mark Shuttleworth, the South African man behind Canonical/Ubuntu. Thawte was acquired by VeriSign during the dot-com craze for US $575 million.



The “Basic Constraints” extension of the intermediate CA.

We can clearly see that this certificate is an X.509 version 3 certificate, meaning it does support certificate extensions. One of its extensions is a Basic Constraints extension, which has been set to signify that this is indeed a Certificate Authority. It also specifies one other parameter, which is the maximum number of intermediate CAs allowed beneath this one in the certificate chain hierarchy. Since this value is set to 0, this means this intermediate CA cannot issue any more CA certificates, but instead can only issue client certificates. Any attempt will to use a client certificate from this CA as a CA or signing certificate will fail, when consumed by a conforming client.

The client certificate

The last screenshot shows the client certificate, which is the last certificate in the chain. This is the certificate that is used by the server at mail.google.com to secure HTTPS traffic, and as we can see, it is also an X.509 v3 certificate (has extensions) and one of those extensions is the “Basic Constraints” extension. This time it is set to indicate that this is not a CA certificate.



The Basic Constraints of the client certificate, indicating it is not a CA certificate.

Basic Contraints – Why it’s needed

The “Basic Constraints” extension is one way for a CA to control the usage of the certificates it issues. For instance, when the root CA certificate in the example above issued the intermediate CA certificate, it set the Basic Constraints extension to signify that:

The issued certificate is for a Certificate Authority, i.e. an intermediate CA.

This certificate may not be used to create further CA certificates

In turn, the intermediate CA certificate was used to create the client certificate for mail.google.com , and it attached a Basic Constraints extension to signify that this certificate was not a CA certificate. By doing this, it was indicating that this certificate should not be used to sign/create further certificates.

This is necessary because of the how trust relationship works in X.509 PKI. Someone who trusts the root CA implicitly trusts all the intermediate CAs, and then by extension, all the client certificates issued by those intermediate CAs! (Note how this creates a single point-of-failure at the root CA as well)

If the CA could not control what the certificates it issued were used for, then someone could purchase a VeriSign certificate and use it to sign/create other certificates which would also be trusted by default! Clearly, this is not desirably from a security or financial point of view, if you are VeriSign. By using extensions such as the Basic Constraints one, the signing CA can enact fine-grained control over how the certificate is used. If the client certificate was used to sign another certificate, that certificate would be rejected by a browser that conformed to the X.509 v3 specifications.

The Grey Area

However, we run into a “grey area” of sorts when faced with a certificate that does not have a Basic Constraints extension. In this case, it is not indicated whether this is a CA certificate or not. How do the browsers respond in this scenario? In this case, it seems to depend on whether the CA is a root CA or an intermediate one.

For root CA certificates, it seems that the Basic Constraints extension is not required in order for the CA certificate to be viewed as valid from the browser’s point of view. (I’ve observed this in Firefox and Internet Explorer) This most likely stems from the fact that there are root CAs that were created and put into operation well before X.509 v3 extensions were in wide use. The VeriSign root CA in our example is an X.509 v1 certificate with a starting validity date of 1996-01-28.

However, for intermediate CAs, it seems that the Basic Constraints extension is required if you want things to work, at least in Firefox and Internet Explorer. I encountered this situation when working with a Private Root CA of my own. I was trying to create an intermediate CA (without any Basic Constraints extension) from this root CA, and was running into problems when using this intermediate CA to create client certificates. Any of the client certificates from the intermediate CA were being essentially rejected by the browser when attempting to visit the website they were being used for.

Because this was a “grey area”, the results were mixed. In Firefox, the site would load correctly, however when attempting to view the certificate chain (by double-clicking the lock icon in the lower right), only the client certificate could be viewed, not the fully certificate chain. Internet Explorer would show the full certificate chain but simply failed to load the page. Neither browser gave any indication as to why things were failing.

However, once I created an Intermediate CA with a Basic Constraints extension set to explicitly signify that this was indeed a CA, everything worked as expected. I don’t believe this is well-documented, though this is understandable since most people will not be creating their own Private CAs unless it’s for a very specialized purpose.

How to do this using the Bouncy Castle APIs

I’ve talked about the Bouncy Castle Java APIs before, and they have been an invaluable resource for simplifying the creation of a Private CA and for issuing certificates.

When issuing a certificate it’s fairly easy to set the Basic Constraints extension to indicate you want the certificate to be a CA certificate. First, take a look at this guide to under the fundamentals of certificate creation with the Bouncy Castle APIs, then look at this code fragment:

private static final int NUM_ALLOWED_INTERMEDIATE_CAS = 0; ... // Construct the certificate. final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); ... // Need this extension to signify that this certificate is a CA and // can issue certificates. (Extension is marked as critical) certGen.addExtension( X509Extensions.BasicConstraints, true, new BasicConstraints( NUM_ALLOWED_INTERMEDIATE_CAS ) ); ... final X509Certificate intermediateCaCert = certGen.generate( signingCaPrivateKey, "SunRsaSign" );

By doing this you ensure that the intermediate CA certificate has the proper Basic Constraints extension to work correctly with modern web browsers.

Conclusion

I hope you found this helpful. Certainly if you’re here, you’ve been puzzled over the same issues that I struggled through!

References