Skip to content

Commit 5f431bd

Browse files
committed
hsmtool: change hsm_secret struct to have length awareness
This commit will be rebased for its crimes. This commit is updating hsmtool and exposesecrets to use the new pattern for storing the secret, which is the secret_data and secret_len, to support both 64 byte and 32 byte seeds. However, it also introduces some anti patterns to handle memleak because we provide a NULL context to tal because want the secret_data and to hang around for longer. We also get rid of the accessors we introduced at the start in this commit.
1 parent 0c27db1 commit 5f431bd

8 files changed

Lines changed: 171 additions & 152 deletions

File tree

common/hsm_secret.c

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,9 @@ static struct hsm_secret *extract_plain_secret(const tal_t *ctx,
189189

190190
hsms->type = HSM_SECRET_PLAIN;
191191
hsms->mnemonic = NULL;
192-
193-
/* Allocate and populate secret_data (new field) */
194192
hsms->secret_len = HSM_SECRET_PLAIN_SIZE;
195193
hsms->secret_data = tal_dup_arr(hsms, u8, hsm_secret, HSM_SECRET_PLAIN_SIZE, 0);
196194

197-
/* Also populate legacy secret field for compatibility */
198-
memcpy(&hsms->secret, hsm_secret, sizeof(hsms->secret));
199-
200195
*err = HSM_SECRET_OK;
201196
return hsms;
202197
}
@@ -221,25 +216,27 @@ static struct hsm_secret *extract_encrypted_secret(const tal_t *ctx,
221216
return tal_free(hsms);
222217
}
223218

224-
/* Clear secret data first in case of partial decryption */
225-
memset(&hsms->secret, 0, sizeof(hsms->secret));
219+
/* Prepare for legacy encrypted secret (decrypted to 32 bytes) */
220+
hsms->secret_len = HSM_SECRET_PLAIN_SIZE;
221+
hsms->secret_data = tal_arr(hsms, u8, HSM_SECRET_PLAIN_SIZE);
222+
memset(hsms->secret_data, 0, HSM_SECRET_PLAIN_SIZE);
226223

227224
/* Attempt decryption */
228-
decrypt_success = decrypt_hsm_secret(encryption_key, hsm_secret, &hsms->secret);
225+
struct secret temp_secret;
226+
decrypt_success = decrypt_hsm_secret(encryption_key, hsm_secret, &temp_secret);
229227

230228
/* Clear encryption key immediately after use */
231229
destroy_secret(encryption_key);
232230

233231
if (!decrypt_success) {
234232
/* Clear any partial decryption data */
235-
memset(&hsms->secret, 0, sizeof(hsms->secret));
233+
memset(hsms->secret_data, 0, HSM_SECRET_PLAIN_SIZE);
236234
*err = HSM_SECRET_ERR_WRONG_PASSPHRASE;
237235
return tal_free(hsms);
238236
}
239237

240-
/* Allocate and populate secret_data (new field) */
241-
hsms->secret_len = HSM_SECRET_PLAIN_SIZE;
242-
hsms->secret_data = tal_dup_arr(hsms, u8, hsms->secret.data, HSM_SECRET_PLAIN_SIZE, 0);
238+
/* Copy decrypted secret */
239+
memcpy(hsms->secret_data, temp_secret.data, HSM_SECRET_PLAIN_SIZE);
243240

244241
hsms->type = HSM_SECRET_ENCRYPTED;
245242
hsms->mnemonic = NULL;
@@ -308,13 +305,10 @@ static struct hsm_secret *extract_mnemonic_secret(const tal_t *ctx,
308305
return tal_free(hsms);
309306
}
310307

311-
/* Allocate and populate secret_data with full 64-byte seed */
312-
hsms->secret_len = HSM_SECRET_MNEMONIC_SIZE;
308+
/* Store the full BIP32 seed for mnemonic-based secrets */
309+
hsms->secret_len = HSM_SECRET_MNEMONIC_SIZE; /* Should be 64 bytes */
313310
hsms->secret_data = tal_dup_arr(hsms, u8, bip32_seed, HSM_SECRET_MNEMONIC_SIZE, 0);
314311

315-
/* Also populate legacy secret field with first 32 bytes for compatibility */
316-
memcpy(hsms->secret.data, bip32_seed, sizeof(hsms->secret.data));
317-
318312
*err = HSM_SECRET_OK;
319313
return hsms;
320314
}

common/hsm_secret.h

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,11 @@ enum hsm_secret_error {
4444
struct hsm_secret {
4545
u8 *secret_data; /* Variable length: 32 bytes (legacy) or 64 bytes (mnemonic) */
4646
size_t secret_len; /* Length of secret_data: 32 or 64 bytes */
47-
struct secret secret; /* Legacy 32-byte field for compatibility */
4847
char *mnemonic; /* NULL if not derived from mnemonic */
49-
enum hsm_secret_type type;
48+
enum hsm_secret_type type;
5049
};
5150

52-
/**
53-
* Get the secret bytes from an hsm_secret.
54-
* Returns secret_data if available, otherwise falls back to legacy secret.data.
55-
*/
56-
static inline const u8 *hsm_secret_bytes(const struct hsm_secret *hsm) {
57-
return hsm->secret_data;
58-
}
5951

60-
/**
61-
* Get the secret size from an hsm_secret.
62-
* Returns secret_len if secret_data is available, otherwise 32 bytes for legacy.
63-
*/
64-
static inline size_t hsm_secret_size(const struct hsm_secret *hsm) {
65-
return hsm->secret_len;
66-
}
6752

6853
/**
6954
* Checks whether the hsm_secret data requires a passphrase to decrypt.

hsmd/hsmd.c

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <common/hsm_secret.h>
1919
#include <common/memleak.h>
2020
#include <common/status.h>
21+
#include <hsmd/libhsmd.h>
2122
#include <common/status_wiregen.h>
2223
#include <common/subdaemon.h>
2324
#include <errno.h>
@@ -30,6 +31,7 @@
3031
#include <sys/stat.h>
3132
#include <wally_bip39.h>
3233
#include <wally_bip32.h>
34+
#include <wally_core.h>
3335
#include <wire/wire_io.h>
3436

3537
/*~ Each subdaemon is started with stdin connected to lightningd (for status
@@ -39,7 +41,7 @@
3941
#define REQ_FD 3
4042

4143
/* Temporary storage for the secret until we pass it to `hsmd_init` */
42-
struct hsm_secret hsm_secret;
44+
struct hsm_secret hsm_secret = { .secret_data = NULL, .secret_len = 0, .mnemonic = NULL, .type = HSM_SECRET_INVALID };
4345

4446
/*~ We keep track of clients, but there's not much to keep. */
4547
struct client {
@@ -368,8 +370,12 @@ static void create_hsm(int fd, const char *passphrase)
368370
}
369371
status_debug("HSM: Derived BIP32 seed from mnemonic");
370372

371-
/* Use first 32 bytes for hsm_secret */
372-
memcpy(&hsm_secret.secret, bip32_seed, sizeof(hsm_secret.secret));
373+
/* Store the full BIP32 seed */
374+
hsm_secret.secret_data = tal_dup_arr(tmpctx, u8, bip32_seed, bip32_seed_len, 0);
375+
hsm_secret.secret_len = bip32_seed_len;
376+
377+
/* Set the type based on whether passphrase was used */
378+
hsm_secret.type = passphrase ? HSM_SECRET_MNEMONIC_WITH_PASS : HSM_SECRET_MNEMONIC_NO_PASS;
373379

374380
/* Write the hsm_secret data to file */
375381
if (!write_all(fd, hsm_secret_data, hsm_secret_len)) {
@@ -471,8 +477,19 @@ static void load_hsm(const char *passphrase)
471477
"Failed to load hsm_secret: %s", hsm_secret_error_str(err));
472478
}
473479

474-
/* Copy the extracted secret to our global hsm_secret */
475-
memcpy(&hsm_secret, &hsms->secret, sizeof(hsm_secret));
480+
/* Deep copy the extracted secret to our global hsm_secret */
481+
hsm_secret = *hsms; /* Copy the basic fields */
482+
483+
/* Deep copy the secret data if it exists */
484+
if (hsms->secret_data) {
485+
hsm_secret.secret_data = tal_dup_arr(NULL, u8, hsms->secret_data, hsms->secret_len, 0);
486+
hsm_secret.secret_len = hsms->secret_len;
487+
}
488+
489+
/* Deep copy the mnemonic if it exists */
490+
if (hsms->mnemonic) {
491+
hsm_secret.mnemonic = tal_strdup(NULL, hsms->mnemonic);
492+
}
476493
}
477494

478495
/*~ We have a pre-init call in developer mode, to set dev flags */
@@ -551,7 +568,9 @@ static struct io_plan *init_hsm(struct io_conn *conn,
551568
hsm_passphrase = (const char *)tlvs->hsm_passphrase;
552569

553570
/*~ Don't swap this. */
554-
sodium_mlock(hsm_secret.secret.data, sizeof(hsm_secret.secret.data));
571+
if (hsm_secret.secret_data && hsm_secret.secret_len > 0) {
572+
sodium_mlock(hsm_secret.secret_data, hsm_secret.secret_len);
573+
}
555574

556575
if (!developer) {
557576
assert(!dev_force_privkey);
@@ -571,9 +590,7 @@ static struct io_plan *init_hsm(struct io_conn *conn,
571590

572591
/* This was tallocated off NULL, and memleak complains if we don't free it */
573592
tal_free(tlvs);
574-
return req_reply(conn, c, hsmd_init(hsm_secret_bytes(&hsm_secret),
575-
hsm_secret_size(&hsm_secret),
576-
hsmd_mutual_version,
593+
return req_reply(conn, c, hsmd_init(hsm_secret.secret_data, hsm_secret.secret_len, hsmd_mutual_version,
577594
bip32_key_version));
578595
}
579596

@@ -657,6 +674,11 @@ static struct io_plan *handle_memleak(struct io_conn *conn,
657674

658675
memleak_ptr(memtable, dev_force_privkey);
659676
memleak_ptr(memtable, dev_force_bip32_seed);
677+
678+
/* Question for Rusty/ Reviewer: Is this a suss pattern? */
679+
memleak_ptr(memtable, hsm_secret.secret_data);
680+
memleak_ptr(memtable, hsm_secret.mnemonic);
681+
memleak_ptr(memtable, get_secretstuff_bip32_seed());
660682

661683
found_leak = dump_memleak(memtable, memleak_status_broken, NULL);
662684
reply = towire_hsmd_dev_memleak_reply(NULL, found_leak);
@@ -715,7 +737,8 @@ static struct io_plan *handle_derive_bip86_key(struct io_conn *conn,
715737
return bad_req(conn, c, msg_in);
716738

717739
/* Check if we have a mnemonic-based HSM secret */
718-
if (hsm_secret_size(&hsm_secret) != 64) {
740+
if (hsm_secret.type != HSM_SECRET_MNEMONIC_NO_PASS &&
741+
hsm_secret.type != HSM_SECRET_MNEMONIC_WITH_PASS) {
719742
return bad_req_fmt(conn, c, msg_in,
720743
"BIP86 derivation requires mnemonic-based HSM secret");
721744
}
@@ -743,7 +766,8 @@ static struct io_plan *handle_check_bip86_pubkey(struct io_conn *conn,
743766
return bad_req(conn, c, msg_in);
744767

745768
/* Check if we have a mnemonic-based HSM secret */
746-
if (hsm_secret_size(&hsm_secret) != 64) {
769+
if (hsm_secret.type != HSM_SECRET_MNEMONIC_NO_PASS &&
770+
hsm_secret.type != HSM_SECRET_MNEMONIC_WITH_PASS) {
747771
return bad_req_fmt(conn, c, msg_in,
748772
"BIP86 derivation requires mnemonic-based HSM secret");
749773
}
@@ -793,6 +817,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
793817
if (developer)
794818
return handle_memleak(conn, c, c->msg_in);
795819
/* fall thru */
820+
796821
case WIRE_HSMD_DERIVE_BIP86_KEY:
797822
return handle_derive_bip86_key(conn, c, c->msg_in);
798823
case WIRE_HSMD_CHECK_BIP86_PUBKEY:
@@ -882,8 +907,8 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
882907
case WIRE_HSMD_PREAPPROVE_KEYSEND_REPLY:
883908
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK_REPLY:
884909
case WIRE_HSMD_PREAPPROVE_KEYSEND_CHECK_REPLY:
885-
case WIRE_HSMD_CHECK_PUBKEY_REPLY:
886910
case WIRE_HSMD_DERIVE_BIP86_KEY_REPLY:
911+
case WIRE_HSMD_CHECK_PUBKEY_REPLY:
887912
case WIRE_HSMD_CHECK_BIP86_PUBKEY_REPLY:
888913
case WIRE_HSMD_SIGN_ANCHORSPEND_REPLY:
889914
case WIRE_HSMD_SIGN_HTLC_TX_MINGLE_REPLY:

0 commit comments

Comments
 (0)