diff --git a/src/bootloader.c b/src/bootloader.c index 6d5eb6d5..9692f691 100644 --- a/src/bootloader.c +++ b/src/bootloader.c @@ -219,9 +219,7 @@ static uint8_t bootloader_unlocked(void) static void bootloader_blink(void) { - led_toggle(); - delay_ms(300); - led_toggle(); + led_wink(); bootloader_report_status(OP_STATUS_OK); } @@ -344,27 +342,17 @@ void bootloader_jump(void) binary_exec(app_start_addr); /* no return */ } - if (touch_button_press(DBB_TOUCH_TIMEOUT) == DBB_ERR_TOUCH_TIMEOUT) { + if (touch_button_press(TOUCH_TIMEOUT) == DBB_ERR_TOUCH_TIMEOUT) { binary_exec(app_start_addr); /* no return */ } } else { - for (int i = 0; i < 9; i++) { - led_toggle(); - delay_ms(100); - led_toggle(); - delay_ms(150); - } - led_off(); + led_abort(); + led_abort(); } // App not entered. Start USB API to receive boot commands usb_suspend_action(); udc_start(); - - for (int i = 0; i < 6; i++) { - led_toggle(); - delay_ms(100); - } - led_off(); + led_abort(); } diff --git a/src/commander.c b/src/commander.c index 28e6f840..7834a897 100644 --- a/src/commander.c +++ b/src/commander.c @@ -2,7 +2,7 @@ The MIT License (MIT) - Copyright (c) 2015-2018 Douglas J. Bakkum + Copyright (c) 2015-2019 Douglas J. Bakkum, Shift Cryptosecurity Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -424,7 +424,7 @@ static void commander_process_backup(yajl_val json_node) if (strlens(erase)) { // Erase single file - int status = touch_button_press(DBB_TOUCH_LONG); + int status = touch_button_press(TOUCH_LONG_WARN); if (status == DBB_TOUCHED) { sd_erase(CMD_backup, erase); } else { @@ -690,7 +690,8 @@ static int commander_check_change_keypath(yajl_val data, yajl_val checkpub) commander_fill_report(cmd_str(CMD_sign), NULL, DBB_ERR_SIGN_KEYPATH); return DBB_ERROR; } - if (wallet_check_keypath_prefix(keypath_utxo_0, keypath_utxo_i, keypath_depth_0) != DBB_OK) { + if (wallet_check_keypath_prefix(keypath_utxo_0, keypath_utxo_i, + keypath_depth_0) != DBB_OK) { commander_fill_report(cmd_str(CMD_sign), NULL, DBB_ERR_SIGN_KEYPATH); return DBB_ERROR; } @@ -894,7 +895,7 @@ static void commander_process_device(yajl_val json_node) if (STREQ(value, attr_str(ATTR_lock))) { if (wallet_seeded() == DBB_OK) { - int status = touch_button_press(DBB_TOUCH_LONG); + int status = touch_button_press(TOUCH_LONG_WARN); if (status == DBB_TOUCHED) { char msg[256]; memory_write_unlocked(0); @@ -1026,7 +1027,7 @@ static void commander_process_led(yajl_val json_node) } if (STREQ(value, attr_str(ATTR_blink))) { - led_abort(); + led_wink(); commander_fill_report(cmd_str(CMD_led), attr_str(ATTR_success), DBB_OK); } else { commander_fill_report(cmd_str(CMD_led), NULL, DBB_ERR_IO_INVALID_CMD); @@ -1492,11 +1493,16 @@ static int commander_touch_button(int found_cmd) if ((found_cmd == CMD_seed || found_cmd == CMD_reset) && wallet_seeded() != DBB_OK) { // Do not require touch if not yet seeded return DBB_OK; + } else if ((found_cmd == CMD_seed || found_cmd == CMD_reset) && + wallet_seeded() == DBB_OK) { + return touch_button_press(TOUCH_LONG_WARN); } else if (found_cmd == CMD_bootloader && commander_bootloader_unlocked()) { // Do not require touch to relock bootloader return DBB_OK; - } else if (found_cmd < CMD_REQUIRE_TOUCH) { - return touch_button_press(DBB_TOUCH_LONG); + } else if (found_cmd == CMD_password || found_cmd == CMD_hidden_password) { + return touch_button_press(TOUCH_LONG_PW); + } else if (found_cmd == CMD_bootloader) { + return touch_button_press(TOUCH_LONG_BOOT); } else { return DBB_OK; } @@ -1566,7 +1572,7 @@ static void commander_parse(char *command) memset(TFA_PIN, 0, sizeof(TFA_PIN)); } } - status = touch_button_press(DBB_TOUCH_LONG_BLINK); + status = touch_button_press(TOUCH_LONG_SIGN); if (status == DBB_TOUCHED) { yajl_tree_free(json_node); json_node = yajl_tree_parse(sign_command, NULL, 0); @@ -1765,7 +1771,7 @@ static int commander_check_init(const char *encrypted_command) } if (memory_report_access_err_count() >= COMMANDER_TOUCH_ATTEMPTS) { - if (touch_button_press(DBB_TOUCH_LONG) != DBB_TOUCHED) { + if (touch_button_press(TOUCH_LONG_PW) != DBB_TOUCHED) { commander_fill_report(cmd_str(CMD_input), NULL, DBB_ERR_IO_TOUCH_BUTTON); return DBB_ERROR; } diff --git a/src/ecdh.c b/src/ecdh.c index 5a86db48..21f3245d 100644 --- a/src/ecdh.c +++ b/src/ecdh.c @@ -2,7 +2,7 @@ The MIT License (MIT) - Copyright (c) 2015-2018 Douglas J. Bakkum, Stephanie Stroka, Shift Cryptosecurity + Copyright (c) 2015-2019 Douglas J. Bakkum, Stephanie Stroka, Shift Cryptosecurity Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -103,7 +103,7 @@ static void ecdh_hash_pubkey_command(const char *pair_hash_pubkey) return; } - int status = touch_button_press(DBB_TOUCH_LONG); + int status = touch_button_press(TOUCH_LONG_PAIR); if (status != DBB_TOUCHED) { utils_zero(TFA_IN_HASH_PUB, SHA256_DIGEST_LENGTH); commander_fill_report(cmd_str(CMD_ecdh), NULL, status); @@ -222,7 +222,7 @@ static void ecdh_challenge_command(void) TFA_VERIFY_BYTEPOS = (TFA_VERIFY_BYTEPOS + 1) % SIZE_ECDH_SHARED_SECRET; TFA_VERIFY_BITPOS = 1; } - led_code(two_bit + 1); + led_2FA_pairing_code(two_bit + 1); utils_zero(encryption_and_authentication_key, SHA512_DIGEST_LENGTH); utils_zero(encryption_and_authentication_challenge, SHA256_DIGEST_LENGTH); diff --git a/src/firmware.c b/src/firmware.c index 90b0056f..f11a365b 100644 --- a/src/firmware.c +++ b/src/firmware.c @@ -2,7 +2,7 @@ The MIT License (MIT) - Copyright (c) 2015-2016 Douglas J. Bakkum + Copyright (c) 2015-2019 Douglas J. Bakkum, Shift Cryptosecurity Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -139,9 +139,7 @@ int main (void) usb_suspend_action(); udc_start(); - led_on(); - delay_ms(300); - led_off(); + led_success(); while (1) { sleepmgr_enter_sleep(); diff --git a/src/flags.h b/src/flags.h index 079d6f88..3bde5c73 100644 --- a/src/flags.h +++ b/src/flags.h @@ -2,7 +2,7 @@ The MIT License (MIT) - Copyright (c) 2015-2018 Douglas J. Bakkum + Copyright (c) 2015-2019 Douglas J. Bakkum, Shift Cryptosecurity Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -157,6 +157,18 @@ X(__FORCE__) \ X(NUM) /* keep last */ +// Types of touch +#define TOUCH_TYPE_TABLE \ +X(LONG_PW) /* LONG_XXXX: brief touch 'reject'; hold 3s 'accept' */\ +X(LONG_SIGN) \ +X(LONG_WARN) \ +X(LONG_BOOT) \ +X(LONG_PAIR) \ +X(REQUIRE_LONG_TOUCH) /* placeholder - do not move */\ +X(TIMEOUT) /* any touch 'accept'; 3s timeout 'reject' */\ +X(SHORT) /* brief touch 'accept'; hold 3s 'reject' */\ +X(REQUIRE_TOUCH) /* placeholder - do not move */ + // Status and error flags #define FLAG_TABLE \ X(OK, 0, 0)\ @@ -165,11 +177,6 @@ X(ERROR_MEM, 0, 0)\ X(TOUCHED, 0, 0)\ X(NOT_TOUCHED, 0, 0)\ X(TOUCHED_ABORT, 0, 0)\ -X(TOUCH_SHORT, 0, 0) /* brief touch accept; hold 3s reject */\ -X(TOUCH_LONG, 0, 0) /* brief touch reject; hold 3s accept (led) */\ -X(TOUCH_LONG_BLINK, 0, 0) /* brief touch reject; hold 3s accept (led) */\ -X(TOUCH_TIMEOUT, 0, 0) /* touch accept; 3s timeout reject */\ -X(TOUCH_REJECT_TIMEOUT, 0, 0) /* touch reject; 3s timeout accept */\ X(KEY_PRESENT, 0, 0)\ X(KEY_ABSENT, 0, 0)\ X(RESET, 0, 0)\ @@ -255,6 +262,10 @@ enum CMD_ENUM { CMD_TABLE }; enum CMD_ATTR_ENUM { ATTR_TABLE }; #undef X +#define X(a) TOUCH_ ## a, +enum TOUCH_TYPE_ENUM { TOUCH_TYPE_TABLE }; +#undef X + #define X(a, b, c) DBB_ ## a, enum FLAG_ENUM { FLAG_TABLE }; #undef X diff --git a/src/led.c b/src/led.c index c4ff000e..b2b1016d 100644 --- a/src/led.c +++ b/src/led.c @@ -2,7 +2,7 @@ The MIT License (MIT) - Copyright (c) 2015-2016 Douglas J. Bakkum + Copyright (c) 2015-2019 Douglas J. Bakkum, Shift Cryptosecurity Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -27,6 +27,7 @@ #include "led.h" #include "drivers/config/mcu.h" +#include "flags.h" #ifndef TESTING #include #include @@ -55,54 +56,67 @@ static int ioport_get_pin_level(int led) #endif - +/** + * led_on() and led_off() should only be used internally by other led commands, + * except in touch.c to allow touch readings to get registered while the led is on. + */ void led_on(void) { ioport_set_pin_level(LED_0_PIN, IOPORT_PIN_LEVEL_LOW); } - void led_off(void) { ioport_set_pin_level(LED_0_PIN, IOPORT_PIN_LEVEL_HIGH); - } - -void led_toggle(void) +static void _short_blink(void) { - ioport_set_pin_level(LED_0_PIN, !ioport_get_pin_level(LED_0_PIN)); + led_on(); + delay_ms(100); + led_off(); + delay_ms(100); } -/** - * Blink the LED. - * Do not expose this function via API (to prevent possible security problems during TFA pairing). - */ -void led_blink(void) +static void _long_blink(void) { led_on(); delay_ms(300); led_off(); + delay_ms(300); } +void led_toggle(void) +{ + ioport_set_pin_level(LED_0_PIN, !ioport_get_pin_level(LED_0_PIN)); +} +/** + * When a LONG_TOUCH is aborted. + */ void led_abort(void) { led_off(); delay_ms(300); - for (int i = 0; i < 6; i++) { - led_on(); - delay_ms(100); - led_off(); - delay_ms(100); + for (int i = 0; i < 8; i++) { + _short_blink(); } } -void led_code(uint8_t code) +/** + * Long blink times for 2FA mobile pairing + */ +void led_2FA_pairing_code(uint8_t code) { + if (code > LED_MAX_CODE_BLINKS) { + return; + } + uint8_t i; delay_ms(500); for (i = 0; i < code; i++) { + // Use explicit blink timing for led_code() to keep it independent, + // for example of led_long(), which is used elsewhere. led_toggle(); delay_ms(300); led_toggle(); @@ -110,3 +124,74 @@ void led_code(uint8_t code) } delay_ms(500); } + +/** + * Indicates one of: + * firmware startup + * long touch 'accept' + * commander_process_led() + * u2f_device_wink() + * bootloader_blink() + */ +void led_success(void) +{ + _short_blink(); + _long_blink(); + _short_blink(); +} + +/** + * Alias of led_success for wink / blink commands. + */ +void led_wink(void) +{ + led_success(); +} + + +/** + * Indicate request to unlock the bootloader. + */ +void led_boot_unlock(void) +{ + // Pass +} + +/** + * Indicate request to sign. Do NOT use for other commands. + */ +void led_sign(void) +{ + _short_blink(); +} + +/** + * Indicate request to set device password or access hidden wallet. + */ +void led_password(void) +{ + _short_blink(); + _short_blink(); +} + +/** + * Indicate the request is potentially dangerous. + * Applies to the lock device, erase backup, and reset/re-seed device commands. + */ +void led_warn(void) +{ + _short_blink(); + _short_blink(); + _short_blink(); +} + +/** + * Indicate a request to start ECDH pairing. Do NOT use for other commands. + */ +void led_pair(void) +{ + _short_blink(); + _short_blink(); + _short_blink(); + _short_blink(); +} diff --git a/src/led.h b/src/led.h index 054ddec2..7bd07839 100644 --- a/src/led.h +++ b/src/led.h @@ -2,7 +2,7 @@ The MIT License (MIT) - Copyright (c) 2015-2016 Douglas J. Bakkum + Copyright (c) 2015-2019 Douglas J. Bakkum, Shift Cryptosecurity Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -33,15 +33,20 @@ #define LED_MAX_CODE_BLINKS 4 -#define LED_MAX_BLINK_SETS 6 void led_on(void); void led_off(void); +void led_warn(void); +void led_pair(void); +void led_success(void); +void led_wink(void); +void led_password(void); +void led_sign(void); +void led_boot_unlock(void); void led_toggle(void); -void led_blink(void); void led_abort(void); -void led_code(uint8_t code); +void led_2FA_pairing_code(uint8_t code); #endif diff --git a/src/touch.c b/src/touch.c index a1ab54c2..3002d08a 100644 --- a/src/touch.c +++ b/src/touch.c @@ -2,7 +2,7 @@ The MIT License (MIT) - Copyright (c) 2015-2016 Douglas J. Bakkum + Copyright (c) 2015-2019 Douglas J. Bakkum, Shift Cryptosecurity Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -68,17 +68,7 @@ void touch_init(void) uint8_t touch_button_press(uint8_t touch_type) { #ifdef TESTING - if (touch_type == DBB_TOUCH_REJECT_TIMEOUT) { - // Simulate touch sequence for ecdh led blink coding - static uint8_t touch_short_count = 0; - if (!touch_short_count) { - touch_short_count++; - return DBB_ERR_TOUCH_TIMEOUT; - } else { - touch_short_count = 0; - return DBB_ERR_TOUCH_ABORT; - } - } + (void) touch_type; commander_fill_report(cmd_str(CMD_touchbutton), flag_msg(DBB_WARN_NO_MCU), DBB_OK); return DBB_TOUCHED; #else @@ -93,17 +83,11 @@ uint8_t touch_button_press(uint8_t touch_type) } - if (touch_type != DBB_TOUCH_LONG && - touch_type != DBB_TOUCH_SHORT && - touch_type != DBB_TOUCH_LONG_BLINK && - touch_type != DBB_TOUCH_REJECT_TIMEOUT && - touch_type != DBB_TOUCH_TIMEOUT) { + if (touch_type >= TOUCH_REQUIRE_TOUCH) { return DBB_ERROR; } - if (touch_type != DBB_TOUCH_REJECT_TIMEOUT) { - led_on(); - } + led_on(); // Make higher priority so that we can timeout NVIC_SetPriority(SysTick_IRQn, 4); @@ -111,18 +95,34 @@ uint8_t touch_button_press(uint8_t touch_type) qt_led_toggle_ms = QTOUCH_TOUCH_BLINK_OFF; systick_current_time_ms = 0; while (systick_current_time_ms < QTOUCH_TOUCH_TIMEOUT || - touch_type == DBB_TOUCH_SHORT || - touch_type == DBB_TOUCH_LONG_BLINK || - touch_type == DBB_TOUCH_LONG) { + touch_type == TOUCH_SHORT || + touch_type < TOUCH_REQUIRE_LONG_TOUCH) { if (systick_current_time_ms > QTOUCH_TOUCH_TIMEOUT_HARD) { break; } - if (touch_type == DBB_TOUCH_LONG_BLINK && systick_current_time_ms > qt_led_toggle_ms) { - led_off(); + // Send an intermittent blink indicator for each touch type. + if (touch_type < TOUCH_REQUIRE_LONG_TOUCH && systick_current_time_ms > qt_led_toggle_ms) { if (systick_current_time_ms > qt_led_toggle_ms + QTOUCH_TOUCH_BLINK_OFF) { qt_led_toggle_ms += QTOUCH_TOUCH_BLINK_ON + QTOUCH_TOUCH_BLINK_OFF; + switch (touch_type) { + case TOUCH_LONG_SIGN: + led_sign(); + break; + case TOUCH_LONG_BOOT: + led_boot_unlock(); + break; + case TOUCH_LONG_PW: + led_password(); + break; + case TOUCH_LONG_PAIR: + led_pair(); + break; + default: + led_warn(); + break; + } led_on(); } } @@ -152,24 +152,21 @@ uint8_t touch_button_press(uint8_t touch_type) // If released before exit_time_ms for: // - DBB_TOUCH_LONG_BLINK, answer is 'reject' // - DBB_TOUCH_LONG, answer is 'reject' - // - DBB_TOUCH_SHORT, answer is 'accept' - if (touch_type == DBB_TOUCH_LONG_BLINK || touch_type == DBB_TOUCH_LONG) { + // - TOUCH_SHORT, answer is 'accept' + if (touch_type < TOUCH_REQUIRE_LONG_TOUCH) { pushed = DBB_TOUCHED_ABORT; break; - } else if (touch_type == DBB_TOUCH_SHORT) { + } else if (touch_type == TOUCH_SHORT) { pushed = DBB_TOUCHED; break; } - } else if (touch_type == DBB_TOUCH_LONG_BLINK || touch_type == DBB_TOUCH_LONG) { + } else if (touch_type < TOUCH_REQUIRE_LONG_TOUCH) { pushed = DBB_TOUCHED; - } else if (touch_type == DBB_TOUCH_SHORT) { + } else if (touch_type == TOUCH_SHORT) { pushed = DBB_TOUCHED_ABORT; - } else if (touch_type == DBB_TOUCH_REJECT_TIMEOUT) { - pushed = DBB_TOUCHED_ABORT; - break; - } else if (touch_type == DBB_TOUCH_TIMEOUT) { + } else if (touch_type == TOUCH_TIMEOUT) { // If touched before exit_time_ms for: - // - DBB_TOUCH_TIMEOUT, answer is 'accept' + // - TOUCH_TIMEOUT, answer is 'accept' pushed = DBB_TOUCHED; break; } @@ -182,10 +179,8 @@ uint8_t touch_button_press(uint8_t touch_type) NVIC_SetPriority(SysTick_IRQn, 15); if (pushed == DBB_TOUCHED) { - if (touch_type == DBB_TOUCH_LONG_BLINK || touch_type == DBB_TOUCH_LONG) { - led_off(); - delay_ms(300); - led_blink(); + if (touch_type < TOUCH_REQUIRE_LONG_TOUCH) { + led_success(); } led_off(); return DBB_TOUCHED; diff --git a/src/u2f_device.c b/src/u2f_device.c index b4c4517b..edbbf0b6 100644 --- a/src/u2f_device.c +++ b/src/u2f_device.c @@ -2,7 +2,7 @@ The MIT License (MIT) - Copyright (c) 2016-2017 Douglas J. Bakkum, Shift Devices AG + Copyright (c) 2016-2019 Douglas J. Bakkum, Shift Cryptosecurity Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -199,7 +199,7 @@ static void u2f_device_register(const USB_APDU *a) return; } - if (touch_button_press(DBB_TOUCH_TIMEOUT) != DBB_TOUCHED) { + if (touch_button_press(TOUCH_TIMEOUT) != DBB_TOUCHED) { u2f_send_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; @@ -282,7 +282,6 @@ static void u2f_device_hijack(const U2F_AUTHENTICATE_REQ *req) report = empty_report; report_len = sizeof(empty_report); } else { - led_blink(); report = commander(hijack_cmd); report_len = MIN(strlens(report) + sizeof(empty_report), COMMANDER_REPORT_SIZE); memmove(report + 1 + U2F_CTR_SIZE, report, MIN(strlens(report), @@ -354,7 +353,7 @@ static void u2f_device_authenticate(const USB_APDU *a) return; } - if (touch_button_press(DBB_TOUCH_TIMEOUT) != DBB_TOUCHED) { + if (touch_button_press(TOUCH_TIMEOUT) != DBB_TOUCHED) { u2f_send_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; @@ -414,7 +413,7 @@ static void u2f_device_wink(const uint8_t *buf, uint32_t len) return; } - led_blink(); + led_wink(); USB_FRAME f; utils_zero(&f, sizeof(f)); diff --git a/src/wallet.c b/src/wallet.c index 2bfc5970..d890ffe9 100644 --- a/src/wallet.c +++ b/src/wallet.c @@ -2,7 +2,7 @@ The MIT License (MIT) - Copyright (c) 2015-2016 Douglas J. Bakkum + Copyright (c) 2015-2019 Douglas J. Bakkum, Shift Cryptosecurity Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -144,7 +144,8 @@ int wallet_check_keypath_prefix(const uint32_t const uint32_t keypath1[MAX_PARSE_KEYPATH_LEVEL], const uint32_t depth) { - if (depth < MIN_WALLET_DEPTH || !MEMEQ(keypath0, keypath1, (depth - 2) * sizeof(uint32_t))) { + if (depth < MIN_WALLET_DEPTH || + !MEMEQ(keypath0, keypath1, (depth - 2) * sizeof(uint32_t))) { return DBB_ERROR; } return DBB_OK;