Browse Source

lightningd/hsm: convert to subd.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 8 years ago
parent
commit
7f406ea80d
  1. 23
      lightningd/hsm/Makefile
  2. 70
      lightningd/hsm/hsm.c
  3. 32
      lightningd/hsm/hsm_control_wire_csv
  4. 12
      lightningd/hsm/hsm_status_wire_csv
  5. 47
      lightningd/hsm/hsm_wire.csv
  6. 54
      lightningd/hsm_control.c
  7. 2
      lightningd/lightningd.h
  8. 33
      lightningd/peer_control.c

23
lightningd/hsm/Makefile

@ -12,16 +12,13 @@ LIGHTNINGD_HSM_CLIENT_SRC := lightningd/hsm/client.c lightningd/hsm/gen_hsm_clie
LIGHTNINGD_HSM_CLIENT_OBJS := $(LIGHTNINGD_HSM_CLIENT_SRC:.c=.o)
# Control daemon uses this:
LIGHTNINGD_HSM_CONTROL_HEADERS := lightningd/hsm/gen_hsm_control_wire.h \
lightningd/hsm/gen_hsm_status_wire.h
LIGHTNINGD_HSM_CONTROL_SRC := lightningd/hsm/gen_hsm_control_wire.c \
lightningd/hsm/gen_hsm_status_wire.c
LIGHTNINGD_HSM_CONTROL_HEADERS := lightningd/hsm/gen_hsm_wire.h
LIGHTNINGD_HSM_CONTROL_SRC := lightningd/hsm/gen_hsm_wire.c
LIGHTNINGD_HSM_CONTROL_OBJS := $(LIGHTNINGD_HSM_CONTROL_SRC:.c=.o)
# lightningd/hsm needs these:
LIGHTNINGD_HSM_HEADERS := lightningd/hsm/gen_hsm_client_wire.h \
lightningd/hsm/gen_hsm_control_wire.h \
lightningd/hsm/gen_hsm_status_wire.h
lightningd/hsm/gen_hsm_wire.h
LIGHTNINGD_HSM_SRC := lightningd/hsm/hsm.c \
$(LIGHTNINGD_HSM_HEADERS:.h=.c)
LIGHTNINGD_HSM_OBJS := $(LIGHTNINGD_HSM_SRC:.c=.o)
@ -50,17 +47,11 @@ lightningd/hsm/gen_hsm_client_wire.h: $(WIRE_GEN) lightningd/hsm/hsm_client_wire
lightningd/hsm/gen_hsm_client_wire.c: $(WIRE_GEN) lightningd/hsm/hsm_client_wire_csv
$(WIRE_GEN) ${@:.c=.h} hsm_client_wire_type< lightningd/hsm/hsm_client_wire_csv > $@
lightningd/hsm/gen_hsm_control_wire.h: $(WIRE_GEN) lightningd/hsm/hsm_control_wire_csv
$(WIRE_GEN) --header $@ hsm_control_wire_type < lightningd/hsm/hsm_control_wire_csv > $@
lightningd/hsm/gen_hsm_wire.h: $(WIRE_GEN) lightningd/hsm/hsm_wire.csv
$(WIRE_GEN) --header $@ hsm_wire_type < lightningd/hsm/hsm_wire.csv > $@
lightningd/hsm/gen_hsm_control_wire.c: $(WIRE_GEN) lightningd/hsm/hsm_control_wire_csv
$(WIRE_GEN) ${@:.c=.h} hsm_control_wire_type < lightningd/hsm/hsm_control_wire_csv > $@
lightningd/hsm/gen_hsm_status_wire.h: $(WIRE_GEN) lightningd/hsm/hsm_status_wire_csv
$(WIRE_GEN) --header $@ hsm_status_wire_type < lightningd/hsm/hsm_status_wire_csv > $@
lightningd/hsm/gen_hsm_status_wire.c: $(WIRE_GEN) lightningd/hsm/hsm_status_wire_csv
$(WIRE_GEN) ${@:.c=.h} hsm_status_wire_type < lightningd/hsm/hsm_status_wire_csv > $@
lightningd/hsm/gen_hsm_wire.c: $(WIRE_GEN) lightningd/hsm/hsm_wire.csv
$(WIRE_GEN) ${@:.c=.h} hsm_wire_type < lightningd/hsm/hsm_wire.csv > $@
check-source: $(LIGHTNINGD_HSM_ALLSRC_NOGEN:%=check-src-include-order/%) $(LIGHTNINGD_HSM_ALLHEADERS_NOGEN:%=check-hdr-include-order/%)
check-source-bolt: $(LIGHTNINGD_HSM_SRC:%=bolt-check/%) $(LIGHTNINGD_HSM_HEADERS:%=bolt-check/%)

70
lightningd/hsm/hsm.c

@ -18,8 +18,7 @@
#include <lightningd/funding_tx.h>
#include <lightningd/hsm/client.h>
#include <lightningd/hsm/gen_hsm_client_wire.h>
#include <lightningd/hsm/gen_hsm_control_wire.h>
#include <lightningd/hsm/gen_hsm_status_wire.h>
#include <lightningd/hsm/gen_hsm_wire.h>
#include <permute_tx.h>
#include <secp256k1_ecdh.h>
#include <sodium/randombytes.h>
@ -155,8 +154,8 @@ static u8 *init_response(struct conn_info *control)
status_failed(WIRE_HSMSTATUS_KEY_FAILED,
"Can't serialize bip32 public key");
msg = towire_hsmctl_init_response(control, &node_id, &peer_seed,
serialized_extkey);
msg = towire_hsmctl_init_reply(control, &node_id, &peer_seed,
serialized_extkey);
tal_free(serialized_extkey);
return msg;
}
@ -252,7 +251,7 @@ static void bitcoin_keypair(struct privkey *privkey,
"BIP32 pubkey %u create failed", index);
}
static u8 *create_new_hsm(struct conn_info *control)
static void create_new_hsm(struct conn_info *control)
{
int fd = open("hsm_secret", O_CREAT|O_EXCL|O_WRONLY, 0400);
if (fd < 0)
@ -284,11 +283,9 @@ static u8 *create_new_hsm(struct conn_info *control)
close(fd);
populate_secretstuff();
return init_response(control);
}
static u8 *load_hsm(struct conn_info *control)
static void load_hsm(struct conn_info *control)
{
int fd = open("hsm_secret", O_RDONLY);
if (fd < 0)
@ -300,6 +297,19 @@ static u8 *load_hsm(struct conn_info *control)
close(fd);
populate_secretstuff();
}
static u8 *init_hsm(struct conn_info *control, const u8 *msg)
{
bool new;
if (!fromwire_hsmctl_init(msg, NULL, &new))
status_failed(WIRE_HSMSTATUS_BAD_REQUEST, "hsmctl_init: %s",
tal_hex(msg, msg));
if (new)
create_new_hsm(control);
else
load_hsm(control);
return init_response(control);
}
@ -349,7 +359,7 @@ static u8 *pass_hsmfd_ecdh(struct io_conn *conn,
io_new_conn(control, fds[0], ecdh_client, c);
*fd_to_pass = fds[1];
return towire_hsmctl_hsmfd_fd_response(control);
return towire_hsmctl_hsmfd_ecdh_fd_reply(control);
}
/* Note that it's the main daemon that asks for the funding signature so it
@ -408,7 +418,7 @@ static u8 *sign_funding_tx(const tal_t *ctx, const u8 *data)
&inprivkey, &inkey, &sig[i]);
}
msg_out = towire_hsmctl_sign_funding_response(ctx, sig);
msg_out = towire_hsmctl_sign_funding_reply(ctx, sig);
tal_free(tmpctx);
return msg_out;
}
@ -416,17 +426,14 @@ static u8 *sign_funding_tx(const tal_t *ctx, const u8 *data)
static struct io_plan *control_received_req(struct io_conn *conn,
struct conn_info *control)
{
enum hsm_control_wire_type t = fromwire_peektype(control->in);
enum hsm_wire_type t = fromwire_peektype(control->in);
status_trace("Control: type %s len %zu",
hsm_control_wire_type_name(t), tal_count(control->in));
hsm_wire_type_name(t), tal_count(control->in));
switch (t) {
case WIRE_HSMCTL_INIT_NEW:
control->out = create_new_hsm(control);
goto send_out;
case WIRE_HSMCTL_INIT_LOAD:
control->out = load_hsm(control);
case WIRE_HSMCTL_INIT:
control->out = init_hsm(control, control->in);
goto send_out;
case WIRE_HSMCTL_HSMFD_ECDH:
control->out = pass_hsmfd_ecdh(conn, control, control->in,
@ -436,9 +443,15 @@ static struct io_plan *control_received_req(struct io_conn *conn,
control->out = sign_funding_tx(control, control->in);
goto send_out;
case WIRE_HSMCTL_INIT_RESPONSE:
case WIRE_HSMCTL_HSMFD_FD_RESPONSE:
case WIRE_HSMCTL_SIGN_FUNDING_RESPONSE:
case WIRE_HSMCTL_INIT_REPLY:
case WIRE_HSMCTL_HSMFD_ECDH_FD_REPLY:
case WIRE_HSMCTL_SIGN_FUNDING_REPLY:
case WIRE_HSMSTATUS_INIT_FAILED:
case WIRE_HSMSTATUS_WRITEMSG_FAILED:
case WIRE_HSMSTATUS_BAD_REQUEST:
case WIRE_HSMSTATUS_FD_FAILED:
case WIRE_HSMSTATUS_KEY_FAILED:
case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST:
break;
}
@ -458,16 +471,11 @@ static struct io_plan *control_init(struct io_conn *conn,
return recv_req(conn, control);
}
/* Exit when control fd closes. */
static void control_finish(struct io_conn *conn, struct conn_info *control)
{
io_break(control);
}
#ifndef TESTING
int main(int argc, char *argv[])
{
struct conn_info *control;
struct io_conn *conn;
if (argc == 2 && streq(argv[1], "--version")) {
printf("%s\n", version());
@ -481,15 +489,13 @@ int main(int argc, char *argv[])
control = tal(NULL, struct conn_info);
conn_info_init(control, control_received_req);
/* Stdout == status, stdin == requests */
status_setup(STDOUT_FILENO);
status_setup(STDIN_FILENO);
io_set_finish(io_new_conn(control, STDIN_FILENO, control_init, control),
control_finish, control);
conn = io_new_conn(NULL, STDIN_FILENO, control_init, control);
/* When conn closes, everything is freed. */
tal_steal(conn, control);
io_loop(NULL, NULL);
tal_free(control);
return 0;
}
#endif

32
lightningd/hsm/hsm_control_wire_csv

@ -1,32 +0,0 @@
# These both respond with init_response
hsmctl_init_new,1
hsmctl_init_load,2
hsmctl_init_response,100
hsmctl_init_response,0,node_id,33
hsmctl_init_response,33,peer_seed,32,struct privkey
hsmctl_init_response,65,bip32_len,2
hsmctl_init_response,67,bip32_seed,bip32_len*1,u8
# ECDH returns an fd.
hsmctl_hsmfd_ecdh,3
hsmctl_hsmfd_ecdh,0,unique_id,8
# Return signature for a funding tx.
#include <lightningd/utxo.h>
# FIXME: This should also take their commit sig & details, to verify.
hsmctl_sign_funding,4
hsmctl_sign_funding,0,satoshi_out,8
hsmctl_sign_funding,8,change_out,8
hsmctl_sign_funding,16,change_keyindex,4
hsmctl_sign_funding,20,our_pubkey,33
hsmctl_sign_funding,52,their_pubkey,33
hsmctl_sign_funding,85,num_inputs,2
hsmctl_sign_funding,87,inputs,num_inputs*49,struct utxo
hsmctl_sign_funding_response,104
hsmctl_sign_funding_response,0,num_sigs,2
hsmctl_sign_funding_response,0,sig,num_sigs*64,secp256k1_ecdsa_signature
# No message, just an fd.
hsmctl_hsmfd_fd_response,103

12
lightningd/hsm/hsm_status_wire_csv

@ -1,12 +0,0 @@
# These are fatal.
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
hsmstatus_client_bad_request,0,unique-id,8
hsmstatus_client_bad_request,8,len,2
hsmstatus_client_bad_request,10,msg,len,u8

47
lightningd/hsm/hsm_wire.csv

@ -0,0 +1,47 @@
# These are fatal.
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,1000
hsmstatus_client_bad_request,0,unique-id,8
hsmstatus_client_bad_request,8,len,2
hsmstatus_client_bad_request,10,msg,len,u8
# Start the HSM.
hsmctl_init,1
hsmctl_init,0,new,1,bool
hsmctl_init_reply,101
hsmctl_init_reply,0,node_id,33
hsmctl_init_reply,33,peer_seed,32,struct privkey
hsmctl_init_reply,65,bip32_len,2
hsmctl_init_reply,67,bip32_seed,bip32_len*1,u8
# ECDH returns an fd.
hsmctl_hsmfd_ecdh,3
hsmctl_hsmfd_ecdh,0,unique_id,8
# No contents, just an fd.
hsmctl_hsmfd_ecdh_fd_reply,103
# Return signature for a funding tx.
#include <lightningd/utxo.h>
# FIXME: This should also take their commit sig & details, to verify.
hsmctl_sign_funding,4
hsmctl_sign_funding,0,satoshi_out,8
hsmctl_sign_funding,8,change_out,8
hsmctl_sign_funding,16,change_keyindex,4
hsmctl_sign_funding,20,our_pubkey,33
hsmctl_sign_funding,52,their_pubkey,33
hsmctl_sign_funding,85,num_inputs,2
hsmctl_sign_funding,87,inputs,num_inputs*49,struct utxo
hsmctl_sign_funding_reply,104
hsmctl_sign_funding_reply,0,num_sigs,2
hsmctl_sign_funding_reply,0,sig,num_sigs*64,secp256k1_ecdsa_signature
Can't render this file because it has a wrong number of fields in line 2.

54
lightningd/hsm_control.c

@ -1,25 +1,24 @@
#include "hsm_control.h"
#include "lightningd.h"
#include "peer_control.h"
#include "subdaemon.h"
#include "subd.h"
#include <ccan/err/err.h>
#include <ccan/io/io.h>
#include <ccan/take/take.h>
#include <daemon/log.h>
#include <inttypes.h>
#include <lightningd/hsm/gen_hsm_control_wire.h>
#include <lightningd/hsm/gen_hsm_status_wire.h>
#include <lightningd/hsm/gen_hsm_wire.h>
#include <wally_bip32.h>
static void hsm_init_done(struct subdaemon *hsm, const u8 *msg,
static bool hsm_init_done(struct subd *hsm, const u8 *msg,
struct lightningd *ld)
{
u8 *serialized_extkey;
if (!fromwire_hsmctl_init_response(hsm, msg, NULL, &ld->dstate.id,
&ld->peer_seed,
&serialized_extkey))
errx(1, "HSM did not give init response");
if (!fromwire_hsmctl_init_reply(hsm, msg, NULL, &ld->dstate.id,
&ld->peer_seed,
&serialized_extkey))
errx(1, "HSM did not give init reply");
log_info_struct(ld->log, "Our ID: %s", struct pubkey, &ld->dstate.id);
ld->bip32_base = tal(ld, struct ext_key);
@ -28,9 +27,10 @@ static void hsm_init_done(struct subdaemon *hsm, const u8 *msg,
errx(1, "HSM did not give unserializable BIP32 extkey");
io_break(ld->hsm);
return true;
}
static void hsm_finished(struct subdaemon *hsm, int status)
static void hsm_finished(struct subd *hsm, int status)
{
if (WIFEXITED(status))
errx(1, "HSM failed (exit status %i), exiting.",
@ -38,10 +38,9 @@ static void hsm_finished(struct subdaemon *hsm, int status)
errx(1, "HSM failed (signal %u), exiting.", WTERMSIG(status));
}
static enum subdaemon_status hsm_status(struct subdaemon *hsm, const u8 *msg,
int fd)
static enum subd_msg_ret hsm_msg(struct subd *hsm, const u8 *msg, int fd)
{
enum hsm_status_wire_type t = fromwire_peektype(msg);
enum hsm_wire_type t = fromwire_peektype(msg);
u8 *badmsg;
struct peer *peer;
u64 id;
@ -68,33 +67,38 @@ static enum subdaemon_status hsm_status(struct subdaemon *hsm, const u8 *msg,
case WIRE_HSMSTATUS_BAD_REQUEST:
case WIRE_HSMSTATUS_FD_FAILED:
case WIRE_HSMSTATUS_KEY_FAILED:
break;
/* HSM doesn't send these */
case WIRE_HSMCTL_INIT:
case WIRE_HSMCTL_HSMFD_ECDH:
case WIRE_HSMCTL_SIGN_FUNDING:
/* Replies should be paired to individual requests. */
case WIRE_HSMCTL_INIT_REPLY:
case WIRE_HSMCTL_HSMFD_ECDH_FD_REPLY:
case WIRE_HSMCTL_SIGN_FUNDING_REPLY:
errx(1, "HSM gave invalid message %s", hsm_wire_type_name(t));
}
return STATUS_COMPLETE;
return SUBD_COMPLETE;
}
void hsm_init(struct lightningd *ld, bool newdir)
{
bool create;
ld->hsm = new_subdaemon(ld, ld, "lightningd_hsm", NULL,
hsm_status_wire_type_name,
hsm_control_wire_type_name,
hsm_status, hsm_finished, -1);
ld->hsm = new_subd(ld, ld, "lightningd_hsm", NULL,
hsm_wire_type_name,
hsm_msg, hsm_finished, -1);
if (!ld->hsm)
err(1, "Could not subdaemon hsm");
err(1, "Could not subd hsm");
if (newdir)
create = true;
else
create = (access("hsm_secret", F_OK) != 0);
if (create)
subdaemon_req(ld->hsm, take(towire_hsmctl_init_new(ld->hsm)),
-1, NULL, hsm_init_done, ld);
else
subdaemon_req(ld->hsm, take(towire_hsmctl_init_load(ld->hsm)),
-1, NULL, hsm_init_done, ld);
subd_req(ld->hsm, take(towire_hsmctl_init(ld->hsm, create)),
-1, NULL, hsm_init_done, ld);
if (io_loop(NULL, NULL) != ld->hsm)
errx(1, "Unexpected io exit during HSM startup");

2
lightningd/lightningd.h

@ -24,7 +24,7 @@ struct lightningd {
struct log *log;
/* Bearer of all my secrets. */
struct subdaemon *hsm;
struct subd *hsm;
/* Daemon looking after peers during init / before channel. */
struct subdaemon *gossip;

33
lightningd/peer_control.c

@ -1,5 +1,6 @@
#include "lightningd.h"
#include "peer_control.h"
#include "subd.h"
#include "subdaemon.h"
#include <bitcoin/script.h>
#include <bitcoin/tx.h>
@ -22,7 +23,7 @@
#include <lightningd/gossip/gen_gossip_status_wire.h>
#include <lightningd/handshake/gen_handshake_control_wire.h>
#include <lightningd/handshake/gen_handshake_status_wire.h>
#include <lightningd/hsm/gen_hsm_control_wire.h>
#include <lightningd/hsm/gen_hsm_wire.h>
#include <lightningd/key_derive.h>
#include <lightningd/opening/gen_opening_control_wire.h>
#include <lightningd/opening/gen_opening_status_wire.h>
@ -156,12 +157,12 @@ err:
tal_free(peer);
}
static void peer_got_handshake_hsmfd(struct subdaemon *hsm, const u8 *msg,
static bool peer_got_handshake_hsmfd(struct subd *hsm, const u8 *msg,
struct peer *peer)
{
const u8 *req;
if (!fromwire_hsmctl_hsmfd_fd_response(msg, NULL)) {
if (!fromwire_hsmctl_hsmfd_ecdh_fd_reply(msg, NULL)) {
log_unusual(peer->ld->log, "Malformed hsmfd response: %s",
tal_hex(peer, msg));
goto error;
@ -197,10 +198,11 @@ static void peer_got_handshake_hsmfd(struct subdaemon *hsm, const u8 *msg,
* back on success */
subdaemon_req(peer->owner, take(req), -1, &peer->fd,
handshake_succeeded, peer);
return;
return true;
error:
tal_free(peer);
return true;
}
/* FIXME: timeout handshake if taking too long? */
@ -212,9 +214,9 @@ static struct io_plan *peer_in(struct io_conn *conn, struct lightningd *ld)
return io_close(conn);
/* Get HSM fd for this peer. */
subdaemon_req(ld->hsm,
take(towire_hsmctl_hsmfd_ecdh(ld, peer->unique_id)),
-1, &peer->hsmfd, peer_got_handshake_hsmfd, peer);
subd_req(ld->hsm,
take(towire_hsmctl_hsmfd_ecdh(ld, peer->unique_id)),
-1, &peer->hsmfd, peer_got_handshake_hsmfd, peer);
/* We don't need conn, we'll pass fd to handshaked. */
return io_close_taken_fd(conn);
@ -343,9 +345,9 @@ static struct io_plan *peer_out(struct io_conn *conn,
peer->id = tal_dup(peer, struct pubkey, &jc->id);
/* Get HSM fd for this peer. */
subdaemon_req(ld->hsm,
take(towire_hsmctl_hsmfd_ecdh(ld, peer->unique_id)),
-1, &peer->hsmfd, peer_got_handshake_hsmfd, peer);
subd_req(ld->hsm,
take(towire_hsmctl_hsmfd_ecdh(ld, peer->unique_id)),
-1, &peer->hsmfd, peer_got_handshake_hsmfd, peer);
/* We don't need conn, we'll pass fd to handshaked. */
return io_close_taken_fd(conn);
@ -555,15 +557,15 @@ static enum watch_result funding_depth_cb(struct peer *peer,
return DELETE_WATCH;
}
static void opening_got_hsm_funding_sig(struct subdaemon *hsm, const u8 *resp,
static bool opening_got_hsm_funding_sig(struct subd *hsm, const u8 *resp,
struct funding_channel *fc)
{
secp256k1_ecdsa_signature *sigs;
struct bitcoin_tx *tx = fc->funding_tx;
size_t i;
if (!fromwire_hsmctl_sign_funding_response(fc, resp, NULL, &sigs))
fatal("HSM gave bad sign_funding_response %s",
if (!fromwire_hsmctl_sign_funding_reply(fc, resp, NULL, &sigs))
fatal("HSM gave bad sign_funding_reply %s",
tal_hex(fc, resp));
if (tal_count(sigs) != tal_count(tx->input))
@ -595,6 +597,7 @@ static void opening_got_hsm_funding_sig(struct subdaemon *hsm, const u8 *resp,
watch_tx(fc->peer, fc->peer->ld->topology, fc->peer, tx,
funding_depth_cb, NULL);
tal_free(fc);
return true;
}
static enum subdaemon_status update_channel_status(struct subdaemon *sd,
@ -715,8 +718,8 @@ static void opening_release_tx(struct subdaemon *opening, const u8 *resp,
&fc->remote_fundingkey,
utxos);
tal_free(utxos);
subdaemon_req(fc->peer->ld->hsm, take(msg), -1, NULL,
opening_got_hsm_funding_sig, fc);
subd_req(fc->peer->ld->hsm, take(msg), -1, NULL,
opening_got_hsm_funding_sig, fc);
/* Start normal channel daemon. */
peer_start_channeld(fc->peer, true,

Loading…
Cancel
Save