Skip to content

Commit 52912af

Browse files
author
Jamie C. Driver
committed
keychain: hold service path as array of uint32_t rather than uint8_t
1 parent 0b451e9 commit 52912af

File tree

6 files changed

+86
-28
lines changed

6 files changed

+86
-28
lines changed

main/keychain.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ void keychain_derive_from_seed(const uint8_t* seed, const size_t seed_len, keych
283283
wally_asset_blinding_key_from_seed(seed, seed_len, keydata->master_unblinding_key, HMAC_SHA512_LEN));
284284

285285
// Compute and cache the path the GA server will use to sign
286-
wallet_calculate_gaservice_path(&keydata->xpriv, keydata->service_path, sizeof(keydata->service_path));
286+
wallet_calculate_gaservice_path(&keydata->xpriv, keydata->gaservice_path, GASERVICE_PATH_LEN);
287287
}
288288

289289
// Derive master key from mnemonic if passed a valid mnemonic
@@ -361,7 +361,9 @@ static void serialize(uint8_t* serialized, const size_t serialized_len, const ke
361361

362362
// ext-key, ga-path, master-blinding-key
363363
JADE_WALLY_VERIFY(bip32_key_serialize(&keydata->xpriv, BIP32_FLAG_KEY_PRIVATE, serialized, BIP32_SERIALIZED_LEN));
364-
memcpy(serialized + BIP32_SERIALIZED_LEN, keydata->service_path, HMAC_SHA512_LEN);
364+
const bool ret = wallet_serialize_gaservice_path(
365+
serialized + BIP32_SERIALIZED_LEN, HMAC_SHA512_LEN, keydata->gaservice_path, GASERVICE_PATH_LEN);
366+
JADE_ASSERT(ret);
365367
memcpy(serialized + BIP32_SERIALIZED_LEN + HMAC_SHA512_LEN, keydata->master_unblinding_key, HMAC_SHA512_LEN);
366368
}
367369

@@ -373,7 +375,9 @@ static void unserialize(const uint8_t* decrypted, const size_t decrypted_len, ke
373375

374376
// ext-key, ga-path, master-blinding-key
375377
JADE_WALLY_VERIFY(bip32_key_unserialize(decrypted, BIP32_SERIALIZED_LEN, &keydata->xpriv));
376-
memcpy(keydata->service_path, decrypted + BIP32_SERIALIZED_LEN, HMAC_SHA512_LEN);
378+
const bool ret = wallet_unserialize_gaservice_path(
379+
decrypted + BIP32_SERIALIZED_LEN, HMAC_SHA512_LEN, keydata->gaservice_path, GASERVICE_PATH_LEN);
380+
JADE_ASSERT(ret);
377381
memcpy(keydata->master_unblinding_key, decrypted + BIP32_SERIALIZED_LEN + HMAC_SHA512_LEN, HMAC_SHA512_LEN);
378382
}
379383

main/keychain.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
#include <wally_crypto.h>
99

1010
#define PASSPHRASE_MAX_LEN 100
11+
#define GASERVICE_PATH_LEN (HMAC_SHA512_LEN / 2)
1112

1213
typedef struct {
13-
struct ext_key xpriv;
14-
uint8_t service_path[HMAC_SHA512_LEN];
14+
uint32_t gaservice_path[GASERVICE_PATH_LEN];
1515
uint8_t master_unblinding_key[HMAC_SHA512_LEN];
1616
uint8_t seed[BIP32_ENTROPY_LEN_512];
17+
struct ext_key xpriv;
1718
size_t seed_len;
1819
} keychain_t;
1920

main/process/debug_handshake.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ void debug_handshake(void* process_ptr)
136136
JADE_ASSERT(res == 0);
137137
res = sodium_memcmp(&keydata.xpriv, &keychain_get()->xpriv, sizeof(keydata.xpriv));
138138
JADE_ASSERT(res == 0);
139-
res = crypto_verify_64(keydata.service_path, keychain_get()->service_path);
139+
res = sodium_memcmp(keydata.gaservice_path, keychain_get()->gaservice_path, sizeof(keydata.gaservice_path));
140140
JADE_ASSERT(res == 0);
141141
res = crypto_verify_64(keydata.master_unblinding_key, keychain_get()->master_unblinding_key);
142142
JADE_ASSERT(res == 0);

main/selfcheck.c

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#ifndef AMALGAMATED_BUILD
22
#include <sdkconfig.h>
33
#include <string.h>
4-
#include <wally_bip32.h>
54

65
#include "bcur.h"
76
#include "jade_assert.h"
@@ -12,15 +11,18 @@
1211
#include "random.h"
1312
#include "rsa.h"
1413
#include "storage.h"
15-
#include <sodium/crypto_verify_64.h>
16-
#include <sodium/utils.h>
17-
#include <utils/malloc_ext.h>
18-
#include <utils/util.h>
19-
14+
#include "utils/malloc_ext.h"
2015
#include "utils/shake256.h"
16+
#include "utils/util.h"
17+
#include "wallet.h"
18+
2119
#include <mbedtls/pem.h>
2220
#include <mbedtls/pk.h>
2321
#include <mbedtls/rsa.h>
22+
#include <sodium/crypto_verify_64.h>
23+
#include <sodium/utils.h>
24+
25+
#include <wally_bip32.h>
2426
#include <wally_bip85.h>
2527

2628
#include <cdecoder.h>
@@ -65,7 +67,7 @@ static bool all_fields_same(const keychain_t* keydata1, const keychain_t* keydat
6567
if (sodium_memcmp(&keydata1->xpriv, &keydata2->xpriv, sizeof(keydata1->xpriv))) {
6668
return false;
6769
}
68-
if (crypto_verify_64(keydata1->service_path, keydata2->service_path)) {
70+
if (sodium_memcmp(keydata1->gaservice_path, keydata2->gaservice_path, sizeof(keydata1->gaservice_path))) {
6971
return false;
7072
}
7173
if (crypto_verify_64(keydata1->master_unblinding_key, keydata2->master_unblinding_key)) {
@@ -97,7 +99,7 @@ static bool any_fields_same(const keychain_t* keydata1, const keychain_t* keydat
9799
if (!sodium_memcmp(&keydata1->xpriv, &keydata2->xpriv, sizeof(keydata1->xpriv))) {
98100
return true;
99101
}
100-
if (!crypto_verify_64(keydata1->service_path, keydata2->service_path)) {
102+
if (!sodium_memcmp(keydata1->gaservice_path, keydata2->gaservice_path, sizeof(keydata1->gaservice_path))) {
101103
return true;
102104
}
103105
if (!crypto_verify_64(keydata1->master_unblinding_key, keydata2->master_unblinding_key)) {
@@ -119,9 +121,9 @@ static bool any_fields_same(const keychain_t* keydata1, const keychain_t* keydat
119121
static bool test_simple_restore(void)
120122
{
121123
size_t written = 0;
122-
uint8_t expected_service_path[HMAC_SHA512_LEN];
124+
uint8_t expected_gaservice_path[HMAC_SHA512_LEN];
123125
const int ret
124-
= wally_hex_to_bytes(SERVICE_PATH_HEX, expected_service_path, sizeof(expected_service_path), &written);
126+
= wally_hex_to_bytes(SERVICE_PATH_HEX, expected_gaservice_path, sizeof(expected_gaservice_path), &written);
125127
if (ret != WALLY_OK || written != HMAC_SHA512_LEN) {
126128
FAIL();
127129
}
@@ -130,9 +132,24 @@ static bool test_simple_restore(void)
130132
if (!keychain_derive_from_mnemonic(TEST_MNEMONIC, NULL, &keydata)) {
131133
FAIL();
132134
}
133-
if (crypto_verify_64(keydata.service_path, expected_service_path) != 0) {
135+
136+
uint8_t serialized[HMAC_SHA512_LEN];
137+
if (!wallet_serialize_gaservice_path(serialized, sizeof(serialized), keydata.gaservice_path, GASERVICE_PATH_LEN)) {
138+
FAIL();
139+
}
140+
if (crypto_verify_64(serialized, expected_gaservice_path) != 0) {
134141
FAIL();
135142
}
143+
144+
uint32_t deserialised_expected_path[GASERVICE_PATH_LEN];
145+
if (!wallet_unserialize_gaservice_path(
146+
expected_gaservice_path, sizeof(expected_gaservice_path), deserialised_expected_path, GASERVICE_PATH_LEN)) {
147+
FAIL();
148+
}
149+
if (sodium_memcmp(keydata.gaservice_path, deserialised_expected_path, sizeof(keydata.gaservice_path))) {
150+
FAIL();
151+
}
152+
136153
return true;
137154
}
138155

main/wallet.c

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -500,11 +500,42 @@ void wallet_build_receive_path(const uint32_t subaccount, const uint32_t branch,
500500
}
501501
}
502502

503+
bool wallet_serialize_gaservice_path(
504+
uint8_t* serialized, const size_t serialized_len, const uint32_t* gaservice_path, const size_t gaservice_path_len)
505+
{
506+
if (!serialized || serialized_len != HMAC_SHA512_LEN || !gaservice_path
507+
|| gaservice_path_len != GASERVICE_PATH_LEN) {
508+
return false;
509+
}
510+
511+
for (size_t i = 0; i < gaservice_path_len; ++i) {
512+
JADE_ASSERT(!(gaservice_path[i] & 0xFFFF0000));
513+
serialized[2 * i] = gaservice_path[i] >> 8;
514+
serialized[2 * i + 1] = gaservice_path[i] & 0xFF;
515+
}
516+
return true;
517+
}
518+
519+
bool wallet_unserialize_gaservice_path(
520+
const uint8_t* serialized, const size_t serialized_len, uint32_t* gaservice_path, const size_t gaservice_path_len)
521+
{
522+
if (!serialized || serialized_len != HMAC_SHA512_LEN || !gaservice_path
523+
|| gaservice_path_len != GASERVICE_PATH_LEN) {
524+
return false;
525+
}
526+
527+
for (size_t i = 0; i < gaservice_path_len; ++i) {
528+
gaservice_path[i] = (serialized[2 * i] << 8) + serialized[2 * i + 1];
529+
}
530+
return true;
531+
}
532+
503533
// Helper to create the service/gait path.
504534
// (The below is correct for newly created wallets, verified in regtest).
505-
bool wallet_calculate_gaservice_path(struct ext_key* root_key, uint8_t* service_path, const size_t service_path_len)
535+
bool wallet_calculate_gaservice_path(
536+
struct ext_key* root_key, uint32_t* gaservice_path, const size_t gaservice_path_len)
506537
{
507-
if (!root_key || !service_path || service_path_len != HMAC_SHA512_LEN) {
538+
if (!root_key || !gaservice_path || gaservice_path_len != (HMAC_SHA512_LEN / 2)) {
508539
return false;
509540
}
510541

@@ -520,13 +551,15 @@ bool wallet_calculate_gaservice_path(struct ext_key* root_key, uint8_t* service_
520551
memcpy(extkeydata, derived.chain_code, sizeof(derived.chain_code));
521552
memcpy(extkeydata + sizeof(derived.chain_code), derived.pub_key, sizeof(derived.pub_key));
522553

523-
// 3. HMAC the fixed GA key message with 2. to yield the 512-bit 'service path' for this mnemonic/private key
554+
// 3. HMAC the fixed GA key message with 2. to yield the 64 'service path' bytes for this mnemonic/private key
555+
uint8_t serialized[HMAC_SHA512_LEN];
524556
JADE_WALLY_VERIFY(wally_hmac_sha512(
525-
GA_KEY_MSG, sizeof(GA_KEY_MSG), extkeydata, sizeof(extkeydata), service_path, service_path_len));
557+
GA_KEY_MSG, sizeof(GA_KEY_MSG), extkeydata, sizeof(extkeydata), serialized, sizeof(serialized)));
526558
SENSITIVE_POP(extkeydata);
527559
SENSITIVE_POP(&derived);
528560

529-
return true;
561+
// 4. Deserialize to 32 '16 bit' (ie. unhardened) path elements
562+
return wallet_unserialize_gaservice_path(serialized, sizeof(serialized), gaservice_path, gaservice_path_len);
530563
}
531564

532565
bool wallet_get_gaservice_fingerprint(const char* network, uint8_t* output, size_t output_len)
@@ -554,7 +587,8 @@ bool wallet_get_gaservice_path(
554587
return false;
555588
}
556589

557-
JADE_ASSERT(keychain_get());
590+
const keychain_t* const keychain = keychain_get();
591+
JADE_ASSERT(keychain);
558592

559593
// We only support the following cases
560594
if (path_len == 2) {
@@ -587,10 +621,8 @@ bool wallet_get_gaservice_path(
587621
}
588622

589623
// GA service path goes in elements 1 - 32 incl.
590-
const keychain_t* const keychain = keychain_get();
591-
for (size_t i = 0; i < 32; ++i) {
592-
ga_path[i + 1] = (keychain->service_path[2 * i] << 8) + keychain->service_path[2 * i + 1];
593-
}
624+
JADE_STATIC_ASSERT(sizeof(keychain->gaservice_path) == (ga_path_len - 1) * sizeof(ga_path[0]));
625+
memcpy(&ga_path[1], keychain->gaservice_path, sizeof(keychain->gaservice_path));
594626

595627
return true;
596628
}

main/wallet.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,11 @@ void wallet_get_fingerprint(uint8_t* output, size_t output_len);
8989
bool wallet_get_hdkey(const uint32_t* path, size_t path_len, uint32_t flags, struct ext_key* output);
9090
bool wallet_get_xpub(const char* network, const uint32_t* path, size_t path_len, char** output);
9191

92-
bool wallet_calculate_gaservice_path(struct ext_key* root_key, uint8_t* service_path, size_t service_path_len);
92+
bool wallet_calculate_gaservice_path(struct ext_key* root_key, uint32_t* gaservice_path, size_t gaservice_path_len);
93+
bool wallet_serialize_gaservice_path(
94+
uint8_t* serialized, size_t serialized_len, const uint32_t* gaservice_path, size_t gaservice_path_len);
95+
bool wallet_unserialize_gaservice_path(
96+
const uint8_t* serialized, size_t serialized_len, uint32_t* gaservice_path, size_t gaservice_path_len);
9397
bool wallet_get_gaservice_fingerprint(const char* network, uint8_t* output, size_t output_len);
9498
bool wallet_get_gaservice_path(
9599
const uint32_t* path, size_t path_len, uint32_t* ga_path, size_t ga_path_len, size_t* written);

0 commit comments

Comments
 (0)