hsmd: take the passphrase raw, not the derived secret.
In preparation for BIP-39, we need to hand the passphrase (if any) to HSMD. So we extend the hsmd wire protocol to allow that.
This commit is contained in:
committed by
Rusty Russell
parent
3da0f16f14
commit
e3fe739f64
22
hsmd/hsmd.c
22
hsmd/hsmd.c
@@ -461,6 +461,7 @@ static struct io_plan *init_hsm(struct io_conn *conn,
|
||||
struct bip32_key_version bip32_key_version;
|
||||
u32 minversion, maxversion;
|
||||
const u32 our_minversion = 4, our_maxversion = 6;
|
||||
struct tlv_hsmd_init_tlvs *tlvs;
|
||||
|
||||
/* This must be lightningd. */
|
||||
assert(is_lightningd(c));
|
||||
@@ -475,7 +476,7 @@ static struct io_plan *init_hsm(struct io_conn *conn,
|
||||
&dev_force_bip32_seed,
|
||||
&dev_force_channel_secrets,
|
||||
&dev_force_channel_secrets_shaseed,
|
||||
&minversion, &maxversion))
|
||||
&minversion, &maxversion, &tlvs))
|
||||
return bad_req(conn, c, msg_in);
|
||||
|
||||
/*~ Usually we don't worry about API breakage between internal daemons,
|
||||
@@ -487,6 +488,25 @@ static struct io_plan *init_hsm(struct io_conn *conn,
|
||||
minversion, maxversion,
|
||||
our_minversion, our_maxversion);
|
||||
|
||||
/*~ We used to have lightningd hand us the encryption key derived from
|
||||
* the passphrase which was used to encrypt the `hsm_secret` file. Then
|
||||
* Rusty gave me the thankless task of introducing BIP-39 mnemonics. I
|
||||
* think this is some kind of obscure CLN hazing ritual? Anyway, the
|
||||
* passphrase needs to be *appended* to the mnemonic, so the HSM needs
|
||||
* the raw passphrase. To avoid a compatibility break, I put it inside
|
||||
* the TLV, and left the old "hsm_encryption_key" field in place, even
|
||||
* though we override it here for the old-style non-BIP39 hsm_secret. */
|
||||
if (tlvs->hsm_passphrase) {
|
||||
const char *hsm_passphrase = (const char *)tlvs->hsm_passphrase;
|
||||
const char *err_msg;
|
||||
|
||||
hsm_encryption_key = tal(NULL, struct secret);
|
||||
if (hsm_secret_encryption_key_with_exitcode(hsm_passphrase, hsm_encryption_key, &err_msg) != 0)
|
||||
return bad_req_fmt(conn, c, msg_in,
|
||||
"Bad passphrase: %s", err_msg);
|
||||
}
|
||||
tal_free(tlvs);
|
||||
|
||||
/*~ The memory is actually copied in towire(), so lock the `hsm_secret`
|
||||
* encryption key (new) memory again here. */
|
||||
if (hsm_encryption_key && sodium_mlock(hsm_encryption_key,
|
||||
|
||||
@@ -29,6 +29,9 @@ msgdata,hsmd_init,dev_force_channel_secrets,?secrets,
|
||||
msgdata,hsmd_init,dev_force_channel_secrets_shaseed,?sha256,
|
||||
msgdata,hsmd_init,hsm_wire_min_version,u32,
|
||||
msgdata,hsmd_init,hsm_wire_max_version,u32,
|
||||
msgdata,hsmd_init,tlvs,hsmd_init_tlvs,
|
||||
tlvtype,hsmd_init_tlvs,hsm_passphrase,1
|
||||
tlvdata,hsmd_init_tlvs,hsm_passphrase,passphrase,wirestring,
|
||||
|
||||
#include <common/bip32.h>
|
||||
# Sorry: I should have put version in v2 :(
|
||||
|
||||
|
@@ -98,7 +98,7 @@ struct ext_key *hsm_init(struct lightningd *ld)
|
||||
/* If hsm_secret is encrypted and the --encrypted-hsm startup option is
|
||||
* not passed, don't let hsmd use the first 32 bytes of the cypher as the
|
||||
* actual secret. */
|
||||
if (!ld->config.keypass) {
|
||||
if (!ld->hsm_passphrase) {
|
||||
if (is_hsm_secret_encrypted("hsm_secret") == 1)
|
||||
errx(EXITCODE_HSM_ERROR_IS_ENCRYPT, "hsm_secret is encrypted, you need to pass the "
|
||||
"--encrypted-hsm startup option.");
|
||||
@@ -122,16 +122,24 @@ struct ext_key *hsm_init(struct lightningd *ld)
|
||||
err(EXITCODE_HSM_GENERIC_ERROR, "Writing preinit msg to hsm");
|
||||
}
|
||||
|
||||
/* Create TLV for passphrase if needed */
|
||||
struct tlv_hsmd_init_tlvs *tlv = NULL;
|
||||
if (ld->hsm_passphrase) {
|
||||
tlv = tlv_hsmd_init_tlvs_new(tmpctx);
|
||||
tlv->hsm_passphrase = ld->hsm_passphrase;
|
||||
}
|
||||
|
||||
if (!wire_sync_write(ld->hsm_fd, towire_hsmd_init(tmpctx,
|
||||
&chainparams->bip32_key_version,
|
||||
chainparams,
|
||||
ld->config.keypass,
|
||||
NULL,
|
||||
ld->dev_force_privkey,
|
||||
ld->dev_force_bip32_seed,
|
||||
ld->dev_force_channel_secrets,
|
||||
ld->dev_force_channel_secrets_shaseed,
|
||||
HSM_MIN_VERSION,
|
||||
HSM_MAX_VERSION)))
|
||||
HSM_MAX_VERSION,
|
||||
tlv)))
|
||||
err(EXITCODE_HSM_GENERIC_ERROR, "Writing init msg to hsm");
|
||||
|
||||
bip32_base = tal(ld, struct ext_key);
|
||||
@@ -143,7 +151,7 @@ struct ext_key *hsm_init(struct lightningd *ld)
|
||||
&unused)) {
|
||||
/* nothing to do. */
|
||||
} else {
|
||||
if (ld->config.keypass)
|
||||
if (ld->hsm_passphrase)
|
||||
errx(EXITCODE_HSM_BAD_PASSWORD, "Wrong password for encrypted hsm_secret.");
|
||||
errx(EXITCODE_HSM_GENERIC_ERROR, "HSM did not give init reply");
|
||||
}
|
||||
|
||||
@@ -309,10 +309,10 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
|
||||
/*~ This is set when a JSON RPC command comes in to shut us down. */
|
||||
ld->stop_conn = NULL;
|
||||
|
||||
/*~ This is used to signal that `hsm_secret` is encrypted, and will
|
||||
* be set to `true` if the `--encrypted-hsm` option is passed at startup.
|
||||
/*~ This is used to store the passphrase for hsm_secret if needed.
|
||||
* It will be set if the `--hsm-passphrase` option is passed at startup.
|
||||
*/
|
||||
ld->encrypted_hsm = false;
|
||||
ld->hsm_passphrase = NULL;
|
||||
|
||||
/* This is used to override subdaemons */
|
||||
strmap_init(&ld->alt_subdaemons);
|
||||
@@ -1305,11 +1305,6 @@ int main(int argc, char *argv[])
|
||||
/*~ This is the ccan/io central poll override from above. */
|
||||
io_poll_override(io_poll_lightningd);
|
||||
|
||||
/*~ If hsm_secret is encrypted, we don't need its encryption key
|
||||
* anymore. Note that sodium_munlock() also zeroes the memory.*/
|
||||
if (ld->config.keypass)
|
||||
discard_key(take(ld->config.keypass));
|
||||
|
||||
/*~ Our default color and alias are derived from our node id, so we
|
||||
* can only set those now (if not set by config options). */
|
||||
setup_color_and_alias(ld);
|
||||
|
||||
@@ -69,8 +69,6 @@ struct config {
|
||||
/* Minimal amount of effective funding_satoshis for accepting channels */
|
||||
u64 min_capacity_sat;
|
||||
|
||||
/* This is the key we use to encrypt `hsm_secret`. */
|
||||
struct secret *keypass;
|
||||
|
||||
/* How long before we give up waiting for INIT msg */
|
||||
u32 connection_timeout_secs;
|
||||
@@ -387,7 +385,9 @@ struct lightningd {
|
||||
char *old_bookkeeper_dir;
|
||||
char *old_bookkeeper_db;
|
||||
|
||||
bool encrypted_hsm;
|
||||
/* HSM passphrase for any format that needs it */
|
||||
char *hsm_passphrase;
|
||||
|
||||
/* What (additional) messages the HSM accepts */
|
||||
u32 *hsm_capabilities;
|
||||
|
||||
|
||||
@@ -597,13 +597,7 @@ static char *opt_set_hsm_password(struct lightningd *ld)
|
||||
}
|
||||
prompt(ld, "");
|
||||
|
||||
ld->config.keypass = tal(NULL, struct secret);
|
||||
|
||||
opt_exitcode = hsm_secret_encryption_key_with_exitcode(passwd, ld->config.keypass, &err_msg);
|
||||
if (opt_exitcode > 0)
|
||||
return cast_const(char *, err_msg);
|
||||
|
||||
ld->encrypted_hsm = true;
|
||||
ld->hsm_passphrase = tal_strdup(ld, passwd);
|
||||
free(passwd);
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -641,6 +641,9 @@ void tell_connectd_peer_importance(struct peer *peer UNNEEDED,
|
||||
/* Generated stub for tlv_hsmd_dev_preinit_tlvs_new */
|
||||
struct tlv_hsmd_dev_preinit_tlvs *tlv_hsmd_dev_preinit_tlvs_new(const tal_t *ctx UNNEEDED)
|
||||
{ fprintf(stderr, "tlv_hsmd_dev_preinit_tlvs_new called!\n"); abort(); }
|
||||
/* Generated stub for tlv_hsmd_init_tlvs_new */
|
||||
struct tlv_hsmd_init_tlvs *tlv_hsmd_init_tlvs_new(const tal_t *ctx UNNEEDED)
|
||||
{ fprintf(stderr, "tlv_hsmd_init_tlvs_new called!\n"); abort(); }
|
||||
/* Generated stub for topology_add_sync_waiter_ */
|
||||
void topology_add_sync_waiter_(const tal_t *ctx UNNEEDED,
|
||||
struct chain_topology *topo UNNEEDED,
|
||||
@@ -712,7 +715,7 @@ u8 *towire_hsmd_forget_channel(const tal_t *ctx UNNEEDED, const struct node_id *
|
||||
u8 *towire_hsmd_get_output_scriptpubkey(const tal_t *ctx UNNEEDED, u64 channel_id UNNEEDED, const struct node_id *peer_id UNNEEDED, const struct pubkey *commitment_point UNNEEDED)
|
||||
{ fprintf(stderr, "towire_hsmd_get_output_scriptpubkey called!\n"); abort(); }
|
||||
/* Generated stub for towire_hsmd_init */
|
||||
u8 *towire_hsmd_init(const tal_t *ctx UNNEEDED, const struct bip32_key_version *bip32_key_version UNNEEDED, const struct chainparams *chainparams UNNEEDED, const struct secret *hsm_encryption_key UNNEEDED, const struct privkey *dev_force_privkey UNNEEDED, const struct secret *dev_force_bip32_seed UNNEEDED, const struct secrets *dev_force_channel_secrets UNNEEDED, const struct sha256 *dev_force_channel_secrets_shaseed UNNEEDED, u32 hsm_wire_min_version UNNEEDED, u32 hsm_wire_max_version UNNEEDED)
|
||||
u8 *towire_hsmd_init(const tal_t *ctx UNNEEDED, const struct bip32_key_version *bip32_key_version UNNEEDED, const struct chainparams *chainparams UNNEEDED, const struct secret *hsm_encryption_key UNNEEDED, const struct privkey *dev_force_privkey UNNEEDED, const struct secret *dev_force_bip32_seed UNNEEDED, const struct secrets *dev_force_channel_secrets UNNEEDED, const struct sha256 *dev_force_channel_secrets_shaseed UNNEEDED, u32 hsm_wire_min_version UNNEEDED, u32 hsm_wire_max_version UNNEEDED, const struct tlv_hsmd_init_tlvs *tlvs UNNEEDED)
|
||||
{ fprintf(stderr, "towire_hsmd_init called!\n"); abort(); }
|
||||
/* Generated stub for towire_hsmd_new_channel */
|
||||
u8 *towire_hsmd_new_channel(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 dbid UNNEEDED)
|
||||
|
||||
Reference in New Issue
Block a user