@@ -39,12 +39,12 @@ static bool _is_unlocked_device = false;
39
39
// Must be defined if is_unlocked is true. Length of the seed store in `_retained_seed`. See also:
40
40
// `_validate_seed_length()`.
41
41
static size_t _seed_length = 0 ;
42
- // Must be defined if is_unlocked is true. ONLY ACCESS THIS WITH _get_seed()
42
+ // Must be defined if is_unlocked is true. ONLY ACCESS THIS WITH keystore_copy_seed().
43
43
static uint8_t _retained_seed [KEYSTORE_MAX_SEED_LENGTH ] = {0 };
44
44
45
45
// Change this ONLY via keystore_unlock_bip39().
46
46
static bool _is_unlocked_bip39 = false;
47
- // Must be defined if _is_unlocked is true. ONLY ACCESS THIS WITH _get_bip39_seed ().
47
+ // Must be defined if _is_unlocked is true. ONLY ACCESS THIS WITH _copy_bip39_seed ().
48
48
static uint8_t _retained_bip39_seed [64 ] = {0 };
49
49
50
50
#ifdef TESTING
@@ -70,40 +70,36 @@ static bool _validate_seed_length(size_t seed_len)
70
70
return seed_len == 16 || seed_len == 24 || seed_len == 32 ;
71
71
}
72
72
73
- static const uint8_t * _get_seed (void )
74
- {
75
- if (!_is_unlocked_device ) {
76
- return NULL ;
77
- }
78
- return _retained_seed ;
79
- }
80
-
81
73
bool keystore_copy_seed (uint8_t * seed_out , size_t * length_out )
82
74
{
83
- if (_get_seed () == NULL ) {
75
+ if (! _is_unlocked_device ) {
84
76
return false;
85
77
}
86
- memcpy (seed_out , _get_seed () , _seed_length );
78
+ memcpy (seed_out , _retained_seed , _seed_length );
87
79
* length_out = _seed_length ;
88
80
return true;
89
81
}
90
82
91
83
/**
92
- * @return the pointer ot the static bip39 seed on success. returns NULL if the
93
- * keystore is locked.
84
+ * Copies the retained bip39 seed into the given buffer. The caller must
85
+ * zero the seed with util_zero once it is no longer needed.
86
+ * @param[out] bip39_seed_out The seed bytes copied from the retained bip39 seed.
87
+ * The buffer must be 64 bytes long.
88
+ * @return true if the bip39 seed is available.
94
89
*/
95
- static const uint8_t * _get_bip39_seed ( void )
90
+ static bool _copy_bip39_seed ( uint8_t * bip39_seed_out )
96
91
{
97
92
if (!_is_unlocked_bip39 ) {
98
- return NULL ;
93
+ return false ;
99
94
}
100
95
// sanity check
101
96
uint8_t zero [64 ] = {0 };
102
97
util_zero (zero , 64 );
103
98
if (MEMEQ (_retained_bip39_seed , zero , sizeof (_retained_bip39_seed ))) {
104
- return NULL ;
99
+ return false ;
105
100
}
106
- return _retained_bip39_seed ;
101
+ memcpy (bip39_seed_out , _retained_bip39_seed , sizeof (_retained_bip39_seed ));
102
+ return true;
107
103
}
108
104
109
105
/**
@@ -382,13 +378,17 @@ bool keystore_unlock_bip39(const char* mnemonic_passphrase)
382
378
if (!_is_unlocked_device ) {
383
379
return false;
384
380
}
385
- const uint8_t * seed = _get_seed ();
386
- if (seed == NULL ) {
387
- return false;
388
- }
389
381
char * mnemonic __attribute__((__cleanup__ (_free_string ))) = NULL ;
390
- if (bip39_mnemonic_from_bytes (NULL , seed , _seed_length , & mnemonic ) != WALLY_OK ) {
391
- return false;
382
+ { // block so that `seed` is zeroed as soon as possible
383
+ uint8_t seed [KEYSTORE_MAX_SEED_LENGTH ] = {0 };
384
+ UTIL_CLEANUP_32 (seed );
385
+ size_t seed_length = 0 ;
386
+ if (!keystore_copy_seed (seed , & seed_length )) {
387
+ return false;
388
+ }
389
+ if (bip39_mnemonic_from_bytes (NULL , seed , seed_length , & mnemonic ) != WALLY_OK ) {
390
+ return false;
391
+ }
392
392
}
393
393
uint8_t bip39_seed [BIP39_SEED_LEN_512 ] = {0 };
394
394
UTIL_CLEANUP_64 (bip39_seed );
@@ -421,13 +421,17 @@ bool keystore_get_bip39_mnemonic(char* mnemonic_out, size_t mnemonic_out_size)
421
421
if (keystore_is_locked ()) {
422
422
return false;
423
423
}
424
- const uint8_t * seed = _get_seed ();
425
- if (seed == NULL ) {
426
- return false;
427
- }
428
424
char * mnemonic = NULL ;
429
- if (bip39_mnemonic_from_bytes (NULL , seed , _seed_length , & mnemonic ) != WALLY_OK ) {
430
- return false;
425
+ { // block so that `seed` is zeroed as soon as possible
426
+ uint8_t seed [KEYSTORE_MAX_SEED_LENGTH ] = {0 };
427
+ UTIL_CLEANUP_32 (seed );
428
+ size_t seed_length = 0 ;
429
+ if (!keystore_copy_seed (seed , & seed_length )) {
430
+ return false;
431
+ }
432
+ if (bip39_mnemonic_from_bytes (NULL , seed , seed_length , & mnemonic ) != WALLY_OK ) {
433
+ return false;
434
+ }
431
435
}
432
436
int snprintf_result = snprintf (mnemonic_out , mnemonic_out_size , "%s" , mnemonic );
433
437
util_cleanup_str (& mnemonic );
@@ -445,8 +449,10 @@ static bool _get_xprv(const uint32_t* keypath, const size_t keypath_len, struct
445
449
if (keystore_is_locked ()) {
446
450
return false;
447
451
}
448
- const uint8_t * bip39_seed = _get_bip39_seed ();
449
- if (bip39_seed == NULL ) {
452
+
453
+ uint8_t bip39_seed [64 ] = {0 };
454
+ UTIL_CLEANUP_64 (bip39_seed );
455
+ if (!_copy_bip39_seed (bip39_seed )) {
450
456
return false;
451
457
}
452
458
struct ext_key xprv_master __attribute__((__cleanup__ (keystore_zero_xkey ))) = {0 };
@@ -456,6 +462,7 @@ static bool _get_xprv(const uint32_t* keypath, const size_t keypath_len, struct
456
462
WALLY_OK ) {
457
463
return false;
458
464
}
465
+ util_zero (bip39_seed , sizeof (bip39_seed ));
459
466
if (keypath_len == 0 ) {
460
467
* xprv_out = xprv_master ;
461
468
} else if (
@@ -621,8 +628,9 @@ bool keystore_get_u2f_seed(uint8_t* seed_out)
621
628
if (keystore_is_locked ()) {
622
629
return false;
623
630
}
624
- const uint8_t * bip39_seed = _get_bip39_seed ();
625
- if (bip39_seed == NULL ) {
631
+ uint8_t bip39_seed [64 ] = {0 };
632
+ UTIL_CLEANUP_64 (bip39_seed );
633
+ if (!_copy_bip39_seed (bip39_seed )) {
626
634
return false;
627
635
}
628
636
const uint8_t message [] = "u2f" ;
@@ -635,8 +643,9 @@ bool keystore_get_u2f_seed(uint8_t* seed_out)
635
643
636
644
bool keystore_get_ed25519_seed (uint8_t * seed_out )
637
645
{
638
- const uint8_t * bip39_seed = _get_bip39_seed ();
639
- if (bip39_seed == NULL ) {
646
+ uint8_t bip39_seed [64 ] = {0 };
647
+ UTIL_CLEANUP_64 (bip39_seed );
648
+ if (!_copy_bip39_seed (bip39_seed )) {
640
649
return false;
641
650
}
642
651
@@ -659,6 +668,7 @@ bool keystore_get_ed25519_seed(uint8_t* seed_out)
659
668
uint8_t message [65 ] = {0 };
660
669
message [0 ] = 0x01 ;
661
670
memcpy (& message [1 ], bip39_seed , 64 );
671
+ util_zero (bip39_seed , sizeof (bip39_seed ));
662
672
if (wally_hmac_sha256 (key , sizeof (key ), message , sizeof (message ), & seed_out [64 ], 32 ) !=
663
673
WALLY_OK ) {
664
674
util_zero (message , sizeof (message ));
0 commit comments