From c89bc56f6ad1e06cbcacc81d835f696c69e3e916 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Wed, 7 Jul 2021 21:44:27 -0700 Subject: [PATCH] Add HTTP/HTTPS Fetch() API to redbean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit You can now say the following in your redbean Lua code: status,headers,payload = Fetch("https://foo.example") The following Lua APIs have been introduced: - Fetch(str) β†’ str,{str:str},str - GetHttpReason(int) β†’ str - GetHttpReason(int) β†’ str - ProgramSslFetchVerify(bool) - ProgramSslClientVerify(bool) The following flags have been introduced: - `-j` enables client SSL verification - `-k` disables Fetch() SSL verification - `-t INT` may now be passed a negative value for keepalive Lua exceptions now invoke Cosmopolitan's garbage collector when unwinding the stack. So it's now safe to use _gc() w/ Lua 𝔱π”₯𝔯𝔬𝔴 See #97 --- Makefile | 3 +- examples/curl.c | 422 ++++++--- examples/examples.mk | 1 + libc/sysv/consts.sh | 4 +- libc/sysv/consts/TCP_FASTOPEN_CONNECT.S | 2 + libc/sysv/consts/TCP_ULP.S | 2 + libc/sysv/consts/tcp.h | 60 +- net/http/http.h | 5 + net/http/http.mk | 29 +- net/http/isacceptablehost.c | 2 + net/http/unchunk.c | 2 +- net/https/describesslverifyfailure.c | 60 ++ net/https/formatssltime.c | 37 + net/https/getsslroots.c | 69 ++ net/https/https.h | 14 + net/https/https.mk | 55 ++ net/net.mk | 3 +- test/libc/dns/parsehoststxt_test.c | 12 +- test/net/http/unchunk_test.c | 1 + third_party/lua/ldo.c | 5 +- third_party/mbedtls/ctr_drbg.c | 2 +- third_party/mbedtls/ctr_drbg.h | 2 +- third_party/mbedtls/mbedtls.mk | 7 +- third_party/mbedtls/ssl.h | 4 +- third_party/mbedtls/ssl_msg.c | 4 +- third_party/mbedtls/x509_crt.c | 9 +- tool/build/deltaify.c | 96 ++ tool/net/counters.inc | 2 + tool/net/demo/fetch.lua | 74 ++ tool/net/demo/hello.lua | 4 +- tool/net/help.txt | 6 +- tool/net/net.mk | 6 +- tool/net/redbean.c | 1104 +++++++++++++++-------- usr/share/ssl/root/digicert.pem | 78 ++ usr/share/ssl/root/isrg.pem | 16 + 35 files changed, 1611 insertions(+), 591 deletions(-) create mode 100644 libc/sysv/consts/TCP_FASTOPEN_CONNECT.S create mode 100644 libc/sysv/consts/TCP_ULP.S create mode 100644 net/https/describesslverifyfailure.c create mode 100644 net/https/formatssltime.c create mode 100644 net/https/getsslroots.c create mode 100644 net/https/https.h create mode 100644 net/https/https.mk create mode 100644 tool/build/deltaify.c create mode 100644 tool/net/demo/fetch.lua diff --git a/Makefile b/Makefile index bfc3cb0cd..a2d585528 100644 --- a/Makefile +++ b/Makefile @@ -130,13 +130,14 @@ include libc/sock/sock.mk #─┐ include dsp/tty/tty.mk # β”œβ”€β”€ONLINE RUNTIME include libc/dns/dns.mk # β”‚ You can communicate with the network include net/http/http.mk # β”‚ +include third_party/mbedtls/mbedtls.mk # β”‚ +include net/https/https.mk # β”‚ include third_party/regex/regex.mk #β”€β”˜ include third_party/third_party.mk include libc/testlib/testlib.mk include tool/viz/lib/vizlib.mk include third_party/lua/lua.mk include third_party/sqlite3/sqlite3.mk -include third_party/mbedtls/mbedtls.mk include third_party/mbedtls/test/test.mk include third_party/quickjs/quickjs.mk include third_party/lz4cli/lz4cli.mk diff --git a/examples/curl.c b/examples/curl.c index 5b96ccf70..d3f1bcd1f 100644 --- a/examples/curl.c +++ b/examples/curl.c @@ -9,6 +9,7 @@ #endif #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" +#include "libc/dce.h" #include "libc/dns/dns.h" #include "libc/errno.h" #include "libc/fmt/conv.h" @@ -24,33 +25,26 @@ #include "libc/str/str.h" #include "libc/sysv/consts/af.h" #include "libc/sysv/consts/dt.h" +#include "libc/sysv/consts/ex.h" +#include "libc/sysv/consts/exit.h" #include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/shut.h" +#include "libc/sysv/consts/so.h" #include "libc/sysv/consts/sock.h" +#include "libc/sysv/consts/sol.h" +#include "libc/sysv/consts/tcp.h" +#include "libc/time/struct/tm.h" #include "libc/x/x.h" #include "net/http/http.h" #include "net/http/url.h" +#include "net/https/https.h" +#include "third_party/getopt/getopt.h" #include "third_party/mbedtls/ctr_drbg.h" #include "third_party/mbedtls/debug.h" #include "third_party/mbedtls/error.h" +#include "third_party/mbedtls/pk.h" #include "third_party/mbedtls/ssl.h" -STATIC_YOINK("zip_uri_support"); -STATIC_YOINK("usr/share/ssl/root/amazon.pem"); -STATIC_YOINK("usr/share/ssl/root/certum.pem"); -STATIC_YOINK("usr/share/ssl/root/comodo.pem"); -STATIC_YOINK("usr/share/ssl/root/digicert.pem"); -STATIC_YOINK("usr/share/ssl/root/dst.pem"); -STATIC_YOINK("usr/share/ssl/root/geotrust.pem"); -STATIC_YOINK("usr/share/ssl/root/globalsign.pem"); -STATIC_YOINK("usr/share/ssl/root/godaddy.pem"); -STATIC_YOINK("usr/share/ssl/root/google.pem"); -STATIC_YOINK("usr/share/ssl/root/isrg.pem"); -STATIC_YOINK("usr/share/ssl/root/quovadis.pem"); -STATIC_YOINK("usr/share/ssl/root/redbean.pem"); -STATIC_YOINK("usr/share/ssl/root/starfield.pem"); -STATIC_YOINK("usr/share/ssl/root/verisign.pem"); - /** * @fileoverview Downloads HTTP URL to stdout. * @@ -58,45 +52,161 @@ STATIC_YOINK("usr/share/ssl/root/verisign.pem"); * o//examples/curl.com http://justine.lol/ape.html */ +#define HasHeader(H) (!!msg.headers[H].a) +#define HeaderData(H) (p + msg.headers[H].a) +#define HeaderLength(H) (msg.headers[H].b - msg.headers[H].a) +#define HeaderEqualCase(H, S) \ + SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H)) + +struct Buffer { + size_t i, n; + char *p; +}; + +static inline bool SlicesEqualCase(const char *a, size_t n, const char *b, + size_t m) { + return n == m && !memcasecmp(a, b, n); +} + +static bool TuneSocket(int fd, int a, int b, int x) { + if (!b) return false; + return setsockopt(fd, a, b, &x, sizeof(x)) != -1; +} + +static int Socket(int family, int type, int protocol) { + int fd; + if ((fd = socket(family, type, protocol)) != -1) { + TuneSocket(fd, SOL_SOCKET, SO_KEEPALIVE, 1); + if (protocol == SOL_TCP) { + TuneSocket(fd, SOL_TCP, TCP_KEEPIDLE, 60); + TuneSocket(fd, SOL_TCP, TCP_KEEPINTVL, 60); + TuneSocket(fd, SOL_TCP, TCP_FASTOPEN_CONNECT, 1); + if (!TuneSocket(fd, SOL_TCP, TCP_QUICKACK, 1)) { + TuneSocket(fd, SOL_TCP, TCP_NODELAY, 1); + } + } + } + return fd; +} + +static int TlsSend(void *c, const unsigned char *p, size_t n) { + int rc; + CHECK_NE(-1, (rc = write(*(int *)c, p, n))); + return rc; +} + +static int TlsRecv(void *c, unsigned char *p, size_t n, uint32_t t) { + int rc; + CHECK_NE(-1, (rc = read(*(int *)c, p, n))); + return rc; +} + +static void TlsDebug(void *c, int v, const char *f, int l, const char *s) { + flogf(v, f, l, 0, "TLS %s", s); +} + +static char *TlsError(int r) { + static char b[128]; + mbedtls_strerror(r, b, sizeof(b)); + return b; +} + +static wontreturn void PrintUsage(FILE *f, int rc) { + fprintf(f, "usage: %s [-ksvV] URL\n", program_invocation_name); + exit(rc); +} + +static wontreturn void TlsDie(const char *s, int r) { + if (IsTiny()) { + fprintf(stderr, "error: %s (-0x%04x %s)\n", s, -r, TlsError(r)); + } else { + fprintf(stderr, "error: %s (grep -0x%04x)\n", s, -r); + } + exit(1); +} + static int GetEntropy(void *c, unsigned char *p, size_t n) { CHECK_EQ(n, getrandom(p, n, 0)); return 0; } -static int TlsSend(void *ctx, const unsigned char *buf, size_t len) { - int rc; - CHECK_NE(-1, (rc = write(*(int *)ctx, buf, len))); - return rc; -} - -static int TlsRecv(void *ctx, unsigned char *buf, size_t len, uint32_t tmo) { - int rc; - CHECK_NE(-1, (rc = read(*(int *)ctx, buf, len))); - return rc; -} - -static void TlsDebug(void *ctx, int level, const char *file, int line, - const char *message) { - flogf(level, file, line, 0, "TLS %s", message); -} - -static char *TlsError(int rc) { - static char ebuf[128]; - mbedtls_strerror(rc, ebuf, sizeof(ebuf)); - return ebuf; +static int AppendFmt(struct Buffer *b, const char *fmt, ...) { + int n; + char *p; + va_list va, vb; + va_start(va, fmt); + va_copy(vb, va); + n = vsnprintf(b->p + b->i, b->n - b->i, fmt, va); + if (n >= b->n - b->i) { + do { + if (b->n) { + b->n += b->n >> 1; + } else { + b->n = 16; + } + } while (b->i + n > b->n); + b->p = realloc(b->p, b->n); + vsnprintf(b->p + b->i, b->n - b->i, fmt, vb); + } + va_end(vb); + va_end(va); + b->i += n; + return n; } int main(int argc, char *argv[]) { + if (!NoDebug()) showcrashreports(); + + /* + * Read flags. + */ + int opt; + struct Headers { + size_t n; + char **p; + } headers = {0}; + int method = kHttpGet; + bool authmode = MBEDTLS_SSL_VERIFY_REQUIRED; + const char *agent = "hurl/1.o (https://github.com/jart/cosmopolitan)"; + while ((opt = getopt(argc, argv, "qksvVIX:H:A:")) != -1) { + switch (opt) { + case 's': + case 'q': + break; + case 'v': + break; + case 'I': + method = kHttpHead; + break; + case 'A': + agent = optarg; + break; + case 'H': + headers.p = realloc(headers.p, ++headers.n * sizeof(*headers.p)); + headers.p[headers.n - 1] = optarg; + break; + case 'X': + CHECK((method = GetHttpMethod(optarg, strlen(optarg)))); + break; + case 'V': + ++mbedtls_debug_threshold; + break; + case 'k': + authmode = MBEDTLS_SSL_VERIFY_NONE; + break; + case 'h': + PrintUsage(stdout, EXIT_SUCCESS); + default: + PrintUsage(stderr, EX_USAGE); + } + } /* * Get argument. */ const char *urlarg; - if (argc != 2) { - fprintf(stderr, "usage: %s URL\n", argv[0]); - exit(1); - } - urlarg = argv[1]; + if (optind == argc) PrintUsage(stderr, EX_USAGE); + urlarg = argv[optind]; /* * Parse URL. @@ -114,10 +224,17 @@ int main(int argc, char *argv[]) { exit(1); } } - host = firstnonnull(_gc(strndup(url.host.p, url.host.n)), "127.0.0.1"); - port = url.port.n ? _gc(strndup(url.port.p, url.port.n)) - : (usessl ? "443" : "80"); - port = _gc(xasprintf("%hu", atoi(port))); + if (url.host.n) { + host = _gc(strndup(url.host.p, url.host.n)); + if (url.port.n) { + port = _gc(strndup(url.port.p, url.port.n)); + } else { + port = usessl ? "443" : "80"; + } + } else { + host = "127.0.0.1"; + port = usessl ? "443" : "80"; + } if (!IsAcceptableHost(host, -1)) { fprintf(stderr, "error: invalid host: %s\n", urlarg); exit(1); @@ -138,40 +255,17 @@ int main(int argc, char *argv[]) { /* * Create HTTP message. */ - const char *msg; - msg = _gc(xasprintf("GET %s HTTP/1.1\r\n" - "Host: %s:%s\r\n" - "Connection: close\r\n" - "Content-Length: 0\r\n" - "Accept: text/plain; */*\r\n" - "User-Agent: github.com/jart/cosmopolitan\r\n" - "\r\n", - _gc(EncodeUrl(&url, 0)), host, port)); - - /* - * Load root certificates. - */ - mbedtls_x509_crt cacert; - if (usessl) { - DIR *zd; - size_t calen; - const char *dir; - char capath[300]; - uint8_t *cabytes; - struct dirent *ze; - mbedtls_x509_crt_init(&cacert); - dir = "zip:usr/share/ssl/root"; - CHECK((zd = opendir(dir)), "%s", dir); - while ((ze = readdir(zd))) { - if (ze->d_type != DT_REG) continue; - snprintf(capath, sizeof(capath), "%s/%s", dir, ze->d_name); - CHECK((cabytes = xslurp(capath, &calen))); - CHECK_EQ(0, mbedtls_x509_crt_parse(&cacert, cabytes, calen + 1), "%s", - capath); - free(cabytes); - } - closedir(zd); + struct Buffer request = {0}; + AppendFmt(&request, + "%s %s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Connection: close\r\n" + "User-Agent: %s\r\n", + kHttpMethod[method], _gc(EncodeUrl(&url, 0)), host, port, agent); + for (int i = 0; i < headers.n; ++i) { + AppendFmt(&request, "%s\r\n", headers.p[i]); } + AppendFmt(&request, "\r\n"); /* * Setup crypto. @@ -183,16 +277,14 @@ int main(int argc, char *argv[]) { mbedtls_ssl_init(&ssl); mbedtls_ctr_drbg_init(&drbg); mbedtls_ssl_config_init(&conf); - CHECK_EQ(0, mbedtls_ctr_drbg_seed(&drbg, GetEntropy, 0, - (const uint8_t *)"justine", 7)); + CHECK_EQ(0, mbedtls_ctr_drbg_seed(&drbg, GetEntropy, 0, "justine", 7)); CHECK_EQ(0, mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)); - mbedtls_ssl_conf_ca_chain(&conf, &cacert, 0); - mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED); + mbedtls_ssl_conf_ca_chain(&conf, GetSslRoots(), 0); + mbedtls_ssl_conf_authmode(&conf, authmode); mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &drbg); - mbedtls_ssl_conf_dbg(&conf, TlsDebug, 0); - /* mbedtls_debug_set_threshold(5); */ + if (!IsTiny()) mbedtls_ssl_conf_dbg(&conf, TlsDebug, 0); CHECK_EQ(0, mbedtls_ssl_setup(&ssl, &conf)); CHECK_EQ(0, mbedtls_ssl_set_hostname(&ssl, host)); } @@ -211,13 +303,14 @@ int main(int argc, char *argv[]) { * Connect to server. */ int ret, sock; - CHECK_NE(-1, (sock = socket(addr->ai_family, addr->ai_socktype, + CHECK_NE(-1, (sock = Socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol))); CHECK_NE(-1, connect(sock, addr->ai_addr, addr->ai_addrlen)); + freeaddrinfo(addr); if (usessl) { mbedtls_ssl_set_bio(&ssl, &sock, TlsSend, 0, TlsRecv); if ((ret = mbedtls_ssl_handshake(&ssl))) { - FATALF("ssl handshake failed (-0x%04x %s)", -ret, TlsError(ret)); + TlsDie("ssl handshake", ret); } } @@ -225,81 +318,126 @@ int main(int argc, char *argv[]) { * Send HTTP Message. */ if (usessl) { - CHECK_EQ(strlen(msg), mbedtls_ssl_write(&ssl, (void *)msg, strlen(msg))); + ret = mbedtls_ssl_write(&ssl, request.p, request.i); + if (ret != request.i) TlsDie("ssl write", ret); } else { - CHECK_EQ(strlen(msg), write(sock, msg, strlen(msg))); - shutdown(sock, SHUT_WR); + CHECK_EQ(request.i, write(sock, request.p, request.i)); } /* * Handle response. - * TODO(jart): use response/chunk parsers */ - char buf[1500]; - size_t got, toto; - ssize_t rc, need; - const char *crlfcrlf; - buf[0] = '\0'; - if (usessl) { - if ((rc = mbedtls_ssl_read(&ssl, (void *)buf, sizeof(buf))) < 0) { - FATALF("ssl read failed (-0x%04x %s)", -ret, TlsError(rc)); + int t; + char *p; + ssize_t rc; + struct HttpMessage msg; + struct HttpUnchunker u; + size_t g, i, n, hdrlen, paylen; + InitHttpMessage(&msg, kHttpResponse); + for (p = 0, hdrlen = paylen = t = i = n = 0;;) { + if (i == n) { + n += 1000; + n += n >> 1; + p = realloc(p, n); } - } else { - CHECK_NE(-1, (rc = read(sock, buf, sizeof(buf)))); - } - got = rc; - CHECK(startswith(buf, "HTTP/1.1 200") || startswith(buf, "HTTP/1.0 200"), - "%`'.*s", got, buf); - CHECK_NOTNULL((crlfcrlf = memmem(buf, got, "\r\n\r\n", 4))); - need = strtol( - (char *)firstnonnull( - memmem(buf, crlfcrlf - buf, "\r\nContent-Length: ", 18), - firstnonnull(memmem(buf, crlfcrlf - buf, "\r\ncontent-length: ", 18), - "\r\nContent-Length: -1")) + - 18, - NULL, 10); - got = MIN(got - (crlfcrlf + 4 - buf), need); - CHECK_EQ(got, write(1, crlfcrlf + 4, got)); - for (toto = got; need == -1 || toto < need; toto += got) { if (usessl) { - if ((rc = mbedtls_ssl_read(&ssl, (void *)buf, sizeof(buf))) < 0) { + if ((rc = mbedtls_ssl_read(&ssl, p + i, n - i)) < 0) { if (rc == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { - CHECK_EQ(0, mbedtls_ssl_close_notify(&ssl)); - got = 0; - break; + rc = 0; } else { - FATALF("ssl read failed (-0x%04x %s)", -rc, TlsError(rc)); + TlsDie("ssl read", rc); } } } else { - CHECK_NE(-1, (rc = read(sock, buf, sizeof(buf)))); + CHECK_NE(-1, (rc = read(sock, p + i, n - i))); + } + g = rc; + i += g; + switch (t) { + case kHttpClientStateHeaders: + CHECK(g); + CHECK_NE(-1, (rc = ParseHttpMessage(&msg, p, i))); + if (rc) { + hdrlen = rc; + if (100 <= msg.status && msg.status <= 199) { + CHECK(!HasHeader(kHttpContentLength) || + HeaderEqualCase(kHttpContentLength, "0")); + CHECK(!HasHeader(kHttpTransferEncoding) || + HeaderEqualCase(kHttpTransferEncoding, "identity")); + DestroyHttpMessage(&msg); + InitHttpMessage(&msg, kHttpResponse); + memmove(p, p + hdrlen, i - hdrlen); + i -= hdrlen; + break; + } + if (method == kHttpHead) { + CHECK_EQ(hdrlen, write(1, p, hdrlen)); + goto Finished; + } else if (msg.status == 204 || msg.status == 304) { + goto Finished; + } + if (HasHeader(kHttpTransferEncoding) && + !HeaderEqualCase(kHttpTransferEncoding, "identity")) { + CHECK(HeaderEqualCase(kHttpTransferEncoding, "chunked")); + t = kHttpClientStateBodyChunked; + memset(&u, 0, sizeof(u)); + goto Chunked; + } else if (HasHeader(kHttpContentLength)) { + CHECK_NE(-1, (rc = ParseContentLength( + HeaderData(kHttpContentLength), + HeaderLength(kHttpContentLength)))); + t = kHttpClientStateBodyLengthed; + paylen = rc; + if (paylen > i - hdrlen) { + CHECK_EQ(i - hdrlen, write(1, p + hdrlen, i - hdrlen)); + } else { + CHECK_EQ(paylen, write(1, p + hdrlen, paylen)); + goto Finished; + } + } else { + t = kHttpClientStateBody; + CHECK_EQ(i - hdrlen, write(1, p + hdrlen, i - hdrlen)); + } + } + break; + case kHttpClientStateBody: + if (!g) goto Finished; + CHECK_EQ(g, write(1, p + i - g, g)); + break; + case kHttpClientStateBodyLengthed: + CHECK(g); + if (i - hdrlen > paylen) g = hdrlen + paylen - (i - g); + CHECK_EQ(g, write(1, p + i - g, g)); + if (i - hdrlen >= paylen) goto Finished; + break; + case kHttpClientStateBodyChunked: + Chunked: + CHECK_NE(-1, (rc = Unchunk(&u, p + hdrlen, i - hdrlen, &paylen))); + if (rc) { + CHECK_EQ(paylen, write(1, p + hdrlen, paylen)); + goto Finished; + } + break; + default: + abort(); } - if (!(got = rc)) break; - CHECK_EQ(got, write(1, buf, got)); - } - if (need != -1) { - CHECK_EQ(need, toto); } - /* - * Close connection. - */ - if (got) { - if (usessl) { - CHECK_EQ(0, mbedtls_ssl_close_notify(&ssl)); - CHECK_EQ(MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY, - mbedtls_ssl_read(&ssl, (void *)buf, 1)); - } else { - shutdown(sock, SHUT_RDWR); - CHECK_EQ(0, read(sock, buf, 1)); - } - } +/* + * Close connection. + */ +Finished: CHECK_NE(-1, close(sock)); + + /* + * Free memory. + */ + free(p); + free(headers.p); if (usessl) { mbedtls_ssl_free(&ssl); - mbedtls_x509_crt_free(&cacert); - mbedtls_ssl_config_free(&conf); mbedtls_ctr_drbg_free(&drbg); + mbedtls_ssl_config_free(&conf); } return 0; diff --git a/examples/examples.mk b/examples/examples.mk index 577184647..d797a2d46 100644 --- a/examples/examples.mk +++ b/examples/examples.mk @@ -66,6 +66,7 @@ EXAMPLES_DIRECTDEPS = \ LIBC_X \ LIBC_ZIPOS \ NET_HTTP \ + NET_HTTPS \ THIRD_PARTY_COMPILER_RT \ THIRD_PARTY_DLMALLOC \ THIRD_PARTY_GDTOA \ diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index c5723fd34..4b4acc36f 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -720,11 +720,13 @@ syscon sol SOL_X25 262 0 0 0 0 0 syscon tcp TCP_NODELAY 1 1 1 1 1 1 # strong consensus for disabling nagle's algorithm; so be sure to disable it by turning this on syscon tcp TCP_CORK 3 4 4 16 0 0 # nagle's algorithm strikes again; TCP_NOPUSH on BSD; be sure to turn it off; protip: mmap+writev vs. write+sendfile; see also /proc/sys/net/ipv4/tcp_autocorking; netbsd is 4 but not implemented syscon tcp TCP_MAXSEG 2 2 2 2 2 0 # reduces tcp segment size; see also tcp offloading -syscon tcp TCP_FASTOPEN 23 0 0x0401 0 0 15 # reduces roundtrips; for listener; Linux 3.7+ (c. 2012) / or is windows it 0x22? /proc/sys/net/ipv4/tcp_fastopen TODO(jart): MSG_FASTOPEN; XNU sources say 261 but not sure if that's true +syscon tcp TCP_FASTOPEN 23 0 0x0401 0 0 15 # reduces roundtrips; for listener; Linux 3.7+ (c. 2012) / or is windows it 0x22? /proc/sys/net/ipv4/tcp_fastopen TODO(jart): MSG_FASTOPEN; XNU sources say 261 but not sure if that's true +syscon tcp TCP_FASTOPEN_CONNECT 30 0 0 0 0 0 # reduces roundtrips; for listener; Linux 3.7+ (c. 2012) / or is windows it 0x22? /proc/sys/net/ipv4/tcp_fastopen TODO(jart): MSG_FASTOPEN; XNU sources say 261 but not sure if that's true syscon tcp TCP_KEEPIDLE 4 0 0x100 0 3 0 # keepalives syscon tcp TCP_KEEPINTVL 5 0x101 0x200 0 5 0 # keepalives syscon tcp TCP_KEEPCNT 6 0x102 0x400 0 6 0 # keepalives syscon tcp TCP_SYNCNT 7 0 0 0 0 0 # how hard to syn packet the enemy +syscon tcp TCP_ULP 31 0 0 0 0 0 # setsockopt(sock, IPPROTO_TCP, TCP_ULP, "tls", 4) syscon tcp TCP_COOKIE_TRANSACTIONS 15 0 0 0 0 0 # defense against the syn packets syscon tcp TCP_LINGER2 8 0 0 0 0 0 # orphaned fin-wait-2 lifetime cf. net.ipv4.tcp_fin_timeout see cloudflare blog syscon tcp TCP_NOTSENT_LOWAT 25 513 0 0 0 0 # limit unset byte queue diff --git a/libc/sysv/consts/TCP_FASTOPEN_CONNECT.S b/libc/sysv/consts/TCP_FASTOPEN_CONNECT.S new file mode 100644 index 000000000..289072631 --- /dev/null +++ b/libc/sysv/consts/TCP_FASTOPEN_CONNECT.S @@ -0,0 +1,2 @@ +#include "libc/sysv/consts/syscon.internal.h" +.syscon tcp,TCP_FASTOPEN_CONNECT,30,0,0,0,0,0 diff --git a/libc/sysv/consts/TCP_ULP.S b/libc/sysv/consts/TCP_ULP.S new file mode 100644 index 000000000..292a3681c --- /dev/null +++ b/libc/sysv/consts/TCP_ULP.S @@ -0,0 +1,2 @@ +#include "libc/sysv/consts/syscon.internal.h" +.syscon tcp,TCP_ULP,31,0,0,0,0,0 diff --git a/libc/sysv/consts/tcp.h b/libc/sysv/consts/tcp.h index ec62a3d2e..0fd438a65 100644 --- a/libc/sysv/consts/tcp.h +++ b/libc/sysv/consts/tcp.h @@ -10,6 +10,7 @@ extern const long TCP_COOKIE_TRANSACTIONS; extern const long TCP_CORK; extern const long TCP_DEFER_ACCEPT; extern const long TCP_FASTOPEN; +extern const long TCP_FASTOPEN_CONNECT; extern const long TCP_INFO; extern const long TCP_KEEPCNT; extern const long TCP_KEEPIDLE; @@ -31,40 +32,43 @@ extern const long TCP_SYNCNT; extern const long TCP_THIN_DUPACK; extern const long TCP_THIN_LINEAR_TIMEOUTS; extern const long TCP_TIMESTAMP; +extern const long TCP_ULP; extern const long TCP_USER_TIMEOUT; extern const long TCP_WINDOW_CLAMP; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#define TCP_CC_INFO SYMBOLIC(TCP_CC_INFO) -#define TCP_CONGESTION SYMBOLIC(TCP_CONGESTION) -#define TCP_COOKIE_TRANSACTIONS SYMBOLIC(TCP_COOKIE_TRANSACTIONS) -#define TCP_CORK SYMBOLIC(TCP_CORK) -#define TCP_DEFER_ACCEPT SYMBOLIC(TCP_DEFER_ACCEPT) -#define TCP_FASTOPEN SYMBOLIC(TCP_FASTOPEN) -#define TCP_INFO SYMBOLIC(TCP_INFO) -#define TCP_KEEPCNT SYMBOLIC(TCP_KEEPCNT) -#define TCP_KEEPIDLE SYMBOLIC(TCP_KEEPIDLE) -#define TCP_KEEPINTVL SYMBOLIC(TCP_KEEPINTVL) -#define TCP_LINGER2 SYMBOLIC(TCP_LINGER2) -#define TCP_MAXSEG SYMBOLIC(TCP_MAXSEG) -#define TCP_MD5SIG SYMBOLIC(TCP_MD5SIG) -#define TCP_MD5SIG_MAXKEYLEN SYMBOLIC(TCP_MD5SIG_MAXKEYLEN) -#define TCP_NODELAY LITERALLY(1) -#define TCP_NOTSENT_LOWAT SYMBOLIC(TCP_NOTSENT_LOWAT) -#define TCP_QUEUE_SEQ SYMBOLIC(TCP_QUEUE_SEQ) -#define TCP_QUICKACK SYMBOLIC(TCP_QUICKACK) -#define TCP_REPAIR SYMBOLIC(TCP_REPAIR) -#define TCP_REPAIR_OPTIONS SYMBOLIC(TCP_REPAIR_OPTIONS) -#define TCP_REPAIR_QUEUE SYMBOLIC(TCP_REPAIR_QUEUE) -#define TCP_SAVED_SYN SYMBOLIC(TCP_SAVED_SYN) -#define TCP_SAVE_SYN SYMBOLIC(TCP_SAVE_SYN) -#define TCP_SYNCNT SYMBOLIC(TCP_SYNCNT) -#define TCP_THIN_DUPACK SYMBOLIC(TCP_THIN_DUPACK) +#define TCP_CC_INFO SYMBOLIC(TCP_CC_INFO) +#define TCP_CONGESTION SYMBOLIC(TCP_CONGESTION) +#define TCP_COOKIE_TRANSACTIONS SYMBOLIC(TCP_COOKIE_TRANSACTIONS) +#define TCP_CORK SYMBOLIC(TCP_CORK) +#define TCP_DEFER_ACCEPT SYMBOLIC(TCP_DEFER_ACCEPT) +#define TCP_FASTOPEN SYMBOLIC(TCP_FASTOPEN) +#define TCP_FASTOPEN_CONNECT SYMBOLIC(TCP_FASTOPEN_CONNECT) +#define TCP_INFO SYMBOLIC(TCP_INFO) +#define TCP_KEEPCNT SYMBOLIC(TCP_KEEPCNT) +#define TCP_KEEPIDLE SYMBOLIC(TCP_KEEPIDLE) +#define TCP_KEEPINTVL SYMBOLIC(TCP_KEEPINTVL) +#define TCP_LINGER2 SYMBOLIC(TCP_LINGER2) +#define TCP_MAXSEG SYMBOLIC(TCP_MAXSEG) +#define TCP_MD5SIG SYMBOLIC(TCP_MD5SIG) +#define TCP_MD5SIG_MAXKEYLEN SYMBOLIC(TCP_MD5SIG_MAXKEYLEN) +#define TCP_NODELAY LITERALLY(1) +#define TCP_NOTSENT_LOWAT SYMBOLIC(TCP_NOTSENT_LOWAT) +#define TCP_QUEUE_SEQ SYMBOLIC(TCP_QUEUE_SEQ) +#define TCP_QUICKACK SYMBOLIC(TCP_QUICKACK) +#define TCP_REPAIR SYMBOLIC(TCP_REPAIR) +#define TCP_REPAIR_OPTIONS SYMBOLIC(TCP_REPAIR_OPTIONS) +#define TCP_REPAIR_QUEUE SYMBOLIC(TCP_REPAIR_QUEUE) +#define TCP_SAVED_SYN SYMBOLIC(TCP_SAVED_SYN) +#define TCP_SAVE_SYN SYMBOLIC(TCP_SAVE_SYN) +#define TCP_SYNCNT SYMBOLIC(TCP_SYNCNT) +#define TCP_THIN_DUPACK SYMBOLIC(TCP_THIN_DUPACK) #define TCP_THIN_LINEAR_TIMEOUTS SYMBOLIC(TCP_THIN_LINEAR_TIMEOUTS) -#define TCP_TIMESTAMP SYMBOLIC(TCP_TIMESTAMP) -#define TCP_USER_TIMEOUT SYMBOLIC(TCP_USER_TIMEOUT) -#define TCP_WINDOW_CLAMP SYMBOLIC(TCP_WINDOW_CLAMP) +#define TCP_TIMESTAMP SYMBOLIC(TCP_TIMESTAMP) +#define TCP_ULP SYMBOLIC(TCP_ULP) +#define TCP_USER_TIMEOUT SYMBOLIC(TCP_USER_TIMEOUT) +#define TCP_WINDOW_CLAMP SYMBOLIC(TCP_WINDOW_CLAMP) #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_TCP_H_ */ diff --git a/net/http/http.h b/net/http/http.h index a92c00b7b..26c506d3b 100644 --- a/net/http/http.h +++ b/net/http/http.h @@ -36,6 +36,11 @@ #define kHttpStateLf1 10 #define kHttpStateLf2 11 +#define kHttpClientStateHeaders 0 +#define kHttpClientStateBody 1 +#define kHttpClientStateBodyChunked 2 +#define kHttpClientStateBodyLengthed 3 + #define kHttpStateChunkStart 0 #define kHttpStateChunkSize 1 #define kHttpStateChunkExt 2 diff --git a/net/http/http.mk b/net/http/http.mk index fb9fe2ee3..007bc3298 100644 --- a/net/http/http.mk +++ b/net/http/http.mk @@ -8,39 +8,22 @@ NET_HTTP = $(NET_HTTP_A_DEPS) $(NET_HTTP_A) NET_HTTP_A = o/$(MODE)/net/http/http.a NET_HTTP_A_FILES := $(wildcard net/http/*) NET_HTTP_A_HDRS = $(filter %.h,$(NET_HTTP_A_FILES)) -NET_HTTP_A_SRCS_S = $(filter %.S,$(NET_HTTP_A_FILES)) -NET_HTTP_A_SRCS_C = $(filter %.c,$(NET_HTTP_A_FILES)) -NET_HTTP_A_SRCS_R = $(filter %.rl,$(NET_HTTP_A_FILES)) - -NET_HTTP_A_SRCS = \ - $(NET_HTTP_A_SRCS_S) \ - $(NET_HTTP_A_SRCS_C) \ - $(NET_HTTP_A_SRCS_R) - -NET_HTTP_A_OBJS = \ - $(NET_HTTP_A_SRCS_S:%.S=o/$(MODE)/%.o) \ - $(NET_HTTP_A_SRCS_C:%.c=o/$(MODE)/%.o) \ - $(NET_HTTP_A_SRCS_R:%.rl=o/$(MODE)/%.o) +NET_HTTP_A_SRCS = $(filter %.c,$(NET_HTTP_A_FILES)) +NET_HTTP_A_OBJS = $(NET_HTTP_A_SRCS:%.c=o/$(MODE)/%.o) NET_HTTP_A_CHECKS = \ $(NET_HTTP_A).pkg \ $(NET_HTTP_A_HDRS:%=o/$(MODE)/%.ok) NET_HTTP_A_DIRECTDEPS = \ - LIBC_CALLS \ LIBC_FMT \ LIBC_INTRIN \ - LIBC_LOG \ LIBC_MEM \ LIBC_NEXGEN32E \ - LIBC_RUNTIME \ - LIBC_SOCK \ - LIBC_STDIO \ LIBC_STR \ LIBC_STUBS \ LIBC_SYSV \ - LIBC_TIME \ - LIBC_X + LIBC_TIME NET_HTTP_A_DEPS := \ $(call uniq,$(foreach x,$(NET_HTTP_A_DIRECTDEPS),$($(x)))) @@ -76,10 +59,8 @@ o/$(MODE)/net/http/formathttpdatetime.o: \ NET_HTTP_LIBS = $(foreach x,$(NET_HTTP_ARTIFACTS),$($(x))) NET_HTTP_SRCS = $(foreach x,$(NET_HTTP_ARTIFACTS),$($(x)_SRCS)) NET_HTTP_HDRS = $(foreach x,$(NET_HTTP_ARTIFACTS),$($(x)_HDRS)) -NET_HTTP_CHECKS = $(foreach x,$(NET_HTTP_ARTIFACTS),$($(x)_CHECKS)) NET_HTTP_OBJS = $(foreach x,$(NET_HTTP_ARTIFACTS),$($(x)_OBJS)) +NET_HTTP_CHECKS = $(foreach x,$(NET_HTTP_ARTIFACTS),$($(x)_CHECKS)) .PHONY: o/$(MODE)/net/http -o/$(MODE)/net/http: \ - $(NET_HTTP_CHECKS) \ - $(NET_HTTP_A_SRCS_R:%.rl=%.svgz) +o/$(MODE)/net/http: $(NET_HTTP_CHECKS) diff --git a/net/http/isacceptablehost.c b/net/http/isacceptablehost.c index f9e2faa9a..e6ce20382 100644 --- a/net/http/isacceptablehost.c +++ b/net/http/isacceptablehost.c @@ -16,6 +16,7 @@ β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR β”‚ β”‚ PERFORMANCE OF THIS SOFTWARE. β”‚ β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/ +#include "libc/dns/dns.h" #include "libc/str/str.h" #include "net/http/http.h" @@ -72,6 +73,7 @@ bool IsAcceptableHost(const char *s, size_t n) { int c, b, j; if (n == -1) n = s ? strlen(s) : 0; if (!n) return true; + if (n > DNS_NAME_MAX) return false; for (b = j = i = 0; i < n; ++i) { c = s[i] & 255; if (isdigit(c)) { diff --git a/net/http/unchunk.c b/net/http/unchunk.c index 3850dbfed..f87750ffc 100644 --- a/net/http/unchunk.c +++ b/net/http/unchunk.c @@ -43,7 +43,7 @@ ssize_t Unchunk(struct HttpUnchunker *u, char *p, size_t n, size_t *l) { if ((h = kHexToInt[c]) != -1) { u->m *= 16; u->m += h; - if (u->i + u->m >= n) return ebadmsg(); + if (u->m >= 0x0000010000000000) return ebadmsg(); break; } u->t = kHttpStateChunkExt; diff --git a/net/https/describesslverifyfailure.c b/net/https/describesslverifyfailure.c new file mode 100644 index 000000000..e02a3a151 --- /dev/null +++ b/net/https/describesslverifyfailure.c @@ -0,0 +1,60 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚ +β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :viβ”‚ +β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘ +β”‚ Copyright 2021 Justine Alexandra Roberts Tunney β”‚ +β”‚ β”‚ +β”‚ Permission to use, copy, modify, and/or distribute this software for β”‚ +β”‚ any purpose with or without fee is hereby granted, provided that the β”‚ +β”‚ above copyright notice and this permission notice appear in all copies. β”‚ +β”‚ β”‚ +β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL β”‚ +β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED β”‚ +β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE β”‚ +β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL β”‚ +β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR β”‚ +β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER β”‚ +β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR β”‚ +β”‚ PERFORMANCE OF THIS SOFTWARE. β”‚ +β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/ +#include "libc/macros.internal.h" +#include "libc/mem/mem.h" +#include "libc/str/str.h" +#include "net/https/https.h" + +static const struct thatispacked SslVerifyString { + int code; + const char *str; +} kSslVerifyStrings[] = { + {MBEDTLS_X509_BADCERT_BAD_KEY, "badcert_bad_key"}, + {MBEDTLS_X509_BADCERT_BAD_MD, "badcert_bad_md"}, + {MBEDTLS_X509_BADCERT_BAD_PK, "badcert_bad_pk"}, + {MBEDTLS_X509_BADCERT_CN_MISMATCH, "badcert_cn_mismatch"}, + {MBEDTLS_X509_BADCERT_EXPIRED, "badcert_expired"}, + {MBEDTLS_X509_BADCERT_EXT_KEY_USAGE, "badcert_ext_key_usage"}, + {MBEDTLS_X509_BADCERT_FUTURE, "badcert_future"}, + {MBEDTLS_X509_BADCERT_KEY_USAGE, "badcert_key_usage"}, + {MBEDTLS_X509_BADCERT_MISSING, "badcert_missing"}, + {MBEDTLS_X509_BADCERT_NOT_TRUSTED, "badcert_not_trusted"}, + {MBEDTLS_X509_BADCERT_NS_CERT_TYPE, "badcert_ns_cert_type"}, + {MBEDTLS_X509_BADCERT_OTHER, "badcert_other"}, + {MBEDTLS_X509_BADCERT_REVOKED, "badcert_revoked"}, + {MBEDTLS_X509_BADCERT_SKIP_VERIFY, "badcert_skip_verify"}, + {MBEDTLS_X509_BADCRL_BAD_KEY, "badcrl_bad_key"}, + {MBEDTLS_X509_BADCRL_BAD_MD, "badcrl_bad_md"}, + {MBEDTLS_X509_BADCRL_BAD_PK, "badcrl_bad_pk"}, + {MBEDTLS_X509_BADCRL_EXPIRED, "badcrl_expired"}, + {MBEDTLS_X509_BADCRL_FUTURE, "badcrl_future"}, + {MBEDTLS_X509_BADCRL_NOT_TRUSTED, "badcrl_not_trusted"}, +}; + +char *DescribeSslVerifyFailure(int flags) { + int i; + char *p, *q; + p = malloc(1024); + q = stpcpy(p, "verify failed"); + for (i = 0; i < ARRAYLEN(kSslVerifyStrings); ++i) { + if (!(flags & kSslVerifyStrings[i].code)) continue; + q = stpcpy(stpcpy(q, " "), kSslVerifyStrings[i].str); + } + return p; +} diff --git a/net/https/formatssltime.c b/net/https/formatssltime.c new file mode 100644 index 000000000..124a5eba0 --- /dev/null +++ b/net/https/formatssltime.c @@ -0,0 +1,37 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚ +β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :viβ”‚ +β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘ +β”‚ Copyright 2021 Justine Alexandra Roberts Tunney β”‚ +β”‚ β”‚ +β”‚ Permission to use, copy, modify, and/or distribute this software for β”‚ +β”‚ any purpose with or without fee is hereby granted, provided that the β”‚ +β”‚ above copyright notice and this permission notice appear in all copies. β”‚ +β”‚ β”‚ +β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL β”‚ +β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED β”‚ +β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE β”‚ +β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL β”‚ +β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR β”‚ +β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER β”‚ +β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR β”‚ +β”‚ PERFORMANCE OF THIS SOFTWARE. β”‚ +β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/ +#include "net/https/https.h" + +void FormatSslTime(char p[restrict hasatleast 16], struct tm *tm) { + p[0x0] = '0' + (tm->tm_year + 1900) / 1000; + p[0x1] = '0' + (tm->tm_year + 1900) / 100 % 10; + p[0x2] = '0' + (tm->tm_year + 1900) / 10 % 10; + p[0x3] = '0' + (tm->tm_year + 1900) % 10; + p[0x4] = '0' + (tm->tm_mon + 1) / 10; + p[0x5] = '0' + (tm->tm_mon + 1) % 10; + p[0x6] = '0' + tm->tm_mday / 10; + p[0x7] = '0' + tm->tm_mday % 10; + p[0x8] = '0' + tm->tm_hour / 10; + p[0x9] = '0' + tm->tm_hour % 10; + p[0xa] = '0' + tm->tm_min / 10; + p[0xb] = '0' + tm->tm_min % 10; + p[0xc] = '0' + tm->tm_sec / 10; + p[0xd] = '0' + tm->tm_sec % 10; + p[0xe] = 0; +} diff --git a/net/https/getsslroots.c b/net/https/getsslroots.c new file mode 100644 index 000000000..68e811621 --- /dev/null +++ b/net/https/getsslroots.c @@ -0,0 +1,69 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚ +β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :viβ”‚ +β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘ +β”‚ Copyright 2021 Justine Alexandra Roberts Tunney β”‚ +β”‚ β”‚ +β”‚ Permission to use, copy, modify, and/or distribute this software for β”‚ +β”‚ any purpose with or without fee is hereby granted, provided that the β”‚ +β”‚ above copyright notice and this permission notice appear in all copies. β”‚ +β”‚ β”‚ +β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL β”‚ +β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED β”‚ +β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE β”‚ +β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL β”‚ +β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR β”‚ +β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER β”‚ +β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR β”‚ +β”‚ PERFORMANCE OF THIS SOFTWARE. β”‚ +β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/ +#include "libc/calls/calls.h" +#include "libc/calls/struct/dirent.h" +#include "libc/errno.h" +#include "libc/log/check.h" +#include "libc/runtime/runtime.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/dt.h" +#include "libc/sysv/consts/o.h" +#include "libc/x/x.h" +#include "net/https/https.h" +#include "third_party/mbedtls/x509_crt.h" + +STATIC_YOINK("zip_uri_support"); +STATIC_YOINK("usr/share/ssl/root/amazon.pem"); +STATIC_YOINK("usr/share/ssl/root/certum.pem"); +STATIC_YOINK("usr/share/ssl/root/comodo.pem"); +STATIC_YOINK("usr/share/ssl/root/digicert.pem"); +STATIC_YOINK("usr/share/ssl/root/dst.pem"); +STATIC_YOINK("usr/share/ssl/root/geotrust.pem"); +STATIC_YOINK("usr/share/ssl/root/globalsign.pem"); +STATIC_YOINK("usr/share/ssl/root/godaddy.pem"); +STATIC_YOINK("usr/share/ssl/root/google.pem"); +STATIC_YOINK("usr/share/ssl/root/isrg.pem"); +STATIC_YOINK("usr/share/ssl/root/quovadis.pem"); +STATIC_YOINK("usr/share/ssl/root/redbean.pem"); +STATIC_YOINK("usr/share/ssl/root/starfield.pem"); +STATIC_YOINK("usr/share/ssl/root/verisign.pem"); + +mbedtls_x509_crt *GetSslRoots(void) { + int fd; + DIR *d; + uint8_t *p; + size_t n, m; + struct dirent *e; + mbedtls_x509_crt *c; + char path[PATH_MAX + 1]; + c = calloc(1, sizeof(*c)); + m = stpcpy(path, "zip:usr/share/ssl/root/") - path; + if ((d = opendir(path))) { + while ((e = readdir(d))) { + if (e->d_type != DT_REG) continue; + if (m + (n = strlen(e->d_name)) > PATH_MAX) continue; + memcpy(path + m, e->d_name, n + 1); + CHECK((p = xslurp(path, &n))); + CHECK_GE(mbedtls_x509_crt_parse(c, p, n + 1), 0, "%s", path); + free(p); + } + closedir(d); + } + return c; +} diff --git a/net/https/https.h b/net/https/https.h new file mode 100644 index 000000000..ec29672e2 --- /dev/null +++ b/net/https/https.h @@ -0,0 +1,14 @@ +#ifndef COSMOPOLITAN_NET_HTTPS_HTTPS_H_ +#define COSMOPOLITAN_NET_HTTPS_HTTPS_H_ +#include "libc/time/struct/tm.h" +#include "third_party/mbedtls/x509_crt.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +char *DescribeSslVerifyFailure(int); +mbedtls_x509_crt *GetSslRoots(void); +void FormatSslTime(char[restrict hasatleast 16], struct tm *); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_NET_HTTPS_HTTPS_H_ */ diff --git a/net/https/https.mk b/net/https/https.mk new file mode 100644 index 000000000..bb681b437 --- /dev/null +++ b/net/https/https.mk @@ -0,0 +1,55 @@ +#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ +#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :viβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +PKGS += NET_HTTPS + +NET_HTTPS_ARTIFACTS += NET_HTTPS_A +NET_HTTPS = $(NET_HTTPS_A_DEPS) $(NET_HTTPS_A) +NET_HTTPS_A = o/$(MODE)/net/https/https.a +NET_HTTPS_A_FILES := $(wildcard net/https/*) +NET_HTTPS_A_CERTS := $(wildcard usr/share/ssl/root/*) +NET_HTTPS_A_HDRS = $(filter %.h,$(NET_HTTPS_A_FILES)) +NET_HTTPS_A_SRCS = $(filter %.c,$(NET_HTTPS_A_FILES)) + +NET_HTTPS_A_OBJS = \ + $(NET_HTTPS_A_SRCS:%.c=o/$(MODE)/%.o) \ + $(NET_HTTPS_A_CERTS:%=o/$(MODE)/%.zip.o) + +NET_HTTPS_A_CHECKS = \ + $(NET_HTTPS_A).pkg \ + $(NET_HTTPS_A_HDRS:%=o/$(MODE)/%.ok) + +NET_HTTPS_A_DIRECTDEPS = \ + LIBC_FMT \ + LIBC_INTRIN \ + LIBC_LOG \ + LIBC_MEM \ + LIBC_NEXGEN32E \ + LIBC_RUNTIME \ + LIBC_STDIO \ + LIBC_STR \ + LIBC_STUBS \ + LIBC_SYSV \ + LIBC_X \ + LIBC_ZIPOS \ + THIRD_PARTY_MBEDTLS + +NET_HTTPS_A_DEPS := \ + $(call uniq,$(foreach x,$(NET_HTTPS_A_DIRECTDEPS),$($(x)))) + +$(NET_HTTPS_A): net/https/ \ + $(NET_HTTPS_A).pkg \ + $(NET_HTTPS_A_OBJS) + +$(NET_HTTPS_A).pkg: \ + $(NET_HTTPS_A_OBJS) \ + $(foreach x,$(NET_HTTPS_A_DIRECTDEPS),$($(x)_A).pkg) + +NET_HTTPS_LIBS = $(foreach x,$(NET_HTTPS_ARTIFACTS),$($(x))) +NET_HTTPS_SRCS = $(foreach x,$(NET_HTTPS_ARTIFACTS),$($(x)_SRCS)) +NET_HTTPS_HDRS = $(foreach x,$(NET_HTTPS_ARTIFACTS),$($(x)_HDRS)) +NET_HTTPS_OBJS = $(foreach x,$(NET_HTTPS_ARTIFACTS),$($(x)_OBJS)) +NET_HTTPS_CHECKS = $(foreach x,$(NET_HTTPS_ARTIFACTS),$($(x)_CHECKS)) + +.PHONY: o/$(MODE)/net/https +o/$(MODE)/net/https: $(NET_HTTPS_CHECKS) diff --git a/net/net.mk b/net/net.mk index 949419a46..88f3ec3e7 100644 --- a/net/net.mk +++ b/net/net.mk @@ -2,4 +2,5 @@ #───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :viβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ .PHONY: o/$(MODE)/net -o/$(MODE)/net: o/$(MODE)/net/http +o/$(MODE)/net: o/$(MODE)/net/http \ + o/$(MODE)/net/https diff --git a/test/libc/dns/parsehoststxt_test.c b/test/libc/dns/parsehoststxt_test.c index 0e1b69b97..5ea5a164f 100644 --- a/test/libc/dns/parsehoststxt_test.c +++ b/test/libc/dns/parsehoststxt_test.c @@ -24,7 +24,7 @@ #include "libc/sysv/consts/af.h" #include "libc/testlib/testlib.h" -static const char *ParseIp(unsigned char ip[4]) { +static const char *parseip(unsigned char ip[4]) { static char g_ipbuf[16]; return inet_ntop(AF_INET, ip, g_ipbuf, sizeof(g_ipbuf)); } @@ -51,16 +51,16 @@ TEST(ParseHostsTxt, testCorrectlyTokenizesAndSorts) { ASSERT_EQ(4, ht->entries.i); EXPECT_STREQ("lol.example.", &ht->strings.p[ht->entries.p[0].name]); EXPECT_STREQ("lol.example.", &ht->strings.p[ht->entries.p[0].canon]); - EXPECT_STREQ("203.0.113.1", ParseIp(ht->entries.p[0].ip)); + EXPECT_STREQ("203.0.113.1", parseip(ht->entries.p[0].ip)); EXPECT_STREQ("lol", &ht->strings.p[ht->entries.p[1].name]); EXPECT_STREQ("lol.example.", &ht->strings.p[ht->entries.p[1].canon]); - EXPECT_STREQ("203.0.113.1", ParseIp(ht->entries.p[1].ip)); + EXPECT_STREQ("203.0.113.1", parseip(ht->entries.p[1].ip)); EXPECT_STREQ("cat.example.", &ht->strings.p[ht->entries.p[2].name]); EXPECT_STREQ("cat.example.", &ht->strings.p[ht->entries.p[2].canon]); - EXPECT_STREQ("203.0.113.2", ParseIp(ht->entries.p[2].ip)); + EXPECT_STREQ("203.0.113.2", parseip(ht->entries.p[2].ip)); EXPECT_STREQ("cat", &ht->strings.p[ht->entries.p[3].name]); EXPECT_STREQ("cat.example.", &ht->strings.p[ht->entries.p[3].canon]); - EXPECT_STREQ("203.0.113.2", ParseIp(ht->entries.p[3].ip)); + EXPECT_STREQ("203.0.113.2", parseip(ht->entries.p[3].ip)); FreeHostsTxt(&ht); fclose(f); } @@ -74,7 +74,7 @@ TEST(ParseHostsTxt, testIpv6_isIgnored) { ASSERT_EQ(1, ht->entries.i); EXPECT_STREQ("cat", &ht->strings.p[ht->entries.p[0].name]); EXPECT_STREQ("cat", &ht->strings.p[ht->entries.p[0].canon]); - EXPECT_STREQ("203.0.113.2", ParseIp(ht->entries.p[0].ip)); + EXPECT_STREQ("203.0.113.2", parseip(ht->entries.p[0].ip)); FreeHostsTxt(&ht); fclose(f); } diff --git a/test/net/http/unchunk_test.c b/test/net/http/unchunk_test.c index d1b1b7d5d..e85c1ee37 100644 --- a/test/net/http/unchunk_test.c +++ b/test/net/http/unchunk_test.c @@ -17,6 +17,7 @@ β”‚ PERFORMANCE OF THIS SOFTWARE. β”‚ β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/ #include "libc/testlib/testlib.h" +#include "libc/x/x.h" #include "net/http/http.h" ssize_t EzUnchunk(char *p, size_t n, size_t *l) { diff --git a/third_party/lua/ldo.c b/third_party/lua/ldo.c index 180ae66e6..4ef41d32a 100644 --- a/third_party/lua/ldo.c +++ b/third_party/lua/ldo.c @@ -7,6 +7,7 @@ #define ldo_c #define LUA_CORE +#include "libc/runtime/gc.h" #include "third_party/lua/lapi.h" #include "third_party/lua/ldebug.h" #include "third_party/lua/ldo.h" @@ -57,14 +58,14 @@ #elif defined(LUA_USE_POSIX) /* }{ */ /* in POSIX, try _longjmp/_setjmp (more efficient) */ -#define LUAI_THROW(L,c) _longjmp((c)->b, 1) +#define LUAI_THROW(L,c) _gclongjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #else /* }{ */ /* ISO C handling with long jumps */ -#define LUAI_THROW(L,c) longjmp((c)->b, 1) +#define LUAI_THROW(L,c) _gclongjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf diff --git a/third_party/mbedtls/ctr_drbg.c b/third_party/mbedtls/ctr_drbg.c index 92b615a5d..c975b7f03 100644 --- a/third_party/mbedtls/ctr_drbg.c +++ b/third_party/mbedtls/ctr_drbg.c @@ -431,7 +431,7 @@ static size_t good_nonce_len( size_t entropy_len ) int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, int (*f_entropy)(void *, unsigned char *, size_t), void *p_entropy, - const unsigned char *custom, + const void *custom, size_t len ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; diff --git a/third_party/mbedtls/ctr_drbg.h b/third_party/mbedtls/ctr_drbg.h index 9b0220d51..6f01d1bb8 100644 --- a/third_party/mbedtls/ctr_drbg.h +++ b/third_party/mbedtls/ctr_drbg.h @@ -244,7 +244,7 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context * ); int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, int (*f_entropy)(void *, unsigned char *, size_t), void *p_entropy, - const unsigned char *custom, + const void *custom, size_t len ); /** diff --git a/third_party/mbedtls/mbedtls.mk b/third_party/mbedtls/mbedtls.mk index fba92c304..b008646b8 100644 --- a/third_party/mbedtls/mbedtls.mk +++ b/third_party/mbedtls/mbedtls.mk @@ -7,13 +7,9 @@ THIRD_PARTY_MBEDTLS_ARTIFACTS += THIRD_PARTY_MBEDTLS_A THIRD_PARTY_MBEDTLS = $(THIRD_PARTY_MBEDTLS_A_DEPS) $(THIRD_PARTY_MBEDTLS_A) THIRD_PARTY_MBEDTLS_A = o/$(MODE)/third_party/mbedtls/mbedtls.a THIRD_PARTY_MBEDTLS_A_FILES := $(wildcard third_party/mbedtls/*) -THIRD_PARTY_MBEDTLS_A_CERTS := $(wildcard usr/share/ssl/root/*) THIRD_PARTY_MBEDTLS_A_HDRS = $(filter %.h,$(THIRD_PARTY_MBEDTLS_A_FILES)) THIRD_PARTY_MBEDTLS_A_SRCS = $(filter %.c,$(THIRD_PARTY_MBEDTLS_A_FILES)) - -THIRD_PARTY_MBEDTLS_A_OBJS = \ - $(THIRD_PARTY_MBEDTLS_A_SRCS:%.c=o/$(MODE)/%.o) \ - $(THIRD_PARTY_MBEDTLS_A_CERTS:%=o/$(MODE)/%.zip.o) +THIRD_PARTY_MBEDTLS_A_OBJS = $(THIRD_PARTY_MBEDTLS_A_SRCS:%.c=o/$(MODE)/%.o) THIRD_PARTY_MBEDTLS_A_CHECKS = \ $(THIRD_PARTY_MBEDTLS_A).pkg \ @@ -33,6 +29,7 @@ THIRD_PARTY_MBEDTLS_A_DIRECTDEPS = \ LIBC_SYSV \ LIBC_TIME \ LIBC_UNICODE \ + NET_HTTP \ THIRD_PARTY_COMPILER_RT \ THIRD_PARTY_GDTOA diff --git a/third_party/mbedtls/ssl.h b/third_party/mbedtls/ssl.h index db26c8093..4abdc8d20 100644 --- a/third_party/mbedtls/ssl.h +++ b/third_party/mbedtls/ssl.h @@ -1429,7 +1429,7 @@ int mbedtls_ssl_handshake( mbedtls_ssl_context * ); int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context * ); int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context * ); int mbedtls_ssl_handshake_step( mbedtls_ssl_context * ); -int mbedtls_ssl_read( mbedtls_ssl_context *, unsigned char *, size_t ); +int mbedtls_ssl_read( mbedtls_ssl_context *, void *, size_t ); int mbedtls_ssl_renegotiate( mbedtls_ssl_context * ); int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *, unsigned char, unsigned char ); int mbedtls_ssl_session_load( mbedtls_ssl_session *, const unsigned char *, size_t ); @@ -1443,7 +1443,7 @@ int mbedtls_ssl_set_hs_own_cert( mbedtls_ssl_context *, mbedtls_x509_crt *, mbed int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *, const unsigned char *, size_t ); int mbedtls_ssl_set_session( mbedtls_ssl_context *, const mbedtls_ssl_session * ); int mbedtls_ssl_setup( mbedtls_ssl_context *, const mbedtls_ssl_config * ); -int mbedtls_ssl_write( mbedtls_ssl_context *, const unsigned char *, size_t ); +int mbedtls_ssl_write( mbedtls_ssl_context *, const void *, size_t ); size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context * ); size_t mbedtls_ssl_get_input_max_frag_len( const mbedtls_ssl_context * ); size_t mbedtls_ssl_get_output_max_frag_len( const mbedtls_ssl_context * ); diff --git a/third_party/mbedtls/ssl_msg.c b/third_party/mbedtls/ssl_msg.c index 235fb1f05..f2c3017b4 100644 --- a/third_party/mbedtls/ssl_msg.c +++ b/third_party/mbedtls/ssl_msg.c @@ -5614,7 +5614,7 @@ static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl ) * \c mbedtls_ssl_check_pending to check for remaining records. * */ -int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) +int mbedtls_ssl_read( mbedtls_ssl_context *ssl, void *buf, size_t len ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; size_t n; @@ -6051,7 +6051,7 @@ static int ssl_write_split( mbedtls_ssl_context *ssl, * \note Attempting to write 0 bytes will result in an empty TLS * application record being sent. */ -int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) +int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const void *buf, size_t len ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write" ) ); diff --git a/third_party/mbedtls/x509_crt.c b/third_party/mbedtls/x509_crt.c index 680ad461f..5045d7cac 100644 --- a/third_party/mbedtls/x509_crt.c +++ b/third_party/mbedtls/x509_crt.c @@ -6,6 +6,7 @@ #include "libc/limits.h" #include "libc/mem/mem.h" #include "libc/stdio/stdio.h" +#include "net/http/http.h" #include "third_party/mbedtls/common.h" #include "third_party/mbedtls/error.h" #include "third_party/mbedtls/oid.h" @@ -2090,7 +2091,7 @@ static const struct x509_crt_verify_string x509_crt_verify_strings[] = { * terminated nul byte), or a negative error code. */ int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, - uint32_t flags ) + uint32_t flags ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; const struct x509_crt_verify_string *cur; @@ -2794,11 +2795,17 @@ static int x509_crt_check_cn( const mbedtls_x509_buf *name, static int x509_crt_check_san( const mbedtls_x509_buf *name, const char *cn, size_t cn_len ) { + int64_t ip; const unsigned char san_type = (unsigned char) name->tag & MBEDTLS_ASN1_TAG_VALUE_MASK; /* dNSName */ if( san_type == MBEDTLS_X509_SAN_DNS_NAME ) return( x509_crt_check_cn( name, cn, cn_len ) ); + if( san_type == MBEDTLS_X509_SAN_IP_ADDRESS && + name->len == 4 && ( ip = ParseIp( cn, cn_len ) ) != -1 && + ip == READ32BE( name->p ) ) { + return( 0 ); + } /* (We may handle other types here later.) */ /* Unrecognized type */ return -1; diff --git a/tool/build/deltaify.c b/tool/build/deltaify.c new file mode 100644 index 000000000..c3194a804 --- /dev/null +++ b/tool/build/deltaify.c @@ -0,0 +1,96 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-β”‚ +β”‚vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :viβ”‚ +β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•‘ +β”‚ Copyright 2021 Justine Alexandra Roberts Tunney β”‚ +β”‚ β”‚ +β”‚ Permission to use, copy, modify, and/or distribute this software for β”‚ +β”‚ any purpose with or without fee is hereby granted, provided that the β”‚ +β”‚ above copyright notice and this permission notice appear in all copies. β”‚ +β”‚ β”‚ +β”‚ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL β”‚ +β”‚ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED β”‚ +β”‚ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE β”‚ +β”‚ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL β”‚ +β”‚ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR β”‚ +β”‚ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER β”‚ +β”‚ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR β”‚ +β”‚ PERFORMANCE OF THIS SOFTWARE. β”‚ +β•šβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€*/ +#include "libc/calls/calls.h" +#include "libc/calls/sigbits.h" +#include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/ucontext.h" +#include "libc/errno.h" +#include "libc/log/check.h" +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/sysv/consts/sa.h" +#include "libc/sysv/consts/sig.h" +#include "libc/time/time.h" +#include "libc/x/x.h" + +static int pid; + +static void RelaySig(int sig, struct siginfo *si, struct ucontext *uc) { + kill(pid, sig); +} + +int main(int argc, char *argv[]) { + FILE *f; + char *s; + bool ok; + int64_t micros; + long double t1, t2; + int ws, pipefds[2]; + t1 = nowl(); + if (argc < 2) { + f = stdin; + } else { + sigset_t block, mask; + struct sigaction saignore = {.sa_handler = SIG_IGN}; + struct sigaction sadefault = {.sa_handler = SIG_DFL}; + struct sigaction sarelay = {.sa_sigaction = RelaySig, + .sa_flags = SA_RESTART}; + sigemptyset(&block); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGQUIT); + sigaddset(&mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &block, &mask); + sigaction(SIGHUP, &sarelay, 0); + sigaction(SIGTERM, &sarelay, 0); + sigaction(SIGINT, &saignore, 0); + sigaction(SIGQUIT, &saignore, 0); + CHECK_NE(-1, pipe(pipefds)); + CHECK_NE(-1, (pid = vfork())); + if (!pid) { + close(pipefds[0]); + dup2(pipefds[1], 1); + sigaction(SIGHUP, &sadefault, NULL); + sigaction(SIGTERM, &sadefault, NULL); + sigaction(SIGINT, &sadefault, NULL); + sigaction(SIGQUIT, &sadefault, NULL); + sigprocmask(SIG_SETMASK, &mask, NULL); + execvp(argv[1], argv + 1); + _exit(127); + } + close(pipefds[1]); + sigprocmask(SIG_SETMASK, &mask, NULL); + CHECK((f = fdopen(pipefds[0], "r"))); + CHECK_NE(-1, setvbuf(f, malloc(4096), _IOLBF, 4096)); + } + for (;;) { + if (!(s = xgetline(f))) break; + t2 = nowl(); + micros = (t2 - t1) * 1e6; + t1 = t2; + printf("%,16ld %s", micros, s); + free(s); + } + ok = !ferror(f); + if (argc < 2) return ok ? 0 : 1; + fclose(f); + while (waitpid(pid, &ws, 0) == -1) CHECK_EQ(EINTR, errno); + return !WIFEXITED(ws) ? 128 + WTERMSIG(ws) : ok ? WEXITSTATUS(ws) : 1; +} diff --git a/tool/net/counters.inc b/tool/net/counters.inc index 317fe7938..807bb301b 100644 --- a/tool/net/counters.inc +++ b/tool/net/counters.inc @@ -84,12 +84,14 @@ C(sslcantciphers) C(sslhandshakefails) C(sslhandshakes) C(sslnociphers) +C(sslnoclientcert) C(sslnoversion) C(sslshakemacs) C(ssltimeouts) C(sslunknownca) C(sslunknowncert) C(sslupgrades) +C(sslverifyfailed) C(statfails) C(staticrequests) C(stats) diff --git a/tool/net/demo/fetch.lua b/tool/net/demo/fetch.lua new file mode 100644 index 000000000..aef64c474 --- /dev/null +++ b/tool/net/demo/fetch.lua @@ -0,0 +1,74 @@ +-- Fetch() API Demo + +local function WriteForm(url) + Write('\r\n') + Write(string.format([[ + redbean fetch demo + +

+ + redbean fetch demo +

+
+ + +
+ ]], EscapeHtml(url))) +end + +local function main() + if IsPublicIp(GetClientAddr()) then + ServeError(403) + elseif GetMethod() == 'GET' or GetMethod() == 'HEAD' then + WriteForm("https://www.cloudflare.com/robots.txt") + elseif GetMethod() == 'POST' then + status, headers, payload = Fetch(GetParam('url')) + WriteForm(GetParam('url')) + Write('
\r\n') + Write('
Status\r\n') + Write(string.format('

%d %s\r\n', status, GetHttpReason(status))) + Write('

Headers\r\n') + Write('

\r\n') + for k,v in pairs(headers) do + Write('') + Write(EscapeHtml(k)) + Write(': ') + Write(EscapeHtml(v)) + Write('\r\n') + end + Write('

Payload\r\n') + Write('
')
+      Write(EscapeHtml(VisualizeControlCodes(payload)))
+      Write('
\r\n') + Write('
\r\n') + else + ServeError(405) + SetHeader('Allow', 'GET, HEAD, POST') + end +end + +main() diff --git a/tool/net/demo/hello.lua b/tool/net/demo/hello.lua index 05569ca65..38226b112 100644 --- a/tool/net/demo/hello.lua +++ b/tool/net/demo/hello.lua @@ -1,2 +1,4 @@ -StoreAsset('/hi', 'sup') +if not IsPublicIp(GetClientAddr()) then + StoreAsset('/hi', 'sup') +end mymodule.hello() diff --git a/tool/net/help.txt b/tool/net/help.txt index 961fb446e..e35640655 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -34,8 +34,10 @@ FLAGS -b log message bodies -a log resource usage -g log handler latency - -f log worker function calls + -j enable ssl client verify + -k disable ssl fetch verify -B use stronger cryptography + -f log worker function calls -s increase silence [repeatable] -v increase verbosity [repeatable] -V increase ssl verbosity [repeatable] @@ -45,8 +47,8 @@ FLAGS -R /X=/Y rewrites X to Y [repeatable] -K PATH tls private key path [repeatable] -C PATH tls certificate(s) path [repeatable] - -t MS tunes read and write timeouts [def. 60000] -M INT tunes max message payload size [def. 65536] + -t INT timeout ms or keepalive sec if <0 [def. 60000] -p PORT listen port [def. 8080; repeatable] -l ADDR listen addr [def. 0.0.0.0; repeatable] -c SEC configures static cache-control diff --git a/tool/net/net.mk b/tool/net/net.mk index acc3eaba8..ad69fd625 100644 --- a/tool/net/net.mk +++ b/tool/net/net.mk @@ -50,6 +50,7 @@ TOOL_NET_DIRECTDEPS = \ LIBC_X \ LIBC_ZIPOS \ NET_HTTP \ + NET_HTTPS \ THIRD_PARTY_GDTOA \ THIRD_PARTY_GETOPT \ THIRD_PARTY_LUA \ @@ -130,6 +131,7 @@ o/$(MODE)/tool/net/redbean-demo.com: \ tool/net/demo/seekable.txt \ tool/net/demo/virtualbean.html \ tool/net/demo/printpayload.lua \ + tool/net/demo/fetch.lua \ tool/net/redbean.c \ net/http/parsehttpmessage.c \ net/http/parseurl.c \ @@ -145,10 +147,10 @@ o/$(MODE)/tool/net/redbean-demo.com: \ @(cd o/$(MODE)/tool/net && ../../host/third_party/infozip/zip.com -qr redbean-demo.com .lua) @$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -qj $@ tool/net/demo/hello.lua tool/net/demo/sql.lua @echo "<-- check out this lua server page" | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -cqj $@ tool/net/demo/redbean.lua - @$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -qj $@ tool/net/demo/404.html tool/net/favicon.ico tool/net/redbean.png tool/net/demo/redbean-form.lua tool/net/demo/redbean-xhr.lua tool/net/demo/printpayload.lua + @$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -qj $@ tool/net/demo/404.html tool/net/favicon.ico tool/net/redbean.png tool/net/demo/redbean-form.lua tool/net/demo/redbean-xhr.lua tool/net/demo/printpayload.lua tool/net/demo/fetch.lua @echo Uncompressed for HTTP Range requests | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -cqj0 $@ tool/net/demo/seekable.txt @$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -q $@ tool/net/ tool/net/demo/ tool/net/demo/index.html tool/net/demo/redbean.css tool/net/redbean.c net/http/parsehttpmessage.c net/http/parseurl.c net/http/encodeurl.c test/net/http/parsehttpmessage_test.c test/net/http/parseurl_test.c - @printf "

This is a live instance of redbean: a tiny multiplatform webserver that went viral on hacker news a few months ago.\r\nSince then, we've added Lua dynamic serving, which also goes as fast as 1,000,000 requests per second on a core i9 (rather than a cheap virtual machine like this)\nin addition to SQLite and SSL. The text you're reading now is a PKZIP End Of Central Directory comment.\r\n

redbean aims to be production worthy across six operating systems, using a single executable file (this demo is hosted on FreeBSD 13). redbean has been enhanced to restore the APE header after startup.\r\nIt automatically generates this listing page based on your zip contents. If you use redbean as an application server / web development environment,\r\nthen you'll find other new and useful features like function call logging so you can get that sweet sweet microsecond scale latency." | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -z $@ + @printf "

Thank you for using redbean the tiniest most vertically integrated actually portable web server with superior performance." | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -z $@ @$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/virtualbean.justine.lol/ @$(COMPILE) -ACP -T$@ cp tool/net/redbean.png o/$(MODE)/tool/net/virtualbean.justine.lol/redbean.png @$(COMPILE) -ACP -T$@ cp tool/net/demo/virtualbean.html o/$(MODE)/tool/net/virtualbean.justine.lol/index.html diff --git a/tool/net/redbean.c b/tool/net/redbean.c index d097ff3a1..c687c3834 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -84,6 +84,7 @@ #include "net/http/http.h" #include "net/http/ip.h" #include "net/http/url.h" +#include "net/https/https.h" #include "third_party/getopt/getopt.h" #include "third_party/lua/lauxlib.h" #include "third_party/lua/ltests.h" @@ -97,6 +98,7 @@ #include "third_party/mbedtls/ecp.h" #include "third_party/mbedtls/entropy.h" #include "third_party/mbedtls/entropy_poll.h" +#include "third_party/mbedtls/error.h" #include "third_party/mbedtls/iana.h" #include "third_party/mbedtls/md5.h" #include "third_party/mbedtls/oid.h" @@ -134,23 +136,6 @@ #define REDBEAN "redbean" #endif -#ifndef UNSECURE -STATIC_YOINK("usr/share/ssl/root/amazon.pem"); -STATIC_YOINK("usr/share/ssl/root/certum.pem"); -STATIC_YOINK("usr/share/ssl/root/comodo.pem"); -STATIC_YOINK("usr/share/ssl/root/digicert.pem"); -STATIC_YOINK("usr/share/ssl/root/dst.pem"); -STATIC_YOINK("usr/share/ssl/root/geotrust.pem"); -STATIC_YOINK("usr/share/ssl/root/globalsign.pem"); -STATIC_YOINK("usr/share/ssl/root/godaddy.pem"); -STATIC_YOINK("usr/share/ssl/root/google.pem"); -STATIC_YOINK("usr/share/ssl/root/isrg.pem"); -STATIC_YOINK("usr/share/ssl/root/quovadis.pem"); -STATIC_YOINK("usr/share/ssl/root/redbean.pem"); -STATIC_YOINK("usr/share/ssl/root/starfield.pem"); -STATIC_YOINK("usr/share/ssl/root/verisign.pem"); -#endif - #define HASH_LOAD_FACTOR /* 1. / */ 4 #define read(F, P, N) readv(F, &(struct iovec){P, N}, 1) #define write(F, P, N) writev(F, &(struct iovec){P, N}, 1) @@ -384,16 +369,18 @@ static bool printport; static bool daemonize; static bool logrusage; static bool logbodies; +static bool sslcliused; static bool loglatency; static bool terminated; static bool uniprocess; static bool invalidated; static bool logmessages; static bool checkedmethod; +static bool sslfetchverify; +static bool sslclientverify; static bool connectionclose; static bool keyboardinterrupt; static bool listeningonport443; -static bool encouragekeepalive; static bool loggednetworkorigin; static bool hasluaglobalhandler; static bool upgradeinsecurerequests; @@ -446,13 +433,9 @@ static struct Buffer hdrbuf; static struct Buffer outbuf; static struct timeval timeout; static struct Buffer effectivepath; -static mbedtls_ssl_config conf; -static mbedtls_ssl_context ssl; -static mbedtls_ctr_drbg_context rng; static struct Url url; static struct HttpMessage msg; -static char slashpath[PATH_MAX]; static struct stat zst; static long double startread; @@ -464,6 +447,16 @@ static long double startconnection; static struct sockaddr_in clientaddr; static struct sockaddr_in *serveraddr; +static mbedtls_ssl_config conf; +static mbedtls_ssl_context ssl; +static mbedtls_ctr_drbg_context rng; + +static mbedtls_ssl_config confcli; +static mbedtls_ssl_context sslcli; +static mbedtls_ctr_drbg_context rngcli; + +static char slashpath[PATH_MAX]; + static char *Route(const char *, size_t, const char *, size_t); static char *RouteHost(const char *, size_t, const char *, size_t); static char *RoutePath(const char *, size_t); @@ -1001,13 +994,18 @@ static void ProgramBrand(const char *s) { static void ProgramTimeout(long ms) { ldiv_t d; - if (ms <= 30) { - fprintf(stderr, "error: timeout needs to be 31ms or greater\n"); - exit(1); + if (ms < 0) { + timeout.tv_sec = ms; /* -(keepalive seconds) */ + timeout.tv_usec = 0; + } else { + if (ms <= 30) { + fprintf(stderr, "error: timeout needs to be 31ms or greater\n"); + exit(1); + } + d = ldiv(ms, 1000); + timeout.tv_sec = d.quot; + timeout.tv_usec = d.rem * 1000; } - d = ldiv(ms, 1000); - timeout.tv_sec = d.quot; - timeout.tv_usec = d.rem * 1000; } static void ProgramCache(long x) { @@ -1020,6 +1018,7 @@ static void SetDefaults(void) { maxpayloadsize = 64 * 1024; ProgramCache(-1); ProgramTimeout(60 * 1000); + sslfetchverify = true; if (IsWindows()) uniprocess = true; } @@ -1306,6 +1305,24 @@ static ssize_t WritevAll(int fd, struct iovec *iov, int iovlen) { return 0; } +static int TlsRecvImpl(void *ctx, unsigned char *buf, size_t len, + uint32_t tmo) { + int rc; + while ((rc = read(*(int *)ctx, buf, len)) == -1) { + if (errno == EINTR) { + return MBEDTLS_ERR_SSL_WANT_READ; + } else if (errno == EAGAIN) { + return MBEDTLS_ERR_SSL_TIMEOUT; + } else if (errno == EPIPE || errno == ECONNRESET || errno == ENETRESET) { + return MBEDTLS_ERR_NET_CONN_RESET; + } else { + WARNF("tls read() error %s", strerror(errno)); + return MBEDTLS_ERR_NET_RECV_FAILED; + } + } + return rc; +} + static int TlsRecv(void *ctx, unsigned char *buf, size_t len, uint32_t tmo) { int rc; if (oldin.n) { @@ -1315,19 +1332,7 @@ static int TlsRecv(void *ctx, unsigned char *buf, size_t len, uint32_t tmo) { oldin.n -= rc; return rc; } - while ((rc = read(client, buf, len)) == -1) { - if (errno == EINTR) { - return MBEDTLS_ERR_SSL_WANT_READ; - } else if (errno == EAGAIN) { - return MBEDTLS_ERR_SSL_TIMEOUT; - } else if (errno == EPIPE || errno == ECONNRESET || errno == ENETRESET) { - return MBEDTLS_ERR_NET_CONN_RESET; - } else { - WARNF("%s tls read() error %s", DescribeClient(), strerror(errno)); - return MBEDTLS_ERR_NET_RECV_FAILED; - } - } - return rc; + return TlsRecvImpl(ctx, buf, len, tmo); } static void TlsDebug(void *ctx, int level, const char *file, int line, @@ -1337,7 +1342,7 @@ static void TlsDebug(void *ctx, int level, const char *file, int line, static int TlsSend(void *ctx, const unsigned char *buf, size_t len) { int rc; - while ((rc = write(client, buf, len)) == -1) { + while ((rc = write(*(int *)ctx, buf, len)) == -1) { if (errno == EINTR) { LockInc(&shared->c.writeinterruputs); if (killed || (meltdown && nowl() - startread > 2)) { @@ -1348,7 +1353,7 @@ static int TlsSend(void *ctx, const unsigned char *buf, size_t len) { } else if (errno == EPIPE || errno == ECONNRESET || errno == ENETRESET) { return MBEDTLS_ERR_NET_CONN_RESET; } else { - WARNF("%s TlsSend error %s", DescribeClient(), strerror(errno)); + WARNF("TlsSend error %s", strerror(errno)); return MBEDTLS_ERR_NET_SEND_FAILED; } } @@ -1402,6 +1407,15 @@ static ssize_t SslWrite(int fd, struct iovec *iov, int iovlen) { return 0; } +static void NotifyClose(void) { +#ifndef UNSECURE + if (usessl) { + DEBUGF("SSL notifying close"); + mbedtls_ssl_close_notify(&ssl); + } +#endif +} + static bool TlsSetup(void) { int r; oldin.p = inbuf.p; @@ -1416,9 +1430,9 @@ static bool TlsSetup(void) { usessl = true; reader = SslRead; writer = SslWrite; - encouragekeepalive = true; - VERBOSEF("%s %s %s", DescribeClient(), mbedtls_ssl_get_version(&ssl), - mbedtls_ssl_get_ciphersuite(&ssl)); + VERBOSEF("SHAKEN %s %s %s", DescribeClient(), + mbedtls_ssl_get_ciphersuite(&ssl), + mbedtls_ssl_get_version(&ssl)); return true; } else if (r == MBEDTLS_ERR_SSL_WANT_READ) { LockInc(&shared->c.handshakeinterrupts); @@ -1436,33 +1450,44 @@ static bool TlsSetup(void) { return false; case MBEDTLS_ERR_SSL_TIMEOUT: LockInc(&shared->c.ssltimeouts); - DEBUGF("%s SSL handshake timeout", DescribeClient()); + DEBUGF("%s %s", DescribeClient(), "ssltimeouts"); return false; case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN: LockInc(&shared->c.sslnociphers); - WARNF("%s SSL no ciphersuites", DescribeClient()); + WARNF("%s %s", DescribeClient(), "sslnociphers"); return false; case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE: LockInc(&shared->c.sslcantciphers); - WARNF("%s SSL can't ciphersuite", DescribeClient()); + WARNF("%s %s", DescribeClient(), "sslcantciphers"); return false; case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION: LockInc(&shared->c.sslnoversion); - WARNF("%s SSL version mismatch", DescribeClient()); + WARNF("%s %s", DescribeClient(), "sslnoversion"); return false; case MBEDTLS_ERR_SSL_INVALID_MAC: LockInc(&shared->c.sslshakemacs); - WARNF("%s SSL handshake failed bad mac", DescribeClient()); + WARNF("%s %s", DescribeClient(), "sslshakemacs"); + return false; + case MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE: + LockInc(&shared->c.sslnoclientcert); + WARNF("%s %s", DescribeClient(), "sslnoclientcert"); + NotifyClose(); + return false; + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + LockInc(&shared->c.sslverifyfailed); + WARNF("%s SSL %s", DescribeClient(), + gc(DescribeSslVerifyFailure( + ssl.session_negotiate->verify_result))); return false; case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE: switch (ssl.fatal_alert) { case MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN: LockInc(&shared->c.sslunknowncert); - DEBUGF("%s SSL shakealert unknown cert", DescribeClient()); + DEBUGF("%s %s", DescribeClient(), "sslunknowncert"); return false; case MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA: LockInc(&shared->c.sslunknownca); - DEBUGF("%s SSL shakealert unknown ca", DescribeClient()); + DEBUGF("%s %s", DescribeClient(), "sslunknownca"); return false; default: WARNF("%s SSL shakealert %s", DescribeClient(), @@ -1507,8 +1532,8 @@ static void ChooseCertificateLifetime(char notbefore[16], char notafter[16]) { now = nowl(); past = now - tolerance; future = now + tolerance + lifetime; - strftime(notbefore, 16, "%Y%m%d%H%M%S", gmtime_r(&past, &tm)); - strftime(notafter, 16, "%Y%m%d%H%M%S", gmtime_r(&future, &tm)); + FormatSslTime(notbefore, gmtime_r(&past, &tm)); + FormatSslTime(notafter, gmtime_r(&future, &tm)); } static void ConfigureCertificate(mbedtls_x509write_cert *cw, struct Cert *ca, @@ -1593,64 +1618,83 @@ static struct Cert *GetKeySigningKey(void) { return NULL; } -static struct Cert GenerateEcpCertificate(struct Cert *ca) { - int i, n; +static void WipeKeySigningKeys(void) { + size_t i; + for (i = 0; i < certs.n; ++i) { + if (!certs.p[i].key) continue; + if (!certs.p[i].cert) continue; + if (!certs.p[i].cert->ca_istrue) continue; + mbedtls_pk_free(certs.p[i].key); + certs.p[i].key = 0; + } +} + +static mbedtls_pk_context *InitializeKey(struct Cert *ca, + mbedtls_x509write_cert *wcert, + int type) { + mbedtls_pk_context *k; + mbedtls_ctr_drbg_context kr; + k = calloc(1, sizeof(mbedtls_pk_context)); + mbedtls_x509write_crt_init(wcert); + mbedtls_x509write_crt_set_issuer_key(wcert, ca ? ca->key : k); + mbedtls_x509write_crt_set_subject_key(wcert, k); + mbedtls_x509write_crt_set_md_alg( + wcert, suiteb ? MBEDTLS_MD_SHA384 : MBEDTLS_MD_SHA256); + mbedtls_x509write_crt_set_version(wcert, MBEDTLS_X509_CRT_VERSION_3); + CHECK_EQ(0, mbedtls_pk_setup(k, mbedtls_pk_info_from_type(type))); + return k; +} + +static struct Cert FinishCertificate(struct Cert *ca, + mbedtls_x509write_cert *wcert, + mbedtls_ctr_drbg_context *kr, + mbedtls_pk_context *key) { + int i, n, rc; unsigned char *p; mbedtls_x509_crt *cert; + p = malloc((n = FRAMESIZE)); + i = mbedtls_x509write_crt_der(wcert, p, n, mbedtls_ctr_drbg_random, kr); + if (i < 0) { + fprintf(stderr, "error: write key (grep -0x%04x)\n", -i); + exit(1); + } + cert = calloc(1, sizeof(mbedtls_x509_crt)); + mbedtls_x509_crt_parse_der(cert, p + n - i, i); + if (ca) cert->next = ca->cert; + mbedtls_x509write_crt_free(wcert); + mbedtls_ctr_drbg_free(kr); + free(p); + if ((rc = mbedtls_pk_check_pair(&cert->pk, key))) { + fprintf(stderr, "error: generate key (grep -0x%04x)\n", -rc); + exit(1); + } + LogCertificate("generated certificate", cert); + UseCertificate(cert, key); + return (struct Cert){cert, key}; +} + +static struct Cert GenerateEcpCertificate(struct Cert *ca) { mbedtls_pk_context *key; mbedtls_ctr_drbg_context kr; mbedtls_x509write_cert wcert; - cert = calloc(1, sizeof(mbedtls_x509_crt)); - key = calloc(1, sizeof(mbedtls_pk_context)); - mbedtls_x509write_crt_init(&wcert); - mbedtls_x509write_crt_set_issuer_key(&wcert, ca ? ca->key : key); - mbedtls_x509write_crt_set_subject_key(&wcert, key); - mbedtls_x509write_crt_set_md_alg( - &wcert, suiteb ? MBEDTLS_MD_SHA384 : MBEDTLS_MD_SHA256); - mbedtls_x509write_crt_set_version(&wcert, MBEDTLS_X509_CRT_VERSION_3); - CHECK_EQ(0, - mbedtls_pk_setup(key, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY))); InitializeRng(&kr); + key = InitializeKey(ca, &wcert, MBEDTLS_PK_ECKEY); CHECK_EQ(0, mbedtls_ecp_gen_key( suiteb ? MBEDTLS_ECP_DP_SECP384R1 : MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(*key), mbedtls_ctr_drbg_random, &kr)); GenerateSerial(&wcert, &kr); ConfigureCertificate(&wcert, ca, MBEDTLS_X509_KU_DIGITAL_SIGNATURE, - MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER); - p = malloc((n = FRAMESIZE)); - i = mbedtls_x509write_crt_der(&wcert, p, n, mbedtls_ctr_drbg_random, &kr); - if (i < 0) { - fprintf(stderr, "error: write ec key (grep -0x%04x)\n", -i); - exit(1); - } - CHECK_EQ(0, mbedtls_x509_crt_parse_der(cert, p + n - i, i)); - if (ca) cert->next = ca->cert; - mbedtls_x509write_crt_free(&wcert); - mbedtls_ctr_drbg_free(&kr); - free(p); - CHECK_EQ(0, mbedtls_pk_check_pair(&cert->pk, key)); - LogCertificate("generated nist elliptic curve certificate", cert); - UseCertificate(cert, key); - return (struct Cert){cert, key}; + MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER | + MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT); + return FinishCertificate(ca, &wcert, &kr, key); } static struct Cert GenerateRsaCertificate(struct Cert *ca) { - int i, n, rc; - unsigned char *p; - mbedtls_x509_crt *cert; mbedtls_pk_context *key; mbedtls_ctr_drbg_context kr; mbedtls_x509write_cert wcert; - cert = calloc(1, sizeof(mbedtls_x509_crt)); - key = calloc(1, sizeof(mbedtls_pk_context)); - mbedtls_x509write_crt_init(&wcert); - mbedtls_x509write_crt_set_issuer_key(&wcert, ca ? ca->key : key); - mbedtls_x509write_crt_set_subject_key(&wcert, key); - mbedtls_x509write_crt_set_md_alg( - &wcert, suiteb ? MBEDTLS_MD_SHA384 : MBEDTLS_MD_SHA256); - mbedtls_x509write_crt_set_version(&wcert, MBEDTLS_X509_CRT_VERSION_3); - CHECK_EQ(0, mbedtls_pk_setup(key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA))); InitializeRng(&kr); + key = InitializeKey(ca, &wcert, MBEDTLS_PK_RSA); CHECK_EQ(0, mbedtls_rsa_gen_key(mbedtls_pk_rsa(*key), mbedtls_ctr_drbg_random, &kr, suiteb ? 4096 : 2048, 65537)); GenerateSerial(&wcert, &kr); @@ -1659,41 +1703,34 @@ static struct Cert GenerateRsaCertificate(struct Cert *ca) { MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_ENCIPHERMENT, MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER | MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT); - p = malloc((n = FRAMESIZE)); - i = mbedtls_x509write_crt_der(&wcert, p, n, mbedtls_ctr_drbg_random, &kr); - if (i < 0) { - fprintf(stderr, "error: write rsa key (grep -0x%04x)\n", -i); - exit(1); - } - mbedtls_x509_crt_parse_der(cert, p + n - i, i); - if (ca) cert->next = ca->cert; - mbedtls_x509write_crt_free(&wcert); - mbedtls_ctr_drbg_free(&kr); - free(p); - if ((rc = mbedtls_pk_check_pair(&cert->pk, key))) { - fprintf(stderr, "error: generate key (grep -0x%04x)\n", -rc); - exit(1); - } - LogCertificate("generated rivest–shamir–adleman certificate", cert); - UseCertificate(cert, key); - return (struct Cert){cert, key}; + return FinishCertificate(ca, &wcert, &kr, key); } static void LoadCertificates(void) { size_t i; - bool havecert; struct Cert *ksk, ecp, rsa; + bool havecert, haveclientcert; havecert = false; + haveclientcert = false; for (i = 0; i < certs.n; ++i) { if (certs.p[i].key && certs.p[i].cert && !certs.p[i].cert->ca_istrue && !mbedtls_x509_crt_check_key_usage(certs.p[i].cert, - MBEDTLS_X509_KU_DIGITAL_SIGNATURE) && - !mbedtls_x509_crt_check_extended_key_usage( - certs.p[i].cert, MBEDTLS_OID_SERVER_AUTH, - MBEDTLS_OID_SIZE(MBEDTLS_OID_SERVER_AUTH))) { - LogCertificate("using certificate", certs.p[i].cert); - UseCertificate(certs.p[i].cert, certs.p[i].key); - havecert = true; + MBEDTLS_X509_KU_DIGITAL_SIGNATURE)) { + if (!mbedtls_x509_crt_check_extended_key_usage( + certs.p[i].cert, MBEDTLS_OID_SERVER_AUTH, + MBEDTLS_OID_SIZE(MBEDTLS_OID_SERVER_AUTH))) { + LogCertificate("using server certificate", certs.p[i].cert); + UseCertificate(certs.p[i].cert, certs.p[i].key); + havecert = true; + } + if (!mbedtls_x509_crt_check_extended_key_usage( + certs.p[i].cert, MBEDTLS_OID_CLIENT_AUTH, + MBEDTLS_OID_SIZE(MBEDTLS_OID_CLIENT_AUTH))) { + LogCertificate("using client certificate", certs.p[i].cert); + CHECK_EQ(0, mbedtls_ssl_conf_own_cert(&confcli, certs.p[i].cert, + certs.p[i].key)); + haveclientcert = true; + } } } if (!havecert) { @@ -1710,9 +1747,15 @@ static void LoadCertificates(void) { } #ifdef MBEDTLS_ECP_C ecp = GenerateEcpCertificate(ksk); + if (!haveclientcert) { + CHECK_EQ(0, mbedtls_ssl_conf_own_cert(&confcli, ecp.cert, ecp.key)); + } #endif #ifdef MBEDTLS_RSA_C rsa = GenerateRsaCertificate(ksk); + if (!haveclientcert) { + CHECK_EQ(0, mbedtls_ssl_conf_own_cert(&confcli, rsa.cert, rsa.key)); + } #endif #ifdef MBEDTLS_ECP_C certs.p = realloc(certs.p, ++certs.n * sizeof(*certs.p)); @@ -1723,21 +1766,11 @@ static void LoadCertificates(void) { certs.p[certs.n - 1] = rsa; #endif } + WipeKeySigningKeys(); } static void LoadSslRoots(void) { - DIR *d; - const char *dir; - struct dirent *e; - char *p, path[300]; - dir = "zip:usr/share/ssl/root"; - CHECK((d = opendir(dir)), "%s", dir); - while ((e = readdir(d))) { - if (e->d_type != DT_REG) continue; - snprintf(path, sizeof(path), "%s/%s", dir, e->d_name); - ProgramFile(path, ProgramCertificate); - } - closedir(d); + InternCertificate(GetSslRoots(), 0); } static bool ClientAcceptsGzip(void) { @@ -2162,7 +2195,7 @@ static wontreturn void PrintUsage(FILE *f, int rc) { static void GetOpts(int argc, char *argv[]) { int opt; while ((opt = getopt(argc, argv, - "azhdugvVsmbfyl:p:r:R:H:c:L:P:U:G:BD:t:M:C:K:F:")) != + "jkazhdugvVsmbfyl:p:r:R:H:c:L:P:U:G:BD:t:M:C:K:F:")) != -1) { switch (opt) { case 'v': @@ -2201,11 +2234,14 @@ static void GetOpts(int argc, char *argv[]) { case 'f': funtrace = true; break; - case 'B': - suiteb = true; + case 'j': + sslclientverify = true; break; case 'k': - encouragekeepalive = true; + sslfetchverify = false; + break; + case 'B': + suiteb = true; break; case 't': ProgramTimeout(strtol(optarg, NULL, 0)); @@ -3293,6 +3329,423 @@ static int LuaStoreAsset(lua_State *L) { return 0; } +static void ReseedRng(mbedtls_ctr_drbg_context *r, const char *s) { +#ifndef UNSECURE + CHECK_EQ(0, mbedtls_ctr_drbg_reseed(r, (void *)s, strlen(s))); +#endif +} + +static char *TlsError(int r) { + static char b[128]; + mbedtls_strerror(r, b, sizeof(b)); + return b; +} + +static wontreturn void LuaThrowTlsError(lua_State *L, const char *s, int r) { + const char *code; + code = gc(xasprintf("-0x%04x", -r)); + if (!IsTiny()) { + luaL_error(L, "tls %s failed (%s %s)", s, code, TlsError(r)); + } else { + luaL_error(L, "tls %s failed (grep %s)", s, code); + } + unreachable; +} + +static bool Tune(int fd, int a, int b, int x) { + if (!b) return false; + return setsockopt(fd, a, b, &x, sizeof(x)) != -1; +} + +static int Socket(int family, int type, int protocol, bool isserver) { + int fd; + if ((fd = socket(family, type, protocol)) != -1) { + if (isserver) { + Tune(fd, SOL_TCP, TCP_FASTOPEN, 100); + Tune(fd, SOL_SOCKET, SO_REUSEADDR, 1); + } else { + Tune(fd, SOL_TCP, TCP_FASTOPEN_CONNECT, 1); + } + if (!Tune(fd, SOL_TCP, TCP_QUICKACK, 1)) { + Tune(fd, SOL_TCP, TCP_NODELAY, 1); + } + if (timeout.tv_sec < 0) { + Tune(fd, SOL_SOCKET, SO_KEEPALIVE, 1); + Tune(fd, SOL_TCP, TCP_KEEPIDLE, -timeout.tv_sec); + Tune(fd, SOL_TCP, TCP_KEEPINTVL, -timeout.tv_sec); + } else { + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); + } + } + return fd; +} + +static char *FoldHeader(struct HttpMessage *msg, char *b, int h, size_t *z) { + char *p; + size_t i, n, m; + struct HttpHeader *x; + n = msg->headers[h].b - msg->headers[h].a; + p = xmalloc(n); + memcpy(p, b + msg->headers[h].a, n); + for (i = 0; i < msg->xheaders.n; ++i) { + x = msg->xheaders.p + i; + if (GetHttpHeader(b + x->k.a, x->k.b - x->k.a) == h) { + m = x->v.b - x->v.a; + p = xrealloc(p, n + 2 + m); + memcpy(mempcpy(p + n, ", ", 2), b + x->v.a, m); + n += 2 + m; + } + } + *z = n; + return p; +} + +static void LuaPushLatin1(lua_State *L, const char *s, size_t n) { + char *t; + size_t m; + t = DecodeLatin1(s, n, &m); + lua_pushlstring(L, t, m); + free(t); +} + +static int LuaPushHeader(lua_State *L, struct HttpMessage *m, char *b, int h) { + char *val; + size_t vallen; + if (!kHttpRepeatable[h]) { + LuaPushLatin1(L, b + m->headers[h].a, m->headers[h].b - m->headers[h].a); + } else { + val = FoldHeader(m, b, h, &vallen); + LuaPushLatin1(L, val, vallen); + free(val); + } + return 1; +} + +static int LuaPushHeaders(lua_State *L, struct HttpMessage *m, const char *b) { + char *s; + size_t i, h; + struct HttpHeader *x; + lua_newtable(L); + for (h = 0; h < kHttpHeadersMax; ++h) { + if (m->headers[h].a) { + LuaPushHeader(L, m, b, h); + lua_setfield(L, -2, GetHttpHeaderName(h)); + } + } + for (i = 0; i < m->xheaders.n; ++i) { + x = m->xheaders.p + i; + if ((h = GetHttpHeader(b + x->v.a, x->v.b - x->v.a)) == -1) { + LuaPushLatin1(L, b + x->v.a, x->v.b - x->v.a); + lua_setfield(L, -2, (s = DecodeLatin1(b + x->k.a, x->k.b - x->k.a, 0))); + free(s); + } + } + return 1; +} + +static void LogMessage(const char *d, const char *s, size_t n) { + size_t n2, n3; + char *s2, *s3; + while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n; + if ((s2 = DecodeLatin1(s, n, &n2))) { + if ((s3 = IndentLines(s2, n2, &n3, 1))) { + LOGF("%s %,ld byte message\n%.*s", d, n, n3, s3); + free(s3); + } + free(s2); + } +} + +static void LogBody(const char *d, const char *s, size_t n) { + char *s2, *s3; + size_t n2, n3; + if (!n) return; + while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n; + if ((s2 = VisualizeControlCodes(s, n, &n2))) { + if ((s3 = IndentLines(s2, n2, &n3, 1))) { + LOGF("%s %,ld byte payload\n%.*s", d, n, n3, s3); + free(s3); + } + free(s2); + } +} + +static int LuaFetch(lua_State *L) { + char *p; + ssize_t rc; + bool usessl; + uint32_t ip; + struct Url url; + int t, ret, sock; + char *host, *port; + struct Buffer inbuf; + struct addrinfo *addr; + struct HttpMessage msg; + struct HttpUnchunker u; + const char *urlarg, *request; + size_t urlarglen, requestlen; + size_t g, i, n, hdrsize, paylen; + struct addrinfo hints = {.ai_family = AF_INET, + .ai_socktype = SOCK_STREAM, + .ai_protocol = IPPROTO_TCP, + .ai_flags = AI_NUMERICSERV}; + + /* + * Get args. + */ + urlarg = luaL_checklstring(L, 1, &urlarglen); + + /* + * Parse URL. + */ + gc(ParseUrl(urlarg, urlarglen, &url)); + gc(url.params.p); + usessl = false; + if (url.scheme.n) { +#ifndef UNSECURE + if (url.scheme.n == 5 && !memcasecmp(url.scheme.p, "https", 5)) { + usessl = true; + } else +#endif + if (!(url.scheme.n == 4 && !memcasecmp(url.scheme.p, "http", 4))) { + luaL_argerror(L, 1, "bad scheme"); + unreachable; + } + } + if (url.host.n) { + host = gc(strndup(url.host.p, url.host.n)); + if (url.port.n) { + port = gc(strndup(url.port.p, url.port.n)); + } else { + port = usessl ? "443" : "80"; + } + } else { + ip = ntohl(servers.p[0].addr.sin_addr.s_addr); + host = + gc(xasprintf("%hhu.%hhu.%hhu.%hhu", ip >> 24, ip >> 16, ip >> 8, ip)); + port = gc(xasprintf("%d", ntohs(servers.p[0].addr.sin_port))); + } + if (!IsAcceptableHost(host, -1)) { + luaL_argerror(L, 1, "invalid host"); + unreachable; + } + url.fragment.p = 0, url.fragment.n = 0; + url.scheme.p = 0, url.scheme.n = 0; + url.user.p = 0, url.user.n = 0; + url.pass.p = 0, url.pass.n = 0; + url.host.p = 0, url.host.n = 0; + url.port.p = 0, url.port.n = 0; + if (!url.path.n || url.path.p[0] != '/') { + p = gc(xmalloc(1 + url.path.n)); + mempcpy(mempcpy(p, "/", 1), url.path.p, url.path.n); + url.path.p = p; + ++url.path.n; + } + + /* + * Create HTTP message. + */ + request = gc(xasprintf("GET %s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Connection: close\r\n" + "User-Agent: %s\r\n" + "\r\n", + gc(EncodeUrl(&url, 0)), host, port, brand)); + requestlen = strlen(request); + + /* + * Perform DNS lookup. + */ + DEBUGF("client resolving %s", host); + if ((rc = getaddrinfo(host, port, &hints, &addr)) != EAI_SUCCESS) { + luaL_error(L, "getaddrinfo(%s:%s) failed", host, port); + unreachable; + } + + /* + * Connect to server. + */ + ip = ntohl(((struct sockaddr_in *)addr->ai_addr)->sin_addr.s_addr); + DEBUGF("client connecting %hhu.%hhu.%hhu.%hhu:%d", ip >> 24, ip >> 16, + ip >> 8, ip, ntohs(((struct sockaddr_in *)addr->ai_addr)->sin_port)); + CHECK_NE(-1, (sock = Socket(addr->ai_family, addr->ai_socktype, + addr->ai_protocol, false))); + if (connect(sock, addr->ai_addr, addr->ai_addrlen) == -1) { + close(sock); + luaL_error(L, "connect(%s:%s) failed: %s", host, port, strerror(errno)); + unreachable; + } + if (usessl) { + if (sslcliused) { + mbedtls_ssl_session_reset(&sslcli); + } else { + ReseedRng(&rngcli, "child"); + } + sslcliused = true; + DEBUGF("client handshaking %`'s", host); + mbedtls_ssl_set_hostname(&sslcli, host); + mbedtls_ssl_set_bio(&sslcli, &sock, TlsSend, 0, TlsRecvImpl); + while ((ret = mbedtls_ssl_handshake(&ssl))) { + switch (ret) { + case MBEDTLS_ERR_SSL_WANT_READ: + break; + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + goto VerifyFailed; + default: + close(sock); + LuaThrowTlsError(L, "handshake", ret); + } + } + LockInc(&shared->c.sslhandshakes); + VERBOSEF("SHAKEN %s:%s %s %s", host, port, + mbedtls_ssl_get_ciphersuite(&ssl), mbedtls_ssl_get_version(&ssl)); + } + + /* + * Send HTTP Message. + */ + DEBUGF("client sending"); + if (usessl) { + ret = mbedtls_ssl_write(&sslcli, request, requestlen); + if (ret != requestlen) { + if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) goto VerifyFailed; + close(sock); + LuaThrowTlsError(L, "write", ret); + } + } else if (write(sock, request, requestlen) != requestlen) { + close(sock); + luaL_error(L, "write failed: %s", strerror(errno)); + unreachable; + } + if (logmessages) LogMessage("sent", request, requestlen); + + /* + * Handle response. + */ + memset(&inbuf, 0, sizeof(inbuf)); + InitHttpMessage(&msg, kHttpResponse); + for (hdrsize = paylen = t = 0;;) { + if (inbuf.n == inbuf.c) { + inbuf.c += 1000; + inbuf.c += inbuf.c >> 1; + inbuf.p = realloc(inbuf.p, inbuf.c); + } + DEBUGF("client reading"); + if (usessl) { + if ((rc = mbedtls_ssl_read(&sslcli, inbuf.p + inbuf.n, + inbuf.c - inbuf.n)) < 0) { + if (rc == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + rc = 0; + } else { + close(sock); + free(inbuf.p); + DestroyHttpMessage(&msg); + LuaThrowTlsError(L, "read", rc); + } + } + } else if ((rc = read(sock, inbuf.p + inbuf.n, inbuf.c - inbuf.n)) == -1) { + close(sock); + free(inbuf.p); + DestroyHttpMessage(&msg); + luaL_error(L, "read failed: %s", strerror(errno)); + unreachable; + } + g = rc; + inbuf.n += g; + switch (t) { + case kHttpClientStateHeaders: + if (!g) goto TransportError; + rc = ParseHttpMessage(&msg, inbuf.p, inbuf.n); + if (rc == -1) goto TransportError; + if (rc) { + hdrsize = rc; + if (logmessages) LogMessage("received", inbuf.p, hdrsize); + if (100 <= msg.status && msg.status <= 199) { + if ((HasHeader(kHttpContentLength) && + !HeaderEqualCase(kHttpContentLength, "0")) || + (HasHeader(kHttpTransferEncoding) && + !HeaderEqualCase(kHttpTransferEncoding, "identity"))) { + goto TransportError; + } + DestroyHttpMessage(&msg); + InitHttpMessage(&msg, kHttpResponse); + memmove(inbuf.p, inbuf.p + hdrsize, inbuf.n - hdrsize); + inbuf.n -= hdrsize; + break; + } + if (msg.status == 204 || msg.status == 304) { + goto Finished; + } + if (HasHeader(kHttpTransferEncoding) && + !HeaderEqualCase(kHttpTransferEncoding, "identity")) { + if (HeaderEqualCase(kHttpTransferEncoding, "chunked")) { + t = kHttpClientStateBodyChunked; + memset(&u, 0, sizeof(u)); + goto Chunked; + } else { + goto TransportError; + } + } else if (HasHeader(kHttpContentLength)) { + rc = ParseContentLength(HeaderData(kHttpContentLength), + HeaderLength(kHttpContentLength)); + if (rc == -1) goto TransportError; + if ((paylen = rc) <= inbuf.n - hdrsize) { + goto Finished; + } else { + t = kHttpClientStateBodyLengthed; + } + } else { + t = kHttpClientStateBody; + } + } + break; + case kHttpClientStateBody: + if (!g) { + paylen = inbuf.n; + goto Finished; + } + break; + case kHttpClientStateBodyLengthed: + if (!g) goto TransportError; + if (inbuf.n - hdrsize >= paylen) goto Finished; + break; + case kHttpClientStateBodyChunked: + Chunked: + rc = Unchunk(&u, inbuf.p + hdrsize, inbuf.n - hdrsize, &paylen); + if (rc == -1) goto TransportError; + if (rc) goto Finished; + break; + default: + unreachable; + } + } + +Finished: + if (paylen && logbodies) LogBody("received", inbuf.p + hdrsize, paylen); + LOGF("FETCH HTTP%02d %d %s %`'.*s", msg.version, msg.status, urlarg, + HeaderLength(kHttpServer), HeaderData(kHttpServer)); + lua_pushinteger(L, msg.status); + LuaPushHeaders(L, &msg, inbuf.p); + lua_pushlstring(L, inbuf.p + hdrsize, paylen); + DestroyHttpMessage(&msg); + free(inbuf.p); + close(sock); + return 3; +TransportError: + close(sock); + free(inbuf.p); + DestroyHttpMessage(&msg); + luaL_error(L, "transport error"); + unreachable; +VerifyFailed: + LockInc(&shared->c.sslverifyfailed); + close(sock); + LuaThrowTlsError( + L, gc(DescribeSslVerifyFailure(sslcli.session_negotiate->verify_result)), + ret); +} + static int LuaGetDate(lua_State *L) { lua_pushinteger(L, shared->nowish); return 1; @@ -3480,51 +3933,14 @@ static int LuaGetPayload(lua_State *L) { return 1; } -static void LuaPushLatin1(lua_State *L, const char *s, size_t n) { - char *t; - size_t m; - t = DecodeLatin1(s, n, &m); - lua_pushlstring(L, t, m); - free(t); -} - -static char *FoldHeader(int h, size_t *z) { - char *p; - size_t i, n, m; - struct HttpHeader *x; - n = msg.headers[h].b - msg.headers[h].a; - p = xmalloc(n); - memcpy(p, inbuf.p + msg.headers[h].a, n); - for (i = 0; i < msg.xheaders.n; ++i) { - x = msg.xheaders.p + i; - if (GetHttpHeader(inbuf.p + x->k.a, x->k.b - x->k.a) == h) { - m = x->v.b - x->v.a; - p = xrealloc(p, n + 2 + m); - memcpy(mempcpy(p + n, ", ", 2), inbuf.p + x->v.a, m); - n += 2 + m; - } - } - *z = n; - return p; -} - static int LuaGetHeader(lua_State *L) { int h; - char *val; const char *key; - size_t i, keylen, vallen; + size_t i, keylen; key = luaL_checklstring(L, 1, &keylen); if ((h = GetHttpHeader(key, keylen)) != -1) { if (msg.headers[h].a) { - if (!kHttpRepeatable[h]) { - LuaPushLatin1(L, inbuf.p + msg.headers[h].a, - msg.headers[h].b - msg.headers[h].a); - } else { - val = FoldHeader(h, &vallen); - LuaPushLatin1(L, val, vallen); - free(val); - } - return 1; + return LuaPushHeader(L, &msg, inbuf.p, h); } } else { for (i = 0; i < msg.xheaders.n; ++i) { @@ -3541,26 +3957,7 @@ static int LuaGetHeader(lua_State *L) { } static int LuaGetHeaders(lua_State *L) { - size_t i; - char *name; - lua_newtable(L); - for (i = 0; i < kHttpHeadersMax; ++i) { - if (msg.headers[i].a) { - LuaPushLatin1(L, inbuf.p + msg.headers[i].a, - msg.headers[i].b - msg.headers[i].a); - lua_setfield(L, -2, GetHttpHeaderName(i)); - } - } - for (i = 0; i < msg.xheaders.n; ++i) { - LuaPushLatin1(L, inbuf.p + msg.xheaders.p[i].v.a, - msg.xheaders.p[i].v.b - msg.xheaders.p[i].v.a); - lua_setfield(L, -2, - (name = DecodeLatin1( - inbuf.p + msg.xheaders.p[i].k.a, - msg.xheaders.p[i].k.b - msg.xheaders.p[i].k.a, 0))); - free(name); - } - return 1; + return LuaPushHeaders(L, &msg, inbuf.p); } static int LuaSetHeader(lua_State *L) { @@ -3966,6 +4363,11 @@ static int LuaSha512(lua_State *L) { return LuaHasher(L, 64, Sha512); } +static int LuaGetHttpReason(lua_State *L) { + lua_pushstring(L, GetHttpReason(luaL_checkinteger(L, 1))); + return 1; +} + static int LuaEncodeLatin1(lua_State *L) { int f; char *p; @@ -4115,6 +4517,19 @@ static int LuaProgramRedirect(lua_State *L) { return 0; } +static int LuaProgramBool(lua_State *L, bool *b) { + *b = lua_toboolean(L, 1); + return 0; +} + +static int LuaProgramSslClientVerify(lua_State *L) { + return LuaProgramBool(L, &sslclientverify); +} + +static int LuaProgramSslFetchVerify(lua_State *L) { + return LuaProgramBool(L, &sslfetchverify); +} + static int LuaGetLogLevel(lua_State *L) { lua_pushinteger(L, __log_level); return 1; @@ -4418,108 +4833,112 @@ static bool LuaRun(const char *path) { } static const luaL_Reg kLuaFuncs[] = { - {"CategorizeIp", LuaCategorizeIp}, // - {"DecodeBase64", LuaDecodeBase64}, // - {"DecodeLatin1", LuaDecodeLatin1}, // - {"EncodeBase64", LuaEncodeBase64}, // - {"EncodeLatin1", LuaEncodeLatin1}, // - {"EncodeUrl", LuaEncodeUrl}, // - {"EscapeFragment", LuaEscapeFragment}, // - {"EscapeHost", LuaEscapeHost}, // - {"EscapeHtml", LuaEscapeHtml}, // - {"EscapeIp", LuaEscapeIp}, // - {"EscapeLiteral", LuaEscapeLiteral}, // - {"EscapeParam", LuaEscapeParam}, // - {"EscapePass", LuaEscapePass}, // - {"EscapePath", LuaEscapePath}, // - {"EscapeSegment", LuaEscapeSegment}, // - {"EscapeUser", LuaEscapeUser}, // - {"FormatHttpDateTime", LuaFormatHttpDateTime}, // - {"FormatIp", LuaFormatIp}, // - {"GetAssetMode", LuaGetAssetMode}, // - {"GetAssetSize", LuaGetAssetSize}, // - {"GetClientAddr", LuaGetClientAddr}, // - {"GetComment", LuaGetComment}, // - {"GetDate", LuaGetDate}, // - {"GetEffectivePath", LuaGetEffectivePath}, // - {"GetFragment", LuaGetFragment}, // - {"GetHeader", LuaGetHeader}, // - {"GetHeaders", LuaGetHeaders}, // - {"GetHost", LuaGetHost}, // - {"GetLastModifiedTime", LuaGetLastModifiedTime}, // - {"GetLogLevel", LuaGetLogLevel}, // - {"GetMethod", LuaGetMethod}, // - {"GetMonospaceWidth", LuaGetMonospaceWidth}, // - {"GetParam", LuaGetParam}, // - {"GetParams", LuaGetParams}, // - {"GetPass", LuaGetPass}, // - {"GetPath", LuaGetPath}, // - {"GetPayload", LuaGetPayload}, // - {"GetPort", LuaGetPort}, // - {"GetRemoteAddr", LuaGetRemoteAddr}, // - {"GetScheme", LuaGetScheme}, // - {"GetServerAddr", LuaGetServerAddr}, // - {"GetUrl", LuaGetUrl}, // - {"GetUser", LuaGetUser}, // - {"GetVersion", LuaGetVersion}, // - {"GetZipPaths", LuaGetZipPaths}, // - {"HasControlCodes", LuaHasControlCodes}, // - {"HasParam", LuaHasParam}, // - {"HidePath", LuaHidePath}, // - {"IndentLines", LuaIndentLines}, // - {"IsAcceptableHost", LuaIsAcceptableHost}, // - {"IsAcceptablePath", LuaIsAcceptablePath}, // - {"IsAcceptablePort", LuaIsAcceptablePort}, // - {"IsCompressed", LuaIsCompressed}, // - {"IsHiddenPath", LuaIsHiddenPath}, // - {"IsLoopbackIp", LuaIsLoopbackIp}, // - {"IsPrivateIp", LuaIsPrivateIp}, // - {"IsPublicIp", LuaIsPublicIp}, // - {"IsReasonablePath", LuaIsReasonablePath}, // - {"IsValidHttpToken", LuaIsValidHttpToken}, // - {"LaunchBrowser", LuaLaunchBrowser}, // - {"LoadAsset", LuaLoadAsset}, // - {"Log", LuaLog}, // - {"ParseHost", LuaParseHost}, // - {"ParseHttpDateTime", LuaParseHttpDateTime}, // - {"ParseIp", LuaParseIp}, // - {"ParseParams", LuaParseParams}, // - {"ParseUrl", LuaParseUrl}, // - {"ProgramAddr", LuaProgramAddr}, // - {"ProgramBrand", LuaProgramBrand}, // - {"ProgramCache", LuaProgramCache}, // - {"ProgramCertificate", LuaProgramCertificate}, // - {"ProgramHeader", LuaProgramHeader}, // - {"ProgramPort", LuaProgramPort}, // - {"ProgramPrivateKey", LuaProgramPrivateKey}, // - {"ProgramRedirect", LuaProgramRedirect}, // - {"ProgramTimeout", LuaProgramTimeout}, // - {"Route", LuaRoute}, // - {"RouteHost", LuaRouteHost}, // - {"RoutePath", LuaRoutePath}, // - {"ServeAsset", LuaServeAsset}, // - {"ServeError", LuaServeError}, // - {"ServeIndex", LuaServeIndex}, // - {"ServeListing", LuaServeListing}, // - {"ServeStatusz", LuaServeStatusz}, // - {"SetHeader", LuaSetHeader}, // - {"SetLogLevel", LuaSetLogLevel}, // - {"SetStatus", LuaSetStatus}, // - {"StoreAsset", LuaStoreAsset}, // - {"Underlong", LuaUnderlong}, // - {"VisualizeControlCodes", LuaVisualizeControlCodes}, // - {"Write", LuaWrite}, // - {"Md5", LuaMd5}, // - {"Sha1", LuaSha1}, // - {"Sha224", LuaSha224}, // - {"Sha256", LuaSha256}, // - {"Sha384", LuaSha384}, // - {"Sha512", LuaSha512}, // - {"bsf", LuaBsf}, // - {"bsr", LuaBsr}, // - {"crc32", LuaCrc32}, // - {"crc32c", LuaCrc32c}, // - {"popcnt", LuaPopcnt}, // + {"CategorizeIp", LuaCategorizeIp}, // + {"DecodeBase64", LuaDecodeBase64}, // + {"DecodeLatin1", LuaDecodeLatin1}, // + {"EncodeBase64", LuaEncodeBase64}, // + {"EncodeLatin1", LuaEncodeLatin1}, // + {"EncodeUrl", LuaEncodeUrl}, // + {"EscapeFragment", LuaEscapeFragment}, // + {"EscapeHost", LuaEscapeHost}, // + {"EscapeHtml", LuaEscapeHtml}, // + {"EscapeIp", LuaEscapeIp}, // + {"EscapeLiteral", LuaEscapeLiteral}, // + {"EscapeParam", LuaEscapeParam}, // + {"EscapePass", LuaEscapePass}, // + {"EscapePath", LuaEscapePath}, // + {"EscapeSegment", LuaEscapeSegment}, // + {"EscapeUser", LuaEscapeUser}, // + {"Fetch", LuaFetch}, // + {"FormatHttpDateTime", LuaFormatHttpDateTime}, // + {"FormatIp", LuaFormatIp}, // + {"GetAssetMode", LuaGetAssetMode}, // + {"GetAssetSize", LuaGetAssetSize}, // + {"GetClientAddr", LuaGetClientAddr}, // + {"GetComment", LuaGetComment}, // + {"GetDate", LuaGetDate}, // + {"GetEffectivePath", LuaGetEffectivePath}, // + {"GetFragment", LuaGetFragment}, // + {"GetHeader", LuaGetHeader}, // + {"GetHeaders", LuaGetHeaders}, // + {"GetHost", LuaGetHost}, // + {"GetHttpReason", LuaGetHttpReason}, // + {"GetLastModifiedTime", LuaGetLastModifiedTime}, // + {"GetLogLevel", LuaGetLogLevel}, // + {"GetMethod", LuaGetMethod}, // + {"GetMonospaceWidth", LuaGetMonospaceWidth}, // + {"GetParam", LuaGetParam}, // + {"GetParams", LuaGetParams}, // + {"GetPass", LuaGetPass}, // + {"GetPath", LuaGetPath}, // + {"GetPayload", LuaGetPayload}, // + {"GetPort", LuaGetPort}, // + {"GetRemoteAddr", LuaGetRemoteAddr}, // + {"GetScheme", LuaGetScheme}, // + {"GetServerAddr", LuaGetServerAddr}, // + {"GetUrl", LuaGetUrl}, // + {"GetUser", LuaGetUser}, // + {"GetVersion", LuaGetVersion}, // + {"GetZipPaths", LuaGetZipPaths}, // + {"HasControlCodes", LuaHasControlCodes}, // + {"HasParam", LuaHasParam}, // + {"HidePath", LuaHidePath}, // + {"IndentLines", LuaIndentLines}, // + {"IsAcceptableHost", LuaIsAcceptableHost}, // + {"IsAcceptablePath", LuaIsAcceptablePath}, // + {"IsAcceptablePort", LuaIsAcceptablePort}, // + {"IsCompressed", LuaIsCompressed}, // + {"IsHiddenPath", LuaIsHiddenPath}, // + {"IsLoopbackIp", LuaIsLoopbackIp}, // + {"IsPrivateIp", LuaIsPrivateIp}, // + {"IsPublicIp", LuaIsPublicIp}, // + {"IsReasonablePath", LuaIsReasonablePath}, // + {"IsValidHttpToken", LuaIsValidHttpToken}, // + {"LaunchBrowser", LuaLaunchBrowser}, // + {"LoadAsset", LuaLoadAsset}, // + {"Log", LuaLog}, // + {"Md5", LuaMd5}, // + {"ParseHost", LuaParseHost}, // + {"ParseHttpDateTime", LuaParseHttpDateTime}, // + {"ParseIp", LuaParseIp}, // + {"ParseParams", LuaParseParams}, // + {"ParseUrl", LuaParseUrl}, // + {"ProgramAddr", LuaProgramAddr}, // + {"ProgramBrand", LuaProgramBrand}, // + {"ProgramCache", LuaProgramCache}, // + {"ProgramCertificate", LuaProgramCertificate}, // + {"ProgramHeader", LuaProgramHeader}, // + {"ProgramPort", LuaProgramPort}, // + {"ProgramPrivateKey", LuaProgramPrivateKey}, // + {"ProgramRedirect", LuaProgramRedirect}, // + {"ProgramSslClientVerify", LuaProgramSslClientVerify}, // + {"ProgramSslFetchVerify", LuaProgramSslFetchVerify}, // + {"ProgramTimeout", LuaProgramTimeout}, // + {"Route", LuaRoute}, // + {"RouteHost", LuaRouteHost}, // + {"RoutePath", LuaRoutePath}, // + {"ServeAsset", LuaServeAsset}, // + {"ServeError", LuaServeError}, // + {"ServeIndex", LuaServeIndex}, // + {"ServeListing", LuaServeListing}, // + {"ServeStatusz", LuaServeStatusz}, // + {"SetHeader", LuaSetHeader}, // + {"SetLogLevel", LuaSetLogLevel}, // + {"SetStatus", LuaSetStatus}, // + {"Sha1", LuaSha1}, // + {"Sha224", LuaSha224}, // + {"Sha256", LuaSha256}, // + {"Sha384", LuaSha384}, // + {"Sha512", LuaSha512}, // + {"StoreAsset", LuaStoreAsset}, // + {"Underlong", LuaUnderlong}, // + {"VisualizeControlCodes", LuaVisualizeControlCodes}, // + {"Write", LuaWrite}, // + {"bsf", LuaBsf}, // + {"bsr", LuaBsr}, // + {"crc32", LuaCrc32}, // + {"crc32c", LuaCrc32c}, // + {"popcnt", LuaPopcnt}, // }; extern int luaopen_lsqlite3(lua_State *); @@ -4581,21 +5000,6 @@ static void LuaReload(void) { #endif } -static void NotifyClose(void) { -#ifndef UNSECURE - if (usessl) { - DEBUGF("SSL notifying close"); - mbedtls_ssl_close_notify(&ssl); - } -#endif -} - -static void ReseedRng(mbedtls_ctr_drbg_context *r, const char *s) { -#ifndef UNSECURE - CHECK_EQ(0, mbedtls_ctr_drbg_reseed(r, (void *)s, strlen(s))); -#endif -} - static const char *DescribeClose(void) { if (killed) return "killed"; if (meltdown) return "meltdown"; @@ -4615,33 +5019,6 @@ static void LogClose(const char *reason) { } } -static void LogMessage(const char *d, const char *s, size_t n) { - size_t n2, n3; - char *s2, *s3; - while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n; - if ((s2 = DecodeLatin1(s, n, &n2))) { - if ((s3 = IndentLines(s2, n2, &n3, 1))) { - LOGF("%s %,ld byte message\n%.*s", d, n, n3, s3); - free(s3); - } - free(s2); - } -} - -static void LogBody(const char *d, const char *s, size_t n) { - char *s2, *s3; - size_t n2, n3; - if (!n) return; - while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n; - if ((s2 = VisualizeControlCodes(s, n, &n2))) { - if ((s3 = IndentLines(s2, n2, &n3, 1))) { - LOGF("%s %,ld byte payload\n%.*s", d, n, n3, s3); - free(s3); - } - free(s2); - } -} - static ssize_t SendString(const char *s) { size_t n; ssize_t rc; @@ -4926,10 +5303,8 @@ static char *SynchronizeChunked(void) { char *SynchronizeStream(void) { int64_t cl; if (HasHeader(kHttpTransferEncoding) && - !SlicesEqualCase("identity", 8, HeaderData(kHttpTransferEncoding), - HeaderLength(kHttpTransferEncoding))) { - if (SlicesEqualCase("chunked", 7, HeaderData(kHttpTransferEncoding), - HeaderLength(kHttpTransferEncoding))) { + !HeaderEqualCase(kHttpTransferEncoding, "identity")) { + if (HeaderEqualCase(kHttpTransferEncoding, "chunked")) { return SynchronizeChunked(); } else { return HandleTransferRefused(); @@ -5382,7 +5757,7 @@ static bool HandleMessage(void) { if (extrahdrs) p = stpcpy(p, extrahdrs); if (connectionclose) { p = stpcpy(p, "Connection: close\r\n"); - } else if (encouragekeepalive && msg.version >= 11) { + } else if (timeout.tv_sec < 0 && msg.version >= 11) { p = stpcpy(p, "Connection: keep-alive\r\n"); } actualcontentlength = contentlength; @@ -5588,7 +5963,7 @@ static void HandleConnection(size_t i) { } } if (!pid) CloseServerFds(); - DEBUGF("%s accepted", DescribeClient()); + VERBOSEF("ACCEPT %s VIA %s", DescribeClient(), DescribeServer()); HandleMessages(); DEBUGF("%s closing after %,ldΒ΅s", DescribeClient(), (long)((nowl() - startconnection) * 1e6L)); @@ -5671,25 +6046,6 @@ static void HandlePoll(void) { } } -static void Tune(int fd, int a, int b, int x, const char *as, const char *bs) { -#define Tune(F, A, B, X) Tune(F, A, B, X, #A, #B) - if (!b) return; - if (setsockopt(fd, a, b, &x, sizeof(x)) == -1) { - WARNF("setsockopt(server, %s, %s, %d) failed %s", as, bs, x, - strerror(errno)); - } -} - -static void TuneServer(int fd) { - Tune(fd, SOL_SOCKET, SO_REUSEADDR, 1); - Tune(fd, IPPROTO_TCP, TCP_CORK, 0); - Tune(fd, IPPROTO_TCP, TCP_NODELAY, 1); - Tune(fd, IPPROTO_TCP, TCP_FASTOPEN, 1); - Tune(fd, IPPROTO_TCP, TCP_QUICKACK, 1); - setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); - setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); -} - static void RestoreApe(void) { char *p; size_t n; @@ -5736,12 +6092,11 @@ static void Listen(void) { servers.p[n].addr.sin_family = AF_INET; servers.p[n].addr.sin_port = htons(ports.p[j]); servers.p[n].addr.sin_addr.s_addr = htonl(ips.p[i]); - if ((servers.p[n].fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, - IPPROTO_TCP)) == -1) { + if ((servers.p[n].fd = Socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, + IPPROTO_TCP, true)) == -1) { perror("socket"); exit(1); } - TuneServer(servers.p[n].fd); if (bind(servers.p[n].fd, &servers.p[n].addr, sizeof(servers.p[n].addr)) == -1) { fprintf(stderr, "error: %s: %hhu.%hhu.%hhu.%hhu:%hu\n", strerror(errno), @@ -5782,6 +6137,7 @@ void RedBean(int argc, char *argv[]) { long double t; #ifndef UNSECURE InitializeRng(&rng); + InitializeRng(&rngcli); LoadSslRoots(); #endif reader = read; @@ -5814,10 +6170,22 @@ void RedBean(int argc, char *argv[]) { mbedtls_ssl_config_defaults( &conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, suiteb ? MBEDTLS_SSL_PRESET_SUITEB : MBEDTLS_SSL_PRESET_DEFAULT); + mbedtls_ssl_config_defaults( + &confcli, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, + suiteb ? MBEDTLS_SSL_PRESET_SUITEB : MBEDTLS_SSL_PRESET_DEFAULT); mbedtls_ssl_conf_dbg(&conf, TlsDebug, 0); + mbedtls_ssl_conf_dbg(&confcli, TlsDebug, 0); LoadCertificates(); mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &rng); + mbedtls_ssl_conf_rng(&confcli, mbedtls_ctr_drbg_random, &rngcli); + mbedtls_ssl_conf_authmode(&conf, sslclientverify ? MBEDTLS_SSL_VERIFY_REQUIRED + : MBEDTLS_SSL_VERIFY_NONE); + mbedtls_ssl_conf_authmode(&confcli, sslfetchverify + ? MBEDTLS_SSL_VERIFY_REQUIRED + : MBEDTLS_SSL_VERIFY_NONE); + mbedtls_ssl_conf_ca_chain(&confcli, GetSslRoots(), 0); mbedtls_ssl_setup(&ssl, &conf); + mbedtls_ssl_setup(&sslcli, &confcli); mbedtls_ssl_set_bio(&ssl, &client, TlsSend, 0, TlsRecv); #endif if (launchbrowser) { diff --git a/usr/share/ssl/root/digicert.pem b/usr/share/ssl/root/digicert.pem index 5a816b647..0c1c33b6b 100644 --- a/usr/share/ssl/root/digicert.pem +++ b/usr/share/ssl/root/digicert.pem @@ -1,3 +1,5 @@ +https://www.digicert.com/kb/digicert-root-certificates.htm + -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -20,6 +22,7 @@ NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -42,6 +45,7 @@ B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo IhNzbM8m9Yop5w== -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu @@ -57,6 +61,7 @@ AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv 6pZjamVFkpUBtA== -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -79,6 +84,7 @@ PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -101,6 +107,7 @@ Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu @@ -116,6 +123,7 @@ AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 sycX -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -139,6 +147,7 @@ Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -171,3 +180,72 @@ r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 /YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ -----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp +Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 +MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ +bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS +7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp +0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS +B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 +BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ +LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 +DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT +HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN +NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs +IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ +ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 +2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp +wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM +pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD +nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po +sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx +Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd +Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX +KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe +XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL +tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv +TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN +AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H +PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF +O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ +REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik +AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv +/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ +p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw +MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF +qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK +ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE----- diff --git a/usr/share/ssl/root/isrg.pem b/usr/share/ssl/root/isrg.pem index b85c8037f..95f5b792e 100644 --- a/usr/share/ssl/root/isrg.pem +++ b/usr/share/ssl/root/isrg.pem @@ -1,3 +1,5 @@ +https://letsencrypt.org/certificates/ + -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh @@ -29,3 +31,17 @@ oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= -----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE-----