ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
33.67k stars 2.47k forks source link

error: TlsInitializationFailed caused by servers lacking TLSv1.3 support #17213

Open pfgithub opened 11 months ago

pfgithub commented 11 months ago

Zig Version

0.12.0-dev.415+5af5d87ad (mac aarch64, windows 10, Linux 5.15.90.1-microsoft-standard-WSL2)

Steps to Reproduce and Observed Behavior

The http client is broken on UofT eduroam wifi but works fine with a hotspot from my phone.

// a.zig
const std = @import("std");
const allocator = std.testing.allocator;
const uri = std.Uri.parse("https://ziglang.org/") catch unreachable;

test {
    var client: std.http.Client = .{ .allocator = allocator };
    defer client.deinit();

    var req = try client.request(.GET, uri, .{ .allocator = allocator }, .{});
    defer req.deinit();
    try req.start();
    try req.wait();

    try std.testing.expect(req.response.status == .ok);
}
zig test a.zig
Test [1/1] test_0... FAIL (TlsInitializationFailed)
/home/pfg/Apps/zig-linux-x86_64-0.12.0-dev.415+5af5d87ad/lib/std/os.zig:753:27: 0x3c0edf in read (test)
            .CONNRESET => return error.ConnectionResetByPeer,
                          ^
/home/pfg/Apps/zig-linux-x86_64-0.12.0-dev.415+5af5d87ad/lib/std/net.zig:1774:13: 0x40b647 in read (test)
            return os.read(self.handle, buffer);
            ^
/home/pfg/Apps/zig-linux-x86_64-0.12.0-dev.415+5af5d87ad/lib/std/net.zig:1805:25: 0x3b81e0 in readAtLeast (test)
            const amt = try s.read(buffer[index..]);
                        ^
/home/pfg/Apps/zig-linux-x86_64-0.12.0-dev.415+5af5d87ad/lib/std/crypto/tls.zig:470:28: 0x3dcfb2 in readAtLeast__anon_12903 (test)
        const actual_amt = try stream.readAtLeast(dest, request_amt);
                           ^
/home/pfg/Apps/zig-linux-x86_64-0.12.0-dev.415+5af5d87ad/lib/std/crypto/tls.zig:479:9: 0x3dd0c4 in readAtLeastOurAmt__anon_12902 (test)
        try readAtLeast(d, stream, our_amt);
        ^
/home/pfg/Apps/zig-linux-x86_64-0.12.0-dev.415+5af5d87ad/lib/std/crypto/tls/Client.zig:240:9: 0x38b443 in init__anon_10845 (test)
        try d.readAtLeastOurAmt(stream, tls.record_header_len);
        ^
/home/pfg/Apps/zig-linux-x86_64-0.12.0-dev.415+5af5d87ad/lib/std/http/Client.zig:949:103: 0x2aa86e in connectUnproxied (test)
            conn.data.tls_client.* = std.crypto.tls.Client.init(stream, client.ca_bundle, host) catch return error.TlsInitializationFailed;
                                                                                                      ^
/home/pfg/Apps/zig-linux-x86_64-0.12.0-dev.415+5af5d87ad/lib/std/http/Client.zig:1018:9: 0x296616 in connect (test)
        return client.connectUnproxied(host, port, protocol);
        ^
/home/pfg/Apps/zig-linux-x86_64-0.12.0-dev.415+5af5d87ad/lib/std/http/Client.zig:1087:44: 0x28d3ac in request (test)
    const conn = options.connection orelse try client.connect(host, port, protocol);
                                           ^
/home/pfg/Dev/Node/temp/generated/aa548188257c94cb525463fd900c11e5/tmp/a.zig:9:15: 0x28cd7d in test_0 (test)
    var req = try client.request(.GET, uri, .{ .allocator = allocator }, .{});
              ^
0 passed; 0 skipped; 1 failed.
error: the following test command failed with exit code 1:
/home/pfg/.cache/zig/o/0ad311e516acf8553fce2d4d9f388c97/test
Exited with code [1]

Expected Behavior

All 1 tests passed.
cactusbento commented 11 months ago

Same here in Clemson University, but this is an issue with Zig's tls support. More specifically, Zig's stdlib does not implement TLS 1.2. Thus, it will fail on eduroam.

Related: https://github.com/ziglang/zig/issues/14172

Also, if you really want to use std.http.Client, I suggest you hook it up to an http proxy running locally on your machine (like tinyproxy), to get around this problem until the TLS 1.2 is supported.

Edit: It's most likely that eduroam doesn't support TLS 1.3, but this is a sample size of 2.

pfgithub commented 11 months ago

Here's a workaround bun + fish script to download packages recursively from a build.zig.zon file until this is fixed

// dnlpkg.ts
import {mkdirSync, readFileSync} from "fs";

process.chdir(process.env.HOME + "/.cache/zig/p");

async function downloadFromZon(zon: string) {
    const file = Bun.file(zon);
    let filetext;
    try {
        filetext = await file.text();
    }catch(e) {
        return;
    }
    const fline = filetext.split("\n");

    let urlv = null;
    for(const line of fline) {
        if(line.includes('.url = ')) {
            const urltxt = line.match(/".+"/);
            if(urltxt == null) throw new Error("no urltxt");
            const urlparsed = JSON.parse(urltxt[0]);
            if(urlv != null) throw new Error("previous url had no hash");
            urlv = urlparsed;
        }else if(line.includes('.hash = ')) {
            const urltxt = line.match(/".+"/);
            if(urltxt == null) throw new Error("no hashtxt");
            const hashparsed = JSON.parse(urltxt[0]);
            if(urlv == null) throw new Error(".hash field above .url field");

            await exec(["fish", __dirname + "/dnlpkg.fish", urlv, hashparsed]);
            urlv = null;

            await downloadFromZon(hashparsed + "/build.zig.zon");
        }
    }
    if(urlv != null) throw new Error("missed url: " + urlv);
}

await downloadFromZon(Bun.argv[2]);

async function exec(cmd) {
    const res = Bun.spawnSync(cmd, {stdio: ["inherit", "pipe", "inherit"]});
    if(res.exitCode !== 0) {
        console.log(cmd, res);
        process.exit(1);
    }
    return new TextDecoder().decode(res.stdout);
}
// dnlpkg.fish

if [ ! -d $argv[2] ]
    rm -f dnl.tar.gz
    rm -rf dnl
    mkdir -p dnl
    wget $argv[1] -O dnl.tar.gz
    tar -xvf dnl.tar.gz --strip-components=1 -C dnl
    mv dnl $argv[2]
    rm -f dnl.tar.gz
    rm -rf dnl
    echo "completed download "$argv[2] 1>&2
else
    echo "already downloaded "$argv[2] 1>&2
end
bun dnlpkg.ts build.zig.zon