Browse Source

channeld: send shared secrets with initial got_commitsig message.

The channel daemon gets the shared secrets from the HSM to save
the master daemon some work.  It used to hand these over at
revoke_and_ack receive, which is when the master daemon needs them.

However, it's a bit simpler to hand them over when we first tell
the master about the incoming HTLC (the first commitsig).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 8 years ago
parent
commit
46efb37152
  1. 81
      lightningd/channel/channel.c
  2. 7
      lightningd/channel/channel_wire.csv
  3. 50
      lightningd/peer_htlcs.c

81
lightningd/channel/channel.c

@ -585,6 +585,36 @@ static struct io_plan *send_revocation(struct io_conn *conn, struct peer *peer)
return peer_read_message(conn, &peer->pcs, peer_in);
}
/* FIXME: We could do this earlier and call HSM async, for speed. */
static void get_shared_secret(const struct htlc *htlc,
struct secret *shared_secret)
{
tal_t *tmpctx = tal_tmpctx(htlc);
struct pubkey ephemeral;
struct onionpacket *op;
u8 *msg;
/* We unwrap the onion now. */
op = parse_onionpacket(tmpctx, htlc->routing, TOTAL_PACKET_SIZE);
if (!op) {
/* Return an invalid shared secret. */
memset(shared_secret, 0, sizeof(*shared_secret));
tal_free(tmpctx);
return;
}
/* Because wire takes struct pubkey. */
ephemeral.pubkey = op->ephemeralkey;
msg = towire_hsm_ecdh_req(tmpctx, &ephemeral);
if (!wire_sync_write(HSM_FD, msg))
status_failed(WIRE_CHANNEL_HSM_FAILED, "Writing ecdh req");
msg = wire_sync_read(tmpctx, HSM_FD);
/* Gives all-zero shares_secret if it was invalid. */
if (!msg || !fromwire_hsm_ecdh_resp(msg, NULL, shared_secret))
status_failed(WIRE_CHANNEL_HSM_FAILED, "Reading ecdh response");
tal_free(tmpctx);
}
static u8 *got_commitsig_msg(const tal_t *ctx,
u64 local_commit_index,
const secp256k1_ecdsa_signature *commit_sig,
@ -596,10 +626,12 @@ static u8 *got_commitsig_msg(const tal_t *ctx,
struct fulfilled_htlc *fulfilled;
struct failed_htlc *failed;
struct added_htlc *added;
struct secret *shared_secret;
u8 *msg;
changed = tal_arr(tmpctx, struct changed_htlc, 0);
added = tal_arr(tmpctx, struct added_htlc, 0);
shared_secret = tal_arr(tmpctx, struct secret, 0);
failed = tal_arr(tmpctx, struct failed_htlc, 0);
fulfilled = tal_arr(tmpctx, struct fulfilled_htlc, 0);
@ -607,6 +639,7 @@ static u8 *got_commitsig_msg(const tal_t *ctx,
const struct htlc *htlc = changed_htlcs[i];
if (htlc->state == RCVD_ADD_COMMIT) {
struct added_htlc *a = tal_arr_append(&added);
struct secret *s = tal_arr_append(&shared_secret);
a->id = htlc->id;
a->amount_msat = htlc->msatoshi;
a->payment_hash = htlc->rhash;
@ -614,6 +647,7 @@ static u8 *got_commitsig_msg(const tal_t *ctx,
memcpy(a->onion_routing_packet,
htlc->routing,
sizeof(a->onion_routing_packet));
get_shared_secret(htlc, s);
} else if (htlc->state == RCVD_REMOVE_COMMIT) {
if (htlc->r) {
struct fulfilled_htlc *f;
@ -642,6 +676,7 @@ static u8 *got_commitsig_msg(const tal_t *ctx,
commit_sig,
htlc_sigs,
added,
shared_secret,
fulfilled,
failed,
changed);
@ -770,68 +805,28 @@ static struct io_plan *handle_peer_commit_sig(struct io_conn *conn,
return io_wait(conn, peer, send_revocation, peer);
}
static void add_htlc_with_ss(u64 **added_ids, struct secret **shared_secrets,
const struct htlc *htlc)
{
tal_t *tmpctx = tal_tmpctx(*added_ids);
struct pubkey ephemeral;
struct onionpacket *op;
u8 *msg;
struct secret *ss = tal_arr_append(shared_secrets);
u64 *id = tal_arr_append(added_ids);
*id = htlc->id;
/* We unwrap the onion now. */
/* FIXME: We could do this earlier and call HSM async, for speed. */
op = parse_onionpacket(tmpctx, htlc->routing, TOTAL_PACKET_SIZE);
if (!op) {
/* Return an invalid shared secret. */
memset(ss, 0, sizeof(*ss));
tal_free(tmpctx);
return;
}
/* Because wire takes struct pubkey. */
ephemeral.pubkey = op->ephemeralkey;
msg = towire_hsm_ecdh_req(tmpctx, &ephemeral);
if (!wire_sync_write(HSM_FD, msg))
status_failed(WIRE_CHANNEL_HSM_FAILED, "Writing ecdh req");
msg = wire_sync_read(tmpctx, HSM_FD);
/* Gives all-zero shares_secret if it was invalid. */
if (!msg || !fromwire_hsm_ecdh_resp(msg, NULL, ss))
status_failed(WIRE_CHANNEL_HSM_FAILED, "Reading ecdh response");
tal_free(tmpctx);
}
static u8 *got_revoke_msg(const tal_t *ctx, u64 revoke_num,
const struct sha256 *per_commitment_secret,
const struct htlc **changed_htlcs)
{
tal_t *tmpctx = tal_tmpctx(ctx);
u8 *msg;
u64 *added_ids = tal_arr(tmpctx, u64, 0);
struct secret *shared_secrets = tal_arr(tmpctx, struct secret, 0);
struct changed_htlc *changed = tal_arr(tmpctx, struct changed_htlc, 0);
for (size_t i = 0; i < tal_count(changed_htlcs); i++) {
struct changed_htlc *c = tal_arr_append(&changed);
const struct htlc *htlc = changed_htlcs[i];
status_trace("HTLC %"PRIu64"[%s] => %s",
htlc->id, side_to_str(htlc_owner(htlc)),
htlc_state_name(htlc->state));
/* We've both committed to their htlc now. */
if (htlc->state == RCVD_ADD_ACK_REVOCATION) {
add_htlc_with_ss(&added_ids, &shared_secrets, htlc);
} else {
struct changed_htlc *c = tal_arr_append(&changed);
c->id = changed_htlcs[i]->id;
c->newstate = changed_htlcs[i]->state;
}
}
msg = towire_channel_got_revoke(ctx, revoke_num, per_commitment_secret,
added_ids, shared_secrets, changed);
changed);
tal_free(tmpctx);
return msg;
}

7
lightningd/channel/channel_wire.csv

@ -108,6 +108,7 @@ channel_got_commitsig,,htlc_signature,num_htlcs*secp256k1_ecdsa_signature
# RCVD_ADD_COMMIT: we're now committed to their new offered HTLCs.
channel_got_commitsig,,num_added,u16
channel_got_commitsig,,added,num_added*struct added_htlc
channel_got_commitsig,,shared_secret,num_added*struct secret
# RCVD_REMOVE_COMMIT: we're now no longer committed to these HTLCs.
channel_got_commitsig,,num_fulfilled,u16
channel_got_commitsig,,fulfilled,num_fulfilled*struct fulfilled_htlc
@ -125,11 +126,7 @@ channel_got_commitsig_reply,121
channel_got_revoke,22
channel_got_revoke,,revokenum,u64
channel_got_revoke,,per_commitment_secret,struct sha256
# RCVD_ADD_ACK_REVOCATION
channel_got_revoke,,num_added,u16
channel_got_revoke,,added_ids,num_added*u64
channel_got_revoke,,shared_secret,num_added*struct secret
# RCVD_REMOVE_ACK_REVOCATION, RCVD_ADD_REVOCATION, RCVD_REMOVE_REVOCATION
# RCVD_ADD_ACK_REVOCATION, RCVD_REMOVE_ACK_REVOCATION, RCVD_ADD_REVOCATION, RCVD_REMOVE_REVOCATION
channel_got_revoke,,num_changed,u16
channel_got_revoke,,changed,num_changed*struct changed_htlc
# Wait for reply, to make sure it's on disk before we continue

Can't render this file because it has a wrong number of fields in line 2.

50
lightningd/peer_htlcs.c

@ -520,7 +520,6 @@ static bool htlc_out_update_state(struct peer *peer,
/* Everyone is committed to this htlc of theirs */
static bool peer_accepted_htlc(struct peer *peer,
u64 id,
const struct secret *shared_secret,
enum onion_type *failcode)
{
struct htlc_in *hin;
@ -536,9 +535,6 @@ static bool peer_accepted_htlc(struct peer *peer,
return false;
}
/* We need to keep this to encrypt failure message replies anyway */
hin->shared_secret = *shared_secret;
if (!htlc_in_update_state(peer, hin, RCVD_ADD_ACK_REVOCATION))
return false;
@ -546,7 +542,7 @@ static bool peer_accepted_htlc(struct peer *peer,
op = parse_onionpacket(tmpctx, hin->onion_routing_packet,
sizeof(hin->onion_routing_packet));
if (!op) {
if (!memeqzero(shared_secret, sizeof(*shared_secret))) {
if (!memeqzero(&hin->shared_secret, sizeof(hin->shared_secret))){
log_broken(peer->log,
"bad onion in got_revoke: %s",
tal_hexstr(peer, hin->onion_routing_packet,
@ -560,13 +556,13 @@ static bool peer_accepted_htlc(struct peer *peer,
}
/* Channeld sets this to zero if HSM won't ecdh it */
if (memeqzero(shared_secret, sizeof(*shared_secret))) {
if (memeqzero(&hin->shared_secret, sizeof(hin->shared_secret))) {
*failcode = WIRE_INVALID_ONION_KEY;
goto out;
}
/* If it's crap, not channeld's fault, just fail it */
rs = process_onionpacket(tmpctx, op, shared_secret->data,
rs = process_onionpacket(tmpctx, op, hin->shared_secret.data,
hin->payment_hash.u.u8,
sizeof(hin->payment_hash));
if (!rs) {
@ -780,17 +776,17 @@ int peer_sending_commitsig(struct peer *peer, const u8 *msg)
return 0;
}
static void added_their_htlc(struct peer *peer, const struct added_htlc *added)
static void added_their_htlc(struct peer *peer,
const struct added_htlc *added,
const struct secret *shared_secret)
{
struct htlc_in *hin;
static struct secret dummy;
/* This stays around even if we fail it immediately: it *is*
* part of the current commitment. */
hin = new_htlc_in(peer, peer, added->id, added->amount_msat,
added->cltv_expiry, &added->payment_hash,
/* FIXME: have user pass shared_secret now */
&dummy, added->onion_routing_packet);
shared_secret, added->onion_routing_packet);
/* FIXME: Save to db */
@ -851,6 +847,7 @@ int peer_got_commitsig(struct peer *peer, const u8 *msg)
secp256k1_ecdsa_signature commit_sig;
secp256k1_ecdsa_signature *htlc_sigs;
struct added_htlc *added;
struct secret *shared_secrets;
struct fulfilled_htlc *fulfilled;
struct failed_htlc *failed;
struct changed_htlc *changed;
@ -861,6 +858,7 @@ int peer_got_commitsig(struct peer *peer, const u8 *msg)
&commit_sig,
&htlc_sigs,
&added,
&shared_secrets,
&fulfilled,
&failed,
&changed)) {
@ -879,7 +877,7 @@ int peer_got_commitsig(struct peer *peer, const u8 *msg)
/* New HTLCs */
for (i = 0; i < tal_count(added); i++)
added_their_htlc(peer, &added[i]);
added_their_htlc(peer, &added[i], &shared_secrets[i]);
/* Save information now for fulfilled & failed HTLCs */
for (i = 0; i < tal_count(fulfilled); i++) {
@ -923,15 +921,12 @@ int peer_got_revoke(struct peer *peer, const u8 *msg)
{
u64 revokenum, shachainidx;
struct sha256 per_commitment_secret;
u64 *added_ids;
struct secret *shared_secret;
struct changed_htlc *changed;
enum onion_type *failcodes;
size_t i;
if (!fromwire_channel_got_revoke(msg, msg, NULL,
&revokenum, &per_commitment_secret,
&added_ids, &shared_secret,
&changed)) {
log_broken(peer->log, "bad fromwire_channel_got_revoke %s",
tal_hex(peer, msg));
@ -939,24 +934,25 @@ int peer_got_revoke(struct peer *peer, const u8 *msg)
}
log_debug(peer->log,
"got revoke %"PRIu64": %zu changed, %zu incoming locked in",
revokenum,
tal_count(changed), tal_count(added_ids));
"got revoke %"PRIu64": %zu changed",
revokenum, tal_count(changed));
/* Save any immediate failures for after we reply. */
failcodes = tal_arr(msg, enum onion_type, tal_count(added_ids));
for (i = 0; i < tal_count(added_ids); i++) {
if (!peer_accepted_htlc(peer, added_ids[i], &shared_secret[i],
failcodes = tal_arrz(msg, enum onion_type, tal_count(changed));
for (i = 0; i < tal_count(changed); i++) {
/* If we're doing final accept, we need to forward */
if (changed[i].newstate == RCVD_ADD_ACK_REVOCATION) {
if (!peer_accepted_htlc(peer, changed[i].id,
&failcodes[i]))
return -1;
}
for (i = 0; i < tal_count(changed); i++) {
} else {
if (!changed_htlc(peer, &changed[i])) {
log_broken(peer->log, "got_revoke: update failed");
log_broken(peer->log,
"got_revoke: update failed");
return -1;
}
}
}
if (revokenum >= (1ULL << 48)) {
log_broken(peer->log, "got_revoke: too many txs %"PRIu64,
@ -996,14 +992,14 @@ int peer_got_revoke(struct peer *peer, const u8 *msg)
subd_send_msg(peer->owner, take(msg));
/* Now, any HTLCs we need to immediately fail? */
for (i = 0; i < tal_count(added_ids); i++) {
for (i = 0; i < tal_count(changed); i++) {
struct sha256 bad_onion_sha;
struct htlc_in *hin;
if (!failcodes[i])
continue;
hin = find_htlc_in(&peer->ld->htlcs_in, peer, added_ids[i]);
hin = find_htlc_in(&peer->ld->htlcs_in, peer, changed[i].id);
sha256(&bad_onion_sha, hin->onion_routing_packet,
sizeof(hin->onion_routing_packet));
fail_htlc(hin, failcodes[i], &bad_onion_sha);

Loading…
Cancel
Save