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.
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.
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
cat key.pem
and is
-----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.
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
and is
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.
The decoded content given by the ASN.1 DER decoder is
SEQUENCE (4 elem) INTEGER 1 OCTET STRING (32 byte) F904E9B00581F09BDA64E721CC89A13BB62839DDD5A01933E4BFC02C0BC18C22 [0] (1 elem) OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve) [1] (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:
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:
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.
Schreiben Sie einen Kommentar