From 050d49a56bc54c78c3fc1f4f125b09634d6c5b83 Mon Sep 17 00:00:00 2001 From: jaseg Date: Thu, 8 Nov 2018 15:41:46 +0900 Subject: Noise integration compiles --- src/demo.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 169 insertions(+), 3 deletions(-) (limited to 'src/demo.c') diff --git a/src/demo.c b/src/demo.c index fdd61e7..a4debe5 100644 --- a/src/demo.c +++ b/src/demo.c @@ -25,6 +25,8 @@ #include "usbh_lld_stm32f4.h" /// provides low level usb host driver for stm32f4 platform #include "usbh_driver_hid.h" /// provides generic usb device driver for Human Interface Device (HID) #include "usbh_driver_hub.h" /// provides usb full speed hub driver (Low speed devices on hub are not supported) +#include "cobs.h" +#include "rand_stm32.h" // STM32f407 compatible #include @@ -41,6 +43,11 @@ #include #include +#include + +void _fini(void); +int generate_identity_key(void); + static inline void delay_ms_busy_loop(uint32_t ms) { for (volatile uint32_t i = 0; i < 14903*ms; i++); } @@ -59,6 +66,8 @@ static void clock_setup(void) { rcc_periph_clock_enable(RCC_TIM6); rcc_periph_clock_enable(RCC_DMA2); rcc_periph_clock_enable(RCC_DMA1); + + rcc_periph_clock_enable(RCC_RNG); } @@ -182,6 +191,96 @@ void dma1_stream6_isr(void) { schedule_dma(usart2_out); } +static struct cobs_decode_state host_cobs_state; +#define CURVE25519_KEY_LEN 32 +#define MAX_HOST_PACKET_SIZE 256 +static volatile uint8_t host_packet_buf[MAX_HOST_PACKET_SIZE]; +static volatile uint8_t host_packet_length = 0; + +void usart2_isr(void) { + if (USART2_SR & USART_SR_ORE) { /* Overrun handling */ + LOG_PRINTF("USART2 data register overrun\n"); + /* Clear interrupt flag */ + (void)USART2_DR; /* FIXME make sure this read is not optimized out */ + return; + } + + uint8_t data = USART2_DR; /* This automatically acknowledges the IRQ */ + + if (host_packet_length) { + LOG_PRINTF("USART2 COBS buffer overrun\n"); + return; + } + + ssize_t rv = cobs_decode_incremental(&host_cobs_state, (char *)host_packet_buf, sizeof(host_packet_buf), data); + if (rv == -2) { + LOG_PRINTF("Host interface COBS packet too large\n"); + } else if (rv < 0) { + LOG_PRINTF("Host interface COBS framing error\n"); + } else if (rv > 0) { + host_packet_length = rv; + } /* else just return and wait for next byte */ +} + +static uint8_t local_key[CURVE25519_KEY_LEN]; +NoiseCipherState *tx_cipher, *rx_cipher; + +#define HANDLE_NOISE_ERROR(x, msg) do { \ + err = x; \ + if (err != NOISE_ERROR_NONE) { \ + char errbuf[256]; \ + noise_strerror(err, errbuf, sizeof(errbuf)); \ + LOG_PRINTF("Error " msg ": %s\n", errbuf); \ + goto errout; \ + } \ + } while(0); + +static NoiseHandshakeState *start_protocol_handshake(void) { + /* TODO Noise-C is nice for prototyping, but we should really get rid of it for mostly two reasons: + * * We don't need cipher/protocol agility, and by baking the final protocol into the firmware we can save a lot + * of flash space by not including all the primitives we don't need as well as noise's dynamic protocol + * abstraction layer. + * * Noise-c is not very embedded-friendly, in particular it uses malloc and free. We should be able to run + * everything with statically allocated buffers instead. + */ + NoiseHandshakeState *handshake; + int err; + + HANDLE_NOISE_ERROR(noise_init(), "initializing noise"); + + HANDLE_NOISE_ERROR(noise_handshakestate_new_by_name(&handshake, "Noise_XX_25519_ChaChaPoly_BLAKE2s", NOISE_ROLE_RESPONDER), "instantiating handshake pattern"); + + NoiseDHState *dh = noise_handshakestate_get_local_keypair_dh(handshake); + HANDLE_NOISE_ERROR(noise_dhstate_set_keypair_private(dh, local_key, sizeof(local_key)), "loading local private keys"); + + HANDLE_NOISE_ERROR(noise_handshakestate_start(handshake), "starting handshake"); + + return handshake; + +errout: + noise_handshakestate_free(handshake); + return 0; +} + +int generate_identity_key(void) { + NoiseDHState *dh; + int err; + + HANDLE_NOISE_ERROR(noise_dhstate_new_by_name(&dh, "25519"), "creating dhstate for key generation"); + HANDLE_NOISE_ERROR(noise_dhstate_generate_keypair(dh), "generating key pair"); + + uint8_t unused[CURVE25519_KEY_LEN]; /* the noise api is a bit bad here. */ + memset(local_key, 0, sizeof(local_key)); + + HANDLE_NOISE_ERROR(noise_dhstate_get_keypair(dh, local_key, sizeof(local_key), unused, sizeof(unused)), "saving key pair"); + + return 0; + +errout: + if (dh) + noise_dhstate_free(dh); + return -1; +} int main(void) { @@ -194,12 +293,17 @@ int main(void) #ifdef USART_DEBUG usart_dma_init(debug_out); #endif + usart_dma_init(usart2_out); + cobs_decode_incremental_initialize(&host_cobs_state); + usart_enable_rx_interrupt(USART2); + nvic_enable_irq(NVIC_USART2_IRQ); LOG_PRINTF("\n==================================\n"); LOG_PRINTF("SecureHID device side initializing\n"); LOG_PRINTF("==================================\n"); + LOG_PRINTF("Initializing USB...\n"); hid_driver_init(&hid_config); hub_driver_init(); @@ -212,7 +316,18 @@ int main(void) */ usbh_init(lld_drivers, device_drivers); - LOG_PRINTF("USB init complete\n"); + LOG_PRINTF("Initializing RNG...\n"); + rand_init(); + + /* FIXME only run this on first boot and persist key in backup sram. Allow reset via jumper-triggered factory reset function. */ + LOG_PRINTF("Generating identity key...\n"); + if (generate_identity_key()) + LOG_PRINTF("Error generating identiy key\n"); + + LOG_PRINTF("Starting noise protocol handshake...\n"); + NoiseHandshakeState *handshake = start_protocol_handshake(); + if (!handshake) + LOG_PRINTF("Error starting protocol handshake.\n"); int i = 0, j = 0; while (23) { @@ -220,10 +335,61 @@ int main(void) delay_ms_busy_loop(1); /* approx 1ms interval between usbh_poll() */ if (i++ == 1000) { i = 0; - const char *s = "foobarfoobarfoobarfoobarfoobar"; - send_packet(usart2_out, (uint8_t *)s, strlen(s)); LOG_PRINTF("Loop iteration %d\n", 1000*(j++)); } + + if (handshake) { +#define MAX_MESSAGE_LEN 256 + uint8_t message[MAX_MESSAGE_LEN]; + NoiseBuffer noise_msg; + /* Run the protocol handshake */ + switch (noise_handshakestate_get_action(handshake)) { + case NOISE_ACTION_WRITE_MESSAGE: + /* Write the next handshake message with a zero-length payload */ + noise_buffer_set_output(noise_msg, message, sizeof(message)); + if (noise_handshakestate_write_message(handshake, &noise_msg, NULL) != NOISE_ERROR_NONE) { + LOG_PRINTF("Error writing handshake message\n"); + noise_handshakestate_free(handshake); + handshake = NULL; + } + send_packet(usart2_out, message, noise_msg.size); + break; + + case NOISE_ACTION_READ_MESSAGE: + if (host_packet_length > 0) { + /* Read the next handshake message and discard the payload */ + noise_buffer_set_input(noise_msg, (uint8_t *)host_packet_buf, host_packet_length); + if (noise_handshakestate_read_message(handshake, &noise_msg, NULL) != NOISE_ERROR_NONE) { + LOG_PRINTF("Error reading handshake message\n"); + noise_handshakestate_free(handshake); + handshake = NULL; + } + } + break; + + case NOISE_ACTION_SPLIT: + if (noise_handshakestate_split(handshake, &tx_cipher, &rx_cipher) != NOISE_ERROR_NONE) { + LOG_PRINTF("Error splitting handshake state\n"); + } else { + LOG_PRINTF("Noise protocol handshake completed successfully\n"); + } + + noise_handshakestate_free(handshake); + handshake = NULL; + break; + + default: + LOG_PRINTF("Noise protocol handshake failed\n"); + noise_handshakestate_free(handshake); + handshake = 0; + break; + } + } } return 0; } + +void _fini() { + while (1); +} + -- cgit