mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-10-31 20:39:48 +00:00
fix(legacy): Abort recovery for invalid words.
This commit is contained in:
parent
fa5e7feda6
commit
f8ffaecd1c
1
legacy/firmware/.changelog.d/noissue.security.3
Normal file
1
legacy/firmware/.changelog.d/noissue.security.3
Normal file
@ -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 (!dry_run) {
|
||||
session_clear(true);
|
||||
}
|
||||
fsm_sendFailure(FailureType_Failure_ProcessError,
|
||||
_("Wrong word retyped"));
|
||||
layoutHome();
|
||||
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();
|
||||
recovery_abort();
|
||||
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…
Reference in New Issue
Block a user