Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
1 task
Tracked by #14178
andrewrk opened this issue Jan 3, 2023 · 39 comments
Closed
1 task
Tracked by #14178

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

andrewrk opened this issue Jan 3, 2023 · 39 comments
Labels
bug Observed behavior contradicts documented or intended behavior contributor friendly This issue is limited in scope and/or knowledge of Zig internals. standard library This issue involves writing Zig code for the standard library.
Milestone

Comments

@andrewrk
Copy link
Member

andrewrk commented Jan 3, 2023

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.

@andrewrk andrewrk added bug Observed behavior contradicts documented or intended behavior contributor friendly This issue is limited in scope and/or knowledge of Zig internals. standard library This issue involves writing Zig code for the standard library. labels Jan 3, 2023
@andrewrk andrewrk added this to the 0.11.0 milestone Jan 3, 2023
@trgwii
Copy link

trgwii commented Jan 12, 2023

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

@rofrol
Copy link
Contributor

rofrol commented Jan 16, 2023

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
Copy link
Contributor

kassane commented Jan 17, 2023

@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
Copy link
Contributor

rofrol commented Jan 17, 2023

@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
Copy link
Contributor

TUSF commented Jan 25, 2023

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
Copy link
Contributor

rofrol commented Jan 26, 2023

@star-tek-mb
Copy link
Contributor

star-tek-mb commented Jan 27, 2023

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
Copy link

trgwii commented Jan 30, 2023

@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
Copy link
Contributor

@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

const cipher_suites = enum_array(tls.CipherSuite, &.{

Leave AES_128_GCM_SHA256 and CHACHA20_POLY1305_SHA256. Those are working ones.

@trgwii
Copy link

trgwii commented Feb 10, 2023

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
Copy link
Contributor

fubark commented Feb 16, 2023

I used #14172 (comment) 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 #14172 (comment) but it ends up hanging.

@trgwii
Copy link

trgwii commented Feb 23, 2023

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

@angaz
Copy link

angaz commented Mar 1, 2023

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
Copy link
Contributor

jedisct1 commented Mar 21, 2023

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
Copy link
Contributor

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
Copy link

ericlanderson commented Apr 29, 2023

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 #14172 (comment) 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
Copy link

dadrian commented May 29, 2023

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
Copy link
Contributor

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
Copy link

dadrian commented May 30, 2023

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
Copy link

gui36 commented Jun 16, 2023

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 andrewrk added this to the 0.12.0 milestone Jul 20, 2023
@andrewrk
Copy link
Member Author

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

@ghost
Copy link

ghost commented Jul 21, 2023

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
Copy link
Contributor

Atomk commented Jul 21, 2023

@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
Copy link

ghost commented Jul 21, 2023

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
Copy link
Member Author

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
Copy link

cztomsik commented Oct 13, 2023

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
Copy link

cztomsik commented Oct 25, 2023

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
Copy link
Contributor

Cloudef commented Jan 1, 2024

In the meantime you can use zig-curl jiacai2050/zig-curl#4

@melonedo
Copy link
Contributor

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
Copy link

VisenDev commented Feb 8, 2024

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
Copy link

3052 commented Feb 8, 2024

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
Copy link
Contributor

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

@nektro
Copy link
Contributor

nektro commented Feb 22, 2024

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

@Cloudef
Copy link
Contributor

Cloudef commented Feb 26, 2024

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

@melonedo
Copy link
Contributor

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
Copy link
Contributor

Cloudef commented Feb 26, 2024

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

@matdibu
Copy link

matdibu commented Jun 3, 2024

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
Copy link
Contributor

ianic commented Jun 20, 2024

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:

  • whatsapp.com
  • wa.me
  • facebook.com
  • instagram.com
  • m.me
  • fb.com
  • fb.me

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

  • wrapped record, application data 1017 bytes
  • wrapped record, application data 1517 bytes
  • wrapped record, application data 495 bytes

Those 3 tls wrapped records contain following handshake messages:

  • handshake certificate 2844 bytes
  • handshake certificate verify 74 bytes
  • handshake protocol finished 32 bytes

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:

  • googleblog.com,
  • feedburner.com,
  • g.page,
  • googleusercontent.com,
  • marriott.com.

3. certificate chain not continuous

Domain:

  • terra.com.br

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.

}) ++ tls.extension(.signature_algorithms, enum_array(tls.SignatureScheme, &.{

Domain:

  • dailymotion.com

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;

})) ++ tls.extension(.supported_groups, enum_array(tls.NamedGroup, &.{

Domain:

  • home.pl

@andrewrk
Copy link
Member Author

andrewrk commented Nov 8, 2024

I consider the criteria for this to be met by #21872 (comment)

Any issues with specific sites can be now tracked separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior contributor friendly This issue is limited in scope and/or knowledge of Zig internals. standard library This issue involves writing Zig code for the standard library.
Projects
Status: Quality Assurance
Development

Successfully merging a pull request may close this issue.