From 64c03f8990707247996846899c56448481d99fe9 Mon Sep 17 00:00:00 2001 From: adi2011 Date: Fri, 24 Jun 2022 05:49:09 +0530 Subject: [PATCH] hsmd: Create derive_secret and makesecret RPC for deriving pseudorandom keys from HSM --- hsmd/hsmd.c | 2 ++ hsmd/hsmd_wire.csv | 8 ++++++++ hsmd/libhsmd.c | 31 +++++++++++++++++++++++++++++- lightningd/hsm_control.c | 41 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 0c354a7ed..85875bf30 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -660,6 +660,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) case WIRE_HSMD_ECDH_REQ: case WIRE_HSMD_CHECK_FUTURE_SECRET: case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY: + case WIRE_HSMD_DERIVE_SECRET: case WIRE_HSMD_CANNOUNCEMENT_SIG_REQ: case WIRE_HSMD_NODE_ANNOUNCEMENT_SIG_REQ: case WIRE_HSMD_CUPDATE_SIG_REQ: @@ -681,6 +682,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: + case WIRE_HSMD_DERIVE_SECRET_REPLY: case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST: case WIRE_HSMD_SIGN_COMMITMENT_TX_REPLY: case WIRE_HSMD_VALIDATE_COMMITMENT_TX_REPLY: diff --git a/hsmd/hsmd_wire.csv b/hsmd/hsmd_wire.csv index a62edce8c..26d552e5b 100644 --- a/hsmd/hsmd_wire.csv +++ b/hsmd/hsmd_wire.csv @@ -281,3 +281,11 @@ msgdata,hsmd_sign_option_will_fund_offer,channel_fee_proportional_basis_max,u16, msgtype,hsmd_sign_option_will_fund_offer_reply,126 msgdata,hsmd_sign_option_will_fund_offer_reply,rsig,secp256k1_ecdsa_signature, + +# Reply with the derived secret +msgtype,hsmd_derive_secret_reply,27 +msgdata,hsmd_derive_secret_reply,secret,secret, + +msgtype,hsmd_derive_secret,127 +msgdata,hsmd_derive_secret,len,u16, +msgdata,hsmd_derive_secret,info,u8,len diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index 84f78de34..a641e3f87 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -23,11 +23,13 @@ struct secret *dev_force_bip32_seed; #endif /*~ Nobody will ever find it here! hsm_secret is our root secret, the bip32 - * tree and bolt12 payer_id keys are derived from that, and cached here. */ + * tree, bolt12 payer_id keys and derived_secret are derived from that, and + * cached here. */ struct { struct secret hsm_secret; struct ext_key bip32; secp256k1_keypair bolt12; + struct secret derived_secret; } secretstuff; /* Have we initialized the secretstuff? */ @@ -117,6 +119,7 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client, case WIRE_HSMD_SIGN_MESSAGE: case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY: case WIRE_HSMD_SIGN_BOLT12: + case WIRE_HSMD_DERIVE_SECRET: return (client->capabilities & HSM_CAP_MASTER) != 0; /*~ These are messages sent by the HSM so we should never receive them. */ @@ -145,6 +148,7 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client, case WIRE_HSMD_SIGN_MESSAGE_REPLY: case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY: case WIRE_HSMD_SIGN_BOLT12_REPLY: + case WIRE_HSMD_DERIVE_SECRET_REPLY: break; } return false; @@ -257,6 +261,22 @@ static void hsm_channel_secret_base(struct secret *channel_seed_base) "peer seed", strlen("peer seed")); } +/* This will derive pseudorandom secret Key from a derived key */ +static u8 *handle_derive_secret(struct hsmd_client *c, const u8 *msg_in) +{ + u8 *info; + struct secret secret; + + if (!fromwire_hsmd_derive_secret(tmpctx, msg_in, &info)) + return hsmd_status_malformed_request(c, msg_in); + + hkdf_sha256(&secret, sizeof(struct secret), NULL, 0, + &secretstuff.derived_secret, sizeof(&secretstuff.derived_secret), + info, tal_bytelen(info)); + + return towire_hsmd_derive_secret_reply(NULL, &secret); +} + /*~ This gets the seed for this particular channel. */ static void get_channel_seed(const struct node_id *peer_id, u64 dbid, struct secret *channel_seed) @@ -1593,9 +1613,12 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client, return handle_sign_remote_htlc_to_us(client, msg); case WIRE_HSMD_SIGN_DELAYED_PAYMENT_TO_US: return handle_sign_delayed_payment_to_us(client, msg); + case WIRE_HSMD_DERIVE_SECRET: + return handle_derive_secret(client, msg); case WIRE_HSMD_DEV_MEMLEAK: case WIRE_HSMD_ECDH_RESP: + case WIRE_HSMD_DERIVE_SECRET_REPLY: case WIRE_HSMD_CANNOUNCEMENT_SIG_REPLY: case WIRE_HSMD_CUPDATE_SIG_REPLY: case WIRE_HSMD_CLIENT_HSMFD_REPLY: @@ -1760,6 +1783,12 @@ u8 *hsmd_init(struct secret hsm_secret, sizeof(secretstuff.hsm_secret), "onion reply secret", strlen("onion reply secret")); + /* We derive the derived_secret key for generating pseudorandom keys + * by taking input string from the makesecret RPC */ + hkdf_sha256(&secretstuff.derived_secret, sizeof(struct secret), NULL, 0, + &secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret), + "derived secrets", strlen("derived secrets")); + /*~ Note: marshalling a bip32 tree only marshals the public side, * not the secrets! So we're not actually handing them out here! */ diff --git a/lightningd/hsm_control.c b/lightningd/hsm_control.c index 9a49c03df..d5f6413a9 100644 --- a/lightningd/hsm_control.c +++ b/lightningd/hsm_control.c @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -146,6 +148,45 @@ static struct command_result *json_getsharedsecret(struct command *cmd, return command_success(cmd, response); } +static struct command_result *json_makesecret(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + u8 *info; + struct json_stream *response; + struct secret secret; + + if (!param(cmd, buffer, params, + p_req("info_hex", param_bin_from_hex, &info), + NULL)) + return command_param_failed(); + + u8 *msg = towire_hsmd_derive_secret(cmd, info); + if (!wire_sync_write(cmd->ld->hsm_fd, take(msg))) + return command_fail(cmd, LIGHTNINGD, + "Could not write to HSM: %s", strerror(errno)); + + + msg = wire_sync_read(tmpctx, cmd->ld->hsm_fd); + if (!fromwire_hsmd_derive_secret_reply(msg, &secret)) + return command_fail(cmd, LIGHTNINGD, + "Bad reply from HSM: %s", strerror(errno)); + + + response = json_stream_success(cmd); + json_add_secret(response, "secret", &secret); + return command_success(cmd, response); +} + +static const struct json_command makesecret_command = { + "makesecret", + "utility", + &json_makesecret, + "Get a pseudorandom secret key, using an info string." +}; +AUTODATA(json_command, &makesecret_command); + static const struct json_command getsharedsecret_command = { "getsharedsecret", "utility", /* FIXME: Or "crypto"? */