github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/fuzzing/tokens/fuzz.go (about)

     1  package tokens
     2  
     3  import (
     4  	"encoding/binary"
     5  	"net"
     6  	"time"
     7  
     8  	"github.com/apernet/quic-go"
     9  	"github.com/apernet/quic-go/internal/handshake"
    10  	"github.com/apernet/quic-go/internal/protocol"
    11  )
    12  
    13  func Fuzz(data []byte) int {
    14  	if len(data) < 32 {
    15  		return -1
    16  	}
    17  	var key quic.TokenGeneratorKey
    18  	copy(key[:], data[:32])
    19  	data = data[32:]
    20  	tg := handshake.NewTokenGenerator(key)
    21  	if len(data) < 1 {
    22  		return -1
    23  	}
    24  	s := data[0] % 3
    25  	data = data[1:]
    26  	switch s {
    27  	case 0:
    28  		tg.DecodeToken(data)
    29  		return 1
    30  	case 1:
    31  		return newToken(tg, data)
    32  	case 2:
    33  		return newRetryToken(tg, data)
    34  	}
    35  	return -1
    36  }
    37  
    38  func newToken(tg *handshake.TokenGenerator, data []byte) int {
    39  	if len(data) < 1 {
    40  		return -1
    41  	}
    42  	usesUDPAddr := data[0]%2 == 0
    43  	data = data[1:]
    44  	if len(data) != 18 {
    45  		return -1
    46  	}
    47  	var addr net.Addr
    48  	if usesUDPAddr {
    49  		addr = &net.UDPAddr{
    50  			Port: int(binary.BigEndian.Uint16(data[:2])),
    51  			IP:   net.IP(data[2:]),
    52  		}
    53  	} else {
    54  		addr = &net.TCPAddr{
    55  			Port: int(binary.BigEndian.Uint16(data[:2])),
    56  			IP:   net.IP(data[2:]),
    57  		}
    58  	}
    59  	start := time.Now()
    60  	encrypted, err := tg.NewToken(addr)
    61  	if err != nil {
    62  		panic(err)
    63  	}
    64  	token, err := tg.DecodeToken(encrypted)
    65  	if err != nil {
    66  		panic(err)
    67  	}
    68  	if token.IsRetryToken {
    69  		panic("didn't encode a Retry token")
    70  	}
    71  	if token.SentTime.Before(start) || token.SentTime.After(time.Now()) {
    72  		panic("incorrect send time")
    73  	}
    74  	if token.OriginalDestConnectionID.Len() > 0 || token.RetrySrcConnectionID.Len() > 0 {
    75  		panic("didn't expect connection IDs")
    76  	}
    77  	return 1
    78  }
    79  
    80  func newRetryToken(tg *handshake.TokenGenerator, data []byte) int {
    81  	if len(data) < 2 {
    82  		return -1
    83  	}
    84  	origDestConnIDLen := int(data[0] % 21)
    85  	retrySrcConnIDLen := int(data[1] % 21)
    86  	data = data[2:]
    87  	if len(data) < origDestConnIDLen {
    88  		return -1
    89  	}
    90  	origDestConnID := protocol.ParseConnectionID(data[:origDestConnIDLen])
    91  	data = data[origDestConnIDLen:]
    92  	if len(data) < retrySrcConnIDLen {
    93  		return -1
    94  	}
    95  	retrySrcConnID := protocol.ParseConnectionID(data[:retrySrcConnIDLen])
    96  	data = data[retrySrcConnIDLen:]
    97  
    98  	if len(data) < 1 {
    99  		return -1
   100  	}
   101  	usesUDPAddr := data[0]%2 == 0
   102  	data = data[1:]
   103  	if len(data) != 18 {
   104  		return -1
   105  	}
   106  	start := time.Now()
   107  	var addr net.Addr
   108  	if usesUDPAddr {
   109  		addr = &net.UDPAddr{
   110  			Port: int(binary.BigEndian.Uint16(data[:2])),
   111  			IP:   net.IP(data[2:]),
   112  		}
   113  	} else {
   114  		addr = &net.TCPAddr{
   115  			Port: int(binary.BigEndian.Uint16(data[:2])),
   116  			IP:   net.IP(data[2:]),
   117  		}
   118  	}
   119  	encrypted, err := tg.NewRetryToken(addr, origDestConnID, retrySrcConnID)
   120  	if err != nil {
   121  		panic(err)
   122  	}
   123  	token, err := tg.DecodeToken(encrypted)
   124  	if err != nil {
   125  		panic(err)
   126  	}
   127  	if !token.IsRetryToken {
   128  		panic("expected a Retry token")
   129  	}
   130  	if token.SentTime.Before(start) || token.SentTime.After(time.Now()) {
   131  		panic("incorrect send time")
   132  	}
   133  	if token.OriginalDestConnectionID != origDestConnID {
   134  		panic("orig dest conn ID doesn't match")
   135  	}
   136  	if token.RetrySrcConnectionID != retrySrcConnID {
   137  		panic("retry src conn ID doesn't match")
   138  	}
   139  	return 1
   140  }