mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-04 03:03:51 +01:00
common/blindedpath: generalize routines.
We're going to share them for onion messages as well as for blinded payments. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
85baca56c6
commit
53e40c4380
5 changed files with 181 additions and 151 deletions
|
@ -19,36 +19,27 @@ static bool blind_node(const struct privkey *blinding,
|
||||||
struct pubkey *node_alias,
|
struct pubkey *node_alias,
|
||||||
struct privkey *next_blinding)
|
struct privkey *next_blinding)
|
||||||
{
|
{
|
||||||
struct secret node_id_blinding;
|
|
||||||
struct pubkey blinding_pubkey;
|
struct pubkey blinding_pubkey;
|
||||||
struct sha256 h;
|
struct sha256 h;
|
||||||
|
|
||||||
/*
|
if (!blindedpath_get_alias(ss, node, node_alias))
|
||||||
* Blinded node_id for N(i), private key known only by N(i):
|
|
||||||
* B(i) = HMAC256("blinded_node_id", ss(i)) * P(i)
|
|
||||||
*/
|
|
||||||
subkey_from_hmac("blinded_node_id", ss, &node_id_blinding);
|
|
||||||
SUPERVERBOSE("\t\"HMAC256('blinded_node_id', ss)\": \"%s\",\n",
|
|
||||||
type_to_string(tmpctx, struct secret,
|
|
||||||
&node_id_blinding));
|
|
||||||
|
|
||||||
*node_alias = *node;
|
|
||||||
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx,
|
|
||||||
&node_alias->pubkey,
|
|
||||||
node_id_blinding.data) != 1)
|
|
||||||
return false;
|
return false;
|
||||||
SUPERVERBOSE("\t\"blinded_node_id\": \"%s\",\n",
|
SUPERVERBOSE("\t\"blinded_node_id\": \"%s\",\n",
|
||||||
type_to_string(tmpctx, struct pubkey, node_alias));
|
type_to_string(tmpctx, struct pubkey, node_alias));
|
||||||
|
|
||||||
/*
|
/* BOLT-route-blinding #4:
|
||||||
* Ephemeral private key, only known by N(r):
|
* - `E(i+1) = SHA256(E(i) || ss(i)) * E(i)`
|
||||||
* e(i+1) = H(E(i) || ss(i)) * e(i)
|
* (NB: `N(i)` MUST NOT learn `e(i)`)
|
||||||
*/
|
*/
|
||||||
if (!pubkey_from_privkey(blinding, &blinding_pubkey))
|
if (!pubkey_from_privkey(blinding, &blinding_pubkey))
|
||||||
return false;
|
return false;
|
||||||
SUPERVERBOSE("\t\"E\": \"%s\",\n",
|
SUPERVERBOSE("\t\"E\": \"%s\",\n",
|
||||||
type_to_string(tmpctx, struct pubkey, &blinding_pubkey));
|
type_to_string(tmpctx, struct pubkey, &blinding_pubkey));
|
||||||
|
|
||||||
|
/* BOLT-route-blinding #4:
|
||||||
|
* - `e(i+1) = SHA256(E(i) || ss(i)) * e(i)`
|
||||||
|
* (blinding ephemeral private key, only known by `N(r)`)
|
||||||
|
*/
|
||||||
blinding_hash_e_and_ss(&blinding_pubkey, ss, &h);
|
blinding_hash_e_and_ss(&blinding_pubkey, ss, &h);
|
||||||
SUPERVERBOSE("\t\"H(E || ss)\": \"%s\",\n",
|
SUPERVERBOSE("\t\"H(E || ss)\": \"%s\",\n",
|
||||||
type_to_string(tmpctx, struct sha256, &h));
|
type_to_string(tmpctx, struct sha256, &h));
|
||||||
|
@ -66,16 +57,15 @@ static u8 *enctlv_from_encmsg_raw(const tal_t *ctx,
|
||||||
struct privkey *next_blinding,
|
struct privkey *next_blinding,
|
||||||
struct pubkey *node_alias)
|
struct pubkey *node_alias)
|
||||||
{
|
{
|
||||||
/* https://github.com/lightning/bolts/blob/route-blinding/proposals/route-blinding.md */
|
|
||||||
struct secret ss, rho;
|
struct secret ss, rho;
|
||||||
u8 *ret;
|
u8 *ret;
|
||||||
int ok;
|
int ok;
|
||||||
/* All-zero npub */
|
/* All-zero npub */
|
||||||
static const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES];
|
static const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES];
|
||||||
|
|
||||||
/*
|
/* BOLT-route-blinding #4:
|
||||||
* shared secret known only by N(r) and N(i):
|
* - `ss(i) = SHA256(e(i) * N(i)) = SHA256(k(i) * E(i))`
|
||||||
* ss(i) = H(e(i) * P(i)) = H(k(i) * E(i))
|
* (ECDH shared secret known only by `N(r)` and `N(i)`)
|
||||||
*/
|
*/
|
||||||
if (secp256k1_ecdh(secp256k1_ctx, ss.data,
|
if (secp256k1_ecdh(secp256k1_ctx, ss.data,
|
||||||
&node->pubkey, blinding->secret.data,
|
&node->pubkey, blinding->secret.data,
|
||||||
|
@ -91,17 +81,20 @@ static u8 *enctlv_from_encmsg_raw(const tal_t *ctx,
|
||||||
ret = tal_dup_talarr(ctx, u8, raw_encmsg);
|
ret = tal_dup_talarr(ctx, u8, raw_encmsg);
|
||||||
SUPERVERBOSE("\t\"encmsg_hex\": \"%s\",\n", tal_hex(tmpctx, ret));
|
SUPERVERBOSE("\t\"encmsg_hex\": \"%s\",\n", tal_hex(tmpctx, ret));
|
||||||
|
|
||||||
/*
|
/* BOLT-route-blinding #4:
|
||||||
* Key used to encrypt payload for N(i) by N(r):
|
* - `rho(i) = HMAC256("rho", ss(i))`
|
||||||
* rho(i) = HMAC256("rho", ss(i))
|
* (key used to encrypt the payload for `N(i)` by `N(r)`)
|
||||||
*/
|
*/
|
||||||
subkey_from_hmac("rho", &ss, &rho);
|
subkey_from_hmac("rho", &ss, &rho);
|
||||||
SUPERVERBOSE("\t\"rho\": \"%s\",\n",
|
SUPERVERBOSE("\t\"rho\": \"%s\",\n",
|
||||||
type_to_string(tmpctx, struct secret, &rho));
|
type_to_string(tmpctx, struct secret, &rho));
|
||||||
|
|
||||||
|
/* BOLT-route-blinding #4:
|
||||||
|
* - MUST encrypt them with ChaCha20-Poly1305 using the `rho(i)` key
|
||||||
|
* and an all-zero nonce
|
||||||
|
*/
|
||||||
/* Encrypt in place */
|
/* Encrypt in place */
|
||||||
towire_pad(&ret, crypto_aead_chacha20poly1305_ietf_ABYTES);
|
towire_pad(&ret, crypto_aead_chacha20poly1305_ietf_ABYTES);
|
||||||
|
|
||||||
ok = crypto_aead_chacha20poly1305_ietf_encrypt(ret, NULL,
|
ok = crypto_aead_chacha20poly1305_ietf_encrypt(ret, NULL,
|
||||||
ret,
|
ret,
|
||||||
tal_bytelen(ret)
|
tal_bytelen(ret)
|
||||||
|
@ -134,15 +127,24 @@ bool unblind_onion(const struct pubkey *blinding,
|
||||||
{
|
{
|
||||||
struct secret hmac;
|
struct secret hmac;
|
||||||
|
|
||||||
/* E(i) */
|
/* BOLT-route-blinding #4:
|
||||||
|
* An intermediate node in the blinded route:
|
||||||
|
*
|
||||||
|
* - MUST compute:
|
||||||
|
* - `ss(i) = SHA256(k(i) * E(i))` (standard ECDH)
|
||||||
|
* - `b(i) = HMAC256("blinded_node_id", ss(i)) * k(i)`
|
||||||
|
*/
|
||||||
ecdh(blinding, ss);
|
ecdh(blinding, ss);
|
||||||
|
|
||||||
/* b(i) = HMAC256("blinded_node_id", ss(i)) * k(i) */
|
|
||||||
subkey_from_hmac("blinded_node_id", ss, &hmac);
|
subkey_from_hmac("blinded_node_id", ss, &hmac);
|
||||||
|
|
||||||
/* We instead tweak the *ephemeral* key from the onion and use
|
/* We instead tweak the *ephemeral* key from the onion and use
|
||||||
* our normal privkey: since hsmd knows only how to ECDH with
|
* our normal privkey: since hsmd knows only how to ECDH with
|
||||||
* our real key */
|
* our real key. IOW: */
|
||||||
|
/* BOLT-route-blinding #4:
|
||||||
|
* - MUST use `b(i)` instead of its private key `k(i)` to decrypt the onion. Note
|
||||||
|
* that the node may instead tweak the onion ephemeral key with
|
||||||
|
* `HMAC256("blinded_node_id", ss(i))` which achieves the same result.
|
||||||
|
*/
|
||||||
return secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx,
|
return secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx,
|
||||||
&onion_key->pubkey,
|
&onion_key->pubkey,
|
||||||
hmac.data) == 1;
|
hmac.data) == 1;
|
||||||
|
@ -158,7 +160,10 @@ static u8 *decrypt_encmsg_raw(const tal_t *ctx,
|
||||||
/* All-zero npub */
|
/* All-zero npub */
|
||||||
static const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES];
|
static const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES];
|
||||||
|
|
||||||
/* We need this to decrypt enctlv */
|
/* BOLT-route-blinding #4:
|
||||||
|
* - If an `encrypted_data` field is provided:
|
||||||
|
* - MUST decrypt it using `rho(r)`
|
||||||
|
*/
|
||||||
subkey_from_hmac("rho", ss, &rho);
|
subkey_from_hmac("rho", ss, &rho);
|
||||||
|
|
||||||
/* BOLT-onion-message #4:
|
/* BOLT-onion-message #4:
|
||||||
|
@ -183,10 +188,10 @@ static u8 *decrypt_encmsg_raw(const tal_t *ctx,
|
||||||
return dec;
|
return dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct tlv_encrypted_data_tlv *decrypt_encmsg(const tal_t *ctx,
|
struct tlv_encrypted_data_tlv *decrypt_encrypted_data(const tal_t *ctx,
|
||||||
const struct pubkey *blinding,
|
const struct pubkey *blinding,
|
||||||
const struct secret *ss,
|
const struct secret *ss,
|
||||||
const u8 *enctlv)
|
const u8 *enctlv)
|
||||||
{
|
{
|
||||||
const u8 *cursor = decrypt_encmsg_raw(tmpctx, blinding, ss, enctlv);
|
const u8 *cursor = decrypt_encmsg_raw(tmpctx, blinding, ss, enctlv);
|
||||||
size_t maxlen = tal_bytelen(cursor);
|
size_t maxlen = tal_bytelen(cursor);
|
||||||
|
@ -203,93 +208,48 @@ static struct tlv_encrypted_data_tlv *decrypt_encmsg(const tal_t *ctx,
|
||||||
return fromwire_tlv_encrypted_data_tlv(ctx, &cursor, &maxlen);
|
return fromwire_tlv_encrypted_data_tlv(ctx, &cursor, &maxlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool decrypt_enctlv(const struct pubkey *blinding,
|
bool blindedpath_get_alias(const struct secret *ss,
|
||||||
const struct secret *ss,
|
const struct pubkey *my_id,
|
||||||
const u8 *enctlv,
|
struct pubkey *alias)
|
||||||
struct pubkey *next_node,
|
|
||||||
struct pubkey *next_blinding)
|
|
||||||
{
|
{
|
||||||
struct tlv_encrypted_data_tlv *encmsg;
|
struct secret node_id_blinding;
|
||||||
|
|
||||||
encmsg = decrypt_encmsg(tmpctx, blinding, ss, enctlv);
|
/* BOLT-route-blinding #4:
|
||||||
if (!encmsg)
|
* - `B(i) = HMAC256("blinded_node_id", ss(i)) * N(i)`
|
||||||
return false;
|
* (blinded `node_id` for `N(i)`, private key known only by `N(i)`)
|
||||||
|
|
||||||
/* BOLT-onion-message #4:
|
|
||||||
*
|
|
||||||
* The reader:
|
|
||||||
* - if it is not the final node according to the onion encryption:
|
|
||||||
*...
|
|
||||||
* - if the `enctlv` ... does not contain
|
|
||||||
* `next_node_id`:
|
|
||||||
* - MUST drop the message.
|
|
||||||
*/
|
*/
|
||||||
if (!encmsg->next_node_id)
|
subkey_from_hmac("blinded_node_id", ss, &node_id_blinding);
|
||||||
return false;
|
SUPERVERBOSE("\t\"HMAC256('blinded_node_id', ss)\": \"%s\",\n",
|
||||||
|
type_to_string(tmpctx, struct secret,
|
||||||
|
&node_id_blinding));
|
||||||
|
|
||||||
/* BOLT-onion-message #4:
|
*alias = *my_id;
|
||||||
* The reader:
|
return secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx,
|
||||||
* - if it is not the final node according to the onion encryption:
|
&alias->pubkey,
|
||||||
*...
|
node_id_blinding.data) == 1;
|
||||||
* - if the `enctlv` contains `path_id`:
|
}
|
||||||
* - MUST drop the message.
|
|
||||||
*/
|
|
||||||
if (encmsg->path_id)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* BOLT-onion-message #4:
|
void blindedpath_next_blinding(const struct tlv_encrypted_data_tlv *enc,
|
||||||
* The reader:
|
const struct pubkey *blinding,
|
||||||
* - if it is not the final node according to the onion encryption:
|
const struct secret *ss,
|
||||||
*...
|
struct pubkey *next_blinding)
|
||||||
* - if `blinding` is specified in the `enctlv`:
|
{
|
||||||
* - MUST pass that as `blinding` in the `onion_message`
|
/* BOLT-route
|
||||||
* - otherwise:
|
* - `E(1) = SHA256(E(0) || ss(0)) * E(0)`
|
||||||
* - MUST pass `blinding` derived as in
|
* ...
|
||||||
* [Route Blinding][route-blinding] (i.e.
|
* - If `encrypted_data` contains a `next_blinding_override`:
|
||||||
* `E(i+1) = H(E(i) || ss(i)) * E(i)`).
|
* - MUST use it as the next blinding point instead of `E(1)`
|
||||||
|
* - Otherwise:
|
||||||
|
* - MUST use `E(1)` as the next blinding point
|
||||||
*/
|
*/
|
||||||
*next_node = *encmsg->next_node_id;
|
if (enc->next_blinding_override)
|
||||||
if (encmsg->next_blinding_override)
|
*next_blinding = *enc->next_blinding_override;
|
||||||
*next_blinding = *encmsg->next_blinding_override;
|
|
||||||
else {
|
else {
|
||||||
/* E(i-1) = H(E(i) || ss(i)) * E(i) */
|
/* E(i-1) = H(E(i) || ss(i)) * E(i) */
|
||||||
struct sha256 h;
|
struct sha256 h;
|
||||||
blinding_hash_e_and_ss(blinding, ss, &h);
|
blinding_hash_e_and_ss(blinding, ss, &h);
|
||||||
blinding_next_pubkey(blinding, &h, next_blinding);
|
blinding_next_pubkey(blinding, &h, next_blinding);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool decrypt_final_enctlv(const tal_t *ctx,
|
|
||||||
const struct pubkey *blinding,
|
|
||||||
const struct secret *ss,
|
|
||||||
const u8 *enctlv,
|
|
||||||
const struct pubkey *my_id,
|
|
||||||
struct pubkey *alias,
|
|
||||||
struct secret **path_id)
|
|
||||||
{
|
|
||||||
struct tlv_encrypted_data_tlv *encmsg;
|
|
||||||
struct secret node_id_blinding;
|
|
||||||
|
|
||||||
/* Repeat the tweak to get the alias it was using for us */
|
|
||||||
subkey_from_hmac("blinded_node_id", ss, &node_id_blinding);
|
|
||||||
*alias = *my_id;
|
|
||||||
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx,
|
|
||||||
&alias->pubkey,
|
|
||||||
node_id_blinding.data) != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
encmsg = decrypt_encmsg(tmpctx, blinding, ss, enctlv);
|
|
||||||
if (!encmsg)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (tal_bytelen(encmsg->path_id) == sizeof(**path_id)) {
|
|
||||||
*path_id = tal(ctx, struct secret);
|
|
||||||
memcpy(*path_id, encmsg->path_id, sizeof(**path_id));
|
|
||||||
} else
|
|
||||||
*path_id = NULL;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *create_enctlv(const tal_t *ctx,
|
u8 *create_enctlv(const tal_t *ctx,
|
||||||
|
|
|
@ -68,41 +68,38 @@ bool unblind_onion(const struct pubkey *blinding,
|
||||||
NO_NULL_ARGS;
|
NO_NULL_ARGS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* decrypt_enctlv - Decrypt an encmsg to form an enctlv.
|
* blindedpath_get_alias - tweak our id to see alias they used.
|
||||||
* @blinding: E(i), the blinding pubkey the previous peer gave us.
|
* @ss: the shared secret from unblind_onion
|
||||||
* @ss: the blinding secret from unblind_onion().
|
* @my_id: my node_id
|
||||||
* @enctlv: the enctlv from the onion (tal, may be NULL).
|
* @alias: (out) the alias.
|
||||||
* @next_node: (out) the next node_id.
|
|
||||||
* @next_blinding: (out) the next blinding E(i+1).
|
|
||||||
*
|
*
|
||||||
* Returns false if decryption failed or encmsg was malformed.
|
* Returns false on ECDH fail.
|
||||||
*/
|
*/
|
||||||
bool decrypt_enctlv(const struct pubkey *blinding,
|
bool blindedpath_get_alias(const struct secret *ss,
|
||||||
const struct secret *ss,
|
const struct pubkey *my_id,
|
||||||
const u8 *enctlv,
|
struct pubkey *alias);
|
||||||
struct pubkey *next_node,
|
|
||||||
struct pubkey *next_blinding)
|
|
||||||
NON_NULL_ARGS(1, 2, 4, 5);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* decrypt_final_enctlv - Decrypt an encmsg to form an enctlv.
|
* decrypt_encrypted_data - Decrypt an encmsg to form an tlv_encrypted_data_tlv.
|
||||||
* @ctx: tal context for @path_id
|
* @ctx: the context to allocate off.
|
||||||
* @blinding: E(i), the blinding pubkey the previous peer gave us.
|
* @blinding: E(i), the blinding pubkey the previous peer gave us.
|
||||||
* @ss: the blinding secret from unblind_onion().
|
* @ss: the blinding secret from unblind_onion().
|
||||||
* @enctlv: the enctlv from the onion (tal, may be NULL).
|
* @enctlv: the enctlv from the onion (tal, may be NULL).
|
||||||
* @my_id: the pubkey of this node.
|
|
||||||
* @alias: (out) the node_id this was addressed to.
|
|
||||||
* @path_id: (out) the secret contained in the enctlv, if any (NULL if invalid or unset)
|
|
||||||
*
|
*
|
||||||
* Returns false if decryption failed or encmsg was malformed.
|
* Returns NULL if decryption failed or encmsg was malformed.
|
||||||
*/
|
*/
|
||||||
bool decrypt_final_enctlv(const tal_t *ctx,
|
struct tlv_encrypted_data_tlv *decrypt_encrypted_data(const tal_t *ctx,
|
||||||
const struct pubkey *blinding,
|
const struct pubkey *blinding,
|
||||||
const struct secret *ss,
|
const struct secret *ss,
|
||||||
const u8 *enctlv,
|
const u8 *enctlv)
|
||||||
const struct pubkey *my_id,
|
NON_NULL_ARGS(2, 3);
|
||||||
struct pubkey *alias,
|
|
||||||
struct secret **path_id)
|
/**
|
||||||
NON_NULL_ARGS(1, 2, 4, 5);
|
* blindedpath_next_blinding - Calculate or extract next blinding pubkey
|
||||||
|
*/
|
||||||
|
void blindedpath_next_blinding(const struct tlv_encrypted_data_tlv *enc,
|
||||||
|
const struct pubkey *blinding,
|
||||||
|
const struct secret *ss,
|
||||||
|
struct pubkey *next_blinding);
|
||||||
|
|
||||||
#endif /* LIGHTNING_COMMON_BLINDEDPATH_H */
|
#endif /* LIGHTNING_COMMON_BLINDEDPATH_H */
|
||||||
|
|
|
@ -91,19 +91,22 @@ static void test_decrypt(const struct pubkey *blinding,
|
||||||
const struct pubkey *expected_next_node,
|
const struct pubkey *expected_next_node,
|
||||||
const struct privkey *expected_next_blinding_priv)
|
const struct privkey *expected_next_blinding_priv)
|
||||||
{
|
{
|
||||||
struct pubkey expected_next_blinding, dummy, next_node, next_blinding;
|
struct pubkey expected_next_blinding, dummy, next_blinding;
|
||||||
struct secret ss;
|
struct secret ss;
|
||||||
|
struct tlv_encrypted_data_tlv *enc;
|
||||||
|
|
||||||
/* We don't actually have an onion, so we put some dummy */
|
/* We don't actually have an onion, so we put some dummy */
|
||||||
pubkey_from_privkey(me, &dummy);
|
pubkey_from_privkey(me, &dummy);
|
||||||
|
|
||||||
mykey = me;
|
mykey = me;
|
||||||
assert(unblind_onion(blinding, test_ecdh, &dummy, &ss));
|
assert(unblind_onion(blinding, test_ecdh, &dummy, &ss));
|
||||||
assert(decrypt_enctlv(blinding, &ss, enctlv, &next_node, &next_blinding));
|
enc = decrypt_encrypted_data(tmpctx, blinding, &ss, enctlv);
|
||||||
|
assert(enc);
|
||||||
|
|
||||||
pubkey_from_privkey(expected_next_blinding_priv, &expected_next_blinding);
|
pubkey_from_privkey(expected_next_blinding_priv, &expected_next_blinding);
|
||||||
|
blindedpath_next_blinding(enc, blinding, &ss, &next_blinding);
|
||||||
assert(pubkey_eq(&next_blinding, &expected_next_blinding));
|
assert(pubkey_eq(&next_blinding, &expected_next_blinding));
|
||||||
assert(pubkey_eq(&next_node, expected_next_node));
|
assert(pubkey_eq(enc->next_node_id, expected_next_node));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_final_decrypt(const struct pubkey *blinding,
|
static void test_final_decrypt(const struct pubkey *blinding,
|
||||||
|
@ -113,7 +116,8 @@ static void test_final_decrypt(const struct pubkey *blinding,
|
||||||
const struct secret *expected_self_id)
|
const struct secret *expected_self_id)
|
||||||
{
|
{
|
||||||
struct pubkey my_pubkey, dummy, alias;
|
struct pubkey my_pubkey, dummy, alias;
|
||||||
struct secret ss, *self_id;
|
struct secret ss;
|
||||||
|
struct tlv_encrypted_data_tlv *enc;
|
||||||
|
|
||||||
/* We don't actually have an onion, so we put some dummy */
|
/* We don't actually have an onion, so we put some dummy */
|
||||||
pubkey_from_privkey(me, &dummy);
|
pubkey_from_privkey(me, &dummy);
|
||||||
|
@ -121,11 +125,13 @@ static void test_final_decrypt(const struct pubkey *blinding,
|
||||||
mykey = me;
|
mykey = me;
|
||||||
pubkey_from_privkey(me, &my_pubkey);
|
pubkey_from_privkey(me, &my_pubkey);
|
||||||
assert(unblind_onion(blinding, test_ecdh, &dummy, &ss));
|
assert(unblind_onion(blinding, test_ecdh, &dummy, &ss));
|
||||||
assert(decrypt_final_enctlv(tmpctx, blinding, &ss, enctlv, &my_pubkey,
|
enc = decrypt_encrypted_data(tmpctx, blinding, &ss, enctlv);
|
||||||
&alias, &self_id));
|
assert(enc);
|
||||||
|
assert(blindedpath_get_alias(&ss, &my_pubkey, &alias));
|
||||||
|
|
||||||
assert(pubkey_eq(&alias, expected_alias));
|
assert(pubkey_eq(&alias, expected_alias));
|
||||||
assert(secret_eq_consttime(self_id, expected_self_id));
|
assert(memeq(enc->path_id, tal_bytelen(enc->path_id), expected_self_id,
|
||||||
|
sizeof(*expected_self_id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
|
|
@ -108,12 +108,13 @@ static u8 *next_onion(const tal_t *ctx, u8 *omsg,
|
||||||
{
|
{
|
||||||
struct onionpacket *op;
|
struct onionpacket *op;
|
||||||
struct pubkey blinding, ephemeral;
|
struct pubkey blinding, ephemeral;
|
||||||
struct pubkey next_node, next_blinding;
|
struct pubkey next_blinding;
|
||||||
struct tlv_onionmsg_payload *om;
|
struct tlv_onionmsg_payload *om;
|
||||||
struct secret ss, onion_ss;
|
struct secret ss, onion_ss;
|
||||||
const u8 *cursor;
|
const u8 *cursor;
|
||||||
size_t max, maxlen;
|
size_t max, maxlen;
|
||||||
struct route_step *rs;
|
struct route_step *rs;
|
||||||
|
struct tlv_encrypted_data_tlv *enc;
|
||||||
|
|
||||||
assert(fromwire_onion_message(tmpctx, omsg, &blinding, &omsg));
|
assert(fromwire_onion_message(tmpctx, omsg, &blinding, &omsg));
|
||||||
assert(pubkey_eq(&blinding, expected_blinding));
|
assert(pubkey_eq(&blinding, expected_blinding));
|
||||||
|
@ -137,8 +138,9 @@ static u8 *next_onion(const tal_t *ctx, u8 *omsg,
|
||||||
if (rs->nextcase == ONION_END)
|
if (rs->nextcase == ONION_END)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
assert(decrypt_enctlv(&blinding, &ss, om->encrypted_data_tlv, &next_node,
|
enc = decrypt_encrypted_data(tmpctx, &blinding, &ss, om->encrypted_data_tlv);
|
||||||
&next_blinding));
|
assert(enc);
|
||||||
|
blindedpath_next_blinding(enc, &blinding, &ss, &next_blinding);
|
||||||
return towire_onion_message(ctx, &next_blinding,
|
return towire_onion_message(ctx, &next_blinding,
|
||||||
serialize_onionpacket(tmpctx, rs->next));
|
serialize_onionpacket(tmpctx, rs->next));
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,71 @@ void onionmsg_req(struct daemon *daemon, const u8 *msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool decrypt_final_onionmsg(const tal_t *ctx,
|
||||||
|
const struct pubkey *blinding,
|
||||||
|
const struct secret *ss,
|
||||||
|
const u8 *enctlv,
|
||||||
|
const struct pubkey *my_id,
|
||||||
|
struct pubkey *alias,
|
||||||
|
struct secret **path_id)
|
||||||
|
{
|
||||||
|
struct tlv_encrypted_data_tlv *encmsg;
|
||||||
|
|
||||||
|
if (!blindedpath_get_alias(ss, my_id, alias))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
encmsg = decrypt_encrypted_data(tmpctx, blinding, ss, enctlv);
|
||||||
|
if (!encmsg)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tal_bytelen(encmsg->path_id) == sizeof(**path_id)) {
|
||||||
|
*path_id = tal(ctx, struct secret);
|
||||||
|
memcpy(*path_id, encmsg->path_id, sizeof(**path_id));
|
||||||
|
} else
|
||||||
|
*path_id = NULL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool decrypt_forwarding_onionmsg(const struct pubkey *blinding,
|
||||||
|
const struct secret *ss,
|
||||||
|
const u8 *enctlv,
|
||||||
|
struct pubkey *next_node,
|
||||||
|
struct pubkey *next_blinding)
|
||||||
|
{
|
||||||
|
struct tlv_encrypted_data_tlv *encmsg;
|
||||||
|
|
||||||
|
encmsg = decrypt_encrypted_data(tmpctx, blinding, ss, enctlv);
|
||||||
|
if (!encmsg)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* BOLT-onion-message #4:
|
||||||
|
*
|
||||||
|
* The reader:
|
||||||
|
* - if it is not the final node according to the onion encryption:
|
||||||
|
*...
|
||||||
|
* - if the `enctlv` ... does not contain
|
||||||
|
* `next_node_id`:
|
||||||
|
* - MUST drop the message.
|
||||||
|
*/
|
||||||
|
if (!encmsg->next_node_id)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* BOLT-onion-message #4:
|
||||||
|
* The reader:
|
||||||
|
* - if it is not the final node according to the onion encryption:
|
||||||
|
*...
|
||||||
|
* - if the `enctlv` contains `path_id`:
|
||||||
|
* - MUST drop the message.
|
||||||
|
*/
|
||||||
|
if (encmsg->path_id)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*next_node = *encmsg->next_node_id;
|
||||||
|
blindedpath_next_blinding(encmsg, blinding, ss, next_blinding);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Peer sends an onion msg. */
|
/* Peer sends an onion msg. */
|
||||||
void handle_onion_message(struct daemon *daemon,
|
void handle_onion_message(struct daemon *daemon,
|
||||||
struct peer *peer, const u8 *msg)
|
struct peer *peer, const u8 *msg)
|
||||||
|
@ -123,9 +188,9 @@ void handle_onion_message(struct daemon *daemon,
|
||||||
if (!om->encrypted_data_tlv) {
|
if (!om->encrypted_data_tlv) {
|
||||||
alias = me;
|
alias = me;
|
||||||
self_id = NULL;
|
self_id = NULL;
|
||||||
} else if (!decrypt_final_enctlv(tmpctx, &blinding, &ss,
|
} else if (!decrypt_final_onionmsg(tmpctx, &blinding, &ss,
|
||||||
om->encrypted_data_tlv, &me, &alias,
|
om->encrypted_data_tlv, &me, &alias,
|
||||||
&self_id)) {
|
&self_id)) {
|
||||||
status_peer_debug(&peer->id,
|
status_peer_debug(&peer->id,
|
||||||
"onion msg: failed to decrypt enctlv"
|
"onion msg: failed to decrypt enctlv"
|
||||||
" %s", tal_hex(tmpctx, om->encrypted_data_tlv));
|
" %s", tal_hex(tmpctx, om->encrypted_data_tlv));
|
||||||
|
@ -159,8 +224,8 @@ void handle_onion_message(struct daemon *daemon,
|
||||||
struct node_id next_node_id;
|
struct node_id next_node_id;
|
||||||
|
|
||||||
/* This fails as expected if no enctlv. */
|
/* This fails as expected if no enctlv. */
|
||||||
if (!decrypt_enctlv(&blinding, &ss, om->encrypted_data_tlv, &next_node,
|
if (!decrypt_forwarding_onionmsg(&blinding, &ss, om->encrypted_data_tlv, &next_node,
|
||||||
&next_blinding)) {
|
&next_blinding)) {
|
||||||
status_peer_debug(&peer->id,
|
status_peer_debug(&peer->id,
|
||||||
"onion msg: invalid enctlv %s",
|
"onion msg: invalid enctlv %s",
|
||||||
tal_hex(tmpctx, om->encrypted_data_tlv));
|
tal_hex(tmpctx, om->encrypted_data_tlv));
|
||||||
|
|
Loading…
Add table
Reference in a new issue