From 7525ed787a58a6d79a7f2ab5d69c130ca5dbd205 Mon Sep 17 00:00:00 2001
From: Rusty Russell <rusty@rustcorp.com.au>
Date: Fri, 24 Feb 2017 16:22:56 +1030
Subject: [PATCH] lightningd/hsm: create a peer-seed for peer secrets.

For the moment this is simply handed through to lightningd for
generating the per-peer secrets; eventually the HSM should keep it and
all peer secret key operations would be done via HSM-ops.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 lightningd/hsm/hsm.c                |  9 ++++++++-
 lightningd/hsm/hsm_control_wire_csv |  5 +++--
 lightningd/hsm_control.c            |  1 +
 lightningd/lightningd.c             | 19 +++++++++++++++++++
 lightningd/lightningd.h             |  8 ++++++++
 5 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/lightningd/hsm/hsm.c b/lightningd/hsm/hsm.c
index 5496f049a..ee39361bc 100644
--- a/lightningd/hsm/hsm.c
+++ b/lightningd/hsm/hsm.c
@@ -139,8 +139,14 @@ static u8 *handle_ecdh(struct client *c, const void *data)
 static u8 *init_response(struct conn_info *control)
 {
 	struct pubkey node_id;
+	struct privkey peer_seed;
 	u8 *serialized_extkey = tal_arr(control, u8, BIP32_SERIALIZED_LEN), *msg;
 
+	hkdf_sha256(&peer_seed, sizeof(peer_seed), NULL, 0,
+		    &secretstuff.hsm_secret,
+		    sizeof(secretstuff.hsm_secret),
+		    "peer seed", strlen("peer seed"));
+
 	node_key(NULL, &node_id);
 	if (bip32_key_serialize(&secretstuff.bip32, BIP32_FLAG_KEY_PUBLIC,
 				serialized_extkey, tal_len(serialized_extkey))
@@ -148,7 +154,8 @@ static u8 *init_response(struct conn_info *control)
 		status_failed(WIRE_HSMSTATUS_KEY_FAILED,
 			      "Can't serialize bip32 public key");
 
-	msg = towire_hsmctl_init_response(control, &node_id, serialized_extkey);
+	msg = towire_hsmctl_init_response(control, &node_id, &peer_seed,
+					  serialized_extkey);
 	tal_free(serialized_extkey);
 	return msg;
 }
diff --git a/lightningd/hsm/hsm_control_wire_csv b/lightningd/hsm/hsm_control_wire_csv
index 9815c92fe..45655d338 100644
--- a/lightningd/hsm/hsm_control_wire_csv
+++ b/lightningd/hsm/hsm_control_wire_csv
@@ -4,8 +4,9 @@ hsmctl_init_load,2
 
 hsmctl_init_response,100
 hsmctl_init_response,0,node_id,33
-hsmctl_init_response,33,bip32_len,2
-hsmctl_init_response,35,bip32_seed,bip32_len*1,u8
+hsmctl_init_response,33,peer_seed,32,struct privkey
+hsmctl_init_response,65,bip32_len,2
+hsmctl_init_response,67,bip32_seed,bip32_len*1,u8
 
 # ECDH returns an fd.
 hsmctl_hsmfd_ecdh,3
diff --git a/lightningd/hsm_control.c b/lightningd/hsm_control.c
index f18b2ab48..a715e1ab9 100644
--- a/lightningd/hsm_control.c
+++ b/lightningd/hsm_control.c
@@ -17,6 +17,7 @@ static void hsm_init_done(struct subdaemon *hsm, const u8 *msg,
 	u8 *serialized_extkey;
 
 	if (!fromwire_hsmctl_init_response(hsm, msg, NULL, &ld->dstate.id,
+					   &ld->peer_seed,
 					   &serialized_extkey))
 		errx(1, "HSM did not give init response");
 
diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c
index 48ee163b9..77e3a4289 100644
--- a/lightningd/lightningd.c
+++ b/lightningd/lightningd.c
@@ -4,6 +4,7 @@
 #include "peer_control.h"
 #include "subdaemon.h"
 #include <ccan/array_size/array_size.h>
+#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
 #include <ccan/err/err.h>
 #include <ccan/io/fdpass/fdpass.h>
 #include <ccan/io/io.h>
@@ -71,6 +72,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
 	struct lightningd *ld = tal(ctx, struct lightningd);
 
 	list_head_init(&ld->peers);
+	ld->peer_counter = 0;
 	ld->bip32_max_index = 0;
 	list_head_init(&ld->utxos);
 	ld->dstate.log_book = new_log_book(&ld->dstate, 20*1024*1024,LOG_INFORM);
@@ -143,6 +145,23 @@ static const char *find_my_path(const tal_t *ctx, const char *argv0)
 	return path_dirname(ctx, take(me));
 }
 
+void derive_peer_seed(struct lightningd *ld, struct privkey *peer_seed,
+		      const struct pubkey *peer_id)
+{
+	be64 counter = cpu_to_be64(ld->peer_counter);
+	u8 input[PUBKEY_DER_LEN + sizeof(counter)];
+
+	pubkey_to_der(input, peer_id);
+	memcpy(input + PUBKEY_DER_LEN, &counter, sizeof(counter));
+
+	hkdf_sha256(peer_seed, sizeof(*peer_seed),
+		    input, sizeof(input),
+		    &ld->peer_seed, sizeof(ld->peer_seed),
+		    "per-ppeer seed", strlen("per-peer seed"));
+	/* FIXME: This must be saved in db. */
+	ld->peer_counter++;
+}
+
 int main(int argc, char *argv[])
 {
 	struct lightningd *ld = new_lightningd(NULL);
diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h
index d1bf74cc2..0636e0252 100644
--- a/lightningd/lightningd.h
+++ b/lightningd/lightningd.h
@@ -1,6 +1,7 @@
 #ifndef LIGHTNING_LIGHTNINGD_LIGHTNINGD_H
 #define LIGHTNING_LIGHTNINGD_LIGHTNINGD_H
 #include "config.h"
+#include <bitcoin/privkey.h>
 #include <ccan/container_of/container_of.h>
 #include <daemon/lightningd.h>
 
@@ -30,6 +31,10 @@ struct lightningd {
 
 	/* All peers we're tracking. */
 	struct list_head peers;
+	/* FIXME: This should stay in HSM */
+	struct privkey peer_seed;
+	/* Used to give a unique seed to every peer. */
+	u64 peer_counter;
 
 	/* Public base for bip32 keys, and max we've ever used. */
 	struct ext_key *bip32_base;
@@ -39,6 +44,9 @@ struct lightningd {
 	struct list_head utxos;
 };
 
+void derive_peer_seed(struct lightningd *ld, struct privkey *peer_seed,
+		      const struct pubkey *peer_id);
+
 /* FIXME */
 static inline struct lightningd *
 ld_from_dstate(const struct lightningd_state *dstate)