2010-01-31 22:39known_hosts and key fingerprintsIf you have used SSH at all, you are likely to have bumped into a warning message when accessing a new host for the first time. This is because unlike with HTTPS, there is no central list of which public keys belong to which hosts (or rather, which entities should be trusted to make those connections). For example, if you access www.google.com over HTTPS in a browser, then your browser does the equivalent of downloading a public key from that host, and a certificate saying that this really is Google’s public key. This certificate itself has to be checked cryptographically, but it will have been created by one of the few central trusted points for handing out certificates, and your browser will be pre-loaded with a list of these trusted points. As SSH clients don’t tend to have pre-loaded lists like this, you are left to make the judgement yourself about whether a given SSH public (host) key belongs to a given host. One way to do this is by comparing the key’s fingerprint (which is presented in the warning message) with another copy of that fingerprint retrieved over a different medium, preferably a trusted one, such as in person. To give someone the information needed to check these fingerprint warnings, you might think of sending them a known_hosts file, which contains a list of hosts and cryptographic data about their public keys, but unfortunately this cryptographic data isn’t stored in the same format as fingerprints. Where there’s a will, there’s a script, though, and so I detail below what can be done. Generating a fingerprintThe first thing to note is that you can generate a fingerprint from a key using the ssh-keygen command. For example, you might run the command below, with the second line being the expected output: ssh-keygen -l -f ~/.ssh/id_rsa.pub 2048 aa:bb:cc:dd:ee:ff:11:22:33:44:55:66:77:88:99:00 /home/foo/.ssh/id_rsa.pub (RSA) The fingerprint would probably look more random (less memorable) though, and the username might be slightly less fictitious. It turns out, unfortunately, that this is the only way ssh-keygen lets you generate a fingerprint, and it does not, for example, let you pipe a public key in as stdin. This is a known bug (or, apparently in the minds of OpenBSD developers, a known feature) reported two years ago. As a known_hosts file typically contains more than one line, you might think that the first step in converting it into a series of fingerprints is to split it into several files, with one line in each. Wouldn’t you? Well, I did, instead of trying the (obvious in retrospect) solution of running ssh-keygen -l -f ~/.ssh/known_hosts which does everything you’d want. Making life more difficultIf one were to simply use the features of the software as intended, one would have much fewer opportunities to try writing awesome sed scripts, as well as fewer opportunities to make snide remarks about OpenBSD developers, so for the rest of this blog post please try to imagine that ssh-keygen doesn’t have the feature mentioned above. Back to splitting the file into several one-line files, then, it would seem that what is needed (as an intermediate step) is to produce output of the following form: line_one > 1 line_two > 2 line_three > 3 line_four > 4 … Here, the numbers after the > characters represent file names, and this output could be used as the input to xargs. Unfortunately, xargs isn’t able to execute commands with > in directly, so the commands would have to run by invoking the shell each time, which does sort of break the rules for one-liners. After all, one could write a one-liner which outputs a two-liner, and passes that to a shell for executing, at which point you might as well have just written a two-liner in the first place. So, now pretending that it is necessary to use sed at all, and that it isn’t cheating to invoke a shell using xargs, the command required looks something like this: cat ~/.ssh/known_hosts | something_which_generates_the_output_above | sed ‘s/.*/”echo &”/’ | xargs -n 1 sh -c which will create files whose names correspond to which line number of known_hosts their contents were taken from. The exciting part is working out what the missing command is, and it turns out that the desired textual transformation is possible with sed. I have to admit I hadn’t looked into the more obscure options to sed before, but this challenge prompted me to, and I found out about the powerful -e option. With it, you can add arbitrary and useful values to the output stream, and in particular in this case the desired values are “the entire line”, “the > character” and “the current line number”. The arguments for doing all this are: sed -n -e ‘p’ -e ‘i >’ -e ‘=’ using -n to suppress the normal output and avoid outputting two copies of the current line, or one copy in the wrong place. ConclusionThis leads to a final command of: cat ~/.ssh/known_hosts | sed -n -e ‘p’ -e ‘i >’ -e ‘=’ | xargs -n 5 | sed ‘s/.*/”echo &”/’ | xargs -n 1 sh -c which is best attempted in a temporary directory. The middle xargs is used to join the three space-separated words from each known_hosts line with the two newline-separated values added by the sed. After running this long command, the following, simpler, command can be run: ls [0-9]* | sort -n | xargs -n 1 ssh-keygen -l -f Which outputs the fingerprints in the order that the files were created, that is, the order that the lines appear in known_hosts. Now, are there any practical uses for sed? Trackbacks
Trackback specific URI for this entry
No Trackbacks
|
QuicksearchCategoriesSyndicate This BlogBlog Administration |