hsmtool: makerune command.

You still need to actually make a rune when lightningd starts, as
commando (for safety) won't work unless you actually generate a rune
(that it knows of!).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: hsmtool: `makerune` command to make a master rune for a node.
This commit is contained in:
Rusty Russell 2023-04-11 12:01:31 +09:30 committed by ShahanaFarooqui
parent 441b38c9ea
commit 62d9ecb6d3
3 changed files with 71 additions and 0 deletions

View File

@ -68,6 +68,11 @@ We need the path to the hsm\_secret containing the wallet seed, and an optional
To generate descriptors using testnet master keys, you may specify *testnet* as
the last parameter. By default, mainnet-encoded keys are generated.
**makerune** *hsm\_secret*
Make a master rune for this node (with `uniqueid` 0)
This produces the same results as lightning-commando-rune(7) on a fresh node.
You will still need to create a rune once the node starts, if you want commando to work (as it is only activated once it has generated one).
BUGS
----

View File

@ -1667,3 +1667,34 @@ def test_upgradewallet(node_factory, bitcoind):
sync_blockheight(l1.bitcoin, [l1])
upgrade = l1.rpc.upgradewallet(feerate="urgent", reservedok=True)
assert upgrade['upgraded_outs'] == 0
def test_hsmtool_makerune(node_factory):
"""Test we can make a valid rune before the node really exists"""
l1 = node_factory.get_node(start=False)
# get_node() creates a secret, but in usual case we generate one.
hsm_path = os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, "hsm_secret")
os.remove(hsm_path)
hsmtool = HsmTool(node_factory.directory, "generatehsm", hsm_path)
master_fd, slave_fd = os.openpty()
hsmtool.start(stdin=slave_fd)
hsmtool.wait_for_log(r"Select your language:")
write_all(master_fd, "0\n".encode("utf-8"))
hsmtool.wait_for_log(r"Introduce your BIP39 word list")
write_all(master_fd, "ritual idle hat sunny universe pluck key alpha wing "
"cake have wedding\n".encode("utf-8"))
hsmtool.wait_for_log(r"Enter your passphrase:")
write_all(master_fd, "This is actually not a passphrase\n".encode("utf-8"))
assert hsmtool.proc.wait(WAIT_TIMEOUT) == 0
hsmtool.is_in_log(r"New hsm_secret file created")
cmd_line = ["tools/hsmtool", "makerune", hsm_path]
out = subprocess.check_output(cmd_line).decode("utf8").split("\n")[0]
l1.start()
# We have to generate a rune now, for commando to even start processing!
rune = l1.rpc.commando_rune()['rune']
assert rune == out

View File

@ -4,6 +4,7 @@
#include <ccan/err/err.h>
#include <ccan/noerr/noerr.h>
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/rune/rune.h>
#include <ccan/tal/grab_file/grab_file.h>
#include <ccan/tal/path/path.h>
#include <ccan/tal/str/str.h>
@ -42,6 +43,7 @@ static void show_usage(const char *progname)
printf(" - generatehsm <path/to/new/hsm_secret>\n");
printf(" - checkhsm <path/to/new/hsm_secret>\n");
printf(" - dumponchaindescriptors <path/to/hsm_secret> [network]\n");
printf(" - makerune <path/to/hsm_secret>\n");
exit(0);
}
@ -611,6 +613,33 @@ static int check_hsm(const char *hsm_secret_path)
return 0;
}
static int make_rune(const char *hsm_secret_path)
{
struct secret hsm_secret, derived_secret, rune_secret;
struct rune *master_rune, *rune;
/* Get hsm_secret */
get_hsm_secret(&hsm_secret, hsm_secret_path);
/* HSM derives a root secret for `makesecret` */
hkdf_sha256(&derived_secret, sizeof(struct secret), NULL, 0,
&hsm_secret, sizeof(hsm_secret),
"derived secrets", strlen("derived secrets"));
/* Commando derives secret using makesecret "commando" */
hkdf_sha256(&rune_secret, sizeof(struct secret), NULL, 0,
&derived_secret, sizeof(derived_secret),
"commando", strlen("commando"));
master_rune = rune_new(tmpctx,
rune_secret.data,
ARRAY_SIZE(rune_secret.data),
NULL);
rune = rune_derive_start(tmpctx, master_rune, "0");
printf("%s\n", rune_to_base64(tmpctx, rune));
return 0;
}
int main(int argc, char *argv[])
{
const char *method;
@ -703,5 +732,11 @@ int main(int argc, char *argv[])
return check_hsm(argv[2]);
}
if (streq(method, "makerune")) {
if (argc < 3)
show_usage(argv[0]);
return make_rune(argv[2]);
}
show_usage(argv[0]);
}