Browse Source

sphinx: Committing the onion packet to the payment-hash

The sphinx onion packet now commits to the HTLC payment-hash it is
associated with. This prevents replay attacks with the same onion.
ppa-0.6.1
Christian Decker 8 years ago
committed by Rusty Russell
parent
commit
cae283087d
  1. 3
      daemon/pay.c
  2. 6
      daemon/peer.c
  3. 26
      daemon/sphinx.c
  4. 12
      daemon/sphinx.h
  5. 9
      test/test_sphinx.c

3
daemon/pay.c

@ -442,7 +442,8 @@ static void json_sendpay(struct command *cmd,
randombytes_buf(&sessionkey, sizeof(sessionkey)); randombytes_buf(&sessionkey, sizeof(sessionkey));
/* Onion will carry us from first peer onwards. */ /* Onion will carry us from first peer onwards. */
packet = create_onionpacket(cmd, ids, hoppayloads, sessionkey); packet = create_onionpacket(cmd, ids, hoppayloads, sessionkey,
rhash.u.u8, sizeof(struct sha256));
onion = serialize_onionpacket(cmd, packet); onion = serialize_onionpacket(cmd, packet);
if (pc) if (pc)

6
daemon/peer.c

@ -887,7 +887,8 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
packet = parse_onionpacket(peer, packet = parse_onionpacket(peer,
htlc->routing, tal_count(htlc->routing)); htlc->routing, tal_count(htlc->routing));
if (packet) if (packet)
step = process_onionpacket(packet, packet, &pk); step = process_onionpacket(packet, packet, &pk, htlc->rhash.u.u8,
sizeof(htlc->rhash));
if (!step) { if (!step) {
log_unusual(peer->log, "Bad onion, failing HTLC %"PRIu64, log_unusual(peer->log, "Bad onion, failing HTLC %"PRIu64,
@ -4730,7 +4731,8 @@ static void json_newhtlc(struct command *cmd,
hoppayloads = tal_arrz(cmd, struct hoppayload, 1); hoppayloads = tal_arrz(cmd, struct hoppayload, 1);
memcpy(&path[0], peer->id, sizeof(struct pubkey)); memcpy(&path[0], peer->id, sizeof(struct pubkey));
randombytes_buf(&sessionkey, sizeof(sessionkey)); randombytes_buf(&sessionkey, sizeof(sessionkey));
packet = create_onionpacket(cmd, path, hoppayloads, sessionkey); packet = create_onionpacket(cmd, path, hoppayloads, sessionkey,
rhash.u.u8, sizeof(rhash));
onion = serialize_onionpacket(cmd, packet); onion = serialize_onionpacket(cmd, packet);
log_debug(peer->log, "JSON command to add new HTLC"); log_debug(peer->log, "JSON command to add new HTLC");

26
daemon/sphinx.c

@ -159,13 +159,18 @@ static bool compute_hmac(
return true; return true;
} }
static void compute_packet_hmac(const struct onionpacket *packet, u8 *mukey, u8 *hmac) static void compute_packet_hmac(const struct onionpacket *packet,
const u8 *assocdata, const size_t assocdatalen,
u8 *mukey, u8 *hmac)
{ {
u8 mactemp[ROUTING_INFO_SIZE + TOTAL_HOP_PAYLOAD_SIZE]; u8 mactemp[ROUTING_INFO_SIZE + TOTAL_HOP_PAYLOAD_SIZE + assocdatalen];
u8 mac[32]; u8 mac[32];
int pos = 0;
write_buffer(mactemp, packet->routinginfo, ROUTING_INFO_SIZE, &pos);
write_buffer(mactemp, packet->hoppayloads, TOTAL_HOP_PAYLOAD_SIZE, &pos);
write_buffer(mactemp, assocdata, assocdatalen, &pos);
memcpy(mactemp, packet->routinginfo, ROUTING_INFO_SIZE);
memcpy(mactemp + ROUTING_INFO_SIZE, packet->hoppayloads, TOTAL_HOP_PAYLOAD_SIZE);
compute_hmac(mac, mactemp, sizeof(mactemp), mukey, KEY_LEN); compute_hmac(mac, mactemp, sizeof(mactemp), mukey, KEY_LEN);
memcpy(hmac, mac, 20); memcpy(hmac, mac, 20);
} }
@ -340,7 +345,9 @@ struct onionpacket *create_onionpacket(
const tal_t *ctx, const tal_t *ctx,
struct pubkey *path, struct pubkey *path,
struct hoppayload hoppayloads[], struct hoppayload hoppayloads[],
const u8 *sessionkey const u8 *sessionkey,
const u8 *assocdata,
const size_t assocdatalen
) )
{ {
struct onionpacket *packet = talz(ctx, struct onionpacket); struct onionpacket *packet = talz(ctx, struct onionpacket);
@ -394,7 +401,8 @@ struct onionpacket *create_onionpacket(
memcpy(packet->hoppayloads + len, hopfiller, sizeof(hopfiller)); memcpy(packet->hoppayloads + len, hopfiller, sizeof(hopfiller));
} }
compute_packet_hmac(packet, keys.mu, nexthmac); compute_packet_hmac(packet, assocdata, assocdatalen, keys.mu,
nexthmac);
pubkey_hash160(nextaddr, &path[i]); pubkey_hash160(nextaddr, &path[i]);
} }
memcpy(packet->mac, nexthmac, sizeof(nexthmac)); memcpy(packet->mac, nexthmac, sizeof(nexthmac));
@ -409,7 +417,9 @@ struct onionpacket *create_onionpacket(
struct route_step *process_onionpacket( struct route_step *process_onionpacket(
const tal_t *ctx, const tal_t *ctx,
const struct onionpacket *msg, const struct onionpacket *msg,
struct privkey *hop_privkey struct privkey *hop_privkey,
const u8 *assocdata,
const size_t assocdatalen
) )
{ {
struct route_step *step = talz(ctx, struct route_step); struct route_step *step = talz(ctx, struct route_step);
@ -427,7 +437,7 @@ struct route_step *process_onionpacket(
create_shared_secret(secret, &msg->ephemeralkey, hop_privkey->secret); create_shared_secret(secret, &msg->ephemeralkey, hop_privkey->secret);
generate_key_set(secret, &keys); generate_key_set(secret, &keys);
compute_packet_hmac(msg, keys.mu, hmac); compute_packet_hmac(msg, assocdata, assocdatalen, keys.mu, hmac);
if (memcmp(msg->mac, hmac, sizeof(hmac)) != 0) { if (memcmp(msg->mac, hmac, sizeof(hmac)) != 0) {
warnx("Computed MAC does not match expected MAC, the message was modified."); warnx("Computed MAC does not match expected MAC, the message was modified.");

12
daemon/sphinx.h

@ -57,12 +57,16 @@ struct route_step {
* HOP_PAYLOAD_SIZE bytes) * HOP_PAYLOAD_SIZE bytes)
* @num_hops: path length in nodes * @num_hops: path length in nodes
* @sessionkey: 20 byte random session key to derive secrets from * @sessionkey: 20 byte random session key to derive secrets from
* @assocdata: associated data to commit to in HMACs
* @assocdatalen: length of the assocdata
*/ */
struct onionpacket *create_onionpacket( struct onionpacket *create_onionpacket(
const tal_t * ctx, const tal_t * ctx,
struct pubkey path[], struct pubkey path[],
struct hoppayload hoppayloads[], struct hoppayload hoppayloads[],
const u8 * sessionkey const u8 * sessionkey,
const u8 *assocdata,
const size_t assocdatalen
); );
/** /**
@ -73,11 +77,15 @@ struct onionpacket *create_onionpacket(
* @packet: incoming packet being processed * @packet: incoming packet being processed
* @hop_privkey: the processing node's private key to decrypt the packet * @hop_privkey: the processing node's private key to decrypt the packet
* @hoppayload: the per-hop payload destined for the processing node. * @hoppayload: the per-hop payload destined for the processing node.
* @assocdata: associated data to commit to in HMACs
* @assocdatalen: length of the assocdata
*/ */
struct route_step *process_onionpacket( struct route_step *process_onionpacket(
const tal_t * ctx, const tal_t * ctx,
const struct onionpacket *packet, const struct onionpacket *packet,
struct privkey *hop_privkey struct privkey *hop_privkey,
const u8 *assocdata,
const size_t assocdatalen
); );
/** /**

9
test/test_sphinx.c

@ -16,6 +16,8 @@ int main(int argc, char **argv)
{ {
bool generate = false, decode = false; bool generate = false, decode = false;
const tal_t *ctx = talz(NULL, tal_t); const tal_t *ctx = talz(NULL, tal_t);
u8 assocdata[32];
memset(assocdata, 'B', sizeof(assocdata));
secp256k1_ctx = secp256k1_context_create( secp256k1_ctx = secp256k1_context_create(
SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
@ -56,7 +58,9 @@ int main(int argc, char **argv)
struct onionpacket *res = create_onionpacket(ctx, struct onionpacket *res = create_onionpacket(ctx,
path, path,
hoppayloads, hoppayloads,
sessionkey); sessionkey,
assocdata,
sizeof(assocdata));
u8 *serialized = serialize_onionpacket(ctx, res); u8 *serialized = serialize_onionpacket(ctx, res);
if (!serialized) if (!serialized)
@ -87,7 +91,8 @@ int main(int argc, char **argv)
if (!msg) if (!msg)
errx(1, "Error parsing message."); errx(1, "Error parsing message.");
step = process_onionpacket(ctx, msg, &seckey); step = process_onionpacket(ctx, msg, &seckey, assocdata,
sizeof(assocdata));
if (!step->next) if (!step->next)
errx(1, "Error processing message."); errx(1, "Error processing message.");

Loading…
Cancel
Save