ziglang / zig

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

test std lib TLS implementation against many real world servers #14172

Open andrewrk opened 1 year ago

andrewrk commented 1 year ago

Extracted from #13980.

Here is a small test program:

const std = @import("std");
const http = std.http;

pub fn main() !void {
    var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    const arena = arena_instance.allocator();
    const gpa = arena;

    const args = try std.process.argsAlloc(arena);

    var client: http.Client = .{
        .allocator = gpa,
    };
    try client.ca_bundle.rescan(gpa);

    const url = try std.Url.parse(args[1]);
    var req = try client.request(url, .{});
    try req.addHeader("Connection", "close");
    try req.end();

    var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
    const w = bw.writer();

    var total: usize = 0;
    var buf: [5000]u8 = undefined;
    while (true) {
        const amt = try req.readAll(&buf);
        total += amt;
        if (amt == 0) break;
        std.debug.print("got {d} bytes (total {d})\n", .{ amt, total });
        try w.writeAll(buf[0..amt]);
    }

    try bw.flush();
}

This issue tracks real world web servers that cannot be accessed. Here's one for starters:

$ ./test https://www.wikipedia.org/ >out.html
error: TlsDecryptError
/home/andy/Downloads/zig/lib/std/crypto/tls/Client.zig:573:41: 0x34ffb6 in init__anon_6275 (test)
                                        return error.TlsDecryptError;
                                        ^
/home/andy/Downloads/zig/lib/std/http/Client.zig:142:30: 0x364fbc in request (test)
            req.tls_client = try std.crypto.tls.Client.init(req.stream, client.ca_bundle, url.host);
                             ^
/home/andy/Downloads/zig/build-release/test.zig:17:15: 0x37640f in main (test)
    var req = try client.request(url, .{});
              ^

This issue can be closed when, idk, the "top 100 most popular websites" or some list like that can all be retrieved successfully.

May require working on the http client as well to support chunked encoding and things like this.

trgwii commented 1 year ago

www.wikipedia.org uses DigiCert, Telegram uses GoDaddy. Might be useful to try to cover a wide range of root certificates?

rofrol commented 1 year ago

Updated example https://github.com/rofrol/http-client-zig-example or here:

const std = @import("std");
const http = std.http;

pub fn main() !void {
    var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    const arena = arena_instance.allocator();
    const gpa = arena;

    const args = try std.process.argsAlloc(arena);

    var client: http.Client = .{
        .allocator = gpa,
    };
    defer client.deinit();

    const url = try std.Uri.parse(args[1]);
    var req = try client.request(url, .{}, .{});
    defer req.deinit();

    var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
    const w = bw.writer();

    var total: usize = 0;
    var buf: [500000]u8 = undefined;
    while (true) {
        const amt = try req.readAll(&buf);
        total += amt;
        if (amt == 0) break;
        std.debug.print("got {d} bytes (total {d})\n", .{ amt, total });
        try w.writeAll(buf[0..amt]);
    }

    try bw.flush();

    std.debug.print("{s}", .{buf[0..total]});
}

slash is needed i.e. zig run http-client.zig -- http://example.com/

Tested on macos m1 in vm ubuntu 22.04 using multipass https://shwjason.medium.com/how-a-simple-script-helped-help-made-me-over-1000-month-a759a604e4b3

kassane commented 1 year ago

@rofrol, nice update.

Now, I just tried this same link and got this error with the version: 0.11.0-dev.1327+b42bd759a

 ./httpClient https://onet.pl/               
error: TlsCertificateNotVerified
/home/kassane/.local/lib/zig/std/crypto/tls/Client.zig:493:49: 0x26a9af in init__anon_5905 (httpClient)
                                .certificate => return error.TlsCertificateNotVerified,
                                                ^
/home/kassane/.local/lib/zig/std/mem.zig:0:13: 0x277225 in request (httpClient)
/home/kassane/.local/lib/zig/std/http/Client.zig:882:23: 0x27722d in request (httpClient)
        .connection = try client.connect(host, port, protocol),
                      ^
/home/kassane/.local/lib/zig/std/process.zig:0:0: 0x2807ce in main (httpClient)

My another suggestion link to test: https://test.openquantumsafe.org/

rofrol commented 1 year ago

@kassane

Some sites are not supported yet

I have updated above example to use master. Works on macos m1.

% uname -v
Darwin Kernel Version 22.2.0: Fri Nov 11 02:04:44 PST 2022; root:xnu-8792.61.2~4/RELEASE_ARM64_T8103
% zig version
0.11.0-dev.1343+f3107e2cb
% zig run http-client.zig -- https://www.onet.pl/
got 303116 bytes (total 303116)
<!DOCTYPE html><html lang="pl" class="device-desktop"><head><meta charset="utf-8"><link rel="canonical" href="https://www.onet.pl"><link rel="preload" href="https://ocdn.eu/onetmobilemainpage/firafonts/p06/FiraSans-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous"><link rel="preload" href="https://ocdn.eu/onetmobilemainpage/firafonts/p06/FiraSans-Medium.woff2" as="font" type="font/woff2" crossorigin="anonymous"><link rel="preload" href="https://ocdn.eu/onetmobilemainpage/firafonts/p06/FiraSans-Bold.woff2" as="font" type="font/woff2" crossorigin="anonymous"><link rel="preload" href="https://ocdn.eu/onetmobilemainpage/icofont/i34/onetsg.woff2" as="font" type="font/woff2" crossorigin="anonymous"><script id="InlineScript-polyfills">(function () {
...

zig built with instructions from https://github.com/ziglang/zig/wiki/Building-Zig-From-Source

First I have run

% time ./build aarch64-macos-none native
% export ZIG_PREFIX=$PWD/out/zig-aarch64-macos-none-native
% export LLVM_PREFIX=$PWD/out/aarch64-macos-none-native

in zig-bootstrap (took 5 hours I think).

Then I have downloaded zig sources and compiled zig:

% time "$ZIG_PREFIX/bin/zig" build \
  -p stage3 \
  --search-prefix "$LLVM_PREFIX" \
  --zig-lib-dir lib \
  -Dstatic-llvm
"$ZIG_PREFIX/bin/zig" build -p stage3 --search-prefix "$LLVM_PREFIX"  "$LIB"   79.68s user 8.79s system 176% cpu 50.099 total
TUSF commented 1 year ago

This issue can be closed when, idk, the "top 100 most popular websites" or some list like that can all be retrieved successfully.

Might be a good idea to include common code repository sites into that list, given the Package Manager MVP can't retrieve tarballs from sourcehut, and probably others.

rofrol commented 1 year ago

I have found these two lists:

And json for moz.com https://github.com/Kikobeats/top-sites/blob/master/top-sites.json

star-tek-mb commented 1 year ago

I think something wrong with AES_256_GCM_SHA384. Servers that select this cipher suite will hang with tls.DecryptError. If I exclude AES_256_GCM_SHA384 from client supported cipher suites, then sites (wikipedia.org, telegram.org, and many more) will open.

trgwii commented 1 year ago

@star-tek-mb does that require editing the source of zig std? Can it be done by providing options to std.http.Client?

star-tek-mb commented 1 year ago

@trgwii Only by editing zig std for now (you can edit source of your current zig installation). You can just reorder, remove other cipher suites in https://github.com/ziglang/zig/blob/885d6968958e1cad4862ed1b6f1ea0b2d84c3845/lib/std/crypto/tls/Client.zig#L1299 Leave AES_128_GCM_SHA256 and CHACHA20_POLY1305_SHA256. Those are working ones.

trgwii commented 1 year ago

I found a new kind of error: CertificatePublicKeyInvalid for nodejs.org, which is valid in browsers.

I managed to fix it by editing my local std, but I'm putting this here as an issue rather than a PR, because I don't know the implications of bumping these memory limits, nor what the proper limits should be.

Here's the repr, including the changes to stdlib I made that fixed it for me locally:

const std = @import("std");

comptime {
    // This program currently errors with error: CertificatePublicKeyInvalid (L466)

    // Tested with:
    // 0.11.0-dev.1586+2d017f379 (x86_64-windows)
    // 0.11.0-dev.1580+a5b34a61a (x86_64-linux)

    // To make this program work on both:

    // Inside this function
    _ = std.crypto.tls.Client.init;
    // 1. change L538
    //-var rsa_mem_buf: [512 * 32]u8 = undefined;
    //+var rsa_mem_buf: [512 * 64]u8 = undefined;

    // 2. change L360
    //-var main_cert_pub_key_buf: [300]u8 = undefined;
    //+var main_cert_pub_key_buf: [600]u8 = undefined;
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer std.debug.assert(!gpa.deinit());
    const allocator = gpa.allocator();

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

    const uri = try std.Uri.parse("https://nodejs.org/en/");

    var request = try client.request(uri, .{}, .{});
    defer request.deinit();
}
fubark commented 1 year ago

I used https://github.com/ziglang/zig/issues/14172#issuecomment-1384567705 to test (0.11.0-dev.1638+7199d7c77): zig run http.zig -- https://zig.news/feed (Getting error.CertificatePublicKeyInvalid) I also tried to apply this fix https://github.com/ziglang/zig/issues/14172#issuecomment-1425544811 but it ends up hanging.

trgwii commented 1 year ago

@fubark try doubling things even further, that has worked for me a couple of times.

angaz commented 1 year ago

It seems that this is also a problem for the module system, I guess that makes sense, just want to report it for future generations.

If I add a URL from sourcehut, it seems to be the same, for example: https://git.sr.ht/~leon_plickat/zig-spoon/archive/a8bc052f45c18216f03e8f2576ca019a9cc2c1ab.tar.gz

Then during zig build:

$ zig build
error: TlsDecryptError

Just that one single line is printed and the execution exits.

jedisct1 commented 1 year ago

I think something wrong with AES_256_GCM_SHA384. Servers that select this cipher suite will hang with tls.DecryptError. If I exclude AES_256_GCM_SHA384 from client supported cipher suites, then sites (wikipedia.org, telegram.org, and many more) will open.

Fixed in #15031 (might fix other issues reported here by the way)

jedisct1 commented 1 year ago

There's a CERT using 4096-bit RSA here.

// 1. change L538
//-var rsa_mem_buf: [512 * 32]u8 = undefined;
//+var rsa_mem_buf: [512 * 64]u8 = undefined;

2 512 32 looks indeed necessary for a 4096-bit modulus.

// 2. change L360
//-var main_cert_pub_key_buf: [300]u8 = undefined;
//+var main_cert_pub_key_buf: [600]u8 = undefined;

512 bytes for the 4096 bit modulus + a couple bytes for the DER encoding. That makes sense.

Bumping these values look reasonable to me. The large memory requirements for rsa_mem_buf will go away once the std.crypto.bigint code lands.

ericlanderson commented 1 year ago

I am encountering error: TlsInitializationFailed.

My environment:

❯ uname -v
Darwin Kernel Version 22.4.0: Mon Mar  6 21:00:17 PST 2023; root:xnu-8796.101.5~3/RELEASE_X86_64
❯ zig version                            
0.11.0-dev.2868+1a455b2dd

I have local changes to support 4096-bit modules so that sites such as https://nodejs.org works.

And my test program (modified from https://github.com/ziglang/zig/issues/14172#issuecomment-1425544811 to support recent changes):

const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    // defer std.debug.assert(!gpa.deinit());
    const allocator = gpa.allocator();

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

    const uri = try std.Uri.parse("https://httpbin.org/ip/");
    var headers = std.http.Headers{ .allocator = allocator };
    defer headers.deinit();
    var request = try client.request(.GET, uri, headers, .{});
    defer request.deinit();
}
dadrian commented 1 year ago

httpbin.org is failing because Zig only offers TLS 1.3, and HTTP Bin only supports through TLS 1.2. I assume the decision to only support 1.3 is at least semi-intentional, since 1.3 and 1.2 have different state machines.

jedisct1 commented 1 year ago

Eventually, everybody's gonna move to TLS 1.3. I'm not sure that it's worth investing time in a TLS 1.2 implementation today, especially since TLS 1.2 has a lot of footguns.

dadrian commented 1 year ago

Eventually, everybody's gonna move to TLS 1.3.

This is not at all true. There are no plans to deprecate TLS 1.2 in the IETF or among browsers, although various key exchange methods, ciphers, and signature types have been deprecated.

I'm not sure that it's worth investing time in a TLS 1.2 implementation today, especially since TLS 1.2 has a lot of footguns.

This might be true. However, most of the footguns can be left out if you only implement ciphers that align with those that are included in 1.3, e.g. the ECDHE + {ECDSA,RSA} + {AES_GCM, ChaChaPoly} subset. Otherwise, it's extremely unlikely you'd be able to connect to any top website that isn't hosted on a CDN, or to any embedded device.

"We haven't gotten to it and it's not that important" is a perfectly fine prioritization decision, but "eventually everyone will be on TLS 1.3" is not a good justification.

If y'all are willing to take it, I'd be happy to work on 1.2 support.

gui36 commented 1 year ago

I fully agree, TLS 1.2 must be supported on the long run.

zig version 0.11.0-dev.3395+1e7dcaa3a

I bumped into the following error with TLS 1.2: error: TlsInitializationFailed C:\zig\zig-windows-x86_64-0.11.0\lib\std\crypto\tls.zig:200:9: 0x7ff703e2b119 in toError (sw.exe.obj) return switch (alert) {

On top of TLS 1.3, i bumped into same error but different root cause: error: TlsInitializationFailed C:\zig\zig-windows-x86_64-0.11.0\lib\std\crypto\Certificate.zig:324:9: 0x7ff67934df59 in verifyHostName (sw.exe.obj) return error.CertificateHostMismatch;

Most probably because I am using the following URI with IP instead of FQDN: const uri = std.Uri.parse("https://10.10.10.10") catch unreachable; and because this IP is not within the certificate SAN. Is there any way to skip the certificate verification while using TLS ?

Cheers, Gui

andrewrk commented 12 months ago

Can you please stop spamming this thread with the same comment? It's a good comment, just leave it alone.

ghost commented 12 months ago

no worries, I have just removed it. I dont like my hours of work being referred to as "spam". I am working on my own TLS implementation, so I was interested in this same question. in the future I would recommend unsubscribing to threads that are too noisy for your taste. good luck, I like the Zig project and hope the best for it.

Atomk commented 12 months ago

@1268 Just to offer a different interpretation, I can't see what you posted (nor how many times you posted it) but Andrew said your comment was a good comment so your work is welcome and appreciated, and one copy of your comment was enough ("just leave it alone").

ghost commented 12 months ago

unsubscribing from this thread. He said what he said. Andrew is an undeniably brilliant programmer, better than I will ever be. but words matter. good luck again to Andrew and the project. I hope the best for Zig, its a good language.

andrewrk commented 12 months ago

I'll reproduce the comment here:


Eventually, everybody's gonna move to TLS 1.3. I'm not sure that it's worth investing time in a TLS 1.2 implementation today, especially since TLS 1.2 has a lot of footguns.

using this input:

https://github.com/Kikobeats/top-sites/blob/master/top-sites.json

here is some Go code:

package main

import (
   "crypto/tls"
   "encoding/json"
   "fmt"
   "net/http"
   "net/url"
   "os"
   "time"
)

func main() {
   text, err := os.ReadFile("top-sites.json")
   if err != nil {
      panic(err)
   }
   var sites []struct {
      Root_Domain string `json:"rootDomain"`
   }
   json.Unmarshal(text, &sites)
   http.DefaultClient.Timeout = 9*time.Second
   http.DefaultTransport = &http.Transport{
      TLSClientConfig: &tls.Config{MaxVersion: tls.VersionTLS12},
   }
   req := new(http.Request)
   req.Header = make(http.Header)
   req.URL = new(url.URL)
   req.URL.Scheme = "https"
   req.ProtoMajor = 1
   req.ProtoMinor = 1
   req.Header["User-Agent"] = []string{"curl/7.84.0"}
   for i, site := range sites {
      req.URL.Host = site.Root_Domain
      res, err := http.DefaultClient.Do(req)
      if err != nil {
         fmt.Print("FAIL ", err, " ")
      } else {
         if err := res.Body.Close(); err != nil {
            panic(err)
         }
         if res.StatusCode != http.StatusOK {
            fmt.Print("FAIL ", res.Status, " ")
         }
      }
      fmt.Println(site.Root_Domain, len(sites)-i)
      time.Sleep(99 * time.Millisecond)
   }
}

from my judgment, every single server that accepted a request worked with TLS 1.2 or below. however if you switch to TLS 1.3:

TLSClientConfig: &tls.Config{MinVersion: tls.VersionTLS13},

you get many failures, including at least the ones below. so to me, TLS 1.2 should have first class support, and TLS 1.3 should be the afterthought. not the reverse.

FAIL Get "https://4shared.com": tls: server selected unsupported protocol version 303 4shared.com 366
FAIL Get "https://admin.ch": tls: server selected unsupported protocol version 303 admin.ch 35
FAIL Get "https://airbnb.com": tls: server selected unsupported protocol version 303 airbnb.com 94
FAIL Get "https://alexa.com": tls: server selected unsupported protocol version 303
FAIL Get "https://alibaba.com": remote error: tls: protocol version not supported alibaba.com 299
FAIL Get "https://aliexpress.com": remote error: tls: protocol version not supported aliexpress.com 380
FAIL Get "https://amazon.ca": tls: server selected unsupported protocol version 303
FAIL Get "https://amazon.co.jp": tls: server selected unsupported protocol version 303 amazon.co.jp 385
FAIL Get "https://amazon.co.uk": tls: server selected unsupported protocol version 303 amazon.co.uk 370
FAIL Get "https://amazon.com": tls: server selected unsupported protocol version 303 amazon.com 468
FAIL Get "https://amazon.de": tls: server selected unsupported protocol version 303 amazon.de 384
FAIL Get "https://amazon.es": tls: server selected unsupported protocol version 303
FAIL Get "https://amazon.fr": tls: server selected unsupported protocol version 303
FAIL Get "https://amazon.in": tls: server selected unsupported protocol version 303
FAIL Get "https://archive.org": remote error: tls: protocol version not supported archive.org 334
FAIL Get "https://arxiv.org": tls: server selected unsupported protocol version 303
FAIL Get "https://assine.abril.com.br/?redirect=abrilcom": tls: server selected unsupported protocol version 303 abril.com.br 395
FAIL Get "https://biglobe.ne.jp": tls: server selected unsupported protocol version 303 biglobe.ne.jp 313
FAIL Get "https://bing.com": tls: server selected unsupported protocol version 303 bing.com 359
FAIL Get "https://britannica.com": tls: server selected unsupported protocol version 303 britannica.com 236
FAIL Get "https://businessinsider.com": remote error: tls: protocol version not supported businessinsider.com 355
FAIL Get "https://ca.gov": tls: server selected unsupported protocol version 303 ca.gov 192
FAIL Get "https://cambridge.org": remote error: tls: protocol version not supported
FAIL Get "https://canada.ca": remote error: tls: protocol version not supported canada.ca 306
FAIL Get "https://cbslocal.com": remote error: tls: protocol version not supported cbslocal.com 87
FAIL Get "https://cbsnews.com": remote error: tls: protocol version not supported cbsnews.com 369
FAIL Get "https://cdc.gov": remote error: tls: handshake failure cdc.gov 331
FAIL Get "https://change.org": remote error: tls: protocol version not supported change.org 377
FAIL Get "https://channel4.com": tls: server selected unsupported protocol version 303 channel4.com 5
FAIL Get "https://chicagotribune.com": tls: server selected unsupported protocol version 303 chicagotribune.com 32
FAIL Get "https://cointernet.com.co": tls: server selected unsupported protocol version 303 cointernet.com.co 296
FAIL Get "https://cornell.edu": remote error: tls: handshake failure cornell.edu 137
FAIL Get "https://corriere.it": tls: server selected unsupported protocol version 303 corriere.it 97
FAIL Get "https://dailystar.co.uk": tls: server selected unsupported protocol version 303 dailystar.co.uk 1
FAIL Get "https://deloitte.com": remote error: tls: handshake failure deloitte.com 50
FAIL Get "https://detik.com": remote error: tls: protocol version not supported detik.com 178
FAIL Get "https://dictionary.com": remote error: tls: protocol version not supported dictionary.com 4
FAIL Get "https://dropbox.com": remote error: tls: protocol version not supported dropbox.com 447
FAIL Get "https://enable-javascript.com": tls: server selected unsupported protocol version 303 enable-javascript.com 458
FAIL Get "https://esa.int": tls: server selected unsupported protocol version 303 esa.int 6
FAIL Get "https://etsy.com": remote error: tls: protocol version not supported etsy.com 12
FAIL Get "https://excite.co.jp": tls: server selected unsupported protocol version 303 excite.co.jp 90
FAIL Get "https://fastcompany.com": remote error: tls: protocol version not supported fastcompany.com 33
FAIL Get "https://forbes.com": remote error: tls: protocol version not supported forbes.com 457
FAIL Get "https://ft.com": remote error: tls: protocol version not supported ft.com 132
FAIL Get "https://giphy.com": remote error: tls: protocol version not supported giphy.com 61
FAIL Get "https://gizmodo.com": remote error: tls: protocol version not supported gizmodo.com 145
FAIL Get "https://godaddy.com": tls: server selected unsupported protocol version 303 godaddy.com 379
FAIL Get "https://goo.ne.jp": remote error: tls: handshake failure goo.ne.jp 55
FAIL Get "https://goodreads.com": tls: server selected unsupported protocol version 303 goodreads.com 188
FAIL Get "https://harvard.edu": remote error: tls: protocol version not supported harvard.edu 134
FAIL Get "https://hatena.ne.jp": tls: server selected unsupported protocol version 303 hatena.ne.jp 417
FAIL Get "https://hindustantimes.com": remote error: tls: protocol version not supported hindustantimes.com 183
FAIL Get "https://hp.com": remote error: tls: handshake failure hp.com 251
FAIL Get "https://huawei.com": tls: server selected unsupported protocol version 303 huawei.com 172
FAIL Get "https://imageshack.us": tls: server selected unsupported protocol version 303 imageshack.us 305
FAIL Get "https://imdb.com": tls: server selected unsupported protocol version 303 imdb.com 431
FAIL Get "https://inc.com": remote error: tls: protocol version not supported inc.com 16
FAIL Get "https://independent.co.uk": remote error: tls: protocol version not supported independent.co.uk 401
FAIL Get "https://insider.com": remote error: tls: protocol version not supported insider.com 202
FAIL Get "https://instructables.com": remote error: tls: protocol version not supported instructables.com 154
FAIL Get "https://issuu.com": remote error: tls: protocol version not supported issuu.com 351
FAIL Get "https://jhu.edu": tls: server selected unsupported protocol version 303 jhu.edu 93
FAIL Get "https://jimdofree.com": remote error: tls: protocol version not supported jimdofree.com 448
FAIL Get "https://justjared.com": tls: server selected unsupported protocol version 303 justjared.com 72
FAIL Get "https://kakao.com": remote error: tls: protocol version not supported kakao.com 100
FAIL Get "https://latimes.com": tls: server selected unsupported protocol version 303 latimes.com 160
FAIL Get "https://leparisien.fr": tls: server selected unsupported protocol version 303 leparisien.fr 186
FAIL Get "https://lexpress.fr": tls: server selected unsupported protocol version 303 lexpress.fr 19
FAIL Get "https://linkedin.com": tls: server selected unsupported protocol version 303 linkedin.com 497
FAIL Get "https://linktr.ee": remote error: tls: protocol version not supported linktr.ee 106
FAIL Get "https://list-manage.com": tls: server selected unsupported protocol version 303 list-manage.com 338
FAIL Get "https://live.com": tls: server selected unsupported protocol version 303 live.com 442
FAIL Get "https://liveinternet.ru": tls: server selected unsupported protocol version 303 liveinternet.ru 250
FAIL Get "https://loc.gov": remote error: tls: protocol version not supported loc.gov 320
FAIL Get "https://mail.ru": tls: server selected unsupported protocol version 303 mail.ru 419
FAIL Get "https://main.jp": remote error: tls: protocol version not supported main.jp 7
FAIL Get "https://mediafire.com": remote error: tls: protocol version not supported mediafire.com 357
FAIL Get "https://mirror.co.uk": tls: server selected unsupported protocol version 303 mirror.co.uk 350
FAIL Get "https://mit.edu": remote error: tls: protocol version not supported mit.edu 326
FAIL Get "https://msn.com": tls: server selected unsupported protocol version 303 msn.com 465
FAIL Get "https://mysql.com": tls: server selected unsupported protocol version 303
FAIL Get "https://namecheap.com": remote error: tls: protocol version not supported
FAIL Get "https://narod.ru": tls: server selected unsupported protocol version 303 narod.ru 67
FAIL Get "https://nasa.gov": remote error: tls: protocol version not supported nasa.gov 416
FAIL Get "https://nationalgeographic.com": tls: server selected unsupported protocol version 303 nationalgeographic.com 170
FAIL Get "https://nbcnews.com": tls: server selected unsupported protocol version 303 nbcnews.com 255
FAIL Get "https://networkadvertising.org": tls: server selected unsupported protocol version 303 networkadvertising.org 364
FAIL Get "https://newsweek.com": tls: server selected unsupported protocol version 303 newsweek.com 194
FAIL Get "https://newyorker.com": remote error: tls: protocol version not supported
FAIL Get "https://nginx.org": remote error: tls: protocol version not supported nginx.org 256
FAIL Get "https://nicovideo.jp": tls: server selected unsupported protocol version 303 nicovideo.jp 56
FAIL Get "https://nih.gov": remote error: tls: handshake failure nih.gov 424
FAIL Get "https://nikkei.com": tls: server selected unsupported protocol version 303 nikkei.com 156
FAIL Get "https://noaa.gov": tls: server selected unsupported protocol version 303 noaa.gov 83
FAIL Get "https://nydailynews.com": tls: server selected unsupported protocol version 303 nydailynews.com 216
FAIL Get "https://nytimes.com": remote error: tls: protocol version not supported nytimes.com 439
FAIL Get "https://oecd.org": remote error: tls: handshake failure oecd.org 81
FAIL Get "https://office.com": tls: server selected unsupported protocol version 303 office.com 383
FAIL Get "https://offset.com": tls: server selected unsupported protocol version 303 offset.com 291
FAIL Get "https://oracle.com": tls: server selected unsupported protocol version 303 oracle.com 179
FAIL Get "https://oup.com": tls: server selected unsupported protocol version 303 oup.com 274
FAIL Get "https://outlook.com": tls: server selected unsupported protocol version 303 outlook.com 294
FAIL Get "https://pbs.org": remote error: tls: protocol version not supported pbs.org 282
FAIL Get "https://php.net": remote error: tls: protocol version not supported php.net 323
FAIL Get "https://planalto.gov.br": remote error: tls: handshake failure planalto.gov.br 402
FAIL Get "https://playstation.com": tls: server selected unsupported protocol version 303 playstation.com 110
FAIL Get "https://prezi.com": tls: server selected unsupported protocol version 303
FAIL Get "https://prnewswire.com": remote error: tls: protocol version not supported prnewswire.com 77
FAIL Get "https://proof.ovh.net": remote error: tls: protocol version not supported
FAIL Get "https://psu.edu": tls: server selected unsupported protocol version 303 psu.edu 45
FAIL Get "https://psychologytoday.com": tls: server selected unsupported protocol version 303 psychologytoday.com 213
FAIL Get "https://qq.com": remote error: tls: protocol version not supported qq.com 167
FAIL Get "https://quora.com": tls: server selected unsupported protocol version 303
FAIL Get "https://rakuten.co.jp": remote error: tls: handshake failure rakuten.co.jp 210
FAIL Get "https://reuters.com": remote error: tls: handshake failure reuters.com 396
FAIL Get "https://reverbnation.com": tls: server selected unsupported protocol version 303 reverbnation.com 85
FAIL Get "https://sakura.ne.jp": remote error: tls: protocol version not supported sakura.ne.jp 266
FAIL Get "https://samsung.com": remote error: tls: handshake failure samsung.com 400
FAIL Get "https://sapo.pt": tls: server selected unsupported protocol version 303 sapo.pt 120
FAIL Get "https://secureserver.net": tls: server selected unsupported protocol version 303 secureserver.net 249
FAIL Get "https://shutterstock.com": tls: server selected unsupported protocol version 303 shutterstock.com 404
FAIL Get "https://sky.com": tls: server selected unsupported protocol version 303 sky.com 215
FAIL Get "https://stanford.edu": remote error: tls: handshake failure stanford.edu 263
FAIL Get "https://statista.com": tls: server selected unsupported protocol version 303 statista.com 238
FAIL Get "https://target.com": remote error: tls: protocol version not supported target.com 184
FAIL Get "https://ted.com": tls: server selected unsupported protocol version 303 ted.com 103
FAIL Get "https://theatlantic.com": remote error: tls: protocol version not supported theatlantic.com 191
FAIL Get "https://thefreedictionary.com": tls: server selected unsupported protocol version 303 thefreedictionary.com 70
FAIL Get "https://thetimes.co.uk": tls: server selected unsupported protocol version 303 thetimes.co.uk 227
FAIL Get "https://umich.edu": remote error: tls: handshake failure umich.edu 29
FAIL Get "https://un.org": tls: server selected unsupported protocol version 303 un.org 378
FAIL Get "https://unam.mx": remote error: tls: protocol version not supported unam.mx 2
FAIL Get "https://unesco.org": remote error: tls: handshake failure unesco.org 226
FAIL Get "https://unsplash.com": remote error: tls: protocol version not supported unsplash.com 150
FAIL Get "https://uol.com.br": tls: server selected unsupported protocol version 303 uol.com.br 474
FAIL Get "https://us.ovhcloud.com/": tls: server selected unsupported protocol version 303 ovhcloud.com 229
FAIL Get "https://usda.gov": remote error: tls: handshake failure usda.gov 23
FAIL Get "https://vice.com": tls: server selected unsupported protocol version 303 vice.com 139
FAIL Get "https://washington.edu": tls: server selected unsupported protocol version 303 washington.edu 41
FAIL Get "https://webmd.com": remote error: tls: handshake failure webmd.com 354
FAIL Get "https://weibo.com": tls: server selected unsupported protocol version 303
FAIL Get "https://wiley.com": tls: server selected unsupported protocol version 303
FAIL Get "https://wired.com": remote error: tls: protocol version not supported wired.com 325
FAIL Get "https://www.elmundo.es/": remote error: tls: protocol version not supported elmundo.es 122
FAIL Get "https://www.gov.br": remote error: tls: handshake failure www.gov.br 199
FAIL Get "https://www.indiatimes.com/": remote error: tls: protocol version not supported indiatimes.com 398
FAIL Get "https://www.lavanguardia.com/": remote error: tls: protocol version not supported lavanguardia.com 113
FAIL Get "https://www.lemonde.fr/": remote error: tls: protocol version not supported lemonde.fr 314
FAIL Get "https://www.marca.com/": remote error: tls: protocol version not supported marca.com 124
FAIL Get "https://www.naver.com/": remote error: tls: protocol version not supported naver.com 268
FAIL Get "https://www.opera.com/": tls: server selected unsupported protocol version 303 opera.com 441
FAIL Get "https://www.redbull.com/": remote error: tls: protocol version not supported redbull.com 123
FAIL Get "https://www.scientificamerican.com/": remote error: tls: protocol version not supported scientificamerican.com 44
FAIL Get "https://www.skype.com/": tls: server selected unsupported protocol version 303 skype.com 279
FAIL Get "https://www.smh.com.au/": remote error: tls: protocol version not supported smh.com.au 258
FAIL Get "https://www.weebly.com": tls: server selected unsupported protocol version 303 www.weebly.com 428
FAIL Get "https://www.zendesk.com/": remote error: tls: protocol version not supported zendesk.com 151
FAIL Get "https://yadi.sk": remote error: tls: protocol version not supported yadi.sk 111
FAIL Get "https://zdf.de": remote error: tls: protocol version not supported zdf.de 309
FAIL Get "https://zippyshare.com": tls: server selected unsupported protocol version 303 zippyshare.com 117
cztomsik commented 9 months ago

FYI it's not possible to connect to huggingface.com from windows. macOS works fine. will update here with more info when I figure out what's the problem...

(Fails with TlsInitializationFailed which comes from TlsCertificateNotVerified)

~Ok, so if I export the Amazon Root CA 1 and install it in the root cert store for the whole machine, then it works fine. So it's just something with CA rescan.~

Ok, I forgot that browsers come with their own list of certificates, so this is easily fixed in user-space.

cztomsik commented 8 months ago

I got into this again, this time because of TLS v1.2. Is anyone working on this? Maybe I could give it a try? (my PR would be limited to "make site XXX work" which is far from perfect but it might be a good first step?)

Cloudef commented 6 months ago

In the meantime you can use zig-curl https://github.com/jiacai2050/zig-curl/pull/4

melonedo commented 6 months ago

Until these websites support TLS 1.3, you may try zig-tls12, which only fails on a few corner cases and some certificate errors.

VisenDev commented 5 months ago

I am also having issues with TLS

Robert@Roberts-MacBook-Pro-2 ~/z/zigscheme (main)> zig fetch https://ccrma.stanford.edu/software/s7/s7.tar.gz
error: unable to connect to server: TlsInitializationFailed
3052 commented 5 months ago

that's a known issue. that server is TLS 1.2 only:

> curl --tlsv1.2 -I https://ccrma.stanford.edu/software/s7/s7.tar.gz
HTTP/1.1 200 OK

> curl --tlsv1.3 -I https://ccrma.stanford.edu/software/s7/s7.tar.gz
curl: (35) OpenSSL/3.1.0: error:0A000410:SSL routines::sslv3 alert handshake failure

for some reason Zig decided to implement TLS 1.3 only, or possible start with TLS 1.3 and add 1.2 later. so if they refuse 1.2, you're just gonna have to build the Zig tool yourself using a third party TLS package, or if they decide to add 1.2, you'll just need to wait until that happens.

RossComputerGuy commented 4 months ago

Just ran into this issue with invisible-mirror.net with zig fetch and got TlsInitializationFailed

nektro commented 4 months ago

which uses TLS 1.2... others please check before listing more sites

Cloudef commented 4 months ago

Could zig optionally use kTLS on linux? https://docs.kernel.org/networking/tls.html

melonedo commented 4 months ago

Could zig optionally use kTLS on linux? https://docs.kernel.org/networking/tls.html

"Currently only the symmetric encryption is handled in the kernel. After the TLS handshake is complete, we have all the parameters required to move the data-path to the kernel". However, most of the complexity of TLS lies in handshaking (many signature and key exchange algorithms are required, plus you need to securely manage the whole process), which is probably why both zig and linux are reluctant to expand its implementation.

Cloudef commented 4 months ago

Makes sense, the issues here indeed are about the handshaking part

matdibu commented 1 month ago

https://github.com/chromium/badssl.com might be useful for testing, since it's not supposed to change its TLS config

there are some unintended expired certificates on some of the subdomains, but it feels a lot more stable to check against domains like these:

might even be able to spin up a local server for testing

ianic commented 3 weeks ago

I made an alternate tls 1.3 and tls 1.2 Zig protocol library. While testing with the top 500 domains and then comparing with std lib I found a few problems in the std lib implementation.

All domains below are tls 1.3 capable.

1. handshake message can be fragmented into multiple tls records

Error:

error: TlsInitializationFailed
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/crypto/tls.zig:551:32: 0x123e4d7 in sub (http_get_std)
        if (end > d.their_end) return error.TlsDecodeError;
                               ^
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/crypto/tls/Client.zig:485:31: 0x12114c8 in init__anon_9815 (http_get_std)
                    var hsd = try ctd.sub(handshake_len);

Current implementation requires one handshake message per wrapped (encrypted) tls record. I found this domains which are sending fragmented handshake messages:

For example whatsapp.com after initial sever hello sends 3 wrapped record:

Those 3 tls wrapped records contain following handshake messages:

Certificate spans all 3 wrapped tls records. And the other two are also in last wrapped record.

Correct implementation should decrypt wrapped record to cleartext buffer, if the handshake message is larger than cleartext buffer it should decrypt another record append it to the cleartext and check cleartext length again until it has full handshake message.

Reference: https://datatracker.ietf.org/doc/html/rfc8446#appendix-C.3

It is also allowed that single tls record contains multiple handshake messages.

2. certificate longer then handshake buffer

tls.Client is in init using handshake_buffer of 8000 bytes. When parsing messages with long certificates it fails:

error: TlsInitializationFailed
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/crypto/tls.zig:470:37: 0x123df6f in readAtLeast__anon_10807 (http_get_std)
        if (request_amt > dest.len) return error.TlsRecordOverflow;
                                    ^
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/crypto/tls/Client.zig:436:9: 0x120f331 in init__anon_9815 (http_get_std)
        try d.readAtLeast(stream, record_len);
        ^
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/http/Client.zig:1357:99: 0x115477b in connectTcp (http_get_std)
        conn.data.tls_client.* = std.crypto.tls.Client.init(stream, client.ca_bundle, host) catch return error.TlsInitializationFailed;
                                                                                                  ^

For example googleblog.com sends 10932 bytes of handshake certificate message.

Domains:

3. certificate chain not continuous

Domain:

Error:

error: TlsInitializationFailed
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/crypto/Certificate.zig:258:13: 0x125c388 in verify (http_get_std)
            return error.CertificateIssuerMismatch;
            ^
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/crypto/tls/Client.zig:547:37: 0x1212b6f in init__anon_9815 (http_get_std)
                                    try prev_cert.verify(subject, now_sec);

If we look at certificates sent by terra.com.br:

$ openssl s_client -connect terra.com.br:443
Certificate chain
 0 s:C = BR, ST = S\C3\A3o Paulo, O = Terra Networks Brasil LTDA, CN = terra.com.br
   i:C = BR, O = Valid Certificadora Digital LTDA, CN = Valid Certificadora RSA OV SSL CA
 1 s:C = GB, ST = Greater Manchester, L = Salford, O = Comodo CA Limited, CN = AAA Certificate Services
   i:C = GB, ST = Greater Manchester, L = Salford, O = Comodo CA Limited, CN = AAA Certificate Services
 2 s:C = BR, O = Valid Certificadora Digital LTDA, CN = Valid Certificadora RSA OV SSL CA
   i:C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority

Certificate 0 and 2 are valid chain, 1 is not part of the chain and should be ignored. Current implementation requires that chain is continuous and fails while verifying 1 with 0.

One possible fix is to change line 547 to:

prev_cert.verify(subject, now_sec) catch |err| switch (err) {
    error.CertificateIssuerMismatch => {
        try certs_decoder.ensure(2);
        certs_decoder.skip(2);
        continue;
    },
    else => return err,
};

4. rsa_pkcs1_sha384 required in client hello signature algorithms extension

error: TlsInitializationFailed
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/crypto/tls.zig:201:9: 0x125024e in toError (http_get_std)
        return switch (alert) {
        ^
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/crypto/tls/Client.zig:253:17: 0x120b7d2 in init__anon_9815 (http_get_std)
                try desc.toError();

alert is: TlsAlertHandshakeFailure

If I add .rsa_pkcs1_sha384 to the list of supported signature algorithms, without implementing that in other places, handshake succeeds. https://github.com/ziglang/zig/blob/f7d72ce881db7162aa74ec0fa05ee3af76ecfe1c/lib/std/crypto/tls/Client.zig#L167

Domain:

5. secp384r1 named group required in client hello supported groups extension

error: TlsInitializationFailed
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/crypto/tls.zig:472:39: 0x123dfeb in readAtLeast__anon_10807 (http_get_std)
        if (actual_amt < request_amt) return error.TlsConnectionTruncated;
                                      ^
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/crypto/tls.zig:480:9: 0x123e2d4 in readAtLeastOurAmt__anon_10806 (http_get_std)
        try readAtLeast(d, stream, our_amt);
        ^
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/crypto/tls/Client.zig:238:9: 0x120b3f5 in init__anon_9815 (http_get_std)
        try d.readAtLeastOurAmt(stream, tls.record_header_len);
        ^
/usr/local/zig/zig-linux-x86_64-0.14.0-dev.66+1fdf13a14/lib/std/http/Client.zig:1357:99: 0x115476b in connectTcp (http_get_std)
        conn.data.tls_client.* = std.crypto.tls.Client.init(stream, client.ca_bundle, host) catch return error.TlsInitializationFailed;

https://github.com/ziglang/zig/blob/f7d72ce881db7162aa74ec0fa05ee3af76ecfe1c/lib/std/crypto/tls/Client.zig#L174

Domain: