#!/usr/bin/env python # convert ~/.ssh/known_hosts entries to SSHFP (RFC4255) DNS records # Copyright: Paul Wouters # License: GNU GENERAL PUBLIC LICENSE Version 2 import os import sys import getopt import base64 import sha global all_hosts global khfile global version global hostnames def usage(): print "NAME\n knownhosts2sshfp - convert SSH's known_hosts public keys to DNS SSHFP records.\n" print "SYNOPSIS\n knownhosts2sshfp [OPTIONS] [ hostname1 hostname2 .. ]\n" print "OPTIONS\n" print " -a, --all\n Convert all known_hosts entries to SSHFP records\n" print " -f, --file\n Location of known_hosts file (default: ~/.ssh/known_hosts)\n" print " -t, --trailing-dot\n Add a trailing dot to the hostname in the SSHFP records\n" print " -h, ----help\n This message\n" print " -v, ----version\n Display version number\n" print "EXAMPLES" print " knownhosts2sshfp -a -t" print " knownhosts2sshfp -f /tmp/known_hosts bofh.xelerance.com www.openswan.org" def create_sshfp(hostname,keytype,keyblob,trailing): if keytype == "ssh-rsa": keytype = "1" else: if keytype == "ssh-dss": keytype = "2" else: return "" rawkey = base64.b64decode(keyblob) fpsha1 = sha.new(keyblob).hexdigest() # check for Reverse entries reverse = 1 parts = hostname.split(".",3) if parts[0] != hostname: for octet in parts: if not octet.isdigit(): reverse = 0 if reverse: hostname = parts[3] + "." + parts[2] + "." + parts[1] + "." + parts[0] + ".in-addr.arpa." # we don't know wether we need a trailing dot :( # eg if someone did "ssh ns.foo" we don't know if this really is "ns.foo." or "ns.foo" plus resolv.conf domainname if trailing and not reverse: hostname = hostname + "." return hostname + " IN SSHFP " + keytype + " 1 " + fpsha1 def main(argv=None): if argv is None: argv = sys.argv try: opts, args = getopt.getopt(argv[1:], "ahtvf:", ["all","help","trailing-dot","version","file"]) except getopt.error, msg: print >>sys.stderr, err.msg print >>sys.stderr, "for help use --help" sys.exit(2) # parse options khfile = "~/.ssh/known_hosts" version = "1.0" trailing = 0 all_hosts = 0 hostnames = () if not opts and not args: usage() sys.exit() for o, a in opts: if o in ("-v", "--version"): print "knownhosts2sshfp version: "+version print "by Paul Wouters " print "ftp://ftp.xelerance.com/knownhosts2sshfp/" sys.exit() if o in ("-h", "--help"): usage() sys.exit() if o in ("-t", "--trailling-dot"): trailing = 1 if o in ("-a", "--all"): all_hosts = 1 if args: print "warning: arguments ignored due to -a/--all option" else: if not args: print "error:no hostnames specified, missing -a/--all option?" if o in ("-f", "--file"): khfile = a # ok, let's do it known_hosts = os.path.expanduser(khfile) try: khfp = open(known_hosts) except IOError: print "Failed to open file "+ known_hosts entries = khfp.read() khfp.close() for line in entries.split("\n"): if line != "": records = line.split(" ") hosts = records[0].split(",") for hostname in hosts: if all_hosts or hostname in args: keytype = records[1] key64blob = records[2] record = create_sshfp(hostname,keytype,key64blob,trailing) if record: print record if __name__ == "__main__": sys.exit(main())