@@ -39,12 +39,12 @@ static bool _is_unlocked_device = false;
3939// Must be defined if is_unlocked is true. Length of the seed store in `_retained_seed`. See also:
4040// `_validate_seed_length()`.
4141static 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().
4343static uint8_t _retained_seed [KEYSTORE_MAX_SEED_LENGTH ] = {0 };
4444
4545// Change this ONLY via keystore_unlock_bip39().
4646static 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 ().
4848static uint8_t _retained_bip39_seed [64 ] = {0 };
4949
5050#ifdef TESTING
@@ -70,40 +70,36 @@ static bool _validate_seed_length(size_t seed_len)
7070 return seed_len == 16 || seed_len == 24 || seed_len == 32 ;
7171}
7272
73- static const uint8_t * _get_seed (void )
74- {
75- if (!_is_unlocked_device ) {
76- return NULL ;
77- }
78- return _retained_seed ;
79- }
80-
8173bool keystore_copy_seed (uint8_t * seed_out , size_t * length_out )
8274{
83- if (_get_seed () == NULL ) {
75+ if (! _is_unlocked_device ) {
8476 return false;
8577 }
86- memcpy (seed_out , _get_seed () , _seed_length );
78+ memcpy (seed_out , _retained_seed , _seed_length );
8779 * length_out = _seed_length ;
8880 return true;
8981}
9082
9183/**
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.
9489 */
95- static const uint8_t * _get_bip39_seed ( void )
90+ static bool _copy_bip39_seed ( uint8_t * bip39_seed_out )
9691{
9792 if (!_is_unlocked_bip39 ) {
98- return NULL ;
93+ return false ;
9994 }
10095 // sanity check
10196 uint8_t zero [64 ] = {0 };
10297 util_zero (zero , 64 );
10398 if (MEMEQ (_retained_bip39_seed , zero , sizeof (_retained_bip39_seed ))) {
104- return NULL ;
99+ return false ;
105100 }
106- return _retained_bip39_seed ;
101+ memcpy (bip39_seed_out , _retained_bip39_seed , sizeof (_retained_bip39_seed ));
102+ return true;
107103}
108104
109105/**
@@ -382,13 +378,17 @@ bool keystore_unlock_bip39(const char* mnemonic_passphrase)
382378 if (!_is_unlocked_device ) {
383379 return false;
384380 }
385- const uint8_t * seed = _get_seed ();
386- if (seed == NULL ) {
387- return false;
388- }
389381 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+ }
392392 }
393393 uint8_t bip39_seed [BIP39_SEED_LEN_512 ] = {0 };
394394 UTIL_CLEANUP_64 (bip39_seed );
@@ -421,13 +421,17 @@ bool keystore_get_bip39_mnemonic(char* mnemonic_out, size_t mnemonic_out_size)
421421 if (keystore_is_locked ()) {
422422 return false;
423423 }
424- const uint8_t * seed = _get_seed ();
425- if (seed == NULL ) {
426- return false;
427- }
428424 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+ }
431435 }
432436 int snprintf_result = snprintf (mnemonic_out , mnemonic_out_size , "%s" , mnemonic );
433437 util_cleanup_str (& mnemonic );
@@ -445,8 +449,10 @@ static bool _get_xprv(const uint32_t* keypath, const size_t keypath_len, struct
445449 if (keystore_is_locked ()) {
446450 return false;
447451 }
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 )) {
450456 return false;
451457 }
452458 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
456462 WALLY_OK ) {
457463 return false;
458464 }
465+ util_zero (bip39_seed , sizeof (bip39_seed ));
459466 if (keypath_len == 0 ) {
460467 * xprv_out = xprv_master ;
461468 } else if (
@@ -621,8 +628,9 @@ bool keystore_get_u2f_seed(uint8_t* seed_out)
621628 if (keystore_is_locked ()) {
622629 return false;
623630 }
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 )) {
626634 return false;
627635 }
628636 const uint8_t message [] = "u2f" ;
@@ -635,8 +643,9 @@ bool keystore_get_u2f_seed(uint8_t* seed_out)
635643
636644bool keystore_get_ed25519_seed (uint8_t * seed_out )
637645{
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 )) {
640649 return false;
641650 }
642651
@@ -659,6 +668,7 @@ bool keystore_get_ed25519_seed(uint8_t* seed_out)
659668 uint8_t message [65 ] = {0 };
660669 message [0 ] = 0x01 ;
661670 memcpy (& message [1 ], bip39_seed , 64 );
671+ util_zero (bip39_seed , sizeof (bip39_seed ));
662672 if (wally_hmac_sha256 (key , sizeof (key ), message , sizeof (message ), & seed_out [64 ], 32 ) !=
663673 WALLY_OK ) {
664674 util_zero (message , sizeof (message ));
0 commit comments