From d24af4ae558608c82b070eb593477948879765f0 Mon Sep 17 00:00:00 2001 From: Mingye Chen Date: Sat, 1 Mar 2025 19:18:24 -0700 Subject: [PATCH] update: rm cf KEMkey & KeySharesParams in TLS13OnlyState These can be set and read via KeySharePrivateKeys. While the breakage is unfortunate for backwards compatibility, it is already unavoidable in one direction: the cloudflare kem key does not store the mlkem seed and is therefore incompatible with crypto/mlkem. --- handshake_client.go | 2 - handshake_client_tls13.go | 87 +++------------------------------------ u_alias.go | 29 +++++++++++++ u_parrots.go | 10 ----- u_public.go | 73 ++++++++++---------------------- 5 files changed, 55 insertions(+), 146 deletions(-) diff --git a/handshake_client.go b/handshake_client.go index f523c6a..91cf41b 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -381,8 +381,6 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { earlySecret: earlySecret, binderKey: binderKey, echContext: ech, - - keySharesParams: NewKeySharesParameters(), // [uTLS] } return hs.handshake() } diff --git a/handshake_client_tls13.go b/handshake_client_tls13.go index 99fd6ea..5b1fb18 100644 --- a/handshake_client_tls13.go +++ b/handshake_client_tls13.go @@ -8,7 +8,6 @@ import ( "bytes" "context" "crypto" - "crypto/ecdh" "crypto/hmac" "crypto/mlkem" "crypto/rsa" @@ -19,74 +18,16 @@ import ( "slices" "time" - "github.com/cloudflare/circl/kem" "github.com/refraction-networking/utls/internal/hkdf" "github.com/refraction-networking/utls/internal/tls13" ) -// [uTLS SECTION START] -// KeySharesParameters serves as a in-memory storage for generated keypairs by UTLS when generating -// ClientHello. It is used to store both ecdhe and kem keypairs. -type KeySharesParameters struct { - ecdhePrivKeymap map[CurveID]*ecdh.PrivateKey - ecdhePubKeymap map[CurveID]*ecdh.PublicKey - - // based on cloudflare/go - kemPrivKeymap map[CurveID]kem.PrivateKey - kemPubKeymap map[CurveID]kem.PublicKey -} - -func NewKeySharesParameters() *KeySharesParameters { - return &KeySharesParameters{ - ecdhePrivKeymap: make(map[CurveID]*ecdh.PrivateKey), - ecdhePubKeymap: make(map[CurveID]*ecdh.PublicKey), - - kemPrivKeymap: make(map[CurveID]kem.PrivateKey), - kemPubKeymap: make(map[CurveID]kem.PublicKey), - } -} - -func (ksp *KeySharesParameters) AddEcdheKeypair(curveID CurveID, ecdheKey *ecdh.PrivateKey, ecdhePubKey *ecdh.PublicKey) { - ksp.ecdhePrivKeymap[curveID] = ecdheKey - ksp.ecdhePubKeymap[curveID] = ecdhePubKey -} - -func (ksp *KeySharesParameters) GetEcdheKey(curveID CurveID) (ecdheKey *ecdh.PrivateKey, ok bool) { - ecdheKey, ok = ksp.ecdhePrivKeymap[curveID] - return -} - -func (ksp *KeySharesParameters) GetEcdhePubkey(curveID CurveID) (params *ecdh.PublicKey, ok bool) { - params, ok = ksp.ecdhePubKeymap[curveID] - return -} - -func (ksp *KeySharesParameters) AddKemKeypair(curveID CurveID, kemKey kem.PrivateKey, kemPubKey kem.PublicKey) { - // if curveID == x25519Kyber768Draft00 { // only store for x25519Kyber768Draft00 - // ksp.kemPrivKeymap[curveID] = kemKey - // ksp.kemPubKeymap[curveID] = kemPubKey - // } -} - -func (ksp *KeySharesParameters) GetKemKey(curveID CurveID) (kemKey kem.PrivateKey, ok bool) { - kemKey, ok = ksp.kemPrivKeymap[curveID] - return -} - -func (ksp *KeySharesParameters) GetKemPubkey(curveID CurveID) (params kem.PublicKey, ok bool) { - params, ok = ksp.kemPubKeymap[curveID] - return -} - -// [uTLS SECTION END] - type clientHandshakeStateTLS13 struct { - c *Conn - ctx context.Context - serverHello *serverHelloMsg - hello *clientHelloMsg - keyShareKeys *keySharePrivateKeys - keySharesParams *KeySharesParameters // [uTLS] support both ecdhe and kem + c *Conn + ctx context.Context + serverHello *serverHelloMsg + hello *clientHelloMsg + keyShareKeys *keySharePrivateKeys session *SessionState earlySecret *tls13.EarlySecret @@ -117,24 +58,6 @@ func (hs *clientHandshakeStateTLS13) handshake() error { return errors.New("tls: server selected TLS 1.3 in a renegotiation") } - // [uTLS SECTION START] - // if hs.keyShareKeys == nil { - // // set echdheParams to what we received from server - // if ecdheKey, ok := hs.keySharesParams.GetEcdheKey(hs.serverHello.serverShare.group); ok { - // hs.keyShareKeys.ecdhe = ecdheKey - // hs.keyShareKeys.curveID = hs.serverHello.serverShare.group - // } - // // set kemParams to what we received from server - // if kemKey, ok := hs.keySharesParams.GetKemKey(hs.serverHello.serverShare.group); ok { - // if kyberKey, ecdhKey, err := mlkemCirclToGo(kemKey); err == nil { - // hs.keyShareKeys.kyber = kyberKey - // hs.keyShareKeys.ecdhe = ecdhKey - // hs.keyShareKeys.curveID = hs.serverHello.serverShare.group - // } - // } - // } - // [uTLS SECTION END] - // Consistency check on the presence of a keyShare and its parameters. if hs.keyShareKeys == nil || hs.keyShareKeys.ecdhe == nil || len(hs.hello.keyShares) == 0 { return c.sendAlert(alertInternalError) diff --git a/u_alias.go b/u_alias.go index af579c2..7cf5d16 100644 --- a/u_alias.go +++ b/u_alias.go @@ -1,5 +1,11 @@ package tls +import ( + "crypto/ecdh" + + "github.com/cloudflare/circl/kem" +) + // This file contains all the alias functions, symbols, names, etc. that // was once used in the old version of the library. This is to ensure // backwards compatibility with the old version of the library. @@ -10,3 +16,26 @@ package tls // // Deprecated: Use ExtendedMasterSecretExtension instead. type UtlsExtendedMasterSecretExtension = ExtendedMasterSecretExtension + +// Deprecated: Use KeySharePrivateKeys instead. This type is not used and will be removed in the future. +// KeySharesParameters serves as a in-memory storage for generated keypairs by UTLS when generating +// ClientHello. It is used to store both ecdhe and kem keypairs. +type KeySharesParameters struct{} + +func NewKeySharesParameters() *KeySharesParameters { return &KeySharesParameters{} } + +func (*KeySharesParameters) AddEcdheKeypair(curveID CurveID, ecdheKey *ecdh.PrivateKey, ecdhePubKey *ecdh.PublicKey) { + return +} + +func (*KeySharesParameters) GetEcdheKey(curveID CurveID) (ecdheKey *ecdh.PrivateKey, ok bool) { return } + +func (*KeySharesParameters) GetEcdhePubkey(curveID CurveID) (params *ecdh.PublicKey, ok bool) { return } + +func (*KeySharesParameters) AddKemKeypair(curveID CurveID, kemKey kem.PrivateKey, kemPubKey kem.PublicKey) { + return +} + +func (ksp *KeySharesParameters) GetKemKey(curveID CurveID) (kemKey kem.PrivateKey, ok bool) { return } + +func (ksp *KeySharesParameters) GetKemPubkey(curveID CurveID) (params kem.PublicKey, ok bool) { return } diff --git a/u_parrots.go b/u_parrots.go index 69c2636..38e7607 100644 --- a/u_parrots.go +++ b/u_parrots.go @@ -2636,7 +2636,6 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error { } else { uconn.HandshakeState.State13.KeyShareKeys = &KeySharePrivateKeys{} } - uconn.HandshakeState.State13.KeySharesParams = NewKeySharesParameters() uconn.echCtx = ech hello := uconn.HandshakeState.Hello @@ -2750,12 +2749,6 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error { return err } - // circlKyberKey, err := kyberGoToCircl(kyberKey, ecdheKey) - // if err != nil { - // return err - // } - // uconn.HandshakeState.State13.KeySharesParams.AddKemKeypair(curveID, circlKyberKey, circlKyberKey.Public()) - if curveID == X25519Kyber768Draft00 { ext.KeyShares[i].Data = append(ecdheKey.PublicKey().Bytes(), mlkemKey.EncapsulationKey().Bytes()...) } else { @@ -2770,7 +2763,6 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error { if len(ext.KeyShares) > i+1 && ext.KeyShares[i+1].Group == X25519 { // Reuse the same X25519 ephemeral key for both keyshares, as allowed by draft-ietf-tls-hybrid-design-09, Section 3.2. uconn.HandshakeState.State13.KeyShareKeys.Ecdhe = ecdheKey - // uconn.HandshakeState.State13.KeySharesParams.AddEcdheKeypair(curveID, ecdheKey, ecdheKey.PublicKey()) ext.KeyShares[i+1].Data = ecdheKey.PublicKey().Bytes() } } else { @@ -2780,8 +2772,6 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error { "To mimic it, fill the Data(key) field manually", curveID) } - // uconn.HandshakeState.State13.KeySharesParams.AddEcdheKeypair(curveID, ecdheKey, ecdheKey.PublicKey()) - ext.KeyShares[i].Data = ecdheKey.PublicKey().Bytes() if !preferredCurveIsSet { // only do this once for the first non-grease curve diff --git a/u_public.go b/u_public.go index a9e851c..f223596 100644 --- a/u_public.go +++ b/u_public.go @@ -41,9 +41,13 @@ type PubClientHandshakeState struct { type TLS13OnlyState struct { // Deprecated: Use KeyShareKeys instead. KeyShareKeys will take precedence if both are set. // Support may be removed in the future. - EcdheKey *ecdh.PrivateKey + EcdheKey *ecdh.PrivateKey + // Deprecated: Use KeyShareKeys instead. This variable is no longer used. + // Will be removed in the future. KeySharesParams *KeySharesParameters - KEMKey *KemPrivateKey + // Deprecated: Use KeyShareKeys instead. This variable is no longer used. + // Will be removed in the future. + KEMKey *KemPrivateKey KeyShareKeys *KeySharePrivateKeys Suite *PubCipherSuiteTLS13 @@ -62,46 +66,11 @@ type TLS12OnlyState struct { Suite PubCipherSuite } -// func mlkemCirclToGo(circlKey kem.PrivateKey) (*mlkem768.DecapsulationKey, *ecdh.PrivateKey, error) { -// if circlKey.Scheme().Name() != "Kyber768-X25519" { -// return nil, nil, fmt.Errorf("circl key is not Kyber768-X25519") -// } - -// encodedKey, err := circlKey.MarshalBinary() -// if err != nil { -// return nil, nil, err -// } - -// ecdhKey := encodedKey[:x25519PublicKeySize] -// kyberKey := encodedKey[x25519PublicKeySize:] - -// goKyberkey, err := mlkem768.NewKeyFromExtendedEncoding(kyberKey) -// if err != nil { -// return nil, nil, err -// } - -// goEcdhKey, err := ecdh.X25519().NewPrivateKey(ecdhKey) -// if err != nil { -// return nil, nil, err -// } - -// return goKyberkey, goEcdhKey, nil -// } - func (chs *TLS13OnlyState) private13KeyShareKeys() *keySharePrivateKeys { if chs.KeyShareKeys != nil { return chs.KeyShareKeys.ToPrivate() } - // if chs.KEMKey != nil { - // if kyberKey, ecdhKey, err := mlkemCirclToGo(chs.KEMKey.SecretKey); err == nil { - // return &keySharePrivateKeys{ - // kyber: kyberKey, - // ecdhe: ecdhKey, - // } - // } - // } - if chs.EcdheKey != nil { return &keySharePrivateKeys{ ecdhe: chs.EcdheKey, @@ -120,11 +89,10 @@ func (chs *PubClientHandshakeState) toPrivate13() *clientHandshakeStateTLS13 { return nil } else { return &clientHandshakeStateTLS13{ - c: chs.C, - serverHello: chs.ServerHello.getPrivatePtr(), - hello: chs.Hello.getPrivatePtr(), - keyShareKeys: chs.State13.private13KeyShareKeys(), - keySharesParams: chs.State13.KeySharesParams, + c: chs.C, + serverHello: chs.ServerHello.getPrivatePtr(), + hello: chs.Hello.getPrivatePtr(), + keyShareKeys: chs.State13.private13KeyShareKeys(), session: chs.Session, binderKey: chs.State13.BinderKey, @@ -146,16 +114,15 @@ func (chs13 *clientHandshakeStateTLS13) toPublic13() *PubClientHandshakeState { return nil } else { tls13State := TLS13OnlyState{ - KeySharesParams: chs13.keySharesParams, - KeyShareKeys: chs13.keyShareKeys.ToPublic(), - EarlySecret: chs13.earlySecret.Secret(), - BinderKey: chs13.binderKey, - CertReq: chs13.certReq.toPublic(), - UsingPSK: chs13.usingPSK, - SentDummyCCS: chs13.sentDummyCCS, - Suite: chs13.suite.toPublic(), - TrafficSecret: chs13.trafficSecret, - Transcript: chs13.transcript, + KeyShareKeys: chs13.keyShareKeys.ToPublic(), + EarlySecret: chs13.earlySecret.Secret(), + BinderKey: chs13.binderKey, + CertReq: chs13.certReq.toPublic(), + UsingPSK: chs13.usingPSK, + SentDummyCCS: chs13.sentDummyCCS, + Suite: chs13.suite.toPublic(), + TrafficSecret: chs13.trafficSecret, + Transcript: chs13.transcript, } return &PubClientHandshakeState{ C: chs13.c, @@ -891,6 +858,8 @@ type kemPrivateKey struct { curveID CurveID } +// Deprecated: Use KeySharePrivateKeys instead. This type is no longer used. +// Will be removed in the future. type KemPrivateKey struct { SecretKey kem.PrivateKey CurveID CurveID