diff --git a/doc/lightningd-config.5 b/doc/lightningd-config.5 index b87ed245f..8292a2541 100644 --- a/doc/lightningd-config.5 +++ b/doc/lightningd-config.5 @@ -155,6 +155,12 @@ Identify the location of the wallet\. This is a fully qualified data source name, including a scheme such as \fBsqlite3\fR or \fBpostgres\fR followed by the connection parameters\. + + \fBencrypted-hsm\fR +If set, you will be prompted to enter a password used to encrypt the \fBhsm_secret\fR\. +Note that once you encrypt the \fBhsm_secret\fR this option will be mandatory for +\fBlightningd\fR to start\. + .SH Lightning node customization options \fBalias\fR=\fIRRGGBB\fR @@ -374,12 +380,15 @@ Always use the \fBproxy\fR, even to connect to normal IP addresses (you can still connect to Unix domain sockets manually)\. This also disables all DNS lookups, to avoid leaking information\. + \fBdisable-dns\fR Disable the DNS bootstrapping mechanism to find a node by its node ID\. + \fBenable-autotor-v2-mode\fR Try to get a v2 onion address from the Tor service call, default is v3\. + \fBtor-service-password\fR=\fIPASSWORD\fR Set a Tor control password, which may be needed for \fIautotor:\fR to authenticate to the Tor control port\. diff --git a/doc/lightningd-config.5.md b/doc/lightningd-config.5.md index 68033b6cf..4d0b14e5d 100644 --- a/doc/lightningd-config.5.md +++ b/doc/lightningd-config.5.md @@ -133,6 +133,11 @@ Identify the location of the wallet. This is a fully qualified data source name, including a scheme such as `sqlite3` or `postgres` followed by the connection parameters. + **encrypted-hsm** +If set, you will be prompted to enter a password used to encrypt the `hsm_secret`. +Note that once you encrypt the `hsm_secret` this option will be mandatory for +`lightningd` to start. + ### Lightning node customization options **alias**=*RRGGBB* diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index bb45b955f..4ef9e5197 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -234,6 +234,11 @@ static struct lightningd *new_lightningd(const tal_t *ctx) /*~ This is set when a JSON RPC command comes in to shut us down. */ ld->stop_conn = NULL; + /*~ This is used to signal that `hsm_secret` is encrypted, and will + * be set to `true` if the `--encrypted` option is passed at startup. + */ + ld->encrypted_hsm = false; + return ld; } diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index 5154a2807..084f1901c 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -71,6 +71,8 @@ struct config { /* Allow to define the default behavior of tot services calls*/ bool use_v3_autotor; + /* This is the key we use to encrypt `hsm_secret`. */ + struct secret *keypass; }; struct lightningd { @@ -235,6 +237,8 @@ struct lightningd { struct plugins *plugins; char *wallet_dsn; + + bool encrypted_hsm; }; /* Turning this on allows a tal allocation to return NULL, rather than aborting. diff --git a/lightningd/options.c b/lightningd/options.c index f876bd76c..f4112239c 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -32,12 +32,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -366,6 +368,58 @@ static char *opt_clear_plugins(struct lightningd *ld) return NULL; } +/* Prompt the user to enter a password, from which will be derived the key used + * for `hsm_secret` encryption. + * The algorithm used to derive the key is Argon2(id), to which libsodium + * defaults. However argon2id-specific constants are used in case someone runs it + * with a libsodium version which default constants differs (typically <1.0.9). + */ +static char *opt_set_hsm_password(struct lightningd *ld) +{ + struct termios current_term, temp_term; + char *passwd = NULL; + size_t passwd_size = 0; + u8 salt[11] = "c-lightning"; + ld->encrypted_hsm = true; + + ld->config.keypass = tal(NULL, struct secret); + /* Don't swap the encryption key ! */ + if (sodium_mlock(ld->config.keypass->data, + sizeof(ld->config.keypass->data)) != 0) + return "Could not lock hsm_secret encryption key memory."; + + /* Get the password from stdin, but don't echo it. */ + if (tcgetattr(fileno(stdin), ¤t_term) != 0) + return "Could not get current terminal options."; + temp_term = current_term; + temp_term.c_lflag &= ~ECHO; + if (tcsetattr(fileno(stdin), TCSAFLUSH, &temp_term) != 0) + return "Could not disable password echoing."; + printf("Enter hsm_secret password : "); + if (getline(&passwd, &passwd_size, stdin) < 0) + return "Could not read password from stdin."; + if (tcsetattr(fileno(stdin), TCSAFLUSH, ¤t_term) != 0) + return "Could not restore terminal options."; + printf("\n"); + + /* Derive the key from the password. */ + if (strlen(passwd) < crypto_pwhash_argon2id_PASSWD_MIN) + return "Password too short to be able to derive a key from it."; + if (strlen(passwd) > crypto_pwhash_argon2id_PASSWD_MAX) + return "Password too long to be able to derive a key from it."; + if (crypto_pwhash(ld->config.keypass->data, sizeof(ld->config.keypass->data), + passwd, strlen(passwd), salt, + /* INTERACTIVE needs 64 MiB of RAM, MODERATE needs 256, + * and SENSITIVE needs 1024. */ + crypto_pwhash_argon2id_OPSLIMIT_MODERATE, + crypto_pwhash_argon2id_MEMLIMIT_MODERATE, + crypto_pwhash_ALG_ARGON2ID13) != 0) + return "Could not derive a key from the password."; + free(passwd); + + return NULL; +} + #if DEVELOPER static char *opt_subprocess_debug(const char *optarg, struct lightningd *ld) { @@ -1029,6 +1083,10 @@ static void register_opts(struct lightningd *ld) opt_register_noarg("--enable-autotor-v2-mode", opt_set_invbool, &ld->config.use_v3_autotor, "Try to get a v2 onion address from the Tor service call, default is v3"); + opt_register_noarg("--encrypted-hsm", opt_set_hsm_password, ld, + "Set the password to encrypt hsm_secret with. If no password is passed through command line, " + "you will be prompted to enter it."); + opt_register_logging(ld); opt_register_version(); @@ -1215,6 +1273,8 @@ static void add_config(struct lightningd *ld, answer = tal_fmt(name0, "%s", ld->daemon_parent_fd == -1 ? "false" : "true"); + } else if (opt->cb == (void *)opt_set_hsm_password) { + json_add_bool(response, "encrypted-hsm", ld->encrypted_hsm); } else { /* Insert more decodes here! */ assert(!"A noarg option was added but was not handled");