Skip to content

Commit 765547c

Browse files
[fix] Some plausible yet wrong mnemonic were deemed valid on NBGL devices
1 parent 7795ade commit 765547c

File tree

13 files changed

+96
-52
lines changed

13 files changed

+96
-52
lines changed

src/bagl/nanox_enter_phrase.c

+3-40
Original file line numberDiff line numberDiff line change
@@ -399,44 +399,6 @@ const bagl_element_t* screen_onboarding_4_restore_word_before_element_display_ca
399399
return element;
400400
}
401401

402-
static uint8_t compare_recovery_phrase(void) {
403-
// convert mnemonic to hex-seed
404-
uint8_t buffer[64];
405-
406-
bolos_ux_mnemonic_to_seed((unsigned char*) G_bolos_ux_context.words_buffer,
407-
G_bolos_ux_context.words_buffer_length,
408-
buffer);
409-
PRINTF("Input seed:\n %.*H\n", 64, buffer);
410-
411-
// get rootkey from hex-seed
412-
cx_hmac_sha512_t ctx;
413-
const char key[] = "Bitcoin seed";
414-
415-
LEDGER_ASSERT(cx_hmac_sha512_init_no_throw(&ctx, (const uint8_t*) key, strlen(key)) == CX_OK,
416-
"HMAC init failed");
417-
LEDGER_ASSERT(cx_hmac_no_throw((cx_hmac_t*) &ctx, CX_LAST, buffer, 64, buffer, 64) == CX_OK,
418-
"HMAC failed");
419-
PRINTF("Root key from input:\n%.*H\n", 64, buffer);
420-
421-
// get rootkey from device's seed
422-
uint8_t buffer_device[64];
423-
424-
// os_derive_bip32* do not accept NULL path, even with a size of 0, so we provide an empty path
425-
const unsigned int empty_path = 0;
426-
if (os_derive_bip32_no_throw(CX_CURVE_256K1,
427-
&empty_path,
428-
0,
429-
buffer_device,
430-
buffer_device + 32) != CX_OK) {
431-
PRINTF("An error occurred while comparing the recovery phrase\n");
432-
return 0;
433-
}
434-
PRINTF("Root key from device: \n%.*H\n", 64, buffer_device);
435-
436-
// compare both rootkey
437-
return os_secure_memcmp(buffer, buffer_device, 64) ? 0 : 1;
438-
}
439-
440402
void screen_onboarding_4_restore_word_validate(void) {
441403
bolos_ux_bip39_idx_strcpy(
442404
G_bolos_ux_context.onboarding_index + G_bolos_ux_context.hslider3_current,
@@ -472,7 +434,8 @@ void screen_onboarding_4_restore_word_validate(void) {
472434

473435
// Display loading icon to user
474436
ux_flow_init(0, ux_load_flow, NULL);
475-
if (compare_recovery_phrase()) {
437+
if (compare_recovery_phrase((unsigned char*) G_bolos_ux_context.words_buffer,
438+
G_bolos_ux_context.words_buffer_length)) {
476439
ux_flow_init(0, ux_succesfull_check_flow, NULL);
477440
} else {
478441
ux_flow_init(0, ux_failed_check_flow, NULL);
@@ -568,7 +531,7 @@ void screen_onboarding_4_restore_word_init(unsigned int firstWord) {
568531
ARRAYLEN(screen_onboarding_4_restore_word_intro_elements);
569532
G_ux.stack[0].element_arrays_count = 1;
570533
ux_stack_display(0);
571-
#else // RESTORE_INTRO_WORD
534+
#else // RESTORE_INTRO_WORD
572535
screen_onboarding_4_restore_word_display_auto_complete();
573536
#endif // RESTORE_INTRO_WORD
574537
}

src/bagl/ux_nano.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#pragma once
1818

1919
#include <ux.h>
20-
#include "ux_common/common.h"
20+
#include "mnemonic_common/common.h"
2121

2222
#if defined(HAVE_BAGL)
2323

@@ -83,7 +83,7 @@ void screen_common_keyboard_init(unsigned int stack_slot,
8383
unsigned int nb_elements,
8484
keyboard_callback_t callback);
8585

86-
#include "ux_common/common_bip39.h"
86+
#include "mnemonic_common/common_bip39.h"
8787

8888
#if defined(TARGET_NANOS)
8989
extern const bagl_element_t screen_onboarding_word_list_elements[9];
File renamed without changes.

src/ux_common/common_bip39.h src/mnemonic_common/common_bip39.h

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ unsigned int bolos_ux_bip39_get_word_count_starting_with(const unsigned char *pr
2020
unsigned int bolos_ux_bip39_get_word_next_letters_starting_with(const unsigned char *prefix,
2121
const unsigned int prefixLength,
2222
unsigned char *next_letters_buffer);
23+
bool compare_recovery_phrase(uint8_t *buffer, size_t buffer_size);
2324

2425
#if defined(HAVE_NBGL)
2526
size_t bolos_ux_bip39_fill_with_candidates(const unsigned char *startingChars,
File renamed without changes.

src/ux_common/onboarding_seed_bip39.c src/mnemonic_common/onboarding_seed_bip39.c

+40
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,46 @@ unsigned int bolos_ux_bip39_get_word_next_letters_starting_with(
207207
return letter_count;
208208
}
209209

210+
bool compare_recovery_phrase(uint8_t* mnemonic, size_t mnemonic_length) {
211+
// convert mnemonic to hex-seed
212+
uint8_t buffer[64];
213+
214+
bolos_ux_mnemonic_to_seed(mnemonic, mnemonic_length, buffer);
215+
PRINTF("Input seed:\n %.*H\n", 64, buffer);
216+
217+
// get rootkey from hex-seed
218+
cx_hmac_sha512_t ctx;
219+
const char key[] = "Bitcoin seed";
220+
221+
LEDGER_ASSERT(cx_hmac_sha512_init_no_throw(&ctx, (const uint8_t*) key, strlen(key)) == CX_OK,
222+
"HMAC init failed");
223+
LEDGER_ASSERT(cx_hmac_no_throw((cx_hmac_t*) &ctx, CX_LAST, buffer, 64, buffer, 64) == CX_OK,
224+
"HMAC failed");
225+
PRINTF("Root key from input:\n%.*H\n", 64, buffer);
226+
227+
// get rootkey from device's seed
228+
uint8_t buffer_device[64];
229+
230+
// os_derive_bip32* do not accept NULL path, even with a size of 0, so we provide an empty path
231+
const unsigned int empty_path = 0;
232+
if (os_derive_bip32_no_throw(CX_CURVE_256K1,
233+
&empty_path,
234+
0,
235+
buffer_device,
236+
buffer_device + 32) != CX_OK) {
237+
PRINTF("An error occurred while comparing the recovery phrase\n");
238+
return 0;
239+
}
240+
PRINTF("Root key from device: \n%.*H\n", 64, buffer_device);
241+
242+
// compare both rootkey
243+
const bool result = os_secure_memcmp(buffer, buffer_device, 64) ? false : true;
244+
explicit_bzero(buffer_device, 64);
245+
explicit_bzero(buffer, 64);
246+
247+
return result;
248+
}
249+
210250
#if defined(HAVE_NBGL)
211251
#include <nbgl_layout.h>
212252

src/nbgl/mnemonic.c

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#include <os.h>
22
#include <string.h>
3+
#include <lcx_hmac.h>
4+
#include <lcx_rng.h>
35

4-
#include "../ux_common/common_bip39.h"
56
#include "./mnemonic.h"
7+
#include "../mnemonic_common/common_bip39.h"
68

79
#if defined(SCREEN_SIZE_WALLET)
810

@@ -45,7 +47,7 @@ size_t get_current_word_number() {
4547
}
4648

4749
void reset_mnemonic() {
48-
memset(&mnemonic, 0, sizeof(mnemonic));
50+
explicit_bzero(&mnemonic, sizeof(mnemonic));
4951
mnemonic.current_word_index = (size_t) -1;
5052
}
5153

@@ -90,10 +92,15 @@ bool check_mnemonic() {
9092
PRINTF("Checking the following mnemonic: '%s' (size %ld)\n",
9193
&mnemonic.buffer[0],
9294
mnemonic.length);
93-
const bool result =
94-
bolos_ux_mnemonic_check((unsigned char*) &mnemonic.buffer[0], mnemonic.length);
95-
// clearing the mnemonic ASAP
95+
96+
if (bolos_ux_mnemonic_check((unsigned char*) &mnemonic.buffer[0], mnemonic.length) == false) {
97+
reset_mnemonic();
98+
return false;
99+
}
100+
101+
const bool result = compare_recovery_phrase((uint8_t*) mnemonic.buffer, mnemonic.length);
96102
reset_mnemonic();
103+
97104
return result;
98105
}
99106

src/nbgl/ui.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
#include <nbgl_page.h>
1515
#include <nbgl_layout.h>
1616

17-
#include "../ux_common/common_bip39.h"
1817
#include "../ui.h"
18+
#include "../mnemonic_common/common_bip39.h"
1919
#include "./mnemonic.h"
2020
#include "./passphrase_length_screen.h"
2121

tests/functional/test_touch_full.py

+37-4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
from .utils import format_instructions
55

66

7-
SPECULOS_MNEMONIC = "glory promote mansion idle axis finger extra " \
8-
"february uncover one trip resource lawn turtle enact monster " \
9-
"seven myth punch hobby comfort wild raise skin"
7+
SPECULOS_MNEMONIC = "glory promote mansion idle axis finger extra february uncover one trip resource " \
8+
"lawn turtle enact monster seven myth punch hobby comfort wild raise skin"
9+
10+
PLAUSIBLE_MNEMONIC= "feature trigger apart fold answer lend enrich blind foam deny match ecology " \
11+
"reform again snow stadium vibrant brain hungry already sadness verify team speed"
1012

1113

1214
def test_nominal_full_passphrase_check_ok(navigator: TouchNavigator, functional_test_directory: str):
@@ -40,6 +42,37 @@ def test_nominal_full_passphrase_check_ok(navigator: TouchNavigator, functional_
4042
screen_change_before_first_instruction=True,
4143
screen_change_after_last_instruction=False)
4244

45+
def test_nominal_full_passphrase_check_plausible_but_wrong(navigator: TouchNavigator, functional_test_directory: str):
46+
# instructions to go the the keyboard
47+
instructions = [
48+
CustomNavInsID.HOME_TO_CHECK,
49+
CustomNavInsID.LENGTH_CHOOSE_24,
50+
]
51+
# instruction to write the words
52+
for word in PLAUSIBLE_MNEMONIC.split():
53+
instructions += [
54+
NavIns(CustomNavInsID.KEYBOARD_WRITE, args=(word[:4], )),
55+
NavIns(CustomNavInsID.KEYBOARD_SELECT_SUGGESTION, args=(1, )),
56+
]
57+
instructions = format_instructions(instructions)
58+
# running the instruction to go to result screen
59+
navigator.navigate(instructions,
60+
screen_change_before_first_instruction=False,
61+
screen_change_after_last_instruction=False)
62+
63+
# now that the 24 words have been written, we check the resulting screen
64+
# should be correct
65+
66+
instructions = format_instructions([
67+
CustomNavInsID.RESULT_TO_HOME,
68+
])
69+
70+
navigator.navigate_and_compare(functional_test_directory,
71+
"nominal_full_passphrase_check_incorrect",
72+
instructions,
73+
screen_change_before_first_instruction=True,
74+
screen_change_after_last_instruction=False)
75+
4376

4477
def test_nominal_full_passphrase_check_error_wrong_passphrase(navigator: TouchNavigator, functional_test_directory: str):
4578
# instructions to go the the keyboard
@@ -68,7 +101,7 @@ def test_nominal_full_passphrase_check_error_wrong_passphrase(navigator: TouchNa
68101
])
69102

70103
navigator.navigate_and_compare(functional_test_directory,
71-
"nominal_full_passphrase_check_error_wrong_passphrase",
104+
"nominal_full_passphrase_check_incorrect",
72105
instructions,
73106
screen_change_before_first_instruction=True,
74107
screen_change_after_last_instruction=False)

0 commit comments

Comments
 (0)