-
Notifications
You must be signed in to change notification settings - Fork 905
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
hsm_secret encryption #3129
hsm_secret encryption #3129
Conversation
f9731da
to
5dc55aa
Compare
Rebased and added handling for non-encrypted to encrypted hsm. Still need to polish the tests and add the doc. |
a1509a3
to
4a06029
Compare
Rebased, added tests and doc, edited OP. Removing WIP. |
854a1d1
to
4e3db08
Compare
Rebased, increase |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like the idea, but minor changes needed before we can get this into -rc1 under @niftynei 's nose :)
* an error message. */ | ||
exit(1); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... else?
If it's encrypted, and they don't provide the key? [Edit: ah, fixed in next commit!]
Or if it's not, and they do? Or if it's been truncated to 31 bytes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... else?
Otherwise we are done, close the fd and populate the secretstuff.
[Edit: ah, fixed in next commit!]
I could have squashed this one ^^ (but the diff was becoming too big and sparse)
Or if it's not, and they do?
Then we load the seed, delete the hsm_secret
and call create_encrypted_hsm_secret()
.
Or if it's been truncated to 31 bytes?
Could it be ? Anyway the encrypted seed is always > 32 so I can make the condition a <=
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's encrypted, and they don't provide the key? [Edit: ah, fixed in next commit!]
As a side note I handle this in hsm_control
because I was not able to get satus_failed
(with a new failure type) to send an error before replying to init
. The msg type would always be zero. Hence also the hacky "wrong password" case handling.
4e3db08
to
e48692f
Compare
Thanks for the review! |
e48692f
to
95f3be4
Compare
Hmm looks like there is a travis cache problem: the |
afaict there's no cache for branch 3129 on Travis |
Ok, thanks for checking. |
419aa7f
to
7fcbf3d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
And you can also add two more functions in the future:
- Change the passwaord:
Ask user to enter the old password, if it is valid then ask user to enter a new password. - Unencrypt:
Ask user to enter the old password, if it is valid then decrypt the secret and don't encrypt it again.
* not start if it cannot do its job correctly. */ | ||
if (sodium_init() == -1) | ||
errx(1, "Could not initialize libsodium. Maybe not enough entropy" | ||
" available ?"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only a question: What does this("not enough entropy") mean? It means the machine can't run clightning
forever?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No it means that, in this rare case (maybe just after booting), the machine does not have enough source of randomness. https://en.wikipedia.org/wiki/Entropy_(computing)
printf("\n"); | ||
|
||
/* Derive the key from the password. */ | ||
if (strlen(passwd) < crypto_pwhash_argon2id_PASSWD_MIN) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will the length of the password and the complexity of the password affect the encryption?
Should we limit minimum length?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is limited actually in lightningd/options.c
, but the limit is set to 0 by the library.
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."; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'd better ask users to enter the password twice and check the consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If two passwords are different, users must repeat this setting process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And if user enter enter
or null
, this process will be cancelled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The decryption is done in hsmd
, and I think it's better to keep it that way so that only one daemon interacts with hsm_secret
. In case of a wrong password, an user can still arrow_up
then enter
:-).
And if user enter enter or null, this process will be cancelled?
If null
is not its password then yes..:
@@ -102,6 +102,8 @@ Once you've started for the first time, there's a script called | |||
`contrib/bootstrap-node.sh` which will connect you to other nodes on | |||
the lightning network. | |||
|
|||
You can encrypt the BIP32 root seed (what is stored in `hsm_secret`) by passing the `--encrypted-hsm` startup argument. You can start `lightningd` with `--encrypted-hsm` on an already existing `lightning-dir` (with a not encrypted `hsm_secret`). If you pass that option, you __will not__ be able to start `lightningd` (with the same wallet) again without the password, so please beware with your password management. Also beware of not feeling too safe with an encrypted `hsm_secret`: unlike for `bitcoind` where the wallet encryption can restrict the usage of some RPC command, `lightningd` always need to access keys from the wallet which is thus __not locked__ (yet), even with an encrypted BIP32 master seed. | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think here we can also remind users like the sentence "Note if the password or hsm_secret losts, you WILL lost all your funds forever. MUST take good care of your hsm_secret
file and its password."
I thought about making a tool to unencrypt |
According to the doc (https://download.libsodium.org/doc): "sodium_init() initializes the library and should be called before any other function provided by Sodium. [...] the function ensures that the system's random number generator has been properly seeded.".
Add a new startup option which will, if set, prompt the user for a password to derive a key from. This key will later be used to encrypt and/or decrypt `hsm_secret`. This was made a noarg option even if it would have been preferable to let the user the choice of how to specify the password. Since we have to chose, better to not let the password in the commands history.
This splits maybe_create_hsm_secret() in two parts (either encrypted or in clear) for clarity, and adds an encryption detection in load_hsm(). There are actually three cases if an encryption key is passed: - There is no hsm_secret => just create it and store the encrypted seed - There is an encrypted hsm_secret => the provided key should be able to decrypt the seed, if the wrong key is passed libsodium will nicely error and hsmd will exit() to not throw a backtrace (using status_failed() as for other errors) at the face of an user who mistyped its password. - There is a non-encrypted hsm_secret => load the seed, delete the hsm_secret, create the hsm_secret, store the encrypted seed.
And also allow to not wait for it to be started. Passing stderr=subprocess.STDOUT can be useful to wait_for_log() also on stderr messages.
7fcbf3d
to
e1af450
Compare
Trivial rebase. |
Ack e1af450 Once Travis is happy, I'll merge. |
This adds a new startup option which allows one to encrypt its
hsm_secret
, bearer of all its secrets. This uses the already-included (and amazing!)libsodium
with defaults (i.e. Argon2id for deriving a key out of the provided password, and XChacha20_Poly1305 for stream encryption).This and #2925 put, I think, the basis to have wallet locking. A plugin using the
rpc_command
hook to restrict the use of some RPC commands against a password, which can easily be bypassed if [it /lightningd
] is killed, but not with an encryptedhsm_secret
.