Skip to content

Commit f507206

Browse files
committed
keystore: make password stretching a function of the securechip
So the two different securechip implementations (ATECC608 and Optiga Trust M V3) can implement stretching differently. This is needed because in the Optiga, we will add an additional stretching step.
1 parent 67c727d commit f507206

File tree

10 files changed

+144
-92
lines changed

10 files changed

+144
-92
lines changed

src/atecc/atecc.c

+52-2
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).
@@ -586,9 +592,53 @@ int atecc_kdf(const uint8_t* msg, size_t len, uint8_t* kdf_out)
586592
return _atecc_kdf(ATECC_SLOT_KDF, msg, len, kdf_out);
587593
}
588594

589-
int atecc_kdf_rollkey(const uint8_t* msg, size_t len, uint8_t* kdf_out)
595+
int atecc_stretch_password(const char* password, uint8_t* stretched_out)
590596
{
591-
return _atecc_kdf(ATECC_SLOT_ROLLKEY, msg, len, kdf_out);
597+
uint8_t password_salted_hashed[32] = {0};
598+
UTIL_CLEANUP_32(password_salted_hashed);
599+
if (!salt_hash_data(
600+
(const uint8_t*)password,
601+
strlen(password),
602+
"keystore_seed_access_in",
603+
password_salted_hashed)) {
604+
return SC_ERR_SALT;
605+
}
606+
607+
uint8_t kdf_in[32] = {0};
608+
UTIL_CLEANUP_32(kdf_in);
609+
memcpy(kdf_in, password_salted_hashed, 32);
610+
611+
// First KDF on rollkey increments the monotonic counter. Call only once!
612+
int securechip_result = _atecc_kdf(ATECC_SLOT_ROLLKEY, kdf_in, 32, stretched_out);
613+
if (securechip_result) {
614+
return securechip_result;
615+
}
616+
// Second KDF does not use the counter and we call it multiple times.
617+
for (int i = 0; i < KDF_NUM_ITERATIONS; i++) {
618+
memcpy(kdf_in, stretched_out, 32);
619+
securechip_result = securechip_kdf(kdf_in, 32, stretched_out);
620+
if (securechip_result) {
621+
return securechip_result;
622+
}
623+
}
624+
625+
if (!salt_hash_data(
626+
(const uint8_t*)password,
627+
strlen(password),
628+
"keystore_seed_access_out",
629+
password_salted_hashed)) {
630+
return SC_ERR_SALT;
631+
}
632+
if (wally_hmac_sha256(
633+
password_salted_hashed,
634+
sizeof(password_salted_hashed),
635+
stretched_out,
636+
32,
637+
stretched_out,
638+
32) != WALLY_OK) {
639+
return SC_ERR_HASH;
640+
}
641+
return 0;
592642
}
593643

594644
bool atecc_gen_attestation_key(uint8_t* pubkey_out)

src/atecc/atecc.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
USE_RESULT int atecc_setup(const securechip_interface_functions_t* ifs);
2929
USE_RESULT bool atecc_update_keys(void);
3030
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);
31+
USE_RESULT int atecc_stretch_password(const char* password, uint8_t* stretched_out);
3232
USE_RESULT bool atecc_gen_attestation_key(uint8_t* pubkey_out);
3333
USE_RESULT bool atecc_attestation_sign(const uint8_t* challenge, uint8_t* signature_out);
3434
USE_RESULT bool atecc_monotonic_increments_remaining(uint32_t* remaining_out);

src/keystore.c

+8-69
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,12 @@ 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 (securechip_result_out != NULL) {
185+
*securechip_result_out = stretch_result;
186+
}
187+
if (stretch_result) {
188+
return KEYSTORE_ERR_SECURECHIP;
249189
}
250190
if (encrypted_len < 49) {
251191
Abort("_get_and_decrypt_seed: underflow / zero size");
@@ -307,9 +247,8 @@ keystore_error_t keystore_encrypt_and_store_seed(
307247
}
308248
uint8_t secret[32] = {0};
309249
UTIL_CLEANUP_32(secret);
310-
keystore_error_t res = _stretch_password(password, secret, NULL);
311-
if (res != KEYSTORE_OK) {
312-
return res;
250+
if (securechip_stretch_password(password, secret)) {
251+
return KEYSTORE_ERR_SECURECHIP;
313252
}
314253

315254
size_t encrypted_seed_len = seed_length + 64;

src/optiga/optiga.c

+56-1
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
#include <optiga_crypt.h>
2424
#include <optiga_util.h>
2525
#include <rust/rust.h>
26+
#include <salt.h>
2627
#include <securechip/securechip.h>
2728
#include <util.h>
29+
#include <wally_crypto.h>
2830

2931
// Set this to 1 for a more convenience during development.
3032
// Factory setup will be performed in the normal firmware, which makes it easier to tinker with the
@@ -67,6 +69,10 @@
6769
// See Solution Reference Manual Table 79 "Data structure arbitrary data object".
6870
#define ARBITRARY_DATA_OBJECT_TYPE_3_MAX_SIZE 140
6971

72+
// This number of KDF iterations on the external kdf slot when stretching the device
73+
// password.
74+
#define KDF_NUM_ITERATIONS (2)
75+
7076
// Struct stored in the arbitrary data object.
7177
#pragma GCC diagnostic push
7278
#pragma GCC diagnostic ignored "-Wpacked"
@@ -1140,7 +1146,7 @@ int optiga_kdf_external(const uint8_t* msg, size_t len, uint8_t* mac_out)
11401146
return 0;
11411147
}
11421148

1143-
int optiga_kdf_internal(const uint8_t* msg, size_t len, uint8_t* kdf_out)
1149+
static int _kdf_internal(const uint8_t* msg, size_t len, uint8_t* kdf_out)
11441150
{
11451151
if (len != 32) {
11461152
return SC_ERR_INVALID_ARGS;
@@ -1172,6 +1178,55 @@ int optiga_kdf_internal(const uint8_t* msg, size_t len, uint8_t* kdf_out)
11721178
return 0;
11731179
}
11741180

1181+
int optiga_stretch_password(const char* password, uint8_t* stretched_out)
1182+
{
1183+
uint8_t password_salted_hashed[32] = {0};
1184+
UTIL_CLEANUP_32(password_salted_hashed);
1185+
if (!salt_hash_data(
1186+
(const uint8_t*)password,
1187+
strlen(password),
1188+
"optiga_password_stretch_in",
1189+
password_salted_hashed)) {
1190+
return SC_ERR_SALT;
1191+
}
1192+
1193+
uint8_t kdf_in[32] = {0};
1194+
UTIL_CLEANUP_32(kdf_in);
1195+
memcpy(kdf_in, password_salted_hashed, 32);
1196+
1197+
// First KDF on internal key increments the monotonic counter. Call only once!
1198+
int securechip_result = _kdf_internal(kdf_in, 32, stretched_out);
1199+
if (securechip_result) {
1200+
return securechip_result;
1201+
}
1202+
// Second KDF does not use the counter and we call it multiple times.
1203+
for (int i = 0; i < KDF_NUM_ITERATIONS; i++) {
1204+
memcpy(kdf_in, stretched_out, 32);
1205+
securechip_result = optiga_kdf_external(kdf_in, 32, stretched_out);
1206+
if (securechip_result) {
1207+
return securechip_result;
1208+
}
1209+
}
1210+
1211+
if (!salt_hash_data(
1212+
(const uint8_t*)password,
1213+
strlen(password),
1214+
"optiga_password_stretch_out",
1215+
password_salted_hashed)) {
1216+
return SC_ERR_SALT;
1217+
}
1218+
if (wally_hmac_sha256(
1219+
password_salted_hashed,
1220+
sizeof(password_salted_hashed),
1221+
stretched_out,
1222+
32,
1223+
stretched_out,
1224+
32) != WALLY_OK) {
1225+
return SC_ERR_HASH;
1226+
}
1227+
return 0;
1228+
}
1229+
11751230
bool optiga_gen_attestation_key(uint8_t* pubkey_out)
11761231
{
11771232
optiga_key_id_t slot = OPTIGA_KEY_ID_E0F1;

src/optiga/optiga.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
USE_RESULT int optiga_setup(const securechip_interface_functions_t* ifs);
2929
USE_RESULT bool optiga_update_keys(void);
3030
USE_RESULT int optiga_kdf_external(const uint8_t* msg, size_t len, uint8_t* mac_out);
31-
USE_RESULT int optiga_kdf_internal(const uint8_t* msg, size_t len, uint8_t* mac_out);
31+
USE_RESULT int optiga_stretch_password(const char* password, uint8_t* stretched_out);
3232
USE_RESULT bool optiga_gen_attestation_key(uint8_t* pubkey_out);
3333
USE_RESULT bool optiga_attestation_sign(const uint8_t* challenge, uint8_t* signature_out);
3434
USE_RESULT bool optiga_monotonic_increments_remaining(uint32_t* remaining_out);

src/securechip/securechip.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ typedef struct {
2323
int (*setup)(const securechip_interface_functions_t* fns);
2424
bool (*update_keys)(void);
2525
int (*kdf)(const uint8_t* msg, size_t msg_len, uint8_t* kdf_out);
26-
int (*kdf_rollkey)(const uint8_t* msg, size_t msg_len, uint8_t* kdf_out);
26+
int (*stretch_password)(const char* password, uint8_t* stretched_out);
2727
bool (*gen_attestation_key)(uint8_t* pubkey_out);
2828
bool (*attestation_sign)(const uint8_t* challenge, uint8_t* signature_out);
2929
bool (*monotonic_increments_remaining)(uint32_t* remaining_out);
@@ -47,7 +47,7 @@ bool securechip_init(void)
4747
_fns.setup = optiga_setup;
4848
_fns.update_keys = optiga_update_keys;
4949
_fns.kdf = optiga_kdf_external;
50-
_fns.kdf_rollkey = optiga_kdf_internal;
50+
_fns.stretch_password = optiga_stretch_password;
5151
_fns.gen_attestation_key = optiga_gen_attestation_key;
5252
_fns.attestation_sign = optiga_attestation_sign;
5353
_fns.monotonic_increments_remaining = optiga_monotonic_increments_remaining;
@@ -65,7 +65,7 @@ bool securechip_init(void)
6565
_fns.setup = atecc_setup;
6666
_fns.update_keys = atecc_update_keys;
6767
_fns.kdf = atecc_kdf;
68-
_fns.kdf_rollkey = atecc_kdf_rollkey;
68+
_fns.stretch_password = atecc_stretch_password;
6969
_fns.gen_attestation_key = atecc_gen_attestation_key;
7070
_fns.attestation_sign = atecc_attestation_sign;
7171
_fns.monotonic_increments_remaining = atecc_monotonic_increments_remaining;
@@ -107,10 +107,10 @@ int securechip_kdf(const uint8_t* msg, size_t msg_len, uint8_t* mac_out)
107107
return _fns.kdf(msg, msg_len, mac_out);
108108
}
109109

110-
int securechip_kdf_rollkey(const uint8_t* msg, size_t msg_len, uint8_t* mac_out)
110+
int securechip_stretch_password(const char* password, uint8_t* stretched_out)
111111
{
112-
ABORT_IF_NULL(kdf_rollkey);
113-
return _fns.kdf_rollkey(msg, msg_len, mac_out);
112+
ABORT_IF_NULL(stretch_password);
113+
return _fns.stretch_password(password, stretched_out);
114114
}
115115

116116
bool securechip_gen_attestation_key(uint8_t* pubkey_out)

src/securechip/securechip.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ typedef enum {
2727
SC_ERR_IFS = -1,
2828
SC_ERR_INVALID_ARGS = -2,
2929
SC_ERR_CONFIG_MISMATCH = -3,
30+
SC_ERR_SALT = -4,
31+
SC_ERR_HASH = -5,
3032

3133
// Errors specific to the ATECC
3234
SC_ATECC_ERR_ZONE_UNLOCKED_CONFIG = -100,
@@ -85,6 +87,7 @@ USE_RESULT bool securechip_update_keys(void);
8587

8688
/**
8789
* Perform KDF using the key in kdf slot with the input msg.
90+
* This must not increment a monotonic counter.
8891
* @param[in] msg Use this msg as input
8992
* @param[in] len Must be <= 127.
9093
* @param[out] kdf_out Must have size 32. Result of the kdf will be stored here.
@@ -95,7 +98,7 @@ USE_RESULT bool securechip_update_keys(void);
9598
USE_RESULT int securechip_kdf(const uint8_t* msg, size_t len, uint8_t* kdf_out);
9699

97100
/**
98-
* Perform KDF using the key in rollkey slot with the input msg.
101+
* Stretch password using secrets in the secure chip.
99102
* Calling this function increments the monotonic counter.
100103
* @param[in] msg Use this msg as input
101104
* @param[in] len Must be <= 127.
@@ -104,7 +107,7 @@ USE_RESULT int securechip_kdf(const uint8_t* msg, size_t len, uint8_t* kdf_out);
104107
* @return 0 on success. Values of `securechip_error_t` if negative. If positive, values of
105108
* `ATCA_STATUS` for ATECC, values of optiga_lib_return_codes.h for Optiga.
106109
*/
107-
USE_RESULT int securechip_kdf_rollkey(const uint8_t* msg, size_t len, uint8_t* kdf_out);
110+
USE_RESULT int securechip_stretch_password(const char* password, uint8_t* stretched_out);
108111

109112
/**
110113
* Generates a new attestation device key and outputs the public key.

test/simulator/framework/mock_securechip.c

+2-7
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,6 @@ bool securechip_update_keys(void)
2929
return true;
3030
}
3131

32-
// Mocked contents of the secure chip rollkey slot.
33-
static const uint8_t _rollkey[32] =
34-
"\x9d\xd1\x34\x1f\x6b\x4b\x26\xb1\x72\x89\xa1\xa3\x92\x71\x5c\xf0\xd0\x57\x8c\x84\xdb\x9a\x51"
35-
"\xeb\xde\x14\x24\x06\x69\xd1\xd0\x5e";
36-
3732
// Mocked contents of the securechip kdf slot.
3833
static const uint8_t _kdfkey[32] =
3934
"\xd2\xe1\xe6\xb1\x8b\x6c\x6b\x08\x43\x3e\xdb\xc1\xd1\x68\xc1\xa0\x04\x37\x74\xa4\x22\x18\x77"
@@ -44,9 +39,9 @@ int securechip_kdf(const uint8_t* msg, size_t len, uint8_t* kdf_out)
4439
wally_hmac_sha256(_kdfkey, 32, msg, len, kdf_out, 32);
4540
return 0;
4641
}
47-
int securechip_kdf_rollkey(const uint8_t* msg, size_t len, uint8_t* kdf_out)
42+
int securechip_stretch_password(const char* password, uint8_t* stretched_out)
4843
{
49-
wally_hmac_sha256(_rollkey, 32, msg, len, kdf_out, 32);
44+
memset(stretched_out, 0, 32);
5045
return 0;
5146
}
5247

0 commit comments

Comments
 (0)