mirror of
https://github.com/refraction-networking/utls.git
synced 2025-04-01 19:17:36 +03:00
* feat: byte to clienthellospecs conversion * feat: specific case for GREASE and ALPS Will automatically add "h2" to ALPS and write to log when GREASE extension is imported in `ImportTLSClientHello()` * fix: ReadCompressionMethods ReadCompressionMethods didn't advance the s and fails reading extensions * fix: remove debug log * fix: use cryptobyte for internal helper `helper.Uint8to16()` now calls `(*cryptobyte.String).ReadUint16()` * fix: preshared key fingerprinter test updated fingerprinter test to test with PreSharedKey extension * fix: naming of FakePreSharedKeyExt It is a Fake extension since `crypto/tls` doesn't really implement PSK-based resumption and neither do we. * feat: Properly check GREASE Adopted from #148. Co-Authored-By: gfw-report <gfw.report@protonmail.com> * feat: add fakeExtensionEncryptThenMAC And reordered `fakeExtensionDelegatedCredentials`. The new `Fingerprinter` is expected to account for the `fakeExtensionEncryptThenMAC` using a `GenericExtension` when `allowBluntMimicry` is set. Co-Authored-By: gfw-report <gfw.report@protonmail.com> * fix: remove keepPSK and minor - Removed all presence of keepPSK flag. - Added check before using the field of a map. --------- Co-authored-by: gfw-report <gfw.report@protonmail.com>
1586 lines
43 KiB
Go
1586 lines
43 KiB
Go
// Copyright 2017 Google Inc. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package tls
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"strings"
|
|
|
|
"golang.org/x/crypto/cryptobyte"
|
|
)
|
|
|
|
// ExtensionIDToExtension returns a TLSExtension for the given extension ID.
|
|
func ExtensionIDToExtension(id uint16) TLSExtensionWriter {
|
|
// deep copy
|
|
switch id {
|
|
case extensionServerName:
|
|
return &SNIExtension{}
|
|
case extensionStatusRequest:
|
|
return &StatusRequestExtension{}
|
|
case extensionSupportedCurves:
|
|
return &SupportedCurvesExtension{}
|
|
case extensionSupportedPoints:
|
|
return &SupportedPointsExtension{}
|
|
case extensionSignatureAlgorithms:
|
|
return &SignatureAlgorithmsExtension{}
|
|
case extensionALPN:
|
|
return &ALPNExtension{}
|
|
case extensionStatusRequestV2:
|
|
return &StatusRequestV2Extension{}
|
|
case extensionSCT:
|
|
return &SCTExtension{}
|
|
case utlsExtensionPadding:
|
|
return &UtlsPaddingExtension{}
|
|
case utlsExtensionExtendedMasterSecret:
|
|
return &UtlsExtendedMasterSecretExtension{}
|
|
case fakeExtensionTokenBinding:
|
|
return &FakeTokenBindingExtension{}
|
|
case utlsExtensionCompressCertificate:
|
|
return &UtlsCompressCertExtension{}
|
|
case fakeExtensionDelegatedCredentials:
|
|
return &FakeDelegatedCredentialsExtension{}
|
|
case extensionSessionTicket:
|
|
return &SessionTicketExtension{}
|
|
case fakeExtensionPreSharedKey:
|
|
return &FakePreSharedKeyExtension{}
|
|
// case extensionEarlyData:
|
|
// return &EarlyDataExtension{}
|
|
case extensionSupportedVersions:
|
|
return &SupportedVersionsExtension{}
|
|
// case extensionCookie:
|
|
// return &CookieExtension{}
|
|
case extensionPSKModes:
|
|
return &PSKKeyExchangeModesExtension{}
|
|
// case extensionCertificateAuthorities:
|
|
// return &CertificateAuthoritiesExtension{}
|
|
case extensionSignatureAlgorithmsCert:
|
|
return &SignatureAlgorithmsCertExtension{}
|
|
case extensionKeyShare:
|
|
return &KeyShareExtension{}
|
|
case extensionNextProtoNeg:
|
|
return &NPNExtension{}
|
|
case utlsExtensionApplicationSettings:
|
|
return &ApplicationSettingsExtension{}
|
|
case fakeOldExtensionChannelID:
|
|
return &FakeChannelIDExtension{true}
|
|
case fakeExtensionChannelID:
|
|
return &FakeChannelIDExtension{}
|
|
case fakeRecordSizeLimit:
|
|
return &FakeRecordSizeLimitExtension{}
|
|
case extensionRenegotiationInfo:
|
|
return &RenegotiationInfoExtension{}
|
|
default:
|
|
if isGREASEUint16(id) {
|
|
return &UtlsGREASEExtension{}
|
|
}
|
|
return nil // not returning GenericExtension, it should be handled by caller
|
|
}
|
|
}
|
|
|
|
type TLSExtension interface {
|
|
writeToUConn(*UConn) error
|
|
|
|
Len() int // includes header
|
|
|
|
// Read reads up to len(p) bytes into p.
|
|
// It returns the number of bytes read (0 <= n <= len(p)) and any error encountered.
|
|
Read(p []byte) (n int, err error) // implements io.Reader
|
|
}
|
|
|
|
// TLSExtensionWriter is an interface allowing a TLS extension to be
|
|
// auto-constucted/recovered by reading in a byte stream.
|
|
type TLSExtensionWriter interface {
|
|
TLSExtension
|
|
|
|
// Write writes up to len(b) bytes from b.
|
|
// It returns the number of bytes written (0 <= n <= len(b)) and any error encountered.
|
|
Write(b []byte) (n int, err error)
|
|
}
|
|
|
|
type NPNExtension struct {
|
|
NextProtos []string
|
|
}
|
|
|
|
func (e *NPNExtension) writeToUConn(uc *UConn) error {
|
|
uc.config.NextProtos = e.NextProtos
|
|
uc.HandshakeState.Hello.NextProtoNeg = true
|
|
return nil
|
|
}
|
|
|
|
func (e *NPNExtension) Len() int {
|
|
return 4
|
|
}
|
|
|
|
func (e *NPNExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
b[0] = byte(extensionNextProtoNeg >> 8)
|
|
b[1] = byte(extensionNextProtoNeg & 0xff)
|
|
// The length is always 0
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
// Write is a no-op for NPNExtension. NextProtos are not included in the
|
|
// ClientHello.
|
|
func (e *NPNExtension) Write(_ []byte) (int, error) {
|
|
return 0, nil
|
|
}
|
|
|
|
type SNIExtension struct {
|
|
ServerName string // not an array because go crypto/tls doesn't support multiple SNIs
|
|
}
|
|
|
|
func (e *SNIExtension) writeToUConn(uc *UConn) error {
|
|
uc.config.ServerName = e.ServerName
|
|
hostName := hostnameInSNI(e.ServerName)
|
|
uc.HandshakeState.Hello.ServerName = hostName
|
|
|
|
return nil
|
|
}
|
|
|
|
func (e *SNIExtension) Len() int {
|
|
// Literal IP addresses, absolute FQDNs, and empty strings are not permitted as SNI values.
|
|
// See RFC 6066, Section 3.
|
|
hostName := hostnameInSNI(e.ServerName)
|
|
if len(hostName) == 0 {
|
|
return 0
|
|
}
|
|
return 4 + 2 + 1 + 2 + len(hostName)
|
|
}
|
|
|
|
func (e *SNIExtension) Read(b []byte) (int, error) {
|
|
// Literal IP addresses, absolute FQDNs, and empty strings are not permitted as SNI values.
|
|
// See RFC 6066, Section 3.
|
|
hostName := hostnameInSNI(e.ServerName)
|
|
if len(hostName) == 0 {
|
|
return 0, io.EOF
|
|
}
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// RFC 3546, section 3.1
|
|
b[0] = byte(extensionServerName >> 8)
|
|
b[1] = byte(extensionServerName)
|
|
b[2] = byte((len(hostName) + 5) >> 8)
|
|
b[3] = byte(len(hostName) + 5)
|
|
b[4] = byte((len(hostName) + 3) >> 8)
|
|
b[5] = byte(len(hostName) + 3)
|
|
// b[6] Server Name Type: host_name (0)
|
|
b[7] = byte(len(hostName) >> 8)
|
|
b[8] = byte(len(hostName))
|
|
copy(b[9:], []byte(hostName))
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
// Write is a no-op for StatusRequestExtension.
|
|
// SNI should not be fingerprinted and is user controlled.
|
|
func (e *SNIExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
// RFC 6066, Section 3
|
|
var nameList cryptobyte.String
|
|
if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() {
|
|
return fullLen, errors.New("unable to read server name extension data")
|
|
}
|
|
var serverName string
|
|
for !nameList.Empty() {
|
|
var nameType uint8
|
|
var serverNameBytes cryptobyte.String
|
|
if !nameList.ReadUint8(&nameType) ||
|
|
!nameList.ReadUint16LengthPrefixed(&serverNameBytes) ||
|
|
serverNameBytes.Empty() {
|
|
return fullLen, errors.New("unable to read server name extension data")
|
|
}
|
|
if nameType != 0 {
|
|
continue
|
|
}
|
|
if len(serverName) != 0 {
|
|
return fullLen, errors.New("multiple names of the same name_type in server name extension are prohibited")
|
|
}
|
|
serverName = string(serverNameBytes)
|
|
if strings.HasSuffix(serverName, ".") {
|
|
return fullLen, errors.New("SNI value may not include a trailing dot")
|
|
}
|
|
}
|
|
// clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &SNIExtension{}) // gaukas moved this line out from the loop.
|
|
|
|
// don't copy SNI from ClientHello to ClientHelloSpec!
|
|
return fullLen, nil
|
|
}
|
|
|
|
type StatusRequestExtension struct {
|
|
}
|
|
|
|
func (e *StatusRequestExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.OcspStapling = true
|
|
return nil
|
|
}
|
|
|
|
func (e *StatusRequestExtension) Len() int {
|
|
return 9
|
|
}
|
|
|
|
func (e *StatusRequestExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// RFC 4366, section 3.6
|
|
b[0] = byte(extensionStatusRequest >> 8)
|
|
b[1] = byte(extensionStatusRequest)
|
|
b[2] = 0
|
|
b[3] = 5
|
|
b[4] = 1 // OCSP type
|
|
// Two zero valued uint16s for the two lengths.
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
// Write is a no-op for StatusRequestExtension. No data for this extension.
|
|
func (e *StatusRequestExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
// RFC 4366, Section 3.6
|
|
var statusType uint8
|
|
var ignored cryptobyte.String
|
|
if !extData.ReadUint8(&statusType) ||
|
|
!extData.ReadUint16LengthPrefixed(&ignored) ||
|
|
!extData.ReadUint16LengthPrefixed(&ignored) {
|
|
return fullLen, errors.New("unable to read status request extension data")
|
|
}
|
|
|
|
if statusType != statusTypeOCSP {
|
|
return fullLen, errors.New("status request extension statusType is not statusTypeOCSP(1)")
|
|
}
|
|
|
|
return fullLen, nil
|
|
}
|
|
|
|
type StatusRequestV2Extension struct {
|
|
}
|
|
|
|
func (e *StatusRequestV2Extension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.OcspStapling = true
|
|
return nil
|
|
}
|
|
|
|
func (e *StatusRequestV2Extension) Len() int {
|
|
return 13
|
|
}
|
|
|
|
func (e *StatusRequestV2Extension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// RFC 4366, section 3.6
|
|
b[0] = byte(extensionStatusRequestV2 >> 8)
|
|
b[1] = byte(extensionStatusRequestV2)
|
|
b[2] = 0
|
|
b[3] = 9
|
|
b[4] = 0
|
|
b[5] = 7
|
|
b[6] = 2 // OCSP type
|
|
b[7] = 0
|
|
b[8] = 4
|
|
// Two zero valued uint16s for the two lengths.
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
// Write is a no-op for StatusRequestV2Extension. No data for this extension.
|
|
func (e *StatusRequestV2Extension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
// RFC 4366, Section 3.6
|
|
var statusType uint8
|
|
var ignored cryptobyte.String
|
|
if !extData.ReadUint16LengthPrefixed(&ignored) ||
|
|
!extData.ReadUint8(&statusType) ||
|
|
!extData.ReadUint16LengthPrefixed(&ignored) ||
|
|
!extData.ReadUint16LengthPrefixed(&ignored) ||
|
|
!extData.ReadUint16LengthPrefixed(&ignored) {
|
|
return fullLen, errors.New("unable to read status request v2 extension data")
|
|
}
|
|
|
|
if statusType != statusV2TypeOCSP {
|
|
return fullLen, errors.New("status request v2 extension statusType is not statusV2TypeOCSP(2)")
|
|
}
|
|
|
|
return fullLen, nil
|
|
}
|
|
|
|
type SupportedCurvesExtension struct {
|
|
Curves []CurveID
|
|
}
|
|
|
|
func (e *SupportedCurvesExtension) writeToUConn(uc *UConn) error {
|
|
uc.config.CurvePreferences = e.Curves
|
|
uc.HandshakeState.Hello.SupportedCurves = e.Curves
|
|
return nil
|
|
}
|
|
|
|
func (e *SupportedCurvesExtension) Len() int {
|
|
return 6 + 2*len(e.Curves)
|
|
}
|
|
|
|
func (e *SupportedCurvesExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// http://tools.ietf.org/html/rfc4492#section-5.5.1
|
|
b[0] = byte(extensionSupportedCurves >> 8)
|
|
b[1] = byte(extensionSupportedCurves)
|
|
b[2] = byte((2 + 2*len(e.Curves)) >> 8)
|
|
b[3] = byte(2 + 2*len(e.Curves))
|
|
b[4] = byte((2 * len(e.Curves)) >> 8)
|
|
b[5] = byte(2 * len(e.Curves))
|
|
for i, curve := range e.Curves {
|
|
b[6+2*i] = byte(curve >> 8)
|
|
b[7+2*i] = byte(curve)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *SupportedCurvesExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
|
|
var curvesBytes cryptobyte.String
|
|
if !extData.ReadUint16LengthPrefixed(&curvesBytes) || curvesBytes.Empty() {
|
|
return 0, errors.New("unable to read supported curves extension data")
|
|
}
|
|
curves := []CurveID{}
|
|
for !curvesBytes.Empty() {
|
|
var curve uint16
|
|
if !curvesBytes.ReadUint16(&curve) {
|
|
return 0, errors.New("unable to read supported curves extension data")
|
|
}
|
|
curves = append(curves, CurveID(unGREASEUint16(curve)))
|
|
}
|
|
e.Curves = curves
|
|
return fullLen, nil
|
|
}
|
|
|
|
type SupportedPointsExtension struct {
|
|
SupportedPoints []uint8
|
|
}
|
|
|
|
func (e *SupportedPointsExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.SupportedPoints = e.SupportedPoints
|
|
return nil
|
|
}
|
|
|
|
func (e *SupportedPointsExtension) Len() int {
|
|
return 5 + len(e.SupportedPoints)
|
|
}
|
|
|
|
func (e *SupportedPointsExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// http://tools.ietf.org/html/rfc4492#section-5.5.2
|
|
b[0] = byte(extensionSupportedPoints >> 8)
|
|
b[1] = byte(extensionSupportedPoints)
|
|
b[2] = byte((1 + len(e.SupportedPoints)) >> 8)
|
|
b[3] = byte(1 + len(e.SupportedPoints))
|
|
b[4] = byte(len(e.SupportedPoints))
|
|
for i, pointFormat := range e.SupportedPoints {
|
|
b[5+i] = pointFormat
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *SupportedPointsExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
// RFC 4492, Section 5.1.2
|
|
supportedPoints := []uint8{}
|
|
if !readUint8LengthPrefixed(&extData, &supportedPoints) ||
|
|
len(supportedPoints) == 0 {
|
|
return 0, errors.New("unable to read supported points extension data")
|
|
}
|
|
e.SupportedPoints = supportedPoints
|
|
return fullLen, nil
|
|
}
|
|
|
|
type SignatureAlgorithmsExtension struct {
|
|
SupportedSignatureAlgorithms []SignatureScheme
|
|
}
|
|
|
|
func (e *SignatureAlgorithmsExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.SupportedSignatureAlgorithms = e.SupportedSignatureAlgorithms
|
|
return nil
|
|
}
|
|
|
|
func (e *SignatureAlgorithmsExtension) Len() int {
|
|
return 6 + 2*len(e.SupportedSignatureAlgorithms)
|
|
}
|
|
|
|
func (e *SignatureAlgorithmsExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
|
|
b[0] = byte(extensionSignatureAlgorithms >> 8)
|
|
b[1] = byte(extensionSignatureAlgorithms)
|
|
b[2] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)) >> 8)
|
|
b[3] = byte(2 + 2*len(e.SupportedSignatureAlgorithms))
|
|
b[4] = byte((2 * len(e.SupportedSignatureAlgorithms)) >> 8)
|
|
b[5] = byte(2 * len(e.SupportedSignatureAlgorithms))
|
|
for i, sigAndHash := range e.SupportedSignatureAlgorithms {
|
|
b[6+2*i] = byte(sigAndHash >> 8)
|
|
b[7+2*i] = byte(sigAndHash)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *SignatureAlgorithmsExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
// RFC 5246, Section 7.4.1.4.1
|
|
var sigAndAlgs cryptobyte.String
|
|
if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
|
|
return 0, errors.New("unable to read signature algorithms extension data")
|
|
}
|
|
supportedSignatureAlgorithms := []SignatureScheme{}
|
|
for !sigAndAlgs.Empty() {
|
|
var sigAndAlg uint16
|
|
if !sigAndAlgs.ReadUint16(&sigAndAlg) {
|
|
return 0, errors.New("unable to read signature algorithms extension data")
|
|
}
|
|
supportedSignatureAlgorithms = append(
|
|
supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
|
|
}
|
|
e.SupportedSignatureAlgorithms = supportedSignatureAlgorithms
|
|
return fullLen, nil
|
|
}
|
|
|
|
type SignatureAlgorithmsCertExtension struct {
|
|
SupportedSignatureAlgorithms []SignatureScheme
|
|
}
|
|
|
|
func (e *SignatureAlgorithmsCertExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.SupportedSignatureAlgorithms = e.SupportedSignatureAlgorithms
|
|
return nil
|
|
}
|
|
|
|
func (e *SignatureAlgorithmsCertExtension) Len() int {
|
|
return 6 + 2*len(e.SupportedSignatureAlgorithms)
|
|
}
|
|
|
|
func (e *SignatureAlgorithmsCertExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
|
|
b[0] = byte(extensionSignatureAlgorithmsCert >> 8)
|
|
b[1] = byte(extensionSignatureAlgorithmsCert)
|
|
b[2] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)) >> 8)
|
|
b[3] = byte(2 + 2*len(e.SupportedSignatureAlgorithms))
|
|
b[4] = byte((2 * len(e.SupportedSignatureAlgorithms)) >> 8)
|
|
b[5] = byte(2 * len(e.SupportedSignatureAlgorithms))
|
|
for i, sigAndHash := range e.SupportedSignatureAlgorithms {
|
|
b[6+2*i] = byte(sigAndHash >> 8)
|
|
b[7+2*i] = byte(sigAndHash)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
// Write implementation copied from SignatureAlgorithmsExtension.Write
|
|
//
|
|
// Warning: not tested.
|
|
func (e *SignatureAlgorithmsCertExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
// RFC 8446, Section 4.2.3
|
|
var sigAndAlgs cryptobyte.String
|
|
if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
|
|
return 0, errors.New("unable to read signature algorithms extension data")
|
|
}
|
|
supportedSignatureAlgorithms := []SignatureScheme{}
|
|
for !sigAndAlgs.Empty() {
|
|
var sigAndAlg uint16
|
|
if !sigAndAlgs.ReadUint16(&sigAndAlg) {
|
|
return 0, errors.New("unable to read signature algorithms extension data")
|
|
}
|
|
supportedSignatureAlgorithms = append(
|
|
supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
|
|
}
|
|
e.SupportedSignatureAlgorithms = supportedSignatureAlgorithms
|
|
return fullLen, nil
|
|
}
|
|
|
|
type RenegotiationInfoExtension struct {
|
|
// Renegotiation field limits how many times client will perform renegotiation: no limit, once, or never.
|
|
// The extension still will be sent, even if Renegotiation is set to RenegotiateNever.
|
|
Renegotiation RenegotiationSupport
|
|
}
|
|
|
|
func (e *RenegotiationInfoExtension) writeToUConn(uc *UConn) error {
|
|
uc.config.Renegotiation = e.Renegotiation
|
|
switch e.Renegotiation {
|
|
case RenegotiateOnceAsClient:
|
|
fallthrough
|
|
case RenegotiateFreelyAsClient:
|
|
uc.HandshakeState.Hello.SecureRenegotiationSupported = true
|
|
case RenegotiateNever:
|
|
default:
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e *RenegotiationInfoExtension) Len() int {
|
|
return 5
|
|
}
|
|
|
|
func (e *RenegotiationInfoExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
var extInnerBody []byte // inner body is empty
|
|
innerBodyLen := len(extInnerBody)
|
|
extBodyLen := innerBodyLen + 1
|
|
|
|
b[0] = byte(extensionRenegotiationInfo >> 8)
|
|
b[1] = byte(extensionRenegotiationInfo & 0xff)
|
|
b[2] = byte(extBodyLen >> 8)
|
|
b[3] = byte(extBodyLen)
|
|
b[4] = byte(innerBodyLen)
|
|
copy(b[5:], extInnerBody)
|
|
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *RenegotiationInfoExtension) Write(_ []byte) (int, error) {
|
|
e.Renegotiation = RenegotiateOnceAsClient
|
|
return 0, nil
|
|
}
|
|
|
|
type ALPNExtension struct {
|
|
AlpnProtocols []string
|
|
}
|
|
|
|
func (e *ALPNExtension) writeToUConn(uc *UConn) error {
|
|
uc.config.NextProtos = e.AlpnProtocols
|
|
uc.HandshakeState.Hello.AlpnProtocols = e.AlpnProtocols
|
|
return nil
|
|
}
|
|
|
|
func (e *ALPNExtension) Len() int {
|
|
bLen := 2 + 2 + 2
|
|
for _, s := range e.AlpnProtocols {
|
|
bLen += 1 + len(s)
|
|
}
|
|
return bLen
|
|
}
|
|
|
|
func (e *ALPNExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
b[0] = byte(extensionALPN >> 8)
|
|
b[1] = byte(extensionALPN & 0xff)
|
|
lengths := b[2:]
|
|
b = b[6:]
|
|
|
|
stringsLength := 0
|
|
for _, s := range e.AlpnProtocols {
|
|
l := len(s)
|
|
b[0] = byte(l)
|
|
copy(b[1:], s)
|
|
b = b[1+l:]
|
|
stringsLength += 1 + l
|
|
}
|
|
|
|
lengths[2] = byte(stringsLength >> 8)
|
|
lengths[3] = byte(stringsLength)
|
|
stringsLength += 2
|
|
lengths[0] = byte(stringsLength >> 8)
|
|
lengths[1] = byte(stringsLength)
|
|
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *ALPNExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
// RFC 7301, Section 3.1
|
|
var protoList cryptobyte.String
|
|
if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
|
|
return 0, errors.New("unable to read ALPN extension data")
|
|
}
|
|
alpnProtocols := []string{}
|
|
for !protoList.Empty() {
|
|
var proto cryptobyte.String
|
|
if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() {
|
|
return 0, errors.New("unable to read ALPN extension data")
|
|
}
|
|
alpnProtocols = append(alpnProtocols, string(proto))
|
|
|
|
}
|
|
e.AlpnProtocols = alpnProtocols
|
|
return fullLen, nil
|
|
}
|
|
|
|
// ApplicationSettingsExtension represents the TLS ALPS extension.
|
|
// At the time of this writing, this extension is currently a draft:
|
|
// https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps-01
|
|
type ApplicationSettingsExtension struct {
|
|
SupportedProtocols []string
|
|
}
|
|
|
|
func (e *ApplicationSettingsExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
func (e *ApplicationSettingsExtension) Len() int {
|
|
bLen := 2 + 2 + 2 // Type + Length + ALPS Extension length
|
|
for _, s := range e.SupportedProtocols {
|
|
bLen += 1 + len(s) // Supported ALPN Length + actual length of protocol
|
|
}
|
|
return bLen
|
|
}
|
|
|
|
func (e *ApplicationSettingsExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
// Read Type.
|
|
b[0] = byte(utlsExtensionApplicationSettings >> 8) // hex: 44 dec: 68
|
|
b[1] = byte(utlsExtensionApplicationSettings & 0xff) // hex: 69 dec: 105
|
|
|
|
lengths := b[2:] // get the remaining buffer without Type
|
|
b = b[6:] // set the buffer to the buffer without Type, Length and ALPS Extension Length (so only the Supported ALPN list remains)
|
|
|
|
stringsLength := 0
|
|
for _, s := range e.SupportedProtocols {
|
|
l := len(s) // Supported ALPN Length
|
|
b[0] = byte(l) // Supported ALPN Length in bytes hex: 02 dec: 2
|
|
copy(b[1:], s) // copy the Supported ALPN as bytes to the buffer
|
|
b = b[1+l:] // set the buffer to the buffer without the Supported ALPN Length and Supported ALPN (so we can continue to the next protocol in this loop)
|
|
stringsLength += 1 + l // Supported ALPN Length (the field itself) + Supported ALPN Length (the value)
|
|
}
|
|
|
|
lengths[2] = byte(stringsLength >> 8) // ALPS Extension Length hex: 00 dec: 0
|
|
lengths[3] = byte(stringsLength) // ALPS Extension Length hex: 03 dec: 3
|
|
stringsLength += 2 // plus ALPS Extension Length field length
|
|
lengths[0] = byte(stringsLength >> 8) // Length hex:00 dec: 0
|
|
lengths[1] = byte(stringsLength) // Length hex: 05 dec: 5
|
|
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
// Write implementation copied from ALPNExtension.Write
|
|
func (e *ApplicationSettingsExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
// https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps-01
|
|
var protoList cryptobyte.String
|
|
if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
|
|
return 0, errors.New("unable to read ALPN extension data")
|
|
}
|
|
alpnProtocols := []string{}
|
|
for !protoList.Empty() {
|
|
var proto cryptobyte.String
|
|
if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() {
|
|
return 0, errors.New("unable to read ALPN extension data")
|
|
}
|
|
alpnProtocols = append(alpnProtocols, string(proto))
|
|
|
|
}
|
|
e.SupportedProtocols = alpnProtocols
|
|
return fullLen, nil
|
|
}
|
|
|
|
type SCTExtension struct {
|
|
}
|
|
|
|
func (e *SCTExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.Scts = true
|
|
return nil
|
|
}
|
|
|
|
func (e *SCTExtension) Len() int {
|
|
return 4
|
|
}
|
|
|
|
func (e *SCTExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// https://tools.ietf.org/html/rfc6962#section-3.3.1
|
|
b[0] = byte(extensionSCT >> 8)
|
|
b[1] = byte(extensionSCT)
|
|
// zero uint16 for the zero-length extension_data
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *SCTExtension) Write(_ []byte) (int, error) {
|
|
return 0, nil
|
|
}
|
|
|
|
type SessionTicketExtension struct {
|
|
Session *ClientSessionState
|
|
}
|
|
|
|
func (e *SessionTicketExtension) writeToUConn(uc *UConn) error {
|
|
if e.Session != nil {
|
|
uc.HandshakeState.Session = e.Session
|
|
uc.HandshakeState.Hello.SessionTicket = e.Session.sessionTicket
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e *SessionTicketExtension) Len() int {
|
|
if e.Session != nil {
|
|
return 4 + len(e.Session.sessionTicket)
|
|
}
|
|
return 4
|
|
}
|
|
|
|
func (e *SessionTicketExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
extBodyLen := e.Len() - 4
|
|
|
|
b[0] = byte(extensionSessionTicket >> 8)
|
|
b[1] = byte(extensionSessionTicket)
|
|
b[2] = byte(extBodyLen >> 8)
|
|
b[3] = byte(extBodyLen)
|
|
if extBodyLen > 0 {
|
|
copy(b[4:], e.Session.sessionTicket)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *SessionTicketExtension) Write(_ []byte) (int, error) {
|
|
// RFC 5077, Section 3.2
|
|
return 0, nil
|
|
}
|
|
|
|
// GenericExtension allows to include in ClientHello arbitrary unsupported extensions.
|
|
type GenericExtension struct {
|
|
Id uint16
|
|
Data []byte
|
|
}
|
|
|
|
func (e *GenericExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
func (e *GenericExtension) Len() int {
|
|
return 4 + len(e.Data)
|
|
}
|
|
|
|
func (e *GenericExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
b[0] = byte(e.Id >> 8)
|
|
b[1] = byte(e.Id)
|
|
b[2] = byte(len(e.Data) >> 8)
|
|
b[3] = byte(len(e.Data))
|
|
if len(e.Data) > 0 {
|
|
copy(b[4:], e.Data)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
type UtlsExtendedMasterSecretExtension struct {
|
|
}
|
|
|
|
// TODO: update when this extension is implemented in crypto/tls
|
|
// but we probably won't have to enable it in Config
|
|
func (e *UtlsExtendedMasterSecretExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.Ems = true
|
|
return nil
|
|
}
|
|
|
|
func (e *UtlsExtendedMasterSecretExtension) Len() int {
|
|
return 4
|
|
}
|
|
|
|
func (e *UtlsExtendedMasterSecretExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// https://tools.ietf.org/html/rfc7627
|
|
b[0] = byte(utlsExtensionExtendedMasterSecret >> 8)
|
|
b[1] = byte(utlsExtensionExtendedMasterSecret)
|
|
// The length is 0
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *UtlsExtendedMasterSecretExtension) Write(_ []byte) (int, error) {
|
|
// https://tools.ietf.org/html/rfc7627
|
|
return 0, nil
|
|
}
|
|
|
|
var extendedMasterSecretLabel = []byte("extended master secret")
|
|
|
|
// extendedMasterFromPreMasterSecret generates the master secret from the pre-master
|
|
// secret and session hash. See https://tools.ietf.org/html/rfc7627#section-4
|
|
func extendedMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret []byte, sessionHash []byte) []byte {
|
|
masterSecret := make([]byte, masterSecretLength)
|
|
prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, sessionHash)
|
|
return masterSecret
|
|
}
|
|
|
|
// GREASE stinks with dead parrots, have to be super careful, and, if possible, not include GREASE
|
|
// https://github.com/google/boringssl/blob/1c68fa2350936ca5897a66b430ebaf333a0e43f5/ssl/internal.h
|
|
const (
|
|
ssl_grease_cipher = iota
|
|
ssl_grease_group
|
|
ssl_grease_extension1
|
|
ssl_grease_extension2
|
|
ssl_grease_version
|
|
ssl_grease_ticket_extension
|
|
ssl_grease_last_index = ssl_grease_ticket_extension
|
|
)
|
|
|
|
// it is responsibility of user not to generate multiple grease extensions with same value
|
|
type UtlsGREASEExtension struct {
|
|
Value uint16
|
|
Body []byte // in Chrome first grease has empty body, second grease has a single zero byte
|
|
}
|
|
|
|
func (e *UtlsGREASEExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
// will panic if ssl_grease_last_index[index] is out of bounds.
|
|
func GetBoringGREASEValue(greaseSeed [ssl_grease_last_index]uint16, index int) uint16 {
|
|
// GREASE value is back from deterministic to random.
|
|
// https://github.com/google/boringssl/blob/a365138ac60f38b64bfc608b493e0f879845cb88/ssl/handshake_client.c#L530
|
|
ret := uint16(greaseSeed[index])
|
|
/* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */
|
|
ret = (ret & 0xf0) | 0x0a
|
|
ret |= ret << 8
|
|
return ret
|
|
}
|
|
|
|
func (e *UtlsGREASEExtension) Len() int {
|
|
return 4 + len(e.Body)
|
|
}
|
|
|
|
func (e *UtlsGREASEExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
b[0] = byte(e.Value >> 8)
|
|
b[1] = byte(e.Value)
|
|
b[2] = byte(len(e.Body) >> 8)
|
|
b[3] = byte(len(e.Body))
|
|
if len(e.Body) > 0 {
|
|
copy(b[4:], e.Body)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *UtlsGREASEExtension) Write(b []byte) (int, error) {
|
|
e.Value = GREASE_PLACEHOLDER
|
|
e.Body = make([]byte, len(b))
|
|
n := copy(e.Body, b)
|
|
return n, nil
|
|
}
|
|
|
|
type UtlsPaddingExtension struct {
|
|
PaddingLen int
|
|
WillPad bool // set to false to disable extension
|
|
|
|
// Functor for deciding on padding length based on unpadded ClientHello length.
|
|
// If willPad is false, then this extension should not be included.
|
|
GetPaddingLen func(clientHelloUnpaddedLen int) (paddingLen int, willPad bool)
|
|
}
|
|
|
|
func (e *UtlsPaddingExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
func (e *UtlsPaddingExtension) Len() int {
|
|
if e.WillPad {
|
|
return 4 + e.PaddingLen
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func (e *UtlsPaddingExtension) Update(clientHelloUnpaddedLen int) {
|
|
if e.GetPaddingLen != nil {
|
|
e.PaddingLen, e.WillPad = e.GetPaddingLen(clientHelloUnpaddedLen)
|
|
}
|
|
}
|
|
|
|
func (e *UtlsPaddingExtension) Read(b []byte) (int, error) {
|
|
if !e.WillPad {
|
|
return 0, io.EOF
|
|
}
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// https://tools.ietf.org/html/rfc7627
|
|
b[0] = byte(utlsExtensionPadding >> 8)
|
|
b[1] = byte(utlsExtensionPadding)
|
|
b[2] = byte(e.PaddingLen >> 8)
|
|
b[3] = byte(e.PaddingLen)
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *UtlsPaddingExtension) Write(_ []byte) (int, error) {
|
|
e.GetPaddingLen = BoringPaddingStyle
|
|
return 0, nil
|
|
}
|
|
|
|
// https://github.com/google/boringssl/blob/7d7554b6b3c79e707e25521e61e066ce2b996e4c/ssl/t1_lib.c#L2803
|
|
func BoringPaddingStyle(unpaddedLen int) (int, bool) {
|
|
if unpaddedLen > 0xff && unpaddedLen < 0x200 {
|
|
paddingLen := 0x200 - unpaddedLen
|
|
if paddingLen >= 4+1 {
|
|
paddingLen -= 4
|
|
} else {
|
|
paddingLen = 1
|
|
}
|
|
return paddingLen, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// UtlsCompressCertExtension is only implemented client-side, for server certificates. Alternate
|
|
// certificate message formats (https://datatracker.ietf.org/doc/html/rfc7250) are not supported.
|
|
//
|
|
// See https://datatracker.ietf.org/doc/html/rfc8879#section-3
|
|
type UtlsCompressCertExtension struct {
|
|
Algorithms []CertCompressionAlgo
|
|
}
|
|
|
|
func (e *UtlsCompressCertExtension) writeToUConn(uc *UConn) error {
|
|
uc.certCompressionAlgs = e.Algorithms
|
|
return nil
|
|
}
|
|
|
|
func (e *UtlsCompressCertExtension) Len() int {
|
|
return 4 + 1 + (2 * len(e.Algorithms))
|
|
}
|
|
|
|
func (e *UtlsCompressCertExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
b[0] = byte(utlsExtensionCompressCertificate >> 8)
|
|
b[1] = byte(utlsExtensionCompressCertificate & 0xff)
|
|
|
|
extLen := 2 * len(e.Algorithms)
|
|
if extLen > 255 {
|
|
return 0, errors.New("too many certificate compression methods")
|
|
}
|
|
|
|
// Extension data length.
|
|
b[2] = byte((extLen + 1) >> 8)
|
|
b[3] = byte((extLen + 1) & 0xff)
|
|
|
|
// Methods length.
|
|
b[4] = byte(extLen)
|
|
|
|
i := 5
|
|
for _, compMethod := range e.Algorithms {
|
|
b[i] = byte(compMethod >> 8)
|
|
b[i+1] = byte(compMethod)
|
|
i += 2
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *UtlsCompressCertExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
methods := []CertCompressionAlgo{}
|
|
methodsRaw := new(cryptobyte.String)
|
|
if !extData.ReadUint8LengthPrefixed(methodsRaw) {
|
|
return 0, errors.New("unable to read cert compression algorithms extension data")
|
|
}
|
|
for !methodsRaw.Empty() {
|
|
var method uint16
|
|
if !methodsRaw.ReadUint16(&method) {
|
|
return 0, errors.New("unable to read cert compression algorithms extension data")
|
|
}
|
|
methods = append(methods, CertCompressionAlgo(method))
|
|
}
|
|
|
|
e.Algorithms = methods
|
|
return fullLen, nil
|
|
}
|
|
|
|
/* TLS 1.3 */
|
|
type KeyShareExtension struct {
|
|
KeyShares []KeyShare
|
|
}
|
|
|
|
func (e *KeyShareExtension) Len() int {
|
|
return 4 + 2 + e.keySharesLen()
|
|
}
|
|
|
|
func (e *KeyShareExtension) keySharesLen() int {
|
|
extLen := 0
|
|
for _, ks := range e.KeyShares {
|
|
extLen += 4 + len(ks.Data)
|
|
}
|
|
return extLen
|
|
}
|
|
|
|
func (e *KeyShareExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
b[0] = byte(extensionKeyShare >> 8)
|
|
b[1] = byte(extensionKeyShare)
|
|
keySharesLen := e.keySharesLen()
|
|
b[2] = byte((keySharesLen + 2) >> 8)
|
|
b[3] = byte(keySharesLen + 2)
|
|
b[4] = byte((keySharesLen) >> 8)
|
|
b[5] = byte(keySharesLen)
|
|
|
|
i := 6
|
|
for _, ks := range e.KeyShares {
|
|
b[i] = byte(ks.Group >> 8)
|
|
b[i+1] = byte(ks.Group)
|
|
b[i+2] = byte(len(ks.Data) >> 8)
|
|
b[i+3] = byte(len(ks.Data))
|
|
copy(b[i+4:], ks.Data)
|
|
i += 4 + len(ks.Data)
|
|
}
|
|
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *KeyShareExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
// RFC 8446, Section 4.2.8
|
|
var clientShares cryptobyte.String
|
|
if !extData.ReadUint16LengthPrefixed(&clientShares) {
|
|
return 0, errors.New("unable to read key share extension data")
|
|
}
|
|
keyShares := []KeyShare{}
|
|
for !clientShares.Empty() {
|
|
var ks KeyShare
|
|
var group uint16
|
|
if !clientShares.ReadUint16(&group) ||
|
|
!readUint16LengthPrefixed(&clientShares, &ks.Data) ||
|
|
len(ks.Data) == 0 {
|
|
return 0, errors.New("unable to read key share extension data")
|
|
}
|
|
ks.Group = CurveID(unGREASEUint16(group))
|
|
// if not GREASE, key share data will be discarded as it should
|
|
// be generated per connection
|
|
if ks.Group != GREASE_PLACEHOLDER {
|
|
ks.Data = nil
|
|
}
|
|
keyShares = append(keyShares, ks)
|
|
}
|
|
e.KeyShares = keyShares
|
|
return fullLen, nil
|
|
}
|
|
|
|
func (e *KeyShareExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.KeyShares = e.KeyShares
|
|
return nil
|
|
}
|
|
|
|
type PSKKeyExchangeModesExtension struct {
|
|
Modes []uint8
|
|
}
|
|
|
|
func (e *PSKKeyExchangeModesExtension) Len() int {
|
|
return 4 + 1 + len(e.Modes)
|
|
}
|
|
|
|
func (e *PSKKeyExchangeModesExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
if len(e.Modes) > 255 {
|
|
return 0, errors.New("too many PSK Key Exchange modes")
|
|
}
|
|
|
|
b[0] = byte(extensionPSKModes >> 8)
|
|
b[1] = byte(extensionPSKModes)
|
|
|
|
modesLen := len(e.Modes)
|
|
b[2] = byte((modesLen + 1) >> 8)
|
|
b[3] = byte(modesLen + 1)
|
|
b[4] = byte(modesLen)
|
|
|
|
if len(e.Modes) > 0 {
|
|
copy(b[5:], e.Modes)
|
|
}
|
|
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *PSKKeyExchangeModesExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
// RFC 8446, Section 4.2.9
|
|
// TODO: PSK Modes have their own form of GREASE-ing which is not currently implemented
|
|
// the current functionality will NOT re-GREASE/re-randomize these values when using a fingerprinted spec
|
|
// https://github.com/refraction-networking/utls/pull/58#discussion_r522354105
|
|
// https://tools.ietf.org/html/draft-ietf-tls-grease-01#section-2
|
|
pskModes := []uint8{}
|
|
if !readUint8LengthPrefixed(&extData, &pskModes) {
|
|
return 0, errors.New("unable to read PSK extension data")
|
|
}
|
|
e.Modes = pskModes
|
|
return fullLen, nil
|
|
}
|
|
|
|
func (e *PSKKeyExchangeModesExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.PskModes = e.Modes
|
|
return nil
|
|
}
|
|
|
|
type SupportedVersionsExtension struct {
|
|
Versions []uint16
|
|
}
|
|
|
|
func (e *SupportedVersionsExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.SupportedVersions = e.Versions
|
|
return nil
|
|
}
|
|
|
|
func (e *SupportedVersionsExtension) Len() int {
|
|
return 4 + 1 + (2 * len(e.Versions))
|
|
}
|
|
|
|
func (e *SupportedVersionsExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
extLen := 2 * len(e.Versions)
|
|
if extLen > 255 {
|
|
return 0, errors.New("too many supported versions")
|
|
}
|
|
|
|
b[0] = byte(extensionSupportedVersions >> 8)
|
|
b[1] = byte(extensionSupportedVersions)
|
|
b[2] = byte((extLen + 1) >> 8)
|
|
b[3] = byte(extLen + 1)
|
|
b[4] = byte(extLen)
|
|
|
|
i := 5
|
|
for _, sv := range e.Versions {
|
|
b[i] = byte(sv >> 8)
|
|
b[i+1] = byte(sv)
|
|
i += 2
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *SupportedVersionsExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
// RFC 8446, Section 4.2.1
|
|
var versList cryptobyte.String
|
|
if !extData.ReadUint8LengthPrefixed(&versList) || versList.Empty() {
|
|
return 0, errors.New("unable to read supported versions extension data")
|
|
}
|
|
supportedVersions := []uint16{}
|
|
for !versList.Empty() {
|
|
var vers uint16
|
|
if !versList.ReadUint16(&vers) {
|
|
return 0, errors.New("unable to read supported versions extension data")
|
|
}
|
|
supportedVersions = append(supportedVersions, unGREASEUint16(vers))
|
|
}
|
|
e.Versions = supportedVersions
|
|
return fullLen, nil
|
|
}
|
|
|
|
// MUST NOT be part of initial ClientHello
|
|
type CookieExtension struct {
|
|
Cookie []byte
|
|
}
|
|
|
|
func (e *CookieExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
func (e *CookieExtension) Len() int {
|
|
return 4 + len(e.Cookie)
|
|
}
|
|
|
|
func (e *CookieExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
b[0] = byte(extensionCookie >> 8)
|
|
b[1] = byte(extensionCookie)
|
|
b[2] = byte(len(e.Cookie) >> 8)
|
|
b[3] = byte(len(e.Cookie))
|
|
if len(e.Cookie) > 0 {
|
|
copy(b[4:], e.Cookie)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
/*
|
|
FAKE EXTENSIONS
|
|
*/
|
|
|
|
type FakeChannelIDExtension struct {
|
|
// The extension ID changed from 30031 to 30032. Set to true to use the old extension ID.
|
|
OldExtensionID bool
|
|
}
|
|
|
|
func (e *FakeChannelIDExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
func (e *FakeChannelIDExtension) Len() int {
|
|
return 4
|
|
}
|
|
|
|
func (e *FakeChannelIDExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
extensionID := fakeExtensionChannelID
|
|
if e.OldExtensionID {
|
|
extensionID = fakeOldExtensionChannelID
|
|
}
|
|
// https://tools.ietf.org/html/draft-balfanz-tls-channelid-00
|
|
b[0] = byte(extensionID >> 8)
|
|
b[1] = byte(extensionID & 0xff)
|
|
// The length is 0
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *FakeChannelIDExtension) Write(_ []byte) (int, error) {
|
|
return 0, nil
|
|
}
|
|
|
|
type FakeRecordSizeLimitExtension struct {
|
|
Limit uint16
|
|
}
|
|
|
|
func (e *FakeRecordSizeLimitExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
func (e *FakeRecordSizeLimitExtension) Len() int {
|
|
return 6
|
|
}
|
|
|
|
func (e *FakeRecordSizeLimitExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// https://tools.ietf.org/html/draft-balfanz-tls-channelid-00
|
|
b[0] = byte(fakeRecordSizeLimit >> 8)
|
|
b[1] = byte(fakeRecordSizeLimit & 0xff)
|
|
|
|
b[2] = byte(0)
|
|
b[3] = byte(2)
|
|
|
|
b[4] = byte(e.Limit >> 8)
|
|
b[5] = byte(e.Limit & 0xff)
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *FakeRecordSizeLimitExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
if !extData.ReadUint16(&e.Limit) {
|
|
return 0, errors.New("unable to read record size limit extension data")
|
|
}
|
|
return fullLen, nil
|
|
}
|
|
|
|
type DelegatedCredentialsExtension struct {
|
|
AlgorithmsSignature []SignatureScheme
|
|
}
|
|
|
|
func (e *DelegatedCredentialsExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
func (e *DelegatedCredentialsExtension) Len() int {
|
|
return 6 + 2*len(e.AlgorithmsSignature)
|
|
}
|
|
|
|
func (e *DelegatedCredentialsExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
b[0] = byte(extensionDelegatedCredentials >> 8)
|
|
b[1] = byte(extensionDelegatedCredentials)
|
|
b[2] = byte((2 + 2*len(e.AlgorithmsSignature)) >> 8)
|
|
b[3] = byte(2 + 2*len(e.AlgorithmsSignature))
|
|
b[4] = byte((2 * len(e.AlgorithmsSignature)) >> 8)
|
|
b[5] = byte(2 * len(e.AlgorithmsSignature))
|
|
for i, sigAndHash := range e.AlgorithmsSignature {
|
|
b[6+2*i] = byte(sigAndHash >> 8)
|
|
b[7+2*i] = byte(sigAndHash)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
// https://tools.ietf.org/html/rfc8472#section-2
|
|
type FakeTokenBindingExtension struct {
|
|
MajorVersion, MinorVersion uint8
|
|
KeyParameters []uint8
|
|
}
|
|
|
|
func (e *FakeTokenBindingExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
func (e *FakeTokenBindingExtension) Len() int {
|
|
// extension ID + data length + versions + key parameters length + key parameters
|
|
return 2 + 2 + 2 + 1 + len(e.KeyParameters)
|
|
}
|
|
|
|
func (e *FakeTokenBindingExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
dataLen := e.Len() - 4
|
|
b[0] = byte(fakeExtensionTokenBinding >> 8)
|
|
b[1] = byte(fakeExtensionTokenBinding & 0xff)
|
|
b[2] = byte(dataLen >> 8)
|
|
b[3] = byte(dataLen & 0xff)
|
|
b[4] = e.MajorVersion
|
|
b[5] = e.MinorVersion
|
|
b[6] = byte(len(e.KeyParameters))
|
|
if len(e.KeyParameters) > 0 {
|
|
copy(b[7:], e.KeyParameters)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *FakeTokenBindingExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
var keyParameters cryptobyte.String
|
|
if !extData.ReadUint8(&e.MajorVersion) ||
|
|
!extData.ReadUint8(&e.MinorVersion) ||
|
|
!extData.ReadUint8LengthPrefixed(&keyParameters) {
|
|
return 0, errors.New("unable to read token binding extension data")
|
|
}
|
|
e.KeyParameters = keyParameters
|
|
return fullLen, nil
|
|
}
|
|
|
|
// https://datatracker.ietf.org/doc/html/draft-ietf-tls-subcerts-15#section-4.1.1
|
|
|
|
type FakeDelegatedCredentialsExtension struct {
|
|
SupportedSignatureAlgorithms []SignatureScheme
|
|
}
|
|
|
|
func (e *FakeDelegatedCredentialsExtension) writeToUConn(uc *UConn) error {
|
|
return nil
|
|
}
|
|
|
|
func (e *FakeDelegatedCredentialsExtension) Len() int {
|
|
return 6 + 2*len(e.SupportedSignatureAlgorithms)
|
|
}
|
|
|
|
func (e *FakeDelegatedCredentialsExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
// https://datatracker.ietf.org/doc/html/draft-ietf-tls-subcerts-15#section-4.1.1
|
|
b[0] = byte(fakeExtensionDelegatedCredentials >> 8)
|
|
b[1] = byte(fakeExtensionDelegatedCredentials)
|
|
b[2] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)) >> 8)
|
|
b[3] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)))
|
|
b[4] = byte((2 * len(e.SupportedSignatureAlgorithms)) >> 8)
|
|
b[5] = byte((2 * len(e.SupportedSignatureAlgorithms)))
|
|
for i, sigAndHash := range e.SupportedSignatureAlgorithms {
|
|
b[6+2*i] = byte(sigAndHash >> 8)
|
|
b[7+2*i] = byte(sigAndHash)
|
|
}
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *FakeDelegatedCredentialsExtension) Write(b []byte) (int, error) {
|
|
fullLen := len(b)
|
|
extData := cryptobyte.String(b)
|
|
//https://datatracker.ietf.org/doc/html/draft-ietf-tls-subcerts-15#section-4.1.1
|
|
var supportedAlgs cryptobyte.String
|
|
if !extData.ReadUint16LengthPrefixed(&supportedAlgs) || supportedAlgs.Empty() {
|
|
return 0, errors.New("unable to read signature algorithms extension data")
|
|
}
|
|
supportedSignatureAlgorithms := []SignatureScheme{}
|
|
for !supportedAlgs.Empty() {
|
|
var sigAndAlg uint16
|
|
if !supportedAlgs.ReadUint16(&sigAndAlg) {
|
|
return 0, errors.New("unable to read signature algorithms extension data")
|
|
}
|
|
supportedSignatureAlgorithms = append(
|
|
supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
|
|
}
|
|
e.SupportedSignatureAlgorithms = supportedSignatureAlgorithms
|
|
return fullLen, nil
|
|
}
|
|
|
|
// FakePreSharedKeyExtension is an extension used to set the PSK extension in the
|
|
// ClientHello.
|
|
//
|
|
// Unfortunately, even when the PSK extension is set, there will be no PSK-based
|
|
// resumption since crypto/tls does not implement PSK.
|
|
type FakePreSharedKeyExtension struct {
|
|
PskIdentities []PskIdentity
|
|
PskBinders [][]byte
|
|
}
|
|
|
|
func (e *FakePreSharedKeyExtension) writeToUConn(uc *UConn) error {
|
|
uc.HandshakeState.Hello.PskIdentities = e.PskIdentities
|
|
uc.HandshakeState.Hello.PskBinders = e.PskBinders
|
|
return nil
|
|
}
|
|
|
|
func (e *FakePreSharedKeyExtension) Len() int {
|
|
length := 4 // extension type + extension length
|
|
length += 2 // identities length
|
|
for _, identity := range e.PskIdentities {
|
|
length += 2 + len(identity.Label) + 4 // identity length + identity + obfuscated ticket age
|
|
}
|
|
length += 2 // binders length
|
|
for _, binder := range e.PskBinders {
|
|
length += len(binder)
|
|
}
|
|
return length
|
|
}
|
|
|
|
func (e *FakePreSharedKeyExtension) Read(b []byte) (int, error) {
|
|
if len(b) < e.Len() {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
b[0] = byte(extensionPreSharedKey >> 8)
|
|
b[1] = byte(extensionPreSharedKey)
|
|
b[2] = byte((e.Len() - 4) >> 8)
|
|
b[3] = byte(e.Len() - 4)
|
|
|
|
// identities length
|
|
identitiesLength := 0
|
|
for _, identity := range e.PskIdentities {
|
|
identitiesLength += 2 + len(identity.Label) + 4 // identity length + identity + obfuscated ticket age
|
|
}
|
|
b[4] = byte(identitiesLength >> 8)
|
|
b[5] = byte(identitiesLength)
|
|
|
|
// identities
|
|
offset := 6
|
|
for _, identity := range e.PskIdentities {
|
|
b[offset] = byte(len(identity.Label) >> 8)
|
|
b[offset+1] = byte(len(identity.Label))
|
|
offset += 2
|
|
copy(b[offset:], identity.Label)
|
|
offset += len(identity.Label)
|
|
b[offset] = byte(identity.ObfuscatedTicketAge >> 24)
|
|
b[offset+1] = byte(identity.ObfuscatedTicketAge >> 16)
|
|
b[offset+2] = byte(identity.ObfuscatedTicketAge >> 8)
|
|
b[offset+3] = byte(identity.ObfuscatedTicketAge)
|
|
offset += 4
|
|
}
|
|
|
|
// binders length
|
|
bindersLength := 0
|
|
for _, binder := range e.PskBinders {
|
|
bindersLength += len(binder)
|
|
}
|
|
b[offset] = byte(bindersLength >> 8)
|
|
b[offset+1] = byte(bindersLength)
|
|
offset += 2
|
|
|
|
// binders
|
|
for _, binder := range e.PskBinders {
|
|
copy(b[offset:], binder)
|
|
offset += len(binder)
|
|
}
|
|
|
|
return e.Len(), io.EOF
|
|
}
|
|
|
|
func (e *FakePreSharedKeyExtension) Write(b []byte) (n int, err error) {
|
|
fullLen := len(b)
|
|
s := cryptobyte.String(b)
|
|
|
|
var identitiesLength uint16
|
|
if !s.ReadUint16(&identitiesLength) {
|
|
return 0, errors.New("tls: invalid PSK extension")
|
|
}
|
|
|
|
// identities
|
|
for identitiesLength > 0 {
|
|
var identityLength uint16
|
|
if !s.ReadUint16(&identityLength) {
|
|
return 0, errors.New("tls: invalid PSK extension")
|
|
}
|
|
identitiesLength -= 2
|
|
|
|
if identityLength > identitiesLength {
|
|
return 0, errors.New("tls: invalid PSK extension")
|
|
}
|
|
|
|
var identity []byte
|
|
if !s.ReadBytes(&identity, int(identityLength)) {
|
|
return 0, errors.New("tls: invalid PSK extension")
|
|
}
|
|
|
|
identitiesLength -= identityLength // identity
|
|
|
|
var obfuscatedTicketAge uint32
|
|
if !s.ReadUint32(&obfuscatedTicketAge) {
|
|
return 0, errors.New("tls: invalid PSK extension")
|
|
}
|
|
|
|
e.PskIdentities = append(e.PskIdentities, PskIdentity{
|
|
Label: identity,
|
|
ObfuscatedTicketAge: obfuscatedTicketAge,
|
|
})
|
|
|
|
identitiesLength -= 4 // obfuscated ticket age
|
|
}
|
|
|
|
var bindersLength uint16
|
|
if !s.ReadUint16(&bindersLength) {
|
|
return 0, errors.New("tls: invalid PSK extension")
|
|
}
|
|
|
|
// binders
|
|
for bindersLength > 0 {
|
|
var binderLength uint8
|
|
if !s.ReadUint8(&binderLength) {
|
|
return 0, errors.New("tls: invalid PSK extension")
|
|
}
|
|
bindersLength -= 1
|
|
|
|
if uint16(binderLength) > bindersLength {
|
|
return 0, errors.New("tls: invalid PSK extension")
|
|
}
|
|
|
|
var binder []byte
|
|
if !s.ReadBytes(&binder, int(binderLength)) {
|
|
return 0, errors.New("tls: invalid PSK extension")
|
|
}
|
|
|
|
e.PskBinders = append(e.PskBinders, binder)
|
|
|
|
bindersLength -= uint16(binderLength)
|
|
}
|
|
|
|
return fullLen, nil
|
|
}
|