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
3 changes: 2 additions & 1 deletion u_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ var (
HelloRandomizedNoALPN = ClientHelloID{helloRandomizedNoALPN, helloAutoVers, nil, nil}

// The rest will will parrot given browser.
HelloFirefox_Auto = HelloFirefox_120
HelloFirefox_Auto = HelloFirefox_141
HelloFirefox_55 = ClientHelloID{helloFirefox, "55", nil, nil}
HelloFirefox_56 = ClientHelloID{helloFirefox, "56", nil, nil}
HelloFirefox_63 = ClientHelloID{helloFirefox, "63", nil, nil}
Expand All @@ -611,6 +611,7 @@ var (
HelloFirefox_102 = ClientHelloID{helloFirefox, "102", nil, nil}
HelloFirefox_105 = ClientHelloID{helloFirefox, "105", nil, nil}
HelloFirefox_120 = ClientHelloID{helloFirefox, "120", nil, nil}
HelloFirefox_141 = ClientHelloID{helloFirefox, "141", nil, nil}

HelloChrome_Auto = HelloChrome_133
HelloChrome_58 = ClientHelloID{helloChrome, "58", nil, nil}
Expand Down
236 changes: 190 additions & 46 deletions u_parrots.go
Original file line number Diff line number Diff line change
Expand Up @@ -1455,6 +1455,132 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
},
},
}, nil
case HelloFirefox_141:
return ClientHelloSpec{
TLSVersMin: VersionTLS12,
TLSVersMax: VersionTLS13,
CipherSuites: []uint16{
TLS_AES_128_GCM_SHA256,
TLS_CHACHA20_POLY1305_SHA256,
TLS_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
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: []uint8{
0x0, // no compression
},
Extensions: []TLSExtension{
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{
Renegotiation: RenegotiateOnceAsClient,
},
&SupportedCurvesExtension{
Curves: []CurveID{
X25519MLKEM768,
X25519,
CurveP256,
CurveP384,
CurveP521,
256,
257,
},
},
&SupportedPointsExtension{
SupportedPoints: []uint8{
0x0, // uncompressed
},
},
&SessionTicketExtension{},
&ALPNExtension{
AlpnProtocols: []string{
"h2",
"http/1.1",
},
},
&StatusRequestExtension{},
&FakeDelegatedCredentialsExtension{
SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512,
ECDSAWithSHA1,
},
},
&SCTExtension{},
&KeyShareExtensionExtended{
KeyShareExtension: &KeyShareExtension{KeyShares: []KeyShare{
{
Group: X25519MLKEM768,
},
{
Group: X25519,
},
{
Group: CurveP256,
},
}},
HybridReuseKey: true,
},
&SupportedVersionsExtension{
Versions: []uint16{
VersionTLS13,
VersionTLS12,
},
},
&SignatureAlgorithmsExtension{
SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512,
PSSWithSHA256,
PSSWithSHA384,
PSSWithSHA512,
PKCS1WithSHA256,
PKCS1WithSHA384,
PKCS1WithSHA512,
ECDSAWithSHA1,
PKCS1WithSHA1,
},
},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&FakeRecordSizeLimitExtension{
Limit: 0x4001,
},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionZlib,
CertCompressionBrotli,
CertCompressionZstd,
}},
&GREASEEncryptedClientHelloExtension{
CandidateCipherSuites: []HPKESymmetricCipherSuite{
{
KdfId: dicttls.HKDF_SHA256,
AeadId: dicttls.AEAD_AES_128_GCM,
},
{
KdfId: dicttls.HKDF_SHA256,
AeadId: dicttls.AEAD_CHACHA20_POLY1305,
},
},
CandidatePayloadLens: []uint16{223}, // +16: 239
},
},
}, nil
case HelloIOS_11_1:
return ClientHelloSpec{
TLSVersMax: VersionTLS12,
Expand Down Expand Up @@ -2872,52 +2998,12 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error {
}
}
case *KeyShareExtension:
preferredCurveIsSet := false
for i := range ext.KeyShares {
curveID := ext.KeyShares[i].Group
if isGREASEUint16(uint16(curveID)) { // just in case the user set a GREASE value instead of unGREASEd
ext.KeyShares[i].Group = CurveID(GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_group))
continue
}
if len(ext.KeyShares[i].Data) > 1 {
continue
}

if curveID == X25519MLKEM768 || curveID == X25519Kyber768Draft00 {
ecdheKey, err := generateECDHEKey(uconn.config.rand(), X25519)
if err != nil {
return err
}
seed := make([]byte, mlkem.SeedSize)
if _, err := io.ReadFull(uconn.config.rand(), seed); err != nil {
return err
}
mlkemKey, err := mlkem.NewDecapsulationKey768(seed)
if err != nil {
return err
}

if curveID == X25519Kyber768Draft00 {
ext.KeyShares[i].Data = append(ecdheKey.PublicKey().Bytes(), mlkemKey.EncapsulationKey().Bytes()...)
} else {
ext.KeyShares[i].Data = append(mlkemKey.EncapsulationKey().Bytes(), ecdheKey.PublicKey().Bytes()...)
}
uconn.HandshakeState.State13.KeyShareKeys.Mlkem = mlkemKey
uconn.HandshakeState.State13.KeyShareKeys.MlkemEcdhe = ecdheKey
} else {
ecdheKey, err := generateECDHEKey(uconn.config.rand(), curveID)
if err != nil {
return fmt.Errorf("unsupported Curve in KeyShareExtension: %v."+
"To mimic it, fill the Data(key) field manually", curveID)
}

ext.KeyShares[i].Data = ecdheKey.PublicKey().Bytes()
if !preferredCurveIsSet {
// only do this once for the first non-grease curve
uconn.HandshakeState.State13.KeyShareKeys.Ecdhe = ecdheKey
preferredCurveIsSet = true
}
}
if err := uconn.setKeyShare(&KeyShareExtensionExtended{KeyShareExtension: ext}); err != nil {
return err
}
case *KeyShareExtensionExtended:
if err := uconn.setKeyShare(ext); err != nil {
return err
}
case *SupportedVersionsExtension:
for i := range ext.Versions {
Expand Down Expand Up @@ -3238,3 +3324,61 @@ func removeRC4Ciphers(s []uint16) []uint16 {
}
return s[:sliceLen]
}

func (uconn *UConn) setKeyShare(ext *KeyShareExtensionExtended) error {
preferredCurveIsSet := false
for i := range ext.KeyShares {
curveID := ext.KeyShares[i].Group
if isGREASEUint16(uint16(curveID)) { // just in case the user set a GREASE value instead of unGREASEd
ext.KeyShares[i].Group = CurveID(GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_group))
continue
}
if len(ext.KeyShares[i].Data) > 1 {
continue
}

if curveID == X25519MLKEM768 || curveID == X25519Kyber768Draft00 {
ecdheKey, err := generateECDHEKey(uconn.config.rand(), X25519)
if err != nil {
return err
}
seed := make([]byte, mlkem.SeedSize)
if _, err := io.ReadFull(uconn.config.rand(), seed); err != nil {
return err
}
mlkemKey, err := mlkem.NewDecapsulationKey768(seed)
if err != nil {
return err
}

if curveID == X25519Kyber768Draft00 {
ext.KeyShares[i].Data = append(ecdheKey.PublicKey().Bytes(), mlkemKey.EncapsulationKey().Bytes()...)
} else {
ext.KeyShares[i].Data = append(mlkemKey.EncapsulationKey().Bytes(), ecdheKey.PublicKey().Bytes()...)
}
uconn.HandshakeState.State13.KeyShareKeys.Mlkem = mlkemKey
uconn.HandshakeState.State13.KeyShareKeys.MlkemEcdhe = ecdheKey

if ext.HybridReuseKey && len(ext.KeyShares) > i+1 && ext.KeyShares[i+1].Group == X25519 {
preferredCurveIsSet = true
uconn.HandshakeState.State13.KeyShareKeys.Ecdhe = ecdheKey
ext.KeyShares[i+1].Data = ecdheKey.PublicKey().Bytes()
}
} else {
ecdheKey, err := generateECDHEKey(uconn.config.rand(), curveID)
if err != nil {
return fmt.Errorf("unsupported Curve in KeyShareExtension: %v."+
"To mimic it, fill the Data(key) field manually", curveID)
}

ext.KeyShares[i].Data = ecdheKey.PublicKey().Bytes()
if !preferredCurveIsSet {
// only do this once for the first non-grease curve
uconn.HandshakeState.State13.KeyShareKeys.Ecdhe = ecdheKey
preferredCurveIsSet = true
}
}
}

return nil
}
10 changes: 10 additions & 0 deletions u_tls_extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,16 @@ func (e *UtlsCompressCertExtension) UnmarshalJSON(b []byte) error {
return nil
}

// Same as KeyShareExtension with extra options added without breaking users that
// use positional struct literal for KeyShareExtension
type KeyShareExtensionExtended struct {
*KeyShareExtension

// whether to reuse keys for the same algorithm for hybrid key shares with traditional key shares
// according to draft-ietf-tls-hybrid-design-14 section 3.2
HybridReuseKey bool
}

// KeyShareExtension implements key_share (51) and is for TLS 1.3 only.
type KeyShareExtension struct {
KeyShares []KeyShare
Expand Down
Loading