mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-14 11:36:47 +01:00
hsmtool: input encryption password from stdin
This slightly breaks the API, but still accept the input: we just don't take it into account anymore. For `dumponchaindescriptors`, we have to still take the old place of the `network` parameter into account to not entirely break the API. Changelog-Added: hsmtool: password must now be entered on stdin. Password passed on the command line are discarded. Signed-off-by: Antoine Poinsot <darosior@protonmail.com>
This commit is contained in:
parent
5b3af00e28
commit
1513a2d07e
3 changed files with 159 additions and 63 deletions
|
@ -6,7 +6,7 @@ from flaky import flaky # noqa: F401
|
||||||
from pyln.client import RpcError, Millisatoshi
|
from pyln.client import RpcError, Millisatoshi
|
||||||
from utils import (
|
from utils import (
|
||||||
only_one, wait_for, sync_blockheight, EXPERIMENTAL_FEATURES,
|
only_one, wait_for, sync_blockheight, EXPERIMENTAL_FEATURES,
|
||||||
VALGRIND, check_coin_moves
|
VALGRIND, check_coin_moves, TailableProc
|
||||||
)
|
)
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
@ -985,6 +985,14 @@ def test_hsm_secret_encryption(node_factory):
|
||||||
assert id == l1.rpc.getinfo()["id"]
|
assert id == l1.rpc.getinfo()["id"]
|
||||||
|
|
||||||
|
|
||||||
|
class HsmTool(TailableProc):
|
||||||
|
"""Helper for testing the hsmtool as a subprocess"""
|
||||||
|
def __init__(self, *args):
|
||||||
|
TailableProc.__init__(self)
|
||||||
|
assert hasattr(self, "env")
|
||||||
|
self.cmd_line = ["tools/hsmtool", *args]
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(VALGRIND, "It does not play well with prompt and key derivation.")
|
@unittest.skipIf(VALGRIND, "It does not play well with prompt and key derivation.")
|
||||||
def test_hsmtool_secret_decryption(node_factory):
|
def test_hsmtool_secret_decryption(node_factory):
|
||||||
l1 = node_factory.get_node()
|
l1 = node_factory.get_node()
|
||||||
|
@ -1004,13 +1012,20 @@ def test_hsmtool_secret_decryption(node_factory):
|
||||||
l1.stop()
|
l1.stop()
|
||||||
|
|
||||||
# We can't use a wrong password !
|
# We can't use a wrong password !
|
||||||
cmd_line = ["tools/hsmtool", "decrypt", hsm_path, "A wrong pass"]
|
hsmtool = HsmTool("decrypt", hsm_path)
|
||||||
with pytest.raises(subprocess.CalledProcessError):
|
hsmtool.start(stdin=slave_fd,
|
||||||
subprocess.check_call(cmd_line)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
hsmtool.wait_for_log(r"Enter hsm_secret password:")
|
||||||
|
os.write(master_fd, "A wrong pass\n\n".encode("utf-8"))
|
||||||
|
hsmtool.proc.wait(5)
|
||||||
|
hsmtool.is_in_log(r"Wrong password")
|
||||||
|
|
||||||
# Decrypt it with hsmtool
|
# Decrypt it with hsmtool
|
||||||
cmd_line[3] = password[:-1]
|
hsmtool.start(stdin=slave_fd,
|
||||||
subprocess.check_call(cmd_line)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
hsmtool.wait_for_log(r"Enter hsm_secret password:")
|
||||||
|
os.write(master_fd, password.encode("utf-8"))
|
||||||
|
assert hsmtool.proc.wait(5) == 0
|
||||||
# Then test we can now start it without password
|
# Then test we can now start it without password
|
||||||
l1.daemon.opts.pop("encrypted-hsm")
|
l1.daemon.opts.pop("encrypted-hsm")
|
||||||
l1.daemon.start(stdin=slave_fd, wait_for_initialized=True)
|
l1.daemon.start(stdin=slave_fd, wait_for_initialized=True)
|
||||||
|
@ -1018,11 +1033,14 @@ def test_hsmtool_secret_decryption(node_factory):
|
||||||
l1.stop()
|
l1.stop()
|
||||||
|
|
||||||
# Test we can encrypt it offline
|
# Test we can encrypt it offline
|
||||||
cmd_line[1] = "encrypt"
|
hsmtool = HsmTool("encrypt", hsm_path)
|
||||||
subprocess.check_call(cmd_line)
|
hsmtool.start(stdin=slave_fd,
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
hsmtool.wait_for_log(r"Enter hsm_secret password:")
|
||||||
|
os.write(master_fd, password.encode("utf-8"))
|
||||||
|
assert hsmtool.proc.wait(5) == 0
|
||||||
# Now we need to pass the encrypted-hsm startup option
|
# Now we need to pass the encrypted-hsm startup option
|
||||||
l1.stop()
|
l1.stop()
|
||||||
|
|
||||||
with pytest.raises(subprocess.CalledProcessError, match=r'returned non-zero exit status 1'):
|
with pytest.raises(subprocess.CalledProcessError, match=r'returned non-zero exit status 1'):
|
||||||
subprocess.check_call(l1.daemon.cmd_line)
|
subprocess.check_call(l1.daemon.cmd_line)
|
||||||
|
|
||||||
|
@ -1034,12 +1052,17 @@ def test_hsmtool_secret_decryption(node_factory):
|
||||||
l1.daemon.wait_for_log(r'The hsm_secret is encrypted')
|
l1.daemon.wait_for_log(r'The hsm_secret is encrypted')
|
||||||
os.write(master_fd, password.encode("utf-8"))
|
os.write(master_fd, password.encode("utf-8"))
|
||||||
l1.daemon.wait_for_log("Server started with public key")
|
l1.daemon.wait_for_log("Server started with public key")
|
||||||
|
print(node_id, l1.rpc.getinfo()["id"])
|
||||||
assert node_id == l1.rpc.getinfo()["id"]
|
assert node_id == l1.rpc.getinfo()["id"]
|
||||||
l1.stop()
|
l1.stop()
|
||||||
|
|
||||||
# And finally test that we can also decrypt if encrypted with hsmtool
|
# And finally test that we can also decrypt if encrypted with hsmtool
|
||||||
cmd_line[1] = "decrypt"
|
hsmtool = HsmTool("decrypt", hsm_path)
|
||||||
subprocess.check_call(cmd_line)
|
hsmtool.start(stdin=slave_fd,
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
hsmtool.wait_for_log(r"Enter hsm_secret password:")
|
||||||
|
os.write(master_fd, password.encode("utf-8"))
|
||||||
|
assert hsmtool.proc.wait(5) == 0
|
||||||
l1.daemon.opts.pop("encrypted-hsm")
|
l1.daemon.opts.pop("encrypted-hsm")
|
||||||
l1.daemon.start(stdin=slave_fd, wait_for_initialized=True)
|
l1.daemon.start(stdin=slave_fd, wait_for_initialized=True)
|
||||||
assert node_id == l1.rpc.getinfo()["id"]
|
assert node_id == l1.rpc.getinfo()["id"]
|
||||||
|
@ -1052,8 +1075,7 @@ def test_hsmtool_dump_descriptors(node_factory, bitcoind):
|
||||||
|
|
||||||
# Get a tpub descriptor of lightningd's wallet
|
# Get a tpub descriptor of lightningd's wallet
|
||||||
hsm_path = os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, "hsm_secret")
|
hsm_path = os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, "hsm_secret")
|
||||||
cmd_line = ["tools/hsmtool", "dumponchaindescriptors", hsm_path, "",
|
cmd_line = ["tools/hsmtool", "dumponchaindescriptors", hsm_path, "testnet"]
|
||||||
"testnet"]
|
|
||||||
out = subprocess.check_output(cmd_line).decode("utf8").split("\n")
|
out = subprocess.check_output(cmd_line).decode("utf8").split("\n")
|
||||||
descriptor = [l for l in out if l.startswith("wpkh(tpub")][0]
|
descriptor = [l for l in out if l.startswith("wpkh(tpub")][0]
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ tools/headerversions: FORCE tools/headerversions.o $(CCAN_OBJS)
|
||||||
|
|
||||||
tools/check-bolt: tools/check-bolt.o $(CCAN_OBJS) $(TOOLS_COMMON_OBJS)
|
tools/check-bolt: tools/check-bolt.o $(CCAN_OBJS) $(TOOLS_COMMON_OBJS)
|
||||||
|
|
||||||
tools/hsmtool: tools/hsmtool.o $(CCAN_OBJS) $(TOOLS_COMMON_OBJS) $(BITCOIN_OBJS) common/amount.o common/bech32.o common/bigsize.o common/derive_basepoints.o common/descriptor_checksum.o common/node_id.o common/type_to_string.o wire/fromwire.o wire/towire.o
|
tools/hsmtool: tools/hsmtool.o $(CCAN_OBJS) $(TOOLS_COMMON_OBJS) $(BITCOIN_OBJS) common/amount.o common/bech32.o common/bigsize.o common/configdir.o common/derive_basepoints.o common/descriptor_checksum.o common/node_id.o common/type_to_string.o common/version.o wire/fromwire.o wire/towire.o
|
||||||
|
|
||||||
tools/lightning-hsmtool: tools/hsmtool
|
tools/lightning-hsmtool: tools/hsmtool
|
||||||
cp $< $@
|
cp $< $@
|
||||||
|
|
168
tools/hsmtool.c
168
tools/hsmtool.c
|
@ -8,6 +8,7 @@
|
||||||
#include <ccan/tal/path/path.h>
|
#include <ccan/tal/path/path.h>
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
#include <common/bech32.h>
|
#include <common/bech32.h>
|
||||||
|
#include <common/configdir.h>
|
||||||
#include <common/derive_basepoints.h>
|
#include <common/derive_basepoints.h>
|
||||||
#include <common/descriptor_checksum.h>
|
#include <common/descriptor_checksum.h>
|
||||||
#include <common/node_id.h>
|
#include <common/node_id.h>
|
||||||
|
@ -29,20 +30,20 @@
|
||||||
#define ERROR_LIBWALLY 4
|
#define ERROR_LIBWALLY 4
|
||||||
#define ERROR_KEYDERIV 5
|
#define ERROR_KEYDERIV 5
|
||||||
#define ERROR_LANG_NOT_SUPPORTED 6
|
#define ERROR_LANG_NOT_SUPPORTED 6
|
||||||
|
#define ERROR_TERM 7
|
||||||
|
|
||||||
static void show_usage(const char *progname)
|
static void show_usage(const char *progname)
|
||||||
{
|
{
|
||||||
printf("%s <method> [arguments]\n", progname);
|
printf("%s <method> [arguments]\n", progname);
|
||||||
printf("methods:\n");
|
printf("methods:\n");
|
||||||
printf(" - decrypt <path/to/hsm_secret> <password>\n");
|
printf(" - decrypt <path/to/hsm_secret>\n");
|
||||||
printf(" - encrypt <path/to/hsm_secret> <password>\n");
|
printf(" - encrypt <path/to/hsm_secret>\n");
|
||||||
printf(" - dumpcommitments <node id> <channel dbid> <depth> "
|
printf(" - dumpcommitments <node id> <channel dbid> <depth> "
|
||||||
"<path/to/hsm_secret> [hsm_secret password]\n");
|
"<path/to/hsm_secret>\n");
|
||||||
printf(" - guesstoremote <P2WPKH address> <node id> <tries> "
|
printf(" - guesstoremote <P2WPKH address> <node id> <tries> "
|
||||||
"<path/to/hsm_secret> [hsm_secret password]\n");
|
"<path/to/hsm_secret>\n");
|
||||||
printf(" - generatehsm <path/to/new//hsm_secret>\n");
|
printf(" - generatehsm <path/to/new/hsm_secret>\n");
|
||||||
printf(" - dumponchaindescriptors <path/to/hsm_secret> [password] "
|
printf(" - dumponchaindescriptors <path/to/hsm_secret> [network]\n");
|
||||||
"[network]\n");
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,13 +158,57 @@ static void get_channel_seed(struct secret *channel_seed, struct node_id *peer_i
|
||||||
info, strlen(info));
|
info, strlen(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decrypt_hsm(const char *hsm_secret_path, const char *passwd)
|
/* We detect an encrypted hsm_secret as a hsm_secret which is larger than
|
||||||
|
* the plaintext seed. */
|
||||||
|
static bool hsm_secret_is_encrypted(const char *hsm_secret_path)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
if (stat(hsm_secret_path, &st) != 0)
|
||||||
|
errx(ERROR_HSM_FILE, "Could not stat hsm_secret");
|
||||||
|
return st.st_size > 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a pass from stdin, disabling echoing as done in lightning/options for the
|
||||||
|
* --encrypted-hsm startup option.
|
||||||
|
* Caller must free the returned string. */
|
||||||
|
static char *read_stdin_pass(void)
|
||||||
|
{
|
||||||
|
struct termios current_term, temp_term;
|
||||||
|
char *passwd = NULL;
|
||||||
|
size_t passwd_size = 0;
|
||||||
|
|
||||||
|
if (tcgetattr(fileno(stdin), ¤t_term) != 0)
|
||||||
|
errx(ERROR_TERM, "Could not get current terminal options.");
|
||||||
|
temp_term = current_term;
|
||||||
|
temp_term.c_lflag &= ~ECHO;
|
||||||
|
if (tcsetattr(fileno(stdin), TCSAFLUSH, &temp_term) != 0)
|
||||||
|
errx(ERROR_TERM, "Could not disable pass echoing.");
|
||||||
|
/* If we don't flush we might end up being buffered and we might seem
|
||||||
|
* to hang while we wait for the password. */
|
||||||
|
fflush(stdout);
|
||||||
|
if (getline(&passwd, &passwd_size, stdin) < 0)
|
||||||
|
errx(ERROR_TERM, "Could not read pass from stdin.");
|
||||||
|
if (passwd[strlen(passwd) - 1] == '\n')
|
||||||
|
passwd[strlen(passwd) - 1] = '\0';
|
||||||
|
if (tcsetattr(fileno(stdin), TCSAFLUSH, ¤t_term) != 0)
|
||||||
|
errx(ERROR_TERM, "Could not restore terminal options.");
|
||||||
|
|
||||||
|
return passwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decrypt_hsm(const char *hsm_secret_path)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct stat st;
|
|
||||||
struct secret hsm_secret;
|
struct secret hsm_secret;
|
||||||
|
char *passwd;
|
||||||
const char *dir, *backup;
|
const char *dir, *backup;
|
||||||
|
|
||||||
|
/* This checks the file existence, too. */
|
||||||
|
if (!hsm_secret_is_encrypted(hsm_secret_path))
|
||||||
|
errx(ERROR_USAGE, "hsm_secret is not encrypted");
|
||||||
|
printf("Enter hsm_secret password:\n");
|
||||||
|
passwd = read_stdin_pass();
|
||||||
|
|
||||||
if (sodium_init() == -1)
|
if (sodium_init() == -1)
|
||||||
err(ERROR_LIBSODIUM,
|
err(ERROR_LIBSODIUM,
|
||||||
"Could not initialize libsodium. Not enough entropy ?");
|
"Could not initialize libsodium. Not enough entropy ?");
|
||||||
|
@ -171,11 +216,10 @@ static int decrypt_hsm(const char *hsm_secret_path, const char *passwd)
|
||||||
dir = path_dirname(NULL, hsm_secret_path);
|
dir = path_dirname(NULL, hsm_secret_path);
|
||||||
backup = path_join(dir, dir, "hsm_secret.backup");
|
backup = path_join(dir, dir, "hsm_secret.backup");
|
||||||
|
|
||||||
if (stat(hsm_secret_path, &st) != 0)
|
|
||||||
err(ERROR_HSM_FILE, "Could not stat hsm_secret");
|
|
||||||
if (st.st_size <= 32)
|
|
||||||
err(ERROR_HSM_FILE, "hsm_secret is not encrypted");
|
|
||||||
get_encrypted_hsm_secret(&hsm_secret, hsm_secret_path, passwd);
|
get_encrypted_hsm_secret(&hsm_secret, hsm_secret_path, passwd);
|
||||||
|
/* Once the encryption key derived, we don't need it anymore. */
|
||||||
|
if (passwd)
|
||||||
|
free(passwd);
|
||||||
|
|
||||||
/* Create a backup file, "just in case". */
|
/* Create a backup file, "just in case". */
|
||||||
rename(hsm_secret_path, backup);
|
rename(hsm_secret_path, backup);
|
||||||
|
@ -205,11 +249,11 @@ static int decrypt_hsm(const char *hsm_secret_path, const char *passwd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int encrypt_hsm(const char *hsm_secret_path, const char *passwd)
|
static int encrypt_hsm(const char *hsm_secret_path)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct stat st;
|
|
||||||
struct secret key, hsm_secret;
|
struct secret key, hsm_secret;
|
||||||
|
char *passwd;
|
||||||
u8 salt[16] = "c-lightning\0\0\0\0\0";
|
u8 salt[16] = "c-lightning\0\0\0\0\0";
|
||||||
crypto_secretstream_xchacha20poly1305_state crypto_state;
|
crypto_secretstream_xchacha20poly1305_state crypto_state;
|
||||||
u8 header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
|
u8 header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
|
||||||
|
@ -217,6 +261,15 @@ static int encrypt_hsm(const char *hsm_secret_path, const char *passwd)
|
||||||
u8 cipher[sizeof(struct secret) + crypto_secretstream_xchacha20poly1305_ABYTES];
|
u8 cipher[sizeof(struct secret) + crypto_secretstream_xchacha20poly1305_ABYTES];
|
||||||
const char *dir, *backup;
|
const char *dir, *backup;
|
||||||
|
|
||||||
|
/* This checks the file existence, too. */
|
||||||
|
if (hsm_secret_is_encrypted(hsm_secret_path))
|
||||||
|
errx(ERROR_USAGE, "hsm_secret is already encrypted");
|
||||||
|
|
||||||
|
printf("Enter hsm_secret password:\n");
|
||||||
|
/* TODO: make the user double check the password. */
|
||||||
|
passwd = read_stdin_pass();
|
||||||
|
get_hsm_secret(&hsm_secret, hsm_secret_path);
|
||||||
|
|
||||||
dir = path_dirname(NULL, hsm_secret_path);
|
dir = path_dirname(NULL, hsm_secret_path);
|
||||||
backup = path_join(dir, dir, "hsm_secret.backup");
|
backup = path_join(dir, dir, "hsm_secret.backup");
|
||||||
|
|
||||||
|
@ -224,12 +277,6 @@ static int encrypt_hsm(const char *hsm_secret_path, const char *passwd)
|
||||||
err(ERROR_LIBSODIUM,
|
err(ERROR_LIBSODIUM,
|
||||||
"Could not initialize libsodium. Not enough entropy ?");
|
"Could not initialize libsodium. Not enough entropy ?");
|
||||||
|
|
||||||
if (stat(hsm_secret_path, &st) != 0)
|
|
||||||
err(ERROR_HSM_FILE, "Could not stat hsm_secret");
|
|
||||||
if (st.st_size > 32)
|
|
||||||
err(ERROR_USAGE, "hsm_secret is already encrypted");
|
|
||||||
get_hsm_secret(&hsm_secret, hsm_secret_path);
|
|
||||||
|
|
||||||
/* Derive the encryption key from the password provided, and try to encrypt
|
/* Derive the encryption key from the password provided, and try to encrypt
|
||||||
* the seed. */
|
* the seed. */
|
||||||
if (crypto_pwhash(key.data, sizeof(key.data), passwd, strlen(passwd), salt,
|
if (crypto_pwhash(key.data, sizeof(key.data), passwd, strlen(passwd), salt,
|
||||||
|
@ -246,6 +293,10 @@ static int encrypt_hsm(const char *hsm_secret_path, const char *passwd)
|
||||||
NULL, 0, 0) != 0)
|
NULL, 0, 0) != 0)
|
||||||
err(ERROR_LIBSODIUM, "Could not encrypt the seed.");
|
err(ERROR_LIBSODIUM, "Could not encrypt the seed.");
|
||||||
|
|
||||||
|
/* Once the encryption key derived, we don't need it anymore. */
|
||||||
|
if (passwd)
|
||||||
|
free(passwd);
|
||||||
|
|
||||||
/* Create a backup file, "just in case". */
|
/* Create a backup file, "just in case". */
|
||||||
rename(hsm_secret_path, backup);
|
rename(hsm_secret_path, backup);
|
||||||
fd = open(hsm_secret_path, O_CREAT|O_EXCL|O_WRONLY, 0400);
|
fd = open(hsm_secret_path, O_CREAT|O_EXCL|O_WRONLY, 0400);
|
||||||
|
@ -276,19 +327,25 @@ static int encrypt_hsm(const char *hsm_secret_path, const char *passwd)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dump_commitments_infos(struct node_id *node_id, u64 channel_id,
|
static int dump_commitments_infos(struct node_id *node_id, u64 channel_id,
|
||||||
u64 depth, char *hsm_secret_path, char *passwd)
|
u64 depth, char *hsm_secret_path)
|
||||||
{
|
{
|
||||||
struct sha256 shaseed;
|
struct sha256 shaseed;
|
||||||
struct secret hsm_secret, channel_seed, per_commitment_secret;
|
struct secret hsm_secret, channel_seed, per_commitment_secret;
|
||||||
struct pubkey per_commitment_point;
|
struct pubkey per_commitment_point;
|
||||||
|
char *passwd;
|
||||||
|
|
||||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
|
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
|
||||||
| SECP256K1_CONTEXT_SIGN);
|
| SECP256K1_CONTEXT_SIGN);
|
||||||
|
|
||||||
if (passwd)
|
/* This checks the file existence, too. */
|
||||||
|
if (hsm_secret_is_encrypted(hsm_secret_path)) {
|
||||||
|
printf("Enter hsm_secret password:\n");
|
||||||
|
passwd = read_stdin_pass();
|
||||||
get_encrypted_hsm_secret(&hsm_secret, hsm_secret_path, passwd);
|
get_encrypted_hsm_secret(&hsm_secret, hsm_secret_path, passwd);
|
||||||
else
|
free(passwd);
|
||||||
|
} else
|
||||||
get_hsm_secret(&hsm_secret, hsm_secret_path);
|
get_hsm_secret(&hsm_secret, hsm_secret_path);
|
||||||
|
|
||||||
get_channel_seed(&channel_seed, node_id, channel_id, &hsm_secret);
|
get_channel_seed(&channel_seed, node_id, channel_id, &hsm_secret);
|
||||||
|
|
||||||
derive_shaseed(&channel_seed, &shaseed);
|
derive_shaseed(&channel_seed, &shaseed);
|
||||||
|
@ -325,9 +382,10 @@ static int dump_commitments_infos(struct node_id *node_id, u64 channel_id,
|
||||||
* :param passwd: The *optional* hsm_secret password
|
* :param passwd: The *optional* hsm_secret password
|
||||||
*/
|
*/
|
||||||
static int guess_to_remote(const char *address, struct node_id *node_id,
|
static int guess_to_remote(const char *address, struct node_id *node_id,
|
||||||
u64 tries, char *hsm_secret_path, char *passwd)
|
u64 tries, char *hsm_secret_path)
|
||||||
{
|
{
|
||||||
struct secret hsm_secret, channel_seed, basepoint_secret;
|
struct secret hsm_secret, channel_seed, basepoint_secret;
|
||||||
|
char *passwd;
|
||||||
struct pubkey basepoint;
|
struct pubkey basepoint;
|
||||||
struct ripemd160 pubkeyhash;
|
struct ripemd160 pubkeyhash;
|
||||||
/* We only support P2WPKH, hence 20. */
|
/* We only support P2WPKH, hence 20. */
|
||||||
|
@ -346,9 +404,13 @@ static int guess_to_remote(const char *address, struct node_id *node_id,
|
||||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
|
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
|
||||||
| SECP256K1_CONTEXT_SIGN);
|
| SECP256K1_CONTEXT_SIGN);
|
||||||
|
|
||||||
if (passwd)
|
/* This checks the file existence, too. */
|
||||||
|
if (hsm_secret_is_encrypted(hsm_secret_path)) {
|
||||||
|
printf("Enter hsm_secret password:\n");
|
||||||
|
passwd = read_stdin_pass();
|
||||||
get_encrypted_hsm_secret(&hsm_secret, hsm_secret_path, passwd);
|
get_encrypted_hsm_secret(&hsm_secret, hsm_secret_path, passwd);
|
||||||
else
|
free(passwd);
|
||||||
|
} else
|
||||||
get_hsm_secret(&hsm_secret, hsm_secret_path);
|
get_hsm_secret(&hsm_secret, hsm_secret_path);
|
||||||
|
|
||||||
for (u64 dbid = 1; dbid < tries ; dbid++) {
|
for (u64 dbid = 1; dbid < tries ; dbid++) {
|
||||||
|
@ -517,10 +579,11 @@ static int generate_hsm(const char *hsm_secret_path)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dumponchaindescriptors(const char *hsm_secret_path, const char *passwd,
|
static int dumponchaindescriptors(const char *hsm_secret_path, const char *old_passwd UNUSED,
|
||||||
const bool is_testnet)
|
const bool is_testnet)
|
||||||
{
|
{
|
||||||
struct secret hsm_secret;
|
struct secret hsm_secret;
|
||||||
|
char *passwd;
|
||||||
u8 bip32_seed[BIP32_ENTROPY_LEN_256];
|
u8 bip32_seed[BIP32_ENTROPY_LEN_256];
|
||||||
u32 salt = 0;
|
u32 salt = 0;
|
||||||
u32 version = is_testnet ?
|
u32 version = is_testnet ?
|
||||||
|
@ -529,9 +592,13 @@ static int dumponchaindescriptors(const char *hsm_secret_path, const char *passw
|
||||||
char *enc_xpub, *descriptor;
|
char *enc_xpub, *descriptor;
|
||||||
struct descriptor_checksum checksum;
|
struct descriptor_checksum checksum;
|
||||||
|
|
||||||
if (passwd)
|
/* This checks the file existence, too. */
|
||||||
|
if (hsm_secret_is_encrypted(hsm_secret_path)) {
|
||||||
|
printf("Enter hsm_secret password:\n");
|
||||||
|
passwd = read_stdin_pass();
|
||||||
get_encrypted_hsm_secret(&hsm_secret, hsm_secret_path, passwd);
|
get_encrypted_hsm_secret(&hsm_secret, hsm_secret_path, passwd);
|
||||||
else
|
free(passwd);
|
||||||
|
} else
|
||||||
get_hsm_secret(&hsm_secret, hsm_secret_path);
|
get_hsm_secret(&hsm_secret, hsm_secret_path);
|
||||||
|
|
||||||
/* We use m/0/0/k as the derivation tree for onchain funds. */
|
/* We use m/0/0/k as the derivation tree for onchain funds. */
|
||||||
|
@ -582,37 +649,37 @@ int main(int argc, char *argv[])
|
||||||
show_usage(argv[0]);
|
show_usage(argv[0]);
|
||||||
|
|
||||||
if (streq(method, "decrypt")) {
|
if (streq(method, "decrypt")) {
|
||||||
if (argc < 4)
|
if (argc < 3)
|
||||||
show_usage(argv[0]);
|
show_usage(argv[0]);
|
||||||
return decrypt_hsm(argv[2], argv[3]);
|
return decrypt_hsm(argv[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(method, "encrypt")) {
|
if (streq(method, "encrypt")) {
|
||||||
if (argc < 4)
|
if (argc < 3)
|
||||||
show_usage(argv[0]);
|
show_usage(argv[0]);
|
||||||
return encrypt_hsm(argv[2], argv[3]);
|
return encrypt_hsm(argv[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(method, "dumpcommitments")) {
|
if (streq(method, "dumpcommitments")) {
|
||||||
/* node_id channel_id depth hsm_secret ?password? */
|
/* node_id channel_id depth hsm_secret */
|
||||||
if (argc < 6)
|
if (argc < 6)
|
||||||
show_usage(argv[0]);
|
show_usage(argv[0]);
|
||||||
struct node_id node_id;
|
struct node_id node_id;
|
||||||
if (!node_id_from_hexstr(argv[2], strlen(argv[2]), &node_id))
|
if (!node_id_from_hexstr(argv[2], strlen(argv[2]), &node_id))
|
||||||
err(ERROR_USAGE, "Bad node id");
|
err(ERROR_USAGE, "Bad node id");
|
||||||
return dump_commitments_infos(&node_id, atol(argv[3]), atol(argv[4]),
|
return dump_commitments_infos(&node_id, atol(argv[3]), atol(argv[4]),
|
||||||
argv[5], argc >= 7 ? argv[6] : NULL);
|
argv[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(method, "guesstoremote")) {
|
if (streq(method, "guesstoremote")) {
|
||||||
/* address node_id depth hsm_secret ?password? */
|
/* address node_id depth hsm_secret */
|
||||||
if (argc < 6)
|
if (argc < 6)
|
||||||
show_usage(argv[0]);
|
show_usage(argv[0]);
|
||||||
struct node_id node_id;
|
struct node_id node_id;
|
||||||
if (!node_id_from_hexstr(argv[3], strlen(argv[3]), &node_id))
|
if (!node_id_from_hexstr(argv[3], strlen(argv[3]), &node_id))
|
||||||
errx(ERROR_USAGE, "Bad node id");
|
errx(ERROR_USAGE, "Bad node id");
|
||||||
return guess_to_remote(argv[2], &node_id, atol(argv[4]),
|
return guess_to_remote(argv[2], &node_id, atol(argv[4]),
|
||||||
argv[5], argc >= 7 ? argv[6] : NULL);
|
argv[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(method, "generatehsm")) {
|
if (streq(method, "generatehsm")) {
|
||||||
|
@ -631,23 +698,30 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(method, "dumponchaindescriptors")) {
|
if (streq(method, "dumponchaindescriptors")) {
|
||||||
|
char *net = NULL;
|
||||||
bool is_testnet;
|
bool is_testnet;
|
||||||
|
|
||||||
if (argc < 3)
|
if (argc < 3)
|
||||||
show_usage(argv[0]);
|
show_usage(argv[0]);
|
||||||
|
|
||||||
if (argc > 4) {
|
if (argc > 3)
|
||||||
is_testnet = streq(argv[4], "testnet");
|
net = argv[3];
|
||||||
if (!is_testnet && !streq(argv[4], "bitcoin"))
|
/* Previously, we accepted hsm_secret passwords on the command line.
|
||||||
|
* This shifted the location of the network parameter.
|
||||||
|
* TODO: remove this 3 releases after v0.9.3 */
|
||||||
|
if (deprecated_apis && argc > 4)
|
||||||
|
net = argv[4];
|
||||||
|
|
||||||
|
if (streq(net, "testnet"))
|
||||||
|
is_testnet = true;
|
||||||
|
else if (!streq(net, "bitcoin"))
|
||||||
errx(ERROR_USAGE, "Network '%s' not supported."
|
errx(ERROR_USAGE, "Network '%s' not supported."
|
||||||
" Supported networks: bitcoin (default),"
|
" Supported networks: bitcoin (default),"
|
||||||
" testnet",
|
" testnet", net);
|
||||||
argv[4]);
|
else
|
||||||
} else
|
|
||||||
is_testnet = false;
|
is_testnet = false;
|
||||||
|
|
||||||
return dumponchaindescriptors(argv[2],
|
return dumponchaindescriptors(argv[2], NULL, is_testnet);
|
||||||
argc > 3 && !streq(argv[3], "") ? argv[3] : NULL,
|
|
||||||
is_testnet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
show_usage(argv[0]);
|
show_usage(argv[0]);
|
||||||
|
|
Loading…
Add table
Reference in a new issue