lightning: confirm password on hsm_secret encryption

Changelog-changed: lightningd: the `--encrypted-hsm` now asks you to confirm your password when first set
Changelog-changed: hsmtool: the `encrypt` now asks you to confirm your password
Signed-off-by: Antoine Poinsot <darosior@protonmail.com>
This commit is contained in:
Antoine Poinsot 2021-01-03 01:40:42 +01:00 committed by Christian Decker
parent 38204f9b6d
commit 56c223886c
3 changed files with 31 additions and 8 deletions

View File

@ -388,7 +388,7 @@ static char *opt_important_plugin(const char *arg, struct lightningd *ld)
static char *opt_set_hsm_password(struct lightningd *ld)
{
struct termios current_term, temp_term;
char *passwd = NULL;
char *passwd = NULL, *passwd_confirmation = NULL;
size_t passwd_size = 0;
u8 salt[16] = "c-lightning\0\0\0\0\0";
ld->encrypted_hsm = true;
@ -408,12 +408,18 @@ static char *opt_set_hsm_password(struct lightningd *ld)
return "Could not disable password echoing.";
printf("The hsm_secret is encrypted with a password. In order to "
"decrypt it and start the node you must provide the password.\n");
printf("Enter hsm_secret password: ");
printf("Enter hsm_secret password:\n");
/* 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)
return "Could not read password from stdin.";
printf("Confirm hsm_secret password:\n");
fflush(stdout);
if (getline(&passwd_confirmation, &passwd_size, stdin) < 0)
return "Could not read password confirmation from stdin.";
if (!streq(passwd, passwd_confirmation))
return "Password confirmation mismatch.";
if (passwd[strlen(passwd) - 1] == '\n')
passwd[strlen(passwd) - 1] = '\0';
if (tcsetattr(fileno(stdin), TCSAFLUSH, &current_term) != 0)
@ -434,6 +440,7 @@ static char *opt_set_hsm_password(struct lightningd *ld)
crypto_pwhash_ALG_ARGON2ID13) != 0)
return "Could not derive a key from the password.";
free(passwd);
free(passwd_confirmation);
return NULL;
}

View File

@ -956,8 +956,9 @@ def test_hsm_secret_encryption(node_factory):
l1.stop()
l1.daemon.opts.update({"encrypted-hsm": None})
l1.daemon.start(stdin=slave_fd, wait_for_initialized=False)
l1.daemon.wait_for_log(r'The hsm_secret is encrypted')
l1.daemon.wait_for_log(r'Enter hsm_secret password')
os.write(master_fd, password.encode("utf-8"))
l1.daemon.wait_for_log(r'Confirm hsm_secret password')
os.write(master_fd, password.encode("utf-8"))
l1.daemon.wait_for_log("Server started with public key")
id = l1.rpc.getinfo()["id"]
@ -972,7 +973,9 @@ def test_hsm_secret_encryption(node_factory):
l1.daemon.opts.update({"encrypted-hsm": None})
l1.daemon.start(stdin=slave_fd, stderr=subprocess.STDOUT,
wait_for_initialized=False)
l1.daemon.wait_for_log(r'The hsm_secret is encrypted')
l1.daemon.wait_for_log(r'Enter hsm_secret password')
os.write(master_fd, password[2:].encode("utf-8"))
l1.daemon.wait_for_log(r'Confirm hsm_secret password')
os.write(master_fd, password[2:].encode("utf-8"))
assert(l1.daemon.proc.wait() == 1)
assert(l1.daemon.is_in_log("Wrong password for encrypted hsm_secret."))
@ -981,6 +984,8 @@ def test_hsm_secret_encryption(node_factory):
l1.daemon.start(stdin=slave_fd, wait_for_initialized=False)
l1.daemon.wait_for_log(r'The hsm_secret is encrypted')
os.write(master_fd, password.encode("utf-8"))
l1.daemon.wait_for_log(r'Confirm hsm_secret password')
os.write(master_fd, password.encode("utf-8"))
l1.daemon.wait_for_log("Server started with public key")
assert id == l1.rpc.getinfo()["id"]
@ -1005,7 +1010,9 @@ def test_hsmtool_secret_decryption(node_factory):
l1.stop()
l1.daemon.opts.update({"encrypted-hsm": None})
l1.daemon.start(stdin=slave_fd, wait_for_initialized=False)
l1.daemon.wait_for_log(r'The hsm_secret is encrypted')
l1.daemon.wait_for_log(r'Enter hsm_secret password')
os.write(master_fd, password.encode("utf-8"))
l1.daemon.wait_for_log(r'Confirm hsm_secret password')
os.write(master_fd, password.encode("utf-8"))
l1.daemon.wait_for_log("Server started with public key")
node_id = l1.rpc.getinfo()["id"]
@ -1038,6 +1045,8 @@ def test_hsmtool_secret_decryption(node_factory):
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
hsmtool.wait_for_log(r"Enter hsm_secret password:")
os.write(master_fd, password.encode("utf-8"))
hsmtool.wait_for_log(r"Confirm 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
l1.stop()
@ -1051,6 +1060,8 @@ def test_hsmtool_secret_decryption(node_factory):
l1.daemon.wait_for_log(r'The hsm_secret is encrypted')
os.write(master_fd, password.encode("utf-8"))
l1.daemon.wait_for_log(r'Confirm hsm_secret password')
os.write(master_fd, password.encode("utf-8"))
l1.daemon.wait_for_log("Server started with public key")
print(node_id, l1.rpc.getinfo()["id"])
assert node_id == l1.rpc.getinfo()["id"]

View File

@ -253,7 +253,7 @@ static int encrypt_hsm(const char *hsm_secret_path)
{
int fd;
struct secret key, hsm_secret;
char *passwd;
char *passwd, *passwd_confirmation;
u8 salt[16] = "c-lightning\0\0\0\0\0";
crypto_secretstream_xchacha20poly1305_state crypto_state;
u8 header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
@ -266,8 +266,11 @@ static int encrypt_hsm(const char *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();
printf("Confirm hsm_secret password:\n");
passwd_confirmation = read_stdin_pass();
if (!streq(passwd, passwd_confirmation))
errx(ERROR_USAGE, "Passwords confirmation mismatch.");
get_hsm_secret(&hsm_secret, hsm_secret_path);
dir = path_dirname(NULL, hsm_secret_path);
@ -296,6 +299,8 @@ static int encrypt_hsm(const char *hsm_secret_path)
/* Once the encryption key derived, we don't need it anymore. */
if (passwd)
free(passwd);
if (passwd_confirmation)
free(passwd_confirmation);
/* Create a backup file, "just in case". */
rename(hsm_secret_path, backup);