How can I use the std.http.Client to open a connection with a self-signed certificate?
I can see that std.crypto.tls.Client has an option for self_signed, but I have no ideea how to use that when opening a http.client connection.
Welcome to ziggit @gturta
Unfortunately there is no way to override the tls options. Http client always uses the .bundle
setting:
There is another way to test tls connections. Instead of using self-signed certificates you can create a test certificate authority, trust the test certificate authority from your clients and issue real signed certificates.
I highly recommend mkcert
for managing your test certificates.
Hello again.
I can’t seem to be able to open a connection from work network - I’m behind a corporate firewall that replaces the certificate of the server with it’s own.
I do have the internal ca certificate installed in ls /etc/ssl/certs/ and curl is working ok.
However, as I’m very new to zig, I struggle to open a connection with it.
I’ve tried below two functions, one with http.Client and the other with a tcp/tls connection.
I have no idea if I’m doing the right thing but in both cases I’m getting the same error (see below).
I’d appreciate any advice you have!
fn test_https() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
const uri = try std.Uri.parse("https://google.com");
var client = std.http.Client{ .allocator = allocator };
var server_header_buf = [_]u8{0} ** 1024;
var request = try client.open(std.http.Method.GET, uri, .{ .server_header_buffer = server_header_buf[0..] });
const reader = request.reader();
var buffer = [_]u8{0} ** 1024;
_ = try reader.readAll(&buffer);
std.debug.print("{s}\n", .{buffer});
}
fn test_tcp() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
var bundle = std.crypto.Certificate.Bundle{};
try bundle.rescan(allocator);
const stream = try std.net.tcpConnectToHost(allocator, "www.google.com", 443);
defer stream.close();
const tlsOptions: std.crypto.tls.Client.Options = .{ .host = .{ .explicit = "www.google.com" }, .ca = .{ .bundle = bundle } };
var tlsclient = try std.crypto.tls.Client.init(stream, tlsOptions);
const dummy_req =
\\GET / HTTP/1.1
\\Host: www.google.com
\\User-Agent: ziggy
\\Accept: text/html
\\Connection: close
;
_ = try tlsclient.writeAll(stream, dummy_req);
var buffer: [1024]u8 = undefined;
_ = try tlsclient.readAll(stream, &buffer);
std.debug.print("{s}\n", .{buffer});
}
And the error:
/home/gabi/.zig/lib/std/crypto/Certificate.zig:261:13: 0x1211f22 in verify (testhttps)
return error.CertificateIssuerMismatch;
^
/home/gabi/.zig/lib/std/crypto/tls/Client.zig:637:33: 0x11ebbee in init__anon_24451 (testhttps)
try prev_cert.verify(subject, now_sec);
^
/home/gabi/learning_zig/testhttps/src/main.zig:36:21: 0x114993f in test_tcp (testhttps)
var tlsclient = try std.crypto.tls.Client.init(stream, tlsOptions);
^
/home/gabi/learning_zig/testhttps/src/main.zig:55:5: 0x1209043 in main (testhttps)
try test_tcp();
This is a zig tls implementation problem.
What happens is that the www.google.com
certificate is valid and verified, but zig expects that the next certificate in the server certificate chain to have as subject the issuer of the first certificate.
There is more information in the section 3. certificate chain not continuous
of test std lib TLS implementation against many real world servers · Issue #14172 · ziglang/zig · GitHub
I think you might solve the problem by re-configuring the produced certification chain from your firewall.
Thank you very much! I’ll look into that.