github.com/daeuniverse/quic-go@v0.0.0-20240413031024-943f218e0810/fuzzing/header/fuzz.go (about) 1 package header 2 3 import ( 4 "bytes" 5 "fmt" 6 7 "github.com/daeuniverse/quic-go/internal/protocol" 8 "github.com/daeuniverse/quic-go/internal/wire" 9 ) 10 11 const version = protocol.Version1 12 13 // PrefixLen is the number of bytes used for configuration 14 const PrefixLen = 1 15 16 // Fuzz fuzzes the QUIC header. 17 // 18 //go:generate go run ./cmd/corpus.go 19 func Fuzz(data []byte) int { 20 if len(data) < PrefixLen { 21 return 0 22 } 23 connIDLen := int(data[0] % 21) 24 data = data[PrefixLen:] 25 26 if wire.IsVersionNegotiationPacket(data) { 27 return fuzzVNP(data) 28 } 29 connID, err := wire.ParseConnectionID(data, connIDLen) 30 if err != nil { 31 return 0 32 } 33 34 if !wire.IsLongHeaderPacket(data[0]) { 35 wire.ParseShortHeader(data, connIDLen) 36 return 1 37 } 38 39 is0RTTPacket := wire.Is0RTTPacket(data) 40 hdr, _, _, err := wire.ParsePacket(data) 41 if err != nil { 42 return 0 43 } 44 if hdr.DestConnectionID != connID { 45 panic(fmt.Sprintf("Expected connection IDs to match: %s vs %s", hdr.DestConnectionID, connID)) 46 } 47 if (hdr.Type == protocol.PacketType0RTT) != is0RTTPacket { 48 panic("inconsistent 0-RTT packet detection") 49 } 50 51 var extHdr *wire.ExtendedHeader 52 // Parse the extended header, if this is not a Retry packet. 53 if hdr.Type == protocol.PacketTypeRetry { 54 extHdr = &wire.ExtendedHeader{Header: *hdr} 55 } else { 56 var err error 57 extHdr, err = hdr.ParseExtended(bytes.NewReader(data), version) 58 if err != nil { 59 return 0 60 } 61 } 62 // We always use a 2-byte encoding for the Length field in Long Header packets. 63 // Serializing the header will fail when using a higher value. 64 if hdr.Length > 16383 { 65 return 1 66 } 67 b, err := extHdr.Append(nil, version) 68 if err != nil { 69 // We are able to parse packets with connection IDs longer than 20 bytes, 70 // but in QUIC version 1, we don't write headers with longer connection IDs. 71 if hdr.DestConnectionID.Len() <= protocol.MaxConnIDLen && 72 hdr.SrcConnectionID.Len() <= protocol.MaxConnIDLen { 73 panic(err) 74 } 75 return 0 76 } 77 // GetLength is not implemented for Retry packets 78 if hdr.Type != protocol.PacketTypeRetry { 79 if expLen := extHdr.GetLength(version); expLen != protocol.ByteCount(len(b)) { 80 panic(fmt.Sprintf("inconsistent header length: %#v. Expected %d, got %d", extHdr, expLen, len(b))) 81 } 82 } 83 return 1 84 } 85 86 func fuzzVNP(data []byte) int { 87 connID, err := wire.ParseConnectionID(data, 0) 88 if err != nil { 89 return 0 90 } 91 dest, src, versions, err := wire.ParseVersionNegotiationPacket(data) 92 if err != nil { 93 return 0 94 } 95 if !bytes.Equal(dest, connID.Bytes()) { 96 panic("connection IDs don't match") 97 } 98 if len(versions) == 0 { 99 panic("no versions") 100 } 101 wire.ComposeVersionNegotiation(src, dest, versions) 102 return 1 103 }