diff --git a/common/onion.c b/common/onion.c index c74c9a1b2..85e7df485 100644 --- a/common/onion.c +++ b/common/onion.c @@ -1,7 +1,9 @@ #include "common/onion.h" #include #include +#include #include +#include #include /* BOLT #4: @@ -210,8 +212,50 @@ size_t onion_payload_length(const u8 *raw_payload, size_t len, bool has_realm, return payload_len; } +#if EXPERIMENTAL_FEATURES +static struct tlv_tlv_payload *decrypt_tlv(const tal_t *ctx, + const struct secret *blinding_ss, + const u8 *enc) +{ + const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + struct secret rho; + u8 *dec; + const u8 *cursor; + size_t max; + int ret; + struct tlv_tlv_payload *tlv; + + subkey_from_hmac("rho", blinding_ss, &rho); + if (tal_bytelen(enc) < crypto_aead_chacha20poly1305_ietf_ABYTES) + return NULL; + + dec = tal_arr(tmpctx, u8, + tal_bytelen(enc) + - crypto_aead_chacha20poly1305_ietf_ABYTES); + ret = crypto_aead_chacha20poly1305_ietf_decrypt(dec, NULL, + NULL, + enc, + tal_bytelen(enc), + NULL, 0, + npub, + rho.data); + if (ret != 0) + return NULL; + + tlv = tlv_tlv_payload_new(ctx); + cursor = dec; + max = tal_bytelen(dec); + if (!fromwire_tlv_payload(&cursor, &max, tlv)) + return tal_free(tlv); + + return tlv; +} +#endif /* EXPERIMENTAL_FEATURES */ + struct onion_payload *onion_decode(const tal_t *ctx, const struct route_step *rs, + const struct pubkey *blinding, + const struct secret *blinding_ss, u64 *failtlvtype, size_t *failtlvpos) { @@ -231,6 +275,10 @@ struct onion_payload *onion_decode(const tal_t *ctx, p->amt_to_forward = fromwire_amount_msat(&cursor, &max); p->outgoing_cltv = fromwire_u32(&cursor, &max); p->payment_secret = NULL; + p->blinding = NULL; + /* We can't handle blinding with a legacy payload */ + if (blinding) + return tal_free(p); if (rs->nextcase == ONION_FORWARD) { p->total_msat = NULL; @@ -296,6 +344,47 @@ struct onion_payload *onion_decode(const tal_t *ctx, } p->payment_secret = NULL; + if (blinding) + p->blinding = tal_dup(p, struct pubkey, blinding); + else + p->blinding = NULL; + +#if EXPERIMENTAL_FEATURES + if (!p->blinding) { + /* If we have no blinding, it could be in TLV. */ + if (tlv->blinding_seed) { + p->blinding = + tal_dup(p, struct pubkey, + &tlv->blinding_seed->blinding_seed); + ecdh(p->blinding, &p->blinding_ss); + } + } else + p->blinding_ss = *blinding_ss; + + if (p->blinding) { + /* If they give us a blinding and we're not terminal, + * we must have an enctlv. */ + if (rs->nextcase == ONION_FORWARD) { + struct tlv_tlv_payload *ntlv; + + if (!tlv->enctlv) + goto fail; + + ntlv = decrypt_tlv(tmpctx, + &p->blinding_ss, + tlv->enctlv->enctlv); + if (!ntlv) + goto fail; + + /* Must override short_channel_id */ + if (!ntlv->short_channel_id) + goto fail; + + *p->forward_channel + = ntlv->short_channel_id->short_channel_id; + } + } +#endif /* EXPERIMENTAL_FEATURES */ if (tlv->payment_data) { p->payment_secret = tal_dup(p, struct secret, diff --git a/common/onion.h b/common/onion.h index 7f7c38feb..3eaac5a04 100644 --- a/common/onion.h +++ b/common/onion.h @@ -1,6 +1,7 @@ #ifndef LIGHTNING_COMMON_ONION_H #define LIGHTNING_COMMON_ONION_H #include "config.h" +#include #include #include @@ -19,6 +20,10 @@ struct onion_payload { struct amount_msat *total_msat; struct short_channel_id *forward_channel; struct secret *payment_secret; + + /* If blinding is set, blinding_ss is the shared secret.*/ + struct pubkey *blinding; + struct secret blinding_ss; }; u8 *onion_nonfinal_hop(const tal_t *ctx, @@ -57,11 +62,17 @@ size_t onion_payload_length(const u8 *raw_payload, size_t len, * @ctx: context to allocate onion_contents off. * @rs: the route_step, whose raw_payload is of at least length * onion_payload_length(). + * @blinding: the optional incoming blinding point. + * @blinding_ss: the shared secret derived from @blinding (iff that's non-NULL) + * @failtlvtype: (out) the tlv type which failed to parse. + * @failtlvpos: (out) the offset in the tlv which failed to parse. * * If the payload is not valid, returns NULL. */ struct onion_payload *onion_decode(const tal_t *ctx, const struct route_step *rs, + const struct pubkey *blinding, + const struct secret *blinding_ss, u64 *failtlvtype, size_t *failtlvpos); diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 3b01287e6..4484559dc 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -1118,6 +1118,7 @@ static bool peer_accepted_htlc(const tal_t *ctx, hook_payload->route_step = tal_steal(hook_payload, rs); hook_payload->payload = onion_decode(hook_payload, rs, + NULL, NULL, &hook_payload->failtlvtype, &hook_payload->failtlvpos); hook_payload->ld = ld; diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 5d71b7be2..7c29663c9 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -412,6 +412,8 @@ enum watch_result onchaind_funding_spent(struct channel *channel UNNEEDED, /* Generated stub for onion_decode */ struct onion_payload *onion_decode(const tal_t *ctx UNNEEDED, const struct route_step *rs UNNEEDED, + const struct pubkey *blinding UNNEEDED, + const struct secret *blinding_ss UNNEEDED, u64 *failtlvtype UNNEEDED, size_t *failtlvpos UNNEEDED) { fprintf(stderr, "onion_decode called!\n"); abort(); }