From 55c25f427f72237930d2bcb2ffff6b687e65c31b Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 10 Jul 2024 10:44:49 +0200 Subject: [PATCH] htlcswitch+refactor: continue modularising extractTLVPayload In this refactor commit, we extract all the steps from extractTLVPayload that have to do with parsing the payload from the sender and verifying the presence of various fields from the sender. --- htlcswitch/hop/iterator.go | 100 ++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 39 deletions(-) diff --git a/htlcswitch/hop/iterator.go b/htlcswitch/hop/iterator.go index 4d9ee95b0..aca562b03 100644 --- a/htlcswitch/hop/iterator.go +++ b/htlcswitch/hop/iterator.go @@ -188,53 +188,20 @@ func (r *sphinxHopIterator) HopPayload() (*Payload, RouteRole, error) { func extractTLVPayload(r *sphinxHopIterator) (*Payload, RouteRole, error) { isFinal := r.processedPacket.Action == sphinx.ExitNode - // Extract TLVs from the packet constructor (the sender). - payload, parsed, err := ParseTLVPayload( - bytes.NewReader(r.processedPacket.Payload.Payload), + // Initial payload parsing and validation + payload, routeRole, recipientData, err := parseAndValidateSenderPayload( + r.processedPacket.Payload.Payload, isFinal, + r.blindingKit.UpdateAddBlinding.IsSome(), ) if err != nil { - // If we couldn't even parse our payload then we do a - // best-effort of determining our role in a blinded route, - // accepting that we can't know whether we were the introduction - // node (as the payload is not parseable). - routeRole := RouteRoleCleartext - if r.blindingKit.UpdateAddBlinding.IsSome() { - routeRole = RouteRoleRelaying - } - return nil, routeRole, err } - // Now that we've parsed our payload we can determine which role we're - // playing in the route. - _, payloadBlinding := parsed[record.BlindingPointOnionType] - routeRole := NewRouteRole( - r.blindingKit.UpdateAddBlinding.IsSome(), payloadBlinding, - ) - - // Validate the presence of the various payload fields we received from - // the sender. - if err := ValidateTLVPayload( - parsed, isFinal, r.blindingKit.UpdateAddBlinding.IsSome(), - ); err != nil { - return nil, routeRole, err - } - - // If there is no encrypted data from the receiver then return the - // payload as is since the forwarding info would have been received - // from the sender. - if payload.encryptedData != nil { + // If the payload contained no recipient data, then we can exit now. + if !recipientData { return payload, routeRole, nil } - // Validate the presence of various fields in the sender payload given - // that we now know that this is a hop with instructions from the - // recipient. - err = ValidatePayloadWithBlinded(isFinal, parsed) - if err != nil { - return payload, routeRole, err - } - // If we had an encrypted data payload present, pull out our forwarding // info from the blob. fwdInfo, err := r.blindingKit.DecryptAndValidateFwdInfo( @@ -249,6 +216,61 @@ func extractTLVPayload(r *sphinxHopIterator) (*Payload, RouteRole, error) { return payload, routeRole, nil } +// parseAndValidateSenderPayload parses the payload bytes received from the +// onion constructor (the sender) and validates that various fields have been +// set. It also uses the presence of a blinding key in either the +// update_add_htlc message or in the payload to determine the RouteRole. +// The RouteRole is returned even if an error is returned. The boolean return +// value indicates that the sender payload includes encrypted data from the +// recipient that should be parsed. +func parseAndValidateSenderPayload(payloadBytes []byte, isFinalHop, + updateAddBlindingSet bool) (*Payload, RouteRole, bool, error) { + + // Extract TLVs from the packet constructor (the sender). + payload, parsed, err := ParseTLVPayload(bytes.NewReader(payloadBytes)) + if err != nil { + // If we couldn't even parse our payload then we do a + // best-effort of determining our role in a blinded route, + // accepting that we can't know whether we were the introduction + // node (as the payload is not parseable). + routeRole := RouteRoleCleartext + if updateAddBlindingSet { + routeRole = RouteRoleRelaying + } + + return nil, routeRole, false, err + } + + // Now that we've parsed our payload we can determine which role we're + // playing in the route. + _, payloadBlinding := parsed[record.BlindingPointOnionType] + routeRole := NewRouteRole(updateAddBlindingSet, payloadBlinding) + + // Validate the presence of the various payload fields we received from + // the sender. + err = ValidateTLVPayload(parsed, isFinalHop, updateAddBlindingSet) + if err != nil { + return nil, routeRole, false, err + } + + // If there is no encrypted data from the receiver then return the + // payload as is since the forwarding info would have been received + // from the sender. + if payload.encryptedData == nil { + return payload, routeRole, false, nil + } + + // Validate the presence of various fields in the sender payload given + // that we now know that this is a hop with instructions from the + // recipient. + err = ValidatePayloadWithBlinded(isFinalHop, parsed) + if err != nil { + return payload, routeRole, true, err + } + + return payload, routeRole, true, nil +} + // ExtractErrorEncrypter decodes and returns the ErrorEncrypter for this hop, // along with a failure code to signal if the decoding was successful. The // ErrorEncrypter is used to encrypt errors back to the sender in the event that