diff --git a/hsmd/capabilities.h b/hsmd/capabilities.h new file mode 100644 index 000000000..9fecb948e --- /dev/null +++ b/hsmd/capabilities.h @@ -0,0 +1,7 @@ +#ifndef LIGHTNING_HSMD_CAPABILITIES_H +#define LIGHTNING_HSMD_CAPABILITIES_H + +#define HSM_CAP_ECDH 1 +#define HSM_CAP_SIGN_GOSSIP 2 + +#endif /* LIGHTNING_HSMD_CAPABILITIES_H */ diff --git a/hsmd/hsm.c b/hsmd/hsm.c index e2c6c85f0..8b8640f87 100644 --- a/hsmd/hsm.c +++ b/hsmd/hsm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,9 @@ struct client { struct pubkey id; struct io_plan *(*handle)(struct io_conn *, struct daemon_conn *); + + /* What is this client allowed to ask for? */ + u64 capabilities; }; static void node_key(struct privkey *node_privkey, struct pubkey *node_id) @@ -77,6 +81,7 @@ static void node_key(struct privkey *node_privkey, struct pubkey *node_id) static struct client *new_client(struct daemon_conn *master, const struct pubkey *id, + const u64 capabilities, struct io_plan *(*handle)(struct io_conn *, struct daemon_conn *), int fd) @@ -85,6 +90,7 @@ static struct client *new_client(struct daemon_conn *master, c->id = *id; c->handle = handle; c->master = master; + c->capabilities = capabilities; daemon_conn_init(c, &c->dc, fd, handle, NULL); /* Free the connection if we exit everything. */ @@ -216,6 +222,62 @@ static struct io_plan *handle_channel_update_sig(struct io_conn *conn, return daemon_conn_read_next(conn, dc); } +static bool check_client_capabilities(struct client *client, + enum hsm_client_wire_type t) +{ + switch (t) { + case WIRE_HSM_ECDH_REQ: + return (client->capabilities & HSM_CAP_ECDH) != 0; + + case WIRE_HSM_CANNOUNCEMENT_SIG_REQ: + case WIRE_HSM_CUPDATE_SIG_REQ: + return (client->capabilities & HSM_CAP_SIGN_GOSSIP) != 0; + + case WIRE_HSM_ECDH_RESP: + case WIRE_HSM_CANNOUNCEMENT_SIG_REPLY: + case WIRE_HSM_CUPDATE_SIG_REPLY: + break; + } + return false; +} + +static struct io_plan *handle_client(struct io_conn *conn, + struct daemon_conn *dc) +{ + struct client *c = container_of(dc, struct client, dc); + enum hsm_client_wire_type t = fromwire_peektype(dc->msg_in); + + /* Before we do anything else, is this client allowed to do + * what he asks for? */ + if (!check_client_capabilities(c, t)) { + daemon_conn_send(c->master, + take(towire_hsmstatus_client_bad_request( + c, &c->id, dc->msg_in))); + return io_close(conn); + } + + /* Now actually go and do what the client asked for */ + switch (t) { + case WIRE_HSM_ECDH_REQ: + return handle_ecdh(conn, dc); + case WIRE_HSM_CANNOUNCEMENT_SIG_REQ: + return handle_cannouncement_sig(conn, dc); + case WIRE_HSM_CUPDATE_SIG_REQ: + return handle_channel_update_sig(conn, dc); + + case WIRE_HSM_ECDH_RESP: + case WIRE_HSM_CANNOUNCEMENT_SIG_REPLY: + case WIRE_HSM_CUPDATE_SIG_REPLY: + break; + } + + daemon_conn_send(c->master, + take(towire_hsmstatus_client_bad_request(c, + &c->id, + dc->msg_in))); + return io_close(conn); +} + static struct io_plan *handle_channeld(struct io_conn *conn, struct daemon_conn *dc) { @@ -418,6 +480,25 @@ static void init_hsm(struct daemon_conn *master, const u8 *msg) send_init_response(master); } +static void pass_client_hsmfd(struct daemon_conn *master, const u8 *msg) +{ + int fds[2]; + u64 capabilities; + struct pubkey id; + + if (!fromwire_hsmctl_client_hsmfd(msg, NULL, &id, &capabilities)) + master_badmsg(WIRE_HSMCTL_CLIENT_HSMFD, msg); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) + status_failed(STATUS_FAIL_INTERNAL_ERROR, "creating fds: %s", strerror(errno)); + + new_client(master, &id, capabilities, handle_client, fds[0]); + daemon_conn_send(master, + take(towire_hsmctl_client_hsmfd_reply(master))); + daemon_conn_send_fd(master, fds[1]); +} + + static void pass_hsmfd_ecdh(struct daemon_conn *master, const u8 *msg) { int fds[2]; @@ -432,7 +513,7 @@ static void pass_hsmfd_ecdh(struct daemon_conn *master, const u8 *msg) /* This is gossipd, so we use our own id */ node_key(NULL, &id); - new_client(master, &id, handle_ecdh, fds[0]); + new_client(master, &id, HSM_CAP_ECDH, handle_ecdh, fds[0]); daemon_conn_send(master, take(towire_hsmctl_hsmfd_ecdh_fd_reply(master))); daemon_conn_send_fd(master, fds[1]); @@ -451,7 +532,7 @@ static void pass_hsmfd_channeld(struct daemon_conn *master, const u8 *msg) status_failed(STATUS_FAIL_INTERNAL_ERROR, "creating fds: %s", strerror(errno)); - new_client(master, &id, handle_channeld, fds[0]); + new_client(master, &id, HSM_CAP_ECDH | HSM_CAP_SIGN_GOSSIP, handle_channeld, fds[0]); daemon_conn_send(master, take(towire_hsmctl_hsmfd_channeld_reply(master))); daemon_conn_send_fd(master, fds[1]); @@ -661,6 +742,9 @@ static struct io_plan *control_received_req(struct io_conn *conn, case WIRE_HSMCTL_INIT: init_hsm(master, master->msg_in); return daemon_conn_read_next(conn, master); + case WIRE_HSMCTL_CLIENT_HSMFD: + pass_client_hsmfd(master, master->msg_in); + return daemon_conn_read_next(conn, master); case WIRE_HSMCTL_HSMFD_ECDH: pass_hsmfd_ecdh(master, master->msg_in); return daemon_conn_read_next(conn, master); @@ -684,6 +768,7 @@ static struct io_plan *control_received_req(struct io_conn *conn, return daemon_conn_read_next(conn, master); case WIRE_HSMCTL_INIT_REPLY: + case WIRE_HSMCTL_CLIENT_HSMFD_REPLY: case WIRE_HSMCTL_HSMFD_ECDH_FD_REPLY: case WIRE_HSMCTL_HSMFD_CHANNELD_REPLY: case WIRE_HSMCTL_SIGN_FUNDING_REPLY: diff --git a/hsmd/hsm_wire.csv b/hsmd/hsm_wire.csv index c9b92d13d..c3f03a6bd 100644 --- a/hsmd/hsm_wire.csv +++ b/hsmd/hsm_wire.csv @@ -14,6 +14,14 @@ hsmctl_init_reply,,node_id,struct pubkey hsmctl_init_reply,,peer_seed,struct secret hsmctl_init_reply,,bip32,struct ext_key +# Get a new HSM FD, with the specified capabilities +hsmctl_client_hsmfd,9 +hsmctl_client_hsmfd,,pubkey,struct pubkey # Which identity to report for requests +hsmctl_client_hsmfd,,capabilities,u64 + +# No content, just an fd. +hsmctl_client_hsmfd_reply,109 + # ECDH returns an fd (for gossipd to do handshake) hsmctl_hsmfd_ecdh,3