Skip to content

Commit 426c1ea

Browse files
committed
unit-test/keystore: test keystore_create_and_store_seed
1 parent b8b6d06 commit 426c1ea

File tree

2 files changed

+76
-11
lines changed

2 files changed

+76
-11
lines changed

test/unit-test/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ set(TEST_LIST
221221
hww
222222
"-Wl,--wrap=random_32_bytes,--wrap=workflow_confirm_dismiss"
223223
keystore
224-
"-Wl,--wrap=secp256k1_anti_klepto_sign,--wrap=memory_is_initialized,--wrap=memory_is_seeded,--wrap=memory_get_failed_unlock_attempts,--wrap=memory_reset_failed_unlock_attempts,--wrap=memory_increment_failed_unlock_attempts,--wrap=memory_set_encrypted_seed_and_hmac,--wrap=memory_get_encrypted_seed_and_hmac,--wrap=reset_reset,--wrap=salt_hash_data,--wrap=cipher_aes_hmac_encrypt"
224+
"-Wl,--wrap=secp256k1_anti_klepto_sign,--wrap=memory_is_initialized,--wrap=memory_is_seeded,--wrap=memory_get_failed_unlock_attempts,--wrap=memory_reset_failed_unlock_attempts,--wrap=memory_increment_failed_unlock_attempts,--wrap=memory_set_encrypted_seed_and_hmac,--wrap=memory_get_encrypted_seed_and_hmac,--wrap=reset_reset,--wrap=salt_hash_data,--wrap=cipher_aes_hmac_encrypt,--wrap=random_32_bytes"
225225
keystore_antiklepto
226226
"-Wl,--wrap=keystore_secp256k1_nonce_commit,--wrap=keystore_secp256k1_sign"
227227
keystore_functional

test/unit-test/test_keystore.c

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
#include <stddef.h>
1818
#include <cmocka.h>
1919

20+
#include <cipher/cipher.h>
2021
#include <keystore.h>
2122
#include <memory/bitbox02_smarteeprom.h>
23+
#include <memory/memory.h>
2224
#include <memory/smarteeprom.h>
2325
#include <secp256k1_ecdsa_s2c.h>
2426
#include <secp256k1_recovery.h>
@@ -29,6 +31,8 @@
2931
#include <stdio.h>
3032
#include <string.h>
3133

34+
#define PASSWORD ("password")
35+
3236
static uint8_t _mock_seed[32] = {
3337
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
3438
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
@@ -46,6 +50,8 @@ static uint8_t _mock_bip39_seed[64] = {
4650
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
4751
};
4852

53+
const uint8_t _aes_iv[32] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
54+
4955
static const uint32_t _keypath[] = {
5056
44 + BIP32_INITIAL_HARDENED_CHILD,
5157
0 + BIP32_INITIAL_HARDENED_CHILD,
@@ -89,6 +95,13 @@ static uint8_t _kdf_out_3[32] = {
8995
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
9096
};
9197

98+
// Fixture: hmac.new(_password_salted_hashed_stretch_out, _kdf_out_3,
99+
// hashlib.sha256).hexdigest()
100+
static uint8_t _expected_secret[32] = {
101+
0x39, 0xa7, 0x4f, 0x75, 0xb6, 0x9d, 0x6c, 0x84, 0x5e, 0x18, 0x91, 0x5b, 0xae, 0x29, 0xd1, 0x06,
102+
0x12, 0x12, 0x40, 0x37, 0x7a, 0x79, 0x97, 0x55, 0xd7, 0xcc, 0xe9, 0x26, 0x1e, 0x16, 0x91, 0x71,
103+
};
104+
92105
int __real_secp256k1_anti_klepto_sign(
93106
const secp256k1_context* ctx,
94107
secp256k1_ecdsa_signature* sig,
@@ -124,6 +137,8 @@ bool __wrap_salt_hash_data(
124137
const char* purpose,
125138
uint8_t* hash_out)
126139
{
140+
check_expected(data);
141+
check_expected(data_len);
127142
check_expected(purpose);
128143
memcpy(hash_out, (const void*)mock(), 32);
129144
return true;
@@ -163,6 +178,11 @@ void __wrap_reset_reset(void)
163178
_reset_reset_called = true;
164179
}
165180

181+
void __wrap_random_32_bytes(uint8_t* buf)
182+
{
183+
memcpy(buf, (const void*)mock(), 32);
184+
}
185+
166186
static bool _pubkeys_equal(
167187
const secp256k1_context* ctx,
168188
const secp256k1_pubkey* pubkey1,
@@ -296,6 +316,8 @@ static void _test_keystore_secp256k1_sign(void** state)
296316

297317
static void _expect_stretch(bool valid)
298318
{
319+
expect_memory(__wrap_salt_hash_data, data, PASSWORD, strlen(PASSWORD));
320+
expect_value(__wrap_salt_hash_data, data_len, strlen(PASSWORD));
299321
expect_string(__wrap_salt_hash_data, purpose, "keystore_seed_access_in");
300322
will_return(__wrap_salt_hash_data, _password_salted_hashed_stretch_in);
301323

@@ -314,6 +336,8 @@ static void _expect_stretch(bool valid)
314336
expect_memory(securechip_kdf, msg, _kdf_out_2, 32);
315337
will_return(securechip_kdf, _kdf_out_3);
316338

339+
expect_memory(__wrap_salt_hash_data, data, PASSWORD, strlen(PASSWORD));
340+
expect_value(__wrap_salt_hash_data, data_len, strlen(PASSWORD));
317341
expect_string(__wrap_salt_hash_data, purpose, "keystore_seed_access_out");
318342
will_return(
319343
__wrap_salt_hash_data,
@@ -327,18 +351,11 @@ static void _expect_encrypt_and_store_seed(void)
327351
_expect_stretch(true); // first stretch to encrypt
328352
_expect_stretch(true); // second stretch to verify
329353

330-
// Fixture: hmac.new(_password_salted_hashed_stretch_out, _kdf_out_3,
331-
// hashlib.sha256).hexdigest()
332-
static uint8_t expected_secret[32] = {
333-
0x39, 0xa7, 0x4f, 0x75, 0xb6, 0x9d, 0x6c, 0x84, 0x5e, 0x18, 0x91,
334-
0x5b, 0xae, 0x29, 0xd1, 0x06, 0x12, 0x12, 0x40, 0x37, 0x7a, 0x79,
335-
0x97, 0x55, 0xd7, 0xcc, 0xe9, 0x26, 0x1e, 0x16, 0x91, 0x71,
336-
};
337-
expect_memory(__wrap_cipher_aes_hmac_encrypt, secret, expected_secret, 32);
354+
expect_memory(__wrap_cipher_aes_hmac_encrypt, secret, _expected_secret, 32);
355+
// For the AES IV:
356+
will_return(__wrap_random_32_bytes, _aes_iv);
338357
}
339358

340-
#define PASSWORD ("password")
341-
342359
static void _test_keystore_encrypt_and_store_seed(void** state)
343360
{
344361
_expect_encrypt_and_store_seed();
@@ -532,6 +549,53 @@ static void _test_keystore_encode_xpub(void** state)
532549
"mzoD84tXp15pviBjgS4df");
533550
}
534551

552+
static void _test_keystore_create_and_store_seed(void** state)
553+
{
554+
const uint8_t seed_random[32] =
555+
"\x98\xef\xa1\xb6\x0a\x83\x39\x16\x61\xa2\x4d\xc7\x4a\x80\x4f\x34\x36\xe8\x33\xe0\xaa\xbe"
556+
"\x75\xe9\x71\x1e\x5d\xef\x3a\x8f\x9f\x7c";
557+
const uint8_t host_entropy[32] =
558+
"\x25\x56\x9b\x9a\x11\xf9\xdb\x65\x60\x45\x9e\x8e\x48\xb4\x72\x7a\x4c\x93\x53\x00\x14\x3d"
559+
"\x97\x89\x89\xed\x55\xdb\x1d\x1b\x9c\xbe";
560+
const uint8_t password_salted_hashed[32] =
561+
"\xad\xee\x84\x29\xf5\xb6\x70\xa9\xd7\x34\x17\x1b\x70\x87\xf3\x8f\x86\x6a\x7e\x26\x5f\x9d"
562+
"\x7d\x06\xf0\x0e\x6f\xa4\x17\x54\xac\x77";
563+
// expected_seed = seed_random ^ host_entropy ^ password_salted_hashed
564+
const uint8_t expected_seed[32] =
565+
"\x10\x57\xbe\x05\xee\xcc\x92\xda\xd6\xd3\xc4\x52\x72\xb3\xce\xc1\xfc\x11\x1e\xc6\xe1\x1e"
566+
"\x9f\x66\x08\xfd\x67\x90\x30\xc0\xaf\xb5";
567+
568+
// Invalid seed lengths.
569+
assert_false(keystore_create_and_store_seed(PASSWORD, host_entropy, 8));
570+
assert_false(keystore_create_and_store_seed(PASSWORD, host_entropy, 24));
571+
assert_false(keystore_create_and_store_seed(PASSWORD, host_entropy, 40));
572+
573+
size_t test_sizes[2] = {16, 32};
574+
for (size_t i = 0; i < sizeof(test_sizes) / sizeof(test_sizes[0]); i++) {
575+
size_t seed_len = test_sizes[i];
576+
// Seed random is xored with host entropy and the salted/hashed user password.
577+
will_return(__wrap_random_32_bytes, seed_random);
578+
expect_memory(__wrap_salt_hash_data, data, PASSWORD, strlen(PASSWORD));
579+
expect_value(__wrap_salt_hash_data, data_len, strlen(PASSWORD));
580+
expect_string(__wrap_salt_hash_data, purpose, "keystore_seed_generation");
581+
will_return(__wrap_salt_hash_data, password_salted_hashed);
582+
_expect_encrypt_and_store_seed();
583+
assert_true(keystore_create_and_store_seed(PASSWORD, host_entropy, seed_len));
584+
585+
// Decrypt and check seed.
586+
uint8_t encrypted_seed_and_hmac[96] = {0};
587+
uint8_t len = 0;
588+
assert_true(memory_get_encrypted_seed_and_hmac(encrypted_seed_and_hmac, &len));
589+
size_t decrypted_len = len - 48;
590+
uint8_t out[decrypted_len];
591+
assert_true(cipher_aes_hmac_decrypt(
592+
encrypted_seed_and_hmac, len, out, &decrypted_len, _expected_secret));
593+
assert_true(decrypted_len == seed_len);
594+
595+
assert_memory_equal(expected_seed, out, seed_len);
596+
}
597+
}
598+
535599
int main(void)
536600
{
537601
const struct CMUnitTest tests[] = {
@@ -545,6 +609,7 @@ int main(void)
545609
cmocka_unit_test(_test_keystore_lock),
546610
cmocka_unit_test(_test_keystore_get_bip39_mnemonic),
547611
cmocka_unit_test(_test_keystore_encode_xpub),
612+
cmocka_unit_test(_test_keystore_create_and_store_seed),
548613
};
549614
return cmocka_run_group_tests(tests, NULL, NULL);
550615
}

0 commit comments

Comments
 (0)