Skip to content

Commit

Permalink
anti-replay: use uint32_t for the interface, document endiannes
Browse files Browse the repository at this point in the history
The counter is a uint32_t so update the interface to reflect that. As it
is returned in pin data and is expected to be little-endian when parsed
by the pin server, document this and add FIXMEs where the bytes currently
aren't swapped for big-endian builds.
  • Loading branch information
jgriffiths committed Jan 7, 2025
1 parent c96d7bd commit e583208
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 11 deletions.
4 changes: 2 additions & 2 deletions main/process/debug_handshake.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ void debug_handshake(void* process_ptr)
JADE_ASSERT(storage_get_counter() == 3);
uint32_t initial_replay_counter = UINT32_MAX;

JADE_ASSERT(storage_get_replay_counter((uint8_t*)&initial_replay_counter));
JADE_ASSERT(storage_get_replay_counter(&initial_replay_counter));
JADE_ASSERT(initial_replay_counter < UINT32_MAX);

jade_process_reply_to_message_ok(process);
Expand All @@ -121,7 +121,7 @@ void debug_handshake(void* process_ptr)
}

uint32_t replay_counter = UINT32_MAX;
JADE_ASSERT(storage_get_replay_counter((uint8_t*)&replay_counter));
JADE_ASSERT(storage_get_replay_counter(&replay_counter));
JADE_ASSERT(replay_counter == initial_replay_counter + 2);

if (!keychain_load(aeskey2, sizeof(aeskey2))) {
Expand Down
15 changes: 12 additions & 3 deletions main/process/pinclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ typedef struct {
uint8_t cke[EC_PUBLIC_KEY_LEN];
uint8_t privkey[EC_PRIVATE_KEY_LEN];
// Monotonic Forward Replay counter required for v2
// (32 bit unsigned little-endian integer)
uint8_t replay_counter[REPLAY_COUNTER_LEN];
} pin_keys_t;

Expand Down Expand Up @@ -207,8 +208,11 @@ static bool generate_ske(pin_keys_t* pinkeys)
return false;
}

if (wally_hmac_sha256(
pinkeys->cke, EC_PUBLIC_KEY_LEN, pinkeys->replay_counter, REPLAY_COUNTER_LEN, hmac_tweak, HMAC_SHA256_LEN)
uint8_t counter[sizeof(pinkeys->replay_counter)];
JADE_STATIC_ASSERT(sizeof(counter) == REPLAY_COUNTER_LEN);
// FIXME: counter needs to be byte-swapped if we are big-endian
memcpy(counter, pinkeys->replay_counter, sizeof(counter));
if (wally_hmac_sha256(pinkeys->cke, EC_PUBLIC_KEY_LEN, counter, sizeof(counter), hmac_tweak, HMAC_SHA256_LEN)
!= WALLY_OK) {
return false;
}
Expand Down Expand Up @@ -308,7 +312,12 @@ static pinserver_result_t generate_ephemeral_pinkeys(pin_keys_t* pinkeys)
}

// Load the replay counter and deduce the server key via tweak
const bool res = storage_get_replay_counter(pinkeys->replay_counter);
uint32_t counter;
const bool res = storage_get_replay_counter(&counter);
if (res) {
// FIXME: counter needs to be byte-swapped if we are big-endian
memcpy(pinkeys->replay_counter, &counter, sizeof(counter));
}
if (!res || !generate_ske(pinkeys)) {
JADE_LOGE("Failed to deduce ephemeral server key");
RETURN_RESULT(
Expand Down
12 changes: 7 additions & 5 deletions main/storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,10 +494,11 @@ uint8_t storage_get_counter(void)
return read_blob_fixed(DEFAULT_NAMESPACE, PIN_COUNTER_FIELD, &counter, sizeof(counter)) ? counter : 0;
}

bool storage_get_replay_counter(uint8_t* replay_counter)
bool storage_get_replay_counter(uint32_t* replay_counter)
{
// returns the latest counter and increments the one on flash for next use
// if a counter is not set we create one set to 0
// returns the latest counter and increments the one on flash for next use.
// Note that the replay counter is never reset, only incremented.
// if no counter is set (i.e. brand new device), we create one set to 0.
JADE_ASSERT(replay_counter);

nvs_handle handle;
Expand All @@ -514,8 +515,9 @@ bool storage_get_replay_counter(uint8_t* replay_counter)
j = 0;
}
JADE_ASSERT(j < UINT32_MAX);
memcpy(replay_counter, &j, sizeof(j));
err = nvs_set_u32(handle, REPLAY_COUNTER_FIELD, ++j);

*replay_counter = j;
err = nvs_set_u32(handle, REPLAY_COUNTER_FIELD, j + 1);
if (err != ESP_OK) {
JADE_LOGE("nvs_set_u32() for %s failed: %u", REPLAY_COUNTER_FIELD, err);
nvs_close(handle);
Expand Down
2 changes: 1 addition & 1 deletion main/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ bool storage_get_encrypted_blob(uint8_t* encrypted, size_t encrypted_len, size_t
bool storage_decrement_counter(void);
bool storage_restore_counter(void);
uint8_t storage_get_counter(void);
bool storage_get_replay_counter(uint8_t* replay_counter);
bool storage_get_replay_counter(uint32_t* replay_counter);
bool storage_erase_encrypted_blob(void);

bool storage_set_key_flags(uint8_t flags);
Expand Down

0 comments on commit e583208

Please sign in to comment.