mirror of
https://github.com/refraction-networking/utls.git
synced 2025-03-31 10:37:36 +03:00
* 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>
319 lines
7.7 KiB
Go
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
|
|
}
|