utls/u_quic_transport_parameters.go
dependabot[bot] fda1888aa8
build(deps): bump github.com/quic-go/quic-go from 0.40.1 to 0.42.0 (#289)
* build(deps): bump github.com/quic-go/quic-go from 0.40.1 to 0.42.0

Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.40.1 to 0.42.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.40.1...v0.42.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* update: remove dependency of quic-go

We now vendor the quicvarint submodule from quic-go for a minimal dependency tree.

This also updates the minimal Go version requirement to Go 1.21, given uTLS promised to support 2 most recent minor versions of Go.

Signed-off-by: Gaukas Wang <i@gaukas.wang>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Gaukas Wang <i@gaukas.wang>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Gaukas Wang <i@gaukas.wang>
2024-04-03 14:16:55 -06:00

319 lines
7.7 KiB
Go

package tls
import (
"crypto/rand"
"encoding/binary"
"math"
"math/big"
"github.com/refraction-networking/utls/internal/quicvarint"
)
const (
// RFC IDs
max_idle_timeout uint64 = 0x1
max_udp_payload_size uint64 = 0x3
initial_max_data uint64 = 0x4
initial_max_stream_data_bidi_local uint64 = 0x5
initial_max_stream_data_bidi_remote uint64 = 0x6
initial_max_stream_data_uni uint64 = 0x7
initial_max_streams_bidi uint64 = 0x8
initial_max_streams_uni uint64 = 0x9
max_ack_delay uint64 = 0xb
disable_active_migration uint64 = 0xc
active_connection_id_limit uint64 = 0xe
initial_source_connection_id uint64 = 0xf
version_information uint64 = 0x11 // RFC 9368
padding uint64 = 0x15
max_datagram_frame_size uint64 = 0x20 // RFC 9221
grease_quic_bit uint64 = 0x2ab2
// Legacy IDs from draft
version_information_legacy uint64 = 0xff73db // draft-ietf-quic-version-negotiation-13 and early
)
type TransportParameters []TransportParameter
func (tps TransportParameters) Marshal() []byte {
var b []byte
for _, tp := range tps {
b = quicvarint.Append(b, tp.ID())
b = quicvarint.Append(b, uint64(len(tp.Value())))
b = append(b, tp.Value()...)
}
return b
}
// TransportParameter represents a QUIC transport parameter.
//
// Caller will write the following to the wire:
//
// var b []byte
// b = quicvarint.Append(b, ID())
// b = quicvarint.Append(b, len(Value()))
// b = append(b, Value())
//
// Therefore Value() should return the exact bytes to be written to the wire AFTER the length field,
// i.e., the bytes MAY be a Variable Length Integer per RFC depending on the type of the transport
// parameter, but MUST NOT including the length field unless the parameter is defined so.
type TransportParameter interface {
ID() uint64
Value() []byte
}
type GREASETransportParameter struct {
IdOverride uint64 // if set to a valid GREASE ID, use this instead of randomly generated one.
Length uint16 // if len(ValueOverride) == 0, will generate random data of this size.
ValueOverride []byte // if len(ValueOverride) > 0, use this instead of random bytes.
}
const (
GREASE_MAX_MULTIPLIER = (0x3FFFFFFFFFFFFFFF - 27) / 31
)
// IsGREASEID returns true if id is a valid GREASE ID for
// transport parameters.
func (GREASETransportParameter) IsGREASEID(id uint64) bool {
return id >= 27 && (id-27)%31 == 0
}
// GetGREASEID returns a random valid GREASE ID for transport parameters.
func (GREASETransportParameter) GetGREASEID() uint64 {
max := big.NewInt(GREASE_MAX_MULTIPLIER)
randMultiply, err := rand.Int(rand.Reader, max)
if err != nil {
return 27
}
return 27 + randMultiply.Uint64()*31
}
func (g *GREASETransportParameter) ID() uint64 {
if !g.IsGREASEID(g.IdOverride) {
g.IdOverride = g.GetGREASEID()
}
return g.IdOverride
}
func (g *GREASETransportParameter) Value() []byte {
if len(g.ValueOverride) == 0 {
g.ValueOverride = make([]byte, g.Length)
rand.Read(g.ValueOverride)
}
return g.ValueOverride
}
type MaxIdleTimeout uint64 // in milliseconds
func (MaxIdleTimeout) ID() uint64 {
return max_idle_timeout
}
func (m MaxIdleTimeout) Value() []byte {
return quicvarint.Append([]byte{}, uint64(m))
}
type MaxUDPPayloadSize uint64
func (MaxUDPPayloadSize) ID() uint64 {
return max_udp_payload_size
}
func (m MaxUDPPayloadSize) Value() []byte {
return quicvarint.Append([]byte{}, uint64(m))
}
type InitialMaxData uint64
func (InitialMaxData) ID() uint64 {
return initial_max_data
}
func (i InitialMaxData) Value() []byte {
return quicvarint.Append([]byte{}, uint64(i))
}
type InitialMaxStreamDataBidiLocal uint64
func (InitialMaxStreamDataBidiLocal) ID() uint64 {
return initial_max_stream_data_bidi_local
}
func (i InitialMaxStreamDataBidiLocal) Value() []byte {
return quicvarint.Append([]byte{}, uint64(i))
}
type InitialMaxStreamDataBidiRemote uint64
func (InitialMaxStreamDataBidiRemote) ID() uint64 {
return initial_max_stream_data_bidi_remote
}
func (i InitialMaxStreamDataBidiRemote) Value() []byte {
return quicvarint.Append([]byte{}, uint64(i))
}
type InitialMaxStreamDataUni uint64
func (InitialMaxStreamDataUni) ID() uint64 {
return initial_max_stream_data_uni
}
func (i InitialMaxStreamDataUni) Value() []byte {
return quicvarint.Append([]byte{}, uint64(i))
}
type InitialMaxStreamsBidi uint64
func (InitialMaxStreamsBidi) ID() uint64 {
return initial_max_streams_bidi
}
func (i InitialMaxStreamsBidi) Value() []byte {
return quicvarint.Append([]byte{}, uint64(i))
}
type InitialMaxStreamsUni uint64
func (InitialMaxStreamsUni) ID() uint64 {
return initial_max_streams_uni
}
func (i InitialMaxStreamsUni) Value() []byte {
return quicvarint.Append([]byte{}, uint64(i))
}
type MaxAckDelay uint64
func (MaxAckDelay) ID() uint64 {
return max_ack_delay
}
func (m MaxAckDelay) Value() []byte {
return quicvarint.Append([]byte{}, uint64(m))
}
type DisableActiveMigration struct{}
func (*DisableActiveMigration) ID() uint64 {
return disable_active_migration
}
// Its Value MUST ALWAYS be empty.
func (*DisableActiveMigration) Value() []byte {
return []byte{}
}
type ActiveConnectionIDLimit uint64
func (ActiveConnectionIDLimit) ID() uint64 {
return active_connection_id_limit
}
func (a ActiveConnectionIDLimit) Value() []byte {
return quicvarint.Append([]byte{}, uint64(a))
}
type InitialSourceConnectionID []byte // if empty, will be set to the Connection ID used for the Initial packet.
func (InitialSourceConnectionID) ID() uint64 {
return initial_source_connection_id
}
func (i InitialSourceConnectionID) Value() []byte {
return []byte(i)
}
type VersionInformation struct {
ChoosenVersion uint32
AvailableVersions []uint32 // Also known as "Other Versions" in early drafts.
LegacyID bool // If true, use the legacy-assigned ID (0xff73db) instead of the RFC-assigned one (0x11).
}
const (
VERSION_NEGOTIATION uint32 = 0x00000000 // rfc9000
VERSION_1 uint32 = 0x00000001 // rfc9000
VERSION_2 uint32 = 0x6b3343cf // rfc9369
VERSION_GREASE uint32 = 0x0a0a0a0a // -> 0x?a?a?a?a
)
func (v *VersionInformation) ID() uint64 {
if v.LegacyID {
return version_information_legacy
}
return version_information
}
func (v *VersionInformation) Value() []byte {
var b []byte
b = binary.BigEndian.AppendUint32(b, v.ChoosenVersion)
for _, version := range v.AvailableVersions {
if version != VERSION_GREASE {
b = binary.BigEndian.AppendUint32(b, version)
} else {
b = binary.BigEndian.AppendUint32(b, v.GetGREASEVersion())
}
}
return b
}
func (*VersionInformation) GetGREASEVersion() uint32 {
// get a random uint32
max := big.NewInt(math.MaxUint32)
randVal, err := rand.Int(rand.Reader, max)
if err != nil {
return VERSION_GREASE
}
return uint32(randVal.Uint64()&math.MaxUint32) | 0x0a0a0a0a // all GREASE versions are in 0x?a?a?a?a
}
type PaddingTransportParameter []byte
func (PaddingTransportParameter) ID() uint64 {
return padding
}
func (p PaddingTransportParameter) Value() []byte {
return p
}
type MaxDatagramFrameSize uint64
func (MaxDatagramFrameSize) ID() uint64 {
return max_datagram_frame_size
}
func (m MaxDatagramFrameSize) Value() []byte {
return quicvarint.Append([]byte{}, uint64(m))
}
type GREASEQUICBit struct{}
func (*GREASEQUICBit) ID() uint64 {
return grease_quic_bit
}
// Its Value MUST ALWAYS be empty.
func (*GREASEQUICBit) Value() []byte {
return []byte{}
}
type FakeQUICTransportParameter struct {
Id uint64
Val []byte
}
func (f *FakeQUICTransportParameter) ID() uint64 {
if f.Id == 0 {
panic("it is not allowed to use a FakeQUICTransportParameter without setting the ID")
}
return f.Id
}
func (f *FakeQUICTransportParameter) Value() []byte {
return f.Val
}