mirror of
https://github.com/aljazceru/lightning.git
synced 2026-02-04 05:34:22 +01:00
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>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
@@ -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,22 +934,23 @@ 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[i]))
|
||||
return -1;
|
||||
}
|
||||
|
||||
failcodes = tal_arrz(msg, enum onion_type, tal_count(changed));
|
||||
for (i = 0; i < tal_count(changed); i++) {
|
||||
if (!changed_htlc(peer, &changed[i])) {
|
||||
log_broken(peer->log, "got_revoke: update failed");
|
||||
return -1;
|
||||
/* 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;
|
||||
} else {
|
||||
if (!changed_htlc(peer, &changed[i])) {
|
||||
log_broken(peer->log,
|
||||
"got_revoke: update failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user