Skip to content

Commit 12a5808

Browse files
authored
Fix TLS 1.2 client key exchange to use negotiated named group (#25007)
The TLS 1.2 implementation was incorrectly hardcoded to always send the secp256r1 public key in the client key exchange message, regardless of which elliptic curve the server actually negotiated. This caused TLS handshake failures with servers that preferred other curves like X25519. This fix: - Tracks the negotiated named group from the server key exchange message - Dynamically selects the correct public key (X25519, secp256r1, or secp384r1) based on what the server negotiated - Properly constructs the client key exchange message with the appropriate key size for each curve type Fixes TLS 1.2 connections to servers like ziglang.freetls.fastly.net that prefer X25519 over secp256r1.
1 parent ae2622b commit 12a5808

File tree

1 file changed

+19
-6
lines changed

1 file changed

+19
-6
lines changed

lib/std/crypto/tls/Client.zig

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
320320
var handshake_state: HandshakeState = .hello;
321321
var handshake_cipher: tls.HandshakeCipher = undefined;
322322
var main_cert_pub_key: CertificatePublicKey = undefined;
323+
var tls12_negotiated_group: ?tls.NamedGroup = null;
323324
const now_sec = std.time.timestamp();
324325

325326
var cleartext_fragment_start: usize = 0;
@@ -679,6 +680,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
679680
const curve_type = hsd.decode(u8);
680681
if (curve_type != 0x03) return error.TlsIllegalParameter; // named_curve
681682
const named_group = hsd.decode(tls.NamedGroup);
683+
tls12_negotiated_group = named_group;
682684
const key_size = hsd.decode(u8);
683685
try hsd.ensure(key_size);
684686
const server_pub_key = hsd.slice(key_size);
@@ -691,10 +693,19 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
691693
if (cipher_state != .cleartext) return error.TlsUnexpectedMessage;
692694
if (handshake_state != .server_hello_done) return error.TlsUnexpectedMessage;
693695

694-
const client_key_exchange_msg = .{@intFromEnum(tls.ContentType.handshake)} ++
696+
const public_key_bytes: []const u8 = switch (tls12_negotiated_group orelse .secp256r1) {
697+
.secp256r1 => &key_share.secp256r1_kp.public_key.toUncompressedSec1(),
698+
.secp384r1 => &key_share.secp384r1_kp.public_key.toUncompressedSec1(),
699+
.x25519 => &key_share.x25519_kp.public_key,
700+
else => return error.TlsIllegalParameter,
701+
};
702+
703+
const client_key_exchange_prefix = .{@intFromEnum(tls.ContentType.handshake)} ++
695704
int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
696-
array(u16, u8, .{@intFromEnum(tls.HandshakeType.client_key_exchange)} ++
697-
array(u24, u8, array(u8, u8, key_share.secp256r1_kp.public_key.toUncompressedSec1())));
705+
int(u16, @intCast(public_key_bytes.len + 5)) ++ // record length
706+
.{@intFromEnum(tls.HandshakeType.client_key_exchange)} ++
707+
int(u24, @intCast(public_key_bytes.len + 1)) ++ // handshake message length
708+
.{@as(u8, @intCast(public_key_bytes.len))}; // public key length
698709
const client_change_cipher_spec_msg = .{@intFromEnum(tls.ContentType.change_cipher_spec)} ++
699710
int(u16, @intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
700711
array(u16, tls.ChangeCipherSpecType, .{.change_cipher_spec});
@@ -703,7 +714,8 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
703714
inline else => |*p| {
704715
const P = @TypeOf(p.*).A;
705716
p.transcript_hash.update(wrapped_handshake);
706-
p.transcript_hash.update(client_key_exchange_msg[tls.record_header_len..]);
717+
p.transcript_hash.update(client_key_exchange_prefix[tls.record_header_len..]);
718+
p.transcript_hash.update(public_key_bytes);
707719
const master_secret = hmacExpandLabel(P.Hmac, pre_master_secret, &.{
708720
"master secret",
709721
&client_hello_rand,
@@ -757,8 +769,9 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
757769
nonce,
758770
pv.app_cipher.client_write_key,
759771
);
760-
var all_msgs_vec: [3][]const u8 = .{
761-
&client_key_exchange_msg,
772+
var all_msgs_vec: [4][]const u8 = .{
773+
&client_key_exchange_prefix,
774+
public_key_bytes,
762775
&client_change_cipher_spec_msg,
763776
&client_verify_msg,
764777
};

0 commit comments

Comments
 (0)