uquic/fuzzing/tokens/fuzz.go
Gaukas Wang 95575f5fe7
break: update repo url [ci skip]
uTLS is not yet bumped to the new version, so this commit breaks the dependencies relationship by getting rid of the local replace.
2023-08-03 18:58:52 -06:00

142 lines
3 KiB
Go

package tokens
import (
"encoding/binary"
"math/rand"
"net"
"time"
"github.com/refraction-networking/uquic/internal/handshake"
"github.com/refraction-networking/uquic/internal/protocol"
)
func Fuzz(data []byte) int {
if len(data) < 8 {
return -1
}
seed := binary.BigEndian.Uint64(data[:8])
data = data[8:]
tg, err := handshake.NewTokenGenerator(rand.New(rand.NewSource(int64(seed))))
if err != nil {
panic(err)
}
if len(data) < 1 {
return -1
}
s := data[0] % 3
data = data[1:]
switch s {
case 0:
tg.DecodeToken(data)
return 1
case 1:
return newToken(tg, data)
case 2:
return newRetryToken(tg, data)
}
return -1
}
func newToken(tg *handshake.TokenGenerator, data []byte) int {
if len(data) < 1 {
return -1
}
usesUDPAddr := data[0]%2 == 0
data = data[1:]
if len(data) != 18 {
return -1
}
var addr net.Addr
if usesUDPAddr {
addr = &net.UDPAddr{
Port: int(binary.BigEndian.Uint16(data[:2])),
IP: net.IP(data[2:]),
}
} else {
addr = &net.TCPAddr{
Port: int(binary.BigEndian.Uint16(data[:2])),
IP: net.IP(data[2:]),
}
}
start := time.Now()
encrypted, err := tg.NewToken(addr)
if err != nil {
panic(err)
}
token, err := tg.DecodeToken(encrypted)
if err != nil {
panic(err)
}
if token.IsRetryToken {
panic("didn't encode a Retry token")
}
if token.SentTime.Before(start) || token.SentTime.After(time.Now()) {
panic("incorrect send time")
}
if token.OriginalDestConnectionID.Len() > 0 || token.RetrySrcConnectionID.Len() > 0 {
panic("didn't expect connection IDs")
}
return 1
}
func newRetryToken(tg *handshake.TokenGenerator, data []byte) int {
if len(data) < 2 {
return -1
}
origDestConnIDLen := int(data[0] % 21)
retrySrcConnIDLen := int(data[1] % 21)
data = data[2:]
if len(data) < origDestConnIDLen {
return -1
}
origDestConnID := protocol.ParseConnectionID(data[:origDestConnIDLen])
data = data[origDestConnIDLen:]
if len(data) < retrySrcConnIDLen {
return -1
}
retrySrcConnID := protocol.ParseConnectionID(data[:retrySrcConnIDLen])
data = data[retrySrcConnIDLen:]
if len(data) < 1 {
return -1
}
usesUDPAddr := data[0]%2 == 0
data = data[1:]
if len(data) != 18 {
return -1
}
start := time.Now()
var addr net.Addr
if usesUDPAddr {
addr = &net.UDPAddr{
Port: int(binary.BigEndian.Uint16(data[:2])),
IP: net.IP(data[2:]),
}
} else {
addr = &net.TCPAddr{
Port: int(binary.BigEndian.Uint16(data[:2])),
IP: net.IP(data[2:]),
}
}
encrypted, err := tg.NewRetryToken(addr, origDestConnID, retrySrcConnID)
if err != nil {
panic(err)
}
token, err := tg.DecodeToken(encrypted)
if err != nil {
panic(err)
}
if !token.IsRetryToken {
panic("expected a Retry token")
}
if token.SentTime.Before(start) || token.SentTime.After(time.Now()) {
panic("incorrect send time")
}
if token.OriginalDestConnectionID != origDestConnID {
panic("orig dest conn ID doesn't match")
}
if token.RetrySrcConnectionID != retrySrcConnID {
panic("retry src conn ID doesn't match")
}
return 1
}