diff --git a/auth.go b/auth.go index 680192f3..998deb9b 100644 --- a/auth.go +++ b/auth.go @@ -15,9 +15,6 @@ import ( "fmt" "hash" "io" - - circlPki "github.com/cloudflare/circl/pki" - circlSign "github.com/cloudflare/circl/sign" ) // verifyHandshakeSignature verifies a signature against pre-hashed @@ -58,20 +55,7 @@ func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc c return err } default: - // [UTLS SECTION BEGINS] - // Ported from cloudflare/go - scheme := circlSchemeBySigType(sigType) - if scheme == nil { - return errors.New("internal error: unknown signature type") - } - pubKey, ok := pubkey.(circlSign.PublicKey) - if !ok { - return fmt.Errorf("expected a %s public key, got %T", scheme.Name(), pubkey) - } - if !scheme.Verify(pubKey, signed, sig, nil) { - return fmt.Errorf("%s verification failure", scheme.Name()) - } - // [UTLS SECTION ENDS] + return errors.New("internal error: unknown signature type") } return nil } @@ -122,18 +106,7 @@ func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType case Ed25519: sigType = signatureEd25519 default: - // [UTLS SECTION BEGINS] - // Ported from cloudflare/go - scheme := circlPki.SchemeByTLSID(uint(signatureAlgorithm)) - if scheme == nil { - return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm) - } - sigType = sigTypeByCirclScheme(scheme) - if sigType == 0 { - return 0, 0, fmt.Errorf("circl scheme %s not supported", - scheme.Name()) - } - // [UTLS SECTION ENDS] + return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm) } switch signatureAlgorithm { case PKCS1WithSHA1, ECDSAWithSHA1: @@ -147,14 +120,7 @@ func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType case Ed25519: hash = directSigning default: - // [UTLS SECTION BEGINS] - // Ported from cloudflare/go - scheme := circlPki.SchemeByTLSID(uint(signatureAlgorithm)) - if scheme == nil { - return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm) - } - hash = directSigning - // [UTLS SECTION ENDS] + return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm) } return sigType, hash, nil } @@ -174,11 +140,6 @@ func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash c // full signature, and not even OpenSSL bothers with the // complexity, so we can't even test it properly. return 0, 0, fmt.Errorf("tls: Ed25519 public keys are not supported before TLS 1.2") - // [UTLS SECTION BEGINS] - // Ported from cloudflare/go - case circlSign.PublicKey: - return 0, 0, fmt.Errorf("tls: circl public keys are not supported before TLS 1.2") - // [UTLS SECTION ENDS] default: return 0, 0, fmt.Errorf("tls: unsupported public key: %T", pub) } @@ -249,16 +210,6 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu } case ed25519.PublicKey: sigAlgs = []SignatureScheme{Ed25519} - // [UTLS SECTION BEGINS] - // Ported from cloudflare/go - case circlSign.PublicKey: - scheme := pub.Scheme() - tlsScheme, ok := scheme.(circlPki.TLSScheme) - if !ok { - return nil - } - sigAlgs = []SignatureScheme{SignatureScheme(tlsScheme.TLSIdentifier())} - // [UTLS SECTION ENDS] default: return nil } diff --git a/auth_test.go b/auth_test.go index 8ee72660..f67a8e0f 100644 --- a/auth_test.go +++ b/auth_test.go @@ -8,7 +8,6 @@ import ( "crypto" "testing" - circlPki "github.com/cloudflare/circl/pki" "github.com/refraction-networking/utls/internal/fips140tls" ) @@ -169,7 +168,7 @@ func TestSupportedSignatureAlgorithms(t *testing.T) { if sigType == 0 { t.Errorf("%v: missing signature type", sigAlg) } - if hash == 0 && sigAlg != Ed25519 && circlPki.SchemeByTLSID(uint(sigAlg)) == nil { // [UTLS] ported from cloudflare/go + if hash == 0 && sigAlg != Ed25519 { t.Errorf("%v: missing hash", sigAlg) } } diff --git a/common.go b/common.go index fea76bd3..73b6dad5 100644 --- a/common.go +++ b/common.go @@ -316,11 +316,6 @@ type ConnectionState struct { // testingOnlyCurveID is the selected CurveID, or zero if an RSA exchanges // is performed. testingOnlyCurveID CurveID - - // ECHRetryConfigs contains the ECH retry configurations sent by the server in - // EncryptedExtensions message. It is only populated if the server sent the - // ech extension in EncryptedExtensions message. - ECHRetryConfigs []ECHConfig // [uTLS] } // ExportKeyingMaterial returns length bytes of exported key material in a new @@ -919,17 +914,6 @@ type Config struct { // autoSessionTicketKeys is like sessionTicketKeys but is owned by the // auto-rotation logic. See Config.ticketKeys. autoSessionTicketKeys []ticketKey - - // ECHConfigs contains the ECH configurations to be used by the ECH - // extension if any. - // It could either be distributed by the server in EncryptedExtensions - // message or out-of-band. - // - // If ECHConfigs is nil and an ECH extension is present, GREASEd ECH - // extension will be sent. - // - // If GREASE ECH extension is present, this field will be ignored. - ECHConfigs []ECHConfig // [uTLS] } // EncryptedClientHelloKey holds a private key that is associated @@ -1036,7 +1020,6 @@ func (c *Config) Clone() *Config { autoSessionTicketKeys: c.autoSessionTicketKeys, PreferSkipResumptionOnNilExtension: c.PreferSkipResumptionOnNilExtension, // [UTLS] - ECHConfigs: c.ECHConfigs, // [uTLS] } } diff --git a/generate_cert.go b/generate_cert.go index dce68f7c..cd4bfc51 100644 --- a/generate_cert.go +++ b/generate_cert.go @@ -25,9 +25,6 @@ import ( "os" "strings" "time" - - circlSign "github.com/cloudflare/circl/sign" - circlSchemes "github.com/cloudflare/circl/sign/schemes" ) var ( @@ -38,7 +35,6 @@ var ( rsaBits = flag.Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set") ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521") ed25519Key = flag.Bool("ed25519", false, "Generate an Ed25519 key") - circlKey = flag.String("circl", "", "Generate a key supported by Circl") // [UTLS] ported from cloudflare/go ) func publicKey(priv any) any { @@ -49,11 +45,6 @@ func publicKey(priv any) any { return &k.PublicKey case ed25519.PrivateKey: return k.Public().(ed25519.PublicKey) - // [UTLS SECTION BEGINS] - // Ported from cloudflare/go - case circlSign.PrivateKey: - return k.Public() - // [UTLS SECTION ENDS] default: return nil } @@ -72,15 +63,6 @@ func main() { case "": if *ed25519Key { _, priv, err = ed25519.GenerateKey(rand.Reader) - // [UTLS SECTION BEGINS] - // Ported from cloudflare/go - } else if *circlKey != "" { - scheme := circlSchemes.ByName(*circlKey) - if scheme == nil { - log.Fatalf("No such Circl scheme: %s", *circlKey) - } - _, priv, err = scheme.GenerateKey() - // [UTLS SECTION ENDS] } else { priv, err = rsa.GenerateKey(rand.Reader, *rsaBits) } diff --git a/go.mod b/go.mod index 4c13f5e1..6cc2d356 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ retract ( require ( github.com/andybalholm/brotli v1.0.6 - github.com/cloudflare/circl v1.5.0 github.com/klauspost/compress v1.17.4 golang.org/x/crypto v0.36.0 golang.org/x/net v0.38.0 diff --git a/go.sum b/go.sum index 17028cd7..82793448 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys= -github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= diff --git a/handshake_client.go b/handshake_client.go index 91cf41b6..bba58a5a 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -27,8 +27,6 @@ import ( "github.com/refraction-networking/utls/internal/fips140tls" "github.com/refraction-networking/utls/internal/hpke" "github.com/refraction-networking/utls/internal/tls13" - - circlSign "github.com/cloudflare/circl/sign" ) type clientHandshakeState struct { @@ -1220,7 +1218,7 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error { } switch certs[0].PublicKey.(type) { - case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey, circlSign.PublicKey: // [UTLS] ported from cloudflare/go + case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey: break default: c.sendAlert(alertUnsupportedCertificate) diff --git a/handshake_client_tls13.go b/handshake_client_tls13.go index 5bee35c2..01c2756c 100644 --- a/handshake_client_tls13.go +++ b/handshake_client_tls13.go @@ -850,7 +850,7 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error { } // See RFC 8446, Section 4.4.3. - if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, c.config.supportedSignatureAlgorithms()) { // [UTLS] ported from cloudflare/go + if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) { c.sendAlert(alertIllegalParameter) return errors.New("tls: certificate used with invalid signature algorithm") } diff --git a/handshake_server.go b/handshake_server.go index 70ba7147..e38ebaeb 100644 --- a/handshake_server.go +++ b/handshake_server.go @@ -19,8 +19,6 @@ import ( "time" "github.com/refraction-networking/utls/internal/byteorder" - - circlSign "github.com/cloudflare/circl/sign" ) // serverHandshakeState contains details of a server handshake in progress. @@ -643,7 +641,7 @@ func (hs *serverHandshakeState) doFullHandshake() error { } if c.vers >= VersionTLS12 { certReq.hasSignatureAlgorithm = true - certReq.supportedSignatureAlgorithms = c.config.supportedSignatureAlgorithms() // [UTLS] ported from cloudflare/go + certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms() } // An empty list of certificateAuthorities signals to @@ -972,7 +970,7 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error { if len(certs) > 0 { switch certs[0].PublicKey.(type) { - case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey, circlSign.PublicKey: // [UTLS] ported from cloudflare/go + case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey: default: c.sendAlert(alertUnsupportedCertificate) return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey) diff --git a/handshake_server_tls13.go b/handshake_server_tls13.go index b05f1421..510db6f6 100644 --- a/handshake_server_tls13.go +++ b/handshake_server_tls13.go @@ -833,7 +833,7 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error { certReq := new(certificateRequestMsgTLS13) certReq.ocspStapling = true certReq.scts = true - certReq.supportedSignatureAlgorithms = c.config.supportedSignatureAlgorithms() // [UTLS] ported from cloudflare/go + certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms() if c.config.ClientCAs != nil { certReq.certificateAuthorities = c.config.ClientCAs.Subjects() } @@ -1089,7 +1089,7 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error { } // See RFC 8446, Section 4.4.3. - if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, c.config.supportedSignatureAlgorithms()) { // [UTLS] ported from cloudflare/go + if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) { c.sendAlert(alertIllegalParameter) return errors.New("tls: client certificate used with invalid signature algorithm") } diff --git a/key_agreement.go b/key_agreement.go index 671c782f..3e96242b 100644 --- a/key_agreement.go +++ b/key_agreement.go @@ -130,7 +130,7 @@ func md5SHA1Hash(slices [][]byte) []byte { // the sigType (for earlier TLS versions). For Ed25519 signatures, which don't // do pre-hashing, it returns the concatenation of the slices. func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) []byte { - if sigType == signatureEd25519 || circlSchemeBySigType(sigType) != nil { // [UTLS] ported from cloudflare/go + if sigType == signatureEd25519 { var signed []byte for _, slice := range slices { signed = append(signed, slice...) diff --git a/prf.go b/prf.go index f99411f6..2c638ba8 100644 --- a/prf.go +++ b/prf.go @@ -225,11 +225,11 @@ func (h finishedHash) serverSum(masterSecret []byte) []byte { // hashForClientCertificate returns the handshake messages so far, pre-hashed if // necessary, suitable for signing by a TLS client certificate. func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash) []byte { - if (h.version >= VersionTLS12 || sigType == signatureEd25519 || circlSchemeBySigType(sigType) != nil) && h.buffer == nil { // [UTLS] ported from cloudflare/go + if (h.version >= VersionTLS12 || sigType == signatureEd25519) && h.buffer == nil { panic("tls: handshake hash for a client certificate requested after discarding the handshake buffer") } - if sigType == signatureEd25519 || circlSchemeBySigType(sigType) != nil { // [UTLS] ported from cloudflare/go + if sigType == signatureEd25519 { return h.buffer } diff --git a/tls.go b/tls.go index 051108fd..d76e0008 100644 --- a/tls.go +++ b/tls.go @@ -25,8 +25,6 @@ import ( "net" "os" "strings" - - circlSign "github.com/cloudflare/circl/sign" ) // Server returns a new TLS server side connection @@ -345,20 +343,6 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) { if !bytes.Equal(priv.Public().(ed25519.PublicKey), pub) { return fail(errors.New("tls: private key does not match public key")) } - // [UTLS SECTION BEGINS] - // Ported from cloudflare/go - case circlSign.PublicKey: - priv, ok := cert.PrivateKey.(circlSign.PrivateKey) - if !ok { - return fail(errors.New("tls: private key type does not match public key type")) - } - pkBytes, err := priv.Public().(circlSign.PublicKey).MarshalBinary() - pkBytes2, err2 := pub.MarshalBinary() - - if err != nil || err2 != nil || !bytes.Equal(pkBytes, pkBytes2) { - return fail(errors.New("tls: private key does not match public key")) - } - // [UTLS SECTION ENDS] default: return fail(errors.New("tls: unknown public key algorithm")) } @@ -375,7 +359,7 @@ func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { } if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { switch key := key.(type) { - case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey, circlSign.PrivateKey: // [uTLS] ported from cloudflare/go + case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey: return key, nil default: return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping") diff --git a/tls_cf.go b/tls_cf.go deleted file mode 100644 index 5b74cb44..00000000 --- a/tls_cf.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2021 Cloudflare, 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 ( - circlPki "github.com/cloudflare/circl/pki" - circlSign "github.com/cloudflare/circl/sign" - "github.com/cloudflare/circl/sign/eddilithium3" -) - -// To add a signature scheme from Circl -// -// 1. make sure it implements TLSScheme and CertificateScheme, -// 2. follow the instructions in crypto/x509/x509_cf.go -// 3. add a signature to the iota in common.go -// 4. add row in the circlSchemes lists below - -var circlSchemes = [...]struct { - sigType uint8 - scheme circlSign.Scheme -}{ - {signatureEdDilithium3, eddilithium3.Scheme()}, -} - -func circlSchemeBySigType(sigType uint8) circlSign.Scheme { - for _, cs := range circlSchemes { - if cs.sigType == sigType { - return cs.scheme - } - } - return nil -} - -func sigTypeByCirclScheme(scheme circlSign.Scheme) uint8 { - for _, cs := range circlSchemes { - if cs.scheme == scheme { - return cs.sigType - } - } - return 0 -} - -var supportedSignatureAlgorithmsWithCircl []SignatureScheme - -// supportedSignatureAlgorithms returns enabled signature schemes. PQ signature -// schemes are only included when tls.Config#PQSignatureSchemesEnabled is set -// and FIPS-only mode is not enabled. -func (c *Config) supportedSignatureAlgorithms() []SignatureScheme { - if c != nil && c.PQSignatureSchemesEnabled { - return supportedSignatureAlgorithmsWithCircl - } - return defaultSupportedSignatureAlgorithms -} - -func init() { - supportedSignatureAlgorithmsWithCircl = append([]SignatureScheme{}, defaultSupportedSignatureAlgorithms...) - for _, cs := range circlSchemes { - supportedSignatureAlgorithmsWithCircl = append(supportedSignatureAlgorithmsWithCircl, - SignatureScheme(cs.scheme.(circlPki.TLSScheme).TLSIdentifier())) - } -} diff --git a/tls_test.go b/tls_test.go index 45da4bbd..c91263b1 100644 --- a/tls_test.go +++ b/tls_test.go @@ -903,8 +903,6 @@ func TestCloneNonFuncFields(t *testing.T) { continue // these are unexported fields that are handled separately case "ApplicationSettings": // [UTLS] ALPS (Application Settings) f.Set(reflect.ValueOf(map[string][]byte{"a": {1}})) - case "ECHConfigs": // [UTLS] ECH (Encrypted Client Hello) Configs - f.Set(reflect.ValueOf([]ECHConfig{{Version: 1}})) default: t.Errorf("all fields must be accounted for, but saw unknown field %q", fn) } diff --git a/u_alias.go b/u_alias.go index 7cf5d16c..a1360c55 100644 --- a/u_alias.go +++ b/u_alias.go @@ -2,8 +2,6 @@ package tls import ( "crypto/ecdh" - - "github.com/cloudflare/circl/kem" ) // This file contains all the alias functions, symbols, names, etc. that @@ -32,10 +30,10 @@ func (*KeySharesParameters) GetEcdheKey(curveID CurveID) (ecdheKey *ecdh.Private func (*KeySharesParameters) GetEcdhePubkey(curveID CurveID) (params *ecdh.PublicKey, ok bool) { return } -func (*KeySharesParameters) AddKemKeypair(curveID CurveID, kemKey kem.PrivateKey, kemPubKey kem.PublicKey) { +func (*KeySharesParameters) AddKemKeypair(curveID CurveID, kemKey any, kemPubKey any) { return } -func (ksp *KeySharesParameters) GetKemKey(curveID CurveID) (kemKey kem.PrivateKey, ok bool) { return } +func (ksp *KeySharesParameters) GetKemKey(curveID CurveID) (kemKey any, ok bool) { return } -func (ksp *KeySharesParameters) GetKemPubkey(curveID CurveID) (params kem.PublicKey, ok bool) { return } +func (ksp *KeySharesParameters) GetKemPubkey(curveID CurveID) (params any, ok bool) { return } diff --git a/u_conn.go b/u_conn.go index dfbf8aab..074b4f3f 100644 --- a/u_conn.go +++ b/u_conn.go @@ -841,7 +841,6 @@ func (c *Conn) utlsHandshakeMessageType(msgType byte) (handshakeMessage, error) // Extending (*Conn).connectionStateLocked() func (c *Conn) utlsConnectionStateLocked(state *ConnectionState) { state.PeerApplicationSettings = c.utls.peerApplicationSettings - state.ECHRetryConfigs = c.utls.echRetryConfigs } type utlsConnExtraFields struct { @@ -850,9 +849,6 @@ type utlsConnExtraFields struct { localApplicationSettings []byte applicationSettingsCodepoint uint16 - // Encrypted Client Hello (ECH) - echRetryConfigs []ECHConfig - sessionController *sessionController } diff --git a/u_ech.go b/u_ech.go index fad8dd02..3a3b4004 100644 --- a/u_ech.go +++ b/u_ech.go @@ -8,8 +8,8 @@ import ( "math/big" "sync" - "github.com/cloudflare/circl/hpke" "github.com/refraction-networking/utls/dicttls" + "github.com/refraction-networking/utls/internal/hpke" "golang.org/x/crypto/cryptobyte" ) @@ -26,9 +26,6 @@ type EncryptedClientHelloExtension interface { // TLSExtension must be implemented by all EncryptedClientHelloExtension implementations. TLSExtension - // Configure configures the EncryptedClientHelloExtension with the given slice of ECHConfig. - Configure([]ECHConfig) error - // MarshalClientHello is called by (*UConn).MarshalClientHello() when an ECH extension // is present to allow the ECH extension to take control of the generation of the // entire ClientHello message. @@ -96,8 +93,7 @@ func (g *GREASEEncryptedClientHelloExtension) init() error { // but MAY be held constant for successive connections to the same server // in the same session. if len(g.CandidateCipherSuites) == 0 { - _, kdf, aead := defaultHPKESuite.Params() - g.cipherSuite = HPKESymmetricCipherSuite{uint16(kdf), uint16(aead)} + g.cipherSuite = HPKESymmetricCipherSuite{uint16(defaultHpkeKdf), uint16(defaultHpkeAead)} } else { // randomly pick one from the list rndIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(g.CandidateCipherSuites)))) @@ -113,21 +109,18 @@ func (g *GREASEEncryptedClientHelloExtension) init() error { } if len(g.EncapsulatedKey) == 0 { - // use default random key from cloudflare/go - kem := hpke.KEM_X25519_HKDF_SHA256 + kem := uint16(defaultHpkeKem) - pk, err := kem.Scheme().UnmarshalBinaryPublicKey(dummyX25519PublicKey) + echPK, err := hpke.ParseHPKEPublicKey(uint16(kem), dummyX25519PublicKey) if err != nil { initErr = fmt.Errorf("tls: grease ech: failed to parse dummy public key: %w", err) return } - sender, err := defaultHPKESuite.NewSender(pk, nil) - if err != nil { - initErr = fmt.Errorf("tls: grease ech: failed to create sender: %w", err) - return + suite := echCipher{ + KDFID: defaultHpkeKdf, + AEADID: defaultHpkeAead, } - - g.EncapsulatedKey, _, err = sender.Setup(rand.Reader) + g.EncapsulatedKey, _, err = hpke.SetupSender(kem, suite.KDFID, suite.AEADID, echPK, []byte{}) if err != nil { initErr = fmt.Errorf("tls: grease ech: failed to setup encapsulated key: %w", err) return @@ -158,8 +151,7 @@ func (g *GREASEEncryptedClientHelloExtension) randomizePayload(encodedHelloInner return errors.New("tls: grease ech: regenerating payload is forbidden") } - aead := hpke.AEAD(g.cipherSuite.AeadId) - g.payload = make([]byte, int(aead.CipherLen(uint(encodedHelloInnerLen)))) + g.payload = make([]byte, cipherLen(g.cipherSuite.AeadId, int(encodedHelloInnerLen))) _, err := rand.Read(g.payload) if err != nil { return fmt.Errorf("tls: generating grease ech payload: %w", err) @@ -207,11 +199,6 @@ func (g *GREASEEncryptedClientHelloExtension) Read(b []byte) (int, error) { return g.Len(), io.EOF } -// Configure implements EncryptedClientHelloExtension. -func (*GREASEEncryptedClientHelloExtension) Configure([]ECHConfig) error { - return nil // no-op, it is not possible to configure a GREASE extension for now -} - // MarshalClientHello implements EncryptedClientHelloExtension. func (*GREASEEncryptedClientHelloExtension) MarshalClientHello(*UConn) error { return errors.New("tls: grease ech: MarshalClientHello() is not implemented, use (*UConn).MarshalClientHello() instead") @@ -269,8 +256,7 @@ func (g *GREASEEncryptedClientHelloExtension) Write(b []byte) (int, error) { if !extData.ReadUint16LengthPrefixed(&ignored) { return fullLen, errors.New("bad payload") } - aead := hpke.AEAD(g.cipherSuite.AeadId) - g.CandidatePayloadLens = []uint16{uint16(len(ignored) - int(aead.CipherLen(0)))} + g.CandidatePayloadLens = []uint16{uint16(len(ignored) - cipherLen(g.cipherSuite.AeadId, 0))} return fullLen, nil } @@ -295,11 +281,6 @@ func (*UnimplementedECHExtension) Read(_ []byte) (int, error) { return 0, errors.New("tls: unimplemented ECHExtension") } -// Configure implements EncryptedClientHelloExtension. -func (*UnimplementedECHExtension) Configure([]ECHConfig) error { - return errors.New("tls: unimplemented ECHExtension") -} - // MarshalClientHello implements EncryptedClientHelloExtension. func (*UnimplementedECHExtension) MarshalClientHello(*UConn) error { return errors.New("tls: unimplemented ECHExtension") diff --git a/u_ech_config.go b/u_ech_config.go deleted file mode 100644 index 633c7b12..00000000 --- a/u_ech_config.go +++ /dev/null @@ -1,135 +0,0 @@ -package tls - -import ( - "errors" - "fmt" - - "github.com/cloudflare/circl/hpke" - "golang.org/x/crypto/cryptobyte" -) - -type ECHConfigContents struct { - KeyConfig HPKEKeyConfig - MaximumNameLength uint8 - PublicName []byte - // Extensions []TLSExtension // ignored for now - rawExtensions []byte -} - -func UnmarshalECHConfigContents(contents []byte) (ECHConfigContents, error) { - var ( - contentCryptobyte = cryptobyte.String(contents) - config ECHConfigContents - ) - - // Parse KeyConfig - var t cryptobyte.String - if !contentCryptobyte.ReadUint8(&config.KeyConfig.ConfigId) || - !contentCryptobyte.ReadUint16(&config.KeyConfig.KemId) || - !contentCryptobyte.ReadUint16LengthPrefixed(&t) || - !t.ReadBytes(&config.KeyConfig.rawPublicKey, len(t)) || - !contentCryptobyte.ReadUint16LengthPrefixed(&t) || - len(t)%4 != 0 { - return config, errors.New("error parsing KeyConfig") - } - - // Parse all CipherSuites in KeyConfig - config.KeyConfig.CipherSuites = nil - for !t.Empty() { - var kdfId, aeadId uint16 - if !t.ReadUint16(&kdfId) || !t.ReadUint16(&aeadId) { - // This indicates an internal bug. - panic("internal error while parsing contents.cipher_suites") - } - config.KeyConfig.CipherSuites = append(config.KeyConfig.CipherSuites, HPKESymmetricCipherSuite{kdfId, aeadId}) - } - - if !contentCryptobyte.ReadUint8(&config.MaximumNameLength) || - !contentCryptobyte.ReadUint8LengthPrefixed(&t) || - !t.ReadBytes(&config.PublicName, len(t)) || - !contentCryptobyte.ReadUint16LengthPrefixed(&t) || - !t.ReadBytes(&config.rawExtensions, len(t)) || - !contentCryptobyte.Empty() { - return config, errors.New("error parsing ECHConfigContents") - } - return config, nil -} - -func (echcc *ECHConfigContents) ParsePublicKey() error { - var err error - kem := hpke.KEM(echcc.KeyConfig.KemId) - if !kem.IsValid() { - return errors.New("invalid KEM") - } - echcc.KeyConfig.PublicKey, err = kem.Scheme().UnmarshalBinaryPublicKey(echcc.KeyConfig.rawPublicKey) - if err != nil { - return fmt.Errorf("error parsing public key: %s", err) - } - return nil -} - -type ECHConfig struct { - Version uint16 - Length uint16 - Contents ECHConfigContents - - raw []byte -} - -// UnmarshalECHConfigs parses a sequence of ECH configurations. -// -// Ported from cloudflare/go -func UnmarshalECHConfigs(raw []byte) ([]ECHConfig, error) { - var ( - err error - config ECHConfig - t, contents cryptobyte.String - ) - configs := make([]ECHConfig, 0) - s := cryptobyte.String(raw) - if !s.ReadUint16LengthPrefixed(&t) || !s.Empty() { - return configs, errors.New("error parsing configs") - } - raw = raw[2:] -ConfigsLoop: - for !t.Empty() { - l := len(t) - if !t.ReadUint16(&config.Version) || - !t.ReadUint16LengthPrefixed(&contents) { - return nil, errors.New("error parsing config") - } - config.Length = uint16(len(contents)) - n := l - len(t) - config.raw = raw[:n] - raw = raw[n:] - - if config.Version != utlsExtensionECH { - continue ConfigsLoop - } - - /**** cloudflare/go original ****/ - // if !readConfigContents(&contents, &config) { - // return nil, errors.New("error parsing config contents") - // } - - config.Contents, err = UnmarshalECHConfigContents(contents) - if err != nil { - return nil, fmt.Errorf("error parsing config contents: %s", err) - } - - /**** cloudflare/go original ****/ - // kem := hpke.KEM(config.kemId) - // if !kem.IsValid() { - // continue ConfigsLoop - // } - // config.pk, err = kem.Scheme().UnmarshalBinaryPublicKey(config.rawPublicKey) - // if err != nil { - // return nil, fmt.Errorf("error parsing public key: %s", err) - // } - - config.Contents.ParsePublicKey() // parse the bytes into a public key - - configs = append(configs, config) - } - return configs, nil -} diff --git a/u_handshake_client.go b/u_handshake_client.go index 5c34a0cd..9928f0c3 100644 --- a/u_handshake_client.go +++ b/u_handshake_client.go @@ -145,7 +145,6 @@ func (hs *clientHandshakeStateTLS13) sendClientEncryptedExtensions() error { func (hs *clientHandshakeStateTLS13) utlsReadServerParameters(encryptedExtensions *encryptedExtensionsMsg) error { hs.c.utls.peerApplicationSettings = encryptedExtensions.utls.applicationSettings hs.c.utls.applicationSettingsCodepoint = encryptedExtensions.utls.applicationSettingsCodepoint - hs.c.utls.echRetryConfigs = encryptedExtensions.utls.echRetryConfigs if hs.c.utls.applicationSettingsCodepoint != 0 { if hs.uconn.vers < VersionTLS13 { @@ -165,23 +164,6 @@ func (hs *clientHandshakeStateTLS13) utlsReadServerParameters(encryptedExtension } } - if len(hs.c.utls.echRetryConfigs) > 0 { - if hs.uconn.vers < VersionTLS13 { - return errors.New("tls: server sent ECH retry configs at invalid version") - } - - // find ECH extension in ClientHello - var echIncluded bool - for _, ext := range hs.uconn.Extensions { - if _, ok := ext.(ECHExtension); ok { - echIncluded = true - } - } - if !echIncluded { - return errors.New("tls: server sent ECH retry configs without client sending ECH extension") - } - } - return nil } diff --git a/u_handshake_messages.go b/u_handshake_messages.go index 9cdb480c..dd8a1d98 100644 --- a/u_handshake_messages.go +++ b/u_handshake_messages.go @@ -56,7 +56,6 @@ func (m *utlsCompressedCertificateMsg) unmarshal(data []byte) bool { type utlsEncryptedExtensionsMsgExtraFields struct { applicationSettings []byte applicationSettingsCodepoint uint16 - echRetryConfigs []ECHConfig customExtension []byte } @@ -67,12 +66,6 @@ func (m *encryptedExtensionsMsg) utlsUnmarshal(extension uint16, extData cryptob case utlsExtensionApplicationSettingsNew: m.utls.applicationSettingsCodepoint = extension m.utls.applicationSettings = []byte(extData) - case utlsExtensionECH: - var err error - m.utls.echRetryConfigs, err = UnmarshalECHConfigs([]byte(extData)) - if err != nil { - return false - } } return true // success/unknown extension } diff --git a/u_hpke.go b/u_hpke.go index 08d5eb4f..e07ada27 100644 --- a/u_hpke.go +++ b/u_hpke.go @@ -1,11 +1,7 @@ package tls import ( - "errors" - "fmt" - - "github.com/cloudflare/circl/hpke" - "github.com/cloudflare/circl/kem" + "github.com/refraction-networking/utls/internal/hpke" ) type HPKERawPublicKey = []byte @@ -18,45 +14,22 @@ type HPKESymmetricCipherSuite struct { AeadId HPKE_AEAD_ID } -type HPKEKeyConfig struct { - ConfigId uint8 - KemId HPKE_KEM_ID - PublicKey kem.PublicKey - rawPublicKey HPKERawPublicKey - CipherSuites []HPKESymmetricCipherSuite -} - -var defaultHPKESuite hpke.Suite - -func init() { - var err error - defaultHPKESuite, err = hpkeAssembleSuite( - uint16(hpke.KEM_X25519_HKDF_SHA256), - uint16(hpke.KDF_HKDF_SHA256), - uint16(hpke.AEAD_AES128GCM), - ) - if err != nil { - panic(fmt.Sprintf("hpke: mandatory-to-implement cipher suite not supported: %s", err)) - } -} - -func hpkeAssembleSuite(kemId, kdfId, aeadId uint16) (hpke.Suite, error) { - kem := hpke.KEM(kemId) - if !kem.IsValid() { - return hpke.Suite{}, errors.New("KEM is not supported") - } - kdf := hpke.KDF(kdfId) - if !kdf.IsValid() { - return hpke.Suite{}, errors.New("KDF is not supported") - } - aead := hpke.AEAD(aeadId) - if !aead.IsValid() { - return hpke.Suite{}, errors.New("AEAD is not supported") - } - return hpke.NewSuite(kem, kdf, aead), nil -} +const defaultHpkeKdf = hpke.KDF_HKDF_SHA256 +const defaultHpkeKem = hpke.DHKEM_X25519_HKDF_SHA256 +const defaultHpkeAead = hpke.AEAD_AES_128_GCM var dummyX25519PublicKey = []byte{ 143, 38, 37, 36, 12, 6, 229, 30, 140, 27, 167, 73, 26, 100, 203, 107, 216, 81, 163, 222, 52, 211, 54, 210, 46, 37, 78, 216, 157, 97, 241, 244, } + +// cipherLen returns the length of a ciphertext corresponding to a message of +// length mLen. +func cipherLen(a uint16, mLen int) int { + switch a { + case hpke.AEAD_AES_128_GCM, hpke.AEAD_AES_256_GCM, hpke.AEAD_ChaCha20Poly1305: + return mLen + 16 + default: + panic("hpke: invalid AEAD identifier") + } +} diff --git a/u_public.go b/u_public.go index 7f7633d7..724bdcd7 100644 --- a/u_public.go +++ b/u_public.go @@ -11,8 +11,6 @@ import ( "crypto/x509" "hash" "time" - - "github.com/cloudflare/circl/kem" ) // ClientHandshakeState includes both TLS 1.3-only and TLS 1.2-only states, @@ -854,14 +852,14 @@ func (TKS TicketKeys) ToPrivate() []ticketKey { } type kemPrivateKey struct { - secretKey kem.PrivateKey + secretKey any curveID CurveID } // Deprecated: Use KeySharePrivateKeys instead. This type is no longer used. // Will be removed in the future. type KemPrivateKey struct { - SecretKey kem.PrivateKey + SecretKey any CurveID CurveID }