@@ -1474,21 +1474,35 @@ add_selected_version(Extensions) ->
1474
1474
Extensions #{server_hello_selected_version => SupportedVersions }.
1475
1475
1476
1476
kse_remove_private_key (# key_share_entry {
1477
- group = Group ,
1478
- key_exchange =
1479
- # 'ECPrivateKey' {publicKey = PublicKey }}) ->
1477
+ group = Group ,
1478
+ key_exchange =
1479
+ # 'ECPrivateKey' {publicKey = PublicKey }}) ->
1480
1480
# key_share_entry {
1481
1481
group = Group ,
1482
1482
key_exchange = PublicKey };
1483
1483
kse_remove_private_key (# key_share_entry {
1484
- group = Group ,
1485
- key_exchange =
1486
- {PublicKey , _ }}) ->
1484
+ group = Group ,
1485
+ key_exchange =
1486
+ {# 'ECPrivateKey' {publicKey = PublicKey1 },
1487
+ {PublicKey2 , _ }}}) ->
1488
+ # key_share_entry {
1489
+ group = Group ,
1490
+ key_exchange = <<PublicKey1 /binary , PublicKey2 /binary >>};
1491
+ kse_remove_private_key (# key_share_entry {
1492
+ group = Group ,
1493
+ key_exchange =
1494
+ {{PublicKey1 , _ }, {PublicKey2 , _ }}}) ->
1495
+ # key_share_entry {
1496
+ group = Group ,
1497
+ key_exchange = <<PublicKey1 /binary , PublicKey2 /binary >>};
1498
+ kse_remove_private_key (# key_share_entry {
1499
+ group = Group ,
1500
+ key_exchange =
1501
+ {PublicKey , _ }}) ->
1487
1502
# key_share_entry {
1488
1503
group = Group ,
1489
1504
key_exchange = PublicKey }.
1490
1505
1491
-
1492
1506
signature_algs_ext (undefined ) ->
1493
1507
undefined ;
1494
1508
signature_algs_ext (SignatureSchemes0 ) ->
@@ -2665,7 +2679,6 @@ encode_versions(Versions) ->
2665
2679
2666
2680
encode_client_shares (ClientShares ) ->
2667
2681
<< << (encode_key_share_entry (KeyShareEntry0 ))/binary >> || KeyShareEntry0 <- ClientShares >>.
2668
-
2669
2682
encode_key_share_entry (# key_share_entry {group = Group ,
2670
2683
key_exchange = KeyExchange }) ->
2671
2684
Len = byte_size (KeyExchange ),
@@ -3057,13 +3070,15 @@ decode_extensions(<<?UINT16(?KEY_SHARE_EXT), ?UINT16(Len),
3057
3070
decode_extensions (<<? UINT16 (? KEY_SHARE_EXT ), ? UINT16 (Len ),
3058
3071
ExtData :Len /binary , Rest /binary >>,
3059
3072
Version , MessageType = server_hello , Acc ) ->
3060
- <<? UINT16 (Group ),? UINT16 (KeyLen ),KeyExchange :KeyLen /binary >> = ExtData ,
3073
+ <<? UINT16 (EnumGroup ),? UINT16 (KeyLen ),KeyExchange0 :KeyLen /binary >> = ExtData ,
3074
+ Group = tls_v1 :enum_to_group (EnumGroup ),
3075
+ KeyExchange = maybe_dec_server_hybrid_share (Group , KeyExchange0 ),
3061
3076
decode_extensions (Rest , Version , MessageType ,
3062
3077
Acc #{key_share =>
3063
3078
# key_share_server_hello {
3064
3079
server_share =
3065
3080
# key_share_entry {
3066
- group = tls_v1 : enum_to_group ( Group ) ,
3081
+ group = Group ,
3067
3082
key_exchange = KeyExchange }}});
3068
3083
3069
3084
decode_extensions (<<? UINT16 (? KEY_SHARE_EXT ), ? UINT16 (Len ),
@@ -3204,8 +3219,53 @@ dec_hashsign(Value) ->
3204
3219
[HashSign ] = decode_sign_alg (? TLS_1_2 , Value ),
3205
3220
HashSign .
3206
3221
3222
+ maybe_dec_server_hybrid_share (x25519mlkem768 , <<MLKem :1088 /binary , X25519 :32 /binary >>) ->
3223
+ % % Concatenation of an ML-KEM ciphertext returned from
3224
+ % % encapsulation to the client's encapsulation key The size of the
3225
+ % % server share is 1120 bytes (1088 bytes for the ML-KEM part and
3226
+ % % 32 bytes for X25519).
3227
+ % % Note exception algorithm should be in reveres order of name due to legacy reason
3228
+ {MLKem , X25519 };
3229
+ maybe_dec_server_hybrid_share (secp256r1mlkem768 , <<Secp256r1 :65 /binary , MLKem :1088 /binary >>) ->
3230
+ % % Concatenation of the server's ephemeral secp256r1 share encoded
3231
+ % % in the same way as the client share and an ML-KEM The size of
3232
+ % % the server share is 1153 bytes (1088 bytes for the ML-KEM part
3233
+ % % and 65 bytes for secp256r1).
3234
+ {Secp256r1 , MLKem };
3235
+ maybe_dec_server_hybrid_share (secp384r1mlkem1024 , <<Secp384r1 :97 /binary , MLKem :1568 /binary >>) ->
3236
+ % % Concatenation of the server's ephemeral secp384r1 share encoded
3237
+ % % in the same way as the client share and an ML-KEM ciphertext
3238
+ % % returned from encapsulation to the client's encapsulation key
3239
+ % % The size of the server share is 1665 bytes (1568 bytes for the
3240
+ % % ML-KEM part and 97 bytes for secp384r1)
3241
+ {Secp384r1 , MLKem };
3242
+ maybe_dec_server_hybrid_share (_ , Share ) ->
3243
+ % % Not hybrid
3244
+ Share .
3245
+
3246
+ maybe_dec_client_hybrid_share (x25519mlkem768 , <<MLKem :1184 /binary , X25519 :32 /binary >>) ->
3247
+ % % Concatenation of the client's ML-KEM-768 encapsulation key and
3248
+ % % the client's X25519 ephemeral share. The size of the client share
3249
+ % % is 1216 bytes (1184 bytes for the ML-KEM part and 32 bytes for
3250
+ % % X25519).
3251
+ % % Note exception algorithm should be in reveres order of name due to legacy reason
3252
+ {MLKem , X25519 };
3253
+ maybe_dec_client_hybrid_share (secp256r1mlkem768 , <<Secp256r1 :65 /binary , MLKem :1184 /binary >>) ->
3254
+ % % Concatenation of the secp256r1 ephemeral share and ML-KEM-768
3255
+ % % encapsulation key The size of the client share is 1249 bytes (65
3256
+ % % bytes for the secp256r1 part and 1184 bytes for ML-KEM). Ignore
3257
+ % % unknown names (only host_name is supported)
3258
+ {Secp256r1 , MLKem };
3259
+ maybe_dec_client_hybrid_share (secp384r1mlkem1024 , <<Secp384r1 :97 /binary , MLKem :1568 /binary >>) ->
3260
+ % % Concatenation of the secp384r1 ephemeral share and the
3261
+ % % ML-KEM-1024 encapsulation key. The size of the client share
3262
+ % % is 1665 bytes (97 bytes for the secp384r1 and the 1568 for the
3263
+ % % ML-KEM).
3264
+ {Secp384r1 , MLKem };
3265
+ maybe_dec_client_hybrid_share (_ , Share ) ->
3266
+ % % Not hybrid
3267
+ Share .
3207
3268
3208
- % % Ignore unknown names (only host_name is supported)
3209
3269
dec_sni (<<? BYTE (? SNI_NAMETYPE_HOST_NAME ), ? UINT16 (Len ),
3210
3270
HostName :Len /binary , _ /binary >>) ->
3211
3271
# sni {hostname = binary_to_list (HostName )};
@@ -3231,12 +3291,13 @@ decode_client_shares(ClientShares) ->
3231
3291
% %
3232
3292
decode_client_shares (<<>>, Acc ) ->
3233
3293
lists :reverse (Acc );
3234
- decode_client_shares (<<? UINT16 (Group0 ),? UINT16 (Len ),KeyExchange :Len /binary ,Rest /binary >>, Acc ) ->
3294
+ decode_client_shares (<<? UINT16 (Group0 ),? UINT16 (Len ),KeyExchange0 :Len /binary ,Rest /binary >>, Acc ) ->
3235
3295
case tls_v1 :enum_to_group (Group0 ) of
3236
3296
undefined ->
3237
3297
% % Ignore key_share with unknown group
3238
3298
decode_client_shares (Rest , Acc );
3239
3299
Group ->
3300
+ KeyExchange = maybe_dec_client_hybrid_share (Group , KeyExchange0 ),
3240
3301
decode_client_shares (Rest , [# key_share_entry {
3241
3302
group = Group ,
3242
3303
key_exchange = KeyExchange
0 commit comments