Skip to content

Commit cabc005

Browse files
committed
Add blog about crypto key formats
Signed-off-by: Daniel Bevenius <[email protected]>
1 parent 120cd1e commit cabc005

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

_posts/2023-01-25-keys.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
---
2+
title: "Is this a cryptographic key which I see before me?"
3+
date: 2023-01-25
4+
author: Daniel Bevenius
5+
---
6+
7+
Yes, it is. Really? Then what format is it in and how can I tell?
8+
9+
I've found myself in this situation a number of times and this post tries to
10+
provide some guidelines for figuring out the type and format of keys without
11+
having to go off and read some project's documentation.
12+
13+
To start off we can try to determine if the key is in a PEM format, or in
14+
DER format.
15+
16+
Keys in PEM format are in ascii and can be inspected from the
17+
command line using `cat`, or opened in any text editor. For example:
18+
```console
19+
$ cat pubkey.pem
20+
-----BEGIN PUBLIC KEY-----
21+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDTvL0PRsxoxMXfSaXu+7w0ovVNzZ
22+
k/BAIoz2GL2cPY3qZENU/+YrR92AuZFXn0jSmmvOktpAzGhnDhtidonkyA==
23+
-----END PUBLIC KEY-----
24+
```
25+
26+
If we try the same with DER format then we will get a bunch of strange
27+
characters printed. For example:
28+
```console
29+
$ cat pubkey.der
30+
;���lƌL]��^��J/T�ٓ�@"����=��dCT��+G݀��W�HҚkΒ�@�hgv���$
31+
```
32+
33+
## PEM formatted keys
34+
So we have determined that the key we have in front of us is in PEM format.
35+
Now, if we take a look at the PEM output above again:
36+
```console
37+
-----BEGIN PUBLIC KEY-----
38+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDTvL0PRsxoxMXfSaXu+7w0ovVNzZ
39+
k/BAIoz2GL2cPY3qZENU/+YrR92AuZFXn0jSmmvOktpAzGhnDhtidonkyA==
40+
-----END PUBLIC KEY-----
41+
```
42+
We can see that it has a header and the footer. Notice that there is no
43+
information about the type of public key that this file contains. This means
44+
that the information about the type of key in baked in there somewhere. So how
45+
can we find out what the type of the key?
46+
One option is to use the `openssl asn1parse` command:
47+
```
48+
$ openssl asn1parse -i -in pubkey.pem
49+
0:d=0 hl=2 l= 89 cons: SEQUENCE
50+
2:d=1 hl=2 l= 19 cons: SEQUENCE
51+
4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
52+
13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1
53+
23:d=1 hl=2 l= 66 prim: BIT STRING
54+
```
55+
And we can see, that there is an id here which is `ecPublicKey`.
56+
57+
As a rule of thumb, if there is no key type in the PEM header, then
58+
the format of the key is most probably in Subject Public Key Info (SPKI) if it
59+
is a public key, and in Public-Key Cryptography Standard 8 (pkcs8) format if it
60+
is a private key.
61+
62+
With the knowledge that the key is an Elliptic Curve (EC) public key we can use
63+
the following openssl command to inspect it:
64+
```console
65+
$ openssl ec -pubin -in pubkey.pem --text --noout
66+
read EC key
67+
Public-Key: (256 bit)
68+
pub:
69+
04:0d:3b:cb:d0:f4:6c:c6:8c:4c:5d:f4:9a:5e:ef:
70+
bb:c3:4a:2f:54:dc:d9:93:f0:40:22:8c:f6:18:bd:
71+
9c:3d:8d:ea:64:43:54:ff:e6:2b:47:dd:80:b9:91:
72+
57:9f:48:d2:9a:6b:ce:92:da:40:cc:68:67:0e:1b:
73+
62:76:89:e4:c8
74+
ASN1 OID: prime256v1
75+
NIST CURVE: P-256
76+
```
77+
78+
Some PEM keys can also be in a specific key format, in which case the type is
79+
in the header of the pem, for example:
80+
```
81+
-----BEGIN RSA PUBLIC KEY-----
82+
...
83+
-----END RSA PUBLIC KEY-----
84+
```
85+
And if needed we can use the `openssl rsa` command to inspect them further.
86+
87+
The same reasoning can be applied to private keys as well with regards to the
88+
PEM header/footer information, and in the case of private keys the `-pubin`
89+
argument to the openssl commands should left out.
90+
91+
## DER formatted keys
92+
As mentioned before we can't just print DER files as they are in binary format,
93+
but we can still use `openssl asn1parse`:
94+
```console
95+
$ openssl asn1parse -i -inform der -in pubkey.der
96+
0:d=0 hl=2 l= 89 cons: SEQUENCE
97+
2:d=1 hl=2 l= 19 cons: SEQUENCE
98+
4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
99+
13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1
100+
23:d=1 hl=2 l= 66 prim: BIT STRING
101+
```
102+
And just like with the PEM example we can use other openssl tools to inspect the
103+
key.
104+
105+
## When the guidelines fail
106+
The above seems to work for most situations, but it can fail.
107+
108+
One example of this is when openssl cannot parse the key at all. I ran into this
109+
recently with [in-toto-rs](https://github.com/in-toto/in-toto-rs), which uses
110+
the Rust [ring](https://crates.io/crates/ring) crate to handle Ed25519 keys.
111+
112+
The issue here is that `ring` supports pkcs8 version 2
113+
([RFC-5958](https://www.rfc-editor.org/rfc/rfc5958)), and OpenSSL currently only
114+
supports pkcs8 version 1 ([RFC-5208](https://www.rfc-editor.org/rfc/rfc5208)),
115+
so the openssl tools will not be able to parse keys in the version 2 format.
116+
117+
Below is an example of trying to use a version 2 formatted Ed25519 key with
118+
openssl:
119+
```console
120+
$ openssl pkey -inform der -in ed25519-1 -pubout
121+
Could not read key from ed25519-1
122+
```
123+
There is an open [openssl issue](https://github.com/openssl/openssl/issues/10468)
124+
for this.
125+
126+
Hopefully there will not be many cases like this, and we hope that the
127+
guidelines provided in this post are helpful.

0 commit comments

Comments
 (0)