Skip to content

Commit dbca939

Browse files
committed
feat: generate different ecdhe key for pq key
When the client sends both pq and non-pq keyshares, the ecdhe key was reused in line with stdlib. However this can be used to fingerprint utls ClientHellos. Generate different ecdhe keys instead, in line with Chrome. This will have to change when we support more browsers with different ways of handling this.
1 parent a7bb5ea commit dbca939

File tree

4 files changed

+50
-29
lines changed

4 files changed

+50
-29
lines changed

handshake_client_tls13.go

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"bytes"
99
"context"
1010
"crypto"
11+
"crypto/ecdh"
1112
"crypto/hmac"
1213
"crypto/mlkem"
1314
"crypto/rsa"
@@ -562,6 +563,22 @@ func (hs *clientHandshakeStateTLS13) processServerHello() error {
562563
return nil
563564
}
564565

566+
// [uTLS] SECTION BEGIN
567+
func getSharedKey(peerData []byte, key *ecdh.PrivateKey) ([]byte, error) {
568+
peerKey, err := key.Curve().NewPublicKey(peerData)
569+
if err != nil {
570+
return nil, errors.New("tls: invalid server key share")
571+
}
572+
sharedKey, err := key.ECDH(peerKey)
573+
if err != nil {
574+
return nil, errors.New("tls: invalid server key share")
575+
}
576+
577+
return sharedKey, nil
578+
}
579+
580+
// [uTLS] SECTION END
581+
565582
func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
566583
c := hs.c
567584

@@ -581,13 +598,8 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
581598
}
582599
ecdhePeerData = hs.serverHello.serverShare.data[:x25519PublicKeySize]
583600
}
601+
sharedKey, err := getSharedKey(ecdhePeerData, hs.keyShareKeys.ecdhe)
584602
// [uTLS] SECTION END
585-
peerKey, err := hs.keyShareKeys.ecdhe.Curve().NewPublicKey(ecdhePeerData)
586-
if err != nil {
587-
c.sendAlert(alertIllegalParameter)
588-
return errors.New("tls: invalid server key share")
589-
}
590-
sharedKey, err := hs.keyShareKeys.ecdhe.ECDH(peerKey)
591603
if err != nil {
592604
c.sendAlert(alertIllegalParameter)
593605
return errors.New("tls: invalid server key share")
@@ -596,6 +608,14 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
596608
if hs.keyShareKeys.mlkem == nil {
597609
return c.sendAlert(alertInternalError)
598610
}
611+
// [uTLS] SECTION BEGIN
612+
if hs.uconn != nil && hs.uconn.clientHelloBuildStatus == BuildByUtls {
613+
if sharedKey, err = getSharedKey(ecdhePeerData, hs.keyShareKeys.mlkemEcdhe); err != nil {
614+
c.sendAlert(alertIllegalParameter)
615+
return errors.New("tls: invalid server key share")
616+
}
617+
}
618+
// [uTLS] SECTION END
599619
ciphertext := hs.serverHello.serverShare.data[:mlkem.CiphertextSize768]
600620
mlkemShared, err := hs.keyShareKeys.mlkem.Decapsulate(ciphertext)
601621
if err != nil {
@@ -609,6 +629,12 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
609629
if hs.keyShareKeys.mlkem == nil {
610630
return c.sendAlert(alertInternalError)
611631
}
632+
if hs.uconn != nil && hs.uconn.clientHelloBuildStatus == BuildByUtls {
633+
if sharedKey, err = getSharedKey(ecdhePeerData, hs.keyShareKeys.mlkemEcdhe); err != nil {
634+
c.sendAlert(alertIllegalParameter)
635+
return errors.New("tls: invalid server key share")
636+
}
637+
}
612638
ciphertext := hs.serverHello.serverShare.data[x25519PublicKeySize:]
613639
kyberShared, err := kyberDecapsulate(hs.keyShareKeys.mlkem, ciphertext)
614640
if err != nil {

key_schedule.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ func (c *cipherSuiteTLS13) exportKeyingMaterial(s *tls13.MasterSecret, transcrip
5151
}
5252

5353
type keySharePrivateKeys struct {
54-
curveID CurveID
55-
ecdhe *ecdh.PrivateKey
56-
mlkem *mlkem.DecapsulationKey768
54+
curveID CurveID
55+
ecdhe *ecdh.PrivateKey
56+
mlkem *mlkem.DecapsulationKey768
57+
mlkemEcdhe *ecdh.PrivateKey // [uTLS] seperate ecdhe key for pq keyshare in line with Chrome, instead of reusing ecdhe key like stdlib
5758
}
5859

5960
const x25519PublicKeySize = 32

u_parrots.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2830,17 +2830,8 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error {
28302830
} else {
28312831
ext.KeyShares[i].Data = append(mlkemKey.EncapsulationKey().Bytes(), ecdheKey.PublicKey().Bytes()...)
28322832
}
2833-
if !preferredCurveIsSet {
2834-
// only do this once for the first non-grease curve
2835-
uconn.HandshakeState.State13.KeyShareKeys.mlkem = mlkemKey
2836-
preferredCurveIsSet = true
2837-
}
2838-
2839-
if len(ext.KeyShares) > i+1 && ext.KeyShares[i+1].Group == X25519 {
2840-
// Reuse the same X25519 ephemeral key for both keyshares, as allowed by draft-ietf-tls-hybrid-design-09, Section 3.2.
2841-
uconn.HandshakeState.State13.KeyShareKeys.Ecdhe = ecdheKey
2842-
ext.KeyShares[i+1].Data = ecdheKey.PublicKey().Bytes()
2843-
}
2833+
uconn.HandshakeState.State13.KeyShareKeys.mlkem = mlkemKey
2834+
uconn.HandshakeState.State13.KeyShareKeys.mlkemEcdhe = ecdheKey
28442835
} else {
28452836
ecdheKey, err := generateECDHEKey(uconn.config.rand(), curveID)
28462837
if err != nil {

u_public.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -888,19 +888,21 @@ func (kpk *kemPrivateKey) ToPublic() *KemPrivateKey {
888888
}
889889

890890
type KeySharePrivateKeys struct {
891-
CurveID CurveID
892-
Ecdhe *ecdh.PrivateKey
893-
mlkem *mlkem.DecapsulationKey768
891+
CurveID CurveID
892+
Ecdhe *ecdh.PrivateKey
893+
mlkem *mlkem.DecapsulationKey768
894+
mlkemEcdhe *ecdh.PrivateKey
894895
}
895896

896897
func (ksp *KeySharePrivateKeys) ToPrivate() *keySharePrivateKeys {
897898
if ksp == nil {
898899
return nil
899900
}
900901
return &keySharePrivateKeys{
901-
curveID: ksp.CurveID,
902-
ecdhe: ksp.Ecdhe,
903-
mlkem: ksp.mlkem,
902+
curveID: ksp.CurveID,
903+
ecdhe: ksp.Ecdhe,
904+
mlkem: ksp.mlkem,
905+
mlkemEcdhe: ksp.mlkemEcdhe,
904906
}
905907
}
906908

@@ -909,8 +911,9 @@ func (ksp *keySharePrivateKeys) ToPublic() *KeySharePrivateKeys {
909911
return nil
910912
}
911913
return &KeySharePrivateKeys{
912-
CurveID: ksp.curveID,
913-
Ecdhe: ksp.ecdhe,
914-
mlkem: ksp.mlkem,
914+
CurveID: ksp.curveID,
915+
Ecdhe: ksp.ecdhe,
916+
mlkem: ksp.mlkem,
917+
mlkemEcdhe: ksp.mlkemEcdhe,
915918
}
916919
}

0 commit comments

Comments
 (0)