77 lines
2.1 KiB
Python
77 lines
2.1 KiB
Python
import base64
|
|
import hashlib
|
|
|
|
import entry
|
|
|
|
class KnownHostsSyntaxError(Exception): pass
|
|
|
|
class HashedHostError(Exception): pass
|
|
|
|
def process_line(line):
|
|
"""process_line(str) → [Entry]
|
|
Given a string containing one line of .ssh/known_hosts file, create
|
|
a list of Entries based on it."""
|
|
assert type(line) == str
|
|
|
|
# Remove trailing newlines
|
|
if line[-1] == '\n': line = line[:-1]
|
|
|
|
# Just skip over empty lines
|
|
if line == '': return []
|
|
|
|
# Each line has host(s), algorithm, public key, and possibly one
|
|
# more optional field
|
|
fields = line.split(' ')
|
|
if len(fields) != 3 and len(fields) != 4:
|
|
raise KnownHostsSyntaxError('Weird number of fields on a line (%i)' % len(fields))
|
|
|
|
hosts, algorithm, public_key = fields[0:3]
|
|
|
|
# Generate public key fingerprint
|
|
# The key is stored base64 encoded, so decode it first
|
|
try:
|
|
public_key_binary = base64.b64decode(public_key, validate = True)
|
|
except (ValueError, base64.binascii.Error) as err:
|
|
raise KnownHostsSyntaxError('Malformed public key: %s' % public_key) from err
|
|
|
|
# Fingerprint is sha256 hash of the public key
|
|
m = hashlib.sha256()
|
|
m.update(public_key_binary)
|
|
fingerprint = m.digest()
|
|
|
|
# There can be several hosts separated with a comma
|
|
entries = []
|
|
for host in hosts.split(','):
|
|
# A host can't be empty
|
|
if len(host) == 0:
|
|
raise KnownHostsSyntaxError('An empty host')
|
|
|
|
# If the host begins with '|' it's hashed
|
|
# We cannot deal with those
|
|
if host[0] == '|':
|
|
raise HashedHostError('Cannot deal with hashed hosts')
|
|
|
|
# If the host behins with '[' it's a nonstandard port
|
|
# The format will be [domain]:port
|
|
# Extractt both
|
|
# Otherwise, default to port 22
|
|
if host[0] == '[':
|
|
host_and_port = host[1:].split(']:')
|
|
if len(host_and_port) != 2:
|
|
raise KnownHostsSyntaxError('Unrecognized host format: ' + host)
|
|
|
|
domain = host_and_port[0]
|
|
try:
|
|
port = int(host_and_port[1])
|
|
except ValueError:
|
|
raise KnownHostsSyntaxError('Malformed port: %i' % port)
|
|
|
|
else:
|
|
domain = host
|
|
port = 22
|
|
|
|
# Default to no comment
|
|
entries.append(entry.create_entry(domain, port, fingerprint, ''))
|
|
|
|
return entries
|