From 9449f387acbe79b21bc07cd3ec8bc177f3e1a47c Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 22 Jan 2016 06:41:48 +1030 Subject: [PATCH] daemon: primitive privkey handling. Eventually this will be in a separate process, etc. Signed-off-by: Rusty Russell --- daemon/Makefile | 2 ++ daemon/lightningd.c | 6 +++- daemon/lightningd.h | 7 ++++ daemon/secrets.c | 88 +++++++++++++++++++++++++++++++++++++++++++++ daemon/secrets.h | 15 ++++++++ 5 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 daemon/secrets.c create mode 100644 daemon/secrets.h diff --git a/daemon/Makefile b/daemon/Makefile index d81d23b5d..699cdc9a7 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -19,6 +19,7 @@ DAEMON_SRC := \ daemon/lightningd.c \ daemon/netaddr.c \ daemon/peer.c \ + daemon/secrets.c \ daemon/timeout.c DAEMON_OBJS := $(DAEMON_SRC:.c=.o) @@ -38,6 +39,7 @@ DAEMON_HEADERS := \ daemon/netaddr.h \ daemon/peer.h \ daemon/pseudorand.h \ + daemon/secrets.h \ daemon/timeout.h $(DAEMON_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_CLI_OBJS): $(DAEMON_HEADERS) $(DAEMON_JSMN_HEADERS) $(BITCOIN_HEADERS) $(CORE_HEADERS) $(GEN_HEADERS) $(CCAN_HEADERS) diff --git a/daemon/lightningd.c b/daemon/lightningd.c index 382c280b8..d67a23e4f 100644 --- a/daemon/lightningd.c +++ b/daemon/lightningd.c @@ -3,6 +3,7 @@ #include "lightningd.h" #include "log.h" #include "peer.h" +#include "secrets.h" #include "timeout.h" #include #include @@ -104,7 +105,10 @@ int main(int argc, char *argv[]) /* Set up connections from peers. */ setup_listeners(state, portnum); - + + /* Set up node ID and private key. */ + secrets_init(state); + log_info(state->base_log, "Hello world!"); /* If io_loop returns NULL, either a timer expired, or all fds closed */ diff --git a/daemon/lightningd.h b/daemon/lightningd.h index 64c6f58c8..37c946a42 100644 --- a/daemon/lightningd.h +++ b/daemon/lightningd.h @@ -1,6 +1,7 @@ #ifndef LIGHTNING_DAEMON_LIGHTNING_H #define LIGHTNING_DAEMON_LIGHTNING_H #include "config.h" +#include "bitcoin/pubkey.h" #include #include #include @@ -25,5 +26,11 @@ struct lightningd_state { /* Crypto tables for global use. */ secp256k1_context *secpctx; + + /* Our private key */ + struct secret *secret; + + /* This is us. */ + struct pubkey id; }; #endif /* LIGHTNING_DAEMON_LIGHTNING_H */ diff --git a/daemon/secrets.c b/daemon/secrets.c new file mode 100644 index 000000000..a6118b7c5 --- /dev/null +++ b/daemon/secrets.c @@ -0,0 +1,88 @@ +#include "bitcoin/privkey.h" +#include "bitcoin/shadouble.h" +#include "bitcoin/signature.h" +#include "lightningd.h" +#include "log.h" +#include "peer.h" +#include "secrets.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct secret { + /* Secret ID of our node; public is state->id. */ + struct privkey privkey; +}; + +void privkey_sign(struct peer *peer, const void *src, size_t len, + struct signature *sig) +{ + struct sha256_double h; + + sha256_double(&h, memcheck(src, len), len); + sign_hash(peer->state->secpctx, + &peer->state->secret->privkey, &h, sig); +} + +void secrets_init(struct lightningd_state *state) +{ + int fd; + + state->secret = tal(state, struct secret); + + fd = open("privkey", O_RDONLY); + if (fd < 0) { + if (errno != ENOENT) + fatal("Failed to open privkey: %s", strerror(errno)); + + log_unusual(state->base_log, "Creating privkey file"); + do { + if (RAND_bytes(state->secret->privkey.secret, + sizeof(state->secret->privkey.secret)) + != 1) + fatal("Could not get random bytes for privkey"); + } while (!pubkey_from_privkey(state->secpctx, + &state->secret->privkey, + &state->id, + SECP256K1_EC_COMPRESSED)); + + fd = open("privkey", O_CREAT|O_EXCL|O_WRONLY, 0400); + if (fd < 0) + fatal("Failed to create privkey file: %s", + strerror(errno)); + if (!write_all(fd, state->secret->privkey.secret, + sizeof(state->secret->privkey.secret))) { + unlink_noerr("privkey"); + fatal("Failed to write to privkey file: %s", + strerror(errno)); + } + if (fsync(fd) != 0) + fatal("Failed to sync to privkey file: %s", + strerror(errno)); + close(fd); + + fd = open("privkey", O_RDONLY); + if (fd < 0) + fatal("Failed to reopen privkey: %s", strerror(errno)); + } + if (!read_all(fd, state->secret->privkey.secret, + sizeof(state->secret->privkey.secret))) + fatal("Failed to read privkey: %s", strerror(errno)); + close(fd); + if (!pubkey_from_privkey(state->secpctx, + &state->secret->privkey, &state->id, + SECP256K1_EC_COMPRESSED)) + fatal("Invalid privkey"); + + log_info(state->base_log, "ID: "); + log_add_hex(state->base_log, state->id.der, pubkey_derlen(&state->id)); +} diff --git a/daemon/secrets.h b/daemon/secrets.h new file mode 100644 index 000000000..f5f78d34a --- /dev/null +++ b/daemon/secrets.h @@ -0,0 +1,15 @@ +#ifndef LIGHTNING_DAEMON_SECRETS_H +#define LIGHTNING_DAEMON_SECRETS_H +/* Routines to handle private keys. */ +#include "config.h" + +struct peer; +struct lightningd_state; +struct signature; + +void privkey_sign(struct peer *peer, const void *src, size_t len, + struct signature *sig); + +void secrets_init(struct lightningd_state *state); + +#endif /* LIGHTNING_DAEMON_SECRETS_H */