From 07adb7efd6120d7ff53b4e5b5d3df2a4a05f1be4 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 17 Jul 2019 07:10:14 +0930 Subject: [PATCH] developer: add --dev-force-privkey to allow setting a specific node key. Signed-off-by: Rusty Russell --- hsmd/hsm_wire.csv | 1 + hsmd/hsmd.c | 24 +++++++++++++++++++++++- lightningd/hsm_control.c | 8 +++++++- lightningd/lightningd.c | 1 + lightningd/lightningd.h | 3 +++ lightningd/options.c | 13 +++++++++++++ 6 files changed, 48 insertions(+), 2 deletions(-) diff --git a/hsmd/hsm_wire.csv b/hsmd/hsm_wire.csv index f1bcdf5799d2..f43eed8b2f19 100644 --- a/hsmd/hsm_wire.csv +++ b/hsmd/hsm_wire.csv @@ -9,6 +9,7 @@ hsmstatus_client_bad_request,,msg,len*u8 # Start the HSM. hsm_init,11 hsm_init,,bip32_key_version,struct bip32_key_version +hsm_init,,dev_force_privkey,?struct privkey #include hsm_init_reply,111 diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 77f3897f0227..fcb135cb7c9e 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -72,6 +72,11 @@ static struct { * so set it static.*/ static struct bip32_key_version bip32_key_version; +#if DEVELOPER +/* If they specify --dev-force-privkey it ends up in here. */ +static struct privkey *dev_force_privkey; +#endif + /*~ We keep track of clients, but there's not much to keep. */ struct client { /* The ccan/io async io connection for this client: it closes, we die. */ @@ -314,6 +319,17 @@ static void node_key(struct privkey *node_privkey, struct pubkey *node_id) salt++; } while (!secp256k1_ec_pubkey_create(secp256k1_ctx, &node_id->pubkey, node_privkey->secret.data)); + +#if DEVELOPER + /* In DEVELOPER mode, we can override with --dev-force-privkey */ + if (dev_force_privkey) { + *node_privkey = *dev_force_privkey; + if (!secp256k1_ec_pubkey_create(secp256k1_ctx, &node_id->pubkey, + node_privkey->secret.data)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Failed to derive pubkey for dev_force_privkey"); + } +#endif } /*~ This secret is the basis for all per-channel secrets: the per-channel seeds @@ -540,6 +556,7 @@ static struct io_plan *init_hsm(struct io_conn *conn, { struct node_id node_id; struct pubkey key; + struct privkey *privkey; /* This must be lightningd. */ assert(is_lightningd(c)); @@ -548,9 +565,12 @@ static struct io_plan *init_hsm(struct io_conn *conn, * definitions in hsm_client_wire.csv. The format of those files is * an extension of the simple comma-separated format output by the * BOLT tools/extract-formats.py tool. */ - if (!fromwire_hsm_init(msg_in, &bip32_key_version)) + if (!fromwire_hsm_init(NULL, msg_in, &bip32_key_version, &privkey)) return bad_req(conn, c, msg_in); +#if DEVELOPER + dev_force_privkey = privkey; +#endif maybe_create_new_hsm(); load_hsm(); @@ -1601,6 +1621,8 @@ static struct io_plan *handle_memleak(struct io_conn *conn, memleak_remove_uintmap(memtable, &clients); memleak_scan_region(memtable, status_conn, tal_bytelen(status_conn)); + memleak_scan_region(memtable, dev_force_privkey, 0); + found_leak = dump_memleak(memtable); reply = towire_hsm_dev_memleak_reply(NULL, found_leak); return req_reply(conn, c, take(reply)); diff --git a/lightningd/hsm_control.c b/lightningd/hsm_control.c index f4eb6537dab4..6211648a84ce 100644 --- a/lightningd/hsm_control.c +++ b/lightningd/hsm_control.c @@ -94,7 +94,13 @@ void hsm_init(struct lightningd *ld) ld->hsm_fd = fds[0]; if (!wire_sync_write(ld->hsm_fd, towire_hsm_init(tmpctx, - &ld->topology->bitcoind->chainparams->bip32_key_version))) + &ld->topology->bitcoind->chainparams->bip32_key_version, +#if DEVELOPER + ld->dev_force_privkey +#else + NULL +#endif + ))) err(1, "Writing init msg to hsm"); ld->wallet->bip32_base = tal(ld->wallet, struct ext_key); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 9bee17ff31fb..3a941613ca45 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -118,6 +118,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx) ld->dev_subdaemon_fail = false; ld->dev_allow_localhost = false; ld->dev_gossip_time = 0; + ld->dev_force_privkey = NULL; #endif /*~ These are CCAN lists: an embedded double-linked list. It's not diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index 9002e993a6f7..78ff5ed78a28 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -205,6 +205,9 @@ struct lightningd { /* Things we've marked as not leaking. */ const void **notleaks; + + /* This is the forced private key for the node. */ + struct privkey *dev_force_privkey; #endif /* DEVELOPER */ /* tor support */ diff --git a/lightningd/options.c b/lightningd/options.c index 57b30608c24a..1cb070f6ae4d 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -438,6 +439,16 @@ static char *opt_subprocess_debug(const char *optarg, struct lightningd *ld) return NULL; } +static char *opt_force_privkey(const char *optarg, struct lightningd *ld) +{ + tal_free(ld->dev_force_privkey); + ld->dev_force_privkey = tal(ld, struct privkey); + if (!hex_decode(optarg, strlen(optarg), + ld->dev_force_privkey, sizeof(*ld->dev_force_privkey))) + return tal_fmt(NULL, "Unable to parse privkey '%s'", optarg); + return NULL; +} + static void dev_register_opts(struct lightningd *ld) { opt_register_noarg("--dev-no-reconnect", opt_set_invbool, @@ -474,6 +485,8 @@ static void dev_register_opts(struct lightningd *ld) opt_register_arg("--dev-gossip-time", opt_set_u32, opt_show_u32, &ld->dev_gossip_time, "UNIX time to override gossipd to use."); + opt_register_arg("--dev-force-privkey", opt_force_privkey, NULL, ld, + "Force HSM to use this as node private key"); } #endif