lightningd/cryptomsg: split raw crypto_state vs peer_crypto_state

Raw crypto_state is what we send across the wire: the peer one is for
use in async crypto io routines (peer_read_message/peer_write_message).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-02-24 16:22:56 +10:30
parent 6cf8a19881
commit 90737371d0
7 changed files with 81 additions and 84 deletions

View File

@ -122,22 +122,22 @@ u8 *cryptomsg_decrypt_body(const tal_t *ctx,
}
static struct io_plan *peer_decrypt_body(struct io_conn *conn,
struct crypto_state *cs)
struct peer_crypto_state *pcs)
{
struct io_plan *plan;
u8 *in, *decrypted;
decrypted = cryptomsg_decrypt_body(cs->in, cs, cs->in);
decrypted = cryptomsg_decrypt_body(pcs->in, &pcs->cs, pcs->in);
if (!decrypted)
return io_close(conn);
/* Steal cs->in: we free it after, and decrypted too unless
* they steal but be careful not to touch anything after
* next_in (could free itself) */
in = tal_steal(NULL, cs->in);
cs->in = NULL;
in = tal_steal(NULL, pcs->in);
pcs->in = NULL;
plan = cs->next_in(conn, cs->peer, decrypted);
plan = pcs->next_in(conn, pcs->peer, decrypted);
tal_free(in);
return plan;
}
@ -174,31 +174,32 @@ bool cryptomsg_decrypt_header(struct crypto_state *cs, u8 hdr[18], u16 *lenp)
}
static struct io_plan *peer_decrypt_header(struct io_conn *conn,
struct crypto_state *cs)
struct peer_crypto_state *pcs)
{
u16 len;
if (!cryptomsg_decrypt_header(cs, cs->in, &len))
if (!cryptomsg_decrypt_header(&pcs->cs, pcs->in, &len))
return io_close(conn);
tal_free(cs->in);
tal_free(pcs->in);
/* BOLT #8:
*
* * Read _exactly_ `l+16` bytes from the network buffer, let
* the bytes be known as `c`.
*/
cs->in = tal_arr(cs, u8, (u32)len + 16);
return io_read(conn, cs->in, tal_count(cs->in), peer_decrypt_body, cs);
pcs->in = tal_arr(conn, u8, (u32)len + 16);
return io_read(conn, pcs->in, tal_count(pcs->in), peer_decrypt_body,
pcs);
}
struct io_plan *peer_read_message(struct io_conn *conn,
struct crypto_state *cs,
struct peer_crypto_state *pcs,
struct io_plan *(*next)(struct io_conn *,
struct peer *,
u8 *msg))
{
assert(!cs->in);
assert(!pcs->in);
/* BOLT #8:
*
* ### Decrypting Messages
@ -208,16 +209,16 @@ struct io_plan *peer_read_message(struct io_conn *conn,
*
* * Read _exactly_ `18-bytes` from the network buffer.
*/
cs->in = tal_arr(cs, u8, 18);
cs->next_in = next;
return io_read(conn, cs->in, 18, peer_decrypt_header, cs);
pcs->in = tal_arr(conn, u8, 18);
pcs->next_in = next;
return io_read(conn, pcs->in, 18, peer_decrypt_header, pcs);
}
static struct io_plan *peer_write_done(struct io_conn *conn,
struct crypto_state *cs)
struct peer_crypto_state *pcs)
{
cs->out = tal_free(cs->out);
return cs->next_out(conn, cs->peer);
pcs->out = tal_free(pcs->out);
return pcs->next_out(conn, pcs->peer);
}
u8 *cryptomsg_encrypt_msg(const tal_t *ctx,
@ -230,7 +231,7 @@ u8 *cryptomsg_encrypt_msg(const tal_t *ctx,
int ret;
u8 *out;
out = tal_arr(cs, u8, sizeof(l) + 16 + mlen + 16);
out = tal_arr(ctx, u8, sizeof(l) + 16 + mlen + 16);
/* BOLT #8:
*
@ -304,41 +305,27 @@ u8 *cryptomsg_encrypt_msg(const tal_t *ctx,
}
struct io_plan *peer_write_message(struct io_conn *conn,
struct crypto_state *cs,
struct peer_crypto_state *pcs,
const u8 *msg,
struct io_plan *(*next)(struct io_conn *,
struct peer *))
{
assert(!cs->out);
assert(!pcs->out);
cs->out = cryptomsg_encrypt_msg(cs, cs, msg);
cs->next_out = next;
pcs->out = cryptomsg_encrypt_msg(conn, &pcs->cs, msg);
pcs->next_out = next;
/* BOLT #8:
* * Send `lc || c` over the network buffer.
*/
return io_write(conn, cs->out, tal_count(cs->out), peer_write_done, cs);
return io_write(conn, pcs->out, tal_count(pcs->out),
peer_write_done, pcs);
}
struct crypto_state *crypto_state(struct peer *peer,
const struct sha256 *sk,
const struct sha256 *rk,
const struct sha256 *rck,
const struct sha256 *sck,
u64 rn, u64 sn)
void init_peer_crypto_state(struct peer *peer, struct peer_crypto_state *pcs)
{
struct crypto_state *cs = tal(peer, struct crypto_state);
cs->rn = rn;
cs->sn = sn;
cs->sk = *sk;
cs->rk = *rk;
cs->s_ck = *sck;
cs->r_ck = *rck;
cs->peer = peer;
cs->out = cs->in = NULL;
return cs;
pcs->peer = peer;
pcs->out = pcs->in = NULL;
}
void towire_crypto_state(u8 **ptr, const struct crypto_state *cs)

View File

@ -15,6 +15,10 @@ struct crypto_state {
struct sha256 sk, rk;
/* Chaining key for re-keying */
struct sha256 s_ck, r_ck;
};
struct peer_crypto_state {
struct crypto_state cs;
/* Peer who owns us: peer->crypto_state == this */
struct peer *peer;
@ -25,24 +29,19 @@ struct crypto_state {
struct io_plan *(*next_out)(struct io_conn *, struct peer *);
};
/* Initializes peer->crypto_state */
struct crypto_state *crypto_state(struct peer *peer,
const struct sha256 *sk,
const struct sha256 *rk,
const struct sha256 *rck,
const struct sha256 *sck,
u64 rn, u64 sn);
/* Initializes peer->cs (still need to read in cs->cs) */
void init_peer_crypto_state(struct peer *peer, struct peer_crypto_state *pcs);
/* Get decrypted message */
struct io_plan *peer_read_message(struct io_conn *conn,
struct crypto_state *cs,
struct peer_crypto_state *cs,
struct io_plan *(*next)(struct io_conn *,
struct peer *,
u8 *msg));
/* Sends and frees message */
struct io_plan *peer_write_message(struct io_conn *conn,
struct crypto_state *cs,
struct peer_crypto_state *cs,
const u8 *msg,
struct io_plan *(*next)(struct io_conn *,
struct peer *));

View File

@ -46,7 +46,7 @@ struct peer {
struct list_node list;
u64 unique_id;
struct crypto_state *cs;
struct peer_crypto_state pcs;
/* File descriptor corresponding to conn. */
int fd;
@ -76,10 +76,11 @@ static void destroy_peer(struct peer *peer)
static struct peer *setup_new_peer(struct daemon *daemon, const u8 *msg)
{
struct peer *peer = tal(daemon, struct peer);
peer->cs = tal(peer, struct crypto_state);
if (!fromwire_gossipctl_new_peer(msg, NULL, &peer->unique_id, peer->cs))
init_peer_crypto_state(peer, &peer->pcs);
if (!fromwire_gossipctl_new_peer(msg, NULL, &peer->unique_id,
&peer->pcs.cs))
return tal_free(peer);
peer->cs->peer = peer;
peer->daemon = daemon;
peer->error = NULL;
peer->msg_out = tal_arr(peer, u8*, 0);
@ -102,15 +103,15 @@ static struct io_plan *peer_msgin(struct io_conn *conn,
case WIRE_CHANNEL_ANNOUNCEMENT:
handle_channel_announcement(peer->daemon->rstate, msg, tal_count(msg));
return peer_read_message(conn, peer->cs, peer_msgin);
return peer_read_message(conn, &peer->pcs, peer_msgin);
case WIRE_NODE_ANNOUNCEMENT:
handle_node_announcement(peer->daemon->rstate, msg, tal_count(msg));
return peer_read_message(conn, peer->cs, peer_msgin);
return peer_read_message(conn, &peer->pcs, peer_msgin);
case WIRE_CHANNEL_UPDATE:
handle_channel_update(peer->daemon->rstate, msg, tal_count(msg));
return peer_read_message(conn, peer->cs, peer_msgin);
return peer_read_message(conn, &peer->pcs, peer_msgin);
case WIRE_INIT:
peer->error = "Duplicate INIT message received";
@ -133,7 +134,7 @@ static struct io_plan *peer_msgin(struct io_conn *conn,
case WIRE_REVOKE_AND_ACK:
/* Not our place to handle this, so we punt */
s = towire_gossipstatus_peer_nongossip(msg, peer->unique_id,
peer->cs, msg);
&peer->pcs.cs, msg);
status_send(s);
status_send_fd(io_conn_fd(conn));
return io_close(conn);
@ -147,7 +148,7 @@ static struct io_plan *peer_msgin(struct io_conn *conn,
if (t & 1) {
status_trace("Peer %"PRIu64" sent unknown packet %u, ignoring",
peer->unique_id, t);
return peer_read_message(conn, peer->cs, peer_msgin);
return peer_read_message(conn, &peer->pcs, peer_msgin);
}
peer->error = tal_fmt(peer, "Unknown packet %u", t);
return io_close(conn);
@ -183,7 +184,8 @@ static struct io_plan *peer_dump_gossip(struct io_conn *conn, struct peer *peer)
/* Going to wake up in pkt_out since we mix time based and message based wakeups */
return io_out_wait(conn, peer, pkt_out, peer);
} else {
return peer_write_message(conn, peer->cs, next->payload, peer_dump_gossip);
return peer_write_message(conn, &peer->pcs, next->payload,
peer_dump_gossip);
}
}
@ -196,7 +198,7 @@ static struct io_plan *pkt_out(struct io_conn *conn, struct peer *peer)
out = peer->msg_out[0];
memmove(peer->msg_out, peer->msg_out + 1, (sizeof(*peer->msg_out)*(n-1)));
tal_resize(&peer->msg_out, n-1);
return peer_write_message(conn, peer->cs, out, pkt_out);
return peer_write_message(conn, &peer->pcs, out, pkt_out);
}
if (peer->gossip_sync){
@ -259,13 +261,13 @@ static struct io_plan *peer_parse_init(struct io_conn *conn,
/* Need to go duplex here, otherwise backpressure would mean
* we both wait indefinitely */
return io_duplex(conn,
peer_read_message(conn, peer->cs, peer_msgin),
peer_read_message(conn, &peer->pcs, peer_msgin),
peer_dump_gossip(conn, peer));
}
static struct io_plan *peer_init_sent(struct io_conn *conn, struct peer *peer)
{
return peer_read_message(conn, peer->cs, peer_parse_init);
return peer_read_message(conn, &peer->pcs, peer_parse_init);
}
static struct io_plan *peer_send_init(struct io_conn *conn, struct peer *peer)
@ -278,7 +280,8 @@ static struct io_plan *peer_send_init(struct io_conn *conn, struct peer *peer)
* SHOULD set feature bits corresponding to features it optionally
* supports.
*/
return peer_write_message(conn, peer->cs, towire_init(peer, NULL, NULL),
return peer_write_message(conn, &peer->pcs,
towire_init(peer, NULL, NULL),
peer_init_sent);
}
@ -337,7 +340,7 @@ static struct io_plan *release_peer(struct io_conn *conn, struct daemon *daemon,
out = towire_gossipctl_release_peer_response(msg,
unique_id,
peer->cs);
&peer->pcs.cs);
return io_write_wire(conn, out, release_peer_fd, peer);
}
}

View File

@ -46,17 +46,16 @@ static void peer_nongossip(struct subdaemon *gossip, const u8 *msg, int fd)
u64 unique_id;
struct peer *peer;
u8 *inner;
struct crypto_state *cs = tal(msg, struct crypto_state);
struct crypto_state cs;
if (!fromwire_gossipstatus_peer_nongossip(msg, msg, NULL,
&unique_id, cs, &inner))
&unique_id, &cs, &inner))
fatal("Gossip gave bad PEER_NONGOSSIP message %s",
tal_hex(msg, msg));
peer = peer_by_unique_id(gossip->ld, unique_id);
if (!peer)
fatal("Gossip gave bad peerid %"PRIu64, unique_id);
cs->peer = peer;
log_debug(gossip->log, "Peer %s said %s",
type_to_string(msg, struct pubkey, peer->id),

View File

@ -972,7 +972,7 @@ int main(int argc, char *argv[])
struct pubkey my_id, their_id;
int hsmfd = 3, clientfd = 4;
struct secret ck, rk, sk;
struct crypto_state *cs;
struct crypto_state cs;
if (argc == 2 && streq(argv[1], "--version")) {
printf("%s\n", version());
@ -994,17 +994,23 @@ int main(int argc, char *argv[])
if (fromwire_handshake_responder_req(msg, NULL, &my_id)) {
responder(clientfd, &my_id, &their_id, &ck, &sk, &rk);
cs = crypto_state(NULL, &sk.s, &rk.s, &ck.s, &ck.s, 0, 0);
cs.rn = cs.sn = 0;
cs.sk = sk.s;
cs.rk = rk.s;
cs.r_ck = cs.s_ck = ck.s;
wire_sync_write(REQ_FD,
towire_handshake_responder_resp(msg,
&their_id,
cs));
&cs));
} else if (fromwire_handshake_initiator_req(msg, NULL, &my_id,
&their_id)) {
initiator(clientfd, &my_id, &their_id, &ck, &sk, &rk);
cs = crypto_state(NULL, &sk.s, &rk.s, &ck.s, &ck.s, 0, 0);
cs.rn = cs.sn = 0;
cs.sk = sk.s;
cs.rk = rk.s;
cs.r_ck = cs.s_ck = ck.s;
wire_sync_write(REQ_FD,
towire_handshake_initiator_resp(msg, cs));
towire_handshake_initiator_resp(msg, &cs));
} else
status_failed(WIRE_HANDSHAKE_BAD_COMMAND, "%i", fromwire_peektype(msg));

View File

@ -88,23 +88,22 @@ struct peer *peer_by_unique_id(struct lightningd *ld, u64 unique_id)
static void handshake_succeeded(struct subdaemon *hs, const u8 *msg,
struct peer *peer)
{
struct crypto_state *cs = tal(peer, struct crypto_state);
struct crypto_state cs;
if (!peer->id) {
struct pubkey id;
if (!fromwire_handshake_responder_resp(msg, NULL, &id, cs))
if (!fromwire_handshake_responder_resp(msg, NULL, &id, &cs))
goto err;
peer->id = tal_dup(peer, struct pubkey, &id);
log_info_struct(hs->log, "Peer in from %s",
struct pubkey, peer->id);
} else {
if (!fromwire_handshake_initiator_resp(msg, NULL, cs))
if (!fromwire_handshake_initiator_resp(msg, NULL, &cs))
goto err;
log_info_struct(hs->log, "Peer out to %s",
struct pubkey, peer->id);
}
cs->peer = peer;
/* FIXME: Look for peer duplicates! */
@ -117,7 +116,7 @@ static void handshake_succeeded(struct subdaemon *hs, const u8 *msg,
peer_set_condition(peer, "Beginning gossip");
/* Tell gossip to handle it now. */
msg = towire_gossipctl_new_peer(msg, peer->unique_id, cs);
msg = towire_gossipctl_new_peer(msg, peer->unique_id, &cs);
subdaemon_req(peer->ld->gossip, msg, peer->fd, &peer->fd, NULL, NULL);
/* Peer struct longer owns fd. */

View File

@ -67,7 +67,7 @@ static struct sha256 sha256_from_hex(const char *hex)
int main(void)
{
tal_t *tmpctx = tal_tmpctx(NULL);
struct crypto_state *cs_out, *cs_in;
struct peer_crypto_state cs_out, cs_in;
struct sha256 sk, rk, ck;
const void *msg = tal_dup_arr(tmpctx, char, "hello", 5, 0);
size_t i;
@ -89,13 +89,17 @@ int main(void)
sk = sha256_from_hex("0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9");
rk = sha256_from_hex("0xbb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442");
cs_out = crypto_state(tmpctx, &sk, &rk, &ck, &ck, 0, 0);
cs_in = crypto_state(tmpctx, &rk, &sk, &ck, &ck, 0, 0);
cs_out.cs.sn = cs_out.cs.rn = cs_in.cs.sn = cs_in.cs.rn = 0;
cs_out.cs.sk = cs_in.cs.rk = sk;
cs_out.cs.rk = cs_in.cs.sk = rk;
cs_out.cs.s_ck = cs_out.cs.r_ck = cs_in.cs.s_ck = cs_in.cs.r_ck = ck;
init_peer_crypto_state(tmpctx, &cs_in);
init_peer_crypto_state(tmpctx, &cs_out);
for (i = 0; i < 1002; i++) {
write_buf = tal_arr(tmpctx, char, 0);
peer_write_message(NULL, cs_out, msg, check_msg_write);
peer_write_message(NULL, &cs_out, msg, check_msg_write);
if ((i % 500) < 2)
status_trace("output %zu: 0x%s", i,
tal_hex(tmpctx, write_buf));
@ -104,7 +108,7 @@ int main(void)
read_buf_len = tal_count(read_buf);
write_buf = tal_arr(tmpctx, char, 0);
peer_read_message(NULL, cs_in, check_msg_read);
peer_read_message(NULL, &cs_in, check_msg_read);
assert(read_buf_len == 0);
}
tal_free(tmpctx);