fix(legacy): Abort recovery for invalid words.

pull/2455/head
Andrew Kozlik 2 years ago committed by matejcik
parent fa5e7feda6
commit f8ffaecd1c

@ -0,0 +1 @@
Fix potential security issues in recovery workflow.

@ -37,12 +37,12 @@
/* number of words expected in the new seed */
static uint32_t word_count;
/* recovery mode:
* 0: not recovering
* 1: recover by scrambled plain text words
* 2: recover by matrix entry
*/
static int awaiting_word = 0;
/* recovery mode */
static enum {
RECOVERY_NONE = 0, // recovery not in progress
RECOVERY_SCRAMBLED = 1, // standard recovery by scrambled plain text words
RECOVERY_MATRIX = 2, // advanced recovery by matrix entry
} recovery_mode = RECOVERY_NONE;
/* True if we should not write anything back to config
* (can be used for testing seed for correctness).
@ -145,7 +145,7 @@ static void format_number(char *dest, int number) {
static void recovery_request(void) {
WordRequest resp = {0};
memzero(&resp, sizeof(WordRequest));
if (awaiting_word == 1) {
if (recovery_mode == RECOVERY_SCRAMBLED) {
resp.type = WordRequestType_WordRequestType_Plain;
} else if (word_index % 4 == 3) {
resp.type = WordRequestType_WordRequestType_Matrix6;
@ -217,7 +217,9 @@ static void recovery_done(void) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid seed, are words in correct order?"));
}
awaiting_word = 0;
memzero(words, sizeof(words));
word_pincode = 0;
recovery_mode = RECOVERY_NONE;
layoutHome();
}
@ -476,6 +478,9 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection,
bool _dry_run) {
if (_word_count != 12 && _word_count != 18 && _word_count != 24) return;
recovery_mode = RECOVERY_NONE;
word_pincode = 0;
word_index = 0;
word_count = _word_count;
enforce_wordlist = _enforce_wordlist;
dry_run = _dry_run;
@ -504,10 +509,9 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection,
config_setU2FCounter(u2f_counter);
}
// Prefer matrix recovery if the host supports it.
if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) {
awaiting_word = 2;
word_index = 0;
word_pincode = 0;
recovery_mode = RECOVERY_MATRIX;
next_matrix();
} else {
for (uint32_t i = 0; i < word_count; i++) {
@ -517,8 +521,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection,
word_order[i] = 0;
}
random_permute(word_order, 24);
awaiting_word = 1;
word_index = 0;
recovery_mode = RECOVERY_SCRAMBLED;
next_word();
}
}
@ -527,29 +530,18 @@ static void recovery_scrambledword(const char *word) {
int index = -1;
if (enforce_wordlist) { // check if word is valid
index = mnemonic_find_word(word);
}
if (word_pos == 0) { // fake word
if (strcmp(word, fake_word) != 0) {
if (index < 0) { // not found
if (!dry_run) {
session_clear(true);
}
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Wrong word retyped"));
layoutHome();
fsm_sendFailure(FailureType_Failure_DataError,
_("Word not found in a wordlist"));
recovery_abort();
return;
}
} else { // real word
if (enforce_wordlist) {
if (index < 0) { // not found
if (!dry_run) {
session_clear(true);
}
fsm_sendFailure(FailureType_Failure_DataError,
_("Word not found in a wordlist"));
layoutHome();
return;
}
}
}
if (word_pos != 0) { // ignore fake words
strlcpy(words[word_pos - 1], word, sizeof(words[word_pos - 1]));
}
@ -565,11 +557,11 @@ static void recovery_scrambledword(const char *word) {
* for scrambled recovery.
*/
void recovery_word(const char *word) {
switch (awaiting_word) {
case 2:
switch (recovery_mode) {
case RECOVERY_MATRIX:
recovery_digit(word[0]);
break;
case 1:
case RECOVERY_SCRAMBLED:
recovery_scrambledword(word);
break;
default:
@ -582,9 +574,11 @@ void recovery_word(const char *word) {
/* Abort recovery.
*/
void recovery_abort(void) {
if (awaiting_word) {
memzero(words, sizeof(words));
word_pincode = 0;
if (recovery_mode != RECOVERY_NONE) {
layoutHome();
awaiting_word = 0;
recovery_mode = RECOVERY_NONE;
}
}

Loading…
Cancel
Save