How does one convert between SSH keys and SSL keys?
Let us first divide the problem into two parts.
Private Key available
The simpler case is when you have the private key. In this
case, SSH private key is in fact the same as an SSL key.
If the key was generated using ssh-keygen -t rsa
then it is a 2048-bit RSA private key for SSL.
It follows that it rather trivial to extract an SSH public key from an SSL private key. You just run
ssh-keygen -f private_key_file -y > ssh.pub
This will prompt you for a password if your key is kept
encrypted as it should be. The ssh.pub
file contains
the SSH public key.
It is similarly easy to extract the SSL public key from an SSH private key.
openssl rsa -in private_key_file -pubout -out ssl.pub
will create ssl.pub
containing the SSL public
key.
Private Key un-available
The more difficult case is when you only have the SSH public key or an SSL certificate. In this case one should be able to extract the SSL public key from the SSL certificate and interchange between the SSL and SSH public keys.
The extraction of the public key from the SSL certificate is achieved by the command1
openssl x509 -in cert_file -pubkey -noout > ssl.pub
which extracts the public key from the SSL certificate.
The Mess
The second part, i. e. converting between SSH and SSL public keys, has a rather tortuous route given that the data contained in the public keys is the same!
First of all one needs some somewhat un-common utilities
(which are currently only in sid
on Debian)
apt-get install lsh-utils
This pulls in the nettle-bin
package which also
contains some useful programs. So one can run
ssh-conv < ssh.pub | sexp-conv
To get a look at the "real stuff" inside the SSH public key.
If ssl.pub
and ssh.pub
refer to the
same key then you will see that the output of
ssh-conv < ssh.pub | sexp-conv -s hex
and
openssl rsa -in ssl.pub -pubin -noout -text
are entirely similar and clearly inter-convertible. The same
applies to DSA keys with the openssl rsa
replaced by
openssl dsa
in the command above.
One could easily write a script that would massage one of these text formats into the other. Luckily, someone did it for us. So we run
sed -e'1d' -e'$d' < /tmp/test.pub | \
pkcs1-conv --public-key-info --base-64 | \
sexp-conv | \
sed -e'1s/(rsa/(rsa-pkcs1-sha1/' | \
sexp-conv -s transport
The output of this is identical to the output of
ssh-conv < ssh.pub | sexp-conv -s transport
Hence, we have reached the point of convertibility! The full pipeline is
sed -e'1d' -e'$d' \< ssl.pub | \
pkcs1-conv --public-key-info --base-64 | \
sexp-conv | \
sed -e'1s/(rsa/(rsa-pkcs1-sha1/' | \
sexp-conv -s transport | \
lsh-export-key --openssh > newssh.pub
Conclusion
Having got this far the reader may be wondering what the purpose of this (lack of) exercise is --- other than writing complex pipelines instead of real code.
- Answer:
-
Since you can now convert certificates into SSH public keys you can check these certificates against the SSH public keys that became bad as a consequence of the recent fiasco.
Moreover, to do this you do not need to have access to the private keys of the certificates.
So help out a friend by checking whether their SSL certificate is based on a weak key. However, note that the above procedure doesn't work for DSA keys. In addition, the publicly available tests for bad keys do not work with 1024-bit RSA keys. If your friend has been using the letter type of keys on a Debian "etch" system then you should advise them to change keys anyway (and switch to 2048-bit RSA in the process).