From 990e32275fb1025037ffe274f66a33758d4295b7 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Fri, 18 Dec 2020 15:51:50 +0100 Subject: [PATCH] feat(legacy): Support on-device passphrase entry. --- legacy/firmware/config.c | 62 ++++++++++++++----------------- legacy/firmware/config.h | 3 ++ legacy/firmware/fsm_msg_common.h | 41 ++++++++++++++++++--- legacy/firmware/protect.c | 63 +++++++++++++++++++++++++++----- 4 files changed, 119 insertions(+), 50 deletions(-) diff --git a/legacy/firmware/config.c b/legacy/firmware/config.c index e48120a3a..32dac82e4 100644 --- a/legacy/firmware/config.c +++ b/legacy/firmware/config.c @@ -68,17 +68,19 @@ static const uint32_t META_MAGIC_V10 = 0xFFFFFFFF; #define KEY_LANGUAGE (3 | APP | FLAG_PUBLIC_SHIFTED) // string(17) #define KEY_LABEL (4 | APP | FLAG_PUBLIC_SHIFTED) // string(33) #define KEY_PASSPHRASE_PROTECTION (5 | APP | FLAG_PUBLIC_SHIFTED) // bool -#define KEY_HOMESCREEN (6 | APP | FLAG_PUBLIC_SHIFTED) // bytes(1024) -#define KEY_NEEDS_BACKUP (7 | APP) // bool -#define KEY_FLAGS (8 | APP) // uint32 -#define KEY_U2F_COUNTER (9 | APP | FLAGS_WRITE_SHIFTED) // uint32 -#define KEY_UNFINISHED_BACKUP (11 | APP) // bool -#define KEY_AUTO_LOCK_DELAY_MS (12 | APP) // uint32 -#define KEY_NO_BACKUP (13 | APP) // bool -#define KEY_INITIALIZED (14 | APP | FLAG_PUBLIC_SHIFTED) // uint32 -#define KEY_NODE (15 | APP) // node -#define KEY_IMPORTED (16 | APP) // bool -#define KEY_U2F_ROOT (17 | APP | FLAG_PUBLIC_SHIFTED) // node +#define KEY_HOMESCREEN (6 | APP | FLAG_PUBLIC_SHIFTED) // bytes(1024) +#define KEY_NEEDS_BACKUP (7 | APP) // bool +#define KEY_FLAGS (8 | APP) // uint32 +#define KEY_U2F_COUNTER (9 | APP | FLAGS_WRITE_SHIFTED) // uint32 +#define KEY_UNFINISHED_BACKUP (11 | APP) // bool +#define KEY_AUTO_LOCK_DELAY_MS (12 | APP) // uint32 +#define KEY_NO_BACKUP (13 | APP) // bool +#define KEY_INITIALIZED (14 | APP | FLAG_PUBLIC_SHIFTED) // uint32 +#define KEY_NODE (15 | APP) // node +#define KEY_IMPORTED (16 | APP) // bool +#define KEY_U2F_ROOT (17 | APP | FLAG_PUBLIC_SHIFTED) // node +#define KEY_PASSPHRASE_ALWAYS_ON_DEVICE \ + (18 | APP | FLAG_PUBLIC_SHIFTED) // bool #define KEY_DEBUG_LINK_PIN (255 | APP | FLAG_PUBLIC_SHIFTED) // string(10) #define MAX_SESSIONS_COUNT 10 @@ -561,6 +563,9 @@ void config_setLanguage(const char *lang) { void config_setPassphraseProtection(bool passphrase_protection) { config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); + if (passphrase_protection == false) { + config_setPassphraseAlwaysOnDevice(false); + } } bool config_getPassphraseProtection(bool *passphrase_protection) { @@ -568,6 +573,17 @@ bool config_getPassphraseProtection(bool *passphrase_protection) { config_get_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); } +void config_setPassphraseAlwaysOnDevice(bool passphrase_always_on_device) { + config_set_bool(KEY_PASSPHRASE_ALWAYS_ON_DEVICE, passphrase_always_on_device); +} + +bool config_getPassphraseAlwaysOnDevice(void) { + bool passphrase_always_on_device = false; + config_get_bool(KEY_PASSPHRASE_ALWAYS_ON_DEVICE, + &passphrase_always_on_device); + return passphrase_always_on_device; +} + void config_setHomescreen(const uint8_t *data, uint32_t size) { if (data != NULL && size == HOMESCREEN_SIZE) { storage_set(KEY_HOMESCREEN, data, size); @@ -601,30 +617,6 @@ const uint8_t *config_getSeed(void) { memzero(passphrase, sizeof(passphrase)); return NULL; } - // passphrase is used - confirm on the display - if (passphrase[0] != 0) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, - _("Access hidden wallet?"), NULL, - _("Next screen will show"), _("the passphrase!"), NULL, - NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - memzero(mnemonic, sizeof(mnemonic)); - memzero(passphrase, sizeof(passphrase)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, - _("Passphrase dismissed")); - layoutHome(); - return NULL; - } - layoutShowPassphrase(passphrase); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - memzero(mnemonic, sizeof(mnemonic)); - memzero(passphrase, sizeof(passphrase)); - fsm_sendFailure(FailureType_Failure_ActionCancelled, - _("Passphrase dismissed")); - layoutHome(); - return NULL; - } - } // if storage was not imported (i.e. it was properly generated or recovered) bool imported = false; config_get_bool(KEY_IMPORTED, &imported); diff --git a/legacy/firmware/config.h b/legacy/firmware/config.h index 4777cb34a..952afd94e 100644 --- a/legacy/firmware/config.h +++ b/legacy/firmware/config.h @@ -114,6 +114,9 @@ void config_setLanguage(const char *lang); void config_setPassphraseProtection(bool passphrase_protection); bool config_getPassphraseProtection(bool *passphrase_protection); +void config_setPassphraseAlwaysOnDevice(bool passphrase_always_on_device); +bool config_getPassphraseAlwaysOnDevice(void); + bool config_getHomescreen(uint8_t *dest, uint16_t dest_size); void config_setHomescreen(const uint8_t *data, uint32_t size); diff --git a/legacy/firmware/fsm_msg_common.h b/legacy/firmware/fsm_msg_common.h index 29c3b5595..827d3f2e4 100644 --- a/legacy/firmware/fsm_msg_common.h +++ b/legacy/firmware/fsm_msg_common.h @@ -64,6 +64,8 @@ bool get_features(Features *resp) { resp->wipe_code_protection = config_hasWipeCode(); resp->has_auto_lock_delay_ms = true; resp->auto_lock_delay_ms = config_getAutoLockDelayMs(); + resp->has_passphrase_always_on_device = true; + resp->passphrase_always_on_device = config_getPassphraseAlwaysOnDevice(); } #if BITCOIN_ONLY @@ -71,7 +73,7 @@ bool get_features(Features *resp) { resp->capabilities[0] = Capability_Capability_Bitcoin; resp->capabilities[1] = Capability_Capability_Crypto; #else - resp->capabilities_count = 8; + resp->capabilities_count = 9; resp->capabilities[0] = Capability_Capability_Bitcoin; resp->capabilities[1] = Capability_Capability_Bitcoin_like; resp->capabilities[2] = Capability_Capability_Crypto; @@ -80,6 +82,7 @@ bool get_features(Features *resp) { resp->capabilities[5] = Capability_Capability_NEM; resp->capabilities[6] = Capability_Capability_Stellar; resp->capabilities[7] = Capability_Capability_U2F; + resp->capabilities[8] = Capability_Capability_PassphraseEntry; #endif return resp; } @@ -361,10 +364,6 @@ void fsm_msgEndSession(const EndSession *msg) { } void fsm_msgApplySettings(const ApplySettings *msg) { - CHECK_PARAM( - !msg->has_passphrase_always_on_device, - _("This firmware is incapable of passphrase entry on the device.")); - CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen || msg->has_auto_lock_delay_ms, _("No setting provided")); @@ -403,6 +402,35 @@ void fsm_msgApplySettings(const ApplySettings *msg) { return; } } + if (msg->has_passphrase_always_on_device) { + bool use_passphrase = false; + if (msg->has_use_passphrase) { + use_passphrase = msg->use_passphrase; + } else { + config_getPassphraseProtection(&use_passphrase); + } + if (use_passphrase == false) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Passphrase is not enabled")); + layoutHome(); + return; + } + if (msg->passphrase_always_on_device) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("restrict passphrase"), + _("entry to be only"), _("allowed on the"), + _("device?"), NULL); + } else { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("allow passphrase"), + _("entry on the host?"), NULL, NULL, NULL); + } + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } if (msg->has_homescreen) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change the home"), @@ -444,6 +472,9 @@ void fsm_msgApplySettings(const ApplySettings *msg) { if (msg->has_use_passphrase) { config_setPassphraseProtection(msg->use_passphrase); } + if (msg->has_passphrase_always_on_device) { + config_setPassphraseAlwaysOnDevice(msg->passphrase_always_on_device); + } if (msg->has_homescreen) { config_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); } diff --git a/legacy/firmware/protect.c b/legacy/firmware/protect.c index 7df3e2c89..53368c6af 100644 --- a/legacy/firmware/protect.c +++ b/legacy/firmware/protect.c @@ -112,6 +112,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) { const char *requestPin(PinMatrixRequestType type, const char *text) { return pin_keyboard(text); + PinMatrixRequest resp = {0}; memzero(&resp, sizeof(PinMatrixRequest)); resp.has_type = true; @@ -352,15 +353,18 @@ bool protectChangeWipeCode(bool removal) { return ret; } -bool protectPassphrase(char *passphrase) { - memzero(passphrase, MAX_PASSPHRASE_LEN + 1); - bool passphrase_protection = false; - config_getPassphraseProtection(&passphrase_protection); - if (!passphrase_protection) { - // passphrase already set to empty by memzero above +static bool protectPassphraseOnDevice(char *passphrase) { + const char *input = passphrase_keyboard(_("Please enter passphrase")); + if (input) { + strlcpy(passphrase, input, MAX_PASSPHRASE_LEN); return true; + } else { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + return false; } +} +static bool protectPassphraseOnHost(char *passphrase) { PassphraseRequest resp = {0}; memzero(&resp, sizeof(PassphraseRequest)); usbTiny(1); @@ -377,10 +381,13 @@ bool protectPassphrase(char *passphrase) { msg_tiny_id = 0xFFFF; PassphraseAck *ppa = (PassphraseAck *)msg_tiny; if (ppa->has_on_device && ppa->on_device == true) { - fsm_sendFailure( - FailureType_Failure_DataError, - _("This firmware is incapable of passphrase entry on the device.")); - result = false; + if (ppa->has_passphrase) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Passphrase provided when it should not be")); + result = false; + break; + } + result = protectPassphraseOnDevice(passphrase); break; } if (!ppa->has_passphrase) { @@ -391,6 +398,26 @@ bool protectPassphrase(char *passphrase) { break; } strlcpy(passphrase, ppa->passphrase, sizeof(ppa->passphrase)); + if (passphrase[0] != '\0') { + // passphrase is used - confirm on the display + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Access hidden wallet?"), NULL, + _("Next screen will show"), _("the passphrase!"), + NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Passphrase dismissed")); + result = false; + break; + } + layoutShowPassphrase(passphrase); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Passphrase dismissed")); + result = false; + break; + } + } result = true; break; } @@ -409,3 +436,19 @@ bool protectPassphrase(char *passphrase) { layoutHome(); return result; } + +bool protectPassphrase(char *passphrase) { + memzero(passphrase, MAX_PASSPHRASE_LEN + 1); + bool passphrase_protection = false; + config_getPassphraseProtection(&passphrase_protection); + if (!passphrase_protection) { + // passphrase already set to empty by memzero above + return true; + } + + if (config_getPassphraseAlwaysOnDevice()) { + return protectPassphraseOnDevice(passphrase); + } else { + return protectPassphraseOnHost(passphrase); + } +}