uquic/fuzzing/tokens/fuzz.go
2023-10-26 22:47:22 -06:00

140 lines
2.9 KiB
Go

package tokens
import (
"encoding/binary"
"net"
"time"
"github.com/refraction-networking/uquic"
"github.com/refraction-networking/uquic/internal/handshake"
"github.com/refraction-networking/uquic/internal/protocol"
)
func Fuzz(data []byte) int {
if len(data) < 32 {
return -1
}
var key quic.TokenGeneratorKey
copy(key[:], data[:32])
data = data[32:]
tg := handshake.NewTokenGenerator(key)
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
}