Skip to content

Commit 08e998c

Browse files
committed
Merge branch 'port-unlock'
2 parents 5feaf82 + 69dd468 commit 08e998c

File tree

13 files changed

+160
-4355
lines changed

13 files changed

+160
-4355
lines changed

src/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ set(DBB-FIRMWARE-SOURCES
3636
${CMAKE_SOURCE_DIR}/src/i2c_ecc.c
3737
${CMAKE_SOURCE_DIR}/src/touch/gestures.c
3838
${CMAKE_SOURCE_DIR}/src/reset.c
39-
${CMAKE_SOURCE_DIR}/src/cipher/cipher.c
4039
${CMAKE_SOURCE_DIR}/src/queue.c
4140
${CMAKE_SOURCE_DIR}/src/usb/usb_processing.c
4241
)

src/cipher/cipher.c

Lines changed: 0 additions & 58 deletions
This file was deleted.

src/cipher/cipher.h

Lines changed: 0 additions & 52 deletions
This file was deleted.

src/keystore.c

Lines changed: 0 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
#include <string.h>
1616

17-
#include "cipher/cipher.h"
1817
#include "hardfault.h"
1918
#include "keystore.h"
2019
#include "memory/bitbox02_smarteeprom.h"
@@ -28,138 +27,6 @@
2827
#include <rust/rust.h>
2928
#include <secp256k1_ecdsa_s2c.h>
3029

31-
// Unlocking the keystore take longer than the 500ms watchdog we have setup. Reset the watchdog
32-
// counter to (~7s) to avoid incorrectly assuming we lost communication with the app.
33-
#define LONG_TIMEOUT (-70)
34-
35-
/**
36-
* We allow seeds of 16, 24 or 32 bytes.
37-
*/
38-
static bool _validate_seed_length(size_t seed_len)
39-
{
40-
return seed_len == 16 || seed_len == 24 || seed_len == 32;
41-
}
42-
43-
/**
44-
* Retrieves the encrypted seed and attempts to decrypt it using the password.
45-
*
46-
* `securechip_result_out`, if not NULL, will contain the error code from `securechip_kdf()` if
47-
* there was a secure chip error, and 0 otherwise.
48-
*/
49-
static keystore_error_t _get_and_decrypt_seed(
50-
const char* password,
51-
uint8_t* decrypted_seed_out,
52-
size_t* decrypted_seed_len_out,
53-
int* securechip_result_out)
54-
{
55-
uint8_t encrypted_seed_and_hmac[96];
56-
UTIL_CLEANUP_32(encrypted_seed_and_hmac);
57-
uint8_t encrypted_len;
58-
if (!memory_get_encrypted_seed_and_hmac(encrypted_seed_and_hmac, &encrypted_len)) {
59-
return KEYSTORE_ERR_MEMORY;
60-
}
61-
uint8_t secret[32];
62-
UTIL_CLEANUP_32(secret);
63-
int stretch_result = securechip_stretch_password(password, secret);
64-
if (stretch_result) {
65-
if (stretch_result == SC_ERR_INCORRECT_PASSWORD) {
66-
// Our Optiga securechip implementation fails password stretching if the password is
67-
// wrong, so we can early-abort here. The ATECC stretches the password without checking
68-
// if the password is correct, and we determine if it is correct in the seed decryption
69-
// step below.
70-
return KEYSTORE_ERR_INCORRECT_PASSWORD;
71-
}
72-
if (securechip_result_out != NULL) {
73-
*securechip_result_out = stretch_result;
74-
}
75-
return KEYSTORE_ERR_SECURECHIP;
76-
}
77-
if (encrypted_len < 49) {
78-
Abort("_get_and_decrypt_seed: underflow / zero size");
79-
}
80-
size_t decrypted_len = encrypted_len - 48;
81-
uint8_t decrypted[decrypted_len];
82-
bool password_correct = cipher_aes_hmac_decrypt(
83-
encrypted_seed_and_hmac, encrypted_len, decrypted, &decrypted_len, secret);
84-
if (!password_correct) {
85-
return KEYSTORE_ERR_INCORRECT_PASSWORD;
86-
}
87-
if (!_validate_seed_length(decrypted_len)) {
88-
util_zero(decrypted, sizeof(decrypted));
89-
return KEYSTORE_ERR_SEED_SIZE;
90-
}
91-
*decrypted_seed_len_out = decrypted_len;
92-
memcpy(decrypted_seed_out, decrypted, decrypted_len);
93-
94-
return KEYSTORE_OK;
95-
}
96-
97-
USE_RESULT static keystore_error_t _retain_seed(const uint8_t* seed, size_t seed_len)
98-
{
99-
if (!rust_keystore_retain_seed(rust_util_bytes(seed, seed_len))) {
100-
return KEYSTORE_ERR_STRETCH_RETAINED_SEED_KEY;
101-
}
102-
return KEYSTORE_OK;
103-
}
104-
105-
keystore_error_t keystore_unlock(
106-
const char* password,
107-
int* securechip_result_out,
108-
uint8_t* seed_out,
109-
size_t* seed_len_out)
110-
{
111-
if (!memory_is_seeded()) {
112-
return KEYSTORE_ERR_UNSEEDED;
113-
}
114-
uint8_t failed_attempts = bitbox02_smarteeprom_get_unlock_attempts();
115-
if (failed_attempts >= MAX_UNLOCK_ATTEMPTS) {
116-
/*
117-
* We reset the device as soon as the MAX_UNLOCK_ATTEMPTSth attempt
118-
* is made. So we should never enter this branch...
119-
* This is just an extraordinary measure for added resilience.
120-
*/
121-
reset_reset(false);
122-
return KEYSTORE_ERR_MAX_ATTEMPTS_EXCEEDED;
123-
}
124-
usb_processing_timeout_reset(LONG_TIMEOUT);
125-
126-
bitbox02_smarteeprom_increment_unlock_attempts();
127-
uint8_t seed[KEYSTORE_MAX_SEED_LENGTH] = {0};
128-
UTIL_CLEANUP_32(seed);
129-
size_t seed_len;
130-
keystore_error_t result =
131-
_get_and_decrypt_seed(password, seed, &seed_len, securechip_result_out);
132-
if (result != KEYSTORE_OK) {
133-
failed_attempts = bitbox02_smarteeprom_get_unlock_attempts();
134-
135-
if (failed_attempts >= MAX_UNLOCK_ATTEMPTS) {
136-
reset_reset(false);
137-
return KEYSTORE_ERR_MAX_ATTEMPTS_EXCEEDED;
138-
}
139-
140-
return result;
141-
}
142-
143-
if (rust_keystore_is_unlocked_device()) {
144-
// Already unlocked. Fail if the seed changed under our feet (should never happen).
145-
if (!rust_keystore_check_retained_seed(rust_util_bytes(seed, seed_len))) {
146-
Abort("Seed has suddenly changed. This should never happen.");
147-
}
148-
} else {
149-
keystore_error_t retain_seed_result = _retain_seed(seed, seed_len);
150-
if (retain_seed_result != KEYSTORE_OK) {
151-
return retain_seed_result;
152-
}
153-
}
154-
bitbox02_smarteeprom_reset_unlock_attempts();
155-
156-
if (seed_out != NULL && seed_len_out != NULL) {
157-
memcpy(seed_out, seed, seed_len);
158-
*seed_len_out = seed_len;
159-
}
160-
return KEYSTORE_OK;
161-
}
162-
16330
bool keystore_get_bip39_word_stack(uint16_t idx, char* word_out, size_t word_out_size)
16431
{
16532
return rust_get_bip39_word(idx, rust_util_bytes_mut((uint8_t*)word_out, word_out_size));

src/keystore.h

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -23,58 +23,11 @@
2323

2424
#include <secp256k1.h>
2525

26-
#define KEYSTORE_MAX_SEED_LENGTH (32)
2726
#define KEYSTORE_U2F_SEED_LENGTH SHA256_LEN
2827

2928
// Max. length of an xpub string, including the null terminator.
3029
#define XPUB_ENCODED_LEN 113
3130

32-
typedef enum {
33-
KEYSTORE_OK,
34-
KEYSTORE_ERR_INCORRECT_PASSWORD,
35-
KEYSTORE_ERR_MAX_ATTEMPTS_EXCEEDED,
36-
KEYSTORE_ERR_UNSEEDED,
37-
KEYSTORE_ERR_MEMORY,
38-
KEYSTORE_ERR_SECURECHIP,
39-
KEYSTORE_ERR_SEED_SIZE,
40-
KEYSTORE_ERR_SALT,
41-
KEYSTORE_ERR_HASH,
42-
KEYSTORE_ERR_ENCRYPT,
43-
KEYSTORE_ERR_DECRYPT,
44-
KEYSTORE_ERR_STRETCH_RETAINED_SEED_KEY,
45-
} keystore_error_t;
46-
47-
/**
48-
* Restores a seed. This also unlocks the keystore with this seed.
49-
* @param[in] seed The seed that is to be restored.
50-
* @param[in] seed_length The length of the seed (max. 32 bytes).
51-
* @param[in] password The password with which we encrypt the seed.
52-
*/
53-
/** Unlocks the keystore seed or checks the password:
54-
* If the keystore is locked, it decrypts and loads the seed, unlocking the keystore:
55-
* 1) loads the stored seed and tries to decrypt using password.
56-
* 2) if successful, the bip39 seed should be derived using keystore_unlock_bip39().
57-
* If the keystore is already unlocked, this function does *not* change the state (can be used to
58-
* check the password).
59-
* @param[in] password keystore password, used to decrypt the seed.
60-
* If it is false, the keystore is not unlocked.
61-
* @param[out] securechip_result_out, if not NULL, will contain the error code from
62-
* @param[out] seed_out The seed bytes copied from the retained seed.
63-
* The buffer should be KEYSTORE_MAX_SEED_LENGTH bytes long. The caller must
64-
* zero the seed once it is no longer needed.
65-
* @param[out] seed_len_out The seed length.
66-
* `securechip_kdf()` if there was a secure chip error, and 0 otherwise.
67-
* @return
68-
* - KEYSTORE_OK if they keystore was successfully unlocked
69-
* - KEYSTORE_ERR_* if unsuccessful.
70-
* Only call this if memory_is_seeded() returns true.
71-
*/
72-
USE_RESULT keystore_error_t keystore_unlock(
73-
const char* password,
74-
int* securechip_result_out,
75-
uint8_t* seed_out,
76-
size_t* seed_len_out);
77-
7831
/**
7932
* Retrieves the BIP39 word by index. `word_out` should be of at least 9 bytes long.
8033
*/

0 commit comments

Comments
 (0)