Browse Source

common: generalize ecdh function.

common/onion is going to need to use this for the case where it finds a blinding
seed inside the TLV.  But how it does ecdh is daemon-specific.

We already had this problem for devtools/gossipwith, which supplied a
special hsm_do_ecdh().  This just makes it more general.

So we create a generic ecdh() interface, with a specific implementation
which subdaemons and lightningd can use.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
travis-debug
Rusty Russell 5 years ago
parent
commit
3b4a06f52b
  1. 1
      channeld/Makefile
  2. 20
      channeld/channeld.c
  3. 2
      common/Makefile
  4. 13
      common/ecdh.h
  5. 29
      common/ecdh_hsmd.c
  6. 13
      common/ecdh_hsmd.h
  7. 4
      common/test/run-sphinx.c
  8. 1
      connectd/Makefile
  9. 35
      connectd/connectd.c
  10. 13
      connectd/handshake.c
  11. 3
      connectd/handshake.h
  12. 6
      connectd/test/run-initiator-success.c
  13. 6
      connectd/test/run-responder-success.c
  14. 6
      devtools/Makefile
  15. 7
      devtools/blindedpath.c
  16. 6
      devtools/gossipwith.c
  17. 7
      devtools/onion.c
  18. 1
      lightningd/Makefile
  19. 13
      lightningd/hsm_control.c
  20. 12
      lightningd/lightningd.c
  21. 5
      lightningd/test/run-find_my_abspath.c

1
channeld/Makefile

@ -46,6 +46,7 @@ CHANNELD_COMMON_OBJS := \
common/daemon_conn.o \
common/derive_basepoints.o \
common/dev_disconnect.o \
common/ecdh_hsmd.o \
common/features.o \
common/fee_states.o \
common/gen_status_wire.o \

20
channeld/channeld.c

@ -30,6 +30,7 @@
#include <common/blinding.h>
#include <common/crypto_sync.h>
#include <common/dev_disconnect.h>
#include <common/ecdh_hsmd.h>
#include <common/features.h>
#include <common/gossip_constants.h>
#include <common/gossip_store.h>
@ -1668,11 +1669,7 @@ static void handle_onion_message(struct peer *peer, const u8 *msg)
status_debug("blinding in = %s",
type_to_string(tmpctx, struct pubkey, blinding_in));
blinding_ss = tal(msg, struct secret);
msg = hsm_req(tmpctx, towire_hsm_ecdh_req(tmpctx, blinding_in));
if (!fromwire_hsm_ecdh_resp(msg, blinding_ss))
status_failed(STATUS_FAIL_HSM_IO,
"Reading ecdh response for blinding");
ecdh(blinding_in, blinding_ss);
/* b(i) = HMAC256("blinded_node_id", ss(i)) * k(i) */
subkey_from_hmac("blinded_node_id", blinding_ss, &hmac);
@ -1691,9 +1688,7 @@ static void handle_onion_message(struct peer *peer, const u8 *msg)
blinding_in = NULL;
}
msg = hsm_req(tmpctx, towire_hsm_ecdh_req(tmpctx, &op.ephemeralkey));
if (!fromwire_hsm_ecdh_resp(msg, &ss))
status_failed(STATUS_FAIL_HSM_IO, "Reading ecdh response");
ecdh(&op.ephemeralkey, &ss);
/* We make sure we can parse onion packet, so we know if shared secret
* is actually valid (this checks hmac). */
@ -1733,11 +1728,7 @@ static void handle_onion_message(struct peer *peer, const u8 *msg)
*blinding_in = om->blinding->blinding;
blinding_ss = tal(msg, struct secret);
msg = hsm_req(tmpctx, towire_hsm_ecdh_req(tmpctx, blinding_in));
if (!fromwire_hsm_ecdh_resp(msg, blinding_ss))
status_failed(STATUS_FAIL_HSM_IO,
"Reading ecdh response for om blinding");
ecdh(blinding_in, blinding_ss);
}
if (om->enctlv) {
@ -3218,6 +3209,9 @@ int main(int argc, char *argv[])
sizeof(peer->announcement_bitcoin_sigs[i]));
}
/* Prepare the ecdh() function for use */
ecdh_hsmd_setup(HSM_FD, status_failed);
/* Read init_channel message sync. */
init_channel(peer);

2
common/Makefile

@ -20,6 +20,7 @@ COMMON_SRC_NOGEN := \
common/decode_array.c \
common/derive_basepoints.c \
common/dev_disconnect.c \
common/ecdh_hsmd.c \
common/features.c \
common/fee_states.c \
common/funding_tx.c \
@ -72,6 +73,7 @@ COMMON_SRC_NOGEN := \
COMMON_SRC_GEN := common/gen_status_wire.c common/gen_peer_status_wire.c
COMMON_HEADERS_NOGEN := $(COMMON_SRC_NOGEN:.c=.h) \
common/ecdh.h \
common/errcode.h \
common/gossip_constants.h \
common/htlc.h \

13
common/ecdh.h

@ -0,0 +1,13 @@
#ifndef LIGHTNING_COMMON_ECDH_H
#define LIGHTNING_COMMON_ECDH_H
#include "config.h"
struct pubkey;
struct secret;
/* This function is implemented differently in various daemons and tools:
* subdaemons need to talk to the HSM via hsm_fd, lightningd needs to use
* its HSM interface, and tools can implement this directly. */
void ecdh(const struct pubkey *point, struct secret *ss);
#endif /* LIGHTNING_COMMON_ECDH_H */

29
common/ecdh_hsmd.c

@ -0,0 +1,29 @@
#include <common/ecdh_hsmd.h>
#include <hsmd/gen_hsm_wire.h>
#include <wire/wire_sync.h>
static int stashed_hsm_fd = -1;
static void (*stashed_failed)(enum status_failreason, const char *fmt, ...);
void ecdh(const struct pubkey *point, struct secret *ss)
{
const u8 *msg = towire_hsm_ecdh_req(NULL, point);
if (!wire_sync_write(stashed_hsm_fd, take(msg)))
stashed_failed(STATUS_FAIL_HSM_IO, "Write ECDH to hsmd failed");
msg = wire_sync_read(tmpctx, stashed_hsm_fd);
if (!msg)
stashed_failed(STATUS_FAIL_HSM_IO, "No hsmd ECDH response");
if (!fromwire_hsm_ecdh_resp(msg, ss))
stashed_failed(STATUS_FAIL_HSM_IO, "Invalid hsmd ECDH response");
}
void ecdh_hsmd_setup(int hsm_fd,
void (*failed)(enum status_failreason,
const char *fmt, ...))
{
stashed_hsm_fd = hsm_fd;
stashed_failed = failed;
}

13
common/ecdh_hsmd.h

@ -0,0 +1,13 @@
#ifndef LIGHTNING_COMMON_ECDH_HSMD_H
#define LIGHTNING_COMMON_ECDH_HSMD_H
#include "config.h"
#include <common/ecdh.h>
#include <common/status_levels.h>
/* The via-the-hsmd implementation of ecdh(). */
/* You must call this before calling ecdh(). */
void ecdh_hsmd_setup(int hsm_fd,
void (*failed)(enum status_failreason,
const char *fmt, ...));
#endif /* LIGHTNING_COMMON_ECDH_HSMD_H */

4
common/test/run-sphinx.c

@ -7,6 +7,7 @@
#include <ccan/short_types/short_types.h>
#include <string.h>
#include <ccan/str/hex/hex.h>
#include <common/ecdh.h>
#include <common/sphinx.h>
#include <common/utils.h>
#include <err.h>
@ -46,6 +47,9 @@ size_t bigsize_get(const u8 *p UNNEEDED, size_t max UNNEEDED, bigsize_t *val UNN
/* Generated stub for bigsize_put */
size_t bigsize_put(u8 buf[BIGSIZE_MAX_LEN] UNNEEDED, bigsize_t v UNNEEDED)
{ fprintf(stderr, "bigsize_put called!\n"); abort(); }
/* Generated stub for ecdh */
void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED)
{ fprintf(stderr, "ecdh called!\n"); abort(); }
/* Generated stub for pubkey_from_node_id */
bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED)
{ fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); }

1
connectd/Makefile

@ -50,6 +50,7 @@ CONNECTD_COMMON_OBJS := \
common/daemon_conn.o \
common/derive_basepoints.o \
common/dev_disconnect.o \
common/ecdh_hsmd.o \
common/features.o \
common/gen_status_wire.o \
common/gossip_rcvd_filter.o \

35
connectd/connectd.c

@ -29,6 +29,7 @@
#include <common/cryptomsg.h>
#include <common/daemon_conn.h>
#include <common/decode_array.h>
#include <common/ecdh_hsmd.h>
#include <common/errcode.h>
#include <common/features.h>
#include <common/jsonrpc_errors.h>
@ -1157,8 +1158,11 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx,
randombytes_buf((void * const)&random, 32);
/* generate static tor node address, take first 32 bytes from secret of node_id plus 32 random bytes from sodiom */
struct sha256 sha;
struct secret ss;
ecdh(&pb, &ss);
/* let's sha, that will clear ctx of hsm data */
sha256(&sha, hsm_do_ecdh(tmpctx, &pb), 32);
sha256(&sha, &ss, 32);
/* even if it's a secret pub derived, tor shall see only the single sha */
memcpy((void *)&blob[0], &sha, 32);
memcpy((void *)&blob[32], &random, 32);
@ -1578,31 +1582,6 @@ static struct io_plan *recv_req(struct io_conn *conn,
t, tal_hex(tmpctx, msg));
}
/*~ Helper for handshake.c: we ask `hsmd` to do the ECDH to get the shared
* secret. It's here because it's nicer then giving the handshake code
* knowledge of the HSM, but also at one stage I made a hacky gossip vampire
* tool which used the handshake code, so it's nice to keep that
* standalone. */
struct secret *hsm_do_ecdh(const tal_t *ctx, const struct pubkey *point)
{
u8 *req = towire_hsm_ecdh_req(tmpctx, point), *resp;
struct secret *secret = tal(ctx, struct secret);
if (!wire_sync_write(HSM_FD, req))
return tal_free(secret);
resp = wire_sync_read(req, HSM_FD);
if (!resp)
return tal_free(secret);
/* Note: hsmd will actually hang up on us if it can't ECDH: that implies
* that our node private key is invalid, and we shouldn't have made
* it this far. */
if (!fromwire_hsm_ecdh_resp(resp, secret))
return tal_free(secret);
return secret;
}
/*~ UNUSED is defined to an __attribute__ for GCC; at one stage we tried to use
* it ubiquitously to make us compile cleanly with -Wunused, but it's bitrotted
* and we'd need to start again.
@ -1648,6 +1627,10 @@ int main(int argc, char *argv[])
* our status_ and failed messages. */
status_setup_async(daemon->master);
/* Set up ecdh() function so it uses our HSM fd, and calls
* status_failed on error. */
ecdh_hsmd_setup(HSM_FD, status_failed);
/* Should never exit. */
io_loop(NULL, NULL);
abort();

13
connectd/handshake.c

@ -7,6 +7,7 @@
#include <ccan/io/io.h>
#include <ccan/mem/mem.h>
#include <common/crypto_state.h>
#include <common/ecdh.h>
#include <common/status.h>
#include <common/type_to_string.h>
#include <common/utils.h>
@ -471,10 +472,8 @@ static struct io_plan *act_three_initiator(struct io_conn *conn,
* 3. `se = ECDH(s.priv, re)`
* * where `re` is the ephemeral public key of the responder
*/
h->ss = hsm_do_ecdh(h, &h->re);
if (!h->ss)
return handshake_failed(conn, h);
h->ss = tal(h, struct secret);
ecdh(&h->re, h->ss);
SUPERVERBOSE("# ss=0x%s", tal_hexstr(tmpctx, h->ss, sizeof(*h->ss)));
/* BOLT #8:
@ -903,10 +902,8 @@ static struct io_plan *act_one_responder2(struct io_conn *conn,
* * The responder performs an ECDH between its static private key and
* the initiator's ephemeral public key.
*/
h->ss = hsm_do_ecdh(h, &h->re);
if (!h->ss)
return handshake_failed(conn, h);
h->ss = tal(h, struct secret);
ecdh(&h->re, h->ss);
SUPERVERBOSE("# ss=0x%s", tal_hexstr(tmpctx, h->ss, sizeof(*h->ss)));
/* BOLT #8:

3
connectd/handshake.h

@ -51,7 +51,4 @@ struct io_plan *responder_handshake_(struct io_conn *conn,
struct crypto_state *,
void *cbarg),
void *cbarg);
/* helper which is defined in connect.c */
struct secret *hsm_do_ecdh(const tal_t *ctx, const struct pubkey *point);
#endif /* LIGHTNING_CONNECTD_HANDSHAKE_H */

6
connectd/test/run-initiator-success.c

@ -229,13 +229,11 @@ static struct io_plan *success(struct io_conn *conn UNUSED,
exit(0);
}
struct secret *hsm_do_ecdh(const tal_t *ctx, const struct pubkey *point)
void ecdh(const struct pubkey *point, struct secret *ss)
{
struct secret *ss = tal(ctx, struct secret);
if (secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey,
ls_priv.secret.data, NULL, NULL) != 1)
return tal_free(ss);
return ss;
abort();
}
int main(void)

6
connectd/test/run-responder-success.c

@ -229,13 +229,11 @@ static struct io_plan *success(struct io_conn *conn UNUSED,
exit(0);
}
struct secret *hsm_do_ecdh(const tal_t *ctx, const struct pubkey *point)
void ecdh(const struct pubkey *point, struct secret *ss)
{
struct secret *ss = tal(ctx, struct secret);
if (secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey,
ls_priv.secret.data, NULL, NULL) != 1)
return tal_free(ss);
return ss;
abort();
}
int main(void)

6
devtools/Makefile

@ -27,8 +27,6 @@ DEVTOOLS_COMMON_OBJS := \
common/htlc_state.o \
common/memleak.o \
common/node_id.o \
common/onion.o \
common/onionreply.o \
common/per_peer_state.o \
common/pseudorand.o \
common/json.o \
@ -68,9 +66,9 @@ devtools/create-gossipstore.o: gossipd/gen_gossip_store.h
devtools/onion.c: ccan/config.h
devtools/onion: $(DEVTOOLS_OBJS) $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/onion.o common/sphinx.o
devtools/onion: $(DEVTOOLS_OBJS) $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) common/onion.o common/onionreply.o wire/fromwire.o wire/towire.o devtools/onion.o common/sphinx.o
devtools/blindedpath: $(DEVTOOLS_OBJS) $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) common/blinding.o $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/blindedpath.o common/sphinx.o
devtools/blindedpath: $(DEVTOOLS_OBJS) $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) common/blinding.o $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/blindedpath.o common/onion.o common/onionreply.o common/sphinx.o
devtools/gossipwith: $(DEVTOOLS_OBJS) $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o wire/gen_peer_wire.o devtools/gossipwith.o common/cryptomsg.o common/cryptomsg.o common/crypto_sync.o

7
devtools/blindedpath.c

@ -7,6 +7,7 @@
#include <ccan/str/hex/hex.h>
#include <ccan/tal/tal.h>
#include <common/blinding.h>
#include <common/ecdh.h>
#include <common/hmac.h>
#include <common/sphinx.h>
#include <common/type_to_string.h>
@ -41,6 +42,12 @@ static void tal_freefn(void *ptr)
tal_free(ptr);
}
/* We don't actually use this, but common/onion needs it */
void ecdh(const struct pubkey *point, struct secret *ss)
{
abort();
}
int main(int argc, char **argv)
{
bool first = false;

6
devtools/gossipwith.c

@ -104,13 +104,11 @@ void peer_failed_connection_lost(void)
exit(0);
}
struct secret *hsm_do_ecdh(const tal_t *ctx, const struct pubkey *point)
void ecdh(const struct pubkey *point, struct secret *ss)
{
struct secret *ss = tal(ctx, struct secret);
if (secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey,
notsosecret.data, NULL, NULL) != 1)
return tal_free(ss);
return ss;
abort();
}
/* We don't want to discard *any* messages. */

7
devtools/onion.c

@ -7,6 +7,7 @@
#include <ccan/tal/grab_file/grab_file.h>
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/ecdh.h>
#include <common/json.h>
#include <common/json_helpers.h>
#include <common/onion.h>
@ -19,6 +20,12 @@
#include <string.h>
#include <unistd.h>
/* We don't actually use this, but common/onion needs it */
void ecdh(const struct pubkey *point, struct secret *ss)
{
abort();
}
static void do_generate(int argc, char **argv,
const u8 *assocdata,
const struct node_id *rvnode_id)

1
lightningd/Makefile

@ -28,6 +28,7 @@ LIGHTNINGD_COMMON_OBJS := \
common/crypto_state.o \
common/daemon.o \
common/derive_basepoints.o \
common/ecdh_hsmd.o \
common/features.o \
common/fee_states.o \
common/funding_tx.o \

13
lightningd/hsm_control.c

@ -5,6 +5,7 @@
#include <ccan/fdpass/fdpass.h>
#include <ccan/io/io.h>
#include <ccan/take/take.h>
#include <common/ecdh.h>
#include <common/json.h>
#include <common/jsonrpc_errors.h>
#include <common/param.h>
@ -134,10 +135,8 @@ static struct command_result *json_getsharedsecret(struct command *cmd,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct lightningd *ld = cmd->ld;
struct pubkey *point;
struct secret ss;
u8 *msg;
struct json_stream *response;
if (!param(cmd, buffer, params,
@ -145,15 +144,7 @@ static struct command_result *json_getsharedsecret(struct command *cmd,
NULL))
return command_param_failed();
msg = towire_hsm_ecdh_req(NULL, point);
if (!wire_sync_write(ld->hsm_fd, take(msg)))
return command_fail(cmd, HSM_ECDH_FAILED,
"Failed to request ECDH to HSM");
msg = wire_sync_read(tmpctx, ld->hsm_fd);
if (!fromwire_hsm_ecdh_resp(msg, &ss))
return command_fail(cmd, HSM_ECDH_FAILED,
"Failed HSM response for ECDH");
ecdh(point, &ss);
response = json_stream_success(cmd);
json_add_secret(response, "shared_secret", &ss);
return command_success(cmd, response);

12
lightningd/lightningd.c

@ -57,6 +57,7 @@
/*~ This is common code: routines shared by one or more executables
* (separate daemons, or the lightning-cli program). */
#include <common/daemon.h>
#include <common/ecdh_hsmd.h>
#include <common/features.h>
#include <common/memleak.h>
#include <common/timeout.h>
@ -736,6 +737,14 @@ static struct feature_set *default_features(const tal_t *ctx)
return ret;
}
/*~ We need this function style to hand to ecdh_hsmd_setup, but it's just a thin
* wrapper around fatal() */
static void hsm_ecdh_failed(enum status_failreason fail,
const char *fmt, ...)
{
fatal("hsm failure: %s", fmt);
}
int main(int argc, char *argv[])
{
struct lightningd *ld;
@ -964,6 +973,9 @@ int main(int argc, char *argv[])
* a backtrace if we fail during startup. */
crashlog = ld->log;
/*~ This sets up the ecdh() function in ecdh_hsmd to talk to hsmd */
ecdh_hsmd_setup(ld->hsm_fd, hsm_ecdh_failed);
/*~ The root of every backtrace (almost). This is our main event
* loop. */
void *io_loop_ret = io_loop_with_timers(ld);

5
lightningd/test/run-find_my_abspath.c

@ -57,6 +57,11 @@ s64 db_get_intvar(struct db *db UNNEEDED, char *varname UNNEEDED, s64 defval UNN
/* Generated stub for db_in_transaction */
bool db_in_transaction(struct db *db UNNEEDED)
{ fprintf(stderr, "db_in_transaction called!\n"); abort(); }
/* Generated stub for ecdh_hsmd_setup */
void ecdh_hsmd_setup(int hsm_fd UNNEEDED,
void (*failed)(enum status_failreason UNNEEDED,
const char *fmt UNNEEDED, ...))
{ fprintf(stderr, "ecdh_hsmd_setup called!\n"); abort(); }
/* Generated stub for fatal */
void fatal(const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "fatal called!\n"); abort(); }

Loading…
Cancel
Save