sshwot/src/check_fingerprint.py

60 lines
2.1 KiB
Python

import enum
from collections import namedtuple
import entry
import hashing
# Result(str/None, u16/None, str)
Result = namedtuple('Result', ['domain', 'port', 'comment'])
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.
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
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:
normalized_hosts[22] = entry.normalize_host(domain, 22)
successes = []
fails = []
same_fingerprint = []
for possible_match in entries:
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
successes.append(Result(domain, current_port, possible_match.comment))
any_host_matched = True
else:
# Fingerprint different, it fails
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))
return successes, fails, same_fingerprint