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.
This commit is contained in:
Mingye Chen 2025-03-01 19:18:24 -07:00
parent 9fada94f7e
commit d24af4ae55
5 changed files with 55 additions and 146 deletions

View file

@ -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()
}

View file

@ -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)

View file

@ -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 }

View file

@ -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

View file

@ -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