In our previous post, we clarified some important cryptographic terms and had a look at basic cryptographic operations. Now it's time to build upon that and start to actually look at certificates in detail.
This post covers the anatomy of a certificate – including its purpose, contents, how it is formatted, and how it is stored in files.
What is a certificate?
In straightforward terms, a certificate is just the public key of a key pair wrapped into a container format that also contains meta data about that public key. Typical meta data you can expect in a certificate is:
- Who owns that public key? (person/organization)
- On which date does the key become valid? ("not valid before")
- At which date does it become invalid? ("not valid after")
- What kind of public key is embedded? (RSA or ecliptic curve, how many bits, etc.)
- What may this public key be used for? (encrypting data, signing data, signing other certificates, etc.)
- What does the public key belong to? (e-mail address, IP address, website domain, etc.)
- Plus many other types of information, most of which are optional
Publishing public keys without this information is pretty useless, since whoever gets a copy of the public key will otherwise have no idea what it is good for or who it is supposed to authenticate. This information has to be stored somewhere, so why not just directly store it together with the key in a single data format? This data format is what we call a certificate.
What does a certificate look like?
This example shows you what a certificate could look like when being dumped in human readable form.
Is the private key also stored in the certificate?
Private keys are not embedded in certificates. There is no need to store meta data with private keys, as the private keys are stored in a format that either also contains all data which make up the public key or contain enough data to at least unambiguously identify the public key.
If you have both the private key and the certificate on your system, the system can map the private keys to the public keys within certificates and then get all meta data from the certificate. As private keys are not supposed to ever be distributed and owners of private keys should always keep a copy of the public key as well (which usually happens in form of the certificate), the problem of requiring storage for extra meta data does not arise.
How are certificates formatted?
Certificates use the ASN.1 data storage format. ASN.1 is a data storage format that encodes data similar to XML or JSON, but it is a binary encoding format that is very compact and easy to process even by primitive CPUs and low level code.
ASN.1 on its own does not define a data format, i.e. it does not define which fields are to be encoded in which order and what the meanings of those fields are. The standard that defines the data fields, their meaning, and whether they are optional or mandatory is named X.509.
When certificates are stored as a file, they are either stored in DER or PEM format. DER is just a binary file containing the raw ASN.1 bytes. PEM on the other hand is a textual format. It's not human readable, but is easy to work with as all binary data is base64 encoded and thus can be opened and viewed by any simple text editor.
A PEM certificate file would look like this:
: ( a lot more data left out )
When storing raw keys, e.g. the private key or the public key without certificate meta data, a container format is required, since those keys also consist of multiple individual data fields.
The two common container formats are named PKCS #1 and PKCS #8. PKCS #1 can only store RSA keys, PKCS #8 can store different key types, including ecliptic curve keys. On top of that, PKCS #8 supports encryption, so keys may be stored encrypted by a password and a password is then required to use or decrypt the key again.
Just as before, those keys in containers can be stored either as raw bytes or as PEM data using base64 encoded bytes.
A PKCS #1 PEM would be wrapped between:
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
for a private key or
-----BEGIN RSA PUBLIC KEY-----
-----END RSA PUBLIC KEY-----
for a public key, whereas a PKCS #8 key would not explicitly speak of RSA, since it allows different kind of keys and which kind of key is encoded in the data itself:
-----BEGIN PRIVATE KEY-----
-----END PRIVATE KEY-----
Further if the PKCS #8 key is encrypted, that would also be written in human readable form:
-----BEGIN ENCRYPTED PRIVATE KEY-----
-----END ENCRYPTED PRIVATE KEY-----
Last but not least, there is PKCS #12, which is a container format that can store keys as well as certificates, grouped in bags (called "SafeBags"), which can also optionally be encrypted and/or signed.
PKCS #12 is a rather complex format that can contain any number of bags and every bag can contain any number of keys and certificates, but most commonly it is used to just store a certificate together with its private key in an encrypted bag. PKS#12 formats are always stored as raw bytes.
Which file extensions can certificates have?
The following list contains the most common file extensions for certificates and what they mean:
- .der: A certificate in DER format.
- .pem: A certificate or key in PEM format.
- .crt: A certificate either in DER or in PEM format.
- .cer: Same as .CER but Microsoft wanted an own extension.
- .key: A key, either in DER or PEM format.
- .p12: PKCS #12 container.
- .pfx: A predecessor to PKCS #12 from Microsoft, Windows still uses this extension for PKCS #12.
- .p7b: A PKCS #7 certificate container. The format encodes certificates either like PEM or DER but it supports grouping multiple certificates into containers and allows storing certificate revocation lists. This format is almost only used by Windows and Java Tomcat.
Tip: Key above can always mean either private or public key.
Using Keychain Access with certificates
On macOS, certificates and keys are usually stored in the Keychain. The Keychain provides secure storage for passwords and other security relevant data like keys and certificates. Apps can directly access the Keychain using the Keychain API, but users can also access the keychain using an application named "Keychain Access".
Keychain Access will automatically import certificates and keys into your keychain when double clicked in Finder. All the file types listed above are supported. It also provides a Quick View module, so when selecting such a file in Finder, you can hit the spacebar and Finder will show you detailed information about certificates.
Once imported, you can re-export keys and certificates from Keychain Access. Certificates can be exported to either .cer files (which is the same as .der format), .pem files or as .p7b certificate bundles. You can also export private keys to PEM files. And when you select a certificate and its private key at the same time, you can export both to a PKCS #12 container.
Sometimes you may require certificates or keys in a different format than what you currently have available. Fortunately macOS ships with a command line utility named openssl that is able to convert between all the different formats. This command line utility is also by default available to most other UNIX like systems, like Linux or FreeBSD.
Only Windows users are left out (as usual) and must resort to using alternative tools offered by Microsoft (like certutil) or by third parties. You can also download and install OpenSSL binaries for Windows, then you can use the same commands as shown in the next section.
Converting from PKCS #12 to PEM:
If you have a PKCS #12 container (container.p12) with a certificate and private key and want to obtain the certificate in PEM format (cert.pem), you can use the following command:
openssl pkcs12 -in container.p12 -out cert.pem -clcerts -nokeys
If stored in a encrypted SafeBag, you will have to provide the decryption password. If you want to obtain the private key in PEM format (key.pem), you would use this command instead:
openssl pkcs12 -in container.p12 -out key.pem -nocerts -nodes
as before, you will have to provide the decryption password, if the private key is stored in an encrypted SafeBag; which is very likely the case.
Note however, that the resulting PEM key will not be encrypted. If you would like to encrypt the PEM key (which is a good idea if you want to archive it or transfer it around), use this command:
openssl pkcs12 -in container.p12 -out key.pem -nocerts
This time you will also get prompted for the PEM pass phrase, which you must enter twice to ensure that you didn't mistype it the first time. Now you have an encrypted PKCS #8 key!
Converting from PEM to PKCS #12:
Converting the other way round is possible as well. If you have a private key (key.pem) and certificate (cert.pem) in PEM format, you can convert both to a PKCS #12 container (container.p12) using the following commend:
openssl pkcs12 -export -out container.p12 -in cert.pem -inkey key.pem
If the key file is encrypted, you will be prompted for the decryption password first. In either case you are prompted for the SafeBag encryption password, again twice to prevent mistyping.
Converting from DER to PEM:
If you have a certificate in DER binary format (cert.der) and you require a PEM version of it (cert.pem), just use:
openssl x509 -inform der -in cert.der -out cert.pem
or on Windows:
certutil -encode cert.der cert.pem
Converting from PEM to DER:
Finally, if you have a certificate in PEM format (cert.pem) and you require a DER binary version of it (cert.der), just use:
openssl x509 -outform der -in cert.pem -out cert.der
or on Windows:
certutil -decode cert.pem cert.der