From 1e6eabf018ed8581015ecb35ce56fb00ff2d137c Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 17 Jul 2019 07:15:14 +0930 Subject: [PATCH] developer: add --dev-force-channel-secrets. We don't have this on a per-channel basis (yet), but it's sufficient for testing now. Signed-off-by: Rusty Russell --- common/derive_basepoints.c | 116 ++++++++++++++++++---------- common/derive_basepoints.h | 10 +++ common/test/run-derive_basepoints.c | 12 +++ hsmd/hsm_wire.csv | 2 + hsmd/hsmd.c | 6 +- lightningd/hsm_control.c | 6 +- lightningd/lightningd.c | 2 + lightningd/lightningd.h | 4 + lightningd/options.c | 39 ++++++++++ 9 files changed, 153 insertions(+), 44 deletions(-) diff --git a/common/derive_basepoints.c b/common/derive_basepoints.c index 176963da6..e47d67b30 100644 --- a/common/derive_basepoints.c +++ b/common/derive_basepoints.c @@ -4,19 +4,73 @@ #include #include +#if DEVELOPER +/* If they specify --dev-force-channel-secrets it ends up in here. */ +struct secrets *dev_force_channel_secrets; +struct sha256 *dev_force_channel_secrets_shaseed; + +void towire_secrets(u8 **pptr, const struct secrets *s) +{ + towire_privkey(pptr, &s->funding_privkey); + towire_secret(pptr, &s->revocation_basepoint_secret); + towire_secret(pptr, &s->payment_basepoint_secret); + towire_secret(pptr, &s->delayed_payment_basepoint_secret); + towire_secret(pptr, &s->htlc_basepoint_secret); +} + +void fromwire_secrets(const u8 **ptr, size_t *max, struct secrets *s) +{ + fromwire_privkey(ptr, max, &s->funding_privkey); + fromwire_secret(ptr, max, &s->revocation_basepoint_secret); + fromwire_secret(ptr, max, &s->payment_basepoint_secret); + fromwire_secret(ptr, max, &s->delayed_payment_basepoint_secret); + fromwire_secret(ptr, max, &s->htlc_basepoint_secret); +} +#else /* !DEVELOPER */ +/* Generate code refers to this, but should never be called! */ +void towire_secrets(u8 **pptr, const struct secrets *s) +{ + abort(); +} + +void fromwire_secrets(const u8 **ptr, size_t *max, struct secrets *s) +{ + abort(); +} +#endif + +struct keys { + struct privkey f, r, h, p, d; + struct sha256 shaseed; +}; + +static void derive_keys(const struct secret *seed, struct keys *keys) +{ + hkdf_sha256(keys, sizeof(*keys), NULL, 0, seed, sizeof(*seed), + "c-lightning", strlen("c-lightning")); + +#if DEVELOPER + if (dev_force_channel_secrets) { + keys->f = dev_force_channel_secrets->funding_privkey; + keys->r.secret = dev_force_channel_secrets->revocation_basepoint_secret; + keys->p.secret = dev_force_channel_secrets->payment_basepoint_secret; + keys->h.secret = dev_force_channel_secrets->htlc_basepoint_secret; + keys->d.secret = dev_force_channel_secrets->delayed_payment_basepoint_secret; + } + if (dev_force_channel_secrets_shaseed) + keys->shaseed = *dev_force_channel_secrets_shaseed; +#endif +} + bool derive_basepoints(const struct secret *seed, struct pubkey *funding_pubkey, struct basepoints *basepoints, struct secrets *secrets, struct sha256 *shaseed) { - struct keys { - struct privkey f, r, h, p, d; - struct sha256 shaseed; - } keys; + struct keys keys; - hkdf_sha256(&keys, sizeof(keys), NULL, 0, seed, sizeof(*seed), - "c-lightning", strlen("c-lightning")); + derive_keys(seed, &keys); if (secrets) { secrets->funding_privkey = keys.f; @@ -95,13 +149,9 @@ bool derive_payment_basepoint(const struct secret *seed, struct pubkey *payment_basepoint, struct secret *payment_secret) { - struct keys { - struct privkey f, r, h, p, d; - struct sha256 shaseed; - } keys; + struct keys keys; - hkdf_sha256(&keys, sizeof(keys), NULL, 0, seed, sizeof(*seed), - "c-lightning", strlen("c-lightning")); + derive_keys(seed, &keys); if (payment_basepoint) { if (!pubkey_from_privkey(&keys.p, payment_basepoint)) @@ -118,13 +168,9 @@ bool derive_delayed_payment_basepoint(const struct secret *seed, struct pubkey *delayed_payment_basepoint, struct secret *delayed_payment_secret) { - struct keys { - struct privkey f, r, h, p, d; - struct sha256 shaseed; - } keys; + struct keys keys; - hkdf_sha256(&keys, sizeof(keys), NULL, 0, seed, sizeof(*seed), - "c-lightning", strlen("c-lightning")); + derive_keys(seed, &keys); if (delayed_payment_basepoint) { if (!pubkey_from_privkey(&keys.d, delayed_payment_basepoint)) @@ -139,13 +185,10 @@ bool derive_delayed_payment_basepoint(const struct secret *seed, bool derive_shaseed(const struct secret *seed, struct sha256 *shaseed) { - struct keys { - struct privkey f, r, h, p, d; - struct sha256 shaseed; - } keys; + struct keys keys; + + derive_keys(seed, &keys); - hkdf_sha256(&keys, sizeof(keys), NULL, 0, seed, sizeof(*seed), - "c-lightning", strlen("c-lightning")); *shaseed = keys.shaseed; return true; } @@ -154,18 +197,17 @@ bool derive_funding_key(const struct secret *seed, struct pubkey *funding_pubkey, struct privkey *funding_privkey) { - struct privkey f; + struct keys keys; - hkdf_sha256(&f, sizeof(f), NULL, 0, seed, sizeof(*seed), - "c-lightning", strlen("c-lightning")); + derive_keys(seed, &keys); if (funding_pubkey) { - if (!pubkey_from_privkey(&f, funding_pubkey)) + if (!pubkey_from_privkey(&keys.f, funding_pubkey)) return false; } if (funding_privkey) - *funding_privkey = f; + *funding_privkey = keys.f; return true; } @@ -174,13 +216,9 @@ bool derive_revocation_basepoint(const struct secret *seed, struct pubkey *revocation_basepoint, struct secret *revocation_secret) { - struct keys { - struct privkey f, r, h, p, d; - struct sha256 shaseed; - } keys; + struct keys keys; - hkdf_sha256(&keys, sizeof(keys), NULL, 0, seed, sizeof(*seed), - "c-lightning", strlen("c-lightning")); + derive_keys(seed, &keys); if (revocation_basepoint) { if (!pubkey_from_privkey(&keys.r, revocation_basepoint)) @@ -197,13 +235,9 @@ bool derive_htlc_basepoint(const struct secret *seed, struct pubkey *htlc_basepoint, struct secret *htlc_secret) { - struct keys { - struct privkey f, r, h, p, d; - struct sha256 shaseed; - } keys; + struct keys keys; - hkdf_sha256(&keys, sizeof(keys), NULL, 0, seed, sizeof(*seed), - "c-lightning", strlen("c-lightning")); + derive_keys(seed, &keys); if (htlc_basepoint) { if (!pubkey_from_privkey(&keys.h, htlc_basepoint)) diff --git a/common/derive_basepoints.h b/common/derive_basepoints.h index 84b6c25c5..e3c00ea5e 100644 --- a/common/derive_basepoints.h +++ b/common/derive_basepoints.h @@ -155,4 +155,14 @@ void towire_basepoints(u8 **pptr, const struct basepoints *b); void fromwire_basepoints(const u8 **ptr, size_t *max, struct basepoints *b); +/* For --dev-force-channel-secrets. */ +#if DEVELOPER +extern struct secrets *dev_force_channel_secrets; +extern struct sha256 *dev_force_channel_secrets_shaseed; +#endif + +/* Note: these abort if !DEVELOPER */ +void towire_secrets(u8 **pptr, const struct secrets *s); +void fromwire_secrets(const u8 **ptr, size_t *max, struct secrets *s); + #endif /* LIGHTNING_COMMON_DERIVE_BASEPOINTS_H */ diff --git a/common/test/run-derive_basepoints.c b/common/test/run-derive_basepoints.c index c079ac69e..630d1e363 100644 --- a/common/test/run-derive_basepoints.c +++ b/common/test/run-derive_basepoints.c @@ -11,12 +11,24 @@ /* Generated stub for fromwire_fail */ const void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_fail called!\n"); abort(); } +/* Generated stub for fromwire_privkey */ +void fromwire_privkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct privkey *privkey UNNEEDED) +{ fprintf(stderr, "fromwire_privkey called!\n"); abort(); } /* Generated stub for fromwire_pubkey */ void fromwire_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct pubkey *pubkey UNNEEDED) { fprintf(stderr, "fromwire_pubkey called!\n"); abort(); } +/* Generated stub for fromwire_secret */ +void fromwire_secret(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct secret *secret UNNEEDED) +{ fprintf(stderr, "fromwire_secret called!\n"); abort(); } +/* Generated stub for towire_privkey */ +void towire_privkey(u8 **pptr UNNEEDED, const struct privkey *privkey UNNEEDED) +{ fprintf(stderr, "towire_privkey called!\n"); abort(); } /* Generated stub for towire_pubkey */ void towire_pubkey(u8 **pptr UNNEEDED, const struct pubkey *pubkey UNNEEDED) { fprintf(stderr, "towire_pubkey called!\n"); abort(); } +/* Generated stub for towire_secret */ +void towire_secret(u8 **pptr UNNEEDED, const struct secret *secret UNNEEDED) +{ fprintf(stderr, "towire_secret called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ STRUCTEQ_DEF(basepoints, 0, diff --git a/hsmd/hsm_wire.csv b/hsmd/hsm_wire.csv index d323ef4ec..ecc56d604 100644 --- a/hsmd/hsm_wire.csv +++ b/hsmd/hsm_wire.csv @@ -11,6 +11,8 @@ hsm_init,11 hsm_init,,bip32_key_version,struct bip32_key_version hsm_init,,dev_force_privkey,?struct privkey hsm_init,,dev_force_bip32_seed,?struct secret +hsm_init,,dev_force_channel_secrets,?struct secrets +hsm_init,,dev_force_channel_secrets_shaseed,?struct sha256 #include hsm_init_reply,111 diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 097f44468..80def06ca 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -572,6 +572,8 @@ static struct io_plan *init_hsm(struct io_conn *conn, struct pubkey key; struct privkey *privkey; struct secret *seed; + struct secrets *secrets; + struct sha256 *shaseed; /* This must be lightningd. */ assert(is_lightningd(c)); @@ -581,12 +583,14 @@ static struct io_plan *init_hsm(struct io_conn *conn, * an extension of the simple comma-separated format output by the * BOLT tools/extract-formats.py tool. */ if (!fromwire_hsm_init(NULL, msg_in, &bip32_key_version, - &privkey, &seed)) + &privkey, &seed, &secrets, &shaseed)) return bad_req(conn, c, msg_in); #if DEVELOPER dev_force_privkey = privkey; dev_force_bip32_seed = seed; + dev_force_channel_secrets = secrets; + dev_force_channel_secrets_shaseed = shaseed; #endif maybe_create_new_hsm(); load_hsm(); diff --git a/lightningd/hsm_control.c b/lightningd/hsm_control.c index bbc04f66c..e7a1d2380 100644 --- a/lightningd/hsm_control.c +++ b/lightningd/hsm_control.c @@ -97,9 +97,11 @@ void hsm_init(struct lightningd *ld) &ld->topology->bitcoind->chainparams->bip32_key_version, #if DEVELOPER ld->dev_force_privkey, - ld->dev_force_bip32_seed + ld->dev_force_bip32_seed, + ld->dev_force_channel_secrets, + ld->dev_force_channel_secrets_shaseed #else - NULL, NULL + NULL, NULL, NULL, NULL #endif ))) err(1, "Writing init msg to hsm"); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index b81ab449a..563c95aea 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -120,6 +120,8 @@ static struct lightningd *new_lightningd(const tal_t *ctx) ld->dev_gossip_time = 0; ld->dev_force_privkey = NULL; ld->dev_force_bip32_seed = NULL; + ld->dev_force_channel_secrets = NULL; + ld->dev_force_channel_secrets_shaseed = 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 918edae1b..47f496175 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -211,6 +211,10 @@ struct lightningd { /* This is the forced bip32 seed for the node. */ struct secret *dev_force_bip32_seed; + + /* These are the forced channel secrets for the node. */ + struct secrets *dev_force_channel_secrets; + struct sha256 *dev_force_channel_secrets_shaseed; #endif /* DEVELOPER */ /* tor support */ diff --git a/lightningd/options.c b/lightningd/options.c index 17555c11a..364fafffc 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -460,6 +461,42 @@ static char *opt_force_bip32_seed(const char *optarg, struct lightningd *ld) return NULL; } +static char *opt_force_channel_secrets(const char *optarg, + struct lightningd *ld) +{ + char **strs; + tal_free(ld->dev_force_channel_secrets); + tal_free(ld->dev_force_channel_secrets_shaseed); + ld->dev_force_channel_secrets = tal(ld, struct secrets); + ld->dev_force_channel_secrets_shaseed = tal(ld, struct sha256); + + strs = tal_strsplit(tmpctx, optarg, "/", STR_EMPTY_OK); + if (tal_count(strs) != 7) /* Last is NULL */ + return "Expected 6 hex secrets separated by /"; + + if (!hex_decode(strs[0], strlen(strs[0]), + &ld->dev_force_channel_secrets->funding_privkey, + sizeof(ld->dev_force_channel_secrets->funding_privkey)) + || !hex_decode(strs[1], strlen(strs[1]), + &ld->dev_force_channel_secrets->revocation_basepoint_secret, + sizeof(ld->dev_force_channel_secrets->revocation_basepoint_secret)) + || !hex_decode(strs[2], strlen(strs[2]), + &ld->dev_force_channel_secrets->payment_basepoint_secret, + sizeof(ld->dev_force_channel_secrets->payment_basepoint_secret)) + || !hex_decode(strs[3], strlen(strs[3]), + &ld->dev_force_channel_secrets->delayed_payment_basepoint_secret, + sizeof(ld->dev_force_channel_secrets->delayed_payment_basepoint_secret)) + || !hex_decode(strs[4], strlen(strs[4]), + &ld->dev_force_channel_secrets->htlc_basepoint_secret, + sizeof(ld->dev_force_channel_secrets->htlc_basepoint_secret)) + || !hex_decode(strs[5], strlen(strs[5]), + ld->dev_force_channel_secrets_shaseed, + sizeof(*ld->dev_force_channel_secrets_shaseed))) + return "Expected 6 hex secrets separated by /"; + + return NULL; +} + static void dev_register_opts(struct lightningd *ld) { opt_register_noarg("--dev-no-reconnect", opt_set_invbool, @@ -500,6 +537,8 @@ static void dev_register_opts(struct lightningd *ld) "Force HSM to use this as node private key"); opt_register_arg("--dev-force-bip32-seed", opt_force_bip32_seed, NULL, ld, "Force HSM to use this as bip32 seed"); + opt_register_arg("--dev-force-channel-secrets", opt_force_channel_secrets, NULL, ld, + "Force HSM to use these for all per-channel secrets"); } #endif