diff --git a/common/blindedpath.c b/common/blindedpath.c index 46176eab1..44a1d7ed9 100644 --- a/common/blindedpath.c +++ b/common/blindedpath.c @@ -205,8 +205,9 @@ struct tlv_encrypted_data_tlv *decrypt_encrypted_data(const tal_t *ctx, /* BOLT-onion-message #4: * - * - if the `enctlv` is not a valid TLV... - * - MUST drop the message. + * - MUST return an error if `encrypted_recipient_data` does not decrypt + * using the blinding point as described in + * [Route Blinding](#route-blinding). */ /* Note: our parser consider nothing is a valid TLV, but decrypt_encmsg_raw * returns NULL if it couldn't decrypt. */ diff --git a/common/onion_decode.c b/common/onion_decode.c index 544ad864f..77b78a251 100644 --- a/common/onion_decode.c +++ b/common/onion_decode.c @@ -9,6 +9,54 @@ #include #include +/* BOLT-route-blinding #4: + * - If `encrypted_recipient_data` is present: + *... + * - If it is not the final node: + * - MUST return an error if the payload contains other tlv fields than + * `encrypted_recipient_data` and `current_blinding_point`. + */ +static bool check_nonfinal_tlv(const struct tlv_tlv_payload *tlv, + u64 *failtlvtype) +{ + for (size_t i = 0; i < tal_count(tlv->fields); i++) { + switch (tlv->fields[i].numtype) { + case TLV_TLV_PAYLOAD_BLINDING_POINT: + case TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA: + continue; + } + *failtlvtype = tlv->fields[i].numtype; + return false; + } + return true; +} + +/* BOLT-route-blinding #4: + * - If `encrypted_recipient_data` is present: + *... + * - If it is the final node: + * - MUST return an error if the payload contains other tlv fields than + * `encrypted_recipient_data`, `current_blinding_point`, `amt_to_forward`, + * `outgoing_cltv_value` and `total_amount_msat`. + */ +static bool check_final_tlv(const struct tlv_tlv_payload *tlv, + u64 *failtlvtype) +{ + for (size_t i = 0; i < tal_count(tlv->fields); i++) { + switch (tlv->fields[i].numtype) { + case TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA: + case TLV_TLV_PAYLOAD_BLINDING_POINT: + case TLV_TLV_PAYLOAD_AMT_TO_FORWARD: + case TLV_TLV_PAYLOAD_OUTGOING_CLTV_VALUE: + case TLV_TLV_PAYLOAD_TOTAL_AMOUNT_MSAT: + continue; + } + *failtlvtype = tlv->fields[i].numtype; + return false; + } + return true; +} + static u64 ceil_div(u64 a, u64 b) { return (a + b - 1) / b; @@ -23,18 +71,8 @@ static bool handle_blinded_forward(struct onion_payload *p, { u64 amt = amount_in.millisatoshis; /* Raw: allowed to wrap */ - /* BOLT-route-blinding #4: - * - If it is not the final node: - * - MUST return an error if the payload contains other tlv fields - * than `encrypted_recipient_data` and `current_blinding_point`. - */ - for (size_t i = 0; i < tal_count(tlv->fields); i++) { - if (tlv->fields[i].numtype != TLV_TLV_PAYLOAD_BLINDING_POINT - && tlv->fields[i].numtype != TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA) { - *failtlvtype = tlv->fields[i].numtype; - return false; - } - } + if (!check_nonfinal_tlv(tlv, failtlvtype)) + return false; /* BOLT-route-blinding #4: * - If it is not the final node: @@ -84,22 +122,8 @@ static bool handle_blinded_terminal(struct onion_payload *p, const struct tlv_encrypted_data_tlv *enc, u64 *failtlvtype) { - /* BOLT-route-blinding #4: - * - If it is the final node: - * - MUST return an error if the payload contains other tlv fields than - * `encrypted_recipient_data`, `current_blinding_point`, `amt_to_forward`, - * `outgoing_cltv_value` and `total_amount_msat`. - */ - for (size_t i = 0; i < tal_count(tlv->fields); i++) { - if (tlv->fields[i].numtype != TLV_TLV_PAYLOAD_BLINDING_POINT - && tlv->fields[i].numtype != TLV_TLV_PAYLOAD_ENCRYPTED_RECIPIENT_DATA - && tlv->fields[i].numtype != TLV_TLV_PAYLOAD_AMT_TO_FORWARD - && tlv->fields[i].numtype != TLV_TLV_PAYLOAD_OUTGOING_CLTV_VALUE - && tlv->fields[i].numtype != TLV_TLV_PAYLOAD_TOTAL_AMOUNT_MSAT) { - *failtlvtype = tlv->fields[i].numtype; - return false; - } - } + if (!check_final_tlv(tlv, failtlvtype)) + return false; /* BOLT-route-blinding #4: * - MUST return an error if `amt_to_forward`, `outgoing_cltv_value` diff --git a/common/onion_message_parse.c b/common/onion_message_parse.c index 311c33ef5..8bf4ef82c 100644 --- a/common/onion_message_parse.c +++ b/common/onion_message_parse.c @@ -50,25 +50,19 @@ static bool decrypt_forwarding_onionmsg(const struct pubkey *blinding, 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 the `encrypted_data_tlv` contains `path_id`: + * - MUST ignore the message. */ - if (!encmsg->next_node_id) + if (encmsg->path_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. + * - SHOULD forward the message using `onion_message` to the next peer + * indicated by `next_node_id`. */ - if (encmsg->path_id) + if (!encmsg->next_node_id) return false; *next_node = *encmsg->next_node_id; @@ -145,7 +139,6 @@ bool onion_message_parse(const tal_t *ctx, tal_hex(tmpctx, rs->raw_payload)); return false; } - if (rs->nextcase == ONION_END) { *next_onion_msg = NULL; *final_om = tal_steal(ctx, om); @@ -167,6 +160,18 @@ bool onion_message_parse(const tal_t *ctx, *final_om = NULL; + /* BOLT-onion-message #4: + * - if it is not the final node according to the onion encryption: + * - if the `onionmsg_tlv` contains other tlv fields than `encrypted_recipient_data`: + * - MUST ignore the message. + */ + if (tal_count(om->fields) != 1) { + status_peer_debug(peer, + "onion_message_parse: " + "disallowed tlv field"); + return false; + } + /* This fails as expected if no enctlv. */ if (!decrypt_forwarding_onionmsg(blinding, &ss, om->encrypted_recipient_data, next_node_id, &next_blinding)) { @@ -175,7 +180,6 @@ bool onion_message_parse(const tal_t *ctx, tal_hex(tmpctx, om->encrypted_recipient_data)); return false; } - *next_onion_msg = towire_onion_message(ctx, &next_blinding, serialize_onionpacket(tmpctx, rs->next)); diff --git a/common/test/run-onion-message-test.c b/common/test/run-onion-message-test.c index 676397eb7..c3ef156b8 100644 --- a/common/test/run-onion-message-test.c +++ b/common/test/run-onion-message-test.c @@ -337,7 +337,7 @@ int main(int argc, char *argv[]) sphinx_path->session_key = &session_key; /* BOLT-onion-message #4: - * - SHOULD set `len` to 1366 or 32834. + * - SHOULD set `onion_message_packet` `len` to 1366 or 32834. */ op = create_onionpacket(tmpctx, sphinx_path, ROUTING_INFO_SIZE, &path_secrets); diff --git a/lightningd/onion_message.c b/lightningd/onion_message.c index 7316b4346..58b693da4 100644 --- a/lightningd/onion_message.c +++ b/lightningd/onion_message.c @@ -216,7 +216,7 @@ static struct command_result *json_sendonionmessage(struct command *cmd, sphinx_add_hop(sphinx_path, &hops[i].node, hops[i].tlv); /* BOLT-onion-message #4: - * - SHOULD set `len` to 1366 or 32834. + * - SHOULD set `onion_message_packet` `len` to 1366 or 32834. */ if (sphinx_path_payloads_size(sphinx_path) <= ROUTING_INFO_SIZE) onion_size = ROUTING_INFO_SIZE;