Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion u_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const (
utlsFakeExtensionCustom uint16 = 1234 // not IANA assigned, for ALPS
utlsExtensionECH uint16 = 0xfe0d // draft-ietf-tls-esni-17
utlsExtensionECHOuterExtensions uint16 = 0xfd00 // draft-ietf-tls-esni-17
utlsExtensionTrustAnchors uint16 = 0xca34 // draft-ietf-tls-trust-anchor-ids

// extensions with 'fake' prefix break connection, if server echoes them back
fakeExtensionEncryptThenMAC uint16 = 22
Expand Down Expand Up @@ -109,6 +110,11 @@ const (
var (
FakePKCS1WithSHA224 SignatureScheme = 0x0301
FakeECDSAWithSHA224 SignatureScheme = 0x0303
// FakeMLDSA* are advertised for ClientHello fingerprint parity only. uTLS
// does not implement ML-DSA certificate signature verification.
FakeMLDSA44 SignatureScheme = 0x0904
FakeMLDSA65 SignatureScheme = 0x0905
FakeMLDSA87 SignatureScheme = 0x0906

FakeSHA1WithDSA SignatureScheme = 0x0202
FakeSHA256WithDSA SignatureScheme = 0x0402
Expand Down Expand Up @@ -613,7 +619,7 @@ var (
HelloFirefox_120 = ClientHelloID{helloFirefox, "120", nil, nil}
HelloFirefox_148 = ClientHelloID{helloFirefox, "148", nil, nil}

HelloChrome_Auto = HelloChrome_133
HelloChrome_Auto = HelloChrome_153
HelloChrome_58 = ClientHelloID{helloChrome, "58", nil, nil}
HelloChrome_62 = ClientHelloID{helloChrome, "62", nil, nil}
HelloChrome_70 = ClientHelloID{helloChrome, "70", nil, nil}
Expand Down Expand Up @@ -645,6 +651,9 @@ var (
HelloChrome_131 = ClientHelloID{helloChrome, "131", nil, nil}
// Chrome w/ New ALPS codepoint
HelloChrome_133 = ClientHelloID{helloChrome, "133", nil, nil}
// Chrome w/ Trust Anchor IDs and post-quantum signature algorithms. The
// trust_anchors extension is feature- and platform-dependent in Chrome.
HelloChrome_153 = ClientHelloID{helloChrome, "153", nil, nil}

HelloIOS_Auto = HelloIOS_14
HelloIOS_11_1 = ClientHelloID{helloIOS, "111", nil, nil} // legacy "111" means 11.1
Expand Down
86 changes: 86 additions & 0 deletions u_parrots.go
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,86 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
&UtlsGREASEExtension{},
}),
}, nil
case HelloChrome_153:
return ClientHelloSpec{
CipherSuites: []uint16{
GREASE_PLACEHOLDER,
TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384,
TLS_CHACHA20_POLY1305_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_AES_256_CBC_SHA,
},
CompressionMethods: []byte{
0x00, // compressionNone
},
Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
GREASE_PLACEHOLDER,
X25519MLKEM768,
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
GREASE_PLACEHOLDER,
FakeMLDSA44,
FakeMLDSA65,
FakeMLDSA87,
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519MLKEM768},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&ApplicationSettingsExtensionNew{SupportedProtocols: []string{"h2"}},
// Chrome sends an empty RequestedTrustAnchorList when the
// trust-anchor-IDs feature is enabled but no IDs are requested.
&GenericExtension{Id: utlsExtensionTrustAnchors, Data: []byte{0, 0}},
BoringGREASEECH(),
&UtlsGREASEExtension{},
}),
}, nil
case HelloFirefox_55, HelloFirefox_56:
return ClientHelloSpec{
TLSVersMax: VersionTLS12,
Expand Down Expand Up @@ -3131,6 +3211,12 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error {
ext.Curves[i] = CurveID(GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_group))
}
}
case *SignatureAlgorithmsExtension:
for i := range ext.SupportedSignatureAlgorithms {
if isGREASEUint16(uint16(ext.SupportedSignatureAlgorithms[i])) {
ext.SupportedSignatureAlgorithms[i] = SignatureScheme(GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_signature_algorithm))
}
}
case *KeyShareExtension:
preferredCurveIsSet := false
reusableClassicalKeys := make(map[CurveID][]*ecdh.PrivateKey)
Expand Down
84 changes: 84 additions & 0 deletions u_parrots_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package tls
import (
"bytes"
"crypto/sha256"
"io"
"net"
"slices"
"testing"
)

Expand Down Expand Up @@ -54,6 +56,88 @@ func newTestUConnWithIncrementingRand() *UConn {
}, HelloCustom)
}

func TestChrome153ClientHelloSpec(t *testing.T) {
if HelloChrome_Auto != HelloChrome_153 {
t.Fatalf("HelloChrome_Auto = %s, want %s", HelloChrome_Auto.Str(), HelloChrome_153.Str())
}

spec, err := UTLSIdToSpec(HelloChrome_153)
if err != nil {
t.Fatalf("creating Chrome 153 spec: %v", err)
}

wantSignatureAlgorithms := []SignatureScheme{
GREASE_PLACEHOLDER,
FakeMLDSA44,
FakeMLDSA65,
FakeMLDSA87,
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
}

var signatureAlgorithms *SignatureAlgorithmsExtension
var trustAnchors *GenericExtension
for _, ext := range spec.Extensions {
switch ext := ext.(type) {
case *SignatureAlgorithmsExtension:
signatureAlgorithms = ext
case *GenericExtension:
if ext.Id == utlsExtensionTrustAnchors {
trustAnchors = ext
}
}
}

if signatureAlgorithms == nil {
t.Fatal("signature_algorithms extension not found")
}
if !slices.Equal(signatureAlgorithms.SupportedSignatureAlgorithms, wantSignatureAlgorithms) {
t.Fatalf("signature_algorithms = %#v, want %#v", signatureAlgorithms.SupportedSignatureAlgorithms, wantSignatureAlgorithms)
}
if trustAnchors == nil {
t.Fatal("trust_anchors extension not found")
}
if !bytes.Equal(trustAnchors.Data, []byte{0, 0}) {
t.Fatalf("trust_anchors data = %x, want 0000", trustAnchors.Data)
}

wire := make([]byte, trustAnchors.Len())
if _, err := trustAnchors.Read(wire); err != io.EOF {
t.Fatalf("trust_anchors Read error = %v, want io.EOF", err)
}
if want := []byte{0xca, 0x34, 0x00, 0x02, 0x00, 0x00}; !bytes.Equal(wire, want) {
t.Fatalf("trust_anchors wire encoding = %x, want %x", wire, want)
}
}

func TestChrome153ReplacesSignatureAlgorithmGREASE(t *testing.T) {
uconn := UClient(&net.TCPConn{}, &Config{
ServerName: "example.com",
Rand: &incrementingSource{next: 0x81},
}, HelloChrome_153)
if err := uconn.BuildHandshakeState(); err != nil {
t.Fatalf("building Chrome 153 ClientHello: %v", err)
}

got := uconn.HandshakeState.Hello.SupportedSignatureAlgorithms[0]
want := SignatureScheme(GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_signature_algorithm))
if got != want {
t.Fatalf("signature algorithm GREASE = %#04x, want %#04x", got, want)
}
if !isGREASEUint16(uint16(got)) {
t.Fatalf("signature algorithm GREASE = %#04x, want a GREASE value", got)
}
if got == GREASE_PLACEHOLDER {
t.Fatalf("signature algorithm GREASE was not randomized: got placeholder %#04x", got)
}
}

func fingerprintsWithHybridClassicalKeyShareReuse() []ClientHelloID {
return []ClientHelloID{
HelloFirefox_148,
Expand Down
4 changes: 3 additions & 1 deletion u_tls_extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,9 @@ const (
ssl_grease_extension2
ssl_grease_version
ssl_grease_ticket_extension
ssl_grease_last_index = ssl_grease_ticket_extension
ssl_grease_ech_config_id
ssl_grease_signature_algorithm
ssl_grease_last_index
)

// it is responsibility of user not to generate multiple grease extensions with same value
Expand Down
Loading