Browse Source
Now "raw_payload" is always the complete string (including realm or length bytes at the front). This has several effects: 1. We can receive an decrypt an onion which is grossly malformed. 2. We can still hand this to the htlc_accepted hook. 3. We then fail it unless the htlc_accepted accepts it manually. 4. The createonion API now takes the raw payload, and does not know anything about "style". The only caveat is that the sphinx code needs to know the payload length: we have a call for that, which simply tells it to copy the entire onion (and treat us as the final node) if it's invalid. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>travis-debug
Rusty Russell
5 years ago
committed by
Christian Decker
17 changed files with 543 additions and 512 deletions
@ -0,0 +1,308 @@ |
|||
#include "common/onion.h" |
|||
#include <assert.h> |
|||
#include <ccan/array_size/array_size.h> |
|||
#include <common/sphinx.h> |
|||
#include <wire/gen_onion_wire.h> |
|||
|
|||
/* BOLT #4:
|
|||
* |
|||
* ## Legacy `hop_data` payload format |
|||
* |
|||
* The `hop_data` format is identified by a single `0x00`-byte length, |
|||
* for backward compatibility. Its payload is defined as: |
|||
* |
|||
* 1. type: `hop_data` (for `realm` 0) |
|||
* 2. data: |
|||
* * [`short_channel_id`:`short_channel_id`] |
|||
* * [`u64`:`amt_to_forward`] |
|||
* * [`u32`:`outgoing_cltv_value`] |
|||
* * [`12*byte`:`padding`] |
|||
*/ |
|||
static u8 *make_v0_hop(const tal_t *ctx, |
|||
const struct short_channel_id *scid, |
|||
struct amount_msat forward, u32 outgoing_cltv) |
|||
{ |
|||
const u8 padding[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
|||
/* Prepend 0 byte for realm */ |
|||
u8 *buf = tal_arrz(ctx, u8, 1); |
|||
towire_short_channel_id(&buf, scid); |
|||
towire_u64(&buf, forward.millisatoshis); /* Raw: low-level serializer */ |
|||
towire_u32(&buf, outgoing_cltv); |
|||
towire(&buf, padding, ARRAY_SIZE(padding)); |
|||
assert(tal_bytelen(buf) == 1 + 32); |
|||
return buf; |
|||
} |
|||
|
|||
static u8 *make_tlv_hop(const tal_t *ctx, |
|||
const struct tlv_tlv_payload *tlv) |
|||
{ |
|||
/* We can't have over 64k anyway */ |
|||
u8 *tlvs = tal_arr(ctx, u8, 3); |
|||
|
|||
towire_tlv_payload(&tlvs, tlv); |
|||
|
|||
switch (bigsize_put(tlvs, tal_bytelen(tlvs) - 3)) { |
|||
case 1: |
|||
/* Move over two unused bytes */ |
|||
memmove(tlvs + 1, tlvs + 3, tal_bytelen(tlvs) - 3); |
|||
tal_resize(&tlvs, tal_bytelen(tlvs) - 2); |
|||
return tlvs; |
|||
case 3: |
|||
return tlvs; |
|||
} |
|||
abort(); |
|||
} |
|||
|
|||
u8 *onion_nonfinal_hop(const tal_t *ctx, |
|||
bool use_tlv, |
|||
const struct short_channel_id *scid, |
|||
struct amount_msat forward, |
|||
u32 outgoing_cltv) |
|||
{ |
|||
if (use_tlv) { |
|||
struct tlv_tlv_payload *tlv = tlv_tlv_payload_new(tmpctx); |
|||
struct tlv_tlv_payload_amt_to_forward tlv_amt; |
|||
struct tlv_tlv_payload_outgoing_cltv_value tlv_cltv; |
|||
struct tlv_tlv_payload_short_channel_id tlv_scid; |
|||
|
|||
/* BOLT #4:
|
|||
* |
|||
* The writer: |
|||
* - MUST include `amt_to_forward` and `outgoing_cltv_value` |
|||
* for every node. |
|||
* - MUST include `short_channel_id` for every non-final node. |
|||
*/ |
|||
tlv_amt.amt_to_forward = forward.millisatoshis; /* Raw: TLV convert */ |
|||
tlv_cltv.outgoing_cltv_value = outgoing_cltv; |
|||
tlv_scid.short_channel_id = *scid; |
|||
tlv->amt_to_forward = &tlv_amt; |
|||
tlv->outgoing_cltv_value = &tlv_cltv; |
|||
tlv->short_channel_id = &tlv_scid; |
|||
|
|||
return make_tlv_hop(ctx, tlv); |
|||
} else { |
|||
return make_v0_hop(ctx, scid, forward, outgoing_cltv); |
|||
} |
|||
} |
|||
|
|||
u8 *onion_final_hop(const tal_t *ctx, |
|||
bool use_tlv, |
|||
struct amount_msat forward, |
|||
u32 outgoing_cltv, |
|||
struct amount_msat total_msat, |
|||
const struct secret *payment_secret) |
|||
{ |
|||
/* These go together! */ |
|||
if (!payment_secret) |
|||
assert(amount_msat_eq(total_msat, forward)); |
|||
|
|||
if (use_tlv) { |
|||
struct tlv_tlv_payload *tlv = tlv_tlv_payload_new(tmpctx); |
|||
struct tlv_tlv_payload_amt_to_forward tlv_amt; |
|||
struct tlv_tlv_payload_outgoing_cltv_value tlv_cltv; |
|||
#if EXPERIMENTAL_FEATURES |
|||
struct tlv_tlv_payload_payment_data tlv_pdata; |
|||
#endif |
|||
|
|||
/* BOLT #4:
|
|||
* |
|||
* The writer: |
|||
* - MUST include `amt_to_forward` and `outgoing_cltv_value` |
|||
* for every node. |
|||
*... |
|||
* - MUST NOT include `short_channel_id` for the final node. |
|||
*/ |
|||
tlv_amt.amt_to_forward = forward.millisatoshis; /* Raw: TLV convert */ |
|||
tlv_cltv.outgoing_cltv_value = outgoing_cltv; |
|||
tlv->amt_to_forward = &tlv_amt; |
|||
tlv->outgoing_cltv_value = &tlv_cltv; |
|||
|
|||
#if EXPERIMENTAL_FEATURES |
|||
if (payment_secret) { |
|||
tlv_pdata.payment_secret = *payment_secret; |
|||
tlv_pdata.total_msat = total_msat.millisatoshis; /* Raw: TLV convert */ |
|||
tlv->payment_data = &tlv_pdata; |
|||
} |
|||
#else |
|||
/* Wihtout EXPERIMENTAL_FEATURES, we can't send payment_secret */ |
|||
if (payment_secret) |
|||
return NULL; |
|||
#endif |
|||
return make_tlv_hop(ctx, tlv); |
|||
} else { |
|||
static struct short_channel_id all_zero_scid; |
|||
/* No payment secrets in legacy format. */ |
|||
if (payment_secret) |
|||
return NULL; |
|||
return make_v0_hop(ctx, &all_zero_scid, forward, outgoing_cltv); |
|||
} |
|||
} |
|||
|
|||
/* Returns true if valid, and fills in type. */ |
|||
static bool pull_payload_length(const u8 **cursor, |
|||
size_t *max, |
|||
enum onion_payload_type *type, |
|||
size_t *len) |
|||
{ |
|||
/* *len will incorporate bytes we read from cursor */ |
|||
const u8 *start = *cursor; |
|||
|
|||
/* BOLT #4:
|
|||
* |
|||
* The `length` field determines both the length and the format of the |
|||
* `hop_payload` field; the following formats are defined: |
|||
*/ |
|||
*len = fromwire_bigsize(cursor, max); |
|||
if (!cursor) |
|||
return false; |
|||
|
|||
/* BOLT #4:
|
|||
* - Legacy `hop_data` format, identified by a single `0x00` byte for |
|||
* length. In this case the `hop_payload_length` is defined to be 32 |
|||
* bytes. |
|||
*/ |
|||
if (*len == 0) { |
|||
if (type) |
|||
*type = ONION_V0_PAYLOAD; |
|||
assert(*cursor - start == 1); |
|||
*len = 1 + 32; |
|||
return true; |
|||
} |
|||
|
|||
#if !EXPERIMENTAL_FEATURES |
|||
/* Only handle legacy format */ |
|||
return false; |
|||
#else |
|||
/* BOLT #4:
|
|||
* - `tlv_payload` format, identified by any length over `1`. In this |
|||
* case the `hop_payload_length` is equal to the numeric value of |
|||
* `length`. |
|||
*/ |
|||
if (*len > 1) { |
|||
/* It's still invalid if it claims to be too long! */ |
|||
if (*len > ROUTING_INFO_SIZE - HMAC_SIZE) |
|||
return false; |
|||
|
|||
if (type) |
|||
*type = ONION_TLV_PAYLOAD; |
|||
*len += (*cursor - start); |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
#endif /* EXPERIMENTAL_FEATURES */ |
|||
} |
|||
|
|||
size_t onion_payload_length(const u8 *raw_payload, size_t len, |
|||
bool *valid, |
|||
enum onion_payload_type *type) |
|||
{ |
|||
size_t max = len, payload_len; |
|||
*valid = pull_payload_length(&raw_payload, &max, type, &payload_len); |
|||
|
|||
/* If it's not valid, copy the entire thing. */ |
|||
if (!*valid) |
|||
return len; |
|||
|
|||
return payload_len; |
|||
} |
|||
|
|||
struct onion_payload *onion_decode(const tal_t *ctx, |
|||
const struct route_step *rs) |
|||
{ |
|||
struct onion_payload *p = tal(ctx, struct onion_payload); |
|||
const u8 *cursor = rs->raw_payload; |
|||
size_t max = tal_bytelen(cursor), len; |
|||
struct tlv_tlv_payload *tlv; |
|||
|
|||
if (!pull_payload_length(&cursor, &max, &p->type, &len)) |
|||
return tal_free(p); |
|||
|
|||
switch (p->type) { |
|||
case ONION_V0_PAYLOAD: |
|||
p->type = ONION_V0_PAYLOAD; |
|||
p->forward_channel = tal(p, struct short_channel_id); |
|||
fromwire_short_channel_id(&cursor, &max, p->forward_channel); |
|||
p->amt_to_forward = fromwire_amount_msat(&cursor, &max); |
|||
p->outgoing_cltv = fromwire_u32(&cursor, &max); |
|||
p->payment_secret = NULL; |
|||
|
|||
if (rs->nextcase == ONION_FORWARD) { |
|||
p->total_msat = NULL; |
|||
} else { |
|||
/* BOLT-e36f7b6517e1173dcbd49da3b516cfe1f48ae556 #4:
|
|||
* - if it is the final node: |
|||
* - MUST treat `total_msat` as if it were equal to |
|||
* `amt_to_forward` if it is not present. */ |
|||
p->total_msat = tal_dup(p, struct amount_msat, |
|||
&p->amt_to_forward); |
|||
} |
|||
|
|||
/* If they somehow got an invalid onion this far, fail. */ |
|||
if (!cursor) |
|||
return tal_free(p); |
|||
return p; |
|||
|
|||
case ONION_TLV_PAYLOAD: |
|||
tlv = tlv_tlv_payload_new(p); |
|||
if (!fromwire_tlv_payload(&cursor, &max, tlv)) |
|||
return tal_free(p); |
|||
if (!tlv_payload_is_valid(tlv, NULL)) |
|||
return tal_free(p); |
|||
|
|||
/* BOLT #4:
|
|||
* |
|||
* The reader: |
|||
* - MUST return an error if `amt_to_forward` or |
|||
* `outgoing_cltv_value` are not present. |
|||
*/ |
|||
if (!tlv->amt_to_forward || !tlv->outgoing_cltv_value) |
|||
return tal_free(p); |
|||
|
|||
amount_msat_from_u64(&p->amt_to_forward, |
|||
tlv->amt_to_forward->amt_to_forward); |
|||
p->outgoing_cltv = tlv->outgoing_cltv_value->outgoing_cltv_value; |
|||
|
|||
/* BOLT #4:
|
|||
* |
|||
* The writer: |
|||
*... |
|||
* - MUST include `short_channel_id` for every non-final node. |
|||
*/ |
|||
if (rs->nextcase == ONION_FORWARD) { |
|||
if (!tlv->short_channel_id) |
|||
return tal_free(p); |
|||
p->forward_channel = tal(p, struct short_channel_id); |
|||
*p->forward_channel |
|||
= tlv->short_channel_id->short_channel_id; |
|||
p->total_msat = NULL; |
|||
} else { |
|||
p->forward_channel = NULL; |
|||
/* BOLT-e36f7b6517e1173dcbd49da3b516cfe1f48ae556 #4:
|
|||
* - if it is the final node: |
|||
* - MUST treat `total_msat` as if it were equal to |
|||
* `amt_to_forward` if it is not present. */ |
|||
p->total_msat = tal_dup(p, struct amount_msat, |
|||
&p->amt_to_forward); |
|||
} |
|||
|
|||
p->payment_secret = NULL; |
|||
|
|||
#if EXPERIMENTAL_FEATURES |
|||
if (tlv->payment_data) { |
|||
p->payment_secret = tal_dup(p, struct secret, |
|||
&tlv->payment_data->payment_secret); |
|||
tal_free(p->total_msat); |
|||
p->total_msat = tal(p, struct amount_msat); |
|||
p->total_msat->millisatoshis /* Raw: tu64 on wire */ |
|||
= tlv->payment_data->total_msat; |
|||
} |
|||
#endif |
|||
tal_free(tlv); |
|||
return p; |
|||
} |
|||
|
|||
/* You said it was a valid type! */ |
|||
abort(); |
|||
} |
@ -0,0 +1,64 @@ |
|||
#ifndef LIGHTNING_COMMON_ONION_H |
|||
#define LIGHTNING_COMMON_ONION_H |
|||
#include "config.h" |
|||
#include <ccan/short_types/short_types.h> |
|||
#include <common/amount.h> |
|||
|
|||
struct route_step; |
|||
|
|||
enum onion_payload_type { |
|||
ONION_V0_PAYLOAD = 0, |
|||
ONION_TLV_PAYLOAD = 1, |
|||
}; |
|||
|
|||
struct onion_payload { |
|||
enum onion_payload_type type; |
|||
|
|||
struct amount_msat amt_to_forward; |
|||
u32 outgoing_cltv; |
|||
struct amount_msat *total_msat; |
|||
struct short_channel_id *forward_channel; |
|||
struct secret *payment_secret; |
|||
}; |
|||
|
|||
u8 *onion_nonfinal_hop(const tal_t *ctx, |
|||
bool use_tlv, |
|||
const struct short_channel_id *scid, |
|||
struct amount_msat forward, |
|||
u32 outgoing_cltv); |
|||
|
|||
/* Note that this can fail if we supply payment_secret and !use_tlv! */ |
|||
u8 *onion_final_hop(const tal_t *ctx, |
|||
bool use_tlv, |
|||
struct amount_msat forward, |
|||
u32 outgoing_cltv, |
|||
struct amount_msat total_msat, |
|||
const struct secret *payment_secret); |
|||
|
|||
/**
|
|||
* onion_payload_length: measure payload length in decrypted onion. |
|||
* @raw_payload: payload to look at. |
|||
* @len: length of @raw_payload in bytes. |
|||
* @valid: set to true if it is valid, false otherwise. |
|||
* @type: if non-NULL, set to type of payload if *@valid is true. |
|||
* |
|||
* If @valid is set, there is room for the HMAC immediately following, |
|||
* as the return value is <= ROUTING_INFO_SIZE - HMAC_SIZE. Otherwise, |
|||
* the return value is @len (i.e. the entire payload). |
|||
*/ |
|||
size_t onion_payload_length(const u8 *raw_payload, size_t len, |
|||
bool *valid, |
|||
enum onion_payload_type *type); |
|||
|
|||
/**
|
|||
* onion_decode: decode payload from a decrypted onion. |
|||
* @ctx: context to allocate onion_contents off. |
|||
* @rs: the route_step, whose raw_payload is of at least length |
|||
* onion_payload_length(). |
|||
* |
|||
* If the payload is not valid, returns NULL. |
|||
*/ |
|||
struct onion_payload *onion_decode(const tal_t *ctx, |
|||
const struct route_step *rs); |
|||
|
|||
#endif /* LIGHTNING_COMMON_ONION_H */ |
Loading…
Reference in new issue