sshwot/src/check_fingerprint.py

60 lines
2.1 KiB
Python
Raw Normal View History

import enum
2018-08-31 17:21:08 +00:00
from collections import namedtuple
import entry
import hashing
2018-08-31 17:21:08 +00:00
# Result(str/None, u16/None, str)
Result = namedtuple('Result', ['domain', 'port', 'comment'])
2018-08-31 17:21:08 +00:00
def check(entries, domain, port, fingerprint):
"""check([Entry], str, u16, bytes[32]) → ([Result]: successes, [Result]: fails, [Result]: same_fingerprint)
Checks if the given host is found with the given fingerprint.
2018-08-31 17:21:08 +00:00
successes contains ones where both the host and the fingerprint match.
fails contains ones where host matches but the fingerprint doesn't.
same_fingerprint contains ones where fingerprint matches but the
host doesn't. Their .domain and .port will be None"""
assert type(entries) == list and all(type(i) == entry.Entry for i in entries)
assert type(domain) == str
assert type(port) == int and 0 <= port <= (1<<16) - 1
assert type(fingerprint) == bytes and len(fingerprint) == 32
# Normalize the host here, so we don't have to do it every time we
# check for a possible match
2018-08-31 17:21:08 +00:00
normalized_hosts = {port: entry.normalize_host(domain, port)}
# If we are looking at non-22 port, also check the general form of
# the host without a port specifier. This seems to be how OpenSSH
# does it too
if port != 22:
2018-08-31 17:21:08 +00:00
normalized_hosts[22] = entry.normalize_host(domain, 22)
2018-08-29 10:29:38 +00:00
successes = []
fails = []
2018-08-31 17:21:08 +00:00
same_fingerprint = []
for possible_match in entries:
2018-08-31 17:21:08 +00:00
any_host_matched = False
for current_port, normalized_host in normalized_hosts.items():
hashed_host = hashing.hash_with_salt(normalized_host, possible_match.salt)
if hashed_host == possible_match.hashed_host:
if fingerprint == possible_match.fingerprint:
# Fingerprint matches, it passes
2018-08-31 17:21:08 +00:00
successes.append(Result(domain, current_port, possible_match.comment))
any_host_matched = True
else:
# Fingerprint different, it fails
2018-08-31 17:21:08 +00:00
fails.append(Result(domain, current_port, possible_match.comment))
if not any_host_matched and fingerprint == possible_match.fingerprint:
# Host is not the same, but the fingerprint
# matches
same_fingerprint.append(Result(None, None, possible_match.comment))
2018-08-31 17:21:08 +00:00
return successes, fails, same_fingerprint