From 66f9e82c5ca313fb90edff6a9d1956c02c973934 Mon Sep 17 00:00:00 2001 From: jaseg Date: Wed, 14 Nov 2018 22:00:06 +0900 Subject: [PATCH] Pairing and fingerprint checking works nicely now --- USB_icon.svg | 88 +++++++++++++++++++++++++++++++++++++++++++++ hexnoise.py | 26 +++++++++++--- pairing.py | 80 ++++++++++++++++++++++++++++++++++------- secureusb_icon.png | Bin 0 -> 13260 bytes src/demo.c | 46 ++++++++++++++++++++++-- src/tracing.h | 20 +++++++++++ 6 files changed, 240 insertions(+), 20 deletions(-) create mode 100644 USB_icon.svg create mode 100644 secureusb_icon.png create mode 100644 src/tracing.h diff --git a/USB_icon.svg b/USB_icon.svg new file mode 100644 index 0000000..aeaefff --- /dev/null +++ b/USB_icon.svg @@ -0,0 +1,88 @@ + + + +image/svg+xml + + \ No newline at end of file diff --git a/hexnoise.py b/hexnoise.py index f2c1790..8ae6c4b 100755 --- a/hexnoise.py +++ b/hexnoise.py @@ -4,6 +4,8 @@ import time import enum import sys from contextlib import contextmanager, suppress, wraps +import hashlib +import secrets import serial from cobs import cobs @@ -195,20 +197,33 @@ class Magic: '''.split() class NoiseEngine: - def __init__(self, packetizer, debug=False): + def __init__(self, host_key, packetizer, debug=False): self.debug = debug self.packetizer = packetizer - self.static_local = bytes([ # FIXME - 0xbb, 0xdb, 0x4c, 0xdb, 0xd3, 0x09, 0xf1, 0xa1, 0xf2, 0xe1, 0x45, 0x69, 0x67, 0xfe, 0x28, 0x8c, - 0xad, 0xd6, 0xf7, 0x12, 0xd6, 0x5d, 0xc7, 0xb7, 0x79, 0x3d, 0x5e, 0x63, 0xda, 0x6b, 0x37, 0x5b - ]) + self.static_local = host_key self.proto = NoiseConnection.from_name(b'Noise_XX_25519_ChaChaPoly_BLAKE2s') self.proto.set_as_initiator() self.proto.set_keypair_from_private_bytes(Keypair.STATIC, self.static_local) self.proto.start_handshake() + self.handshake = self.proto.noise_protocol.handshake_state # save for later because someone didn't think self.paired = False self.connected = False + @property + def remote_fingerprint(self): + ''' Return the SHA-256 hash of the remote static key (rs). This can be used to fingerprint the remote party. ''' + return hashlib.sha256(self.handshake.rs.public_bytes).hexdigest() + + @classmethod + def generate_private_key_x25519(kls): + # This is taken from noise-c's reference implementation. This would not be needed had not cryptography/hazmat + # decided noone would ever need serialized x25519 private keys and noiseprotocol stopped just short of implementing + # key generation (who'd need that anyway, amiright?) -.- + key = list(secrets.token_bytes(32)) + key[0] &= 0xF8 + key[31] = (key[31] & 0x7F) | 0x40 + return bytes(key) + @wraps(print) def debug_print(self, *args, **kwargs): if self.debug: @@ -306,6 +321,7 @@ class NoiseEngine: yield user_input elif msg_type is ReportType.PAIRING_SUCCESS: + self.paired = True break elif msg_type is ReportType.PAIRING_ERROR: diff --git a/pairing.py b/pairing.py index 3924755..840e0bc 100755 --- a/pairing.py +++ b/pairing.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 import threading +import binascii import re +import os import serial import gi @@ -14,6 +16,7 @@ class PairingWindow(Gtk.Window): Gtk.Window.__init__(self, title='SecureHID pairing') self.noise = noise self.debug = debug + self.trusted = False self.set_border_width(10) self.set_default_size(600, 200) @@ -30,6 +33,16 @@ class PairingWindow(Gtk.Window): self.entry.set_editable(False) self.vbox.pack_start(self.entry, True, True, 0) + self.confirm_button = Gtk.Button(label='Trust this device') + self.confirm_button.connect('clicked', self.confirm_trust) + self.confirm_button.set_sensitive(False) + self.abort_button = Gtk.Button(label='Abort') + self.abort_button.connect('clicked', lambda _foo: self.destroy()) + self.bbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + self.bbox.pack_start(self.confirm_button, True, True, 0) + self.bbox.pack_start(self.abort_button, True, True, 0) + self.vbox.pack_start(self.bbox, True, True, 0) + self.add(self.vbox) self.handshaker = threading.Thread(target=self.pair, daemon=True) @@ -64,9 +77,19 @@ class PairingWindow(Gtk.Window): try: for user_input in self.noise.pairing_messages(): GLib.idle_add(update_text, user_input) - self.destroy() - except noise.ProtocolError as e: - GLib.idle_add(self.label.set_markup, f'Error: {e}!') + + GLib.idle_add(self.finish_pairing) + except hexnoise.ProtocolError as e: + GLib.idle_add(self.label.set_markup, f'Error: {e}') + + def finish_pairing(self): + self.label.set_markup(f'Step 3\n\nConfirm pairing.\n' + f'In case the device did not sound an alarm just now, confirm pairing now using the button below.') + self.confirm_button.set_sensitive(True) + + def confirm_trust(self, _foo): + self.trusted = True + self.destroy() class StatusIcon(Gtk.StatusIcon): @@ -75,12 +98,30 @@ class StatusIcon(Gtk.StatusIcon): self.set_tooltip_text('SecureHID connected') self.set_from_file('secureusb_icon.png') +def run_pairing_gui(port, baudrate, debug=False): + XDG_CONFIG_HOME = os.environ.get('XDG_CONFIG_HOME') or os.path.join(os.path.expandvars('$HOME'), '.config', 'secure_hid') + if not os.path.isdir(XDG_CONFIG_HOME): + os.mkdir(XDG_CONFIG_HOME) -def run_pairing_gui(serial, baudrate, debug=False): - ser = serial.Serial(serial, baudrate) - packetizer = hexnoise.Packetizer(serial, debug=debug) - noise = hexnoise.NoiseEngine(packetizer, debug=debug) + private_key_file = os.path.join(XDG_CONFIG_HOME, 'host_key.pem') + if not os.path.isfile(private_key_file): + with open(private_key_file, 'w') as f: + f.write(binascii.hexlify(hexnoise.NoiseEngine.generate_private_key_x25519()).decode()) + + known_devices_file = os.path.join(XDG_CONFIG_HOME, 'known_devices') + if not os.path.isfile(known_devices_file): + with open(known_devices_file, 'w') as f: + f.write('# This file contains the hex-encoded SHA-256 fingerprints of the X25519 keys of all trusted SecureHID devices\n') + + with open(private_key_file) as f: + host_key_private = binascii.unhexlify(f.read()) + + ser = serial.Serial(port, baudrate) + packetizer = hexnoise.Packetizer(ser, debug=debug) + noise = hexnoise.NoiseEngine(host_key_private, packetizer, debug=debug) noise.perform_handshake() + print('Connected.') + print('Device fingerprint:', noise.remote_fingerprint) if not noise.paired: window = PairingWindow(noise, debug=debug) @@ -88,12 +129,27 @@ def run_pairing_gui(serial, baudrate, debug=False): window.show_all() Gtk.main() - if self.noise.paired: - input_runner = threading.Thread(target=noise.uinput_passthrough, daemon=True) - input_runner.start() + if not window.trusted: + raise SystemError('User abort') - status_icon = StatusIcon() - Gtk.main() + if not noise.paired: + raise SystemError('Unknown noise error') + + with open(known_devices_file, 'a') as f: + f.write(noise.remote_fingerprint) + + else: + with open(known_devices_file) as f: + known_devices = [ l.strip() for l in f.readlines() if not l[0] == '#' ] + + if noise.remote_fingerprint not in known_devices: + raise ValueError('Remote host is untrusted but seems to trust us.') + + input_runner = threading.Thread(target=noise.uinput_passthrough, daemon=True) + input_runner.start() + + status_icon = StatusIcon() + Gtk.main() if __name__ == '__main__': import argparse diff --git a/secureusb_icon.png b/secureusb_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..97a68cf055dac9142f4a8ab891f57346e3449c9d GIT binary patch literal 13260 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 literal 0 HcmV?d00001 diff --git a/src/demo.c b/src/demo.c index abe8f19..ad73cff 100644 --- a/src/demo.c +++ b/src/demo.c @@ -175,7 +175,6 @@ int pairing_check(struct NoiseState *st, const char *buf) { if (strncasecmp(p, "and", plen)) { /* ignore "and" */ int num = -1; - /* FIXME ignore "and", ignore commata and dots */ for (int i=0; i<256; i++) { if ((!strncasecmp(p, adjectives[i], plen) && plen == strlen(adjectives[i])) || (!strncasecmp(p, nouns[i], plen) && plen == strlen(nouns[i] ))) { @@ -237,7 +236,7 @@ void pairing_input(uint8_t modbyte, uint8_t keycode) { case KEY_BACKSPACE: if (pairing_buf_pos > 0) pairing_buf_pos--; - pairing_buf[pairing_buf_pos] = '\0'; /* FIXME debug */ + pairing_buf[pairing_buf_pos] = '\0'; ch = '\b'; break; @@ -250,7 +249,7 @@ void pairing_input(uint8_t modbyte, uint8_t keycode) { if (pairing_buf_pos < sizeof(pairing_buf)-1) /* allow for terminating null byte */ { pairing_buf[pairing_buf_pos++] = ch; - pairing_buf[pairing_buf_pos] = '\0'; /* FIXME debug */ + pairing_buf[pairing_buf_pos] = '\0'; } else { LOG_PRINTF("Pairing confirmation user input buffer full\n"); @@ -356,6 +355,42 @@ struct dma_usart_file debug_out_s = { }; struct dma_usart_file *debug_out = &debug_out_s; +/* FIXME start unsafe debug code */ +void usart1_isr(void) { + if (USART1_SR & USART_SR_ORE) { /* Overrun handling */ + LOG_PRINTF("USART1 data register overrun\n"); + /* Clear interrupt flag */ + return (void)USART1_DR; + } + + uint8_t data = USART1_DR; /* This automatically acknowledges the IRQ */ + for (size_t i=0; keycode_mapping[i].kc != KEY_NONE; i++) { + struct hid_report report = {0}; + if (keycode_mapping[i].ch[0] == data) + report.modifiers = 0; + else if (keycode_mapping[i].ch[1] == data) + report.modifiers = MOD_LSHIFT; + else continue; + + report.keycodes[0] = keycode_mapping[i].kc; + pairing_parse_report(&report, 8); + break; + } + LOG_PRINTF(" %02x ", data); + if (data == 0x7f) { + struct hid_report report = {.modifiers=0, .keycodes={KEY_BACKSPACE, 0}}; + pairing_parse_report(&report, 8); + } else if (data == '\r') { + struct hid_report report = {.modifiers=0, .keycodes={KEY_ENTER, 0}}; + pairing_parse_report(&report, 8); + LOG_PRINTF("\n"); + } + + struct hid_report report = {0}; + pairing_parse_report(&report, 8); +} +/* end unsafe debug code */ + void DMA_ISR(DEBUG_USART_DMA_NUM, DEBUG_USART_DMA_STREAM_NUM)(void) { TRACING_SET(TR_DEBUG_OUT_DMA_IRQ); if (dma_get_interrupt_flag(debug_out->dma, debug_out->stream, DMA_FEIF)) { @@ -384,6 +419,11 @@ int main(void) #ifdef USART_DEBUG usart_dma_init(debug_out); + /* FIXME start unsafe debug code */ + usart_enable_rx_interrupt(debug_out->usart); + nvic_enable_irq(NVIC_USART1_IRQ); + nvic_set_priority(NVIC_USART1_IRQ, 3<<4); + /* end unsafe debug code */ #endif usart_dma_init(usart2_out); diff --git a/src/tracing.h b/src/tracing.h new file mode 100644 index 0000000..9aa9216 --- /dev/null +++ b/src/tracing.h @@ -0,0 +1,20 @@ +#ifndef __TRACING_H__ +#define __TRACING_H__ + +#include + +#define TRACING_SET(i) gpio_set(GPIOD, (1<