Skip to content

Commit

Permalink
hsmd: Create derive_secret and makesecret RPC for deriving pseudorand…
Browse files Browse the repository at this point in the history
…om keys from HSM
  • Loading branch information
adi2011 authored and niftynei committed Jul 14, 2022
1 parent ba7d4a8 commit 64c03f8
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 1 deletion.
2 changes: 2 additions & 0 deletions hsmd/hsmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down
8 changes: 8 additions & 0 deletions hsmd/hsmd_wire.csv
Original file line number Diff line number Diff line change
Expand Up @@ -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
31 changes: 30 additions & 1 deletion hsmd/libhsmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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? */
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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!
*/
Expand Down
41 changes: 41 additions & 0 deletions lightningd/hsm_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
#include <common/ecdh.h>
#include <common/errcode.h>
#include <common/hsm_encryption.h>
#include <common/json_command.h>
#include <common/json_helpers.h>
#include <common/json_tok.h>
#include <common/param.h>
#include <common/type_to_string.h>
#include <errno.h>
Expand Down Expand Up @@ -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"? */
Expand Down

0 comments on commit 64c03f8

Please sign in to comment.