Formats of security certificates
While I was integrating wolfSSL in a project, I had to study its possibilities to import or export keys and certificates. I came across different formats of security certificates which were unfamiliar. I thought that it would be interesting to share what I learned.
wolfSSL is a lightweight SSL/TLS library targeted at, among others, embedded environments. It provides APIs for several ciphers that allow a strong and secure end-to-end encryption and can exploit the cryptographic hardware units of some SoC.
Overview of formats of security certificates
The standards for security certificates are usually well known. For example, X.509 v3 is a standard for security documents and PKCS#7 (Public-Key Cryptography Standards #7) and PKCS#12 (Public-Key Cryptography Standards #12) are standard container syntaxes for digital certificates. X.509 v3 defines which fields must be present in a certificate, while PKCS#7 and PKCS#12 are typically used to bundle different pieces of information together. In the case of PKCS#7, it could be the chain of trust of the client certificate with CRL. In the case of PKCS#12, it could be the private key, the X.509 certificate and the chain of trust.
What is probably less known is the encoding formats that these standards use. X.509 v3 specifies that when executing an operation on a data, this data must be encoded with ASN.1 DER (defined in ITU-T X.690). The X.509 v3 certificate itself, PKCS#7 and PKCS#12 can be stored in ASN.1 DER or PEM formats.
ASN.1 DER is intended for situations where a unique encoding is required (contrary to its variant ASN.1 BER for example) and defines how to encode data into binary format. This article of Let’s Encrypt explains the basics of the encoding.
PEM (Privacy Enhanced Mail) defines the textual encodings (contrary to DER which defines the binary, octet-oriented encodings). The value is simply the binary format (e.g. given by DER) encoded in base64.
The remaining part of this article will present the encoding in ASN.1 DER and PEM formats of an elliptic curve keypair.
Example of formats of security certificates
To really understand what ASN.1 DER and PEM are, let’s get some hands on. The example uses openSSL and a terminal.
Open a terminal where openSSL is installed and generate a key pair:
openssl ecparam -name prime256v1 -genkey -out key.pem
This keypair is saved in PEM format. Use the command
openssl ec -in key.pem -text -noout
to display the decoded human-readable content:
read EC key Private-Key: (256 bit) priv: f9:04:e9:b0:05:81:f0:9b:da:64:e7:21:cc:89:a1: 3b:b6:28:39:dd:d5:a0:19:33:e4:bf:c0:2c:0b:c1: 8c:22 pub: 04:6d:54:36:45:f5:9a:d6:4e:94:f1:12:2b:9c:a2: b3:69:bf:0b:f8:58:b0:c9:7a:75:06:de:02:90:7a: d3:e2:fd:3d:65:d4:4d:b6:45:9b:92:3f:59:87:b1: 2b:ac:e2:2b:5e:18:49:3b:f3:a0:31:6a:15:e3:7b: 87:75:d4:8e:c1 ASN1 OID: prime256v1 NIST CURVE: P-256
The content above tells us that there are two 256-bit EC keys, a private and a public, and that the curve is P-256.
In the two next sections, the content above will be displayed using different encoding formats. Keep in mind that the content is still exactly what is presented above.
The content of the file key.pem itself can be displayed with the command
-----BEGIN EC PARAMETERS----- BggqhkjOPQMBBw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MHcCAQEEIPkE6bAFgfCb2mTnIcyJoTu2KDnd1aAZM+S/wCwLwYwioAoGCCqGSM49 AwEHoUQDQgAEbVQ2RfWa1k6U8RIrnKKzab8L+FiwyXp1Bt4CkHrT4v09ZdRNtkWb kj9Zh7ErrOIrXhhJO/OgMWoV43uHddSOwQ== -----END EC PRIVATE KEY-----
This format is often seen because it can be easily embedded in e-mails for example. Humans are also able to easily recognise the patterns of such a format.
ASN.1 DER format
Export in ASN.1 DER format
The keys (public and private) can be exported in ASN.1 DER format with the command
openssl ec -in key.pem -outform DER > key.der
The hexadecimal content of key.der can be retrieved with
hexdump key.der -C
30 77 02 01 01 04 20 F9 04 E9 B0 05 81 F0 9B DA 64 E7 21 CC 89 A1 3B B6 28 39 DD D5 A0 19 33 E4 BF C0 2C 0B C1 8C 22 A0 0A 06 08 2A 86 48 CE 3D 03 01 07 A1 44 03 42 00 04 6D 54 36 45 F5 9A D6 4E 94 F1 12 2B 9C A2 B3 69 BF 0B F8 58 B0 C9 7A 75 06 DE 02 90 7A D3 E2 FD 3D 65 D4 4D B6 45 9B 92 3F 59 87 B1 2B AC E2 2B 5E 18 49 3B F3 A0 31 6A 15 E3 7B 87 75 D4 8E C1
I invite you to copy the five lines above in the ASN1.DER decoder. It would be easier to follow the next part.
Decoded content of the ASN.1 DER format
The decoded content given by the ASN.1 DER decoder is
SEQUENCE (4 elem) INTEGER 1 OCTET STRING (32 byte) F904E9B00581F09BDA64E721CC89A13BB62839DDD5A01933E4BFC02C0BC18C22  (1 elem) OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve)  (1 elem) BIT STRING (520 bit) 0000010001101101010101000011011001000101111101011001101011010110010011...
The header is encoded using sequence/integer and the curve is encoded using a context-specific tag (A[x]).
The private key is encoded as
04 20 F9 04 E9 B0 05 81 F0 9B DA 64 E7 21 CC 89 A1 3B B6 28 39 DD D5 A0 19 33 E4 BF C0 2C 0B C1 8C 22
whose bytes mean:
- 04 represents the type OCTET STRING
- 20 represents the length: the following 0x20 (or 32) bytes are contained in this octet string
- the rest is the private key itself
The public key is encoded, within a context-specific tag (A1 44), as
03 42 00 04 6D 54 36 45 F5 9A D6 4E 94 F1 12 2B 9C A2 B3 69 BF 0B F8 58 B0 C9 7A 75 06 DE 02 90 7A D3 E2 FD 3D 65 D4 4D B6 45 9B 92 3F 59 87 B1 2B AC E2 2B 5E 18 49 3B F3 A0 31 6A 15 E3 7B 87 75 D4 8E C1
whose bytes mean:
- 03 represents the type BIT STRING
- 42 represents the length (short form because bit 8 is zero): the following 0x42 bytes are contained in this bit string
- 00 represents the number of unused bits at the end of the bit string; as all bits are used, there are no unused bit
- 04 means uncompressed key
- the rest is the public key itself
ASN.1 DER and PEM are easily convertible from one to the other. The PEM format is easier to display on the screen or to include in an e-mail while the ASN.1 DER format is closer to the byte representation and may be easier to handle in a lightweight software used on a microcontroller.