Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 50 additions & 6 deletions src/memory/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)) {
Expand All @@ -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);
Expand All @@ -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) {
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down
16 changes: 16 additions & 0 deletions src/memory/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
20 changes: 20 additions & 0 deletions test/unit-test/test_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <memory/memory.h>
#include <memory/memory_shared.h>
#include <util.h>

#include <stdint.h>
#include <stdio.h>
Expand Down Expand Up @@ -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++) {
Expand All @@ -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 \
Expand Down
Loading