From 78841456e0b4be404c524bb70cbf0e25b35785c7 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 10 Jan 2017 15:38:33 +1030 Subject: [PATCH] lightningd/handshake: test handshake, produce BOLT 8 test vectors. Signed-off-by: Rusty Russell --- lightningd/handshake/test/.gitignore | 1 + lightningd/handshake/test/Makefile | 16 ++ lightningd/handshake/test/run-handshake.c | 170 ++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 lightningd/handshake/test/.gitignore create mode 100644 lightningd/handshake/test/Makefile create mode 100644 lightningd/handshake/test/run-handshake.c diff --git a/lightningd/handshake/test/.gitignore b/lightningd/handshake/test/.gitignore new file mode 100644 index 000000000..620f7c82e --- /dev/null +++ b/lightningd/handshake/test/.gitignore @@ -0,0 +1 @@ +run-handshake diff --git a/lightningd/handshake/test/Makefile b/lightningd/handshake/test/Makefile new file mode 100644 index 000000000..59f51fec4 --- /dev/null +++ b/lightningd/handshake/test/Makefile @@ -0,0 +1,16 @@ +check: lightningd/handshake-tests + +# Note that these actually #include everything they need, except ccan/ and bitcoin/. +# That allows for unit testing of statics, and special effects. +LIGHTNINGD_HANDSHAKE_TEST_SRC := $(wildcard lightningd/handshake/test/run-*.c) +LIGHTNINGD_HANDSHAKE_TEST_OBJS := $(LIGHTNINGD_HANDSHAKE_TEST_SRC:.c=.o) +LIGHTNINGD_HANDSHAKE_TEST_PROGRAMS := $(LIGHTNINGD_HANDSHAKE_TEST_OBJS:.o=) + +update-mocks: $(LIGHTNINGD_HANDSHAKE_TEST_SRC:%=update-mocks/%) + +$(LIGHTNINGD_HANDSHAKE_TEST_PROGRAMS): $(CCAN_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(LIBBASE58_OBJS) libsecp256k1.a utils.o $(LIGHTNINGD_HANDSHAKE_GEN_SRC:.c=.o) + +$(LIGHTNINGD_HANDSHAKE_TEST_OBJS): $(LIGHTNINGD_HANDSHAKE_HEADERS) $(BITCOIN_HEADERS) $(CORE_HEADERS) $(GEN_HEADERS) $(WIRE_HEADERS) $(CCAN_HEADERS) $(LIBBASE58_HEADERS) + +lightningd/handshake-tests: $(LIGHTNINGD_HANDSHAKE_TEST_PROGRAMS:%=unittest/%) + diff --git a/lightningd/handshake/test/run-handshake.c b/lightningd/handshake/test/run-handshake.c new file mode 100644 index 000000000..bfb1d53ed --- /dev/null +++ b/lightningd/handshake/test/run-handshake.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "status.h" + +/* Since we use pipes, we need different fds for read and write. */ +static int read_fd, write_fd; + +static bool fake_read_all(int fd, void *buf, size_t count) +{ + return read_all(read_fd, buf, count); +} + +static ssize_t fake_write_all(int fd, const void *buf, size_t count) +{ + return write_all(write_fd, buf, count); +} + +static const char *status_prefix; + +/* Simply print out status updates. */ +#define status_send(msg) \ + printf("%s:# Act %s\n", status_prefix, \ + fromwire_peektype(msg) == WIRE_INITR_ACT_ONE ? "One" \ + : fromwire_peektype(msg) == WIRE_INITR_ACT_TWO ? "Two" \ + : fromwire_peektype(msg) == WIRE_INITR_ACT_THREE ? "Three" \ + : fromwire_peektype(msg) == WIRE_RESPR_ACT_ONE ? "One" \ + : fromwire_peektype(msg) == WIRE_RESPR_ACT_TWO ? "Two" \ + : fromwire_peektype(msg) == WIRE_RESPR_ACT_THREE ? "Three" \ + : "UNKNOWN") +#define status_failed(code, fmt, ...) \ + errx(1, "%s:%s:" fmt "\n", status_prefix, #code, __VA_ARGS__) +#define status_trace(fmt, ...) \ + printf("%s:" fmt "\n", status_prefix, __VA_ARGS__) + +#define read_all fake_read_all +#define write_all fake_write_all + +/* No randomness please, we want to replicate test vectors. */ +#include + +static unsigned char e_priv[32]; +#define randombytes_buf(secret, len) memcpy((secret), e_priv, len) + +#define TESTING +#include "../handshake.c" +#include "utils.h" +#include + +secp256k1_context *secp256k1_ctx; +const void *trc; +static struct privkey privkey; + +void hsm_setup(int fd) +{ +} + +bool hsm_do_ecdh(struct sha256 *ss, const struct pubkey *point) +{ + return secp256k1_ecdh(secp256k1_ctx, ss->u.u8, &point->pubkey, + privkey.secret) == 1; +} + +char *type_to_string_(const tal_t *ctx, const char *typename, + union printable_types u) +{ + assert(streq(typename, "struct pubkey")); + return pubkey_to_hexstr(ctx, u.pubkey); +} + +int main(void) +{ + int fds1[2], fds2[2]; + struct pubkey responder_id; + struct privkey responder_privkey; + struct secret ck, sk, rk; + const tal_t *ctx = tal_tmpctx(NULL); + + trc = tal_tmpctx(ctx); + + secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY + | SECP256K1_CONTEXT_SIGN); + + memset(responder_privkey.secret, 0x21, + sizeof(responder_privkey.secret)); + if (!secp256k1_ec_pubkey_create(secp256k1_ctx, + &responder_id.pubkey, + responder_privkey.secret)) + errx(1, "Keygen failed"); + + if (pipe(fds1) != 0 || pipe(fds2) != 0) + err(1, "Making pipes"); + + switch (fork()) { + case -1: + err(1, "fork failed"); + case 0: { + struct pubkey their_id; + + memset(e_priv, 0x22, sizeof(e_priv)); + read_fd = fds1[0]; + write_fd = fds2[1]; + close(fds1[1]); + close(fds2[0]); + privkey = responder_privkey; + status_prefix = "RESPR"; + status_trace("ls.priv: 0x%s", + tal_hexstr(trc, responder_privkey.secret, + sizeof(responder_privkey))); + status_trace("ls.pub: 0x%s", + type_to_string(trc, struct pubkey, &responder_id)); + responder(-1, &responder_id, &their_id, &ck, &sk, &rk); + if (!write_all(write_fd, &ck, sizeof(ck)) + || !write_all(write_fd, &sk, sizeof(sk)) + || !write_all(write_fd, &rk, sizeof(rk))) + err(1, "writing out secrets failed"); + goto out; + } + default: { + struct pubkey initiator_id; + struct privkey initiator_privkey; + struct secret their_ck, their_sk, their_rk; + + read_fd = fds2[0]; + write_fd = fds1[1]; + close(fds2[1]); + close(fds1[0]); + + memset(initiator_privkey.secret, 0x11, + sizeof(initiator_privkey.secret)); + memset(e_priv, 0x12, sizeof(e_priv)); + if (!secp256k1_ec_pubkey_create(secp256k1_ctx, + &initiator_id.pubkey, + initiator_privkey.secret)) + errx(1, "Initiator keygen failed"); + privkey = initiator_privkey; + status_prefix = "INITR"; + status_trace("rs.pub: 0x%s", + type_to_string(trc, struct pubkey, &responder_id)); + status_trace("ls.priv: 0x%s", + tal_hexstr(trc, initiator_privkey.secret, + sizeof(initiator_privkey))); + status_trace("ls.pub: 0x%s", + type_to_string(trc, struct pubkey, &initiator_id)); + + initiator(-1, &initiator_id, &responder_id, &ck, &sk, &rk); + if (!read_all(read_fd, &their_ck, sizeof(their_ck)) + || !read_all(read_fd, &their_sk, sizeof(their_sk)) + || !read_all(read_fd, &their_rk, sizeof(their_rk))) + err(1, "reading their secrets failed"); + + assert(structeq(&ck, &their_ck)); + assert(structeq(&sk, &their_rk)); + assert(structeq(&rk, &their_sk)); + goto out; + } + } + +out: + /* No memory leaks please */ + secp256k1_context_destroy(secp256k1_ctx); + tal_free(ctx); + return 0; +}