Do work on curl/mbedtls/zstd

This change fixes stderr to be unbuffered. Added hardware AES on ARM64
to help safeguard against timing attacks. The curl.com command will be
somewhat more pleasant to use.
This commit is contained in:
Justine Tunney 2023-07-07 10:00:49 -07:00
parent a186143f62
commit 0d3c1c8b1a
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
37 changed files with 1565 additions and 290 deletions

View file

@ -203,6 +203,7 @@ include third_party/chibicc/test/test.mk
include third_party/python/python.mk
include tool/build/build.mk
include tool/curl/curl.mk
include tool/ape/ape.mk
include third_party/qemu/qemu.mk
include examples/examples.mk
include examples/pyapp/pyapp.mk

View file

@ -33,6 +33,7 @@ endif
# - Better GDB debugging
#
ifeq ($(MODE), zero)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
OVERRIDE_CFLAGS += -O0
OVERRIDE_CXXFLAGS += -O0
@ -156,7 +157,7 @@ endif
ifeq ($(MODE), dbg)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_ADDRESS__
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_ADDRESS__ -D__SANITIZE_UNDEFINED__
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline
CONFIG_COPTS += -fsanitize=address -fsanitize=undefined
TARGET_ARCH ?= -msse3
@ -166,7 +167,7 @@ endif
ifeq ($(MODE), aarch64-dbg)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g
CONFIG_CPPFLAGS += -DMODE_DBG
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline
CONFIG_COPTS += -fsanitize=undefined
QUOTA ?= -C64 -L300

View file

@ -33,7 +33,7 @@ static FILE __stderr;
__attribute__((__constructor__)) static void __stderr_init(void) {
stderr = &__stderr;
stderr->fd = STDERR_FILENO;
stderr->bufmode = _IOLBF;
stderr->bufmode = _IONBF;
stderr->iomode = O_WRONLY;
stderr->buf = stderr->mem;
stderr->size = sizeof(stderr->mem);

View file

@ -57,14 +57,7 @@ int memcasecmp(const void *p, const void *q, size_t n) {
if ((a = p) != (b = q)) {
for (i = 0; i < n; ++i) {
while (i + 8 <= n) {
if ((w = (((uint64_t)a[0] << 000 | (uint64_t)a[1] << 010 |
(uint64_t)a[2] << 020 | (uint64_t)a[3] << 030 |
(uint64_t)a[4] << 040 | (uint64_t)a[5] << 050 |
(uint64_t)a[6] << 060 | (uint64_t)a[7] << 070) ^
((uint64_t)b[0] << 000 | (uint64_t)b[1] << 010 |
(uint64_t)b[2] << 020 | (uint64_t)b[3] << 030 |
(uint64_t)b[4] << 040 | (uint64_t)b[5] << 050 |
(uint64_t)b[6] << 060 | (uint64_t)b[7] << 070)))) {
if ((w = (READ64LE(a) ^ READ64LE(b)))) {
u = __builtin_ctzll(w);
i += u >> 3;
break;

View file

@ -18,54 +18,62 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/dirent.h"
#include "libc/errno.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/mem.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 "libc/thread/thread.h"
#include "third_party/mbedtls/x509_crt.h"
STATIC_YOINK("ssl_root_support");
static void FreeSslRoots(mbedtls_x509_crt *c) {
mbedtls_x509_crt_free(c);
free(c);
#define SSL_ROOT_DIR "/zip/usr/share/ssl/root"
static struct {
pthread_once_t once;
mbedtls_x509_crt chain;
} g_ssl_roots;
static void FreeSslRoots(void) {
mbedtls_x509_crt_free(&g_ssl_roots.chain);
}
static void InitSslRoots(void) {
DIR *dir;
if (!(dir = opendir(SSL_ROOT_DIR))) {
perror(SSL_ROOT_DIR);
return;
}
struct dirent *ent;
while ((ent = readdir(dir))) {
if (ent->d_type != DT_REG && //
ent->d_type != DT_UNKNOWN) {
continue;
}
char path[PATH_MAX];
strlcpy(path, SSL_ROOT_DIR "/", sizeof(path));
strlcat(path, ent->d_name, sizeof(path));
uint8_t *data;
int fd = open(path, O_RDONLY); // punt error to lseek
size_t size = lseek(fd, 0, SEEK_END); // punt error to calloc
if ((data = calloc(1, size + 1)) && pread(fd, data, size, 0) == size) {
if (mbedtls_x509_crt_parse(&g_ssl_roots.chain, data, size + 1)) {
tinyprint(2, path, ": error loading ssl root\n", NULL);
}
} else {
perror(path);
}
free(data);
close(fd);
}
closedir(dir);
atexit(FreeSslRoots);
}
/**
* Returns singleton of SSL roots stored in /zip/usr/share/ssl/root/...
*/
mbedtls_x509_crt *GetSslRoots(void) {
int fd;
DIR *d;
uint8_t *p;
size_t n, m;
struct dirent *e;
static bool once;
char path[PATH_MAX];
static mbedtls_x509_crt *c;
if (!once) {
if ((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)) >= ARRAYLEN(path)) 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);
}
__cxa_atexit(FreeSslRoots, c, 0);
}
once = true;
}
return c;
pthread_once(&g_ssl_roots.once, InitSslRoots);
return &g_ssl_roots.chain;
}

View file

@ -7,7 +7,7 @@ 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_CERTS := $(wildcard usr/share/ssl/root/*.pem)
NET_HTTPS_A_HDRS = $(filter %.h,$(NET_HTTPS_A_FILES))
NET_HTTPS_A_SRCS = $(filter %.c,$(NET_HTTPS_A_FILES))

View file

@ -15,10 +15,14 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "third_party/mbedtls/aes.h"
#include "libc/intrin/bits.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "third_party/mbedtls/aes.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/hwcap.h"
#include "third_party/mbedtls/aesce.h"
#include "third_party/mbedtls/aesni.h"
#include "third_party/mbedtls/common.h"
#include "third_party/mbedtls/error.h"
@ -471,6 +475,26 @@ static dontinline void aes_gen_tables( void )
#endif /* MBEDTLS_AES_FEWER_TABLES */
int mbedtls_aes_uses_hardware( void )
{
#ifdef __x86_64__
return( X86_HAVE( AES ) );
#else
static char once;
static char result;
if( !once )
{
unsigned long auxval;
auxval = getauxval( AT_HWCAP );
result = ( !auxval ||
(auxval & ( HWCAP_ASIMD | HWCAP_AES ) ) ==
( HWCAP_ASIMD | HWCAP_AES ) );
once = 1;
}
return( result );
#endif
}
void mbedtls_aes_init( mbedtls_aes_context *ctx )
{
AES_VALIDATE( ctx != NULL );
@ -535,8 +559,12 @@ int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key,
#endif
ctx->rk = RK = ctx->buf;
#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
if( X86_HAVE( AES ) )
if( mbedtls_aes_uses_hardware() )
return( mbedtls_aesni_setkey_enc( (unsigned char *) ctx->rk, key, keybits ) );
#endif
#if defined(MBEDTLS_AESCE_C) && defined(__aarch64__)
if( mbedtls_aes_uses_hardware() )
return( mbedtls_aesce_setkey_enc( (unsigned char *) RK, key, keybits ) );
#endif
for( i = 0; i < ( keybits >> 5 ); i++ )
{
@ -603,7 +631,7 @@ int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key,
*/
#if !defined(MBEDTLS_AES_SETKEY_DEC_ALT)
int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits )
unsigned int keybits )
{
int i, j, ret;
mbedtls_aes_context cty;
@ -625,10 +653,18 @@ int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key,
goto exit;
ctx->nr = cty.nr;
#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
if( X86_HAVE( AES ) )
if( mbedtls_aes_uses_hardware() )
{
mbedtls_aesni_inverse_key( (unsigned char *) ctx->rk,
(const unsigned char *) cty.rk, ctx->nr );
(const unsigned char *) cty.rk, ctx->nr );
goto exit;
}
#endif
#if defined(MBEDTLS_AESCE_C) && defined(__aarch64__)
if( mbedtls_aes_uses_hardware() )
{
mbedtls_aesce_inverse_key( (unsigned char *) ctx->rk,
(const unsigned char *) cty.rk, ctx->nr );
goto exit;
}
#endif
@ -887,9 +923,13 @@ int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx,
AES_VALIDATE_RET( mode == MBEDTLS_AES_ENCRYPT ||
mode == MBEDTLS_AES_DECRYPT );
#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64)
if( X86_HAVE( AES ) )
if( mbedtls_aes_uses_hardware() )
return( mbedtls_aesni_crypt_ecb( ctx, mode, input, output ) );
#endif
#if defined(MBEDTLS_AESCE_C) && defined(__aarch64__)
if( mbedtls_aes_uses_hardware() )
return mbedtls_aesce_crypt_ecb( ctx, mode, input, output );
#endif
#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)
if( aes_padlock_ace )
{

View file

@ -46,12 +46,14 @@ mbedtls_aes_context;
typedef struct mbedtls_aes_xts_context
{
mbedtls_aes_context crypt; /*!< The AES context to use for AES block
encryption or decryption. */
encryption or decryption. */
mbedtls_aes_context tweak; /*!< The AES context used for tweak
computation. */
computation. */
} mbedtls_aes_xts_context;
#endif /* MBEDTLS_CIPHER_MODE_XTS */
int mbedtls_aes_uses_hardware( void );
/**
* \brief This function initializes the specified AES context.
*

412
third_party/mbedtls/aesce.c vendored Normal file
View file

@ -0,0 +1,412 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright The Mbed TLS Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 │
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "third_party/mbedtls/aesce.h"
#include "libc/str/str.h"
#include "third_party/aarch64/arm_neon.internal.h"
asm(".ident\t\"\\n\\n\
Mbed TLS (Apache 2.0)\\n\
Copyright ARM Limited\\n\
Copyright Mbed TLS Contributors\"");
asm(".include \"libc/disclaimer.inc\"");
// clang-format off
/*
* Armv8-A Cryptographic Extension support functions for Aarch64
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(__aarch64__) && !defined(__ARM_FEATURE_CRYPTO) && \
defined(__clang__) && __clang_major__ >= 4
/* TODO: Re-consider above after https://reviews.llvm.org/D131064 merged.
*
* The intrinsic declaration are guarded by predefined ACLE macros in clang:
* these are normally only enabled by the -march option on the command line.
* By defining the macros ourselves we gain access to those declarations without
* requiring -march on the command line.
*
* `arm_neon.h` could be included by any header file, so we put these defines
* at the top of this file, before any includes.
*/
#define __ARM_FEATURE_CRYPTO 1
/* See: https://arm-software.github.io/acle/main/acle.html#cryptographic-extensions
*
* `__ARM_FEATURE_CRYPTO` is deprecated, but we need to continue to specify it
* for older compilers.
*/
#define __ARM_FEATURE_AES 1
#define MBEDTLS_ENABLE_ARM_CRYPTO_EXTENSIONS_COMPILER_FLAG
#endif
#if defined(MBEDTLS_AESCE_C)
#ifdef __aarch64__
#if !defined(__ARM_FEATURE_AES) || defined(MBEDTLS_ENABLE_ARM_CRYPTO_EXTENSIONS_COMPILER_FLAG)
# if defined(__clang__)
# if __clang_major__ < 4
# error "A more recent Clang is required for MBEDTLS_AESCE_C"
# endif
# pragma clang attribute push (__attribute__((target("crypto"))), apply_to=function)
# define MBEDTLS_POP_TARGET_PRAGMA
# elif defined(__GNUC__)
# if __GNUC__ < 6
# error "A more recent GCC is required for MBEDTLS_AESCE_C"
# endif
# pragma GCC push_options
# pragma GCC target ("arch=armv8-a+crypto")
# define MBEDTLS_POP_TARGET_PRAGMA
# else
# error "Only GCC and Clang supported for MBEDTLS_AESCE_C"
# endif
#endif /* !__ARM_FEATURE_AES || MBEDTLS_ENABLE_ARM_CRYPTO_EXTENSIONS_COMPILER_FLAG */
static uint8x16_t aesce_encrypt_block(uint8x16_t block,
unsigned char *keys,
int rounds)
{
for (int i = 0; i < rounds - 1; i++) {
/* AES AddRoundKey, SubBytes, ShiftRows (in this order).
* AddRoundKey adds the round key for the previous round. */
block = vaeseq_u8(block, vld1q_u8(keys + i * 16));
/* AES mix columns */
block = vaesmcq_u8(block);
}
/* AES AddRoundKey for the previous round.
* SubBytes, ShiftRows for the final round. */
block = vaeseq_u8(block, vld1q_u8(keys + (rounds -1) * 16));
/* Final round: no MixColumns */
/* Final AddRoundKey */
block = veorq_u8(block, vld1q_u8(keys + rounds * 16));
return block;
}
static uint8x16_t aesce_decrypt_block(uint8x16_t block,
unsigned char *keys,
int rounds)
{
for (int i = 0; i < rounds - 1; i++) {
/* AES AddRoundKey, SubBytes, ShiftRows */
block = vaesdq_u8(block, vld1q_u8(keys + i * 16));
/* AES inverse MixColumns for the next round.
*
* This means that we switch the order of the inverse AddRoundKey and
* inverse MixColumns operations. We have to do this as AddRoundKey is
* done in an atomic instruction together with the inverses of SubBytes
* and ShiftRows.
*
* It works because MixColumns is a linear operation over GF(2^8) and
* AddRoundKey is an exclusive or, which is equivalent to addition over
* GF(2^8). (The inverse of MixColumns needs to be applied to the
* affected round keys separately which has been done when the
* decryption round keys were calculated.) */
block = vaesimcq_u8(block);
}
/* The inverses of AES AddRoundKey, SubBytes, ShiftRows finishing up the
* last full round. */
block = vaesdq_u8(block, vld1q_u8(keys + (rounds - 1) * 16));
/* Inverse AddRoundKey for inverting the initial round key addition. */
block = veorq_u8(block, vld1q_u8(keys + rounds * 16));
return block;
}
/*
* AES-ECB block en(de)cryption
*/
int mbedtls_aesce_crypt_ecb(mbedtls_aes_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16])
{
uint8x16_t block = vld1q_u8(&input[0]);
unsigned char *keys = (unsigned char *) (ctx->rk);
if (mode == MBEDTLS_AES_ENCRYPT) {
block = aesce_encrypt_block(block, keys, ctx->nr);
} else {
block = aesce_decrypt_block(block, keys, ctx->nr);
}
vst1q_u8(&output[0], block);
return 0;
}
/*
* Compute decryption round keys from encryption round keys
*/
void mbedtls_aesce_inverse_key(unsigned char *invkey,
const unsigned char *fwdkey,
int nr)
{
int i, j;
j = nr;
vst1q_u8(invkey, vld1q_u8(fwdkey + j * 16));
for (i = 1, j--; j > 0; i++, j--) {
vst1q_u8(invkey + i * 16,
vaesimcq_u8(vld1q_u8(fwdkey + j * 16)));
}
vst1q_u8(invkey + i * 16, vld1q_u8(fwdkey + j * 16));
}
static inline uint32_t aes_rot_word(uint32_t word)
{
return (word << (32 - 8)) | (word >> 8);
}
static inline uint32_t aes_sub_word(uint32_t in)
{
uint8x16_t v = vreinterpretq_u8_u32(vdupq_n_u32(in));
uint8x16_t zero = vdupq_n_u8(0);
/* vaeseq_u8 does both SubBytes and ShiftRows. Taking the first row yields
* the correct result as ShiftRows doesn't change the first row. */
v = vaeseq_u8(zero, v);
return vgetq_lane_u32(vreinterpretq_u32_u8(v), 0);
}
/*
* Key expansion function
*/
static void aesce_setkey_enc(unsigned char *rk,
const unsigned char *key,
const size_t key_bit_length)
{
static uint8_t const rcon[] = { 0x01, 0x02, 0x04, 0x08, 0x10,
0x20, 0x40, 0x80, 0x1b, 0x36 };
/* See https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf
* - Section 5, Nr = Nk + 6
* - Section 5.2, the length of round keys is Nb*(Nr+1)
*/
const uint32_t key_len_in_words = key_bit_length / 32; /* Nk */
const size_t round_key_len_in_words = 4; /* Nb */
const size_t rounds_needed = key_len_in_words + 6; /* Nr */
const size_t round_keys_len_in_words =
round_key_len_in_words * (rounds_needed + 1); /* Nb*(Nr+1) */
const uint32_t *rko_end = (uint32_t *) rk + round_keys_len_in_words;
memcpy(rk, key, key_len_in_words * 4);
for (uint32_t *rki = (uint32_t *) rk;
rki + key_len_in_words < rko_end;
rki += key_len_in_words) {
size_t iteration = (rki - (uint32_t *) rk) / key_len_in_words;
uint32_t *rko;
rko = rki + key_len_in_words;
rko[0] = aes_rot_word(aes_sub_word(rki[key_len_in_words - 1]));
rko[0] ^= rcon[iteration] ^ rki[0];
rko[1] = rko[0] ^ rki[1];
rko[2] = rko[1] ^ rki[2];
rko[3] = rko[2] ^ rki[3];
if (rko + key_len_in_words > rko_end) {
/* Do not write overflow words.*/
continue;
}
switch (key_bit_length) {
case 128:
break;
case 192:
rko[4] = rko[3] ^ rki[4];
rko[5] = rko[4] ^ rki[5];
break;
case 256:
rko[4] = aes_sub_word(rko[3]) ^ rki[4];
rko[5] = rko[4] ^ rki[5];
rko[6] = rko[5] ^ rki[6];
rko[7] = rko[6] ^ rki[7];
break;
}
}
}
/*
* Key expansion, wrapper
*/
int mbedtls_aesce_setkey_enc(unsigned char *rk,
const unsigned char *key,
size_t bits)
{
switch (bits) {
case 128:
case 192:
case 256:
aesce_setkey_enc(rk, key, bits);
break;
default:
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
}
return 0;
}
#if defined(MBEDTLS_GCM_C)
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ == 5
/* Some intrinsics are not available for GCC 5.X. */
#define vreinterpretq_p64_u8(a) ((poly64x2_t) a)
#define vreinterpretq_u8_p128(a) ((uint8x16_t) a)
static inline poly64_t vget_low_p64(poly64x2_t __a)
{
uint64x2_t tmp = (uint64x2_t) (__a);
uint64x1_t lo = vcreate_u64(vgetq_lane_u64(tmp, 0));
return (poly64_t) (lo);
}
#endif /* !__clang__ && __GNUC__ && __GNUC__ == 5*/
/* vmull_p64/vmull_high_p64 wrappers.
*
* Older compilers miss some intrinsic functions for `poly*_t`. We use
* uint8x16_t and uint8x16x3_t as input/output parameters.
*/
static inline uint8x16_t pmull_low(uint8x16_t a, uint8x16_t b)
{
return vreinterpretq_u8_p128(
vmull_p64(
(poly64_t) vget_low_p64(vreinterpretq_p64_u8(a)),
(poly64_t) vget_low_p64(vreinterpretq_p64_u8(b))));
}
static inline uint8x16_t pmull_high(uint8x16_t a, uint8x16_t b)
{
return vreinterpretq_u8_p128(
vmull_high_p64(vreinterpretq_p64_u8(a),
vreinterpretq_p64_u8(b)));
}
/* GHASH does 128b polynomial multiplication on block in GF(2^128) defined by
* `x^128 + x^7 + x^2 + x + 1`.
*
* Arm64 only has 64b->128b polynomial multipliers, we need to do 4 64b
* multiplies to generate a 128b.
*
* `poly_mult_128` executes polynomial multiplication and outputs 256b that
* represented by 3 128b due to code size optimization.
*
* Output layout:
* | | | |
* |------------|-------------|-------------|
* | ret.val[0] | h3:h2:00:00 | high 128b |
* | ret.val[1] | :m2:m1:00 | middle 128b |
* | ret.val[2] | : :l1:l0 | low 128b |
*/
static inline uint8x16x3_t poly_mult_128(uint8x16_t a, uint8x16_t b)
{
uint8x16x3_t ret;
uint8x16_t h, m, l; /* retval high/middle/low */
uint8x16_t c, d, e;
h = pmull_high(a, b); /* h3:h2:00:00 = a1*b1 */
l = pmull_low(a, b); /* : :l1:l0 = a0*b0 */
c = vextq_u8(b, b, 8); /* :c1:c0 = b0:b1 */
d = pmull_high(a, c); /* :d2:d1:00 = a1*b0 */
e = pmull_low(a, c); /* :e2:e1:00 = a0*b1 */
m = veorq_u8(d, e); /* :m2:m1:00 = d + e */
ret.val[0] = h;
ret.val[1] = m;
ret.val[2] = l;
return ret;
}
/*
* Modulo reduction.
*
* See: https://www.researchgate.net/publication/285612706_Implementing_GCM_on_ARMv8
*
* Section 4.3
*
* Modular reduction is slightly more complex. Write the GCM modulus as f(z) =
* z^128 +r(z), where r(z) = z^7+z^2+z+ 1. The well known approach is to
* consider that z^128 r(z) (mod z^128 +r(z)), allowing us to write the 256-bit
* operand to be reduced as a(z) = h(z)z^128 +l(z)h(z)r(z) + l(z). That is, we
* simply multiply the higher part of the operand by r(z) and add it to l(z). If
* the result is still larger than 128 bits, we reduce again.
*/
static inline uint8x16_t poly_mult_reduce(uint8x16x3_t input)
{
uint8x16_t const ZERO = vdupq_n_u8(0);
/* use 'asm' as an optimisation barrier to prevent loading MODULO from memory */
uint64x2_t r = vreinterpretq_u64_u8(vdupq_n_u8(0x87));
asm ("" : "+w" (r));
uint8x16_t const MODULO = vreinterpretq_u8_u64(vshrq_n_u64(r, 64 - 8));
uint8x16_t h, m, l; /* input high/middle/low 128b */
uint8x16_t c, d, e, f, g, n, o;
h = input.val[0]; /* h3:h2:00:00 */
m = input.val[1]; /* :m2:m1:00 */
l = input.val[2]; /* : :l1:l0 */
c = pmull_high(h, MODULO); /* :c2:c1:00 = reduction of h3 */
d = pmull_low(h, MODULO); /* : :d1:d0 = reduction of h2 */
e = veorq_u8(c, m); /* :e2:e1:00 = m2:m1:00 + c2:c1:00 */
f = pmull_high(e, MODULO); /* : :f1:f0 = reduction of e2 */
g = vextq_u8(ZERO, e, 8); /* : :g1:00 = e1:00 */
n = veorq_u8(d, l); /* : :n1:n0 = d1:d0 + l1:l0 */
o = veorq_u8(n, f); /* o1:o0 = f1:f0 + n1:n0 */
return veorq_u8(o, g); /* = o1:o0 + g1:00 */
}
/*
* GCM multiplication: c = a times b in GF(2^128)
*/
void mbedtls_aesce_gcm_mult(unsigned char c[16],
const unsigned char a[16],
const unsigned char b[16])
{
uint8x16_t va, vb, vc;
va = vrbitq_u8(vld1q_u8(&a[0]));
vb = vrbitq_u8(vld1q_u8(&b[0]));
vc = vrbitq_u8(poly_mult_reduce(poly_mult_128(va, vb)));
vst1q_u8(&c[0], vc);
}
#endif /* MBEDTLS_GCM_C */
#if defined(MBEDTLS_POP_TARGET_PRAGMA)
#if defined(__clang__)
#pragma clang attribute pop
#elif defined(__GNUC__)
#pragma GCC pop_options
#endif
#undef MBEDTLS_POP_TARGET_PRAGMA
#endif
#endif /* MBEDTLS_HAVE_ARM64 */
#endif /* MBEDTLS_AESCE_C */

62
third_party/mbedtls/aesce.h vendored Normal file
View file

@ -0,0 +1,62 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_MBEDTLS_AESCE_H_
#define COSMOPOLITAN_THIRD_PARTY_MBEDTLS_AESCE_H_
#include "third_party/mbedtls/aes.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* \brief Internal AES-ECB block encryption and decryption
*
* \param ctx AES context
* \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
* \param input 16-byte input block
* \param output 16-byte output block
*
* \return 0 on success (cannot fail)
*/
int mbedtls_aesce_crypt_ecb(mbedtls_aes_context *ctx, int mode,
const unsigned char input[16],
unsigned char output[16]);
/**
* \brief Internal GCM multiplication: c = a * b in GF(2^128)
*
* \note This function is only for internal use by other library
* functions; you must not call it directly.
*
* \param c Result
* \param a First operand
* \param b Second operand
*
* \note Both operands and result are bit strings interpreted as
* elements of GF(2^128) as per the GCM spec.
*/
void mbedtls_aesce_gcm_mult(unsigned char c[16], const unsigned char a[16],
const unsigned char b[16]);
/**
* \brief Internal round key inversion. This function computes
* decryption round keys from the encryption round keys.
*
* \param invkey Round keys for the equivalent inverse cipher
* \param fwdkey Original round keys (for encryption)
* \param nr Number of rounds (that is, number of round keys minus one)
*/
void mbedtls_aesce_inverse_key(unsigned char *invkey,
const unsigned char *fwdkey, int nr);
/**
* \brief Internal key expansion for encryption
*
* \param rk Destination buffer where the round keys are written
* \param key Encryption key
* \param bits Key size in bits (must be 128, 192 or 256)
*
* \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH
*/
int mbedtls_aesce_setkey_enc(unsigned char *rk, const unsigned char *key,
size_t bits);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_MBEDTLS_AESCE_H_ */

View file

@ -26,11 +26,9 @@
/* ciphers */
#define MBEDTLS_AES_C
#ifndef TINY
#define MBEDTLS_CHACHA20_C
#define MBEDTLS_POLY1305_C
#define MBEDTLS_CHACHAPOLY_C
#endif
#ifdef MBEDTLS_SSL_PROTO_TLS1
#define MBEDTLS_DES_C
#endif
@ -58,9 +56,9 @@
#define MBEDTLS_ECDSA_C
#define MBEDTLS_ECDSA_DETERMINISTIC
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#ifndef TINY
#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
#define MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED
#ifndef TINY
#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
#define MBEDTLS_DHM_C
#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
@ -73,8 +71,8 @@
/* eliptic curves */
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
#ifndef TINY
#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
#ifndef TINY
#define MBEDTLS_ECP_DP_CURVE448_ENABLED
/*#define MBEDTLS_ECP_DP_SECP521R1_ENABLED*/
/*#define MBEDTLS_ECP_DP_BP384R1_ENABLED*/
@ -103,10 +101,9 @@
* Hardens against against sbox side channels
*/
#define MBEDTLS_AESNI_C
#if defined(__x86_64__) && !defined(TINY)
#define MBEDTLS_AESCE_C
#define MBEDTLS_HAVE_X86_64
#define MBEDTLS_HAVE_SSE2
#endif
#ifndef TINY
/*

40
third_party/mbedtls/describecode.c vendored Normal file
View file

@ -0,0 +1,40 @@
/*-*- 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 2023 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/fmt/itoa.h"
#include "libc/str/str.h"
#include "third_party/mbedtls/iana.h"
const char *DescribeMbedtlsErrorCode(int ret) {
static _Thread_local char sslerr[64];
char *p = sslerr;
p = stpcpy(p, "mbedtls error code ");
if (-ret <= 0xffffu) {
*p++ = '-';
*p++ = '0';
*p++ = 'x';
*p++ = "0123456789abcdef"[(-ret & 0xf000) >> 12];
*p++ = "0123456789abcdef"[(-ret & 0x0f00) >> 8];
*p++ = "0123456789abcdef"[(-ret & 0x00f0) >> 4];
*p++ = "0123456789abcdef"[(-ret & 0x000f) >> 0];
*p = 0;
} else {
FormatInt32(p, ret);
}
return sslerr;
}

View file

@ -1,4 +1,4 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:2;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright The Mbed TLS Contributors
@ -24,7 +24,7 @@
* @see RFC5246 §7.2
*/
const char *GetAlertDescription(unsigned char x) {
static char buf[21];
static _Thread_local char buf[21];
switch (x) {
case MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY: /* 0 */
return "close_notify";

View file

@ -6,8 +6,10 @@ COSMOPOLITAN_C_START_
bool IsCipherSuiteGood(uint16_t);
const char *GetCipherSuiteName(uint16_t);
const char *DescribeMbedtlsErrorCode(int);
const char *GetAlertDescription(unsigned char);
dontdiscard char *FormatSslClientCiphers(const mbedtls_ssl_context *);
const char *DescribeSslClientHandshakeError(const mbedtls_ssl_context *, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -25,14 +25,12 @@ THIRD_PARTY_MBEDTLS_A_DIRECTDEPS = \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_LOG \
LIBC_STDIO \
LIBC_STR \
LIBC_SYSV \
LIBC_TIME \
NET_HTTP \
THIRD_PARTY_COMPILER_RT \
THIRD_PARTY_GDTOA \
THIRD_PARTY_ZLIB
THIRD_PARTY_MBEDTLS_A_DEPS := \

View file

@ -15,6 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "third_party/mbedtls/sha1.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/bits.h"
#include "libc/macros.internal.h"
@ -26,7 +27,6 @@
#include "third_party/mbedtls/error.h"
#include "third_party/mbedtls/md.h"
#include "third_party/mbedtls/platform.h"
#include "third_party/mbedtls/sha1.h"
asm(".ident\t\"\\n\\n\
Mbed TLS (Apache 2.0)\\n\
@ -115,30 +115,27 @@ int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx,
SHA1_VALIDATE_RET( ctx != NULL );
SHA1_VALIDATE_RET( (const unsigned char *)data != NULL );
if( !IsTiny() || X86_NEED( SHA ) )
if( X86_HAVE( SHA ) )
{
if( X86_HAVE( SHA ) )
if( IsAsan() )
{
if( IsAsan() )
{
__asan_verify( data, 64 );
__asan_verify( ctx, sizeof(*ctx) );
}
sha1_transform_ni( ctx->state, data, 1 );
return( 0 );
__asan_verify( data, 64 );
__asan_verify( ctx, sizeof(*ctx) );
}
if( X86_HAVE( BMI ) &&
X86_HAVE( BMI2 ) &&
X86_HAVE( AVX2 ) )
sha1_transform_ni( ctx->state, data, 1 );
return( 0 );
}
if( X86_HAVE( BMI ) &&
X86_HAVE( BMI2 ) &&
X86_HAVE( AVX2 ) )
{
if( IsAsan() )
{
if( IsAsan() )
{
__asan_verify( data, 64 );
__asan_verify( ctx, sizeof(*ctx) );
}
sha1_transform_avx2( ctx->state, data, 1 );
return( 0 );
__asan_verify( data, 64 );
__asan_verify( ctx, sizeof(*ctx) );
}
sha1_transform_avx2( ctx->state, data, 1 );
return( 0 );
}
#ifdef MBEDTLS_SHA1_SMALLER
@ -413,7 +410,7 @@ int mbedtls_sha1_update_ret( mbedtls_sha1_context *ctx,
if( ilen >= 64 )
{
if( ( !IsTiny() || X86_NEED(SHA) ) && X86_HAVE( SHA ) )
if( X86_HAVE( SHA ) )
{
if( IsAsan() )
__asan_verify( input, ilen );
@ -421,8 +418,7 @@ int mbedtls_sha1_update_ret( mbedtls_sha1_context *ctx,
input += ROUNDDOWN( ilen, 64 );
ilen -= ROUNDDOWN( ilen, 64 );
}
else if( !IsTiny() &&
X86_HAVE( BMI ) &&
else if( X86_HAVE( BMI ) &&
X86_HAVE( BMI2 ) &&
X86_HAVE( AVX2 ) )
{

View file

@ -172,26 +172,23 @@ int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx,
SHA256_VALIDATE_RET( ctx != NULL );
SHA256_VALIDATE_RET( (const unsigned char *)data != NULL );
if( !IsTiny() || X86_NEED( SHA ) )
if( X86_HAVE( SHA ) &&
X86_HAVE( SSE2 ) &&
X86_HAVE( SSSE3 ) )
{
if( X86_HAVE( SHA ) &&
X86_HAVE( SSE2 ) &&
X86_HAVE( SSSE3 ) )
{
if( IsAsan() )
__asan_verify( data, 64 );
sha256_transform_ni( ctx->state, data, 1 );
return( 0 );
}
if( X86_HAVE( BMI2 ) &&
X86_HAVE( AVX ) &&
X86_HAVE( AVX2 ) )
{
if( IsAsan() )
__asan_verify( data, 64 );
sha256_transform_rorx( ctx->state, data, 1 );
return( 0 );
}
if( IsAsan() )
__asan_verify( data, 64 );
sha256_transform_ni( ctx->state, data, 1 );
return( 0 );
}
if( X86_HAVE( BMI2 ) &&
X86_HAVE( AVX ) &&
X86_HAVE( AVX2 ) )
{
if( IsAsan() )
__asan_verify( data, 64 );
sha256_transform_rorx( ctx->state, data, 1 );
return( 0 );
}
for( i = 0; i < 8; i++ )
@ -311,8 +308,7 @@ int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx,
if( ilen >= 64 )
{
if( !IsTiny() &&
X86_HAVE( SHA ) &&
if( X86_HAVE( SHA ) &&
X86_HAVE( SSE2 ) &&
X86_HAVE( SSSE3 ) )
{
@ -322,8 +318,7 @@ int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx,
input += ROUNDDOWN( ilen, 64 );
ilen -= ROUNDDOWN( ilen, 64 );
}
else if( !IsTiny() &&
X86_HAVE( BMI ) &&
else if( X86_HAVE( BMI ) &&
X86_HAVE( BMI2 ) &&
X86_HAVE( AVX2 ) )
{

98
third_party/mbedtls/shakedescription.c vendored Normal file
View file

@ -0,0 +1,98 @@
/*-*- 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 2023 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 "third_party/mbedtls/iana.h"
#include "third_party/mbedtls/net_sockets.h"
#include "third_party/mbedtls/ssl.h"
#include "third_party/mbedtls/x509.h"
const char *DescribeSslClientHandshakeError(const mbedtls_ssl_context *ssl,
int ret) {
switch (ret) {
case MBEDTLS_ERR_SSL_CONN_EOF:
return "connection eof";
case MBEDTLS_ERR_NET_CONN_RESET:
return "connection reset";
case MBEDTLS_ERR_SSL_TIMEOUT:
return "ssl timeout";
case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN:
return "no cipher chosen";
case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE:
return "no usable ciphersuite";
case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION:
return "bad ssl version";
case MBEDTLS_ERR_SSL_INVALID_MAC:
return "bad ssl mac";
case MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE:
return "bad key exchange";
case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:
switch (ssl->session_negotiate->verify_result) {
case MBEDTLS_X509_BADCERT_EXPIRED:
return "the certificate validity has expired";
case MBEDTLS_X509_BADCERT_REVOKED:
return "the certificate has been revoked (is on a crl)";
case MBEDTLS_X509_BADCERT_CN_MISMATCH:
return "the certificate common name (cn) does not match with the "
"expected cn";
case MBEDTLS_X509_BADCERT_NOT_TRUSTED:
return "the certificate is not correctly signed by the trusted ca";
case MBEDTLS_X509_BADCRL_NOT_TRUSTED:
return "the crl is not correctly signed by the trusted ca";
case MBEDTLS_X509_BADCRL_EXPIRED:
return "the crl is expired";
case MBEDTLS_X509_BADCERT_MISSING:
return "certificate was missing";
case MBEDTLS_X509_BADCERT_SKIP_VERIFY:
return "certificate verification was skipped";
case MBEDTLS_X509_BADCERT_OTHER:
return "other reason (can be used by verify callback)";
case MBEDTLS_X509_BADCERT_FUTURE:
return "the certificate validity starts in the future";
case MBEDTLS_X509_BADCRL_FUTURE:
return "the crl is from the future";
case MBEDTLS_X509_BADCERT_KEY_USAGE:
return "usage does not match the keyusage extension";
case MBEDTLS_X509_BADCERT_EXT_KEY_USAGE:
return "usage does not match the extendedkeyusage extension";
case MBEDTLS_X509_BADCERT_NS_CERT_TYPE:
return "usage does not match the nscerttype extension";
case MBEDTLS_X509_BADCERT_BAD_MD:
return "the certificate is signed with an unacceptable hash";
case MBEDTLS_X509_BADCERT_BAD_PK:
return "the certificate is signed with an unacceptable pk alg (eg "
"rsa vs ecdsa)";
case MBEDTLS_X509_BADCERT_BAD_KEY:
return "the certificate is signed with an unacceptable key (eg bad "
"curve, rsa too short)";
case MBEDTLS_X509_BADCRL_BAD_MD:
return "the crl is signed with an unacceptable hash";
case MBEDTLS_X509_BADCRL_BAD_PK:
return "the crl is signed with an unacceptable pk alg (eg rsa vs "
"ecdsa)";
case MBEDTLS_X509_BADCRL_BAD_KEY:
return "the crl is signed with an unacceptable key (eg bad curve, "
"rsa too short)";
default:
return "verification failed";
}
case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE:
return GetAlertDescription(ssl->fatal_alert);
default:
return DescribeMbedtlsErrorCode(ret);
}
}

View file

@ -15,12 +15,16 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "third_party/mbedtls/ssl_ciphersuites.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/hwcap.h"
#include "third_party/mbedtls/aes.h"
#include "third_party/mbedtls/cipher.h"
#include "third_party/mbedtls/common.h"
#include "third_party/mbedtls/platform.h"
#include "third_party/mbedtls/ssl.h"
#include "third_party/mbedtls/ssl_ciphersuites.h"
asm(".ident\t\"\\n\\n\
Mbed TLS (Apache 2.0)\\n\
@ -1500,7 +1504,7 @@ const uint16_t *mbedtls_ssl_list_ciphersuites( void )
const uint16_t *p;
uint16_t *q;
if( X86_HAVE( AES ) )
if( mbedtls_aes_uses_hardware() )
p = ciphersuite_preference;
else
p = ciphersuite_preference_nehalem;

View file

@ -5060,7 +5060,7 @@ int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl )
if( ssl->in_msglen != 1 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid CCS message, len: %" MBEDTLS_PRINTF_SIZET,
ssl->in_msglen ) );
ssl->in_msglen ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
@ -5096,7 +5096,7 @@ int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl )
to be packed in a single message, but Mbed TLS doesn't
currently support this. */
MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid alert message, len: %" MBEDTLS_PRINTF_SIZET,
ssl->in_msglen ) );
ssl->in_msglen ) );
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}

View file

@ -1683,7 +1683,7 @@ int UTIL_countCores(int logical)
return numCores;
}
#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__CYGWIN__)
#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__CYGWIN__) || defined(__COSMOPOLITAN__)
/* Use POSIX sysconf
* see: man 3 sysconf */

View file

@ -56,6 +56,7 @@
#include "libc/stdio/temp.h"
#include "third_party/musl/tempnam.h" /* fprintf(), stdin, stdout, stderr */
#include "libc/errno.h" /* errno */
#include "libc/runtime/runtime.h"
#include "libc/assert.h" /* assert */
#include "third_party/zstd/programs/fileio.h" /* stdinmark, stdoutmark, ZSTD_EXTENSION */
@ -853,6 +854,10 @@ typedef enum { zom_compress, zom_decompress, zom_test, zom_bench, zom_train, zom
int main(int argCount, const char* argv[])
{
#ifndef NDEBUG
ShowCrashReports();
#endif
int argNb,
followLinks = 0,
allowBlockDevices = 0,

View file

@ -110,16 +110,17 @@ THIRD_PARTY_ZSTD_A_CHECKS = \
$(THIRD_PARTY_ZSTD_A_HDRS:%=o/$(MODE)/%.ok)
THIRD_PARTY_ZSTD_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_NEXGEN32E \
LIBC_STR \
LIBC_MEM \
LIBC_STDIO \
LIBC_TIME \
LIBC_CALLS \
LIBC_RUNTIME \
LIBC_FMT \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_STR \
LIBC_THREAD \
LIBC_TIME \
LIBC_SYSV
THIRD_PARTY_ZSTD_A_DEPS := \
@ -144,6 +145,10 @@ $(THIRD_PARTY_ZSTD_A_OBJS): private \
-Wframe-larger-than=262144 \
-Wno-comment
$(THIRD_PARTY_ZSTD_A_OBJS): private \
CPPFLAGS += \
-DZSTD_MULTITHREAD
o/$(MODE)/third_party/zstd/zstd.com.dbg: \
$(THIRD_PARTY_ZSTD) \
o/$(MODE)/third_party/zstd/programs/zstdcli.o \
@ -151,6 +156,10 @@ o/$(MODE)/third_party/zstd/zstd.com.dbg: \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/third_party/zstd/lib/compress/zstd_lazy.o: private \
CFLAGS += \
-O3
o/$(MODE)/third_party/zstd/lib/compress/zstd_lazy.o: \
QUOTA += -C64

412
tool/ape/ape.c Normal file
View file

@ -0,0 +1,412 @@
/*-*- 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 2023 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/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dns/dns.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/goodsocket.internal.h"
#include "libc/sock/sock.h"
#include "libc/stdio/append.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/str/slice.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/sock.h"
#include "net/http/http.h"
#include "net/http/url.h"
#include "net/https/https.h"
#include "third_party/getopt/getopt.internal.h"
#include "third_party/mbedtls/ctr_drbg.h"
#include "third_party/mbedtls/debug.h"
#include "third_party/mbedtls/error.h"
#include "third_party/mbedtls/iana.h"
#include "third_party/mbedtls/net_sockets.h"
#include "third_party/mbedtls/ssl.h"
#include "third_party/mbedtls/x509.h"
/**
* @fileoverview Downloads HTTP URL to stdout.
*/
#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))
static int sock;
static int outfd;
static const char *prog;
static const char *outpath;
static wontreturn void PrintUsage(int fd, int rc) {
tinyprint(fd, "usage: ", prog, " [-iksvV] URL\n", NULL);
exit(rc);
}
static const char *DescribeErrno(void) {
const char *reason;
if (!(reason = _strerdoc(errno))) reason = "Unknown error";
return reason;
}
static int GetSslEntropy(void *c, unsigned char *p, size_t n) {
if (getrandom(p, n, 0) != n) {
perror("getrandom");
exit(1);
}
return 0;
}
static void OnSslDebug(void *ctx, int level, const char *file, int line,
const char *message) {
char sline[12];
char slevel[12];
FormatInt32(sline, line);
FormatInt32(slevel, level);
tinyprint(2, file, ":", sline, ": (", slevel, ") ", message, "\n", NULL);
}
static void WriteOutput(const void *p, size_t n) {
if (!outfd) {
if (outpath) {
if ((outfd = creat(outpath, 0644)) <= 0) {
perror(outpath);
exit(1);
}
} else {
outfd = 1;
outpath = "<stdout>";
}
}
ssize_t rc;
for (size_t i = 0; i < n; i += rc) {
rc = write(outfd, p, n);
if (rc <= 0) {
perror(outpath);
exit(1);
}
}
}
static int TlsSend(void *c, const unsigned char *p, size_t n) {
int rc;
if ((rc = write(*(int *)c, p, n)) == -1) {
perror("TlsSend");
exit(1);
}
return rc;
}
static int TlsRecv(void *c, unsigned char *p, size_t n, uint32_t o) {
int r;
struct iovec v[2];
static unsigned a, b;
static unsigned char t[4096];
if (a < b) {
r = MIN(n, b - a);
memcpy(p, t + a, r);
if ((a += r) == b) {
a = b = 0;
}
return r;
}
v[0].iov_base = p;
v[0].iov_len = n;
v[1].iov_base = t;
v[1].iov_len = sizeof(t);
if ((r = readv(*(int *)c, v, 2)) == -1) {
perror("TlsRecv");
exit(1);
}
if (r > n) {
b = r - n;
}
return MIN(n, r);
}
int _curl(int argc, char *argv[]) {
if (!NoDebug()) {
ShowCrashReports();
}
prog = argv[0];
if (!prog) {
prog = "curl";
}
/*
* Read flags.
*/
int opt;
while ((opt = getopt(argc, argv, "hV")) != -1) {
switch (opt) {
case 'V':
++mbedtls_debug_threshold;
break;
case 'h':
PrintUsage(1, 0);
default:
PrintUsage(2, 1);
}
}
/*
* Get argument.
*/
const char *urlarg;
if (optind == argc) {
tinyprint(2, prog, ": missing url\n", NULL);
PrintUsage(2, 1);
}
urlarg = argv[optind];
/*
* Parse URL.
*/
struct Url url;
char *host, *port;
gc(ParseUrl(urlarg, -1, &url, kUrlPlus));
gc(url.params.p);
if (url.host.n) {
if (url.scheme.n &&
!(url.scheme.n == 5 && !memcasecmp(url.scheme.p, "https", 5))) {
tinyprint(2, prog, ": not an https url: ", urlarg, "\n", NULL);
exit(1);
}
host = gc(strndup(url.host.p, url.host.n));
if (url.port.n) {
port = gc(strndup(url.port.p, url.port.n));
} else {
port = "443";
}
} else {
host = "127.0.0.1";
port = "443";
}
if (!IsAcceptableHost(host, -1)) {
tinyprint(2, prog, ": invalid host: ", urlarg, "\n", NULL);
exit(1);
}
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] != '/') {
char *p = gc(malloc(1 + url.path.n));
mempcpy(mempcpy(p, "/", 1), url.path.p, url.path.n);
url.path.p = p;
++url.path.n;
}
char *request = 0;
appendf(&request,
"GET %s HTTP/1.1\r\n"
"Connection: close\r\n"
"User-Agent: ape/1.1\r\n"
"Host: %s:%d\r\n"
"\r\n",
gc(EncodeUrl(&url, 0)), host, port);
/*
* Perform DNS lookup.
*/
struct addrinfo *addr;
struct addrinfo hints = {.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = IPPROTO_TCP,
.ai_flags = AI_NUMERICSERV};
if (getaddrinfo(host, port, &hints, &addr) != EAI_SUCCESS) {
tinyprint(2, prog, ": could not resolve host: ", host, "\n", NULL);
exit(1);
}
/*
* Connect to server.
*/
int ret;
if ((sock = GoodSocket(addr->ai_family, addr->ai_socktype, addr->ai_protocol,
false, &(struct timeval){-60})) == -1) {
perror("socket");
exit(1);
}
if (connect(sock, addr->ai_addr, addr->ai_addrlen)) {
tinyprint(2, prog, ": failed to connect to ", host, " port ", port, ": ",
DescribeErrno(), "\n", NULL);
exit(1);
}
freeaddrinfo(addr);
/*
* Setup crypto.
*/
mbedtls_ssl_config conf;
mbedtls_ssl_context ssl;
mbedtls_ctr_drbg_context drbg;
mbedtls_ssl_init(&ssl);
mbedtls_ctr_drbg_init(&drbg);
mbedtls_ssl_config_init(&conf);
_unassert(!mbedtls_ctr_drbg_seed(&drbg, GetSslEntropy, 0, "justine", 7));
_unassert(!mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT));
mbedtls_ssl_conf_ca_chain(&conf, GetSslRoots(), 0);
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &drbg);
#ifndef NDEBUG
mbedtls_ssl_conf_dbg(&conf, OnSslDebug, 0);
#endif
_unassert(!mbedtls_ssl_setup(&ssl, &conf));
_unassert(!mbedtls_ssl_set_hostname(&ssl, host));
mbedtls_ssl_set_bio(&ssl, &sock, TlsSend, 0, TlsRecv);
if ((ret = mbedtls_ssl_handshake(&ssl))) {
tinyprint(2, prog, ": ssl negotiation with ", host,
" failed: ", DescribeSslClientHandshakeError(&ssl, ret), "\n",
NULL);
exit(1);
}
/*
* Send HTTP Message.
*/
ssize_t rc;
size_t i, n;
n = appendz(request).i;
for (i = 0; i < n; i += rc) {
rc = mbedtls_ssl_write(&ssl, request + i, n - i);
if (rc <= 0) {
tinyprint(2, prog, ": ssl send failed: ", DescribeMbedtlsErrorCode(rc),
"\n", NULL);
exit(1);
}
}
/*
* Handle response.
*/
int t;
char *p;
ssize_t paylen;
size_t g, hdrlen;
struct HttpMessage msg;
struct HttpUnchunker u;
InitHttpMessage(&msg, kHttpResponse);
for (p = 0, hdrlen = paylen = t = i = n = 0;;) {
if (i == n) {
n += 1000;
n += n >> 1;
p = realloc(p, n);
}
if ((rc = mbedtls_ssl_read(&ssl, p + i, n - i)) < 0) {
if (rc == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
rc = 0;
} else {
tinyprint(2, prog, ": recv failed: ", DescribeMbedtlsErrorCode(rc),
"\n", NULL);
exit(1);
}
}
g = rc;
i += g;
switch (t) {
case kHttpClientStateHeaders:
_unassert(g);
if ((rc = ParseHttpMessage(&msg, p, i)) == -1) {
tinyprint(2, prog, ": ", host, " sent bad http message\n", NULL);
exit(1);
}
if (rc) {
hdrlen = rc;
if (100 <= msg.status && msg.status <= 199) {
DestroyHttpMessage(&msg);
InitHttpMessage(&msg, kHttpResponse);
memmove(p, p + hdrlen, i - hdrlen);
i -= hdrlen;
break;
}
if (msg.status == 204 || msg.status == 304) {
goto Finished;
}
if (!HasHeader(kHttpContentLength) ||
(paylen = ParseContentLength(HeaderData(kHttpContentLength),
HeaderLength(kHttpContentLength))) ==
-1 ||
(HasHeader(kHttpTransferEncoding) &&
!HeaderEqualCase(kHttpTransferEncoding, "identity"))) {
tinyprint(2, prog, ": ", host, " sent bad transfer\n", NULL);
exit(1);
}
t = kHttpClientStateBodyLengthed;
if (paylen > i - hdrlen) {
WriteOutput(p + hdrlen, i - hdrlen);
} else {
WriteOutput(p + hdrlen, paylen);
goto Finished;
}
}
break;
case kHttpClientStateBodyLengthed:
_unassert(g);
if (i - hdrlen > paylen) {
g = hdrlen + paylen - (i - g);
}
WriteOutput(p + i - g, g);
if (i - hdrlen >= paylen) {
goto Finished;
}
break;
default:
abort();
}
}
/*
* Close connection.
*/
Finished:
if (close(sock)) {
tinyprint(2, prog, ": close failed: ", DescribeErrno(), "\n", NULL);
exit(1);
}
/*
* Free memory.
*/
mbedtls_ssl_free(&ssl);
mbedtls_ctr_drbg_free(&drbg);
mbedtls_ssl_config_free(&conf);
mbedtls_ctr_drbg_free(&drbg);
free(p);
return 0;
}

67
tool/ape/ape.mk Normal file
View file

@ -0,0 +1,67 @@
#-*-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 += TOOL_APE
TOOL_APE_ARTIFACTS += TOOL_APE_A
TOOL_APE = $(TOOL_APE_DEPS) $(TOOL_APE_A)
TOOL_APE_A = o/$(MODE)/tool/ape/ape.a
TOOL_APE_FILES := $(wildcard tool/ape/*)
TOOL_APE_HDRS = $(filter %.h,$(TOOL_APE_FILES))
TOOL_APE_INCS = $(filter %.inc,$(TOOL_APE_FILES))
TOOL_APE_SRCS = $(filter %.c,$(TOOL_APE_FILES))
TOOL_APE_OBJS = $(TOOL_APE_SRCS:%.c=o/$(MODE)/%.o)
TOOL_APE_DIRECTDEPS = \
LIBC_CALLS \
LIBC_DNS \
LIBC_FMT \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_STDIO \
LIBC_STR \
LIBC_SYSV \
LIBC_TIME \
LIBC_X \
LIBC_ZIPOS \
NET_HTTP \
NET_HTTPS \
THIRD_PARTY_GETOPT \
THIRD_PARTY_MBEDTLS
TOOL_APE_DEPS := \
$(call uniq,$(foreach x,$(TOOL_APE_DIRECTDEPS),$($(x))))
TOOL_APE_CHECKS = \
$(TOOL_APE_A).pkg \
$(TOOL_APE_HDRS:%=o/$(MODE)/%.ok)
$(TOOL_APE_A): \
tool/ape/ \
$(TOOL_APE_A).pkg \
$(TOOL_APE_OBJS)
$(TOOL_APE_A).pkg: \
$(TOOL_APE_OBJS) \
$(foreach x,$(TOOL_APE_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/tool/ape/ape.com.dbg: \
$(TOOL_APE) \
o/$(MODE)/tool/ape/ape.o \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
TOOL_APE_LIBS = $(TOOL_APE_A)
TOOL_APE_BINS = $(TOOL_APE_COMS) $(TOOL_APE_COMS:%=%.dbg)
TOOL_APE_COMS = o/$(MODE)/tool/ape/ape.com
$(TOOL_APE_OBJS): $(BUILD_FILES) tool/ape/ape.mk
.PHONY: o/$(MODE)/tool/ape
o/$(MODE)/tool/ape: \
$(TOOL_APE_BINS) \
$(TOOL_APE_CHECKS)

13
tool/ape/zstd.sh Executable file
View file

@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -ex
rm -rf o/samples
make -j16 o//third_party/zstd/zstd.com
o//third_party/zstd/zstd.com --maxdict=524288 -9 -T0 -B4096 --train $(find o//{examples,tool,third_party} -name \*.com)
o//third_party/zstd/zstd.com -9 --ultra -fz o//tool/curl/curl.com
o//third_party/zstd/zstd.com -D dictionary -9 --ultra -fz o//tool/curl/curl.com
o//third_party/zstd/zstd.com -9 --ultra -fz o//examples/hello.com
o//third_party/zstd/zstd.com -D dictionary -9 --ultra -fz o//examples/hello.com
o//third_party/zstd/zstd.com -9 --ultra -fz o//examples/hello2.com
o//third_party/zstd/zstd.com -D dictionary -9 --ultra -fz o//examples/hello2.com
o//third_party/zstd/zstd.com -9 --ultra -fz o//examples/hello3.com
o//third_party/zstd/zstd.com -D dictionary -9 --ultra -fz o//examples/hello3.com

View file

@ -336,7 +336,6 @@ int main(int argc, char *argv[]) {
struct Args args = {reballoc(0, 4096, sizeof(char *))};
struct Args names = {reballoc(0, 4096, sizeof(char *))};
struct Ints modes = {reballoc(0, 4096, sizeof(int))};
struct Ints longnames = {reballoc(0, 256, sizeof(int))};
struct Ints sizes = {reballoc(0, 4096, sizeof(int))};
struct Ints symnames = {reballoc(0, 16384, sizeof(int))};
struct Bytes symbols = {reballoc(0, 131072, sizeof(char))};

View file

@ -89,7 +89,6 @@ void GetOpts(int argc, char *argv[]) {
g_mode = MODE_MACHO;
break;
case 'h':
case '?':
write(1, USAGE, sizeof(USAGE) - 1);
exit(0);
default:

View file

@ -7,18 +7,18 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dns/dns.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/goodsocket.internal.h"
#include "libc/sock/sock.h"
@ -28,31 +28,20 @@
#include "libc/str/slice.h"
#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/sig.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 "libc/x/xsigaction.h"
#include "net/http/http.h"
#include "net/http/url.h"
#include "net/https/https.h"
#include "net/https/sslcache.h"
#include "third_party/getopt/getopt.internal.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/iana.h"
#include "third_party/mbedtls/net_sockets.h"
#include "third_party/mbedtls/ssl.h"
#include "third_party/mbedtls/ssl_ticket.h"
#include "tool/curl/cmd.h"
#include "third_party/mbedtls/x509.h"
/**
* @fileoverview Downloads HTTP URL to stdout.
@ -64,31 +53,67 @@
#define HeaderEqualCase(H, S) \
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
int sock;
static int sock;
static int outfd;
static const char *prog;
static const char *outpath;
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 wontreturn void PrintUsage(int fd, int rc) {
tinyprint(fd, "usage: ", prog, " [-iksvV] URL\n", NULL);
exit(rc);
}
static void Write(const void *p, size_t n) {
ssize_t rc;
rc = write(1, p, n);
if (rc == -1 && errno == EPIPE) {
close(sock);
exit(128 + SIGPIPE);
}
if (rc != n) {
fprintf(stderr, "write failed: %m\n");
static const char *DescribeErrno(void) {
const char *reason;
if (!(reason = _strerdoc(errno))) reason = "Unknown error";
return reason;
}
static int GetSslEntropy(void *c, unsigned char *p, size_t n) {
if (getrandom(p, n, 0) != n) {
perror("getrandom");
exit(1);
}
return 0;
}
static void OnSslDebug(void *ctx, int level, const char *file, int line,
const char *message) {
char sline[12];
char slevel[12];
FormatInt32(sline, line);
FormatInt32(slevel, level);
tinyprint(2, file, ":", sline, ": (", slevel, ") ", message, "\n", NULL);
}
static void WriteOutput(const void *p, size_t n) {
if (!outfd) {
if (outpath) {
if ((outfd = creat(outpath, 0644)) <= 0) {
perror(outpath);
exit(1);
}
} else {
outfd = 1;
outpath = "<stdout>";
}
}
ssize_t rc;
for (size_t i = 0; i < n; i += rc) {
rc = write(outfd, p, n);
if (rc <= 0) {
perror(outpath);
exit(1);
}
}
}
static int TlsSend(void *c, const unsigned char *p, size_t n) {
int rc;
NOISEF("begin send %zu", n);
CHECK_NE(-1, (rc = write(*(int *)c, p, n)));
NOISEF("end send %zu", n);
if ((rc = write(*(int *)c, p, n)) == -1) {
perror("TlsSend");
exit(1);
}
return rc;
}
@ -100,27 +125,35 @@ static int TlsRecv(void *c, unsigned char *p, size_t n, uint32_t o) {
if (a < b) {
r = MIN(n, b - a);
memcpy(p, t + a, r);
if ((a += r) == b) a = b = 0;
if ((a += r) == b) {
a = b = 0;
}
return r;
}
v[0].iov_base = p;
v[0].iov_len = n;
v[1].iov_base = t;
v[1].iov_len = sizeof(t);
NOISEF("begin recv %zu", n + sizeof(t) - b);
CHECK_NE(-1, (r = readv(*(int *)c, v, 2)));
NOISEF("end recv %zu", r);
if (r > n) b = r - n;
if ((r = readv(*(int *)c, v, 2)) == -1) {
perror("TlsRecv");
exit(1);
}
if (r > n) {
b = r - n;
}
return MIN(n, r);
}
static wontreturn void PrintUsage(FILE *f, int rc) {
fprintf(f, "usage: %s [-iksvV] URL\n", program_invocation_name);
exit(rc);
}
int _curl(int argc, char *argv[]) {
if (!NoDebug()) ShowCrashReports();
if (!NoDebug()) {
ShowCrashReports();
}
prog = argv[0];
if (!prog) {
prog = "curl";
}
/*
* Read flags.
@ -131,18 +164,18 @@ int _curl(int argc, char *argv[]) {
char **p;
} headers = {0};
int method = 0;
bool authmode = MBEDTLS_SSL_VERIFY_REQUIRED;
int authmode = MBEDTLS_SSL_VERIFY_REQUIRED;
int ciphersuite = MBEDTLS_SSL_PRESET_SUITEC;
bool includeheaders = false;
const char *postdata = NULL;
const char *agent = "hurl/1.o (https://github.com/jart/cosmopolitan)";
__log_level = kLogWarn;
while ((opt = getopt(argc, argv, "qiksvVIX:H:A:d:")) != -1) {
while ((opt = getopt(argc, argv, "qiksvBVIX:H:A:d:o:")) != -1) {
switch (opt) {
case 's':
case 'q':
break;
case 'v':
++__log_level;
case 'o':
outpath = optarg;
break;
case 'i':
includeheaders = true;
@ -161,7 +194,10 @@ int _curl(int argc, char *argv[]) {
postdata = optarg;
break;
case 'X':
CHECK((method = GetHttpMethod(optarg, strlen(optarg))));
if (!(method = GetHttpMethod(optarg, strlen(optarg)))) {
tinyprint(2, prog, ": bad http method: ", optarg, "\n", NULL);
exit(1);
}
break;
case 'V':
++mbedtls_debug_threshold;
@ -169,10 +205,13 @@ int _curl(int argc, char *argv[]) {
case 'k':
authmode = MBEDTLS_SSL_VERIFY_NONE;
break;
case 'B':
ciphersuite = MBEDTLS_SSL_PRESET_SUITEB;
break;
case 'h':
PrintUsage(stdout, EXIT_SUCCESS);
PrintUsage(1, 0);
default:
PrintUsage(stderr, EX_USAGE);
PrintUsage(2, 1);
}
}
@ -180,7 +219,10 @@ int _curl(int argc, char *argv[]) {
* Get argument.
*/
const char *urlarg;
if (optind == argc) PrintUsage(stderr, EX_USAGE);
if (optind == argc) {
tinyprint(2, prog, ": missing url\n", NULL);
PrintUsage(2, 1);
}
urlarg = argv[optind];
/*
@ -189,20 +231,20 @@ int _curl(int argc, char *argv[]) {
struct Url url;
char *host, *port;
bool usessl = false;
_gc(ParseUrl(urlarg, -1, &url, kUrlPlus));
_gc(url.params.p);
gc(ParseUrl(urlarg, -1, &url, kUrlPlus));
gc(url.params.p);
if (url.scheme.n) {
if (url.scheme.n == 5 && !memcasecmp(url.scheme.p, "https", 5)) {
usessl = true;
} else if (!(url.scheme.n == 4 && !memcasecmp(url.scheme.p, "http", 4))) {
fprintf(stderr, "error: not an http/https url: %s\n", urlarg);
tinyprint(2, prog, ": not an http/https url: ", urlarg, "\n", NULL);
exit(1);
}
}
if (url.host.n) {
host = _gc(strndup(url.host.p, 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));
port = gc(strndup(url.port.p, url.port.n));
} else {
port = usessl ? "443" : "80";
}
@ -211,7 +253,7 @@ int _curl(int argc, char *argv[]) {
port = usessl ? "443" : "80";
}
if (!IsAcceptableHost(host, -1)) {
fprintf(stderr, "error: invalid host: %s\n", urlarg);
tinyprint(2, prog, ": invalid host: ", urlarg, "\n", NULL);
exit(1);
}
url.fragment.p = 0, url.fragment.n = 0;
@ -221,7 +263,7 @@ int _curl(int argc, char *argv[]) {
url.host.p = 0, url.host.n = 0;
url.port.p = 0, url.port.n = 0;
if (!url.path.n || url.path.p[0] != '/') {
char *p = _gc(xmalloc(1 + url.path.n));
char *p = gc(malloc(1 + url.path.n));
mempcpy(mempcpy(p, "/", 1), url.path.p, url.path.n);
url.path.p = p;
++url.path.n;
@ -230,34 +272,87 @@ int _curl(int argc, char *argv[]) {
/*
* Create HTTP message.
*/
if (!method) method = postdata ? kHttpPost : kHttpGet;
if (!method) {
if (postdata) {
method = kHttpPost;
} else {
method = kHttpGet;
}
}
char *request = 0;
appendf(&request,
"%s %s HTTP/1.1\r\n"
"Connection: close\r\n"
"User-Agent: %s\r\n",
kHttpMethod[method], _gc(EncodeUrl(&url, 0)), agent);
kHttpMethod[method], gc(EncodeUrl(&url, 0)), agent);
bool senthost = false, sentcontenttype = false, sentcontentlength = false;
bool senthost = false;
bool sentcontenttype = false;
bool sentcontentlength = false;
for (int i = 0; i < headers.n; ++i) {
appendf(&request, "%s\r\n", headers.p[i]);
if (!strncasecmp("Host:", headers.p[i], 5))
appends(&request, headers.p[i]);
appends(&request, "\r\n");
if (!strncasecmp("Host:", headers.p[i], 5)) {
senthost = true;
else if (!strncasecmp("Content-Type:", headers.p[i], 13))
} else if (!strncasecmp("Content-Type:", headers.p[i], 13)) {
sentcontenttype = true;
else if (!strncasecmp("Content-Length:", headers.p[i], 15))
} else if (!strncasecmp("Content-Length:", headers.p[i], 15)) {
sentcontentlength = true;
}
}
if (!senthost) {
appends(&request, "Host: ");
appends(&request, host);
appendw(&request, ':');
appends(&request, port);
appends(&request, "\r\n");
}
if (!senthost) appendf(&request, "Host: %s:%s\r\n", host, port);
if (postdata) {
if (!sentcontenttype)
if (!sentcontenttype) {
appends(&request, "Content-Type: application/x-www-form-urlencoded\r\n");
if (!sentcontentlength)
appendf(&request, "Content-Length: %d\r\n", strlen(postdata));
}
if (!sentcontentlength) {
char ibuf[21];
FormatUint64(ibuf, strlen(postdata));
appends(&request, "Content-Length: ");
appends(&request, ibuf);
appends(&request, "\r\n");
}
}
appendf(&request, "\r\n");
if (postdata) appends(&request, postdata);
appends(&request, "\r\n");
if (postdata) {
appends(&request, postdata);
}
/*
* Perform DNS lookup.
*/
struct addrinfo *addr;
struct addrinfo hints = {.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = IPPROTO_TCP,
.ai_flags = AI_NUMERICSERV};
if (getaddrinfo(host, port, &hints, &addr) != EAI_SUCCESS) {
tinyprint(2, prog, ": could not resolve host: ", host, "\n", NULL);
exit(1);
}
/*
* Connect to server.
*/
int ret;
if ((sock = GoodSocket(addr->ai_family, addr->ai_socktype, addr->ai_protocol,
false, &(struct timeval){-60})) == -1) {
perror("socket");
exit(1);
}
if (connect(sock, addr->ai_addr, addr->ai_addrlen)) {
tinyprint(2, prog, ": failed to connect to ", host, " port ", port, ": ",
DescribeErrno(), "\n", NULL);
exit(1);
}
freeaddrinfo(addr);
/*
* Setup crypto.
@ -269,67 +364,58 @@ int _curl(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, "justine", 7));
CHECK_EQ(0, mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT));
_unassert(!mbedtls_ctr_drbg_seed(&drbg, GetSslEntropy, 0, "justine", 7));
_unassert(!mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
ciphersuite));
mbedtls_ssl_conf_authmode(&conf, authmode);
mbedtls_ssl_conf_ca_chain(&conf, GetSslRoots(), 0);
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &drbg);
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));
}
/*
* Perform DNS lookup.
*/
struct addrinfo *addr;
struct addrinfo hints = {.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = IPPROTO_TCP,
.ai_flags = AI_NUMERICSERV};
CHECK_EQ(EAI_SUCCESS, getaddrinfo(host, port, &hints, &addr));
/*
* Connect to server.
*/
int ret;
CHECK_NE(-1, (sock = GoodSocket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol, false,
&(struct timeval){-60})));
CHECK_NE(-1, connect(sock, addr->ai_addr, addr->ai_addrlen));
freeaddrinfo(addr);
if (usessl) {
#ifndef NDEBUG
mbedtls_ssl_conf_dbg(&conf, OnSslDebug, 0);
#endif
_unassert(!mbedtls_ssl_setup(&ssl, &conf));
_unassert(!mbedtls_ssl_set_hostname(&ssl, host));
mbedtls_ssl_set_bio(&ssl, &sock, TlsSend, 0, TlsRecv);
if ((ret = mbedtls_ssl_handshake(&ssl))) {
TlsDie("ssl handshake", ret);
tinyprint(2, prog, ": ssl negotiation with ", host,
" failed: ", DescribeSslClientHandshakeError(&ssl, ret), "\n",
NULL);
exit(1);
}
}
/*
* Send HTTP Message.
*/
size_t n;
ssize_t rc;
size_t i, n;
n = appendz(request).i;
if (usessl) {
ret = mbedtls_ssl_write(&ssl, request, n);
if (ret != n) TlsDie("ssl write", ret);
} else {
CHECK_EQ(n, write(sock, request, n));
for (i = 0; i < n; i += rc) {
if (usessl) {
rc = mbedtls_ssl_write(&ssl, request + i, n - i);
if (rc <= 0) {
tinyprint(2, prog, ": ssl send failed: ", DescribeMbedtlsErrorCode(rc),
"\n", NULL);
exit(1);
}
} else {
rc = write(sock, request + i, n - i);
if (rc <= 0) {
tinyprint(2, prog, ": send failed: ", DescribeErrno(), "\n", NULL);
exit(1);
}
}
}
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
/*
* Handle response.
*/
int t;
char *p;
ssize_t rc;
struct HttpMessage msg;
struct HttpUnchunker u;
size_t g, i, hdrlen, paylen;
size_t g, hdrlen, paylen;
InitHttpMessage(&msg, kHttpResponse);
for (p = 0, hdrlen = paylen = t = i = n = 0;;) {
if (i == n) {
@ -342,25 +428,30 @@ int _curl(int argc, char *argv[]) {
if (rc == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
rc = 0;
} else {
TlsDie("ssl read", rc);
tinyprint(2, prog,
": ssl recv failed: ", DescribeMbedtlsErrorCode(rc), "\n",
NULL);
exit(1);
}
}
} else {
CHECK_NE(-1, (rc = read(sock, p + i, n - i)));
if ((rc = read(sock, p + i, n - i)) == -1) {
tinyprint(2, prog, ": recv failed: ", DescribeErrno(), "\n", NULL);
exit(1);
}
}
g = rc;
i += g;
switch (t) {
case kHttpClientStateHeaders:
CHECK(g);
CHECK_NE(-1, (rc = ParseHttpMessage(&msg, p, i)));
_unassert(g);
if ((rc = ParseHttpMessage(&msg, p, i)) == -1) {
tinyprint(2, prog, ": ", host, " sent bad http message\n", NULL);
exit(1);
}
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);
@ -368,50 +459,65 @@ int _curl(int argc, char *argv[]) {
break;
}
if (method == kHttpHead || includeheaders) {
Write(p, hdrlen);
WriteOutput(p, hdrlen);
}
if (method == kHttpHead || msg.status == 204 || msg.status == 304) {
goto Finished;
}
if (HasHeader(kHttpTransferEncoding) &&
!HeaderEqualCase(kHttpTransferEncoding, "identity")) {
CHECK(HeaderEqualCase(kHttpTransferEncoding, "chunked"));
if (!HeaderEqualCase(kHttpTransferEncoding, "chunked")) {
tinyprint(2, prog, ": ", host,
" sent unsupported transfer encoding\n", NULL);
exit(1);
}
t = kHttpClientStateBodyChunked;
memset(&u, 0, sizeof(u));
goto Chunked;
} else if (HasHeader(kHttpContentLength)) {
CHECK_NE(-1, (rc = ParseContentLength(
HeaderData(kHttpContentLength),
HeaderLength(kHttpContentLength))));
if ((rc = ParseContentLength(HeaderData(kHttpContentLength),
HeaderLength(kHttpContentLength))) ==
-1) {
tinyprint(2, prog, ": ", host, " sent bad content length\n",
NULL);
exit(1);
}
t = kHttpClientStateBodyLengthed;
paylen = rc;
if (paylen > i - hdrlen) {
Write(p + hdrlen, i - hdrlen);
WriteOutput(p + hdrlen, i - hdrlen);
} else {
Write(p + hdrlen, paylen);
WriteOutput(p + hdrlen, paylen);
goto Finished;
}
} else {
t = kHttpClientStateBody;
Write(p + hdrlen, i - hdrlen);
WriteOutput(p + hdrlen, i - hdrlen);
}
}
break;
case kHttpClientStateBody:
WriteOutput(p + i - g, g);
if (!g) goto Finished;
Write(p + i - g, g);
break;
case kHttpClientStateBodyLengthed:
CHECK(g);
if (i - hdrlen > paylen) g = hdrlen + paylen - (i - g);
Write(p + i - g, g);
if (i - hdrlen >= paylen) goto Finished;
_unassert(g);
if (i - hdrlen > paylen) {
g = hdrlen + paylen - (i - g);
}
WriteOutput(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 = Unchunk(&u, p + hdrlen, i - hdrlen, &paylen)) == -1) {
tinyprint(2, prog, ": ", host, " sent bad chunk coding\n", NULL);
exit(1);
}
if (rc) {
Write(p + hdrlen, paylen);
WriteOutput(p + hdrlen, paylen);
goto Finished;
}
break;
@ -424,7 +530,10 @@ int _curl(int argc, char *argv[]) {
* Close connection.
*/
Finished:
CHECK_NE(-1, close(sock));
if (close(sock)) {
tinyprint(2, prog, ": close failed: ", DescribeErrno(), "\n", NULL);
exit(1);
}
/*
* Free memory.

View file

@ -26,7 +26,6 @@ TOOL_CURL_DIRECTDEPS = \
LIBC_STR \
LIBC_SYSV \
LIBC_TIME \
LIBC_X \
LIBC_ZIPOS \
NET_HTTP \
NET_HTTPS \

23
tool/curl/test.sh Executable file
View file

@ -0,0 +1,23 @@
#!/bin/sh
m=zero
make -j16 m=$m o/$m/tool/curl/curl.com || exit
for t in expired \
wrong.host \
self-signed \
untrusted-root \
revoked \
dh480 \
dh512 \
no-common-name \
no-subject \
incomplete-chain \
superfish \
captive-portal \
edellroot \
mitm-software \
rc4; do
u=https://$t.badssl.com/
echo
echo $u
o/$m/tool/curl/curl.com $u
done

View file

@ -77,12 +77,14 @@
#include "libc/str/str.h"
#include "libc/str/strwidth.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/dt.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/hwcap.h"
#include "libc/sysv/consts/inaddr.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/madv.h"
@ -7212,8 +7214,8 @@ static void TlsInit(void) {
int suite;
if (unsecure) return;
if (suiteb && !X86_HAVE(AES)) {
WARNF("(srvr) requested suite b crypto, but aes-ni is not present");
if (suiteb && !mbedtls_aes_uses_hardware()) {
WARNF("(srvr) requested suiteb crypto, but hardware aes not present");
}
if (!sslinitialized) {

View file

@ -3,6 +3,7 @@
.PHONY: o/$(MODE)/tool
o/$(MODE)/tool: \
o/$(MODE)/tool/ape \
o/$(MODE)/tool/args \
o/$(MODE)/tool/build \
o/$(MODE)/tool/curl \

View file

@ -1,24 +1,4 @@
-----BEGIN CERTIFICATE-----
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx

8
usr/share/ssl/root/show.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/sh
for f in usr/share/ssl/root/*.pem; do
echo
echo File: $f
echo
openssl crl2pkcs7 -nocrl -certfile $f |
openssl pkcs7 -print_certs -text -noout
done