hsm: return BIP32 public seed on initialization.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-02-21 15:15:29 +10:30
parent fddb38126d
commit 891a915e0f
7 changed files with 106 additions and 5 deletions

View File

@ -107,7 +107,7 @@ check-makefile: check-lightningd-makefile
check-lightningd-makefile:
@for f in lightningd/*.h lightningd/*/*.h; do if ! echo $(LIGHTNINGD_HEADERS_NOGEN) $(LIGHTNINGD_HEADERS_GEN) "" | grep -q "$$f "; then echo $$f not mentioned in LIGHTNINGD_HEADERS_NOGEN or LIGHTNINGD_HEADERS_GEN >&2; exit 1; fi; done
lightningd/lightningd: $(LIGHTNINGD_OBJS) $(LIGHTNINGD_OLD_OBJS) $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(LIGHTNINGD_JSMN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(CCAN_OBJS) $(LIGHTNINGD_HSM_CONTROL_OBJS) $(LIGHTNINGD_HANDSHAKE_CONTROL_OBJS) $(LIGHTNINGD_GOSSIP_CONTROL_OBJS) $(LIBBASE58_OBJS) libsecp256k1.a libsodium.a
lightningd/lightningd: $(LIGHTNINGD_OBJS) $(LIGHTNINGD_OLD_OBJS) $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(LIGHTNINGD_JSMN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(CCAN_OBJS) $(LIGHTNINGD_HSM_CONTROL_OBJS) $(LIGHTNINGD_HANDSHAKE_CONTROL_OBJS) $(LIGHTNINGD_GOSSIP_CONTROL_OBJS) $(LIBBASE58_OBJS) libsecp256k1.a libsodium.a libwallycore.a
clean: lightningd-clean

View File

@ -37,9 +37,11 @@ $(LIGHTNINGD_HSM_OBJS) $(LIGHTNINGD_HSM_CLIENT_OBJS): $(LIGHTNINGD_HEADERS)
$(LIGHTNINGD_HSM_CONTROL_OBJS) : $(LIGHTNINGD_HSM_CONTROL_HEADERS)
$(LIGHTNINGD_HSM_OBJS): $(CORE_TX_HEADERS)
lightningd/hsm-all: lightningd/lightningd_hsm $(LIGHTNINGD_HSM_CLIENT_OBJS)
lightningd/lightningd_hsm: $(LIGHTNINGD_HSM_OBJS) $(CORE_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(CCAN_OBJS) $(LIBBASE58_OBJS) libsecp256k1.a libsodium.a libwallycore.a
lightningd/lightningd_hsm: $(LIGHTNINGD_HSM_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(CCAN_OBJS) $(LIBBASE58_OBJS) lightningd/utxo.o libsecp256k1.a libsodium.a libwallycore.a
$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS)
lightningd/hsm/gen_hsm_client_wire.h: $(WIRE_GEN) lightningd/hsm/hsm_client_wire_csv

View File

@ -135,14 +135,25 @@ static u8 *handle_ecdh(struct client *c, const void *data)
static u8 *init_response(struct conn_info *control)
{
struct pubkey node_id;
u8 *serialized_extkey = tal_arr(control, u8, BIP32_SERIALIZED_LEN), *msg;
node_key(NULL, &node_id);
return towire_hsmctl_init_response(control, &node_id);
if (bip32_key_serialize(&secretstuff.bip32, BIP32_FLAG_KEY_PUBLIC,
serialized_extkey, tal_len(serialized_extkey))
!= WALLY_OK)
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
"Can't serialize bip32 public key");
msg = towire_hsmctl_init_response(control, &node_id, serialized_extkey);
tal_free(serialized_extkey);
return msg;
}
static void populate_secretstuff(void)
{
u8 bip32_seed[BIP32_ENTROPY_LEN_256];
u32 salt = 0;
struct ext_key master_extkey, child_extkey;
/* Fill in the BIP32 tree for bitcoin addresses. */
do {
@ -154,7 +165,79 @@ static void populate_secretstuff(void)
salt++;
} while (bip32_key_from_seed(bip32_seed, sizeof(bip32_seed),
BIP32_VER_TEST_PRIVATE,
0, &secretstuff.bip32) != WALLY_OK);
0, &master_extkey) != WALLY_OK);
/* BIP 32:
*
* The default wallet layout
*
* An HDW is organized as several 'accounts'. Accounts are numbered,
* the default account ("") being number 0. Clients are not required
* to support more than one account - if not, they only use the
* default account.
*
* Each account is composed of two keypair chains: an internal and an
* external one. The external keychain is used to generate new public
* addresses, while the internal keychain is used for all other
* operations (change addresses, generation addresses, ..., anything
* that doesn't need to be communicated). Clients that do not support
* separate keychains for these should use the external one for
* everything.
*
* - m/iH/0/k corresponds to the k'th keypair of the external chain of account number i of the HDW derived from master m.
*/
/* Hence child 0, then child 0 again to get extkey to derive from. */
if (bip32_key_from_parent(&master_extkey, 0, BIP32_FLAG_KEY_PRIVATE,
&child_extkey) != WALLY_OK)
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
"Can't derive child bip32 key");
if (bip32_key_from_parent(&child_extkey, 0, BIP32_FLAG_KEY_PRIVATE,
&secretstuff.bip32) != WALLY_OK)
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
"Can't derive private bip32 key");
}
static inline void bitcoin_pubkey(struct pubkey *pubkey, u32 index)
{
struct ext_key ext;
if (index >= BIP32_INITIAL_HARDENED_CHILD)
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
"Index %u too great", index);
if (bip32_key_from_parent(&secretstuff.bip32, index,
BIP32_FLAG_KEY_PUBLIC, &ext) != WALLY_OK)
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
"BIP32 of %u failed", index);
if (!secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey->pubkey,
ext.pub_key, sizeof(ext.pub_key)))
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
"Parse of BIP32 child %u pubkey failed", index);
}
static inline void bitcoin_keypair(struct privkey *privkey,
struct pubkey *pubkey,
u32 index)
{
struct ext_key ext;
if (index >= BIP32_INITIAL_HARDENED_CHILD)
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
"Index %u too great", index);
if (bip32_key_from_parent(&secretstuff.bip32, index,
BIP32_FLAG_KEY_PRIVATE, &ext) != WALLY_OK)
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
"BIP32 of %u failed", index);
/* libwally says: The private key with prefix byte 0 */
memcpy(privkey->secret, ext.priv_key+1, 32);
if (!secp256k1_ec_pubkey_create(secp256k1_ctx, &pubkey->pubkey,
privkey->secret))
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
"BIP32 pubkey %u create failed", index);
}
static u8 *create_new_hsm(struct conn_info *control)

View File

@ -4,6 +4,8 @@ hsmctl_init_load,2
hsmctl_init_response,100
hsmctl_init_response,0,node_id,33
hsmctl_init_response,33,bip32_len,2
hsmctl_init_response,35,bip32_seed,bip32_len*1,u8
# ECDH returns an fd.
hsmctl_hsmfd_ecdh,3

View File

@ -3,6 +3,7 @@ hsmstatus_init_failed,0x8000
hsmstatus_writemsg_failed,0x8001
hsmstatus_bad_request,0x8002
hsmstatus_fd_failed,0x8003
hsmstatus_key_failed,0x8004
# Clients should not give a bad request but not the HSM's decision to crash.
hsmstatus_client_bad_request,1

View File

@ -9,14 +9,23 @@
#include <inttypes.h>
#include <lightningd/hsm/gen_hsm_control_wire.h>
#include <lightningd/hsm/gen_hsm_status_wire.h>
#include <wally_bip32.h>
static void hsm_init_done(struct subdaemon *hsm, const u8 *msg,
struct lightningd *ld)
{
if (!fromwire_hsmctl_init_response(msg, NULL, &ld->dstate.id))
u8 *serialized_extkey;
if (!fromwire_hsmctl_init_response(hsm, msg, NULL, &ld->dstate.id,
&serialized_extkey))
errx(1, "HSM did not give init response");
log_info_struct(ld->log, "Our ID: %s", struct pubkey, &ld->dstate.id);
ld->bip32_base = tal(ld, struct ext_key);
if (bip32_key_unserialize(serialized_extkey, tal_len(serialized_extkey),
ld->bip32_base) != WALLY_OK)
errx(1, "HSM did not give unserializable BIP32 extkey");
io_break(ld->hsm);
}
@ -57,6 +66,7 @@ static enum subdaemon_status hsm_status(struct subdaemon *hsm, const u8 *msg,
case WIRE_HSMSTATUS_WRITEMSG_FAILED:
case WIRE_HSMSTATUS_BAD_REQUEST:
case WIRE_HSMSTATUS_FD_FAILED:
case WIRE_HSMSTATUS_KEY_FAILED:
break;
}
return STATUS_COMPLETE;

View File

@ -30,6 +30,9 @@ struct lightningd {
/* All peers we're tracking. */
struct list_head peers;
/* Public base for bip32 keys. */
struct ext_key *bip32_base;
};
/* FIXME */