authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-27 00:45:49-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-06-27 00:45:49-07:00
logd9e867172e85270d479fc1b00f42648bc0ca0179
treebfaaaf3c5cfe4e02b37e32e6c49a8836f8462c24
parent9343c31c3879514c890c9bfa2a1cd1a1f222ed6d
parent8239d3b358878ec4c0662a0dc2ccdc42c0e313c1
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16233 from jacobly0/tls

crypto.tls.Client: fix occasional crash in `readvAdvanced`

1 files changed, 31 insertions(+), 24 deletions(-)

lib/std/crypto/tls/Client.zig+31-24
......@@ -140,7 +140,7 @@ pub fn InitError(comptime Stream: type) type {
140140///
141141/// `host` is only borrowed during this function call.
142142pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) InitError(@TypeOf(stream))!Client {
143 const host_len = @as(u16, @intCast(host.len));
143 const host_len: u16 = @intCast(host.len);
144144
145145 var random_buffer: [128]u8 = undefined;
146146 crypto.random.bytes(&random_buffer);
......@@ -194,7 +194,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
194194 int2(host_len);
195195
196196 const extensions_header =
197 int2(@as(u16, @intCast(extensions_payload.len + host_len))) ++
197 int2(@intCast(extensions_payload.len + host_len)) ++
198198 extensions_payload;
199199
200200 const legacy_compression_methods = 0x0100;
......@@ -209,13 +209,13 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
209209
210210 const out_handshake =
211211 [_]u8{@intFromEnum(tls.HandshakeType.client_hello)} ++
212 int3(@as(u24, @intCast(client_hello.len + host_len))) ++
212 int3(@intCast(client_hello.len + host_len)) ++
213213 client_hello;
214214
215215 const plaintext_header = [_]u8{
216216 @intFromEnum(tls.ContentType.handshake),
217217 0x03, 0x01, // legacy_record_version
218 } ++ int2(@as(u16, @intCast(out_handshake.len + host_len))) ++ out_handshake;
218 } ++ int2(@intCast(out_handshake.len + host_len)) ++ out_handshake;
219219
220220 {
221221 var iovecs = [_]std.os.iovec_const{
......@@ -466,7 +466,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
466466 },
467467 };
468468
469 const inner_ct = @as(tls.ContentType, @enumFromInt(cleartext[cleartext.len - 1]));
469 const inner_ct: tls.ContentType = @enumFromInt(cleartext[cleartext.len - 1]);
470470 if (inner_ct != .handshake) return error.TlsUnexpectedMessage;
471471
472472 var ctd = tls.Decoder.fromTheirSlice(cleartext[0 .. cleartext.len - 1]);
......@@ -520,7 +520,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
520520
521521 const subject_cert: Certificate = .{
522522 .buffer = certd.buf,
523 .index = @as(u32, @intCast(certd.idx)),
523 .index = @intCast(certd.idx),
524524 };
525525 const subject = try subject_cert.parse();
526526 if (cert_index == 0) {
......@@ -534,7 +534,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
534534 if (pub_key.len > main_cert_pub_key_buf.len)
535535 return error.CertificatePublicKeyInvalid;
536536 @memcpy(main_cert_pub_key_buf[0..pub_key.len], pub_key);
537 main_cert_pub_key_len = @as(@TypeOf(main_cert_pub_key_len), @intCast(pub_key.len));
537 main_cert_pub_key_len = @intCast(pub_key.len);
538538 } else {
539539 try prev_cert.verify(subject, now_sec);
540540 }
......@@ -679,7 +679,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
679679 .write_seq = 0,
680680 .partial_cleartext_idx = 0,
681681 .partial_ciphertext_idx = 0,
682 .partial_ciphertext_end = @as(u15, @intCast(leftover.len)),
682 .partial_ciphertext_end = @intCast(leftover.len),
683683 .received_close_notify = false,
684684 .application_cipher = app_cipher,
685685 .partially_read_buffer = undefined,
......@@ -797,11 +797,11 @@ fn prepareCiphertextRecord(
797797 const overhead_len = tls.record_header_len + P.AEAD.tag_length + 1;
798798 const close_notify_alert_reserved = tls.close_notify_alert.len + overhead_len;
799799 while (true) {
800 const encrypted_content_len = @as(u16, @intCast(@min(
800 const encrypted_content_len: u16 = @intCast(@min(
801801 @min(bytes.len - bytes_i, max_ciphertext_len - 1),
802802 ciphertext_buf.len - close_notify_alert_reserved -
803803 overhead_len - ciphertext_end,
804 )));
804 ));
805805 if (encrypted_content_len == 0) return .{
806806 .iovec_end = iovec_end,
807807 .ciphertext_end = ciphertext_end,
......@@ -920,7 +920,7 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.os.iovec)
920920 // Give away the buffered cleartext we have, if any.
921921 const partial_cleartext = c.partially_read_buffer[c.partial_cleartext_idx..c.partial_ciphertext_idx];
922922 if (partial_cleartext.len > 0) {
923 const amt = @as(u15, @intCast(vp.put(partial_cleartext)));
923 const amt: u15 = @intCast(vp.put(partial_cleartext));
924924 c.partial_cleartext_idx += amt;
925925
926926 if (c.partial_cleartext_idx == c.partial_ciphertext_idx and
......@@ -958,6 +958,13 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.os.iovec)
958958 // The amount of the user's buffer that will be used to give cleartext. The
959959 // beginning of the buffer will be used for such purposes.
960960 const cleartext_buf_len = free_size - ciphertext_buf_len;
961
962 // Recoup `partially_read_buffer space`. This is necessary because it is assumed
963 // below that `frag0` is big enough to hold at least one record.
964 limitedOverlapCopy(c.partially_read_buffer[0..c.partial_ciphertext_end], c.partial_ciphertext_idx);
965 c.partial_ciphertext_end -= c.partial_ciphertext_idx;
966 c.partial_ciphertext_idx = 0;
967 c.partial_cleartext_idx = 0;
961968 const first_iov = c.partially_read_buffer[c.partial_ciphertext_end..];
962969
963970 var ask_iovecs_buf: [2]std.os.iovec = .{
......@@ -1037,7 +1044,7 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.os.iovec)
10371044 in = 0;
10381045 continue;
10391046 }
1040 const ct = @as(tls.ContentType, @enumFromInt(frag[in]));
1047 const ct: tls.ContentType = @enumFromInt(frag[in]);
10411048 in += 1;
10421049 const legacy_version = mem.readIntBig(u16, frag[in..][0..2]);
10431050 in += 2;
......@@ -1070,8 +1077,8 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.os.iovec)
10701077 switch (ct) {
10711078 .alert => {
10721079 if (in + 2 > frag.len) return error.TlsDecodeError;
1073 const level = @as(tls.AlertLevel, @enumFromInt(frag[in]));
1074 const desc = @as(tls.AlertDescription, @enumFromInt(frag[in + 1]));
1080 const level: tls.AlertLevel = @enumFromInt(frag[in]);
1081 const desc: tls.AlertDescription = @enumFromInt(frag[in + 1]);
10751082 _ = level;
10761083
10771084 try desc.toError();
......@@ -1105,11 +1112,11 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.os.iovec)
11051112
11061113 c.read_seq = try std.math.add(u64, c.read_seq, 1);
11071114
1108 const inner_ct = @as(tls.ContentType, @enumFromInt(cleartext[cleartext.len - 1]));
1115 const inner_ct: tls.ContentType = @enumFromInt(cleartext[cleartext.len - 1]);
11091116 switch (inner_ct) {
11101117 .alert => {
1111 const level = @as(tls.AlertLevel, @enumFromInt(cleartext[0]));
1112 const desc = @as(tls.AlertDescription, @enumFromInt(cleartext[1]));
1118 const level: tls.AlertLevel = @enumFromInt(cleartext[0]);
1119 const desc: tls.AlertDescription = @enumFromInt(cleartext[1]);
11131120 if (desc == .close_notify) {
11141121 c.received_close_notify = true;
11151122 c.partial_ciphertext_end = c.partial_ciphertext_idx;
......@@ -1124,7 +1131,7 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.os.iovec)
11241131 .handshake => {
11251132 var ct_i: usize = 0;
11261133 while (true) {
1127 const handshake_type = @as(tls.HandshakeType, @enumFromInt(cleartext[ct_i]));
1134 const handshake_type: tls.HandshakeType = @enumFromInt(cleartext[ct_i]);
11281135 ct_i += 1;
11291136 const handshake_len = mem.readIntBig(u24, cleartext[ct_i..][0..3]);
11301137 ct_i += 3;
......@@ -1186,13 +1193,13 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.os.iovec)
11861193 c.partially_read_buffer[c.partial_ciphertext_idx..][0..msg.len],
11871194 msg,
11881195 );
1189 c.partial_ciphertext_idx = @as(@TypeOf(c.partial_ciphertext_idx), @intCast(c.partial_ciphertext_idx + msg.len));
1196 c.partial_ciphertext_idx = @intCast(c.partial_ciphertext_idx + msg.len);
11901197 } else {
11911198 const amt = vp.put(msg);
11921199 if (amt < msg.len) {
11931200 const rest = msg[amt..];
11941201 c.partial_cleartext_idx = 0;
1195 c.partial_ciphertext_idx = @as(@TypeOf(c.partial_ciphertext_idx), @intCast(rest.len));
1202 c.partial_ciphertext_idx = @intCast(rest.len);
11961203 @memcpy(c.partially_read_buffer[0..rest.len], rest);
11971204 }
11981205 }
......@@ -1220,12 +1227,12 @@ fn finishRead(c: *Client, frag: []const u8, in: usize, out: usize) usize {
12201227 const saved_buf = frag[in..];
12211228 if (c.partial_ciphertext_idx > c.partial_cleartext_idx) {
12221229 // There is cleartext at the beginning already which we need to preserve.
1223 c.partial_ciphertext_end = @as(@TypeOf(c.partial_ciphertext_end), @intCast(c.partial_ciphertext_idx + saved_buf.len));
1230 c.partial_ciphertext_end = @intCast(c.partial_ciphertext_idx + saved_buf.len);
12241231 @memcpy(c.partially_read_buffer[c.partial_ciphertext_idx..][0..saved_buf.len], saved_buf);
12251232 } else {
12261233 c.partial_cleartext_idx = 0;
12271234 c.partial_ciphertext_idx = 0;
1228 c.partial_ciphertext_end = @as(@TypeOf(c.partial_ciphertext_end), @intCast(saved_buf.len));
1235 c.partial_ciphertext_end = @intCast(saved_buf.len);
12291236 @memcpy(c.partially_read_buffer[0..saved_buf.len], saved_buf);
12301237 }
12311238 return out;
......@@ -1235,14 +1242,14 @@ fn finishRead(c: *Client, frag: []const u8, in: usize, out: usize) usize {
12351242fn finishRead2(c: *Client, first: []const u8, frag1: []const u8, out: usize) usize {
12361243 if (c.partial_ciphertext_idx > c.partial_cleartext_idx) {
12371244 // There is cleartext at the beginning already which we need to preserve.
1238 c.partial_ciphertext_end = @as(@TypeOf(c.partial_ciphertext_end), @intCast(c.partial_ciphertext_idx + first.len + frag1.len));
1245 c.partial_ciphertext_end = @intCast(c.partial_ciphertext_idx + first.len + frag1.len);
12391246 // TODO: eliminate this call to copyForwards
12401247 std.mem.copyForwards(u8, c.partially_read_buffer[c.partial_ciphertext_idx..][0..first.len], first);
12411248 @memcpy(c.partially_read_buffer[c.partial_ciphertext_idx + first.len ..][0..frag1.len], frag1);
12421249 } else {
12431250 c.partial_cleartext_idx = 0;
12441251 c.partial_ciphertext_idx = 0;
1245 c.partial_ciphertext_end = @as(@TypeOf(c.partial_ciphertext_end), @intCast(first.len + frag1.len));
1252 c.partial_ciphertext_end = @intCast(first.len + frag1.len);
12461253 // TODO: eliminate this call to copyForwards
12471254 std.mem.copyForwards(u8, c.partially_read_buffer[0..first.len], first);
12481255 @memcpy(c.partially_read_buffer[first.len..][0..frag1.len], frag1);