From 45f5bb7facf0acc03a815ed5ae67c7edcc0acfcb Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 22 Nov 2017 10:55:39 +1030 Subject: [PATCH] bolt11: move to common/ and sign via callback. JSON stuff is moved to lightningd/invoice.c. Signed-off-by: Rusty Russell --- common/Makefile | 1 + {lightningd => common}/bolt11.c | 173 ++---------------------------- {lightningd => common}/bolt11.h | 25 +++-- lightningd/Makefile | 2 +- lightningd/hsm_control.c | 1 + lightningd/invoice.c | 179 +++++++++++++++++++++++++++++++- lightningd/pay.c | 2 +- 7 files changed, 210 insertions(+), 173 deletions(-) rename {lightningd => common}/bolt11.c (83%) rename {lightningd => common}/bolt11.h (79%) diff --git a/common/Makefile b/common/Makefile index 82a82f04a..8954f2a7b 100644 --- a/common/Makefile +++ b/common/Makefile @@ -1,6 +1,7 @@ COMMON_SRC := \ common/bech32.c \ common/bip32.c \ + common/bolt11.c \ common/channel_config.c \ common/close_tx.c \ common/configdir.c \ diff --git a/lightningd/bolt11.c b/common/bolt11.c similarity index 83% rename from lightningd/bolt11.c rename to common/bolt11.c index e73eac657..8f03db3a7 100644 --- a/lightningd/bolt11.c +++ b/common/bolt11.c @@ -8,11 +8,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -877,9 +877,13 @@ static void encode_extra(u5 **data, const struct bolt11_field *extra) } /* Encodes, even if it's nonsense. */ -char *bolt11_encode(const tal_t *ctx, - struct lightningd *ld, - const struct bolt11 *b11, bool n_field) +char *bolt11_encode_(const tal_t *ctx, + const struct bolt11 *b11, bool n_field, + bool (*sign)(const u5 *u5bytes, + const u8 *hrpu8, + secp256k1_ecdsa_recoverable_signature *rsig, + void *arg), + void *arg) { tal_t *tmpctx = tal_tmpctx(ctx); u5 *data = tal_arr(tmpctx, u5, 0); @@ -889,7 +893,7 @@ char *bolt11_encode(const tal_t *ctx, struct bolt11_field *extra; secp256k1_ecdsa_recoverable_signature rsig; u8 sig_and_recid[65]; - u8 *hrpu8, *msg; + u8 *hrpu8; int recid; size_t i; @@ -963,15 +967,8 @@ char *bolt11_encode(const tal_t *ctx, /* Need exact length here */ hrpu8 = tal_dup_arr(tmpctx, u8, (const u8 *)hrp, strlen(hrp), 0); - msg = towire_hsmctl_sign_invoice(tmpctx, data, hrpu8); - - if (!wire_sync_write(ld->hsm_fd, take(msg))) - fatal("Could not write to HSM: %s", strerror(errno)); - - msg = hsm_sync_read(tmpctx, ld); - if (!fromwire_hsmctl_sign_invoice_reply(msg, NULL, &rsig)) - fatal("HSM gave bad sign_invoice_reply %s", - tal_hex(msg, msg)); + if (!sign(data, hrpu8, &rsig, arg)) + return tal_free(tmpctx); secp256k1_ecdsa_recoverable_signature_serialize_compact( secp256k1_ctx, @@ -1044,151 +1041,3 @@ struct bolt11 *bolt11_out_check(const struct bolt11 *b11, const char *abortstr) } return cast_const(struct bolt11 *, b11); } - -static void json_decodepay(struct command *cmd, - const char *buffer, const jsmntok_t *params) -{ - jsmntok_t *bolt11tok, *desctok; - struct bolt11 *b11; - struct json_result *response; - char *str, *desc, *fail; - - if (!json_get_params(buffer, params, - "bolt11", &bolt11tok, - "?description", &desctok, - NULL)) { - command_fail(cmd, "Need bolt11 string"); - return; - } - - str = tal_strndup(cmd, buffer + bolt11tok->start, - bolt11tok->end - bolt11tok->start); - - if (desctok) - desc = tal_strndup(cmd, buffer + desctok->start, - desctok->end - desctok->start); - else - desc = NULL; - - b11 = bolt11_decode(cmd, str, desc, &fail); - - if (!b11) { - command_fail(cmd, "Invalid bolt11: %s", fail); - return; - } - - response = new_json_result(cmd); - json_object_start(response, NULL); - - json_add_string(response, "currency", b11->chain->bip173_name); - json_add_u64(response, "timestamp", b11->timestamp); - json_add_u64(response, "expiry", b11->expiry); - json_add_pubkey(response, "payee", &b11->receiver_id); - if (b11->msatoshi) - json_add_u64(response, "msatoshi", *b11->msatoshi); - if (b11->description) - json_add_string(response, "description", b11->description); - if (b11->description_hash) - json_add_hex(response, "description_hash", - b11->description_hash, - sizeof(*b11->description_hash)); - if (tal_len(b11->fallback)) { - struct bitcoin_address pkh; - struct ripemd160 sh; - struct sha256 wsh; - - json_object_start(response, "fallback"); - if (is_p2pkh(b11->fallback, &pkh)) { - json_add_string(response, "type", "P2PKH"); - json_add_string(response, "addr", - bitcoin_to_base58(cmd, - b11->chain->testnet, - &pkh)); - } else if (is_p2sh(b11->fallback, &sh)) { - json_add_string(response, "type", "P2SH"); - json_add_string(response, "addr", - p2sh_to_base58(cmd, - b11->chain->testnet, - &sh)); - } else if (is_p2wpkh(b11->fallback, &pkh)) { - char out[73 + strlen(b11->chain->bip173_name)]; - json_add_string(response, "type", "P2WPKH"); - if (segwit_addr_encode(out, b11->chain->bip173_name, 0, - (const u8 *)&pkh, sizeof(pkh))) - json_add_string(response, "addr", out); - } else if (is_p2wsh(b11->fallback, &wsh)) { - char out[73 + strlen(b11->chain->bip173_name)]; - json_add_string(response, "type", "P2WSH"); - if (segwit_addr_encode(out, b11->chain->bip173_name, 0, - (const u8 *)&wsh, sizeof(wsh))) - json_add_string(response, "addr", out); - } - json_add_hex(response, "hex", - b11->fallback, tal_len(b11->fallback)); - json_object_end(response); - } - - if (tal_count(b11->routes)) { - size_t i, n; - - json_array_start(response, "routes"); - for (i = 0; i < tal_count(b11->routes); i++) { - json_array_start(response, NULL); - for (n = 0; n < tal_count(b11->routes[i]); n++) { - json_object_start(response, NULL); - json_add_pubkey(response, "pubkey", - &b11->routes[i][n].pubkey); - json_add_short_channel_id(response, - "short_channel_id", - &b11->routes[i][n] - .short_channel_id); - json_add_u64(response, "fee", - b11->routes[i][n].fee); - json_add_num(response, "cltv_expiry_delta", - b11->routes[i][n] - .cltv_expiry_delta); - json_object_end(response); - } - json_array_end(response); - } - json_array_end(response); - } - - if (!list_empty(&b11->extra_fields)) { - struct bolt11_field *extra; - - json_array_start(response, "extra"); - list_for_each(&b11->extra_fields, extra, list) { - char *data = tal_arr(cmd, char, tal_len(extra->data)+1); - size_t i; - - for (i = 0; i < tal_len(extra->data); i++) - data[i] = bech32_charset[extra->data[i]]; - data[i] = '\0'; - json_object_start(response, NULL); - json_add_string(response, "tag", - tal_fmt(data, "%c", extra->tag)); - json_add_string(response, "data", data); - tal_free(data); - json_object_end(response); - } - json_array_end(response); - } - - json_add_hex(response, "payment_hash", - &b11->payment_hash, sizeof(b11->payment_hash)); - - json_add_string(response, "signature", - type_to_string(cmd, secp256k1_ecdsa_signature, - &b11->sig)); - json_object_end(response); - command_success(cmd, response); -} - -static const struct json_command decodepay_command = { - "decodepay", - json_decodepay, - "Parse and decode {bolt11} if possible", - "Returns a verbose description on success" -}; -AUTODATA(json_command, &decodepay_command); diff --git a/lightningd/bolt11.h b/common/bolt11.h similarity index 79% rename from lightningd/bolt11.h rename to common/bolt11.h index 73b0a9802..76829232f 100644 --- a/lightningd/bolt11.h +++ b/common/bolt11.h @@ -1,5 +1,5 @@ -#ifndef LIGHTNING_LIGHTNINGD_BOLT11_H -#define LIGHTNING_LIGHTNINGD_BOLT11_H +#ifndef LIGHTNING_COMMON_BOLT11_H +#define LIGHTNING_COMMON_BOLT11_H #include "config.h" #include @@ -7,8 +7,7 @@ #include #include #include - -struct lightningd; +#include /* We only have 10 bits for the field length, meaning < 640 bytes */ #define BOLT11_FIELD_BYTE_LIMIT ((1 << 10) * 5 / 8) @@ -73,9 +72,21 @@ struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str, struct bolt11 *new_bolt11(const tal_t *ctx, u64 *msatoshi); /* Encodes and signs, even if it's nonsense. */ -char *bolt11_encode(const tal_t *ctx, - struct lightningd *ld, - const struct bolt11 *b11, bool n_field); +char *bolt11_encode_(const tal_t *ctx, + const struct bolt11 *b11, bool n_field, + bool (*sign)(const u5 *u5bytes, + const u8 *hrpu8, + secp256k1_ecdsa_recoverable_signature *rsig, + void *arg), + void *arg); + +#define bolt11_encode(ctx, b11, n_field, sign, arg) \ + bolt11_encode_((ctx), (b11), (n_field), \ + typesafe_cb_preargs(bool, void *, (sign), (arg), \ + const u5 *, \ + const u8 *, \ + secp256k1_ecdsa_recoverable_signature *rsig), \ + (arg)) /** * bolt11_out_check - check a bolt11 struct for validity and consistency diff --git a/lightningd/Makefile b/lightningd/Makefile index f150a4f8d..681a420fd 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -16,6 +16,7 @@ default: lightningd-all LIGHTNINGD_COMMON_OBJS := \ common/bech32.o \ common/bip32.o \ + common/bolt11.o \ common/channel_config.o \ common/configdir.o \ common/crypto_state.o \ @@ -42,7 +43,6 @@ LIGHTNINGD_COMMON_OBJS := \ LIGHTNINGD_SRC := \ lightningd/bitcoind.c \ - lightningd/bolt11.c \ lightningd/build_utxos.c \ lightningd/chaintopology.c \ lightningd/gossip_control.c \ diff --git a/lightningd/hsm_control.c b/lightningd/hsm_control.c index 99b50eab9..a4e06089a 100644 --- a/lightningd/hsm_control.c +++ b/lightningd/hsm_control.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/lightningd/invoice.c b/lightningd/invoice.c index c61e288b1..006829b38 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -1,14 +1,22 @@ #include "invoice.h" #include "jsonrpc.h" #include "lightningd.h" +#include +#include +#include #include #include #include +#include +#include #include +#include +#include #include -#include +#include #include #include +#include struct invoice_waiter { struct list_node list; @@ -100,6 +108,25 @@ void resolve_invoice(struct lightningd *ld, struct invoice *invoice) wallet_payment_set_status(ld->wallet, &invoice->rhash, PAYMENT_COMPLETE); } +static bool hsm_sign_b11(const u5 *u5bytes, + const u8 *hrpu8, + secp256k1_ecdsa_recoverable_signature *rsig, + struct lightningd *ld) +{ + u8 *msg = towire_hsmctl_sign_invoice(ld, u5bytes, hrpu8); + + if (!wire_sync_write(ld->hsm_fd, take(msg))) + fatal("Could not write to HSM: %s", strerror(errno)); + + msg = hsm_sync_read(ld, ld); + if (!fromwire_hsmctl_sign_invoice_reply(msg, NULL, rsig)) + fatal("HSM gave bad sign_invoice_reply %s", + tal_hex(msg, msg)); + + tal_free(msg); + return true; +} + static void json_invoice(struct command *cmd, const char *buffer, const jsmntok_t *params) { @@ -178,7 +205,7 @@ static void json_invoice(struct command *cmd, desc->end - desc->start); /* FIXME: add private routes if necessary! */ - b11enc = bolt11_encode(cmd, cmd->ld, b11, false); + b11enc = bolt11_encode(cmd, b11, false, hsm_sign_b11, cmd->ld); /* OK, connect it to main state, respond with hash */ tal_steal(invs, invoice); @@ -421,3 +448,151 @@ static const struct json_command waitinvoice_command = { "Returns {label}, {rhash} and {msatoshi} on success" }; AUTODATA(json_command, &waitinvoice_command); + +static void json_decodepay(struct command *cmd, + const char *buffer, const jsmntok_t *params) +{ + jsmntok_t *bolt11tok, *desctok; + struct bolt11 *b11; + struct json_result *response; + char *str, *desc, *fail; + + if (!json_get_params(buffer, params, + "bolt11", &bolt11tok, + "?description", &desctok, + NULL)) { + command_fail(cmd, "Need bolt11 string"); + return; + } + + str = tal_strndup(cmd, buffer + bolt11tok->start, + bolt11tok->end - bolt11tok->start); + + if (desctok) + desc = tal_strndup(cmd, buffer + desctok->start, + desctok->end - desctok->start); + else + desc = NULL; + + b11 = bolt11_decode(cmd, str, desc, &fail); + + if (!b11) { + command_fail(cmd, "Invalid bolt11: %s", fail); + return; + } + + response = new_json_result(cmd); + json_object_start(response, NULL); + + json_add_string(response, "currency", b11->chain->bip173_name); + json_add_u64(response, "timestamp", b11->timestamp); + json_add_u64(response, "expiry", b11->expiry); + json_add_pubkey(response, "payee", &b11->receiver_id); + if (b11->msatoshi) + json_add_u64(response, "msatoshi", *b11->msatoshi); + if (b11->description) + json_add_string(response, "description", b11->description); + if (b11->description_hash) + json_add_hex(response, "description_hash", + b11->description_hash, + sizeof(*b11->description_hash)); + if (tal_len(b11->fallback)) { + struct bitcoin_address pkh; + struct ripemd160 sh; + struct sha256 wsh; + + json_object_start(response, "fallback"); + if (is_p2pkh(b11->fallback, &pkh)) { + json_add_string(response, "type", "P2PKH"); + json_add_string(response, "addr", + bitcoin_to_base58(cmd, + b11->chain->testnet, + &pkh)); + } else if (is_p2sh(b11->fallback, &sh)) { + json_add_string(response, "type", "P2SH"); + json_add_string(response, "addr", + p2sh_to_base58(cmd, + b11->chain->testnet, + &sh)); + } else if (is_p2wpkh(b11->fallback, &pkh)) { + char out[73 + strlen(b11->chain->bip173_name)]; + json_add_string(response, "type", "P2WPKH"); + if (segwit_addr_encode(out, b11->chain->bip173_name, 0, + (const u8 *)&pkh, sizeof(pkh))) + json_add_string(response, "addr", out); + } else if (is_p2wsh(b11->fallback, &wsh)) { + char out[73 + strlen(b11->chain->bip173_name)]; + json_add_string(response, "type", "P2WSH"); + if (segwit_addr_encode(out, b11->chain->bip173_name, 0, + (const u8 *)&wsh, sizeof(wsh))) + json_add_string(response, "addr", out); + } + json_add_hex(response, "hex", + b11->fallback, tal_len(b11->fallback)); + json_object_end(response); + } + + if (tal_count(b11->routes)) { + size_t i, n; + + json_array_start(response, "routes"); + for (i = 0; i < tal_count(b11->routes); i++) { + json_array_start(response, NULL); + for (n = 0; n < tal_count(b11->routes[i]); n++) { + json_object_start(response, NULL); + json_add_pubkey(response, "pubkey", + &b11->routes[i][n].pubkey); + json_add_short_channel_id(response, + "short_channel_id", + &b11->routes[i][n] + .short_channel_id); + json_add_u64(response, "fee", + b11->routes[i][n].fee); + json_add_num(response, "cltv_expiry_delta", + b11->routes[i][n] + .cltv_expiry_delta); + json_object_end(response); + } + json_array_end(response); + } + json_array_end(response); + } + + if (!list_empty(&b11->extra_fields)) { + struct bolt11_field *extra; + + json_array_start(response, "extra"); + list_for_each(&b11->extra_fields, extra, list) { + char *data = tal_arr(cmd, char, tal_len(extra->data)+1); + size_t i; + + for (i = 0; i < tal_len(extra->data); i++) + data[i] = bech32_charset[extra->data[i]]; + data[i] = '\0'; + json_object_start(response, NULL); + json_add_string(response, "tag", + tal_fmt(data, "%c", extra->tag)); + json_add_string(response, "data", data); + tal_free(data); + json_object_end(response); + } + json_array_end(response); + } + + json_add_hex(response, "payment_hash", + &b11->payment_hash, sizeof(b11->payment_hash)); + + json_add_string(response, "signature", + type_to_string(cmd, secp256k1_ecdsa_signature, + &b11->sig)); + json_object_end(response); + command_success(cmd, response); +} + +static const struct json_command decodepay_command = { + "decodepay", + json_decodepay, + "Parse and decode {bolt11} if possible", + "Returns a verbose description on success" +}; +AUTODATA(json_command, &decodepay_command); diff --git a/lightningd/pay.c b/lightningd/pay.c index 6e9372e17..16c7161cc 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -4,10 +4,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include