diff --git a/common/hsm_version.h b/common/hsm_version.h index 38a54d7b3..6407f262f 100644 --- a/common/hsm_version.h +++ b/common/hsm_version.h @@ -10,7 +10,8 @@ * v2: dd89bf9323dff42200003fb864abb6608f3aa645b636fdae3ec81d804ac05196 * v3: edd3d288fc88a5470adc2f99abcbfe4d4af29fae0c7a80b4226f28810a815524 * v3 without v1: 3f813898f7de490e9126ab817e1c9a29af79c0413d5e37068acedce3ea7b5429 + * v4: 41a730986c51b930e2d8d12b3169d24966c2004e08d424bdda310edbbde5ba70 */ #define HSM_MIN_VERSION 3 -#define HSM_MAX_VERSION 3 +#define HSM_MAX_VERSION 4 #endif /* LIGHTNING_COMMON_HSM_VERSION_H */ diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 833725599..f4459f3f6 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -695,6 +695,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) case WIRE_HSMD_SIGN_WITHDRAWAL_REPLY: case WIRE_HSMD_SIGN_INVOICE_REPLY: case WIRE_HSMD_INIT_REPLY_V2: + case WIRE_HSMD_INIT_REPLY_V4: case WIRE_HSMD_DERIVE_SECRET_REPLY: case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST: case WIRE_HSMD_SIGN_COMMITMENT_TX_REPLY: diff --git a/hsmd/hsmd_wire.csv b/hsmd/hsmd_wire.csv index 05a5bc6a7..ac6fa86e8 100644 --- a/hsmd/hsmd_wire.csv +++ b/hsmd/hsmd_wire.csv @@ -19,11 +19,25 @@ msgdata,hsmd_init,hsm_wire_min_version,u32, msgdata,hsmd_init,hsm_wire_max_version,u32, #include +# DEPRECATED after 23.05, remove in two versions! msgtype,hsmd_init_reply_v2,113 msgdata,hsmd_init_reply_v2,node_id,node_id, msgdata,hsmd_init_reply_v2,bip32,ext_key, msgdata,hsmd_init_reply_v2,bolt12,pubkey, +# Sorry: I should have put version in v2 :( +msgtype,hsmd_init_reply_v4,114 +# This gets upgraded when the wire protocol changes in incompatible +# ways: +msgdata,hsmd_init_reply_v4,hsm_version,u32, +# Capabilities, by convention are message numbers, indicating +# that the HSM supports you sending this message. +msgdata,hsmd_init_reply_v4,num_hsm_capabilities,u16, +msgdata,hsmd_init_reply_v4,hsm_capabilities,u32,num_hsm_capabilities +msgdata,hsmd_init_reply_v4,node_id,node_id, +msgdata,hsmd_init_reply_v4,bip32,ext_key, +msgdata,hsmd_init_reply_v4,bolt12,pubkey, + # Declare a new channel. msgtype,hsmd_new_channel,30 msgdata,hsmd_new_channel,id,node_id, diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index d04f7e84a..0a362f1b5 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -137,6 +137,7 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client, case WIRE_HSMD_SIGN_WITHDRAWAL_REPLY: case WIRE_HSMD_SIGN_INVOICE_REPLY: case WIRE_HSMD_INIT_REPLY_V2: + case WIRE_HSMD_INIT_REPLY_V4: case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST: case WIRE_HSMD_SIGN_COMMITMENT_TX_REPLY: case WIRE_HSMD_VALIDATE_COMMITMENT_TX_REPLY: @@ -1662,6 +1663,7 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client, case WIRE_HSMD_SIGN_WITHDRAWAL_REPLY: case WIRE_HSMD_SIGN_INVOICE_REPLY: case WIRE_HSMD_INIT_REPLY_V2: + case WIRE_HSMD_INIT_REPLY_V4: case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST: case WIRE_HSMD_SIGN_COMMITMENT_TX_REPLY: case WIRE_HSMD_VALIDATE_COMMITMENT_TX_REPLY: @@ -1815,8 +1817,11 @@ u8 *hsmd_init(struct secret hsm_secret, /*~ Note: marshalling a bip32 tree only marshals the public side, * not the secrets! So we're not actually handing them out here! + * + * And version is 4: we offer limited compatibility (or at least, + * incompatibility detection) with alternate implementations. */ - return take(towire_hsmd_init_reply_v2( - NULL, &node_id, &secretstuff.bip32, - &bolt12)); + return take(towire_hsmd_init_reply_v4( + NULL, 4, NULL, &node_id, &secretstuff.bip32, + &bolt12)); } diff --git a/lightningd/hsm_control.c b/lightningd/hsm_control.c index bdc8a2097..d35dc9453 100644 --- a/lightningd/hsm_control.c +++ b/lightningd/hsm_control.c @@ -77,11 +77,23 @@ static unsigned int hsm_msg(struct subd *hsmd, return 0; } +/* Is this capability supported by the HSM? (So far, always a message + * number) */ +bool hsm_capable(struct lightningd *ld, u32 msgtype) +{ + for (size_t i = 0; i < tal_count(ld->hsm_capabilities); i++) { + if (ld->hsm_capabilities[i] == msgtype) + return true; + } + return false; +} + struct ext_key *hsm_init(struct lightningd *ld) { u8 *msg; int fds[2]; struct ext_key *bip32_base; + u32 hsm_version; /* We actually send requests synchronously: only status is async. */ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) != 0) @@ -118,14 +130,39 @@ struct ext_key *hsm_init(struct lightningd *ld) bip32_base = tal(ld, struct ext_key); msg = wire_sync_read(tmpctx, ld->hsm_fd); - if (!fromwire_hsmd_init_reply_v2(msg, - &ld->id, bip32_base, - &ld->bolt12_base)) { + if (fromwire_hsmd_init_reply_v4(ld, msg, + &hsm_version, + &ld->hsm_capabilities, + &ld->id, bip32_base, + &ld->bolt12_base)) { + /* nothing to do. */ + } else if (fromwire_hsmd_init_reply_v2(msg, + &ld->id, bip32_base, + &ld->bolt12_base)) { + /* implicit version */ + hsm_version = 3; + ld->hsm_capabilities = NULL; + } else { if (ld->config.keypass) errx(EXITCODE_HSM_BAD_PASSWORD, "Wrong password for encrypted hsm_secret."); errx(EXITCODE_HSM_GENERIC_ERROR, "HSM did not give init reply"); } + if (hsm_version < HSM_MIN_VERSION) + errx(EXITCODE_HSM_GENERIC_ERROR, + "HSM version %u below minimum %u", + hsm_version, HSM_MIN_VERSION); + if (hsm_version > HSM_MAX_VERSION) + errx(EXITCODE_HSM_GENERIC_ERROR, + "HSM version %u above maximum %u", + hsm_version, HSM_MAX_VERSION); + + /* Debugging help */ + for (size_t i = 0; i < tal_count(ld->hsm_capabilities); i++) { + log_debug(ld->hsm->log, "capability +%s", + hsmd_wire_name(ld->hsm_capabilities[i])); + } + /* This is equivalent to makesecret("bolt12-invoice-base") */ msg = towire_hsmd_derive_secret(NULL, tal_dup_arr(tmpctx, u8, (const u8 *)INVOICE_PATH_BASE_STRING, diff --git a/lightningd/hsm_control.h b/lightningd/hsm_control.h index e32326c7c..ffef42a81 100644 --- a/lightningd/hsm_control.h +++ b/lightningd/hsm_control.h @@ -16,5 +16,9 @@ int hsm_get_client_fd(struct lightningd *ld, /* Ask HSM for an fd for a global subdaemon to use (gossipd, connectd) */ int hsm_get_global_fd(struct lightningd *ld, int capabilities); +/* Is this capability supported by the HSM? (So far, always a message + * number) */ +bool hsm_capable(struct lightningd *ld, u32 msgtype); + struct ext_key *hsm_init(struct lightningd *ld); #endif /* LIGHTNING_LIGHTNINGD_HSM_CONTROL_H */ diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index e0d27b189..2eeaa48ae 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -319,6 +319,8 @@ struct lightningd { char *wallet_dsn; bool encrypted_hsm; + /* What (additional) messages the HSM accepts */ + u32 *hsm_capabilities; mode_t initial_umask; diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 4f00783fe..a42a8f722 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -1951,6 +1951,7 @@ int main(int argc, const char *argv[]) ld = tal(tmpctx, struct lightningd); ld->config = test_config; + ld->hsm_capabilities = NULL; /* Only elements in ld we should access */ ld->peers = tal(ld, struct peer_node_id_map);