hsmd/libhsmd: change hsmd_init to have secret_data and secret_len

hsmd: plumb length-aware secret into hsmd_init; keep 32B mirror

BIP86 (from BIP39) wants the full 64-byte BIP32 seed. This commit plumbs a variable-length (32/64B) secret into hsmd and uses the accessors from the previous commit. We keep the old 32B hsm_secret mirror and, for now, only use the first 32 bytes so legacy paths keep working.

Spoiler: HKDFs will keep using the 32B seed; only wallet address derivation
will switch to the full 64B in a follow-up.
This commit is contained in:
Sangbida Chaudhuri
2025-10-24 13:57:45 +10:30
committed by Rusty Russell
parent 0192b82e94
commit fc981f4d30
3 changed files with 21 additions and 9 deletions

View File

@@ -551,7 +551,9 @@ static struct io_plan *init_hsm(struct io_conn *conn,
/* This was tallocated off NULL, and memleak complains if we don't free it */
tal_free(tlvs);
return req_reply(conn, c, hsmd_init(hsm_secret.secret, hsmd_mutual_version,
return req_reply(conn, c, hsmd_init(hsm_secret_bytes(&hsm_secret),
hsm_secret_size(&hsm_secret),
hsmd_mutual_version,
bip32_key_version));
}

View File

@@ -8,6 +8,7 @@
#include <common/hash_u5.h>
#include <common/key_derive.h>
#include <common/lease_rates.h>
#include <common/memleak.h>
#include <common/utils.h>
#include <hsmd/libhsmd.h>
#include <hsmd/permissions.h>
@@ -25,11 +26,17 @@ struct privkey *dev_force_privkey;
/* If they specify --dev-force-bip32-seed it ends up in here. */
struct secret *dev_force_bip32_seed;
/*~ Nobody will ever find it here! hsm_secret is our root secret, the bip32
/*~ Nobody will ever find it here! bip32_seed is our root secret, the bip32
* tree, bolt12 payer_id keys and derived_secret are derived from that, and
* cached here. */
struct {
/* keep for legacy callers that read 32B directly today */
struct secret hsm_secret;
/* new: full root bytes we received (32 or 64) */
u8 *bip32_seed;
size_t bip32_seed_len;
struct ext_key bip32;
struct secret bolt12;
struct secret derived_secret;
@@ -2334,7 +2341,7 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client,
return hsmd_status_bad_request(client, msg, "Unknown request");
}
u8 *hsmd_init(struct secret hsm_secret, const u64 hsmd_version,
u8 *hsmd_init(const u8 *secret_data, size_t secret_len, const u64 hsmd_version,
struct bip32_key_version bip32_key_version)
{
u8 bip32_seed[BIP32_ENTROPY_LEN_256];
@@ -2356,10 +2363,13 @@ u8 *hsmd_init(struct secret hsm_secret, const u64 hsmd_version,
};
u32 *caps;
/*~ Don't swap this. */
sodium_mlock(secretstuff.hsm_secret.data,
sizeof(secretstuff.hsm_secret.data));
memcpy(secretstuff.hsm_secret.data, hsm_secret.data, sizeof(hsm_secret.data));
/* new: keep the full 32/64B root */
secretstuff.bip32_seed_len = secret_len;
secretstuff.bip32_seed = notleak(tal_dup_arr(NULL, u8, secret_data, secret_len, 0));
sodium_mlock(secretstuff.bip32_seed, secret_len);
/* legacy mirror: first 32 bytes for existing code paths */
memcpy(secretstuff.hsm_secret.data, secret_data, 32);
assert(bip32_key_version.bip32_pubkey_version == BIP32_VER_MAIN_PUBLIC
|| bip32_key_version.bip32_pubkey_version == BIP32_VER_TEST_PUBLIC);

View File

@@ -38,7 +38,7 @@ struct hsmd_client {
/* Given the (unencrypted) base secret, intialize all derived secrets.
*
* While we ensure that the memory the internal secrets are stored in
* is secure (mlock), the caller must make sure that the `hsm_secret`
* is secure (mlock), the caller must make sure that the `secret_data`
* argument is handled securely before this call to avoid potential
* issues. The function copies the secret, so the caller can free the
* secret after the call.
@@ -46,7 +46,7 @@ struct hsmd_client {
* Returns the `hsmd_init_reply` with the information required by
* `lightningd`.
*/
u8 *hsmd_init(struct secret hsm_secret, const u64 hsmd_version,
u8 *hsmd_init(const u8 *secret_data, size_t secret_len, const u64 hsmd_version,
struct bip32_key_version bip32_key_version);
struct hsmd_client *hsmd_client_new_main(const tal_t *ctx, u64 capabilities,