60 lines
2.1 KiB
Python
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
|