|
| 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