Creating Those Neat OpenSSH RSA Public Keys in OpenSSL (along with DSA and ECDSA Keys)

Not too long ago, I wanted to know how to generate the public-keys that OpenSSH generates, as a transitional step to understanding how to decode them. In this fashion, I might apply the knowledge, some day, to a dynamically configurable SSH platform to allow a client to connect via SSH and to authenticate against a database, such as with Github and Bitbucket.

What I did not learn while painfully trolling and reverse-engineering all of the key-generation code for ssh-keygen was that this representation is described by PKCS8. Yes, more than a little time was unnecessarily wasted. In fact, you can generate PKCS8-formatted public keys with OpenSSL.

Needless to say, I never finished reverse-engineering the code. This wasn’t so much because it became a monster, but rather the code was unfathomably ugly. It would’ve taken an enormous amount of time to hack something together, and the same amount of time to refactor it into being something elegant. It required too much of a commitment for something without an immediate need. It would’ve been quicker (and funnier) to write a FUSE wrapper to read the database, and just point OpenSSH to the mountpoint.

Generating an RSA public-key and converting it to PKCS8:

$ openssl genrsa -out mykey.pem 2048
Generating RSA private key, 2048 bit long modulus
.................+++
.........................................................................+++
e is 65537 (0x10001)

$ openssl rsa -in mykey.pem -pubout | ssh-keygen -f /dev/stdin -i -m PKCS8
writing RSA key
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCb7G51EdPBy8Np3x84DoWB5moC/ijLqDKr7ipvajNs6rICIEgX70D5S5jPAiC7HCcubHbxAEV3rRlQJpsKyiy85vKHL787IRhmHu9ILFRm+7OxYY783QCBNP+NcZJVFWsHASxm05hOB8Z4pC0d2ql/eajqUOvk83TdiJnJA3lg+3/LCTd6mfQAKybycllBZxE8W6FLXlpsva2J1hW3bxs5FcvsoqzVjboPmbXNuC0sKk5gWPq/Rrpc7E9N8bEPt/jk/CAUtUPxFtFMe48odHvXnb4YAkt2sTKHzH9BWgn4jSjPsjwYBiG2xWk0n5RcAi2GoPHCwveD2rArY+fQW8+5

The parameters to ssh-keygen simply indicate that the data is coming from STDIN, we’re doing an import, and the key-format is PKCS8.

Also, with DSA:

$ openssl dsaparam -out dsaparam.pem 2048
Generating DSA parameters, 2048 bit long prime
This could take some time
..............+.........+.................+...........+++++++++++++++++++++++++++++++++++++++++++++++++++*
.......+....+...........+......+...+................+.....+.....................+...+...................................+..........+....+..........+.........+..+.+...........+.....+..+......+.......+.....+........+.............+.....+.....+...+..+..............+++++++++++++++++++++++++++++++++++++++++++++++++++*

$ openssl gendsa dsaparam.pem -out dsa_priv.pem
Generating DSA key, 2048 bits

$ openssl dsa -in dsa_priv.pem -pubout | ssh-keygen -f /dev/stdin -i -m PKCS8
read DSA key
writing DSA key
ssh-dss AAAAB3NzaC1kc3MAAAEBAMq+cozwNedgZotyF85hu2yTtdm2EPQhZkSR3iC1qsidkO99HTt4Gpx5vrkdPs13D/RSJj7EJYwvsWSOI/OgY+OsqymR7Erqpf0NGdwzHpTz8nYe2oQNZgpaxh9iTMsfCQwdfchGT4QwewVf4fAGXRZRtmTSbNZIXOJMBiI9h6qW29DvI1TH/x4iWL3j1XA6NDGbVECYU4CE3bQUt/F3wuYTcy6JZU9JzbCLwO6lIkFQmVk4HyMODwM5YKectFh38a7r18oTosnewu9bKoiXCVmOK6RoEgiz/+Sqjxgi8GZ/LeJtLJGxPZxuUmRe8HGMprNW4VmaxoRkNgVL5LoyBNkAAAAVANmGyUL5j1iOp5ABkqKJuiq1sqEXAAABADzHG6NVAzVvZ8xFHc4G2gs56/HvkmvsyKyyQE5o1sV5Yp9yZq9LDW6egrCSRi1Ny6PeBCuSBPU1piZwObX7ZDJCvMvQZf55EONuZYVYBhYvV0Cxw0aet94Qz/u9RA9h1CKl7321d8SDWw4DDNAmQ7nS+NuS6bkAV9djpzK8WFh6PHjARF4DdefbjaYIVig8iWxxu3qju1iQQta2/XZ23OJxZb8eUE+Dgeq5Qdosb508VIRPByovRL3o9RbQ2y50Zp2OXmbib94nW1CpFzo/84RQfnP3RG2LPpmeK+KBTqbctj43B+ATvuIw5vHYj67o3P1MgOHvFpGnDt/McdUo1BoAAAEACqjSYFC9Zj5w5P2uMRhj+o9Gc7z3bYC/OphTcWhjZSs2OAF8+PGjpEjQYSpHPmbLhdbPsZpf2NAnAtz1WxCRVvOFeuSl9zdp4/JeRj3SKrxk0L/r5ZPGCkx+FdWV65sSwK8usaFHyKXeges1N8nmzTegphW3xVb4qI9OazanQ5sxqr+TzDa2yRAMK/PwW8mxyaYkofyct7uHOR0CD6/WjkYHHOEDzubPo1/nh2oKGC2eQnluNP8xBAg7Z5sqm6ZBSIWmOhpaOgIDNcwYla9gJJHrMecgbHkb6HuPcpaJvd2dCZpujFfB0+2jFUgPUsgygIMfV5mjUI3Zajmgmwtqiw==

I included DSA because generating a key-pair with DSA for general PKE is a bit more obscure. I don’t know why. It is still possible, however.

Lastly, ECDSA (elliptic-curve DSA), for completeness. This is really the one that you want to be using, if given a choice. See how cute/short the public-keys are for an algorithm with considerably-more strength? A 256-bit curve is equivalent to a traditional 3072-bit RSA key.

$ openssl ecparam -genkey -name prime256v1 -noout -out prime256v1.key.pem
$ openssl ec -in prime256v1.key.pem -pubout | ssh-keygen -f /dev/stdin -i -m PKCS8
read EC key
writing EC key
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC3FrhznL2pQ/titzgnWrbznR3ve2eNEgevog/aS7SszS9Vkq0uFefavBF4M2Txc34sIQ5TPiZxYdm9uO1siXSw=

Environment Variables Under SSH

It’s a fairly important point that if you want to define global environment variables on an Ubuntu host that will be accessible from a command executed via SSH, OpenSSH provides few options and most blogs will give users incorrect advice.

It turns out that adding variables to /etc/profile or /etc/profile.d/* is patently incorrect.

If you want to add an environment variable that any script for any user can see when executed via SSH (“ssh <user>@<host> <command>“), add it to /etc/environment. It’s similar to ~/.ssh/environment (if that’s turned-on with PermitUserEnvironment), but global.

Status of PySecure

A couple of months ago, I was looking for a Python SSH/SFTP solution. The only one that turned up and had some credibility was Paramiko. It’s pure Python, and reliable. It works great, but it hasn’t moved beyond RSA and DSA keys. This proved a problem with OpenSSH’s default now being ECDSA.

I spent some time getting into ECDSA so that I could extend Paramiko to include it. I was either going to integrate python-ecdsa or resign myself to compromising the pure-Python nature of Paramiko and calling OpenSSL. However, right as I got to this point, I thought of libssh, and, sure enough, it [allegedly] supports ECDSA as of recently. I immediately began to write a Python library to make the whole process elegant and clean.

We’re nearing completion (see PySecure). It’s easy to connect to a host via password or key. Some of the available and tested features:

  • Local and reverse port forwarding
  • Open a remote shell
  • Enumerate remote files with SFTP.
  • Manipulate a file. This object has all of the standard filesystem functions, and is also a full “file-like” object. It can be read and written like any other file.
  • Remote filesystem recursion and mirroring.

I love the last feature.

I’m currently working on the X11-forwarding, but it requires some back-and-forth with the libssh developers. It also turns out that their EC support might need some debugging. It looks like they’re actively working on it. They’ve been very responsive.