A Web PKI x509 certificate primer

X.509 (in this document referred as x509) is an ITU standard to describe certificates. This article provides an overview of what these are and how they work.

Three versions of the x509 standard have been defined for web-pki. In this document we will be referring to the current standard in use for web pki: x509 v3, which is described in detail in RFC 5280. In general, x509 certificates bind a signature to a validity period, a public key, a subject, an issuer, and a set of extensions. The extensions define extra properties of the certificate such as extra attributes of the certificate or constraints on the use of the certificate. In order for a certificate to be valid these three requirements must be met:

  1. There is a verification path from the site certificate to a trusted certificate of the user agent (ie if you follow the issuer path you will end on a self-signed certificate that is considered trusted by the browser).
  2. The attributes of the certificates in the verification path have valid parameters for that verification (for example the validity period of all the certificates are valid for the time the verification is being done)
  3. Revocation checks are considered OK for that particular validation.

One issue that is not commonly known is that the x509 trust graph is not a forest (a bunch of trees where each root is a trusted root) but a cyclic graph, where the same key/issuer can be a root or an intermediate for another root in the browsers key store (when roots create intermediates for each other it is called cross-signing).

Extensions

While RFC 5280 defines 16 extensions for webpki in this document we will be describing the six extensions we considered critical for understanding. Certificates can have other extensions not described on RFC 5280, but that is out of the scope of this document. Extensions can be marked as critical or non-critical, conforming certificate verification libraries should stop processing verification when encountering a critical extension that they do not understand ( and should continue processing if the extension is marked as non-critical) mozila::pkix has this behavior.

Subject alternate name

This extension defines what other names (such as DNS names) are valid for this certificate. This allows for a certificate to be used for more than one FQDN, for example you can have a certificate that is valid for both a.example.com and b.example.com

Basic constraints

This allows certificates to be asserted as issuing certificates (it is mandatory for CA certificates). It can also be used to express the maximum depth of the trust path from the CA.

Key usage

This extension is used to constrain the purpose for the key in the certificate. More than one key usage can be asserted. Examples of key usages are: digitalSignature, keyEncipherment, dataEncipherment, keyCertSign, and cRLSign. For CA certificates the keyCertSign bit must be set.

Extended key usages

This is another bitfield to constrain the usages of the key of the certificate. Its is directed mostly at what type of application the certificate was issued for. Examples of extended key usages are: serverAuth, clientAuth, and OCSPSigning. For end-entity certificates for PKI this extension is required to exist with the serverAuth bit asserted.

Name constraints

This is an extension exclusive for CA and indicates limits on the name space for its children. This is one of the most powerful extensions for businesses to have to help limit risk imposed by losing the private key of the CA.

Authority information access

This extension is primarily used to to describe the OCSP location for revocation checking. It is mandatory for certificates that chain up to a root in the Mozilla CA program.

Self-signed certificates

These are the steps to generate a certificate for www.example.com. Replace this value with the actual server name in the steps below.
1. Generate the key using the following command:

  • openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:2048
  • 2048 is considered secure for the next 4 years.

2. Generate CSR using this command:

  • openssl req -new -key key.pem -days 1096 -extensions v3_ca -batch -out example.csr -utf8 -subj '/CN=www.example.com'
  • This creates a new Certificate Signing Request (CSR) that will be valid for 3 years.

3. Write extensions file by creating a new file with name openssl.ss.cnf with the following contents:

  • basicConstraints = CA:FALSE
  • subjectAltName =DNS:www.example.com
  • extendedKeyUsage =serverAuth

4. Self-sign csr (using SHA256) and append the extensions described in the file

  • "openssl x509 -req -sha256 -days 3650 -in example.csr -signkey key.pem -set_serial $ANY_INTEGER -extfile openssl.ss.cnf -out example.pem"

You can now use example.pem as your certfile

CAs included in Firefox

When you visit a secure website, Firefox will validate the website’s certificate by checking that the certificate that signed it is valid, and checking that the certificate that signed the parent certificate is valid and so forth up to a root certificate that is known to be valid. This chain of certificates is called the Certificate Hierarchy.

If your certificates will only be used to verify one domain (e.g. *.yourcompany.com) but you want others outside of your organization to be able to browse to your website using https without having to manually import a root certificate, then you can get an SSL certificate from one of the CAs who already have a root certificate included in the major browsers.

Firefox uses a default set of X.509v3 root certificates for various Certification Authorities (CAs). The root certificates included by default have their "trust bits" set to indicate if the CA's root certificates may be used to verify certificates for SSL servers, S/MIME email users, and/or digitally-signed code objects without having to ask users for further permission or information.

CAs apply to have their root certificates included by default in Mozilla products by following the Mozilla CA Certificate Policy and applying for inclusion as per CA:How_to_apply. Users may override the default root certificate settings using the Certificate Manager.

Some organizations make use of the set of CAs included in Mozilla's products. If you wish to do this, you should read the relevant part of the Mozilla CA FAQ before doing so.

Running your Own CA

If you are going to have your own CA, we recommend building 3 certificates: a long term root cert, a medium term intermediate cert, and a short term end-entity cert. This type of hierarchy allows for a relatively simple long term root to be distributed to clients, and some flexibility on the intermediate cert so that you can change parameters based on best practices and security research.

Generate your CA Root

Update *.example.com and *.example.net below to match your domains.

Assumptions:

  • You are the domain owner of *.example.com and *.example.net.
  • Your computer is not connected to the internet.

Steps to generate your CA root certificate:

  1. Generate key
    • "openssl genpkey -algorithm RSA -out rootkey.pem -pkeyopt rsa_keygen_bits:4096"
    • 4096 is considered secure for the next 15 years.
  2. Generate csr
    • "openssl req -new -key rootkey.pem -days 5480 -extensions v3_ca -batch -out root.csr -utf8 -subj '/C=US/O=Orgname/OU=SomeInternalName'
    • Make a new Certificate Signing Request (CSR) that will be valid for 15 years.
  3. Write extensions File (openssl.root.cnf)
    • basicConstraints = critical, CA:TRUE
    • keyUsage = keyCertSign, cRLSign
    • subjectKeyIdentifier = hash
    • nameConstraints = permitted;DNS:example.com,permitted;DNS:example.net
  4. Self-sign csr (using SHA256) and append the extensions described in the file
    • "openssl x509 -req -sha256 -days 3650 -in root.csr -signkey rootkey.pem -set_serial $ANY_SMALL_INTEGER -extfile openssl.root.cnf -out root.pem"

Now you have CA pem file with its associated key.

Generate your Intermediate cert

The following steps create an intermediate cert that is valid for 8 years.

  1. Generate key
    • "openssl genpkey -algorithm RSA -out r=intkey.pem -pkeyopt rsa_keygen_bits: 3072"
    • A 3072 bit key is considered secure for the next 8 years.
  2. Generate csr
    • "openssl req -new -key intkey.pem -days 2922 -extensions v3_ca -batch -out int.csr - utf8 -subj '/C=US/O=Orgname/OU=SomeInternalName2'
    • Make a new Certificate Signing Request (CSR) that will be valid for 8 years.
  3. Write extensions File (openssl.int.cnf)
    • basicConstraints = critical, CA:TRUE
    • authorityKeyIdentifier = keyid, issuer
    • subjectKeyIdentifier = hash
    • keyUsage = keyCertSign, cRLSign
    • extendedKeyUsage =serverAuth
    • authorityInfoAccess = OCSP;URI:http://ocsp.example.com:8888/
  4. Sign the intermediate csr with the root key and the intermediate extensions
    • "openssl x509 -req -sha256 -days 2922 -in int.csr -CAkey rootkey.pem -CA root.pem -set_serial $SOME_LARGE_INTEGER -out int.pem -extfile openssl.int.cnf"

Generate the end entity certificate

Update www.example.com below to match your domain.

  1. Generate key
    • "openssl genpkey -algorithm RSA -out eekey.pem -pkeyopt rsa_keygen_bits: 2048"
    • 2048 is considered secure for the next 4 years.
  2. Generate csr
    • "openssl req -new -key key.pem -days 1096 -extensions v3_ca -batch -out example.csr - utf8 -subj '/CN=www.example.com'
    • Make a new Certificate Signing Request (CSR) that will be valid for 3 years.
  3. Write extensions file (make a new file with name openssl.ss.cnf with the following contents)
    • basicConstraints = CA:FALSE
    • subjectAltName =DNS:www.example.com
    • extendedKeyUsage =serverAuth
    • authorityInfoAccess = OCSP;URI:http://ocsp.example.com:80/
  4. Intermediate signs the csr (using SHA256) and appends the extensions described in the file
    • "openssl x509 -req -sha256 -days 1096 -in example.csr -CAkey intkey.pem -CA int.pem -set_serial $SOME_LARGE_INTEGER -out www.example.com.pem -extfile openssl.int.cnf"

Security Notes

There are several organizations that provide recommendations regarding the security parameters for key/hash sizes given current computational power. For the end date of the root cert created following the instructions in this page (year 2017). These are the recomendations of bit sizes (from http://www.keylength.com/):

Asymmetric ECC(Key) Hash
Linestra(2004) 1902 172 172
Ecrypt 2012 2432 224 224
NIST 2012 2048 224 224
ANSSI 2010 4096 200 256
RFC 3766 2358 200 ---
BSI 1976 256 256

In other words, SHA1 is now deprecated for new uses. We should use at least 3072 key sizes and at least a 256 ECC curve. Thus the recommendation here is for the root to be 4096 if using RSA and p384 for the root key. (p384 also chosen for compatibility as most SSL/TLS implementations support this part of suite B).

Error Codes in Firefox

Here are some common errors that might be encountered when working with certificates in Firefox.

Error Code What It Means What Can I Do
SEC_ERROR_BAD_DER A certificate is not properly encoded according to ASN.1 (DER) encoding Re-generate the improperly-encoded certificate
SEC_ERROR_CA_CERT_INVALID An end-entity certificate is being used to issue another certificate Ensure that any certificate intended to issue certificates has a basic constraints extension with cA: TRUE
SEC_ERROR_BAD_SIGNATURE A signature on a certificate is improperly formatted or the certificate has been tampered with Re-issue the certificate with the bad signature
SEC_ERROR_CERT_BAD_ACCESS_LOCATION The OCSP URI in the authorityInformationAccess extension is improperly formed Re-generate the certificate with a well-formed OCSP URI
SEC_ERROR_CERT_NOT_IN_NAME_SPACE A certificate has a common name or subject alternative name that is not in the namespace of an issuing certificate Re-issue the certificate with names that are within the namespace of all certificates in the chain
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED A certificate has been signed with an obsolete algorithm Re-sign the certificate using a modern algorithm
SEC_ERROR_EXPIRED_CERTIFICATE A certificate is too old to be used Re-generate the certificate
SEC_ERROR_EXTENSION_VALUE_INVALID A certificate has an extension with an empty value Re-generate the certificate without the extension, or re-generate it with a non-empty value
SEC_ERROR_INADEQUATE_CERT_TYPE A certificate has an extended key usage extension that does not assert a required usage, or an end-entity certificate asserts the id-kp-OCSPSigning usage when it shouldn't Re-generate the certificate with the appropriate extended key usage values
SEC_ERROR_INADEQUATE_KEY_USAGE A certificate has a key usage extension that does not assert a required usage Re-generate the certificate with the appropriate key usage values
SEC_ERROR_INVALID_ALGORITHM A certificate has been signed with an unknown algorithm Re-sign the certificate with a standardized certificate signing algorithm
SEC_ERROR_INVALID_TIME A time field in a certificate has an invalid value Re-generate the certificate with valid encodings for time fields
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE
SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID
SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION A certificate contains an extension marked as critical that is not handled by mozilla::pkix Re-generate the certificate without the extension or with it not marked as critical
SEC_ERROR_UNKNOWN_ISSUER Either a missing intermediate or root certificate is necessary to verify the certificate Import the root certificate into Firefox or have the server send the intermediate
SEC_ERROR_INVALID_KEY
SEC_ERROR_UNSUPPORTED_KEYALG
SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE An issuer certificate is too old Re-issue the issuer certificate
MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY A certificate with a basic constraints extension with cA:TRUE is being used as an end-entity certificate Re-generate the end-entity certificate without the basic constraints extension
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE A certificate has a key that is too small to be secure Re-generate a larger key and issue a certificate using that key