This article needs a technical review. How you can help.
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:
- 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).
- 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)
- 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:
- Generate key
- "openssl genpkey -algorithm RSA -out rootkey.pem -pkeyopt rsa_keygen_bits:4096"
- 4096 is considered secure for the next 15 years.
- 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.
- Write extensions File (openssl.root.cnf)
- basicConstraints = critical, CA:TRUE
- keyUsage = keyCertSign, cRLSign
- subjectKeyIdentifier = hash
- nameConstraints = permitted;DNS:example.com,permitted;DNS:example.net
- 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.
- 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.
- 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.
- Write extensions File (openssl.int.cnf)
- basicConstraints = critical, CA:TRUE
- authorityKeyIdentifier = keyid, issuer
- subjectKeyIdentifier = hash
- keyUsage = keyCertSign, cRLSign
- extendedKeyUsage =serverAuth
- authorityInfoAccess = OCSP;URI:https://ocsp.example.com:8888/
- 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.
- Generate key
- "openssl genpkey -algorithm RSA -out eekey.pem -pkeyopt rsa_keygen_bits: 2048"
- 2048 is considered secure for the next 4 years.
- 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.
- 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:https://ocsp.example.com:80/
- Intermediate sings 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 https://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 |