Repository: libp2p/go-libp2p
Pull request #2826 (2024-06-07 08:46:48)

circuitv2: improve voucher validation


Patch:
diff --git a/p2p/protocol/circuitv2/client/reservation.go b/p2p/protocol/circuitv2/client/reservation.go
index dbb92419..462c01d2 100644
--- a/p2p/protocol/circuitv2/client/reservation.go
+++ b/p2p/protocol/circuitv2/client/reservation.go
@@ -93,10 +93,7 @@ func Reserve(ctx context.Context, h host.Host, ai peer.AddrInfo) (*Reservation,
 	}
 
 	if msg.GetType() != pbv2.HopMessage_STATUS {
-		return nil, ReservationError{
-			Status: pbv2.Status_MALFORMED_MESSAGE,
-			Reason: fmt.Sprintf("unexpected relay response: not a status message (%d)", msg.GetType()),
-			err:    err}
+		return nil, ReservationError{Status: pbv2.Status_MALFORMED_MESSAGE, Reason: fmt.Sprintf("unexpected relay response: not a status message (%d)", msg.GetType())}
 	}
 
 	if status := msg.GetStatus(); status != pbv2.Status_OK {
@@ -130,7 +127,7 @@ func Reserve(ctx context.Context, h host.Host, ai peer.AddrInfo) (*Reservation,
 
 	voucherBytes := rsvp.GetVoucher()
 	if voucherBytes != nil {
-		_, rec, err := record.ConsumeEnvelope(voucherBytes, proto.RecordDomain)
+		env, rec, err := record.ConsumeEnvelope(voucherBytes, proto.RecordDomain)
 		if err != nil {
 			return nil, ReservationError{
 				Status: pbv2.Status_MALFORMED_MESSAGE,
@@ -146,6 +143,27 @@ func Reserve(ctx context.Context, h host.Host, ai peer.AddrInfo) (*Reservation,
 				Reason: fmt.Sprintf("unexpected voucher record type: %+T", rec),
 			}
 		}
+		signerPeerID, err := peer.IDFromPublicKey(env.PublicKey)
+		if err != nil {
+			return nil, ReservationError{
+				Status: pbv2.Status_MALFORMED_MESSAGE,
+				Reason: fmt.Sprintf("invalid voucher signing public key: %s", err),
+				err:    err,
+			}
+		}
+		if signerPeerID != voucher.Relay {
+			return nil, ReservationError{
+				Status: pbv2.Status_MALFORMED_MESSAGE,
+				Reason: fmt.Sprintf("invalid voucher relay id: expected %s, got %s", signerPeerID, voucher.Relay),
+			}
+		}
+		if h.ID() != voucher.Peer {
+			return nil, ReservationError{
+				Status: pbv2.Status_MALFORMED_MESSAGE,
+				Reason: fmt.Sprintf("invalid voucher peer id: expected %s, got %s", h.ID(), voucher.Peer),
+			}
+
+		}
 		result.Voucher = voucher
 	}
 


Test patch:
diff --git a/p2p/protocol/circuitv2/client/reservation_test.go b/p2p/protocol/circuitv2/client/reservation_test.go
index decb3e71..d1ab6dc6 100644
--- a/p2p/protocol/circuitv2/client/reservation_test.go
+++ b/p2p/protocol/circuitv2/client/reservation_test.go
@@ -8,8 +8,11 @@ import (
 	"time"
 
 	"github.com/libp2p/go-libp2p"
+	"github.com/libp2p/go-libp2p/core/crypto"
 	"github.com/libp2p/go-libp2p/core/network"
 	"github.com/libp2p/go-libp2p/core/peer"
+	"github.com/libp2p/go-libp2p/core/record"
+	"github.com/libp2p/go-libp2p/core/test"
 	"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client"
 	pbv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/pb"
 	"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/proto"
@@ -84,6 +87,45 @@ func TestReservationFailures(t *testing.T) {
 			err:    "error consuming voucher envelope: failed when unmarshalling the envelope",
 			status: pbv2.Status_MALFORMED_MESSAGE,
 		},
+		{
+			name: "invalid voucher 2",
+			streamHandler: func(s network.Stream) {
+				status := pbv2.Status_OK
+				expire := uint64(time.Now().Add(time.Hour).UnixNano())
+				priv, _, err := test.RandTestKeyPair(crypto.Ed25519, 256)
+				if err != nil {
+					s.Reset()
+					return
+				}
+				relay, _ := test.RandPeerID()
+				peer, _ := test.RandPeerID()
+				voucher := &proto.ReservationVoucher{
+					Relay:      relay,
+					Peer:       peer,
+					Expiration: time.Now().Add(time.Hour),
+				}
+				signedVoucher, err := record.Seal(voucher, priv)
+				if err != nil {
+					s.Reset()
+					return
+				}
+				env, err := signedVoucher.Marshal()
+				if err != nil {
+					s.Reset()
+					return
+				}
+				util.NewDelimitedWriter(s).WriteMsg(&pbv2.HopMessage{
+					Type:   pbv2.HopMessage_STATUS.Enum(),
+					Status: &status,
+					Reservation: &pbv2.Reservation{
+						Expire:  &expire,
+						Voucher: env,
+					},
+				})
+			},
+			err:    "invalid voucher relay id",
+			status: pbv2.Status_MALFORMED_MESSAGE,
+		},
 	}
 
 	for _, tc := range testcases {