Skip to content

Commit caf7c8b

Browse files
committed
Merge remote-tracking branch 'benma/optiga-lowctr'
2 parents 051e45b + 5f380b2 commit caf7c8b

File tree

12 files changed

+745
-164
lines changed

12 files changed

+745
-164
lines changed

src/atecc/atecc.c

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
#include "hardfault.h"
1717
#include "securechip/securechip.h"
1818
#include <i2c_ecc.h>
19+
#include <salt.h>
1920
#include <util.h>
21+
#include <wally_crypto.h>
2022

2123
// disabling some warnings, as it's an external library.
2224
#pragma GCC diagnostic push
@@ -75,6 +77,10 @@ static uint8_t _configuration[ATCA_ECC_CONFIG_SIZE] = {
7577
// Number of times the first kdf slot can be used.
7678
#define MONOTONIC_COUNTER_MAX_USE (730500)
7779

80+
// This number of KDF iterations on the 2nd kdf slot when stretching the device
81+
// password.
82+
#define KDF_NUM_ITERATIONS (2)
83+
7884
// The total individual size of the public key data slots (slots 9-15) is 72 bytes. Using encrypted
7985
// read/write it is only possible to transmit 32 bytes. The last block is therefore 8 (72 =
8086
// 32+32+8).
@@ -516,14 +522,6 @@ static ATCA_STATUS _update_kdf_key(void)
516522
ATECC_SLOT_KDF, 0, new_key, encryption_key, ATECC_SLOT_ENCRYPTION_KEY, nonce_contribution);
517523
}
518524

519-
bool atecc_update_keys(void)
520-
{
521-
if (_rollkey() != ATCA_SUCCESS) {
522-
return false;
523-
}
524-
return _update_kdf_key() == ATCA_SUCCESS;
525-
}
526-
527525
static int _atecc_kdf(atecc_slot_t slot, const uint8_t* msg, size_t len, uint8_t* kdf_out)
528526
{
529527
if (len > 127 || (slot != ATECC_SLOT_ROLLKEY && slot != ATECC_SLOT_KDF)) {
@@ -586,9 +584,70 @@ int atecc_kdf(const uint8_t* msg, size_t len, uint8_t* kdf_out)
586584
return _atecc_kdf(ATECC_SLOT_KDF, msg, len, kdf_out);
587585
}
588586

589-
int atecc_kdf_rollkey(const uint8_t* msg, size_t len, uint8_t* kdf_out)
587+
int atecc_init_new_password(const char* password)
588+
{
589+
(void)password;
590+
if (!atecc_reset_keys()) {
591+
return SC_ATECC_ERR_RESET_KEYS;
592+
}
593+
return 0;
594+
}
595+
596+
int atecc_stretch_password(const char* password, uint8_t* stretched_out)
590597
{
591-
return _atecc_kdf(ATECC_SLOT_ROLLKEY, msg, len, kdf_out);
598+
uint8_t password_salted_hashed[32] = {0};
599+
UTIL_CLEANUP_32(password_salted_hashed);
600+
if (!salt_hash_data(
601+
(const uint8_t*)password,
602+
strlen(password),
603+
"keystore_seed_access_in",
604+
password_salted_hashed)) {
605+
return SC_ERR_SALT;
606+
}
607+
608+
uint8_t kdf_in[32] = {0};
609+
UTIL_CLEANUP_32(kdf_in);
610+
memcpy(kdf_in, password_salted_hashed, 32);
611+
612+
// First KDF on rollkey increments the monotonic counter. Call only once!
613+
int securechip_result = _atecc_kdf(ATECC_SLOT_ROLLKEY, kdf_in, 32, stretched_out);
614+
if (securechip_result) {
615+
return securechip_result;
616+
}
617+
// Second KDF does not use the counter and we call it multiple times.
618+
for (int i = 0; i < KDF_NUM_ITERATIONS; i++) {
619+
memcpy(kdf_in, stretched_out, 32);
620+
securechip_result = securechip_kdf(kdf_in, 32, stretched_out);
621+
if (securechip_result) {
622+
return securechip_result;
623+
}
624+
}
625+
626+
if (!salt_hash_data(
627+
(const uint8_t*)password,
628+
strlen(password),
629+
"keystore_seed_access_out",
630+
password_salted_hashed)) {
631+
return SC_ERR_SALT;
632+
}
633+
if (wally_hmac_sha256(
634+
password_salted_hashed,
635+
sizeof(password_salted_hashed),
636+
stretched_out,
637+
32,
638+
stretched_out,
639+
32) != WALLY_OK) {
640+
return SC_ERR_HASH;
641+
}
642+
return 0;
643+
}
644+
645+
bool atecc_reset_keys(void)
646+
{
647+
if (_rollkey() != ATCA_SUCCESS) {
648+
return false;
649+
}
650+
return _update_kdf_key() == ATCA_SUCCESS;
592651
}
593652

594653
bool atecc_gen_attestation_key(uint8_t* pubkey_out)

src/atecc/atecc.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@
2626
#include <stdint.h>
2727

2828
USE_RESULT int atecc_setup(const securechip_interface_functions_t* ifs);
29-
USE_RESULT bool atecc_update_keys(void);
3029
USE_RESULT int atecc_kdf(const uint8_t* msg, size_t len, uint8_t* kdf_out);
31-
USE_RESULT int atecc_kdf_rollkey(const uint8_t* msg, size_t len, uint8_t* kdf_out);
30+
USE_RESULT int atecc_init_new_password(const char* password);
31+
USE_RESULT int atecc_stretch_password(const char* password, uint8_t* stretched_out);
32+
USE_RESULT bool atecc_reset_keys(void);
3233
USE_RESULT bool atecc_gen_attestation_key(uint8_t* pubkey_out);
3334
USE_RESULT bool atecc_attestation_sign(const uint8_t* challenge, uint8_t* signature_out);
3435
USE_RESULT bool atecc_monotonic_increments_remaining(uint32_t* remaining_out);

src/factorysetup.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,12 @@ static void _api_msg(const uint8_t* input, size_t in_len, uint8_t* output, size_
277277
screen_print_debug("DONE", 0);
278278
break;
279279
case OP_SC_ROLLKEYS:
280-
if (!securechip_update_keys()) {
281-
screen_print_debug("rollkeys: failed", 0);
280+
if (!securechip_reset_keys()) {
281+
screen_print_debug("resetting securechip keys: failed", 0);
282282
result = ERR_FAILED;
283283
break;
284284
}
285-
screen_print_debug("rollkeys: success", 100);
285+
screen_print_debug("resetting securechip keys: success", 100);
286286
if (!securechip_u2f_counter_set(0)) {
287287
screen_print_debug("reset u2f counter", 0);
288288
result = ERR_FAILED;

src/keystore.c

Lines changed: 16 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -160,69 +160,6 @@ static bool _copy_bip39_seed(uint8_t* bip39_seed_out)
160160
return true;
161161
}
162162

163-
/**
164-
* Stretch the user password using the securechip, putting the result in `kdf_out`, which must be 32
165-
* bytes. `securechip_result_out`, if not NULL, will contain the error code from `securechip_kdf()`
166-
* if there was a secure chip error, and 0 otherwise.
167-
*/
168-
static keystore_error_t _stretch_password(
169-
const char* password,
170-
uint8_t* kdf_out,
171-
int* securechip_result_out)
172-
{
173-
if (securechip_result_out != NULL) {
174-
*securechip_result_out = 0;
175-
}
176-
uint8_t password_salted_hashed[32] = {0};
177-
UTIL_CLEANUP_32(password_salted_hashed);
178-
if (!salt_hash_data(
179-
(const uint8_t*)password,
180-
strlen(password),
181-
"keystore_seed_access_in",
182-
password_salted_hashed)) {
183-
return KEYSTORE_ERR_SALT;
184-
}
185-
186-
uint8_t kdf_in[32] = {0};
187-
UTIL_CLEANUP_32(kdf_in);
188-
memcpy(kdf_in, password_salted_hashed, 32);
189-
190-
// First KDF on rollkey increments the monotonic counter. Call only once!
191-
int securechip_result = securechip_kdf_rollkey(kdf_in, 32, kdf_out);
192-
if (securechip_result) {
193-
if (securechip_result_out != NULL) {
194-
*securechip_result_out = securechip_result;
195-
}
196-
return KEYSTORE_ERR_SECURECHIP;
197-
}
198-
// Second KDF does not use the counter and we call it multiple times.
199-
for (int i = 0; i < KDF_NUM_ITERATIONS; i++) {
200-
memcpy(kdf_in, kdf_out, 32);
201-
securechip_result = securechip_kdf(kdf_in, 32, kdf_out);
202-
if (securechip_result) {
203-
if (securechip_result_out != NULL) {
204-
*securechip_result_out = securechip_result;
205-
}
206-
return KEYSTORE_ERR_SECURECHIP;
207-
}
208-
}
209-
210-
if (!salt_hash_data(
211-
(const uint8_t*)password,
212-
strlen(password),
213-
"keystore_seed_access_out",
214-
password_salted_hashed)) {
215-
return KEYSTORE_ERR_SALT;
216-
}
217-
if (wally_hmac_sha256(
218-
password_salted_hashed, sizeof(password_salted_hashed), kdf_out, 32, kdf_out, 32) !=
219-
WALLY_OK) {
220-
return KEYSTORE_ERR_HASH;
221-
}
222-
223-
return KEYSTORE_OK;
224-
}
225-
226163
/**
227164
* Retrieves the encrypted seed and attempts to decrypt it using the password.
228165
*
@@ -243,9 +180,19 @@ static keystore_error_t _get_and_decrypt_seed(
243180
}
244181
uint8_t secret[32];
245182
UTIL_CLEANUP_32(secret);
246-
keystore_error_t result = _stretch_password(password, secret, securechip_result_out);
247-
if (result != KEYSTORE_OK) {
248-
return result;
183+
int stretch_result = securechip_stretch_password(password, secret);
184+
if (stretch_result) {
185+
if (stretch_result == SC_ERR_INCORRECT_PASSWORD) {
186+
// Our Optiga securechip implementation fails password stretching if the password is
187+
// wrong, so we can early-abort here. The ATECC stretches the password without checking
188+
// if the password is correct, and we determine if it is correct in the seed decryption
189+
// step below.
190+
return KEYSTORE_ERR_INCORRECT_PASSWORD;
191+
}
192+
if (securechip_result_out != NULL) {
193+
*securechip_result_out = stretch_result;
194+
}
195+
return KEYSTORE_ERR_SECURECHIP;
249196
}
250197
if (encrypted_len < 49) {
251198
Abort("_get_and_decrypt_seed: underflow / zero size");
@@ -299,17 +246,13 @@ keystore_error_t keystore_encrypt_and_store_seed(
299246
if (!_validate_seed_length(seed_length)) {
300247
return KEYSTORE_ERR_SEED_SIZE;
301248
}
302-
// Update the two kdf keys before setting a new password. This already
303-
// happens on a device reset, but we do it here again anyway so the keys are
304-
// initialized also on first use, reducing trust in the factory setup.
305-
if (!securechip_update_keys()) {
249+
if (securechip_init_new_password(password)) {
306250
return KEYSTORE_ERR_SECURECHIP;
307251
}
308252
uint8_t secret[32] = {0};
309253
UTIL_CLEANUP_32(secret);
310-
keystore_error_t res = _stretch_password(password, secret, NULL);
311-
if (res != KEYSTORE_OK) {
312-
return res;
254+
if (securechip_stretch_password(password, secret)) {
255+
return KEYSTORE_ERR_SECURECHIP;
313256
}
314257

315258
size_t encrypted_seed_len = seed_length + 64;

0 commit comments

Comments
 (0)