@@ -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+ }
0 commit comments