diff --git a/src/memory/memory.c b/src/memory/memory.c index f5b58352da..6aa3d92df4 100644 --- a/src/memory/memory.c +++ b/src/memory/memory.c @@ -134,7 +134,8 @@ typedef union { // Hash of bootloader used in the attestation sighash. // If not set, the actual bootloader area is hashed. secbool_u8 attestation_bootloader_hash_set; - uint8_t reserved[3]; + secbool_u8 reset_hww; + uint8_t reserved[2]; uint8_t attestation_bootloader_hash[32]; } fields; uint8_t bytes[CHUNK_SIZE]; @@ -304,11 +305,17 @@ bool memory_setup(const memory_interface_functions_t* ifs) } _interface_functions = ifs; + // Factory setup chunk_0_t chunk = {0}; CLEANUP_CHUNK(chunk); _read_chunk(CHUNK_0_PERMANENT, chunk_bytes); if (chunk.fields.factory_setup_done == sectrue_u8) { - // already factory installed + // already factory installed, check if there is a failed hww reset + if (memory_get_reset_hww()) { + if (!memory_reset_hww()) { + return false; + } + } return true; } // Perform factory setup. @@ -363,6 +370,10 @@ bool memory_cleanup_smarteeprom(void) bool memory_reset_hww(void) { + if (!memory_set_reset_hww()) { + return false; + } + // Erase all app data chunks expect the first and the last one, which is permanent. for (uint32_t chunk = CHUNK_1; chunk < (FLASH_APPDATA_LEN / CHUNK_SIZE) - 1; chunk++) { if (!_write_chunk(chunk, NULL)) { @@ -371,7 +382,6 @@ bool memory_reset_hww(void) } // Initialize hww memory - chunk_1_t chunk = {0}; CLEANUP_CHUNK(chunk); _read_chunk(CHUNK_1, chunk_bytes); @@ -382,7 +392,9 @@ bool memory_reset_hww(void) // Set a new noise static private key. rust_noise_generate_static_private_key(rust_util_bytes_mut( chunk.fields.noise_static_private_key, sizeof(chunk.fields.noise_static_private_key))); - bool res = _write_chunk(CHUNK_1, chunk.bytes); + if (!_write_chunk(CHUNK_1, chunk.bytes)) { + return false; + } // Reset bond-db and reinitialize IRK and identity address if (memory_get_platform() == MEMORY_PLATFORM_BITBOX02_PLUS) { @@ -405,10 +417,16 @@ bool memory_reset_hww(void) chunk_shared.fields.ble_identity_address[0] |= 0xc; memset(&chunk_shared.fields.ble_bond_db, 0xff, sizeof(chunk_shared.fields.ble_bond_db)); - res |= _write_to_address(FLASH_SHARED_DATA_START, 0, chunk_shared.bytes); + if (!_write_to_address(FLASH_SHARED_DATA_START, 0, chunk_shared.bytes)) { + return false; + } } - return res; + if (!memory_clear_reset_hww()) { + return false; + } + + return true; } static bool _is_bitmask_flag_set(uint8_t flag) @@ -443,6 +461,32 @@ bool memory_set_initialized(void) return _write_chunk(CHUNK_1, chunk.bytes); } +bool memory_set_reset_hww(void) +{ + chunk_7_t chunk = {0}; + CLEANUP_CHUNK(chunk); + _read_chunk(CHUNK_7_PERMANENT, chunk_bytes); + chunk.fields.reset_hww = sectrue_u8; + return _write_chunk(CHUNK_7_PERMANENT, chunk.bytes); +} + +bool memory_clear_reset_hww(void) +{ + chunk_7_t chunk = {0}; + CLEANUP_CHUNK(chunk); + _read_chunk(CHUNK_7_PERMANENT, chunk_bytes); + chunk.fields.reset_hww = secfalse_u8; + return _write_chunk(CHUNK_7_PERMANENT, chunk.bytes); +} + +bool memory_get_reset_hww(void) +{ + chunk_7_t chunk = {0}; + CLEANUP_CHUNK(chunk); + _read_chunk(CHUNK_7_PERMANENT, chunk_bytes); + return chunk.fields.reset_hww == sectrue_u8; +} + bool memory_is_mnemonic_passphrase_enabled(void) { return _is_bitmask_flag_set(BITMASK_ENABLE_MNEMONIC_PASSPHRASE); diff --git a/src/memory/memory.h b/src/memory/memory.h index 25bdc3709d..9a0111829b 100644 --- a/src/memory/memory.h +++ b/src/memory/memory.h @@ -106,6 +106,22 @@ USE_RESULT bool memory_is_initialized(void); */ USE_RESULT bool memory_set_initialized(void); +/** + * Sets the "reset hww" flag to indicate that reset is in progress. Returns false if it fails to + * write to flash. + */ +USE_RESULT bool memory_set_reset_hww(void); + +/** + * Clears the "reset hww" flag. Returns false if it fails to write to flash. + */ +USE_RESULT bool memory_clear_reset_hww(void); + +/** + * Get the "reset hww" flag. + */ +USE_RESULT bool memory_get_reset_hww(void); + /** * Returns true if the bip39 passphrase feature is enabled. */ diff --git a/test/unit-test/test_memory.c b/test/unit-test/test_memory.c index 5db877d66f..2b56a1c771 100644 --- a/test/unit-test/test_memory.c +++ b/test/unit-test/test_memory.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -117,6 +118,16 @@ static const memory_interface_functions_t _ifs = { static void _expect_reset(uint8_t* empty_chunk1, uint8_t* empty_chunk2) { + EMPTYCHUNK(chunk7); + // set "reset hww" flag in chunk 7 + expect_value(__wrap_memory_read_chunk_fake, chunk_num, 7); + will_return(__wrap_memory_read_chunk_fake, chunk7); + + expect_value(__wrap_memory_write_chunk_fake, chunk_num, 7); + chunk7[1] = sectrue_u8; + expect_memory(__wrap_memory_write_chunk_fake, chunk, chunk7, CHUNK_SIZE); + will_return(__wrap_memory_write_chunk_fake, true); + // Reset all except first and last chunk. for (uint32_t write_calls = 0; write_calls < FLASH_APP_DATA_LEN / CHUNK_SIZE - 2; write_calls++) { @@ -136,6 +147,15 @@ static void _expect_reset(uint8_t* empty_chunk1, uint8_t* empty_chunk2) memcpy(&empty_chunk2[_addr_salt_root], _salt_root, 32); expect_memory(__wrap_memory_write_chunk_fake, chunk, empty_chunk2, CHUNK_SIZE); will_return(__wrap_memory_write_chunk_fake, true); + + // clear "reset hww" flag in chunk 7 + expect_value(__wrap_memory_read_chunk_fake, chunk_num, 7); + will_return(__wrap_memory_read_chunk_fake, chunk7); + + expect_value(__wrap_memory_write_chunk_fake, chunk_num, 7); + chunk7[1] = secfalse_u8; + expect_memory(__wrap_memory_write_chunk_fake, chunk, chunk7, CHUNK_SIZE); + will_return(__wrap_memory_write_chunk_fake, true); } #define EXPECT_RESET \