Skip to content

Commit 7186a96

Browse files
mingyechMingye Chen
authored andcommitted
feat: add option to reuse keyshares for hybrid key
1 parent 689ddce commit 7186a96

2 files changed

Lines changed: 78 additions & 49 deletions

File tree

u_parrots.go

Lines changed: 68 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,8 +1521,8 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
15211521
},
15221522
},
15231523
&SCTExtension{},
1524-
&KeyShareExtension{
1525-
KeyShares: []KeyShare{
1524+
&KeyShareExtensionExtended{
1525+
KeyShareExtension: &KeyShareExtension{KeyShares: []KeyShare{
15261526
{
15271527
Group: X25519MLKEM768,
15281528
},
@@ -1532,7 +1532,8 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
15321532
{
15331533
Group: CurveP256,
15341534
},
1535-
},
1535+
}},
1536+
HybridReuseKey: true,
15361537
},
15371538
&SupportedVersionsExtension{
15381539
Versions: []uint16{
@@ -2998,52 +2999,12 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error {
29982999
}
29993000
}
30003001
case *KeyShareExtension:
3001-
preferredCurveIsSet := false
3002-
for i := range ext.KeyShares {
3003-
curveID := ext.KeyShares[i].Group
3004-
if isGREASEUint16(uint16(curveID)) { // just in case the user set a GREASE value instead of unGREASEd
3005-
ext.KeyShares[i].Group = CurveID(GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_group))
3006-
continue
3007-
}
3008-
if len(ext.KeyShares[i].Data) > 1 {
3009-
continue
3010-
}
3011-
3012-
if curveID == X25519MLKEM768 || curveID == X25519Kyber768Draft00 {
3013-
ecdheKey, err := generateECDHEKey(uconn.config.rand(), X25519)
3014-
if err != nil {
3015-
return err
3016-
}
3017-
seed := make([]byte, mlkem.SeedSize)
3018-
if _, err := io.ReadFull(uconn.config.rand(), seed); err != nil {
3019-
return err
3020-
}
3021-
mlkemKey, err := mlkem.NewDecapsulationKey768(seed)
3022-
if err != nil {
3023-
return err
3024-
}
3025-
3026-
if curveID == X25519Kyber768Draft00 {
3027-
ext.KeyShares[i].Data = append(ecdheKey.PublicKey().Bytes(), mlkemKey.EncapsulationKey().Bytes()...)
3028-
} else {
3029-
ext.KeyShares[i].Data = append(mlkemKey.EncapsulationKey().Bytes(), ecdheKey.PublicKey().Bytes()...)
3030-
}
3031-
uconn.HandshakeState.State13.KeyShareKeys.Mlkem = mlkemKey
3032-
uconn.HandshakeState.State13.KeyShareKeys.MlkemEcdhe = ecdheKey
3033-
} else {
3034-
ecdheKey, err := generateECDHEKey(uconn.config.rand(), curveID)
3035-
if err != nil {
3036-
return fmt.Errorf("unsupported Curve in KeyShareExtension: %v."+
3037-
"To mimic it, fill the Data(key) field manually", curveID)
3038-
}
3039-
3040-
ext.KeyShares[i].Data = ecdheKey.PublicKey().Bytes()
3041-
if !preferredCurveIsSet {
3042-
// only do this once for the first non-grease curve
3043-
uconn.HandshakeState.State13.KeyShareKeys.Ecdhe = ecdheKey
3044-
preferredCurveIsSet = true
3045-
}
3046-
}
3002+
if err := uconn.setKeyShare(&KeyShareExtensionExtended{KeyShareExtension: ext}); err != nil {
3003+
return err
3004+
}
3005+
case *KeyShareExtensionExtended:
3006+
if err := uconn.setKeyShare(ext); err != nil {
3007+
return err
30473008
}
30483009
case *SupportedVersionsExtension:
30493010
for i := range ext.Versions {
@@ -3364,3 +3325,61 @@ func removeRC4Ciphers(s []uint16) []uint16 {
33643325
}
33653326
return s[:sliceLen]
33663327
}
3328+
3329+
func (uconn *UConn) setKeyShare(ext *KeyShareExtensionExtended) error {
3330+
preferredCurveIsSet := false
3331+
for i := range ext.KeyShares {
3332+
curveID := ext.KeyShares[i].Group
3333+
if isGREASEUint16(uint16(curveID)) { // just in case the user set a GREASE value instead of unGREASEd
3334+
ext.KeyShares[i].Group = CurveID(GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_group))
3335+
continue
3336+
}
3337+
if len(ext.KeyShares[i].Data) > 1 {
3338+
continue
3339+
}
3340+
3341+
if curveID == X25519MLKEM768 || curveID == X25519Kyber768Draft00 {
3342+
ecdheKey, err := generateECDHEKey(uconn.config.rand(), X25519)
3343+
if err != nil {
3344+
return err
3345+
}
3346+
seed := make([]byte, mlkem.SeedSize)
3347+
if _, err := io.ReadFull(uconn.config.rand(), seed); err != nil {
3348+
return err
3349+
}
3350+
mlkemKey, err := mlkem.NewDecapsulationKey768(seed)
3351+
if err != nil {
3352+
return err
3353+
}
3354+
3355+
if curveID == X25519Kyber768Draft00 {
3356+
ext.KeyShares[i].Data = append(ecdheKey.PublicKey().Bytes(), mlkemKey.EncapsulationKey().Bytes()...)
3357+
} else {
3358+
ext.KeyShares[i].Data = append(mlkemKey.EncapsulationKey().Bytes(), ecdheKey.PublicKey().Bytes()...)
3359+
}
3360+
uconn.HandshakeState.State13.KeyShareKeys.Mlkem = mlkemKey
3361+
uconn.HandshakeState.State13.KeyShareKeys.MlkemEcdhe = ecdheKey
3362+
3363+
if ext.HybridReuseKey && len(ext.KeyShares) > i+1 && ext.KeyShares[i+1].Group == X25519 {
3364+
preferredCurveIsSet = true
3365+
uconn.HandshakeState.State13.KeyShareKeys.Ecdhe = ecdheKey
3366+
ext.KeyShares[i+1].Data = ecdheKey.PublicKey().Bytes()
3367+
}
3368+
} else {
3369+
ecdheKey, err := generateECDHEKey(uconn.config.rand(), curveID)
3370+
if err != nil {
3371+
return fmt.Errorf("unsupported Curve in KeyShareExtension: %v."+
3372+
"To mimic it, fill the Data(key) field manually", curveID)
3373+
}
3374+
3375+
ext.KeyShares[i].Data = ecdheKey.PublicKey().Bytes()
3376+
if !preferredCurveIsSet {
3377+
// only do this once for the first non-grease curve
3378+
uconn.HandshakeState.State13.KeyShareKeys.Ecdhe = ecdheKey
3379+
preferredCurveIsSet = true
3380+
}
3381+
}
3382+
}
3383+
3384+
return nil
3385+
}

u_tls_extensions.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,16 @@ func (e *UtlsCompressCertExtension) UnmarshalJSON(b []byte) error {
12261226
return nil
12271227
}
12281228

1229+
// Same as KeyShareExtension with extra options added without breaking users that
1230+
// use positional struct literal for KeyShareExtension
1231+
type KeyShareExtensionExtended struct {
1232+
*KeyShareExtension
1233+
1234+
// whether to reuse keys for the same algorithm for hybrid key shares with traditional key shares
1235+
// according to draft-ietf-tls-hybrid-design-14 section 3.2
1236+
HybridReuseKey bool
1237+
}
1238+
12291239
// KeyShareExtension implements key_share (51) and is for TLS 1.3 only.
12301240
type KeyShareExtension struct {
12311241
KeyShares []KeyShare

0 commit comments

Comments
 (0)