2021-04-21 20:45:12 +02:00
|
|
|
|
#include <bitcoin/script.h>
|
2021-04-20 22:41:33 +02:00
|
|
|
|
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
|
2021-04-21 15:13:04 +02:00
|
|
|
|
#include <common/bolt12_merkle.h>
|
2021-04-21 15:46:04 +02:00
|
|
|
|
#include <common/hash_u5.h>
|
2021-04-21 20:45:12 +02:00
|
|
|
|
#include <common/key_derive.h>
|
2021-04-13 17:25:29 +02:00
|
|
|
|
#include <hsmd/capabilities.h>
|
|
|
|
|
#include <hsmd/libhsmd.h>
|
2021-04-21 20:49:50 +02:00
|
|
|
|
#include <wire/peer_wire.h>
|
2021-04-13 17:25:29 +02:00
|
|
|
|
|
|
|
|
|
/* Version codes for BIP32 extended keys in libwally-core.
|
|
|
|
|
* It's not suitable to add this struct into client struct,
|
|
|
|
|
* so set it static.*/
|
|
|
|
|
struct bip32_key_version bip32_key_version;
|
|
|
|
|
|
|
|
|
|
#if DEVELOPER
|
|
|
|
|
/* If they specify --dev-force-privkey it ends up in here. */
|
|
|
|
|
struct privkey *dev_force_privkey;
|
|
|
|
|
/* If they specify --dev-force-bip32-seed it ends up in here. */
|
|
|
|
|
struct secret *dev_force_bip32_seed;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Have we initialized the secretstuff? */
|
|
|
|
|
bool initialized = false;
|
|
|
|
|
|
|
|
|
|
struct hsmd_client *hsmd_client_new_main(const tal_t *ctx, u64 capabilities,
|
|
|
|
|
void *extra)
|
|
|
|
|
{
|
|
|
|
|
struct hsmd_client *c = tal(ctx, struct hsmd_client);
|
|
|
|
|
c->dbid = 0;
|
|
|
|
|
c->capabilities = capabilities;
|
|
|
|
|
c->extra = extra;
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct hsmd_client *hsmd_client_new_peer(const tal_t *ctx, u64 capabilities,
|
|
|
|
|
u64 dbid,
|
|
|
|
|
const struct node_id *peer_id,
|
|
|
|
|
void *extra)
|
|
|
|
|
{
|
|
|
|
|
struct hsmd_client *c = tal(ctx, struct hsmd_client);
|
|
|
|
|
c->dbid = dbid;
|
|
|
|
|
c->capabilities = capabilities;
|
|
|
|
|
c->id = *peer_id;
|
|
|
|
|
c->extra = extra;
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-20 22:33:27 +02:00
|
|
|
|
/*~ This routine checks that a client is allowed to call the handler. */
|
|
|
|
|
bool check_client_capabilities(struct hsmd_client *client, enum hsmd_wire t)
|
|
|
|
|
{
|
|
|
|
|
/*~ Here's a useful trick: enums in C are not real types, they're
|
|
|
|
|
* semantic sugar sprinkled over an int, bascally (in fact, older
|
|
|
|
|
* versions of gcc used to convert the values ints in the parser!).
|
|
|
|
|
*
|
|
|
|
|
* But GCC will do one thing for us: if we have a switch statement
|
|
|
|
|
* with a controlling expression which is an enum, it will warn us
|
|
|
|
|
* if a declared enum value is *not* handled in the switch, eg:
|
|
|
|
|
* enumeration value ‘FOOBAR’ not handled in switch [-Werror=switch]
|
|
|
|
|
*
|
|
|
|
|
* This only works if there's no 'default' label, which is sometimes
|
|
|
|
|
* hard, as we *can* have non-enum values in our enum. But the tradeoff
|
|
|
|
|
* is worth it so the compiler tells us everywhere we have to fix when
|
|
|
|
|
* we add a new enum identifier!
|
|
|
|
|
*/
|
|
|
|
|
switch (t) {
|
|
|
|
|
case WIRE_HSMD_ECDH_REQ:
|
|
|
|
|
return (client->capabilities & HSM_CAP_ECDH) != 0;
|
|
|
|
|
|
|
|
|
|
case WIRE_HSMD_CANNOUNCEMENT_SIG_REQ:
|
|
|
|
|
case WIRE_HSMD_CUPDATE_SIG_REQ:
|
|
|
|
|
case WIRE_HSMD_NODE_ANNOUNCEMENT_SIG_REQ:
|
|
|
|
|
return (client->capabilities & HSM_CAP_SIGN_GOSSIP) != 0;
|
|
|
|
|
|
|
|
|
|
case WIRE_HSMD_SIGN_DELAYED_PAYMENT_TO_US:
|
|
|
|
|
case WIRE_HSMD_SIGN_REMOTE_HTLC_TO_US:
|
|
|
|
|
case WIRE_HSMD_SIGN_PENALTY_TO_US:
|
|
|
|
|
case WIRE_HSMD_SIGN_LOCAL_HTLC_TX:
|
|
|
|
|
return (client->capabilities & HSM_CAP_SIGN_ONCHAIN_TX) != 0;
|
|
|
|
|
|
|
|
|
|
case WIRE_HSMD_GET_PER_COMMITMENT_POINT:
|
|
|
|
|
case WIRE_HSMD_CHECK_FUTURE_SECRET:
|
|
|
|
|
return (client->capabilities & HSM_CAP_COMMITMENT_POINT) != 0;
|
|
|
|
|
|
|
|
|
|
case WIRE_HSMD_SIGN_REMOTE_COMMITMENT_TX:
|
|
|
|
|
case WIRE_HSMD_SIGN_REMOTE_HTLC_TX:
|
|
|
|
|
return (client->capabilities & HSM_CAP_SIGN_REMOTE_TX) != 0;
|
|
|
|
|
|
|
|
|
|
case WIRE_HSMD_SIGN_MUTUAL_CLOSE_TX:
|
|
|
|
|
return (client->capabilities & HSM_CAP_SIGN_CLOSING_TX) != 0;
|
|
|
|
|
|
|
|
|
|
case WIRE_HSMD_INIT:
|
|
|
|
|
case WIRE_HSMD_CLIENT_HSMFD:
|
|
|
|
|
case WIRE_HSMD_SIGN_WITHDRAWAL:
|
|
|
|
|
case WIRE_HSMD_SIGN_INVOICE:
|
|
|
|
|
case WIRE_HSMD_SIGN_COMMITMENT_TX:
|
|
|
|
|
case WIRE_HSMD_GET_CHANNEL_BASEPOINTS:
|
|
|
|
|
case WIRE_HSMD_DEV_MEMLEAK:
|
|
|
|
|
case WIRE_HSMD_SIGN_MESSAGE:
|
|
|
|
|
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY:
|
|
|
|
|
case WIRE_HSMD_SIGN_BOLT12:
|
|
|
|
|
return (client->capabilities & HSM_CAP_MASTER) != 0;
|
|
|
|
|
|
|
|
|
|
/*~ These are messages sent by the HSM so we should never receive them. */
|
|
|
|
|
/* FIXME: Since we autogenerate these, we should really generate separate
|
|
|
|
|
* enums for replies to avoid this kind of clutter! */
|
|
|
|
|
case WIRE_HSMD_ECDH_RESP:
|
|
|
|
|
case WIRE_HSMD_CANNOUNCEMENT_SIG_REPLY:
|
|
|
|
|
case WIRE_HSMD_CUPDATE_SIG_REPLY:
|
|
|
|
|
case WIRE_HSMD_CLIENT_HSMFD_REPLY:
|
|
|
|
|
case WIRE_HSMD_NODE_ANNOUNCEMENT_SIG_REPLY:
|
|
|
|
|
case WIRE_HSMD_SIGN_WITHDRAWAL_REPLY:
|
|
|
|
|
case WIRE_HSMD_SIGN_INVOICE_REPLY:
|
|
|
|
|
case WIRE_HSMD_INIT_REPLY:
|
|
|
|
|
case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST:
|
|
|
|
|
case WIRE_HSMD_SIGN_COMMITMENT_TX_REPLY:
|
|
|
|
|
case WIRE_HSMD_SIGN_TX_REPLY:
|
|
|
|
|
case WIRE_HSMD_GET_PER_COMMITMENT_POINT_REPLY:
|
|
|
|
|
case WIRE_HSMD_CHECK_FUTURE_SECRET_REPLY:
|
|
|
|
|
case WIRE_HSMD_GET_CHANNEL_BASEPOINTS_REPLY:
|
|
|
|
|
case WIRE_HSMD_DEV_MEMLEAK_REPLY:
|
|
|
|
|
case WIRE_HSMD_SIGN_MESSAGE_REPLY:
|
|
|
|
|
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY:
|
|
|
|
|
case WIRE_HSMD_SIGN_BOLT12_REPLY:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-20 22:37:07 +02:00
|
|
|
|
/*~ ccan/compiler.h defines PRINTF_FMT as the gcc compiler hint so it will
|
|
|
|
|
* check that fmt and other trailing arguments really are the correct type.
|
|
|
|
|
*/
|
|
|
|
|
/* This function is used to format an error message before passing it
|
|
|
|
|
* to the library user specified hsmd_status_bad_request */
|
2021-04-20 22:41:33 +02:00
|
|
|
|
static u8 *hsmd_status_bad_request_fmt(struct hsmd_client *client,
|
|
|
|
|
const u8 *msg, const char *fmt, ...)
|
|
|
|
|
PRINTF_FMT(3, 4);
|
2021-04-20 22:37:07 +02:00
|
|
|
|
|
2021-04-20 22:41:33 +02:00
|
|
|
|
static u8 *hsmd_status_bad_request_fmt(struct hsmd_client *client,
|
|
|
|
|
const u8 *msg, const char *fmt, ...)
|
2021-04-20 22:37:07 +02:00
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
str = tal_fmt(tmpctx, fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
return hsmd_status_bad_request(client, msg, str);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-20 22:41:33 +02:00
|
|
|
|
/* Convenience wrapper for when we simply can't parse. */
|
|
|
|
|
static u8 *hsmd_status_malformed_request(struct hsmd_client *c, const u8 *msg_in)
|
|
|
|
|
{
|
|
|
|
|
return hsmd_status_bad_request(c, msg_in, "could not parse request");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*~ This returns the secret and/or public key for this node. */
|
|
|
|
|
static void node_key(struct privkey *node_privkey, struct pubkey *node_id)
|
|
|
|
|
{
|
|
|
|
|
u32 salt = 0;
|
|
|
|
|
struct privkey unused_s;
|
|
|
|
|
struct pubkey unused_k;
|
|
|
|
|
|
|
|
|
|
/* If caller specifies NULL, they don't want the results. */
|
|
|
|
|
if (node_privkey == NULL)
|
|
|
|
|
node_privkey = &unused_s;
|
|
|
|
|
if (node_id == NULL)
|
|
|
|
|
node_id = &unused_k;
|
|
|
|
|
|
|
|
|
|
/*~ So, there is apparently a 1 in 2^127 chance that a random value is
|
|
|
|
|
* not a valid private key, so this never actually loops. */
|
|
|
|
|
do {
|
|
|
|
|
/*~ ccan/crypto/hkdf_sha256 implements RFC5869 "Hardened Key
|
|
|
|
|
* Derivation Functions". That means that if a derived key
|
|
|
|
|
* leaks somehow, the other keys are not compromised. */
|
|
|
|
|
hkdf_sha256(node_privkey, sizeof(*node_privkey),
|
|
|
|
|
&salt, sizeof(salt),
|
|
|
|
|
&secretstuff.hsm_secret,
|
|
|
|
|
sizeof(secretstuff.hsm_secret),
|
|
|
|
|
"nodeid", 6);
|
|
|
|
|
salt++;
|
|
|
|
|
} while (!secp256k1_ec_pubkey_create(secp256k1_ctx, &node_id->pubkey,
|
|
|
|
|
node_privkey->secret.data));
|
|
|
|
|
|
|
|
|
|
#if DEVELOPER
|
|
|
|
|
/* In DEVELOPER mode, we can override with --dev-force-privkey */
|
|
|
|
|
if (dev_force_privkey) {
|
|
|
|
|
*node_privkey = *dev_force_privkey;
|
|
|
|
|
if (!secp256k1_ec_pubkey_create(secp256k1_ctx, &node_id->pubkey,
|
|
|
|
|
node_privkey->secret.data))
|
|
|
|
|
hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
|
|
|
|
"Failed to derive pubkey for dev_force_privkey");
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 15:13:04 +02:00
|
|
|
|
/*~ This returns the secret and/or public x-only key for this node. */
|
|
|
|
|
static void node_schnorrkey(secp256k1_keypair *node_keypair,
|
|
|
|
|
struct pubkey32 *node_id32)
|
|
|
|
|
{
|
|
|
|
|
secp256k1_keypair unused_kp;
|
|
|
|
|
struct privkey node_privkey;
|
|
|
|
|
|
|
|
|
|
if (!node_keypair)
|
|
|
|
|
node_keypair = &unused_kp;
|
|
|
|
|
|
|
|
|
|
node_key(&node_privkey, NULL);
|
|
|
|
|
if (secp256k1_keypair_create(secp256k1_ctx, node_keypair,
|
|
|
|
|
node_privkey.secret.data) != 1)
|
|
|
|
|
hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
|
|
|
|
"Failed to derive keypair");
|
|
|
|
|
|
|
|
|
|
if (node_id32) {
|
|
|
|
|
if (secp256k1_keypair_xonly_pub(secp256k1_ctx,
|
|
|
|
|
&node_id32->pubkey,
|
|
|
|
|
NULL, node_keypair) != 1)
|
|
|
|
|
hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
|
|
|
|
"Failed to derive xonly pub");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 18:41:20 +02:00
|
|
|
|
/*~ This secret is the basis for all per-channel secrets: the per-channel seeds
|
|
|
|
|
* will be generated by mixing in the dbid and the peer node_id. */
|
|
|
|
|
static void hsm_channel_secret_base(struct secret *channel_seed_base)
|
|
|
|
|
{
|
|
|
|
|
hkdf_sha256(channel_seed_base, sizeof(struct secret), NULL, 0,
|
|
|
|
|
&secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret),
|
|
|
|
|
/*~ Initially, we didn't support multiple channels per
|
|
|
|
|
* peer at all: a channel had to be completely forgotten
|
|
|
|
|
* before another could exist. That was slightly relaxed,
|
|
|
|
|
* but the phrase "peer seed" is wired into the seed
|
|
|
|
|
* generation here, so we need to keep it that way for
|
|
|
|
|
* existing clients, rather than using "channel seed". */
|
|
|
|
|
"peer seed", strlen("peer seed"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*~ 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)
|
|
|
|
|
{
|
|
|
|
|
struct secret channel_base;
|
|
|
|
|
u8 input[sizeof(peer_id->k) + sizeof(dbid)];
|
|
|
|
|
/*~ Again, "per-peer" should be "per-channel", but Hysterical Raisins */
|
|
|
|
|
const char *info = "per-peer seed";
|
|
|
|
|
|
|
|
|
|
/*~ We use the DER encoding of the pubkey, because it's platform
|
|
|
|
|
* independent. Since the dbid is unique, however, it's completely
|
|
|
|
|
* unnecessary, but again, existing users can't be broken. */
|
|
|
|
|
/* FIXME: lnd has a nicer BIP32 method for deriving secrets which we
|
|
|
|
|
* should migrate to. */
|
|
|
|
|
hsm_channel_secret_base(&channel_base);
|
|
|
|
|
memcpy(input, peer_id->k, sizeof(peer_id->k));
|
|
|
|
|
BUILD_ASSERT(sizeof(peer_id->k) == PUBKEY_CMPR_LEN);
|
|
|
|
|
/*~ For all that talk about platform-independence, note that this
|
|
|
|
|
* field is endian-dependent! But let's face it, little-endian won.
|
|
|
|
|
* In related news, we don't support EBCDIC or middle-endian. */
|
|
|
|
|
memcpy(input + PUBKEY_CMPR_LEN, &dbid, sizeof(dbid));
|
|
|
|
|
|
|
|
|
|
hkdf_sha256(channel_seed, sizeof(*channel_seed),
|
|
|
|
|
input, sizeof(input),
|
|
|
|
|
&channel_base, sizeof(channel_base),
|
|
|
|
|
info, strlen(info));
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 20:45:12 +02:00
|
|
|
|
/*~ For almost every wallet tx we use the BIP32 seed, but not for onchain
|
|
|
|
|
* unilateral closes from a peer: they (may) have an output to us using a
|
|
|
|
|
* public key based on the channel basepoints. It's a bit spammy to spend
|
|
|
|
|
* those immediately just to make the wallet simpler, and we didn't appreciate
|
|
|
|
|
* the problem when we designed the protocol for commitment transaction keys.
|
|
|
|
|
*
|
|
|
|
|
* So we store just enough about the channel it came from (which may be
|
|
|
|
|
* long-gone) to regenerate the keys here. That has the added advantage that
|
|
|
|
|
* the secrets themselves stay within the HSM. */
|
|
|
|
|
static void hsm_unilateral_close_privkey(struct privkey *dst,
|
|
|
|
|
struct unilateral_close_info *info)
|
|
|
|
|
{
|
|
|
|
|
struct secret channel_seed;
|
|
|
|
|
struct basepoints basepoints;
|
|
|
|
|
struct secrets secrets;
|
|
|
|
|
|
|
|
|
|
get_channel_seed(&info->peer_id, info->channel_id, &channel_seed);
|
|
|
|
|
derive_basepoints(&channel_seed, NULL, &basepoints, &secrets, NULL);
|
|
|
|
|
|
|
|
|
|
/* BOLT #3:
|
|
|
|
|
*
|
|
|
|
|
* If `option_static_remotekey` or `option_anchor_outputs` is
|
|
|
|
|
* negotiated, the `remotepubkey` is simply the remote node's
|
|
|
|
|
* `payment_basepoint`, otherwise it is calculated as above using the
|
|
|
|
|
* remote node's `payment_basepoint`.
|
|
|
|
|
*/
|
|
|
|
|
/* In our UTXO representation, this is indicated by a NULL
|
|
|
|
|
* commitment_point. */
|
|
|
|
|
if (!info->commitment_point)
|
|
|
|
|
dst->secret = secrets.payment_basepoint_secret;
|
|
|
|
|
else if (!derive_simple_privkey(&secrets.payment_basepoint_secret,
|
|
|
|
|
&basepoints.payment,
|
|
|
|
|
info->commitment_point,
|
|
|
|
|
dst)) {
|
|
|
|
|
hsmd_status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
|
|
|
|
"Deriving unilateral_close_privkey");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-20 22:41:33 +02:00
|
|
|
|
/*~ lightningd asks us to sign a message. I tweeted the spec
|
|
|
|
|
* in https://twitter.com/rusty_twit/status/1182102005914800128:
|
|
|
|
|
*
|
|
|
|
|
* @roasbeef & @bitconner point out that #lnd algo is:
|
|
|
|
|
* zbase32(SigRec(SHA256(SHA256("Lightning Signed Message:" + msg)))).
|
|
|
|
|
* zbase32 from https://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
|
|
|
|
|
* and SigRec has first byte 31 + recovery id, followed by 64 byte sig. #specinatweet
|
|
|
|
|
*/
|
|
|
|
|
static u8 *handle_sign_message(struct hsmd_client *c, const u8 *msg_in)
|
|
|
|
|
{
|
|
|
|
|
u8 *msg;
|
|
|
|
|
struct sha256_ctx sctx = SHA256_INIT;
|
|
|
|
|
struct sha256_double shad;
|
|
|
|
|
secp256k1_ecdsa_recoverable_signature rsig;
|
|
|
|
|
struct privkey node_pkey;
|
|
|
|
|
|
|
|
|
|
if (!fromwire_hsmd_sign_message(tmpctx, msg_in, &msg))
|
|
|
|
|
return hsmd_status_malformed_request(c, msg_in);
|
|
|
|
|
|
|
|
|
|
/* Prefixing by a known string means we'll never be convinced
|
|
|
|
|
* to sign some gossip message, etc. */
|
|
|
|
|
sha256_update(&sctx, "Lightning Signed Message:",
|
|
|
|
|
strlen("Lightning Signed Message:"));
|
|
|
|
|
sha256_update(&sctx, msg, tal_count(msg));
|
|
|
|
|
sha256_double_done(&sctx, &shad);
|
|
|
|
|
|
|
|
|
|
node_key(&node_pkey, NULL);
|
|
|
|
|
/*~ By no small coincidence, this libsecp routine uses the exact
|
|
|
|
|
* recovery signature format mandated by BOLT 11. */
|
|
|
|
|
if (!secp256k1_ecdsa_sign_recoverable(secp256k1_ctx, &rsig,
|
|
|
|
|
shad.sha.u.u8,
|
|
|
|
|
node_pkey.secret.data,
|
|
|
|
|
NULL, NULL)) {
|
|
|
|
|
return hsmd_status_bad_request(c, msg_in, "Failed to sign message");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return towire_hsmd_sign_message_reply(NULL, &rsig);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 15:13:04 +02:00
|
|
|
|
/*~ lightningd asks us to sign a bolt12 (e.g. offer). */
|
|
|
|
|
static u8 *handle_sign_bolt12(struct hsmd_client *c, const u8 *msg_in)
|
|
|
|
|
{
|
|
|
|
|
char *messagename, *fieldname;
|
|
|
|
|
struct sha256 merkle, sha;
|
|
|
|
|
struct bip340sig sig;
|
|
|
|
|
secp256k1_keypair kp;
|
|
|
|
|
u8 *publictweak;
|
|
|
|
|
|
|
|
|
|
if (!fromwire_hsmd_sign_bolt12(tmpctx, msg_in,
|
|
|
|
|
&messagename, &fieldname, &merkle,
|
|
|
|
|
&publictweak))
|
|
|
|
|
return hsmd_status_malformed_request(c, msg_in);
|
|
|
|
|
|
|
|
|
|
sighash_from_merkle(messagename, fieldname, &merkle, &sha);
|
|
|
|
|
|
|
|
|
|
if (!publictweak) {
|
|
|
|
|
node_schnorrkey(&kp, NULL);
|
|
|
|
|
} else {
|
|
|
|
|
/* If we're tweaking key, we use bolt12 key */
|
|
|
|
|
struct pubkey32 bolt12;
|
|
|
|
|
struct sha256 tweak;
|
|
|
|
|
|
|
|
|
|
if (secp256k1_keypair_xonly_pub(secp256k1_ctx,
|
|
|
|
|
&bolt12.pubkey, NULL,
|
|
|
|
|
&secretstuff.bolt12) != 1)
|
|
|
|
|
hsmd_status_failed(
|
|
|
|
|
STATUS_FAIL_INTERNAL_ERROR,
|
|
|
|
|
"Could not derive bolt12 public key.");
|
|
|
|
|
payer_key_tweak(&bolt12, publictweak, tal_bytelen(publictweak),
|
|
|
|
|
&tweak);
|
|
|
|
|
|
|
|
|
|
kp = secretstuff.bolt12;
|
|
|
|
|
|
|
|
|
|
if (secp256k1_keypair_xonly_tweak_add(secp256k1_ctx,
|
|
|
|
|
&kp,
|
|
|
|
|
tweak.u.u8) != 1) {
|
|
|
|
|
return hsmd_status_bad_request_fmt(
|
|
|
|
|
c, msg_in, "Failed to get tweak key");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!secp256k1_schnorrsig_sign(secp256k1_ctx, sig.u8,
|
|
|
|
|
sha.u.u8,
|
|
|
|
|
&kp,
|
|
|
|
|
NULL, NULL)) {
|
|
|
|
|
return hsmd_status_bad_request_fmt(c, msg_in,
|
|
|
|
|
"Failed to sign bolt12");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return towire_hsmd_sign_bolt12_reply(NULL, &sig);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 15:46:04 +02:00
|
|
|
|
/*~ Lightning invoices, defined by BOLT 11, are signed. This has been
|
|
|
|
|
* surprisingly controversial; it means a node needs to be online to create
|
|
|
|
|
* invoices. However, it seems clear to me that in a world without
|
|
|
|
|
* intermedaries you need proof that you have received an offer (the
|
|
|
|
|
* signature), as well as proof that you've paid it (the preimage). */
|
|
|
|
|
static u8 *handle_sign_invoice(struct hsmd_client *c, const u8 *msg_in)
|
|
|
|
|
{
|
|
|
|
|
/*~ We make up a 'u5' type to represent BOLT11's 5-bits-per-byte
|
|
|
|
|
* format: it's only for human consumption, as typedefs are almost
|
|
|
|
|
* entirely transparent to the C compiler. */
|
|
|
|
|
u5 *u5bytes;
|
|
|
|
|
u8 *hrpu8;
|
|
|
|
|
char *hrp;
|
|
|
|
|
struct sha256 sha;
|
|
|
|
|
secp256k1_ecdsa_recoverable_signature rsig;
|
|
|
|
|
struct hash_u5 hu5;
|
|
|
|
|
struct privkey node_pkey;
|
|
|
|
|
|
|
|
|
|
if (!fromwire_hsmd_sign_invoice(tmpctx, msg_in, &u5bytes, &hrpu8))
|
|
|
|
|
return hsmd_status_malformed_request(c, msg_in);
|
|
|
|
|
|
|
|
|
|
/* BOLT #11:
|
|
|
|
|
*
|
|
|
|
|
* A writer... MUST set `signature` to a valid 512-bit
|
|
|
|
|
* secp256k1 signature of the SHA2 256-bit hash of the
|
|
|
|
|
* human-readable part, represented as UTF-8 bytes,
|
|
|
|
|
* concatenated with the data part (excluding the signature)
|
|
|
|
|
* with 0 bits appended to pad the data to the next byte
|
|
|
|
|
* boundary, with a trailing byte containing the recovery ID
|
|
|
|
|
* (0, 1, 2, or 3).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* FIXME: Check invoice! */
|
|
|
|
|
|
|
|
|
|
/*~ tal_dup_arr() does what you'd expect: allocate an array by copying
|
|
|
|
|
* another; the cast is needed because the hrp is a 'char' array, not
|
|
|
|
|
* a 'u8' (unsigned char) as it's the "human readable" part.
|
|
|
|
|
*
|
|
|
|
|
* The final arg of tal_dup_arr() is how many extra bytes to allocate:
|
|
|
|
|
* it's so often zero that I've thought about dropping the argument, but
|
|
|
|
|
* in cases like this (adding a NUL terminator) it's perfect. */
|
|
|
|
|
hrp = tal_dup_arr(tmpctx, char, (char *)hrpu8, tal_count(hrpu8), 1);
|
|
|
|
|
hrp[tal_count(hrpu8)] = '\0';
|
|
|
|
|
|
|
|
|
|
hash_u5_init(&hu5, hrp);
|
|
|
|
|
hash_u5(&hu5, u5bytes, tal_count(u5bytes));
|
|
|
|
|
hash_u5_done(&hu5, &sha);
|
|
|
|
|
|
|
|
|
|
node_key(&node_pkey, NULL);
|
|
|
|
|
/*~ By no small coincidence, this libsecp routine uses the exact
|
|
|
|
|
* recovery signature format mandated by BOLT 11. */
|
|
|
|
|
if (!secp256k1_ecdsa_sign_recoverable(secp256k1_ctx, &rsig,
|
|
|
|
|
(const u8 *)&sha,
|
|
|
|
|
node_pkey.secret.data,
|
|
|
|
|
NULL, NULL)) {
|
|
|
|
|
return hsmd_status_bad_request_fmt(c, msg_in,
|
|
|
|
|
"Failed to sign invoice");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return towire_hsmd_sign_invoice_reply(NULL, &rsig);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 18:41:20 +02:00
|
|
|
|
/*~ This gets the basepoints for a channel; it's not private information really
|
|
|
|
|
* (we tell the peer this to establish a channel, as it sets up the keys used
|
|
|
|
|
* for each transaction).
|
|
|
|
|
*
|
|
|
|
|
* Note that this is asked by lightningd, so it tells us what channels it wants.
|
|
|
|
|
*/
|
|
|
|
|
static u8 *handle_get_channel_basepoints(struct hsmd_client *c,
|
|
|
|
|
const u8 *msg_in)
|
|
|
|
|
{
|
|
|
|
|
struct node_id peer_id;
|
|
|
|
|
u64 dbid;
|
|
|
|
|
struct secret seed;
|
|
|
|
|
struct basepoints basepoints;
|
|
|
|
|
struct pubkey funding_pubkey;
|
|
|
|
|
|
|
|
|
|
if (!fromwire_hsmd_get_channel_basepoints(msg_in, &peer_id, &dbid))
|
|
|
|
|
return hsmd_status_malformed_request(c, msg_in);
|
|
|
|
|
|
|
|
|
|
get_channel_seed(&peer_id, dbid, &seed);
|
|
|
|
|
derive_basepoints(&seed, &funding_pubkey, &basepoints, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
return towire_hsmd_get_channel_basepoints_reply(NULL, &basepoints,
|
|
|
|
|
&funding_pubkey);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 18:45:09 +02:00
|
|
|
|
/*~ The client has asked us to extract the shared secret from an EC Diffie
|
|
|
|
|
* Hellman token. This doesn't leak any information, but requires the private
|
|
|
|
|
* key, so the hsmd performs it. It's used to set up an encryption key for the
|
|
|
|
|
* connection handshaking (BOLT #8) and for the onion wrapping (BOLT #4). */
|
|
|
|
|
static u8 *handle_ecdh(struct hsmd_client *c, const u8 *msg_in)
|
|
|
|
|
{
|
|
|
|
|
struct privkey privkey;
|
|
|
|
|
struct pubkey point;
|
|
|
|
|
struct secret ss;
|
|
|
|
|
|
|
|
|
|
if (!fromwire_hsmd_ecdh_req(msg_in, &point))
|
|
|
|
|
return hsmd_status_malformed_request(c, msg_in);
|
|
|
|
|
|
|
|
|
|
/*~ We simply use the secp256k1_ecdh function: if privkey.secret.data is invalid,
|
|
|
|
|
* we kill them for bad randomness (~1 in 2^127 if privkey.secret.data is random) */
|
|
|
|
|
node_key(&privkey, NULL);
|
|
|
|
|
if (secp256k1_ecdh(secp256k1_ctx, ss.data, &point.pubkey,
|
|
|
|
|
privkey.secret.data, NULL, NULL) != 1) {
|
|
|
|
|
return hsmd_status_bad_request_fmt(c, msg_in,
|
|
|
|
|
"secp256k1_ecdh fail");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*~ In the normal case, we return the shared secret, and then read
|
|
|
|
|
* the next msg. */
|
|
|
|
|
return towire_hsmd_ecdh_resp(NULL, &ss);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 19:10:55 +02:00
|
|
|
|
/*~ This is used when the remote peer claims to have knowledge of future
|
|
|
|
|
* commitment states (option_data_loss_protect in the spec) which means we've
|
|
|
|
|
* been restored from backup or something, and may have already revealed
|
|
|
|
|
* secrets. We carefully check that this is true, here. */
|
|
|
|
|
static u8 *handle_check_future_secret(struct hsmd_client *c, const u8 *msg_in)
|
|
|
|
|
{
|
|
|
|
|
struct secret channel_seed;
|
|
|
|
|
struct sha256 shaseed;
|
|
|
|
|
u64 n;
|
|
|
|
|
struct secret secret, suggested;
|
|
|
|
|
|
|
|
|
|
if (!fromwire_hsmd_check_future_secret(msg_in, &n, &suggested))
|
|
|
|
|
return hsmd_status_malformed_request(c, msg_in);
|
|
|
|
|
|
|
|
|
|
get_channel_seed(&c->id, c->dbid, &channel_seed);
|
|
|
|
|
if (!derive_shaseed(&channel_seed, &shaseed))
|
|
|
|
|
return hsmd_status_bad_request_fmt(c, msg_in,
|
|
|
|
|
"bad derive_shaseed");
|
|
|
|
|
|
|
|
|
|
if (!per_commit_secret(&shaseed, &secret, n))
|
|
|
|
|
return hsmd_status_bad_request_fmt(
|
|
|
|
|
c, msg_in, "bad commit secret #%" PRIu64, n);
|
|
|
|
|
|
|
|
|
|
/*~ Note the special secret_eq_consttime: we generate foo_eq for many
|
|
|
|
|
* types using ccan/structeq, but not 'struct secret' because any
|
|
|
|
|
* comparison risks leaking information about the secret if it is
|
|
|
|
|
* timing dependent. */
|
|
|
|
|
return towire_hsmd_check_future_secret_reply(
|
|
|
|
|
NULL, secret_eq_consttime(&secret, &suggested));
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 20:45:12 +02:00
|
|
|
|
static u8 *handle_get_output_scriptpubkey(struct hsmd_client *c,
|
|
|
|
|
const u8 *msg_in)
|
|
|
|
|
{
|
|
|
|
|
struct pubkey pubkey;
|
|
|
|
|
struct privkey privkey;
|
|
|
|
|
struct unilateral_close_info info;
|
|
|
|
|
u8 *scriptPubkey;
|
|
|
|
|
|
|
|
|
|
info.commitment_point = NULL;
|
|
|
|
|
if (!fromwire_hsmd_get_output_scriptpubkey(tmpctx, msg_in,
|
|
|
|
|
&info.channel_id,
|
|
|
|
|
&info.peer_id,
|
|
|
|
|
&info.commitment_point))
|
|
|
|
|
return hsmd_status_malformed_request(c, msg_in);
|
|
|
|
|
|
|
|
|
|
hsm_unilateral_close_privkey(&privkey, &info);
|
|
|
|
|
pubkey_from_privkey(&privkey, &pubkey);
|
|
|
|
|
scriptPubkey = scriptpubkey_p2wpkh(tmpctx, &pubkey);
|
|
|
|
|
|
|
|
|
|
return towire_hsmd_get_output_scriptpubkey_reply(NULL,
|
|
|
|
|
scriptPubkey);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 20:49:50 +02:00
|
|
|
|
/*~ The specific routine to sign the channel_announcement message. This is
|
|
|
|
|
* defined in BOLT #7, and requires *two* signatures: one from this node's key
|
|
|
|
|
* (to prove it's from us), and one from the bitcoin key used to create the
|
|
|
|
|
* funding transaction (to prove we own the output). */
|
|
|
|
|
static u8 *handle_cannouncement_sig(struct hsmd_client *c, const u8 *msg_in)
|
|
|
|
|
{
|
|
|
|
|
/*~ Our autogeneration code doesn't define field offsets, so we just
|
|
|
|
|
* copy this from the spec itself.
|
|
|
|
|
*
|
|
|
|
|
* Note that 'check-source' will actually find and check this quote
|
|
|
|
|
* against the spec (if available); whitespace is ignored and
|
|
|
|
|
* "..." means some content is skipped, but it works remarkably well to
|
|
|
|
|
* track spec changes. */
|
|
|
|
|
|
|
|
|
|
/* BOLT #7:
|
|
|
|
|
*
|
|
|
|
|
* - MUST compute the double-SHA256 hash `h` of the message, beginning
|
|
|
|
|
* at offset 256, up to the end of the message.
|
|
|
|
|
* - Note: the hash skips the 4 signatures but hashes the rest of the
|
|
|
|
|
* message, including any future fields appended to the end.
|
|
|
|
|
*/
|
|
|
|
|
/* First type bytes are the msg type */
|
|
|
|
|
size_t offset = 2 + 256;
|
|
|
|
|
struct privkey node_pkey;
|
|
|
|
|
secp256k1_ecdsa_signature node_sig, bitcoin_sig;
|
|
|
|
|
struct sha256_double hash;
|
|
|
|
|
u8 *reply;
|
|
|
|
|
u8 *ca;
|
|
|
|
|
struct pubkey funding_pubkey;
|
|
|
|
|
struct privkey funding_privkey;
|
|
|
|
|
struct secret channel_seed;
|
|
|
|
|
|
|
|
|
|
/*~ You'll find FIXMEs like this scattered through the code.
|
|
|
|
|
* Sometimes they suggest simple improvements which someone like
|
|
|
|
|
* yourself should go ahead an implement. Sometimes they're deceptive
|
|
|
|
|
* quagmires which will cause you nothing but grief. You decide! */
|
|
|
|
|
|
|
|
|
|
/*~ Christian uses TODO(cdecker) or FIXME(cdecker), but I'm sure he won't
|
|
|
|
|
* mind if you fix this for him! */
|
|
|
|
|
|
|
|
|
|
/* FIXME: We should cache these. */
|
|
|
|
|
get_channel_seed(&c->id, c->dbid, &channel_seed);
|
|
|
|
|
derive_funding_key(&channel_seed, &funding_pubkey, &funding_privkey);
|
|
|
|
|
|
|
|
|
|
/*~ fromwire_ routines which need to do allocation take a tal context
|
|
|
|
|
* as their first field; tmpctx is good here since we won't need it
|
|
|
|
|
* after this function. */
|
|
|
|
|
if (!fromwire_hsmd_cannouncement_sig_req(tmpctx, msg_in, &ca))
|
|
|
|
|
return hsmd_status_malformed_request(c, msg_in);
|
|
|
|
|
|
|
|
|
|
if (tal_count(ca) < offset)
|
|
|
|
|
return hsmd_status_bad_request_fmt(
|
|
|
|
|
c, msg_in, "bad cannounce length %zu", tal_count(ca));
|
|
|
|
|
|
|
|
|
|
if (fromwire_peektype(ca) != WIRE_CHANNEL_ANNOUNCEMENT)
|
|
|
|
|
return hsmd_status_bad_request_fmt(
|
|
|
|
|
c, msg_in, "Invalid channel announcement");
|
|
|
|
|
|
|
|
|
|
node_key(&node_pkey, NULL);
|
|
|
|
|
sha256_double(&hash, ca + offset, tal_count(ca) - offset);
|
|
|
|
|
|
|
|
|
|
sign_hash(&node_pkey, &hash, &node_sig);
|
|
|
|
|
sign_hash(&funding_privkey, &hash, &bitcoin_sig);
|
|
|
|
|
|
|
|
|
|
reply = towire_hsmd_cannouncement_sig_reply(NULL, &node_sig,
|
|
|
|
|
&bitcoin_sig);
|
|
|
|
|
return reply;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 20:53:39 +02:00
|
|
|
|
/*~ It's optional for nodes to send node_announcement, but it lets us set our
|
|
|
|
|
* favourite color and cool alias! Plus other minor details like how to
|
|
|
|
|
* connect to us. */
|
|
|
|
|
static u8 *handle_sign_node_announcement(struct hsmd_client *c,
|
|
|
|
|
const u8 *msg_in)
|
|
|
|
|
{
|
|
|
|
|
/* BOLT #7:
|
|
|
|
|
*
|
|
|
|
|
* The origin node:
|
|
|
|
|
*...
|
|
|
|
|
* - MUST set `signature` to the signature of the double-SHA256 of the
|
|
|
|
|
* entire remaining packet after `signature` (using the key given by
|
|
|
|
|
* `node_id`).
|
|
|
|
|
*/
|
|
|
|
|
/* 2 bytes msg type + 64 bytes signature */
|
|
|
|
|
size_t offset = 66;
|
|
|
|
|
struct sha256_double hash;
|
|
|
|
|
struct privkey node_pkey;
|
|
|
|
|
secp256k1_ecdsa_signature sig;
|
|
|
|
|
u8 *reply;
|
|
|
|
|
u8 *ann;
|
|
|
|
|
|
|
|
|
|
if (!fromwire_hsmd_node_announcement_sig_req(tmpctx, msg_in, &ann))
|
|
|
|
|
return hsmd_status_malformed_request(c, msg_in);
|
|
|
|
|
|
|
|
|
|
if (tal_count(ann) < offset)
|
|
|
|
|
return hsmd_status_bad_request(c, msg_in,
|
|
|
|
|
"Node announcement too short");
|
|
|
|
|
|
|
|
|
|
if (fromwire_peektype(ann) != WIRE_NODE_ANNOUNCEMENT)
|
|
|
|
|
return hsmd_status_bad_request(c, msg_in,
|
|
|
|
|
"Invalid announcement");
|
|
|
|
|
|
|
|
|
|
node_key(&node_pkey, NULL);
|
|
|
|
|
sha256_double(&hash, ann + offset, tal_count(ann) - offset);
|
|
|
|
|
|
|
|
|
|
sign_hash(&node_pkey, &hash, &sig);
|
|
|
|
|
|
|
|
|
|
reply = towire_hsmd_node_announcement_sig_reply(NULL, &sig);
|
|
|
|
|
return reply;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 20:56:33 +02:00
|
|
|
|
/*~ The specific routine to sign the channel_update message. */
|
|
|
|
|
static u8 *handle_channel_update_sig(struct hsmd_client *c, const u8 *msg_in)
|
|
|
|
|
{
|
|
|
|
|
/* BOLT #7:
|
|
|
|
|
*
|
|
|
|
|
* - MUST set `signature` to the signature of the double-SHA256 of the
|
|
|
|
|
* entire remaining packet after `signature`, using its own
|
|
|
|
|
* `node_id`.
|
|
|
|
|
*/
|
|
|
|
|
/* 2 bytes msg type + 64 bytes signature */
|
|
|
|
|
size_t offset = 66;
|
|
|
|
|
struct privkey node_pkey;
|
|
|
|
|
struct sha256_double hash;
|
|
|
|
|
secp256k1_ecdsa_signature sig;
|
|
|
|
|
struct short_channel_id scid;
|
|
|
|
|
u32 timestamp, fee_base_msat, fee_proportional_mill;
|
|
|
|
|
struct amount_msat htlc_minimum, htlc_maximum;
|
|
|
|
|
u8 message_flags, channel_flags;
|
|
|
|
|
u16 cltv_expiry_delta;
|
|
|
|
|
struct bitcoin_blkid chain_hash;
|
|
|
|
|
u8 *cu;
|
|
|
|
|
|
|
|
|
|
if (!fromwire_hsmd_cupdate_sig_req(tmpctx, msg_in, &cu))
|
|
|
|
|
return hsmd_status_malformed_request(c, msg_in);
|
|
|
|
|
|
|
|
|
|
if (!fromwire_channel_update_option_channel_htlc_max(cu, &sig,
|
|
|
|
|
&chain_hash, &scid, ×tamp, &message_flags,
|
|
|
|
|
&channel_flags, &cltv_expiry_delta,
|
|
|
|
|
&htlc_minimum, &fee_base_msat,
|
|
|
|
|
&fee_proportional_mill, &htlc_maximum)) {
|
|
|
|
|
return hsmd_status_bad_request(c, msg_in,
|
|
|
|
|
"Bad inner channel_update");
|
|
|
|
|
}
|
|
|
|
|
if (tal_count(cu) < offset)
|
|
|
|
|
return hsmd_status_bad_request(
|
|
|
|
|
c, msg_in, "inner channel_update too short");
|
|
|
|
|
|
|
|
|
|
node_key(&node_pkey, NULL);
|
|
|
|
|
sha256_double(&hash, cu + offset, tal_count(cu) - offset);
|
|
|
|
|
|
|
|
|
|
sign_hash(&node_pkey, &hash, &sig);
|
|
|
|
|
|
|
|
|
|
cu = towire_channel_update_option_channel_htlc_max(tmpctx, &sig, &chain_hash,
|
|
|
|
|
&scid, timestamp, message_flags, channel_flags,
|
|
|
|
|
cltv_expiry_delta, htlc_minimum,
|
|
|
|
|
fee_base_msat, fee_proportional_mill,
|
|
|
|
|
htlc_maximum);
|
|
|
|
|
return towire_hsmd_cupdate_sig_reply(NULL, cu);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 21:00:53 +02:00
|
|
|
|
/*~ This get the Nth a per-commitment point, and for N > 2, returns the
|
|
|
|
|
* grandparent per-commitment secret. This pattern is because after
|
|
|
|
|
* negotiating commitment N-1, we send them the next per-commitment point,
|
|
|
|
|
* and reveal the previous per-commitment secret as a promise not to spend
|
|
|
|
|
* the previous commitment transaction. */
|
|
|
|
|
static u8 *handle_get_per_commitment_point(struct hsmd_client *c, const u8 *msg_in)
|
|
|
|
|
{
|
|
|
|
|
struct secret channel_seed;
|
|
|
|
|
struct sha256 shaseed;
|
|
|
|
|
struct pubkey per_commitment_point;
|
|
|
|
|
u64 n;
|
|
|
|
|
struct secret *old_secret;
|
|
|
|
|
|
|
|
|
|
if (!fromwire_hsmd_get_per_commitment_point(msg_in, &n))
|
|
|
|
|
return hsmd_status_malformed_request(c, msg_in);
|
|
|
|
|
|
|
|
|
|
get_channel_seed(&c->id, c->dbid, &channel_seed);
|
|
|
|
|
if (!derive_shaseed(&channel_seed, &shaseed))
|
|
|
|
|
return hsmd_status_bad_request(c, msg_in, "bad derive_shaseed");
|
|
|
|
|
|
|
|
|
|
if (!per_commit_point(&shaseed, &per_commitment_point, n))
|
|
|
|
|
return hsmd_status_bad_request_fmt(
|
|
|
|
|
c, msg_in, "bad per_commit_point %" PRIu64, n);
|
|
|
|
|
|
|
|
|
|
if (n >= 2) {
|
|
|
|
|
old_secret = tal(tmpctx, struct secret);
|
|
|
|
|
if (!per_commit_secret(&shaseed, old_secret, n - 2)) {
|
|
|
|
|
return hsmd_status_bad_request_fmt(
|
|
|
|
|
c, msg_in, "Cannot derive secret %" PRIu64, n - 2);
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
old_secret = NULL;
|
|
|
|
|
|
|
|
|
|
/*~ hsm_client_wire.csv marks the secret field here optional, so it only
|
|
|
|
|
* gets included if the parameter is non-NULL. We violate 80 columns
|
|
|
|
|
* pretty badly here, but it's a recommendation not a religion. */
|
|
|
|
|
return towire_hsmd_get_per_commitment_point_reply(
|
|
|
|
|
NULL, &per_commitment_point, old_secret);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-13 17:25:29 +02:00
|
|
|
|
u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client,
|
|
|
|
|
const u8 *msg)
|
|
|
|
|
{
|
2021-04-20 22:41:33 +02:00
|
|
|
|
enum hsmd_wire t = fromwire_peektype(msg);
|
|
|
|
|
|
|
|
|
|
hsmd_status_debug("Client: Received message %d from client", t);
|
|
|
|
|
|
|
|
|
|
/* Before we do anything else, is this client allowed to do
|
|
|
|
|
* what he asks for? */
|
|
|
|
|
if (!check_client_capabilities(client, t))
|
|
|
|
|
return hsmd_status_bad_request_fmt(
|
|
|
|
|
client, msg, "does not have capability to run %d", t);
|
|
|
|
|
|
|
|
|
|
/* If we aren't initialized yet we better get an init message
|
|
|
|
|
* first. Otherwise we don't load the secret and every
|
|
|
|
|
* signature we produce is just going to be junk. */
|
|
|
|
|
if (!initialized && t != WIRE_HSMD_INIT)
|
|
|
|
|
hsmd_status_failed(STATUS_FAIL_MASTER_IO,
|
|
|
|
|
"hsmd was not initialized correctly, expected "
|
|
|
|
|
"message type %d, got %d",
|
|
|
|
|
WIRE_HSMD_INIT, t);
|
|
|
|
|
|
|
|
|
|
/* Now actually go and do what the client asked for */
|
|
|
|
|
switch (t) {
|
|
|
|
|
case WIRE_HSMD_INIT:
|
|
|
|
|
case WIRE_HSMD_CLIENT_HSMFD:
|
|
|
|
|
case WIRE_HSMD_SIGN_WITHDRAWAL:
|
|
|
|
|
case WIRE_HSMD_SIGN_COMMITMENT_TX:
|
|
|
|
|
case WIRE_HSMD_SIGN_DELAYED_PAYMENT_TO_US:
|
|
|
|
|
case WIRE_HSMD_SIGN_REMOTE_HTLC_TO_US:
|
|
|
|
|
case WIRE_HSMD_SIGN_PENALTY_TO_US:
|
|
|
|
|
case WIRE_HSMD_SIGN_LOCAL_HTLC_TX:
|
|
|
|
|
case WIRE_HSMD_SIGN_REMOTE_COMMITMENT_TX:
|
|
|
|
|
case WIRE_HSMD_SIGN_REMOTE_HTLC_TX:
|
|
|
|
|
case WIRE_HSMD_SIGN_MUTUAL_CLOSE_TX:
|
|
|
|
|
/* Not implemented yet. Should not have been passed here yet. */
|
|
|
|
|
return hsmd_status_bad_request_fmt(client, msg, "Not implemented yet.");
|
|
|
|
|
|
2021-04-21 20:45:12 +02:00
|
|
|
|
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY:
|
|
|
|
|
return handle_get_output_scriptpubkey(client, msg);
|
2021-04-21 19:10:55 +02:00
|
|
|
|
case WIRE_HSMD_CHECK_FUTURE_SECRET:
|
|
|
|
|
return handle_check_future_secret(client, msg);
|
2021-04-21 18:45:09 +02:00
|
|
|
|
case WIRE_HSMD_ECDH_REQ:
|
|
|
|
|
return handle_ecdh(client, msg);
|
2021-04-21 15:46:04 +02:00
|
|
|
|
case WIRE_HSMD_SIGN_INVOICE:
|
|
|
|
|
return handle_sign_invoice(client, msg);
|
2021-04-21 15:13:04 +02:00
|
|
|
|
case WIRE_HSMD_SIGN_BOLT12:
|
|
|
|
|
return handle_sign_bolt12(client, msg);
|
2021-04-20 22:41:33 +02:00
|
|
|
|
case WIRE_HSMD_SIGN_MESSAGE:
|
|
|
|
|
return handle_sign_message(client, msg);
|
2021-04-21 18:41:20 +02:00
|
|
|
|
case WIRE_HSMD_GET_CHANNEL_BASEPOINTS:
|
|
|
|
|
return handle_get_channel_basepoints(client, msg);
|
2021-04-21 20:49:50 +02:00
|
|
|
|
case WIRE_HSMD_CANNOUNCEMENT_SIG_REQ:
|
|
|
|
|
return handle_cannouncement_sig(client, msg);
|
2021-04-21 20:53:39 +02:00
|
|
|
|
case WIRE_HSMD_NODE_ANNOUNCEMENT_SIG_REQ:
|
|
|
|
|
return handle_sign_node_announcement(client, msg);
|
2021-04-21 20:56:33 +02:00
|
|
|
|
case WIRE_HSMD_CUPDATE_SIG_REQ:
|
|
|
|
|
return handle_channel_update_sig(client, msg);
|
2021-04-21 21:00:53 +02:00
|
|
|
|
case WIRE_HSMD_GET_PER_COMMITMENT_POINT:
|
|
|
|
|
return handle_get_per_commitment_point(client, msg);
|
2021-04-20 22:41:33 +02:00
|
|
|
|
|
|
|
|
|
case WIRE_HSMD_DEV_MEMLEAK:
|
|
|
|
|
case WIRE_HSMD_ECDH_RESP:
|
|
|
|
|
case WIRE_HSMD_CANNOUNCEMENT_SIG_REPLY:
|
|
|
|
|
case WIRE_HSMD_CUPDATE_SIG_REPLY:
|
|
|
|
|
case WIRE_HSMD_CLIENT_HSMFD_REPLY:
|
|
|
|
|
case WIRE_HSMD_NODE_ANNOUNCEMENT_SIG_REPLY:
|
|
|
|
|
case WIRE_HSMD_SIGN_WITHDRAWAL_REPLY:
|
|
|
|
|
case WIRE_HSMD_SIGN_INVOICE_REPLY:
|
|
|
|
|
case WIRE_HSMD_INIT_REPLY:
|
|
|
|
|
case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST:
|
|
|
|
|
case WIRE_HSMD_SIGN_COMMITMENT_TX_REPLY:
|
|
|
|
|
case WIRE_HSMD_SIGN_TX_REPLY:
|
|
|
|
|
case WIRE_HSMD_GET_PER_COMMITMENT_POINT_REPLY:
|
|
|
|
|
case WIRE_HSMD_CHECK_FUTURE_SECRET_REPLY:
|
|
|
|
|
case WIRE_HSMD_GET_CHANNEL_BASEPOINTS_REPLY:
|
|
|
|
|
case WIRE_HSMD_DEV_MEMLEAK_REPLY:
|
|
|
|
|
case WIRE_HSMD_SIGN_MESSAGE_REPLY:
|
|
|
|
|
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY:
|
|
|
|
|
case WIRE_HSMD_SIGN_BOLT12_REPLY:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return hsmd_status_bad_request(client, msg, "Unknown request");
|
2021-04-13 17:25:29 +02:00
|
|
|
|
}
|