hsmd: code to sign a bolt12 merkle root.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2020-12-09 14:27:50 +10:30
parent f315f1c63f
commit 86176e8d0a
5 changed files with 151 additions and 3 deletions

View File

@ -42,6 +42,10 @@ HSMD_COMMON_OBJS := \
common/utxo.o \
common/version.o
ifeq ($(EXPERIMENTAL_FEATURES),1)
HSMD_COMMON_OBJS += common/bolt12_merkle.o
endif
lightningd/lightning_hsmd: $(HSMD_OBJS) $(HSMD_COMMON_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS)
-include hsmd/test/Makefile

View File

@ -25,6 +25,9 @@
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/take/take.h>
#include <ccan/tal/str/str.h>
#if EXPERIMENTAL_FEATURES
#include <common/bolt12_merkle.h>
#endif
#include <common/daemon_conn.h>
#include <common/derive_basepoints.h>
#include <common/hash_u5.h>
@ -43,6 +46,7 @@
#include <hsmd/hsmd_wiregen.h>
#include <inttypes.h>
#include <secp256k1_ecdh.h>
#include <secp256k1_schnorrsig.h>
#include <sodium.h>
#include <sys/socket.h>
#include <sys/stat.h>
@ -313,7 +317,7 @@ static void node_key(struct privkey *node_privkey, struct pubkey *node_id)
/* If caller specifies NULL, they don't want the results. */
if (node_privkey == NULL)
node_privkey = &unused_s;
else if (node_id == NULL)
if (node_id == NULL)
node_id = &unused_k;
/*~ So, there is apparently a 1 in 2^127 chance that a random value is
@ -343,6 +347,33 @@ static void node_key(struct privkey *node_privkey, struct pubkey *node_id)
#endif
}
#if EXPERIMENTAL_FEATURES
/*~ 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)
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)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Failed to derive xonly pub");
}
}
#endif
/*~ 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)
@ -1790,6 +1821,36 @@ static struct io_plan *handle_sign_message(struct io_conn *conn,
take(towire_hsmd_sign_message_reply(NULL, &rsig)));
}
#if EXPERIMENTAL_FEATURES
/*~ lightningd asks us to sign a bolt12 (e.g. offer). */
static struct io_plan *handle_sign_bolt12(struct io_conn *conn,
struct client *c,
const u8 *msg_in)
{
char *messagename, *fieldname;
struct sha256 merkle, sha;
struct bip340sig sig;
secp256k1_keypair node_kp;
if (!fromwire_hsmd_sign_bolt12(tmpctx, msg_in,
&messagename, &fieldname, &merkle))
return bad_req(conn, c, msg_in);
sighash_from_merkle(messagename, fieldname, &merkle, &sha);
node_schnorrkey(&node_kp, NULL);
if (!secp256k1_schnorrsig_sign(secp256k1_ctx, sig.u8,
sha.u.u8,
&node_kp,
NULL, NULL)) {
return bad_req_fmt(conn, c, msg_in, "Failed to sign bolt12");
}
return req_reply(conn, c,
take(towire_hsmd_sign_bolt12_reply(NULL, &sig)));
}
#endif
#if DEVELOPER
static struct io_plan *handle_memleak(struct io_conn *conn,
struct client *c,
@ -1871,6 +1932,7 @@ static bool check_client_capabilities(struct client *client,
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. */
@ -1893,6 +1955,7 @@ static bool check_client_capabilities(struct client *client,
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;
@ -1975,6 +2038,13 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
case WIRE_HSMD_SIGN_MESSAGE:
return handle_sign_message(conn, c, c->msg_in);
case WIRE_HSMD_SIGN_BOLT12:
#if EXPERIMENTAL_FEATURES
return handle_sign_bolt12(conn, c, c->msg_in);
#else
break;
#endif
#if DEVELOPER
case WIRE_HSMD_DEV_MEMLEAK:
return handle_memleak(conn, c, c->msg_in);
@ -1998,6 +2068,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
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;
}

View File

@ -198,3 +198,13 @@ msgdata,hsmd_get_output_scriptpubkey,commitment_point,?pubkey,
msgtype,hsmd_get_output_scriptpubkey_reply,124
msgdata,hsmd_get_output_scriptpubkey_reply,script_len,u16,
msgdata,hsmd_get_output_scriptpubkey_reply,script,u8,script_len
# Sign a bolt12-style merkle hash
msgtype,hsmd_sign_bolt12,25
msgdata,hsmd_sign_bolt12,messagename,wirestring,
msgdata,hsmd_sign_bolt12,fieldname,wirestring,
msgdata,hsmd_sign_bolt12,merkleroot,sha256,
msgtype,hsmd_sign_bolt12_reply,125
msgdata,hsmd_sign_bolt12_reply,sig,bip340sig,

1 # Clients should not give a bad request but not the HSM's decision to crash.
198
199
200
201
202
203
204
205
206
207
208
209
210

53
hsmd/hsmd_wiregen.c generated
View File

@ -60,6 +60,8 @@ const char *hsmd_wire_name(int e)
case WIRE_HSMD_SIGN_MESSAGE_REPLY: return "WIRE_HSMD_SIGN_MESSAGE_REPLY";
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY: return "WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY";
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY: return "WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY";
case WIRE_HSMD_SIGN_BOLT12: return "WIRE_HSMD_SIGN_BOLT12";
case WIRE_HSMD_SIGN_BOLT12_REPLY: return "WIRE_HSMD_SIGN_BOLT12_REPLY";
}
snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e);
@ -108,6 +110,8 @@ bool hsmd_wire_is_defined(u16 type)
case WIRE_HSMD_SIGN_MESSAGE_REPLY:;
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY:;
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY:;
case WIRE_HSMD_SIGN_BOLT12:;
case WIRE_HSMD_SIGN_BOLT12_REPLY:;
return true;
}
return false;
@ -1214,4 +1218,51 @@ bool fromwire_hsmd_get_output_scriptpubkey_reply(const tal_t *ctx, const void *p
fromwire_u8_array(&cursor, &plen, *script, script_len);
return cursor != NULL;
}
// SHA256STAMP:02b3951c8bdb27997f5a30ebcf2e174cb99d6089d889b94da925fd674fca653f
/* WIRE: HSMD_SIGN_BOLT12 */
/* Sign a bolt12-style merkle hash */
u8 *towire_hsmd_sign_bolt12(const tal_t *ctx, const wirestring *messagename, const wirestring *fieldname, const struct sha256 *merkleroot)
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_HSMD_SIGN_BOLT12);
towire_wirestring(&p, messagename);
towire_wirestring(&p, fieldname);
towire_sha256(&p, merkleroot);
return memcheck(p, tal_count(p));
}
bool fromwire_hsmd_sign_bolt12(const tal_t *ctx, const void *p, wirestring **messagename, wirestring **fieldname, struct sha256 *merkleroot)
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_HSMD_SIGN_BOLT12)
return false;
*messagename = fromwire_wirestring(ctx, &cursor, &plen);
*fieldname = fromwire_wirestring(ctx, &cursor, &plen);
fromwire_sha256(&cursor, &plen, merkleroot);
return cursor != NULL;
}
/* WIRE: HSMD_SIGN_BOLT12_REPLY */
u8 *towire_hsmd_sign_bolt12_reply(const tal_t *ctx, const struct bip340sig *sig)
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_HSMD_SIGN_BOLT12_REPLY);
towire_bip340sig(&p, sig);
return memcheck(p, tal_count(p));
}
bool fromwire_hsmd_sign_bolt12_reply(const void *p, struct bip340sig *sig)
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_HSMD_SIGN_BOLT12_REPLY)
return false;
fromwire_bip340sig(&cursor, &plen, sig);
return cursor != NULL;
}
// SHA256STAMP:cb033b99e13d9bdd06582a34132ba7cd311f4cf074298da1addcdad06b3fdf8f

14
hsmd/hsmd_wiregen.h generated
View File

@ -76,6 +76,9 @@ enum hsmd_wire {
/* lightningd needs to get a scriptPubkey for a utxo with closeinfo */
WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY = 24,
WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY = 124,
/* Sign a bolt12-style merkle hash */
WIRE_HSMD_SIGN_BOLT12 = 25,
WIRE_HSMD_SIGN_BOLT12_REPLY = 125,
};
const char *hsmd_wire_name(int e);
@ -269,6 +272,15 @@ bool fromwire_hsmd_get_output_scriptpubkey(const tal_t *ctx, const void *p, u64
u8 *towire_hsmd_get_output_scriptpubkey_reply(const tal_t *ctx, const u8 *script);
bool fromwire_hsmd_get_output_scriptpubkey_reply(const tal_t *ctx, const void *p, u8 **script);
/* WIRE: HSMD_SIGN_BOLT12 */
/* Sign a bolt12-style merkle hash */
u8 *towire_hsmd_sign_bolt12(const tal_t *ctx, const wirestring *messagename, const wirestring *fieldname, const struct sha256 *merkleroot);
bool fromwire_hsmd_sign_bolt12(const tal_t *ctx, const void *p, wirestring **messagename, wirestring **fieldname, struct sha256 *merkleroot);
/* WIRE: HSMD_SIGN_BOLT12_REPLY */
u8 *towire_hsmd_sign_bolt12_reply(const tal_t *ctx, const struct bip340sig *sig);
bool fromwire_hsmd_sign_bolt12_reply(const void *p, struct bip340sig *sig);
#endif /* LIGHTNING_HSMD_HSMD_WIREGEN_H */
// SHA256STAMP:02b3951c8bdb27997f5a30ebcf2e174cb99d6089d889b94da925fd674fca653f
// SHA256STAMP:cb033b99e13d9bdd06582a34132ba7cd311f4cf074298da1addcdad06b3fdf8f