Add sshwot-verify

Esse commit está contido em:
Juhani Krekelä 2018-09-01 22:33:41 +03:00
commit 973ba3c63a
5 arquivos alterados com 141 adições e 6 exclusões

1
.gitignore externo
Ver arquivo

@ -6,3 +6,4 @@ __pycache__
build
sshwot-export-known-hosts
sshwot-filter
sshwot-verify

Ver arquivo

@ -1,4 +1,4 @@
BINS:=sshwot-export-known-hosts sshwot-filter
BINS:=sshwot-export-known-hosts sshwot-filter sshwot-verify
SSHWOT_EXPORT_KNOWN_HOSTS_MAIN:=src/main-export-known-hosts.py
SSHWOT_EXPORT_KNOWN_HOSTS_DEPS:=src/entry.py src/hashing.py src/process_known_hosts.py src/write_file.py
@ -6,6 +6,9 @@ SSHWOT_EXPORT_KNOWN_HOSTS_DEPS:=src/entry.py src/hashing.py src/process_known_ho
SSHWOT_FILTER_MAIN:=src/main-filter.py
SSHWOT_FILTER_DEPS:=src/entry.py src/hashing.py src/default_files.py src/read_file.py src/write_file.py
SSHWOT_VERIFY_MAIN:=src/main-verify.py
SSHWOT_VERIFY_DEPS:=src/check_fingerprint.py src/default_files.py src/entry.py src/hashing.py src/read_file.py
all: $(BINS)
sshwot-export-known-hosts: $(SSHWOT_EXPORT_KNOWN_HOSTS_MAIN) $(SSHWOT_EXPORT_KNOWN_HOSTS_DEPS)
@ -26,6 +29,15 @@ sshwot-filter: $(SSHWOT_FILTER_MAIN) $(SSHWOT_FILTER_DEPS)
cat build/$@.zip >> $@
chmod +x $@
sshwot-verify: $(SSHWOT_VERIFY_MAIN) $(SSHWOT_VERIFY_DEPS)
mkdir -p build/$@
cp $(SSHWOT_VERIFY_DEPS) build/$@/
cp $(SSHWOT_VERIFY_MAIN) build/$@/__main__.py
zip --quiet --junk-paths build/$@.zip build/$@/*.py
echo '#!/usr/bin/env python3' > $@
cat build/$@.zip >> $@
chmod +x $@
.PHONY: all clean distclean buildclean
clean:

Ver arquivo

@ -1,8 +1,8 @@
import os
def open_all():
"""open_all() → [file(rb)]
Open the default sshwot files"""
def list_all():
"""list_all() → [str]
List the default sshwot files"""
try:
homedir = os.environ['HOME']
@ -17,10 +17,20 @@ def open_all():
return []
# Read all the .sshwot files from /.sshwot by default
files = []
paths = []
for dir_entry in sshwot_dir:
if dir_entry.split('.')[-1] == 'sshwot':
path = os.path.join(sshwot_dir_path, dir_entry)
files.append(open(path, 'rb'))
paths.append(path)
return paths
def open_all():
"""open_all() → [file(rb)]
Open the default sshwot files"""
files = []
for path in list_all():
files.append(open(path, 'rb'))
return files

Ver arquivo

@ -90,6 +90,11 @@ def main():
sys.exit(1)
# We encode this, because hashing.base64dec expects bytes
fingerprint = hashing.base64dec(args.fingerprint[7:].encode())
# A valid sha256 fingerprint is 32 bytes
if len(fingerprint) < 32:
raise Exception('Fingerprint too short')
elif len(fingerprint) > 32:
raise Exception('Fingerprint too long')
else:
fingerprint = None

107
src/main-verify.py Normal file
Ver arquivo

@ -0,0 +1,107 @@
import argparse
import os
import sys
import check_fingerprint
import default_files
import entry
import hashing
import read_file
def main():
# TODO: Do known_hosts files too
parser = argparse.ArgumentParser(
description = """Search sshwot files for matching fingerprints.""",
# We want to provide help on --help, but the default thing
# also adds -h, which we don't want
add_help = False
)
# --help to get help
parser.add_argument('--help',
action = 'help',
help = 'show this help message and exit'
)
# -p/--port for port, but host is a positional argument
parser.add_argument('-p', '--port',
action = 'store',
dest = 'port',
# Automatically convert to integer
type = int,
help = 'the port associated with the given host'
)
# Host and fingerprint are required
parser.add_argument('host',
help = 'the domain to check'
)
parser.add_argument('fingerprint',
help = 'the fingerprint to check'
)
# Input file(s)
# Don't use argparse.FileType('rb'), since we want to know the names
parser.add_argument('infiles',
nargs = '*',
# The text shown for these in the usage
metavar = 'sshwot-file',
help = 'a sshwot file to search'
)
# This automatically parses the command line args for us. If it
# returns, we have correct arguments
args = parser.parse_args()
# Default to port 22
port = 22 if args.port is None else args.port
# Check the validity of the fingerprint and de-base64 it
if args.fingerprint[0:7].upper() != 'SHA256:':
print('We can only handle sha256 fingerprints (starts with SHA256:)')
sys.exit(1)
# We encode this, because hashing.base64dec expects bytes
fingerprint = hashing.base64dec(args.fingerprint[7:].encode())
# A valid sha256 fingerprint is 32 bytes
if len(fingerprint) < 32:
raise Exception('Fingerprint too short')
elif len(fingerprint) > 32:
raise Exception('Fingerprint too long')
# Use the default files if no input files were specified
if len(args.infiles) == 0:
infiles = default_files.list_all()
else:
infiles = args.infiles
# Check
for path in infiles:
# Remove the directory and the extension from the file
name = os.path.basename(path)
if name.split('.')[-1] == 'sshwot':
name = '.'.join(name.split('.')[:-1])
with open(path, 'rb') as f:
entries, file_comment = read_file.read(f)
success, fail, same_fingerprint = check_fingerprint.check(entries, args.host, port, fingerprint)
for match_host, match_port, match_comment in success:
# Use for display the same normalzed format as internally
# We do .decode() here, as it produces bytes
host_display = entry.normalize_host(match_host, match_port).decode()
print('[\x1b[32mok\x1b[0m] %s: %s: %s' % (name, host_display, match_comment))
for fail_host, fail_port, fail_comment in fail:
host_display = entry.normalize_host(fail_host, fail_port).decode()
print('[\x1b[31mfail\x1b[0m] %s: %s: %s' % (name, host_display, fail_comment))
for _, _, same_fingerprint_comment in same_fingerprint:
print('[same fingerprint] %s: (unknown host): %s' % (name, same_fingerprint_comment))
if __name__ == '__main__':
try:
main()
except Exception as err:
print('Error: %s' % err, file=sys.stderr)
sys.exit(1)