12
12
#include <ccan/io/fdpass/fdpass.h>
13
13
#include <ccan/noerr/noerr.h>
14
14
#include <ccan/read_write_all/read_write_all.h>
15
+ #include <ccan/tal/grab_file/grab_file.h>
15
16
#include <ccan/tal/str/str.h>
16
17
#include <common/daemon_conn.h>
17
- #include <common/hsm_encryption .h>
18
+ #include <common/hsm_secret .h>
18
19
#include <common/memleak.h>
19
20
#include <common/status.h>
20
21
#include <common/status_wiregen.h>
21
22
#include <common/subdaemon.h>
22
23
#include <errno.h>
23
24
#include <fcntl.h>
25
+ #include <stdarg.h>
24
26
/*~ _wiregen files are autogenerated by tools/generate-wire.py */
25
27
#include <hsmd/libhsmd.h>
26
28
#include <hsmd/permissions.h>
27
29
#include <sys/socket.h>
28
30
#include <sys/stat.h>
31
+ #include <wally_bip39.h>
29
32
#include <wire/wire_io.h>
30
33
31
34
/*~ Each subdaemon is started with stdin connected to lightningd (for status
35
38
#define REQ_FD 3
36
39
37
40
/* Temporary storage for the secret until we pass it to `hsmd_init` */
38
- struct secret hsm_secret ;
41
+ struct hsm_secret hsm_secret ;
39
42
40
43
/*~ We keep track of clients, but there's not much to keep. */
41
44
struct client {
@@ -270,66 +273,138 @@ static struct io_plan *req_reply(struct io_conn *conn,
270
273
return io_write_wire (conn , msg_out , client_read_next , c );
271
274
}
272
275
273
- /*~ This encrypts the content of the `struct secret hsm_secret` and
274
- * stores it in hsm_secret, this is called instead of create_hsm() if
275
- * `lightningd` is started with --encrypted-hsm.
276
- */
277
- static void create_encrypted_hsm (int fd , const struct secret * encryption_key )
276
+ /* Send an init reply failure message to lightningd and then call status_failed */
277
+ static void hsmd_send_init_reply_failure (enum hsm_secret_error error_code , enum status_failreason reason , const char * error_msg , ...)
278
278
{
279
- struct encrypted_hsm_secret cipher ;
280
-
281
- if (!encrypt_hsm_secret (encryption_key , & hsm_secret ,
282
- & cipher ))
283
- status_failed (STATUS_FAIL_INTERNAL_ERROR ,
284
- "Encrypting hsm_secret" );
285
- if (!write_all (fd , cipher .data , ENCRYPTED_HSM_SECRET_LEN )) {
286
- unlink_noerr ("hsm_secret" );
287
- status_failed (STATUS_FAIL_INTERNAL_ERROR ,
288
- "Writing encrypted hsm_secret: %s" , strerror (errno ));
279
+ u8 * msg ;
280
+ va_list ap ;
281
+ char * formatted_msg ;
282
+
283
+ va_start (ap , error_msg );
284
+ formatted_msg = tal_vfmt (tmpctx , error_msg , ap );
285
+ va_end (ap );
286
+
287
+ /* Send the init reply failure first */
288
+ msg = towire_hsmd_init_reply_failure (NULL , error_code , formatted_msg );
289
+ if (msg ) {
290
+ /* Send directly to lightningd via REQ_FD */
291
+ write_all (REQ_FD , msg , tal_bytelen (msg ));
292
+ tal_free (msg );
289
293
}
294
+
295
+ /* Then call status_failed with the error message */
296
+ status_failed (reason , "%s" , formatted_msg );
290
297
}
291
298
292
- static void create_hsm (int fd )
299
+ static void create_hsm (int fd , const char * passphrase )
293
300
{
294
- /*~ ccan/read_write_all has a more convenient return than write() where
295
- * we'd have to check the return value == the length we gave: write()
296
- * can return short on normal files if we run out of disk space. */
297
- if (!write_all (fd , & hsm_secret , sizeof (hsm_secret ))) {
298
- /* ccan/noerr contains useful routines like this, which don't
299
- * clobber errno, so we can use it in our error report. */
301
+ u8 * hsm_secret_data ;
302
+ size_t hsm_secret_len ;
303
+ int ret ;
304
+ /* Always create a mnemonic-based hsm_secret */
305
+ u8 entropy [BIP39_ENTROPY_LEN_128 ];
306
+ char * mnemonic = NULL ;
307
+ struct sha256 seed_hash ;
308
+
309
+ status_debug ("HSM: Starting create_hsm with passphrase=%s" , passphrase ? "provided" : "none" );
310
+
311
+ /* Initialize wally tal context for libwally operations */
312
+
313
+ status_debug ("HSM: Initialized wally tal context" );
314
+
315
+ /* Generate random entropy for new mnemonic */
316
+ randombytes_buf (entropy , sizeof (entropy ));
317
+ status_debug ("HSM: Generated random entropy" );
318
+
319
+
320
+ /* Generate mnemonic from entropy */
321
+ tal_wally_start ();
322
+ ret = bip39_mnemonic_from_bytes (NULL , entropy , sizeof (entropy ), & mnemonic );
323
+ tal_wally_end (tmpctx );
324
+
325
+ if (ret != WALLY_OK ) {
326
+ unlink_noerr ("hsm_secret" );
327
+ hsmd_send_init_reply_failure (HSM_SECRET_ERR_SEED_DERIVATION_FAILED , STATUS_FAIL_INTERNAL_ERROR ,
328
+ "Failed to generate mnemonic from entropy" );
329
+ }
330
+ status_debug ("HSM: Generated mnemonic from entropy" );
331
+
332
+ if (!mnemonic ) {
333
+ unlink_noerr ("hsm_secret" );
334
+ hsmd_send_init_reply_failure (HSM_SECRET_ERR_SEED_DERIVATION_FAILED , STATUS_FAIL_INTERNAL_ERROR ,
335
+ "Failed to get generated mnemonic" );
336
+ }
337
+
338
+ /* Derive seed hash from mnemonic + passphrase (or zero if no passphrase) */
339
+ if (!derive_seed_hash (mnemonic , passphrase , & seed_hash )) {
340
+ unlink_noerr ("hsm_secret" );
341
+ hsmd_send_init_reply_failure (HSM_SECRET_ERR_SEED_DERIVATION_FAILED , STATUS_FAIL_INTERNAL_ERROR ,
342
+ "Failed to derive seed hash from mnemonic" );
343
+ }
344
+ status_debug ("HSM: Derived seed hash from mnemonic" );
345
+
346
+ /* Create hsm_secret format: seed_hash (32 bytes) + mnemonic */
347
+ hsm_secret_len = PASSPHRASE_HASH_LEN + strlen (mnemonic );
348
+ hsm_secret_data = tal_arr (tmpctx , u8 , hsm_secret_len );
349
+
350
+ /* Copy seed hash first */
351
+ memcpy (hsm_secret_data , & seed_hash , PASSPHRASE_HASH_LEN );
352
+ /* Copy mnemonic after seed hash */
353
+ memcpy (hsm_secret_data + PASSPHRASE_HASH_LEN , mnemonic , strlen (mnemonic ));
354
+ status_debug ("HSM: Created hsm_secret data structure" );
355
+
356
+ /* Derive the actual secret from mnemonic + passphrase for our global hsm_secret */
357
+ u8 bip32_seed [BIP39_SEED_LEN_512 ];
358
+ size_t bip32_seed_len ;
359
+
360
+ tal_wally_start ();
361
+ ret = bip39_mnemonic_to_seed (mnemonic , passphrase , bip32_seed , sizeof (bip32_seed ), & bip32_seed_len );
362
+ tal_wally_end (tmpctx );
363
+ if (ret != WALLY_OK ) {
364
+ unlink_noerr ("hsm_secret" );
365
+ hsmd_send_init_reply_failure (HSM_SECRET_ERR_SEED_DERIVATION_FAILED , STATUS_FAIL_INTERNAL_ERROR ,
366
+ "Failed to derive seed from mnemonic" );
367
+ }
368
+ status_debug ("HSM: Derived BIP32 seed from mnemonic" );
369
+
370
+ /* Use first 32 bytes for hsm_secret */
371
+ memcpy (& hsm_secret .secret , bip32_seed , sizeof (hsm_secret .secret ));
372
+
373
+ /* Write the hsm_secret data to file */
374
+ if (!write_all (fd , hsm_secret_data , hsm_secret_len )) {
300
375
unlink_noerr ("hsm_secret" );
301
376
status_failed (STATUS_FAIL_INTERNAL_ERROR ,
302
377
"writing: %s" , strerror (errno ));
303
378
}
379
+ status_debug ("HSM: Successfully wrote hsm_secret to file" );
304
380
}
305
381
306
382
/*~ We store our root secret in a "hsm_secret" file (like all of Core Lightning,
307
- * we run in the user's .lightning directory). */
308
- static void maybe_create_new_hsm (const struct secret * encryption_key ,
309
- bool random_hsm )
383
+ * we run in the user's .lightning directory).
384
+ *
385
+ * NOTE: This function no longer creates encrypted 32-byte secrets. New hsm_secret
386
+ * files will use mnemonic format with passphrases.
387
+ */
388
+ static void maybe_create_new_hsm (const char * passphrase )
310
389
{
311
390
/*~ Note that this is opened for write-only, even though the permissions
312
391
* are set to read-only. That's perfectly valid! */
313
392
int fd = open ("hsm_secret" , O_CREAT |O_EXCL |O_WRONLY , 0400 );
314
393
if (fd < 0 ) {
315
394
/* If this is not the first time we've run, it will exist. */
316
- if (errno == EEXIST )
395
+ if (errno == EEXIST ) {
396
+ status_debug ("HSM: hsm_secret file already exists, skipping creation" );
317
397
return ;
398
+ }
318
399
status_failed (STATUS_FAIL_INTERNAL_ERROR ,
319
400
"creating: %s" , strerror (errno ));
320
401
}
321
402
322
- /*~ This is libsodium's cryptographic randomness routine: we assume
323
- * it's doing a good job. */
324
- if (random_hsm )
325
- randombytes_buf (& hsm_secret , sizeof (hsm_secret ));
326
-
327
- /*~ If an encryption_key was provided, store an encrypted seed. */
328
- if (encryption_key )
329
- create_encrypted_hsm (fd , encryption_key );
330
- /*~ Otherwise store the seed in clear.. */
331
- else
332
- create_hsm (fd );
403
+ status_debug ("HSM: Creating new hsm_secret file" );
404
+
405
+ /*~ Store the seed in clear. New hsm_secret files will use mnemonic format
406
+ * with passphrases, not encrypted 32-byte secrets. */
407
+ create_hsm (fd , passphrase );
333
408
/*~ fsync (mostly!) ensures that the file has reached the disk. */
334
409
if (fsync (fd ) != 0 ) {
335
410
unlink_noerr ("hsm_secret" );
@@ -367,62 +442,36 @@ static void maybe_create_new_hsm(const struct secret *encryption_key,
367
442
/*~ We always load the HSM file, even if we just created it above. This
368
443
* both unifies the code paths, and provides a nice sanity check that the
369
444
* file contents are as they will be for future invocations. */
370
- static void load_hsm (const struct secret * encryption_key )
445
+ static void load_hsm (const char * passphrase )
371
446
{
372
- struct stat st ;
373
- int fd = open ("hsm_secret" , O_RDONLY );
374
- if (fd < 0 )
375
- status_failed (STATUS_FAIL_INTERNAL_ERROR ,
376
- "opening: %s" , strerror (errno ));
377
- if (stat ("hsm_secret" , & st ) != 0 )
378
- status_failed (STATUS_FAIL_INTERNAL_ERROR ,
379
- "stating: %s" , strerror (errno ));
380
-
381
- /* If the seed is stored in clear. */
382
- if (st .st_size == 32 ) {
383
- if (!read_all (fd , & hsm_secret , sizeof (hsm_secret )))
384
- status_failed (STATUS_FAIL_INTERNAL_ERROR ,
385
- "reading: %s" , strerror (errno ));
386
- /* If an encryption key was passed with a not yet encrypted hsm_secret,
387
- * remove the old one and create an encrypted one. */
388
- if (encryption_key ) {
389
- if (close (fd ) != 0 )
390
- status_failed (STATUS_FAIL_INTERNAL_ERROR ,
391
- "closing: %s" , strerror (errno ));
392
- if (remove ("hsm_secret" ) != 0 )
393
- status_failed (STATUS_FAIL_INTERNAL_ERROR ,
394
- "removing clear hsm_secret: %s" , strerror (errno ));
395
- maybe_create_new_hsm (encryption_key , false);
396
- fd = open ("hsm_secret" , O_RDONLY );
397
- if (fd < 0 )
398
- status_failed (STATUS_FAIL_INTERNAL_ERROR ,
399
- "opening: %s" , strerror (errno ));
400
- }
447
+ u8 * hsm_secret_contents ;
448
+ struct hsm_secret * hsms ;
449
+ enum hsm_secret_error err ;
450
+
451
+ /* Read the hsm_secret file */
452
+ hsm_secret_contents = grab_file (tmpctx , "hsm_secret" );
453
+ if (!hsm_secret_contents ) {
454
+ hsmd_send_init_reply_failure (HSM_SECRET_ERR_INVALID_FORMAT , STATUS_FAIL_INTERNAL_ERROR ,
455
+ "Could not read hsm_secret: %s" , strerror (errno ));
401
456
}
402
- /* If an encryption key was passed and the `hsm_secret` is stored
403
- * encrypted, recover the seed from the cipher. */
404
- else if (st .st_size == ENCRYPTED_HSM_SECRET_LEN ) {
405
- struct encrypted_hsm_secret encrypted_secret ;
406
457
407
- /* hsm_control must have checked it! */
408
- assert ( encryption_key );
409
-
410
- if (! read_all ( fd , encrypted_secret . data , ENCRYPTED_HSM_SECRET_LEN ))
411
- status_failed ( STATUS_FAIL_INTERNAL_ERROR ,
412
- "Reading encrypted hsm_secret: %s" , strerror ( errno ));
413
- if (! decrypt_hsm_secret ( encryption_key , & encrypted_secret ,
414
- & hsm_secret )) {
415
- /* Exit but don't throw a backtrace when the user made a mistake in typing
416
- * its password. Instead exit and `lightningd` will be able to give
417
- * an error message. */
418
- exit ( 1 );
419
- }
458
+ /* Remove the NUL terminator that grab_file adds */
459
+ tal_resize ( & hsm_secret_contents , tal_bytelen ( hsm_secret_contents ) - 1 );
460
+
461
+ /* Extract the secret using the new hsm_secret module */
462
+ tal_wally_start ();
463
+ hsms = extract_hsm_secret ( tmpctx , hsm_secret_contents ,
464
+ tal_bytelen ( hsm_secret_contents ) ,
465
+ passphrase , & err );
466
+ tal_wally_end ( tmpctx );
467
+ if (! hsms ) {
468
+ status_debug ( "HSM: Failed to load hsm_secret: %s" , hsm_secret_error_str ( err ));
469
+ hsmd_send_init_reply_failure ( err , STATUS_FAIL_INTERNAL_ERROR ,
470
+ "Failed to load hsm_secret: %s" , hsm_secret_error_str ( err ));
420
471
}
421
- else
422
- status_failed (STATUS_FAIL_INTERNAL_ERROR , "Invalid hsm_secret, "
423
- "no plaintext nor encrypted"
424
- " seed." );
425
- close (fd );
472
+
473
+ /* Copy the extracted secret to our global hsm_secret */
474
+ memcpy (& hsm_secret , & hsms -> secret , sizeof (hsm_secret ));
426
475
}
427
476
428
477
/*~ We have a pre-init call in developer mode, to set dev flags */
@@ -458,6 +507,7 @@ static struct io_plan *init_hsm(struct io_conn *conn,
458
507
const u8 * msg_in )
459
508
{
460
509
struct secret * hsm_encryption_key ;
510
+ const char * hsm_passphrase ;
461
511
struct bip32_key_version bip32_key_version ;
462
512
u32 minversion , maxversion ;
463
513
const u32 our_minversion = 4 , our_maxversion = 6 ;
@@ -494,27 +544,13 @@ static struct io_plan *init_hsm(struct io_conn *conn,
494
544
* think this is some kind of obscure CLN hazing ritual? Anyway, the
495
545
* passphrase needs to be *appended* to the mnemonic, so the HSM needs
496
546
* the raw passphrase. To avoid a compatibility break, I put it inside
497
- * the TLV, and left the old "hsm_encryption_key" field in place, even
498
- * though we override it here for the old-style non-BIP39 hsm_secret. */
499
- if (tlvs -> hsm_passphrase ) {
500
- const char * hsm_passphrase = (const char * )tlvs -> hsm_passphrase ;
501
- const char * err_msg ;
502
-
503
- hsm_encryption_key = tal (NULL , struct secret );
504
- if (hsm_secret_encryption_key_with_exitcode (hsm_passphrase , hsm_encryption_key , & err_msg ) != 0 )
505
- return bad_req_fmt (conn , c , msg_in ,
506
- "Bad passphrase: %s" , err_msg );
507
- }
508
- tal_free (tlvs );
547
+ * the TLV, and left the old "hsm_encryption_key" field in place (and lightningd
548
+ * never sets that anymore), and we use the TLV instead. */
549
+ if (tlvs -> hsm_passphrase )
550
+ hsm_passphrase = (const char * )tlvs -> hsm_passphrase ;
509
551
510
- /*~ The memory is actually copied in towire(), so lock the `hsm_secret`
511
- * encryption key (new) memory again here. */
512
- if (hsm_encryption_key && sodium_mlock (hsm_encryption_key ,
513
- sizeof (hsm_encryption_key )) != 0 )
514
- status_failed (STATUS_FAIL_INTERNAL_ERROR ,
515
- "Could not lock memory for hsm_secret encryption key." );
516
552
/*~ Don't swap this. */
517
- sodium_mlock (hsm_secret .data , sizeof (hsm_secret .data ));
553
+ sodium_mlock (hsm_secret .secret . data , sizeof (hsm_secret . secret .data ));
518
554
519
555
if (!developer ) {
520
556
assert (!dev_force_privkey );
@@ -526,16 +562,15 @@ static struct io_plan *init_hsm(struct io_conn *conn,
526
562
/* Once we have read the init message we know which params the master
527
563
* will use */
528
564
c -> chainparams = chainparams ;
529
- maybe_create_new_hsm (hsm_encryption_key , true);
530
- load_hsm (hsm_encryption_key );
531
-
532
- /*~ We don't need the hsm_secret encryption key anymore. */
533
- if (hsm_encryption_key )
534
- discard_key (take (hsm_encryption_key ));
565
+ maybe_create_new_hsm (hsm_passphrase );
566
+ load_hsm (hsm_passphrase );
535
567
536
568
/* Define the minimum common max version for the hsmd one */
537
569
hsmd_mutual_version = maxversion < our_maxversion ? maxversion : our_maxversion ;
538
- return req_reply (conn , c , hsmd_init (hsm_secret , hsmd_mutual_version ,
570
+
571
+ /* This was tallocated off NULL, and memleak complains if we don't free it */
572
+ tal_free (tlvs );
573
+ return req_reply (conn , c , hsmd_init (hsm_secret .secret , hsmd_mutual_version ,
539
574
bip32_key_version ));
540
575
}
541
576
@@ -756,6 +791,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
756
791
case WIRE_HSMD_SIGN_WITHDRAWAL_REPLY :
757
792
case WIRE_HSMD_SIGN_INVOICE_REPLY :
758
793
case WIRE_HSMD_INIT_REPLY_V4 :
794
+ case WIRE_HSMD_INIT_REPLY_FAILURE :
759
795
case WIRE_HSMD_DERIVE_SECRET_REPLY :
760
796
case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST :
761
797
case WIRE_HSMD_SIGN_COMMITMENT_TX_REPLY :
0 commit comments