authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-11-02 02:45:12-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-11-07 20:25:26-05:00
log7afb2777250a251a065b8a970eb7f14e2d5b5ce2
tree90a778fca9e850330aa238748b7d830ee36a9127
parent7f20c78c95d54e7fb0958693a9df2dee40dd99d6

std.crypto.tls: fix x25519_ml_kem768 key share

This is mostly nfc cleanup as I was bisecting the client hello to find the problematic part, and the only bug fix ended up being key_share.x25519_kp.public_key ++ key_share.ml_kem768_kp.public_key.toBytes() to key_share.ml_kem768_kp.public_key.toBytes() ++ key_share.x25519_kp.public_key) and the same swap in `KeyShare.exchange` as per some random blog that says "a hybrid keyshare, constructed by concatenating the public KEM key with the public X25519 key". I also note that based on the same blog post, there was a draft version of this method that indeed had these values swapped, and that used to be supported by this code, but it was not properly fixed up when this code was updated from the draft spec. Closes #21747

2 files changed, 135 insertions(+), 138 deletions(-)

lib/std/crypto/tls.zig+43-24
......@@ -291,6 +291,12 @@ pub const NamedGroup = enum(u16) {
291291 _,
292292};
293293
294pub const PskKeyExchangeMode = enum(u8) {
295 psk_ke = 0,
296 psk_dhe_ke = 1,
297 _,
298};
299
294300pub const CipherSuite = enum(u16) {
295301 RSA_WITH_AES_128_CBC_SHA = 0x002F,
296302 DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033,
......@@ -407,6 +413,11 @@ pub const CipherSuite = enum(u16) {
407413 }
408414};
409415
416pub const CompressionMethod = enum(u8) {
417 null = 0,
418 _,
419};
420
410421pub const CertificateType = enum(u8) {
411422 X509 = 0,
412423 RawPublicKey = 2,
......@@ -419,6 +430,11 @@ pub const KeyUpdateRequest = enum(u8) {
419430 _,
420431};
421432
433pub const ChangeCipherSpecType = enum(u8) {
434 change_cipher_spec = 1,
435 _,
436};
437
422438pub fn HandshakeCipherT(comptime AeadType: type, comptime HashType: type, comptime explicit_iv_length: comptime_int) type {
423439 return struct {
424440 pub const A = ApplicationCipherT(AeadType, HashType, explicit_iv_length);
......@@ -560,34 +576,38 @@ pub fn hmac(comptime Hmac: type, message: []const u8, key: [Hmac.key_length]u8)
560576 return result;
561577}
562578
563pub inline fn extension(comptime et: ExtensionType, bytes: anytype) [2 + 2 + bytes.len]u8 {
564 return int2(@intFromEnum(et)) ++ array(1, bytes);
565}
566
567pub inline fn array(comptime elem_size: comptime_int, bytes: anytype) [2 + bytes.len]u8 {
568 comptime assert(bytes.len % elem_size == 0);
569 return int2(bytes.len) ++ bytes;
579pub inline fn extension(et: ExtensionType, bytes: anytype) [2 + 2 + bytes.len]u8 {
580 return int(u16, @intFromEnum(et)) ++ array(u16, u8, bytes);
570581}
571582
572pub inline fn enum_array(comptime E: type, comptime tags: []const E) [2 + @sizeOf(E) * tags.len]u8 {
573 assert(@sizeOf(E) == 2);
574 var result: [tags.len * 2]u8 = undefined;
575 for (tags, 0..) |elem, i| {
576 result[i * 2] = @as(u8, @truncate(@intFromEnum(elem) >> 8));
577 result[i * 2 + 1] = @as(u8, @truncate(@intFromEnum(elem)));
583pub inline fn array(
584 comptime Len: type,
585 comptime Elem: type,
586 elems: anytype,
587) [@divExact(@bitSizeOf(Len), 8) + @divExact(@bitSizeOf(Elem), 8) * elems.len]u8 {
588 const len_size = @divExact(@bitSizeOf(Len), 8);
589 const elem_size = @divExact(@bitSizeOf(Elem), 8);
590 var arr: [len_size + elem_size * elems.len]u8 = undefined;
591 std.mem.writeInt(Len, arr[0..len_size], @intCast(elem_size * elems.len), .big);
592 const ElemInt = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(Elem) } });
593 for (0.., @as([elems.len]Elem, elems)) |index, elem| {
594 std.mem.writeInt(
595 ElemInt,
596 arr[len_size + elem_size * index ..][0..elem_size],
597 switch (@typeInfo(Elem)) {
598 .int => @as(Elem, elem),
599 .@"enum" => @intFromEnum(@as(Elem, elem)),
600 else => @bitCast(@as(Elem, elem)),
601 },
602 .big,
603 );
578604 }
579 return array(2, result);
580}
581
582pub inline fn int2(int: u16) [2]u8 {
583 var arr: [2]u8 = undefined;
584 std.mem.writeInt(u16, &arr, int, .big);
585605 return arr;
586606}
587607
588pub inline fn int3(int: u24) [3]u8 {
589 var arr: [3]u8 = undefined;
590 std.mem.writeInt(u24, &arr, int, .big);
608pub inline fn int(comptime Int: type, val: Int) [@divExact(@bitSizeOf(Int), 8)]u8 {
609 var arr: [@divExact(@bitSizeOf(Int), 8)]u8 = undefined;
610 std.mem.writeInt(Int, &arr, val, .big);
591611 return arr;
592612}
593613
......@@ -670,9 +690,8 @@ pub const Decoder = struct {
670690 else => @compileError("unsupported int type: " ++ @typeName(T)),
671691 },
672692 .@"enum" => |info| {
673 const int = d.decode(info.tag_type);
674693 if (info.is_exhaustive) @compileError("exhaustive enum cannot be used");
675 return @as(T, @enumFromInt(int));
694 return @enumFromInt(d.decode(info.tag_type));
676695 },
677696 else => @compileError("unsupported type: " ++ @typeName(T)),
678697 }
lib/std/crypto/tls/Client.zig+92-114
......@@ -10,10 +10,8 @@ const Certificate = std.crypto.Certificate;
1010const max_ciphertext_len = tls.max_ciphertext_len;
1111const hmacExpandLabel = tls.hmacExpandLabel;
1212const hkdfExpandLabel = tls.hkdfExpandLabel;
13const int2 = tls.int2;
14const int3 = tls.int3;
13const int = tls.int;
1514const array = tls.array;
16const enum_array = tls.enum_array;
1715
1816tls_version: tls.ProtocolVersion,
1917read_seq: u64,
......@@ -156,70 +154,62 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
156154 error.IdentityElement => return error.InsufficientEntropy,
157155 };
158156
159 const extensions_payload =
160 tls.extension(.supported_versions, [_]u8{2 + 2} ++ // byte length of supported versions
161 int2(@intFromEnum(tls.ProtocolVersion.tls_1_3)) ++
162 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2))) ++
163 tls.extension(.signature_algorithms, enum_array(tls.SignatureScheme, &.{
157 const extensions_payload = tls.extension(.supported_versions, array(u8, tls.ProtocolVersion, .{
158 .tls_1_3,
159 .tls_1_2,
160 })) ++ tls.extension(.signature_algorithms, array(u16, tls.SignatureScheme, .{
164161 .ecdsa_secp256r1_sha256,
165162 .ecdsa_secp384r1_sha384,
166163 .rsa_pss_rsae_sha256,
167164 .rsa_pss_rsae_sha384,
168165 .rsa_pss_rsae_sha512,
169166 .ed25519,
170 })) ++ tls.extension(.supported_groups, enum_array(tls.NamedGroup, &.{
167 })) ++ tls.extension(.supported_groups, array(u16, tls.NamedGroup, .{
171168 .x25519_ml_kem768,
172169 .secp256r1,
173170 .x25519,
174 })) ++ tls.extension(
175 .key_share,
176 array(1, int2(@intFromEnum(tls.NamedGroup.x25519)) ++
177 array(1, key_share.x25519_kp.public_key) ++
178 int2(@intFromEnum(tls.NamedGroup.secp256r1)) ++
179 array(1, key_share.secp256r1_kp.public_key.toUncompressedSec1()) ++
180 int2(@intFromEnum(tls.NamedGroup.x25519_ml_kem768)) ++
181 array(1, key_share.x25519_kp.public_key ++ key_share.ml_kem768_kp.public_key.toBytes())),
182 ) ++
183 int2(@intFromEnum(tls.ExtensionType.server_name)) ++
184 int2(host_len + 5) ++ // byte length of this extension payload
185 int2(host_len + 3) ++ // server_name_list byte count
186 [1]u8{0x00} ++ // name_type
187 int2(host_len);
171 })) ++ tls.extension(.psk_key_exchange_modes, array(u8, tls.PskKeyExchangeMode, .{
172 .psk_dhe_ke,
173 })) ++ tls.extension(.key_share, array(
174 u16,
175 u8,
176 int(u16, @intFromEnum(tls.NamedGroup.x25519_ml_kem768)) ++
177 array(u16, u8, key_share.ml_kem768_kp.public_key.toBytes() ++ key_share.x25519_kp.public_key) ++
178 int(u16, @intFromEnum(tls.NamedGroup.secp256r1)) ++
179 array(u16, u8, key_share.secp256r1_kp.public_key.toUncompressedSec1()) ++
180 int(u16, @intFromEnum(tls.NamedGroup.x25519)) ++
181 array(u16, u8, key_share.x25519_kp.public_key),
182 )) ++ int(u16, @intFromEnum(tls.ExtensionType.server_name)) ++
183 int(u16, 2 + 1 + 2 + host_len) ++ // byte length of this extension payload
184 int(u16, 1 + 2 + host_len) ++ // server_name_list byte count
185 .{0x00} ++ // name_type
186 int(u16, host_len);
188187
189188 const extensions_header =
190 int2(@intCast(extensions_payload.len + host_len)) ++
189 int(u16, @intCast(extensions_payload.len + host_len)) ++
191190 extensions_payload;
192191
193 const legacy_compression_methods = 0x0100;
194
195192 const client_hello =
196 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
193 int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
197194 client_hello_rand ++
198195 [1]u8{32} ++ legacy_session_id ++
199196 cipher_suites ++
200 int2(legacy_compression_methods) ++
197 array(u8, tls.CompressionMethod, .{.null}) ++
201198 extensions_header;
202199
203 const out_handshake =
204 [_]u8{@intFromEnum(tls.HandshakeType.client_hello)} ++
205 int3(@intCast(client_hello.len + host_len)) ++
200 const out_handshake = .{@intFromEnum(tls.HandshakeType.client_hello)} ++
201 int(u24, @intCast(client_hello.len + host_len)) ++
206202 client_hello;
207203
208 const cleartext_header = [_]u8{@intFromEnum(tls.ContentType.handshake)} ++
209 int2(@intFromEnum(tls.ProtocolVersion.tls_1_0)) ++ // legacy_record_version
210 int2(@intCast(out_handshake.len + host_len)) ++
204 const cleartext_header = .{@intFromEnum(tls.ContentType.handshake)} ++
205 int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_0)) ++
206 int(u16, @intCast(out_handshake.len + host_len)) ++
211207 out_handshake;
212208
213209 {
214210 var iovecs = [_]std.posix.iovec_const{
215 .{
216 .base = &cleartext_header,
217 .len = cleartext_header.len,
218 },
219 .{
220 .base = host.ptr,
221 .len = host.len,
222 },
211 .{ .base = &cleartext_header, .len = cleartext_header.len },
212 .{ .base = host.ptr, .len = host.len },
223213 };
224214 try stream.writevAll(&iovecs);
225215 }
......@@ -526,7 +516,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
526516 },
527517 .change_cipher_spec => {
528518 try ctd.ensure(1);
529 if (ctd.decode(u8) != 0x01) return error.TlsIllegalParameter;
519 if (ctd.decode(tls.ChangeCipherSpecType) != .change_cipher_spec) return error.TlsIllegalParameter;
530520 cipher_state = pending_cipher_state;
531521 },
532522 .handshake => while (true) {
......@@ -648,20 +638,13 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
648638 if (handshake_state != .server_hello_done) return error.TlsUnexpectedMessage;
649639 handshake_state = .finished;
650640
651 const client_key_exchange_msg =
652 [_]u8{@intFromEnum(tls.ContentType.handshake)} ++ // record content type
653 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
654 int2(0x46) ++ // record length
655 .{@intFromEnum(tls.HandshakeType.client_key_exchange)} ++ // handshake type
656 int3(0x42) ++ // params length
657 .{0x41} ++ // pubkey length
658 key_share.secp256r1_kp.public_key.toUncompressedSec1();
659 // This message is to trick buggy proxies into behaving correctly.
660 const client_change_cipher_spec_msg =
661 [_]u8{@intFromEnum(tls.ContentType.change_cipher_spec)} ++ // record content type
662 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
663 int2(1) ++ // record length
664 .{0x01};
641 const client_key_exchange_msg = .{@intFromEnum(tls.ContentType.handshake)} ++
642 int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
643 array(u16, u8, .{@intFromEnum(tls.HandshakeType.client_key_exchange)} ++
644 array(u24, u8, array(u8, u8, key_share.secp256r1_kp.public_key.toUncompressedSec1())));
645 const client_change_cipher_spec_msg = .{@intFromEnum(tls.ContentType.change_cipher_spec)} ++
646 int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
647 array(u16, tls.ChangeCipherSpecType, .{.change_cipher_spec});
665648 const pre_master_secret = key_share.getSharedSecret().?;
666649 switch (handshake_cipher) {
667650 inline else => |*p| {
......@@ -680,10 +663,13 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
680663 @sizeOf(P.Tls_1_2),
681664 );
682665 const verify_data_len = 12;
683 const client_verify_cleartext =
684 [_]u8{@intFromEnum(tls.HandshakeType.finished)} ++ // handshake type
685 int3(verify_data_len) ++ // verify data length
686 hmacExpandLabel(P.Hmac, &master_secret, &.{ "client finished", &p.transcript_hash.peek() }, verify_data_len);
666 const client_verify_cleartext = .{@intFromEnum(tls.HandshakeType.finished)} ++
667 array(u24, u8, hmacExpandLabel(
668 P.Hmac,
669 &master_secret,
670 &.{ "client finished", &p.transcript_hash.peek() },
671 verify_data_len,
672 ));
687673 p.transcript_hash.update(&client_verify_cleartext);
688674 p.version = .{ .tls_1_2 = .{
689675 .server_verify_data = hmacExpandLabel(
......@@ -709,25 +695,23 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
709695 const operand: V = pad ++ @as([8]u8, @bitCast(big(write_seq)));
710696 break :nonce @as(V, pv.app_cipher.client_write_IV ++ pv.app_cipher.client_salt) ^ operand;
711697 };
712 var client_verify_msg = [_]u8{@intFromEnum(tls.ContentType.handshake)} ++ // record content type
713 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
714 int2(P.record_iv_length + client_verify_cleartext.len + P.mac_length) ++ // record length
715 nonce[P.fixed_iv_length..].* ++
716 @as([client_verify_cleartext.len + P.mac_length]u8, undefined);
698 var client_verify_msg = .{@intFromEnum(tls.ContentType.handshake)} ++
699 int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
700 array(u16, u8, nonce[P.fixed_iv_length..].* ++
701 @as([client_verify_cleartext.len + P.mac_length]u8, undefined));
717702 P.AEAD.encrypt(
718703 client_verify_msg[client_verify_msg.len - P.mac_length -
719704 client_verify_cleartext.len ..][0..client_verify_cleartext.len],
720705 client_verify_msg[client_verify_msg.len - P.mac_length ..][0..P.mac_length],
721706 &client_verify_cleartext,
722 std.mem.toBytes(big(write_seq)) ++ client_verify_msg[0 .. 1 + 2] ++ int2(client_verify_cleartext.len),
707 std.mem.toBytes(big(write_seq)) ++ client_verify_msg[0 .. 1 + 2] ++ int(u16, client_verify_cleartext.len),
723708 nonce,
724709 pv.app_cipher.client_write_key,
725710 );
726711 const all_msgs = client_key_exchange_msg ++ client_change_cipher_spec_msg ++ client_verify_msg;
727 var all_msgs_vec = [_]std.posix.iovec_const{.{
728 .base = &all_msgs,
729 .len = all_msgs.len,
730 }};
712 var all_msgs_vec = [_]std.posix.iovec_const{
713 .{ .base = &all_msgs, .len = all_msgs.len },
714 };
731715 try stream.writevAll(&all_msgs_vec);
732716 },
733717 }
......@@ -755,11 +739,9 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
755739 if (cipher_state == .cleartext) return error.TlsUnexpectedMessage;
756740 if (handshake_state != .finished) return error.TlsUnexpectedMessage;
757741 // This message is to trick buggy proxies into behaving correctly.
758 const client_change_cipher_spec_msg =
759 [_]u8{@intFromEnum(tls.ContentType.change_cipher_spec)} ++
760 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
761 int2(1) ++ // length
762 .{0x01};
742 const client_change_cipher_spec_msg = .{@intFromEnum(tls.ContentType.change_cipher_spec)} ++
743 int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
744 array(u16, tls.ChangeCipherSpecType, .{.change_cipher_spec});
763745 const app_cipher = app_cipher: switch (handshake_cipher) {
764746 inline else => |*p, tag| switch (tls_version) {
765747 .tls_1_3 => {
......@@ -771,17 +753,15 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
771753 if (!mem.eql(u8, &expected_server_verify_data, hsd.buf)) return error.TlsDecryptError;
772754 const handshake_hash = p.transcript_hash.finalResult();
773755 const verify_data = tls.hmac(P.Hmac, &handshake_hash, pv.client_finished_key);
774 const out_cleartext = [_]u8{
775 @intFromEnum(tls.HandshakeType.finished),
776 0, 0, verify_data.len, // length
777 } ++ verify_data ++ [1]u8{@intFromEnum(tls.ContentType.handshake)};
756 const out_cleartext = .{@intFromEnum(tls.HandshakeType.finished)} ++
757 array(u24, u8, verify_data) ++
758 .{@intFromEnum(tls.ContentType.handshake)};
778759
779760 const wrapped_len = out_cleartext.len + P.AEAD.tag_length;
780761
781 var finished_msg = [_]u8{@intFromEnum(tls.ContentType.application_data)} ++
782 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
783 int2(wrapped_len) ++ // byte length of encrypted record
784 @as([wrapped_len]u8, undefined);
762 var finished_msg = .{@intFromEnum(tls.ContentType.application_data)} ++
763 int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
764 array(u16, u8, @as([wrapped_len]u8, undefined));
785765
786766 const ad = finished_msg[0..tls.record_header_len];
787767 const ciphertext = finished_msg[tls.record_header_len..][0..out_cleartext.len];
......@@ -790,10 +770,9 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
790770 P.AEAD.encrypt(ciphertext, auth_tag, &out_cleartext, ad, nonce, pv.client_handshake_key);
791771
792772 const all_msgs = client_change_cipher_spec_msg ++ finished_msg;
793 var all_msgs_vec = [_]std.posix.iovec_const{.{
794 .base = &all_msgs,
795 .len = all_msgs.len,
796 }};
773 var all_msgs_vec = [_]std.posix.iovec_const{
774 .{ .base = &all_msgs, .len = all_msgs.len },
775 };
797776 try stream.writevAll(&all_msgs_vec);
798777
799778 const client_secret = hkdfExpandLabel(P.Hkdf, pv.master_secret, "c ap traffic", &handshake_hash, P.Hash.digest_length);
......@@ -965,10 +944,9 @@ fn prepareCiphertextRecord(
965944
966945 const record_start = ciphertext_end;
967946 const ad = ciphertext_buf[ciphertext_end..][0..tls.record_header_len];
968 ad.* =
969 [_]u8{@intFromEnum(tls.ContentType.application_data)} ++
970 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
971 int2(ciphertext_len + P.AEAD.tag_length);
947 ad.* = .{@intFromEnum(tls.ContentType.application_data)} ++
948 int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
949 int(u16, ciphertext_len + P.AEAD.tag_length);
972950 ciphertext_end += ad.len;
973951 const ciphertext = ciphertext_buf[ciphertext_end..][0..ciphertext_len];
974952 ciphertext_end += ciphertext_len;
......@@ -1023,10 +1001,10 @@ fn prepareCiphertextRecord(
10231001 const record_start = ciphertext_end;
10241002 const record_header = ciphertext_buf[ciphertext_end..][0..tls.record_header_len];
10251003 ciphertext_end += tls.record_header_len;
1026 record_header.* = [_]u8{@intFromEnum(inner_content_type)} ++
1027 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
1028 int2(P.record_iv_length + message_len + P.mac_length);
1029 const ad = std.mem.toBytes(big(c.write_seq)) ++ record_header[0 .. 1 + 2] ++ int2(message_len);
1004 record_header.* = .{@intFromEnum(inner_content_type)} ++
1005 int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
1006 int(u16, P.record_iv_length + message_len + P.mac_length);
1007 const ad = std.mem.toBytes(big(c.write_seq)) ++ record_header[0 .. 1 + 2] ++ int(u16, message_len);
10301008 const record_iv = ciphertext_buf[ciphertext_end..][0..P.record_iv_length];
10311009 ciphertext_end += P.record_iv_length;
10321010 const nonce: [P.AEAD.nonce_length]u8 = if (builtin.zig_backend == .stage2_x86_64 and
......@@ -1569,25 +1547,17 @@ const KeyShare = struct {
15691547 ) error{ TlsIllegalParameter, TlsDecryptFailure }!void {
15701548 switch (named_group) {
15711549 .x25519_ml_kem768 => {
1572 const xksl = crypto.dh.X25519.public_length;
1573 const hksl = xksl + crypto.kem.ml_kem.MLKem768.ciphertext_length;
1574 if (server_pub_key.len != hksl) return error.TlsIllegalParameter;
1550 const hksl = crypto.kem.ml_kem.MLKem768.ciphertext_length;
1551 const xksl = hksl + crypto.dh.X25519.public_length;
1552 if (server_pub_key.len != xksl) return error.TlsIllegalParameter;
15751553
1576 const xsk = crypto.dh.X25519.scalarmult(ks.x25519_kp.secret_key, server_pub_key[0..xksl].*) catch
1554 const hsk = ks.ml_kem768_kp.secret_key.decaps(server_pub_key[0..hksl]) catch
15771555 return error.TlsDecryptFailure;
1578 const hsk = ks.ml_kem768_kp.secret_key.decaps(server_pub_key[xksl..hksl]) catch
1556 const xsk = crypto.dh.X25519.scalarmult(ks.x25519_kp.secret_key, server_pub_key[hksl..xksl].*) catch
15791557 return error.TlsDecryptFailure;
1580 @memcpy(ks.sk_buf[0..xsk.len], &xsk);
1581 @memcpy(ks.sk_buf[xsk.len..][0..hsk.len], &hsk);
1582 ks.sk_len = xsk.len + hsk.len;
1583 },
1584 .x25519 => {
1585 const ksl = crypto.dh.X25519.public_length;
1586 if (server_pub_key.len != ksl) return error.TlsIllegalParameter;
1587 const sk = crypto.dh.X25519.scalarmult(ks.x25519_kp.secret_key, server_pub_key[0..ksl].*) catch
1588 return error.TlsDecryptFailure;
1589 @memcpy(ks.sk_buf[0..sk.len], &sk);
1590 ks.sk_len = sk.len;
1558 @memcpy(ks.sk_buf[0..hsk.len], &hsk);
1559 @memcpy(ks.sk_buf[hsk.len..][0..xsk.len], &xsk);
1560 ks.sk_len = hsk.len + xsk.len;
15911561 },
15921562 .secp256r1 => {
15931563 const PublicKey = crypto.sign.ecdsa.EcdsaP256Sha256.PublicKey;
......@@ -1598,6 +1568,14 @@ const KeyShare = struct {
15981568 @memcpy(ks.sk_buf[0..sk.len], &sk);
15991569 ks.sk_len = sk.len;
16001570 },
1571 .x25519 => {
1572 const ksl = crypto.dh.X25519.public_length;
1573 if (server_pub_key.len != ksl) return error.TlsIllegalParameter;
1574 const sk = crypto.dh.X25519.scalarmult(ks.x25519_kp.secret_key, server_pub_key[0..ksl].*) catch
1575 return error.TlsDecryptFailure;
1576 @memcpy(ks.sk_buf[0..sk.len], &sk);
1577 ks.sk_len = sk.len;
1578 },
16011579 else => return error.TlsIllegalParameter,
16021580 }
16031581 }
......@@ -1877,7 +1855,7 @@ fn limitVecs(iovecs: []std.posix.iovec, len: usize) []std.posix.iovec {
18771855/// aes128-gcm: 138 MiB/s
18781856/// aes256-gcm: 120 MiB/s
18791857const cipher_suites = if (crypto.core.aes.has_hardware_support)
1880 enum_array(tls.CipherSuite, &.{
1858 array(u16, tls.CipherSuite, .{
18811859 .AEGIS_128L_SHA256,
18821860 .AEGIS_256_SHA512,
18831861 .AES_128_GCM_SHA256,
......@@ -1888,7 +1866,7 @@ const cipher_suites = if (crypto.core.aes.has_hardware_support)
18881866 .ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
18891867 })
18901868else
1891 enum_array(tls.CipherSuite, &.{
1869 array(u16, tls.CipherSuite, .{
18921870 .CHACHA20_POLY1305_SHA256,
18931871 .ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
18941872 .AEGIS_128L_SHA256,