OpenSSH public key file format?
I am having trouble parsing an OpenSSH public key file. I believe (but I am not certain) the format is detailed in RFC 4253, The Secure Shell (SSH) Transport Layer Protocol Section 6.6, Public Key Algorithms.
In the case of a RSA key, the RFC says:
The "ssh-rsa" key format has the following specific encoding:
string "ssh-rsa" mpint e mpint n
Here the 'e' and 'n' parameters form the signature key blob.
Here is where the problems begin. The document does not provide a grammar, and does not define what string
and mpint
are. Which leads to:
$ cat rsa.ssh.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDSNM6RVVmwN3y0NurIQnmZgjcx5K5zzZu9nDqopW4J
In/mr8OYZI3heSJShnIM8EThvwVGXXXyyJVRQAvRHYFO4DxS6bufSNWr3BxBGaGYlYxI9mgvQnT6+MzE
3oZyEMdQNPlV5VfbileXlrPoAk1TkGdVdhwdLJMI2B4KUyMf+Q== jwalton@test
And then:
$ echo 'AAAAB3NzaC1yc2EAAAADAQABAAAAgQDSNM6RVVmwN3y0NurIQnmZgjcx5K5zzZu9nDqopW4
JIn/mr8OYZI3heSJShnIM8EThvwVGXXXyyJVRQAvRHYFO4DxS6bufSNWr3BxBGaGYlYxI9mgvQnT6+M
zE3oZyEMdQNPlV5VfbileXlrPoAk1TkGdVdhwdLJMI2B4KUyMf+Q==' | base64 -d > rsa.bin
And finally:
$ hexdump -C rsa.bin
00000000 00 00 00 07 73 73 68 2d 72 73 61 00 00 00 03 01 |....ssh-rsa.....|
00000010 00 01 00 00 00 81 00 d2 34 ce 91 55 59 b0 37 7c |........4..UY.7||
00000020 b4 36 ea c8 42 79 99 82 37 31 e4 ae 73 cd 9b bd |.6..By..71..s...|
00000030 9c 3a a8 a5 6e 09 22 7f e6 af c3 98 64 8d e1 79 |.:..n.".....d..y|
00000040 22 52 86 72 0c f0 44 e1 bf 05 46 5d 75 f2 c8 95 |"R.r..D...F]u...|
00000050 51 40 0b d1 1d 81 4e e0 3c 52 e9 bb 9f 48 d5 ab |[email protected].<R...H..|
00000060 dc 1c 41 19 a1 98 95 8c 48 f6 68 2f 42 74 fa f8 |..A.....H.h/Bt..|
00000070 cc c4 de 86 72 10 c7 50 34 f9 55 e5 57 db 8a 57 |....r..P4.U.W..W|
00000080 97 96 b3 e8 02 4d 53 90 67 55 76 1c 1d 2c 93 08 |.....MS.gUv..,..|
00000090 d8 1e 0a 53 23 1f f9 |...S#..|
00000097
So there seems to be undocumented fields in the public key file. The RFC does not appear to refer to other documents for the definitions of the fields. The RFC also fails to document the private key file. I am stalled at the moment.
Where does OpenSSH define the fields used in its key files?
Solution 1:
So there seems to be undocumented fields in the public key file. The RFC does not appear to refer to other documents for the definitions of the fields.
They are defined in RFC 4251 "The Secure Shell (SSH) Protocol Architecture", section 5.
The RFC also fails to document the private key file.
The SSH protocol does not document any file formats at all. It only defines serialization of public keys when they are sent as part of the SSH protocol (e.g. when a client sends SSH_MSG_USERAUTH to offer its public key).
So because the private key is never sent over the network as part of SSH protocol, its serialization does not need to be part of the spec either – only the signatures made by that key need to have a defined format.
Where does OpenSSH define the fields used in its key files?
For public keys, OpenSSH most likely has chosen to re-use the same RFC 4253 format for storing them in files because it's the most convenient option (i.e. it already has the serialization code anyway). It's not required to do so by spec, and indeed most other clients have their own formats.
Because OpenSSH uses OpenSSL for the cryptographic code (algorithms, key generation), previous versions of OpenSSH simply stored private keys using whatever format the OpenSSL functions offered – which was DER-serialized PKCS#1 'RSAPrivateKey' format (also commonly known as PEM format) most of the time. See RFC 3447 for the ASN.1 definition of the format.
(OpenSSL itself now prefers storing private keys in PKCS#8 format, which means OpenSSH can load those keys as well, although it does not write them. See RFC 5208 for the ASN.1 definition of the container format.)
You can recognize the PKCS#1 format by the "BEGIN RSA PRIVATE KEY" header, and PKCS#8 by the "BEGIN PRIVATE KEY" header. You can use dumpasn1
or openssl asn1parse
to investigate their contents, as well as openssl rsa
and openssl pkey
.
Recent versions of OpenSSH have invented a new, custom format for private key files. The container format is documented in PROTOCOL.key, and the individual key formats are [probably?] the same as used by ssh-agent, which is documented in draft-miller-ssh-agent. This format uses the RFC 4251 data types.
Other SSH software often has different formats. For example, PuTTY uses "PPK" format (which is documented somewhere, I remember, but oddly I can't find where) for storing both public and private keys. Its Public-Lines
field stores the same RFC 4253 public key, while the private fields are custom.
There is also RFC 4716, which claims to be "The SSH Public Key Format", but it is not generally considered to be an integral part of SSH. (SSH.COM, SecureCRT, and probably MultiNet SSH use this format.)