hsmd: add variant of preapprove commands to have it check only, not do anything.

Apparently VLS actually does something when we preapprove: if caller is just
checking we want to tell it not to do that!

I put in a flag so we can test both old and new APIs.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2024-04-04 14:06:13 +10:30
parent 33cfef84d8
commit 6ea95da342
7 changed files with 106 additions and 12 deletions

View file

@ -24,6 +24,7 @@
* v5 with sign_any_cannouncement: 5fdb9068c43a21887dc03f7dce410d2e3eeff6277f0d49b4fc56595a798fd4a4
* v5 drop init v2: 5024454532fe5a78bb7558000cb344190888b9915360d3d56ddca22eaba9b872
* v5 with dev_preinit: b93e18534a468a4aa9f7015db42e9c363c32aeee5f9146b36dc953ebbdc3d33c
* v5 with preapprove_check: 0ed6dd4ea2c02b67c51b1420b3d07ab2227a4c06ce7e2942d946967687e9baf7
*/
#define HSM_MIN_VERSION 5
#define HSM_MAX_VERSION 5

View file

@ -439,6 +439,9 @@ static struct io_plan *preinit_hsm(struct io_conn *conn,
if (tlv->fail_preapprove)
dev_fail_preapprove = *tlv->fail_preapprove;
if (tlv->no_preapprove_check)
dev_no_preapprove_check = *tlv->no_preapprove_check;
/* We don't send a reply, just read next */
return client_read_next(conn, c);
}
@ -688,6 +691,8 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
case WIRE_HSMD_SIGN_BOLT12:
case WIRE_HSMD_PREAPPROVE_INVOICE:
case WIRE_HSMD_PREAPPROVE_KEYSEND:
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK:
case WIRE_HSMD_PREAPPROVE_KEYSEND_CHECK:
case WIRE_HSMD_ECDH_REQ:
case WIRE_HSMD_CHECK_FUTURE_SECRET:
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY:
@ -741,6 +746,8 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
case WIRE_HSMD_SIGN_BOLT12_REPLY:
case WIRE_HSMD_PREAPPROVE_INVOICE_REPLY:
case WIRE_HSMD_PREAPPROVE_KEYSEND_REPLY:
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK_REPLY:
case WIRE_HSMD_PREAPPROVE_KEYSEND_CHECK_REPLY:
case WIRE_HSMD_CHECK_PUBKEY_REPLY:
case WIRE_HSMD_SIGN_ANCHORSPEND_REPLY:
case WIRE_HSMD_SIGN_HTLC_TX_MINGLE_REPLY:

View file

@ -12,6 +12,8 @@ msgtype,hsmd_dev_preinit,99
msgdata,hsmd_dev_preinit,tlvs,hsmd_dev_preinit_tlvs,
tlvtype,hsmd_dev_preinit_tlvs,fail_preapprove,1
tlvdata,hsmd_dev_preinit_tlvs,fail_preapprove,fail,bool,
tlvtype,hsmd_dev_preinit_tlvs,no_preapprove_check,3
tlvdata,hsmd_dev_preinit_tlvs,no_preapprove_check,disable,bool,
#include <bitcoin/chainparams.h>
# Start the HSM.
@ -164,6 +166,26 @@ msgdata,hsmd_preapprove_keysend,amount_msat,amount_msat,
msgtype,hsmd_preapprove_keysend_reply,139
msgdata,hsmd_preapprove_keysend_reply,approved,bool,
# Preapprove an invoice for payment (with "check_only" option)
msgtype,hsmd_preapprove_invoice_check,51
msgdata,hsmd_preapprove_invoice_check,invstring,wirestring,
msgdata,hsmd_preapprove_invoice_check,check_only,bool,
# Result is true if approved, declined if false
msgtype,hsmd_preapprove_invoice_check_reply,151
msgdata,hsmd_preapprove_invoice_check_reply,approved,bool,
# Preapprove a keysend payment (with "check_only" option)
msgtype,hsmd_preapprove_keysend_check,52
msgdata,hsmd_preapprove_keysend_check,destination,node_id,
msgdata,hsmd_preapprove_keysend_check,payment_hash,sha256,
msgdata,hsmd_preapprove_keysend_check,amount_msat,amount_msat,
msgdata,hsmd_preapprove_keysend_check,check_only,bool,
# Result is true if approved, declined if false
msgtype,hsmd_preapprove_keysend_check_reply,152
msgdata,hsmd_preapprove_keysend_check_reply,approved,bool,
# Give me ECDH(node-id-secret,point)
msgtype,hsmd_ecdh_req,1
msgdata,hsmd_ecdh_req,point,pubkey,

Can't render this file because it contains an unexpected character in line 169 and column 43.

View file

@ -35,6 +35,7 @@ bool initialized = false;
/* Do we fail all preapprove requests? */
bool dev_fail_preapprove = false;
bool dev_no_preapprove_check = false;
struct hsmd_client *hsmd_client_new_main(const tal_t *ctx, u64 capabilities,
void *extra)
@ -134,6 +135,8 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client,
case WIRE_HSMD_SIGN_BOLT12:
case WIRE_HSMD_PREAPPROVE_INVOICE:
case WIRE_HSMD_PREAPPROVE_KEYSEND:
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK:
case WIRE_HSMD_PREAPPROVE_KEYSEND_CHECK:
case WIRE_HSMD_DERIVE_SECRET:
case WIRE_HSMD_CHECK_PUBKEY:
case WIRE_HSMD_SIGN_ANY_PENALTY_TO_US:
@ -177,6 +180,8 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client,
case WIRE_HSMD_SIGN_BOLT12_REPLY:
case WIRE_HSMD_PREAPPROVE_INVOICE_REPLY:
case WIRE_HSMD_PREAPPROVE_KEYSEND_REPLY:
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK_REPLY:
case WIRE_HSMD_PREAPPROVE_KEYSEND_CHECK_REPLY:
case WIRE_HSMD_DERIVE_SECRET_REPLY:
case WIRE_HSMD_CHECK_PUBKEY_REPLY:
case WIRE_HSMD_SIGN_ANCHORSPEND_REPLY:
@ -775,7 +780,10 @@ static u8 *handle_preapprove_invoice(struct hsmd_client *c, const u8 *msg_in)
{
char *invstring;
bool approved;
if (!fromwire_hsmd_preapprove_invoice(tmpctx, msg_in, &invstring))
bool check_only = false;
if (!fromwire_hsmd_preapprove_invoice(tmpctx, msg_in, &invstring)
&& !fromwire_hsmd_preapprove_invoice_check(tmpctx, msg_in, &invstring, &check_only))
return hsmd_status_malformed_request(c, msg_in);
/* This stub always approves unless overridden */
@ -793,8 +801,13 @@ static u8 *handle_preapprove_keysend(struct hsmd_client *c, const u8 *msg_in)
struct sha256 payment_hash;
struct amount_msat amount_msat;
bool approved;
if (!fromwire_hsmd_preapprove_keysend(msg_in, &destination, &payment_hash, &amount_msat))
bool check_only = false;
if (!fromwire_hsmd_preapprove_keysend(msg_in, &destination, &payment_hash, &amount_msat)
&& !fromwire_hsmd_preapprove_keysend_check(msg_in, &destination, &payment_hash,
&amount_msat, &check_only)) {
return hsmd_status_malformed_request(c, msg_in);
}
/* This stub always approves unless overridden */
approved = !dev_fail_preapprove;
@ -2049,8 +2062,10 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client,
case WIRE_HSMD_SIGN_BOLT12:
return handle_sign_bolt12(client, msg);
case WIRE_HSMD_PREAPPROVE_INVOICE:
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK:
return handle_preapprove_invoice(client, msg);
case WIRE_HSMD_PREAPPROVE_KEYSEND:
case WIRE_HSMD_PREAPPROVE_KEYSEND_CHECK:
return handle_preapprove_keysend(client, msg);
case WIRE_HSMD_SIGN_MESSAGE:
return handle_sign_message(client, msg);
@ -2140,6 +2155,8 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client,
case WIRE_HSMD_SIGN_BOLT12_REPLY:
case WIRE_HSMD_PREAPPROVE_INVOICE_REPLY:
case WIRE_HSMD_PREAPPROVE_KEYSEND_REPLY:
case WIRE_HSMD_PREAPPROVE_INVOICE_CHECK_REPLY:
case WIRE_HSMD_PREAPPROVE_KEYSEND_CHECK_REPLY:
case WIRE_HSMD_CHECK_PUBKEY_REPLY:
case WIRE_HSMD_SIGN_ANCHORSPEND_REPLY:
case WIRE_HSMD_SIGN_HTLC_TX_MINGLE_REPLY:
@ -2166,7 +2183,10 @@ u8 *hsmd_init(struct secret hsm_secret, const u64 hsmd_version,
WIRE_HSMD_CHECK_OUTPOINT,
WIRE_HSMD_FORGET_CHANNEL,
WIRE_HSMD_REVOKE_COMMITMENT_TX,
WIRE_HSMD_PREAPPROVE_INVOICE_CHECK,
WIRE_HSMD_PREAPPROVE_KEYSEND_CHECK,
};
const u32 *caps;
/*~ Don't swap this. */
sodium_mlock(secretstuff.hsm_secret.data,
@ -2288,6 +2308,17 @@ u8 *hsmd_init(struct secret hsm_secret, const u64 hsmd_version,
&secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret),
"derived secrets", strlen("derived secrets"));
/* Capabilities arg needs to be a tal array */
if (dev_no_preapprove_check) {
/* Skip preapprove capabilities */
caps = tal_dup_arr(tmpctx, u32,
capabilities, ARRAY_SIZE(capabilities) - 2,
0);
} else {
caps = tal_dup_arr(tmpctx, u32,
capabilities, ARRAY_SIZE(capabilities), 0);
}
/*~ Note: marshalling a bip32 tree only marshals the public side,
* not the secrets! So we're not actually handing them out here!
*
@ -2295,10 +2326,7 @@ u8 *hsmd_init(struct secret hsm_secret, const u64 hsmd_version,
* incompatibility detection) with alternate implementations.
*/
return take(towire_hsmd_init_reply_v4(
NULL, hsmd_version,
/* Capabilities arg needs to be a tal array */
tal_dup_arr(tmpctx, u32, capabilities,
ARRAY_SIZE(capabilities), 0),
NULL, hsmd_version, caps,
&node_id, &secretstuff.bip32,
&bolt12));
}

View file

@ -95,4 +95,6 @@ extern struct privkey *dev_force_privkey;
extern struct secret *dev_force_bip32_seed;
/* If they specify --dev-hsmd-fail-preapprove it ends up in here. */
extern bool dev_fail_preapprove;
/* If they specify --dev-no-preapprove-check it ends up in here. */
extern bool dev_no_preapprove_check;
#endif /* LIGHTNING_HSMD_LIBHSMD_H */

View file

@ -1870,6 +1870,7 @@ static struct command_result *json_preapproveinvoice(struct command *cmd,
const char *invstring;
struct json_stream *response;
bool approved;
u8 *req;
const u8 *msg;
if (!param(cmd, buffer, params,
@ -1878,11 +1879,20 @@ static struct command_result *json_preapproveinvoice(struct command *cmd,
NULL))
return command_param_failed();
msg = hsm_sync_req(tmpctx, cmd->ld,
take(towire_hsmd_preapprove_invoice(NULL, invstring)));
if (!fromwire_hsmd_preapprove_invoice_reply(msg, &approved))
/* Old version didn't have `bool check_only` at end */
if (!hsm_capable(cmd->ld, WIRE_HSMD_PREAPPROVE_INVOICE_CHECK))
req = towire_hsmd_preapprove_invoice(NULL, invstring);
else
req = towire_hsmd_preapprove_invoice_check(NULL, invstring, false);
msg = hsm_sync_req(tmpctx, cmd->ld, take(req));
/* These are identical, but use separate numbers for clarity */
if (!fromwire_hsmd_preapprove_invoice_reply(msg, &approved)
&& !fromwire_hsmd_preapprove_invoice_check_reply(msg, &approved)) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"HSM gave bad preapprove_invoice_reply %s", tal_hex(msg, msg));
}
if (!approved)
return command_fail(cmd, PAY_INVOICE_PREAPPROVAL_DECLINED, "invoice was declined");
@ -1910,6 +1920,7 @@ static struct command_result *json_preapprovekeysend(struct command *cmd,
struct json_stream *response;
bool approved;
const u8 *msg;
u8 *req;
if (!param(cmd, buffer, params,
p_req("destination", param_node_id, &destination),
@ -1918,12 +1929,20 @@ static struct command_result *json_preapprovekeysend(struct command *cmd,
NULL))
return command_param_failed();
msg = towire_hsmd_preapprove_keysend(NULL, destination, payment_hash, *amount);
if (!hsm_capable(cmd->ld, WIRE_HSMD_PREAPPROVE_KEYSEND_CHECK))
req = towire_hsmd_preapprove_keysend(NULL, destination, payment_hash, *amount);
else
req = towire_hsmd_preapprove_keysend_check(NULL, destination, payment_hash,
*amount, false);
msg = hsm_sync_req(tmpctx, cmd->ld, take(msg));
if (!fromwire_hsmd_preapprove_keysend_reply(msg, &approved))
msg = hsm_sync_req(tmpctx, cmd->ld, take(req));
/* These are identical, but use separate numbers for clarity */
if (!fromwire_hsmd_preapprove_keysend_reply(msg, &approved)
&& !fromwire_hsmd_preapprove_keysend_check_reply(msg, &approved)) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"HSM gave bad preapprove_keysend_reply %s", tal_hex(msg, msg));
}
if (!approved)
return command_fail(cmd, PAY_KEYSEND_PREAPPROVAL_DECLINED, "keysend was declined");

View file

@ -290,9 +290,15 @@ bool fromwire_connectd_peer_spoke(const tal_t *ctx UNNEEDED, const void *p UNNEE
/* Generated stub for fromwire_dualopend_dev_memleak_reply */
bool fromwire_dualopend_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED)
{ fprintf(stderr, "fromwire_dualopend_dev_memleak_reply called!\n"); abort(); }
/* Generated stub for fromwire_hsmd_preapprove_invoice_check_reply */
bool fromwire_hsmd_preapprove_invoice_check_reply(const void *p UNNEEDED, bool *approved UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_preapprove_invoice_check_reply called!\n"); abort(); }
/* Generated stub for fromwire_hsmd_preapprove_invoice_reply */
bool fromwire_hsmd_preapprove_invoice_reply(const void *p UNNEEDED, bool *approved UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_preapprove_invoice_reply called!\n"); abort(); }
/* Generated stub for fromwire_hsmd_preapprove_keysend_check_reply */
bool fromwire_hsmd_preapprove_keysend_check_reply(const void *p UNNEEDED, bool *approved UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_preapprove_keysend_check_reply called!\n"); abort(); }
/* Generated stub for fromwire_hsmd_preapprove_keysend_reply */
bool fromwire_hsmd_preapprove_keysend_reply(const void *p UNNEEDED, bool *approved UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_preapprove_keysend_reply called!\n"); abort(); }
@ -325,6 +331,9 @@ u32 get_feerate(const struct fee_states *fee_states UNNEEDED,
/* Generated stub for hash_htlc_key */
size_t hash_htlc_key(const struct htlc_key *htlc_key UNNEEDED)
{ fprintf(stderr, "hash_htlc_key called!\n"); abort(); }
/* Generated stub for hsm_capable */
bool hsm_capable(struct lightningd *ld UNNEEDED, u32 msgtype UNNEEDED)
{ fprintf(stderr, "hsm_capable called!\n"); abort(); }
/* Generated stub for hsm_sync_req */
const u8 *hsm_sync_req(const tal_t *ctx UNNEEDED,
struct lightningd *ld UNNEEDED,
@ -949,9 +958,15 @@ u8 *towire_errorfmt(const tal_t *ctx UNNEEDED,
/* Generated stub for towire_hsmd_preapprove_invoice */
u8 *towire_hsmd_preapprove_invoice(const tal_t *ctx UNNEEDED, const wirestring *invstring UNNEEDED)
{ fprintf(stderr, "towire_hsmd_preapprove_invoice called!\n"); abort(); }
/* Generated stub for towire_hsmd_preapprove_invoice_check */
u8 *towire_hsmd_preapprove_invoice_check(const tal_t *ctx UNNEEDED, const wirestring *invstring UNNEEDED, bool check_only UNNEEDED)
{ fprintf(stderr, "towire_hsmd_preapprove_invoice_check called!\n"); abort(); }
/* Generated stub for towire_hsmd_preapprove_keysend */
u8 *towire_hsmd_preapprove_keysend(const tal_t *ctx UNNEEDED, const struct node_id *destination UNNEEDED, const struct sha256 *payment_hash UNNEEDED, struct amount_msat amount_msat UNNEEDED)
{ fprintf(stderr, "towire_hsmd_preapprove_keysend called!\n"); abort(); }
/* Generated stub for towire_hsmd_preapprove_keysend_check */
u8 *towire_hsmd_preapprove_keysend_check(const tal_t *ctx UNNEEDED, const struct node_id *destination UNNEEDED, const struct sha256 *payment_hash UNNEEDED, struct amount_msat amount_msat UNNEEDED, bool check_only UNNEEDED)
{ fprintf(stderr, "towire_hsmd_preapprove_keysend_check called!\n"); abort(); }
/* Generated stub for towire_hsmd_sign_bolt12 */
u8 *towire_hsmd_sign_bolt12(const tal_t *ctx UNNEEDED, const wirestring *messagename UNNEEDED, const wirestring *fieldname UNNEEDED, const struct sha256 *merkleroot UNNEEDED, const u8 *publictweak UNNEEDED)
{ fprintf(stderr, "towire_hsmd_sign_bolt12 called!\n"); abort(); }