common: use struct onionreply.

This makes it clear we're dealing with a message which is a wrapped error
reply (needing unwrap_onionreply), not an already-wrapped one.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2020-01-23 10:08:04 +10:30
parent aa6aad0131
commit 1099f6a5e1
27 changed files with 126 additions and 90 deletions

View File

@@ -3,6 +3,7 @@
#include <ccan/crypto/shachain/shachain.h>
#include <common/htlc_wire.h>
#include <common/memleak.h>
#include <common/onionreply.h>
#include <wire/wire.h>
/* FIXME: We could adapt tools/generate-wire.py to generate structures
@@ -26,8 +27,8 @@ void towire_fulfilled_htlc(u8 **pptr, const struct fulfilled_htlc *fulfilled)
void towire_failed_htlc(u8 **pptr, const struct failed_htlc *failed)
{
/* Only one can be set. */
assert(failed->failcode || tal_count(failed->failreason));
assert(!failed->failcode || !tal_count(failed->failreason));
assert(failed->failcode || failed->failreason);
assert(!failed->failcode || !failed->failreason);
towire_u64(pptr, failed->id);
towire_u16(pptr, failed->failcode);
if (failed->failcode & UPDATE) {
@@ -37,9 +38,7 @@ void towire_failed_htlc(u8 **pptr, const struct failed_htlc *failed)
assert(!failed->scid);
if (!failed->failcode) {
assert(failed->failreason);
towire_u16(pptr, tal_count(failed->failreason));
towire_u8_array(pptr, failed->failreason,
tal_count(failed->failreason));
towire_onionreply(pptr, failed->failreason);
}
}
}
@@ -98,12 +97,8 @@ struct failed_htlc *fromwire_failed_htlc(const tal_t *ctx, const u8 **cursor, si
failed->id = fromwire_u64(cursor, max);
failed->failcode = fromwire_u16(cursor, max);
if (failed->failcode == 0) {
u16 failreason_len;
failed->scid = NULL;
failreason_len = fromwire_u16(cursor, max);
failed->failreason = tal_arr(failed, u8, failreason_len);
fromwire_u8_array(cursor, max, failed->failreason,
failreason_len);
failed->failreason = fromwire_onionreply(failed, cursor, max);
} else {
failed->failreason = NULL;
if (failed->failcode & UPDATE) {

View File

@@ -29,7 +29,7 @@ struct failed_htlc {
u64 id;
/* Either this is 0 and failreason non-NULL, or vice versa. */
enum onion_type failcode;
u8 *failreason;
const struct onionreply *failreason;
/* Non-NULL if failcode & UPDATE */
struct short_channel_id *scid;
};

View File

@@ -6,6 +6,7 @@
#include <ccan/mem/mem.h>
#include <common/node_id.h>
#include <common/onion.h>
#include <common/onionreply.h>
#include <common/sphinx.h>
#include <common/utils.h>
@@ -529,12 +530,14 @@ struct route_step *process_onionpacket(
return step;
}
u8 *create_onionreply(const tal_t *ctx, const struct secret *shared_secret,
const u8 *failure_msg)
struct onionreply *create_onionreply(const tal_t *ctx,
const struct secret *shared_secret,
const u8 *failure_msg)
{
size_t msglen = tal_count(failure_msg);
size_t padlen = ONION_REPLY_SIZE - msglen;
u8 *reply = tal_arr(ctx, u8, 0), *payload = tal_arr(ctx, u8, 0);
struct onionreply *reply = tal(ctx, struct onionreply);
u8 *payload = tal_arr(ctx, u8, 0);
u8 key[KEY_LEN];
u8 hmac[HMAC_SIZE];
@@ -574,21 +577,23 @@ u8 *create_onionreply(const tal_t *ctx, const struct secret *shared_secret,
generate_key(key, "um", 2, shared_secret->data);
compute_hmac(hmac, payload, tal_count(payload), key, KEY_LEN);
towire(&reply, hmac, sizeof(hmac));
reply->contents = tal_arr(reply, u8, 0),
towire(&reply->contents, hmac, sizeof(hmac));
towire(&reply, payload, tal_count(payload));
towire(&reply->contents, payload, tal_count(payload));
tal_free(payload);
return reply;
}
u8 *wrap_onionreply(const tal_t *ctx,
const struct secret *shared_secret, const u8 *reply)
struct onionreply *wrap_onionreply(const tal_t *ctx,
const struct secret *shared_secret,
const struct onionreply *reply)
{
u8 key[KEY_LEN];
size_t streamlen = tal_count(reply);
size_t streamlen = tal_count(reply->contents);
u8 stream[streamlen];
u8 *result = tal_arr(ctx, u8, streamlen);
struct onionreply *result = tal(ctx, struct onionreply);
/* BOLT #4:
*
@@ -600,39 +605,43 @@ u8 *wrap_onionreply(const tal_t *ctx,
*/
generate_key(key, "ammag", 5, shared_secret->data);
generate_cipher_stream(stream, key, streamlen);
xorbytes(result, stream, reply, streamlen);
result->contents = tal_arr(result, u8, streamlen);
xorbytes(result->contents, stream, reply->contents, streamlen);
return result;
}
u8 *unwrap_onionreply(const tal_t *ctx,
const struct secret *shared_secrets,
const int numhops, const u8 *reply,
const int numhops,
const struct onionreply *reply,
int *origin_index)
{
u8 *msg = tal_arr(tmpctx, u8, tal_count(reply)), *final;
struct onionreply *r;
u8 key[KEY_LEN], hmac[HMAC_SIZE];
const u8 *cursor;
u8 *final;
size_t max;
u16 msglen;
if (tal_count(reply) != ONION_REPLY_SIZE + sizeof(hmac) + 4) {
if (tal_count(reply->contents) != ONION_REPLY_SIZE + sizeof(hmac) + 4) {
return NULL;
}
memcpy(msg, reply, tal_count(reply));
r = new_onionreply(tmpctx, reply->contents);
*origin_index = -1;
for (int i = 0; i < numhops; i++) {
/* Since the encryption is just XORing with the cipher
* stream encryption is identical to decryption */
msg = wrap_onionreply(tmpctx, &shared_secrets[i], msg);
r = wrap_onionreply(tmpctx, &shared_secrets[i], r);
/* Check if the HMAC matches, this means that this is
* the origin */
generate_key(key, "um", 2, shared_secrets[i].data);
compute_hmac(hmac, msg + sizeof(hmac),
tal_count(msg) - sizeof(hmac), key, KEY_LEN);
if (memcmp(hmac, msg, sizeof(hmac)) == 0) {
compute_hmac(hmac, r->contents + sizeof(hmac),
tal_count(r->contents) - sizeof(hmac),
key, KEY_LEN);
if (memcmp(hmac, r->contents, sizeof(hmac)) == 0) {
*origin_index = i;
break;
}
@@ -641,8 +650,8 @@ u8 *unwrap_onionreply(const tal_t *ctx,
return NULL;
}
cursor = msg + sizeof(hmac);
max = tal_count(msg) - sizeof(hmac);
cursor = r->contents + sizeof(hmac);
max = tal_count(r->contents) - sizeof(hmac);
msglen = fromwire_u16(&cursor, &max);
if (msglen > ONION_REPLY_SIZE) {
@@ -650,7 +659,7 @@ u8 *unwrap_onionreply(const tal_t *ctx,
}
final = tal_arr(ctx, u8, msglen);
fromwire(&cursor, &max, final, msglen);
if (!fromwire(&cursor, &max, final, msglen))
return tal_free(final);
return final;
}

View File

@@ -164,8 +164,9 @@ enum onion_type parse_onionpacket(const u8 *src,
* HMAC
* @failure_msg: message (must support tal_len)
*/
u8 *create_onionreply(const tal_t *ctx, const struct secret *shared_secret,
const u8 *failure_msg);
struct onionreply *create_onionreply(const tal_t *ctx,
const struct secret *shared_secret,
const u8 *failure_msg);
/**
* wrap_onionreply - Add another encryption layer to the reply.
@@ -175,8 +176,9 @@ u8 *create_onionreply(const tal_t *ctx, const struct secret *shared_secret,
* encryption.
* @reply: the reply to wrap
*/
u8 *wrap_onionreply(const tal_t *ctx, const struct secret *shared_secret,
const u8 *reply);
struct onionreply *wrap_onionreply(const tal_t *ctx,
const struct secret *shared_secret,
const struct onionreply *reply);
/**
* unwrap_onionreply - Remove layers, check integrity and parse reply
@@ -186,10 +188,13 @@ u8 *wrap_onionreply(const tal_t *ctx, const struct secret *shared_secret,
* @numhops: path length and number of shared_secrets provided
* @reply: the incoming reply
* @origin_index: the index in the path where the reply came from (-1 if unknown)
*
* Reverses create_onionreply and wrap_onionreply.
*/
u8 *unwrap_onionreply(const tal_t *ctx,
const struct secret *shared_secrets,
const int numhops, const u8 *reply,
const int numhops,
const struct onionreply *reply,
int *origin_index);
/**

View File

@@ -1,4 +1,5 @@
#include "../onion.c"
#include "../onionreply.c"
#include "../sphinx.c"
#include <secp256k1.h>
#include <ccan/opt/opt.h>
@@ -61,8 +62,8 @@ static struct secret secret_from_hex(const char *hex)
static void run_unit_tests(void)
{
u8 *oreply;
struct onionreply *reply;
int origin_index;
u8 *reply;
u8 *raw = tal_hexdata(tmpctx, "2002", 4);
/* Shared secrets we already have from the forward path */
@@ -158,10 +159,10 @@ static void run_unit_tests(void)
reply = create_onionreply(tmpctx, &ss[4], raw);
for (int i = 4; i >= 0; i--) {
printf("input_packet %s\n", tal_hex(tmpctx, reply));
printf("input_packet %s\n", tal_hex(tmpctx, reply->contents));
reply = wrap_onionreply(tmpctx, &ss[i], reply);
printf("obfuscated_packet %s\n", tal_hex(tmpctx, reply));
assert(memcmp(reply, intermediates[i], tal_count(reply)) == 0);
printf("obfuscated_packet %s\n", tal_hex(tmpctx, reply->contents));
assert(memcmp(reply->contents, intermediates[i], tal_count(reply->contents)) == 0);
}
oreply = unwrap_onionreply(tmpctx, ss, 5, reply, &origin_index);