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