| author | |
| committer | |
| log | aa73bb6bc969ef053a8fab265da8bf28e024b2d2 |
| tree | 464ec9bc857e5bacb896def9760909e5fc1aa3f8 |
| parent | fae742a6804fcd1e9c901a49d91f265a7b0c1709 |
| signature |
On decryption tls client should remove zero byte padding after the
content type field. This padding is rarely used, the only site (from the
list of top domains) that I found using it is `tutanota.com`.
From [RFC](https://datatracker.ietf.org/doc/html/rfc8446#section-5.4):
> All encrypted TLS records can be padded.
> Padding is a string of zero-valued bytes appended to the ContentType
field before encryption.
> the receiving implementation scans the field from the end toward the
beginning until it finds a non-zero octet. This non-zero octet is the
content type of the message.
Currently we can't connect to that site:
```
$ zig run main.zig -- tutanota.com
error: TlsInitializationFailed
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.208+854e86c56/lib/std/crypto/tls/Client.zig:476:45: 0x121fbed in init__anon_10331 (http_get_std)
if (inner_ct != .handshake) return error.TlsUnexpectedMessage;
^
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.208+854e86c56/lib/std/http/Client.zig:1357:99: 0x1161f0b in connectTcp (http_get_std)
conn.data.tls_client.* = std.crypto.tls.Client.init(stream, client.ca_bundle, host) catch return error.TlsInitializationFailed;
^
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.208+854e86c56/lib/std/http/Client.zig:1492:14: 0x11271e1 in connect (http_get_std)
} orelse return client.connectTcp(host, port, protocol);
^
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.208+854e86c56/lib/std/http/Client.zig:1640:9: 0x111a24e in open (http_get_std)
try client.connect(valid_uri.host.?.raw, uriPort(valid_uri, protocol), protocol);
^
/home/ianic/Code/tls.zig/example/http_get_std.zig:28:19: 0x1118f8c in main (http_get_std)
var req = try client.open(.GET, uri, .{ .server_header_buffer = &server_header_buffer });
^
```
using this example:
```zig
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
if (args.len > 1) {
const domain = args[1];
var client: std.http.Client = .{ .allocator = allocator };
defer client.deinit();
// Add https:// prefix if needed
const url = brk: {
const scheme = "https://";
if (domain.len >= scheme.len and std.mem.eql(u8, domain[0..scheme.len], scheme))
break :brk domain;
var url_buf: [128]u8 = undefined;
break :brk try std.fmt.bufPrint(&url_buf, "https://{s}", .{domain});
};
const uri = try std.Uri.parse(url);
var server_header_buffer: [16 * 1024]u8 = undefined;
var req = try client.open(.GET, uri, .{ .server_header_buffer = &server_header_buffer });
defer req.deinit();
try req.send();
try req.wait();
}
}
```1 files changed, 2 insertions(+), 2 deletions(-)
lib/std/crypto/tls/Client.zig+2-2| ... | @@ -468,7 +468,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In | ... | @@ -468,7 +468,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In |
| 468 | read_seq += 1; | 468 | read_seq += 1; |
| 469 | P.AEAD.decrypt(cleartext, ciphertext, auth_tag, record_header, nonce, p.server_handshake_key) catch | 469 | P.AEAD.decrypt(cleartext, ciphertext, auth_tag, record_header, nonce, p.server_handshake_key) catch |
| 470 | return error.TlsBadRecordMac; | 470 | return error.TlsBadRecordMac; |
| 471 | break :c cleartext; | 471 | break :c @constCast(mem.trimRight(u8, cleartext, "\x00")); |
| 472 | }, | 472 | }, |
| 473 | }; | 473 | }; |
| 474 | 474 | ||
| ... | @@ -1146,7 +1146,7 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.posix.iove | ... | @@ -1146,7 +1146,7 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.posix.iove |
| 1146 | const cleartext = cleartext_buf[0..ciphertext.len]; | 1146 | const cleartext = cleartext_buf[0..ciphertext.len]; |
| 1147 | P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, p.server_key) catch | 1147 | P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, p.server_key) catch |
| 1148 | return error.TlsBadRecordMac; | 1148 | return error.TlsBadRecordMac; |
| 1149 | break :c cleartext; | 1149 | break :c mem.trimRight(u8, cleartext, "\x00"); |
| 1150 | }, | 1150 | }, |
| 1151 | }; | 1151 | }; |
| 1152 | 1152 |