Add SSL to redbean

Your redbean can now interoperate with clients that require TLS crypto.
This is accomplished using a protocol polyglot that lets us distinguish
between HTTP and HTTPS regardless of the port number. Certificates will
be generated automatically, if none are supplied by the user. Footprint
increases by only a few hundred kb so redbean in MODY=tiny is now 1.0mb

- Add lseek() polyfills for ZIP executable
- Automatically polyfill /tmp/FOO paths on NT
- Fix readdir() / ftw() / nftw() bugs on Windows
- Introduce -B flag for slower SSL that's stronger
- Remove mbedtls features Cosmopolitan doesn't need
- Have base64 decoder support the uri-safe alternative
- Remove Truncated HMAC because it's forbidden by the IETF
- Add all the mbedtls test suites and make them go 3x faster
- Support opendir() / readdir() / closedir() on ZIP executable
- Use Everest for ECDHE-ECDSA because it's so good it's so good
- Add tinier implementation of sha1 since it's not worth the rom
- Add chi-square monte-carlo mean correlation tests for getrandom()
- Source entropy on Windows from the proper interface everyone uses

We're continuing to outperform NGINX and other servers on raw message
throughput. Using SSL means that instead of 1,000,000 qps you can get
around 300,000 qps. However redbean isn't as fast as NGINX yet at SSL
handshakes, since redbean can do 2,627 per second and NGINX does 4.3k

Right now, the SSL UX story works best if you give your redbean a key
signing key since that can be easily generated by openssl using a one
liner then redbean will do all the things that are impossibly hard to
do like signing ecdsa and rsa certificates that'll work in chrome. We
should integrate the let's encrypt acme protocol in the future.

Live Demo: https://redbean.justine.lol/
Root Cert: https://redbean.justine.lol/redbean1.crt
This commit is contained in:
Justine Tunney 2021-06-24 12:31:26 -07:00
parent 1beeb7a829
commit cc1920749e
1032 changed files with 152673 additions and 69310 deletions

View file

@ -1,335 +0,0 @@
/*-*- 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 2020 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/crypto/rijndael.h"
#include "libc/dce.h"
#include "libc/fmt/bing.internal.h"
#include "libc/runtime/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/prot.h"
#include "libc/testlib/testlib.h"
/**
* Test vectors published by:
*
* Morris Dworkin
* National Institute of Standards and Technology
* Recommendation for Block Cipher Modes of Operation: Methods and Techniques
* SP 800-38A (DOI)
* December 2001
*/
FIXTURE(rijndael, disableHardwareExtensions) {
memset((/*unconst*/ void *)kCpuids, 0, sizeof(kCpuids));
}
/**
* F.1.1: ECB-AES128.Encrypt
*
* Key 2b7e151628aed2a6abf7158809cf4f3c
*
* Block No. 1
* Plaintext 6bc1bee22e409f96e93d7e117393172a
* Input Block 6bc1bee22e409f96e93d7e117393172a
* Output Block 3ad77bb40d7a3660a89ecaf32466ef97
* Ciphertext 3ad77bb40d7a3660a89ecaf32466ef97
*
* Block No. 2
* Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
* Input Block ae2d8a571e03ac9c9eb76fac45af8e51
* Output Block f5d3d58503b9699de785895a96fdbaaf
* Ciphertext f5d3d58503b9699de785895a96fdbaaf
*
* Block No. 3
* Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
* Input Block 30c81c46a35ce411e5fbc1191a0a52ef
* Output Block 43b1cd7f598ece23881b00e3ed030688
* Ciphertext 43b1cd7f598ece23881b00e3ed030688
*
* Block No. 4
* Plaintext f69f2445df4f9b17ad2b417be66c3710
* Input Block f69f2445df4f9b17ad2b417be66c3710
* Output Block 7b0c785e27e8ad3f8223207104725dd4
* Ciphertext 7b0c785e27e8ad3f8223207104725dd4
*/
TEST(aes128, testNistEcbRijndael) {
struct Rijndael ctx;
aes_block_t k1, block;
unhexbuf(&k1, 16, "2b7e151628aed2a6abf7158809cf4f3c");
rijndaelinit(&ctx, 10, k1, k1);
unhexbuf(&block, 16, "6bc1bee22e409f96e93d7e117393172a");
block = rijndael(10, block, &ctx);
EXPECT_BINEQ("3ad77bb40d7a3660a89ecaf32466ef97", &block);
unhexbuf(&block, 16, "ae2d8a571e03ac9c9eb76fac45af8e51");
block = rijndael(10, block, &ctx);
EXPECT_BINEQ("f5d3d58503b9699de785895a96fdbaaf", &block);
unhexbuf(&block, 16, "30c81c46a35ce411e5fbc1191a0a52ef");
block = rijndael(10, block, &ctx);
EXPECT_BINEQ("43b1cd7f598ece23881b00e3ed030688", &block);
unhexbuf(&block, 16, "f69f2445df4f9b17ad2b417be66c3710");
block = rijndael(10, block, &ctx);
EXPECT_BINEQ("7b0c785e27e8ad3f8223207104725dd4", &block);
}
/**
* F.1.2: ECB-AES128.Decrypt
*
* Key 2b7e151628aed2a6abf7158809cf4f3c
*
* Block No. 1
* Plaintext 3ad77bb40d7a3660a89ecaf32466ef97
* Input Block 3ad77bb40d7a3660a89ecaf32466ef97
* Output Block 6bc1bee22e409f96e93d7e117393172a
* Ciphertext 6bc1bee22e409f96e93d7e117393172a
*
* Block No. 2
* Plaintext f5d3d58503b9699de785895a96fdbaaf
* Input Block f5d3d58503b9699de785895a96fdbaaf
* Output Block ae2d8a571e03ac9c9eb76fac45af8e51
* Ciphertext ae2d8a571e03ac9c9eb76fac45af8e51
*
* Block No. 3
* Plaintext 43b1cd7f598ece23881b00e3ed030688
* Input Block 43b1cd7f598ece23881b00e3ed030688
* Output Block 30c81c46a35ce411e5fbc1191a0a52ef
* Ciphertext 30c81c46a35ce411e5fbc1191a0a52ef
*
* Block No. 4
* Plaintext 7b0c785e27e8ad3f8223207104725dd4
* Input Block 7b0c785e27e8ad3f8223207104725dd4
* Output Block f69f2445df4f9b17ad2b417be66c3710
* Ciphertext f69f2445df4f9b17ad2b417be66c3710
*/
TEST(aes128, testNistEcbUnrijndael) {
struct Rijndael ctx;
aes_block_t k1, block;
unhexbuf(&k1, 16, "2b7e151628aed2a6abf7158809cf4f3c");
unrijndaelinit(&ctx, 10, k1, k1);
unhexbuf(&block, 16, "3ad77bb40d7a3660a89ecaf32466ef97");
block = unrijndael(10, block, &ctx);
EXPECT_BINEQ("6bc1bee22e409f96e93d7e117393172a", &block);
unhexbuf(&block, 16, "f5d3d58503b9699de785895a96fdbaaf");
block = unrijndael(10, block, &ctx);
EXPECT_BINEQ("ae2d8a571e03ac9c9eb76fac45af8e51", &block);
unhexbuf(&block, 16, "43b1cd7f598ece23881b00e3ed030688");
block = unrijndael(10, block, &ctx);
EXPECT_BINEQ("30c81c46a35ce411e5fbc1191a0a52ef", &block);
unhexbuf(&block, 16, "7b0c785e27e8ad3f8223207104725dd4");
block = unrijndael(10, block, &ctx);
EXPECT_BINEQ("f69f2445df4f9b17ad2b417be66c3710", &block);
}
/**
* F.1.3: ECB-AES192.Encrypt
*
* Key 8e73b0f7da0e6452c810f32b809079e5
* 62f8ead2522c6b7b
*
* Block No. 1
* Plaintext 6bc1bee22e409f96e93d7e117393172a
* Input Block 6bc1bee22e409f96e93d7e117393172a
* Output Block bd334f1d6e45f25ff712a214571fa5cc
* Ciphertext bd334f1d6e45f25ff712a214571fa5cc
*
* Block No. 2
* Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
* Input Block ae2d8a571e03ac9c9eb76fac45af8e51
* Output Block 974104846d0ad3ad7734ecb3ecee4eef
* Ciphertext 974104846d0ad3ad7734ecb3ecee4eef
*
* Block No. 3
* Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
* Input Block 30c81c46a35ce411e5fbc1191a0a52ef
* Output Block ef7afd2270e2e60adce0ba2face6444e
* Ciphertext ef7afd2270e2e60adce0ba2face6444e
*
* Block No. 4
* Plaintext f69f2445df4f9b17ad2b417be66c3710
* Input Block f69f2445df4f9b17ad2b417be66c3710
* Output Block 9a4b41ba738d6c72fb16691603c18e0e
* Ciphertext 9a4b41ba738d6c72fb16691603c18e0e
*/
TEST(aes192, testNistEcbRijndael) {
struct Rijndael ctx;
aes_block_t k1, k2, block;
unhexbuf(&k1, 16, "8e73b0f7da0e6452c810f32b809079e5");
unhexbuf(&k2, 16, "62f8ead2522c6b7bDEADBEEFFEEDFACE");
rijndaelinit(&ctx, 12, k1, k2);
unhexbuf(&block, 16, "6bc1bee22e409f96e93d7e117393172a");
block = rijndael(12, block, &ctx);
EXPECT_BINEQ("bd334f1d6e45f25ff712a214571fa5cc", &block);
unhexbuf(&block, 16, "ae2d8a571e03ac9c9eb76fac45af8e51");
block = rijndael(12, block, &ctx);
EXPECT_BINEQ("974104846d0ad3ad7734ecb3ecee4eef", &block);
unhexbuf(&block, 16, "30c81c46a35ce411e5fbc1191a0a52ef");
block = rijndael(12, block, &ctx);
EXPECT_BINEQ("ef7afd2270e2e60adce0ba2face6444e", &block);
unhexbuf(&block, 16, "f69f2445df4f9b17ad2b417be66c3710");
block = rijndael(12, block, &ctx);
EXPECT_BINEQ("9a4b41ba738d6c72fb16691603c18e0e", &block);
}
/**
* F.1.4: ECB-AES192.Decrypt
*
* Key 8e73b0f7da0e6452c810f32b809079e5
* 62f8ead2522c6b7b
*
* Block No. 1
* Plaintext bd334f1d6e45f25ff712a214571fa5cc
* Input Block bd334f1d6e45f25ff712a214571fa5cc
* Output Block 6bc1bee22e409f96e93d7e117393172a
* Ciphertext 6bc1bee22e409f96e93d7e117393172a
*
* Block No. 2
* Plaintext 974104846d0ad3ad7734ecb3ecee4eef
* Input Block 974104846d0ad3ad7734ecb3ecee4eef
* Output Block ae2d8a571e03ac9c9eb76fac45af8e51
* Ciphertext ae2d8a571e03ac9c9eb76fac45af8e51
*
* Block No. 3
* Plaintext ef7afd2270e2e60adce0ba2face6444e
* Input Block ef7afd2270e2e60adce0ba2face6444e
* Output Block 30c81c46a35ce411e5fbc1191a0a52ef
* Ciphertext 30c81c46a35ce411e5fbc1191a0a52ef
*
* Block No. 4
* Plaintext 9a4b41ba738d6c72fb16691603c18e0e
* Input Block 9a4b41ba738d6c72fb16691603c18e0e
* Output Block f69f2445df4f9b17ad2b417be66c3710
* Ciphertext f69f2445df4f9b17ad2b417be66c3710
*/
TEST(aes192, testNistEcbUnrijndael) {
struct Rijndael ctx;
aes_block_t k1, k2, block;
unhexbuf(&k1, 16, "8e73b0f7da0e6452c810f32b809079e5");
unhexbuf(&k2, 16, "62f8ead2522c6b7bDEADBEEFFEEDFACE");
unrijndaelinit(&ctx, 12, k1, k2);
unhexbuf(&block, 16, "bd334f1d6e45f25ff712a214571fa5cc");
block = unrijndael(12, block, &ctx);
EXPECT_BINEQ("6bc1bee22e409f96e93d7e117393172a", &block);
unhexbuf(&block, 16, "974104846d0ad3ad7734ecb3ecee4eef");
block = unrijndael(12, block, &ctx);
EXPECT_BINEQ("ae2d8a571e03ac9c9eb76fac45af8e51", &block);
unhexbuf(&block, 16, "ef7afd2270e2e60adce0ba2face6444e");
block = unrijndael(12, block, &ctx);
EXPECT_BINEQ("30c81c46a35ce411e5fbc1191a0a52ef", &block);
unhexbuf(&block, 16, "9a4b41ba738d6c72fb16691603c18e0e");
block = unrijndael(12, block, &ctx);
EXPECT_BINEQ("f69f2445df4f9b17ad2b417be66c3710", &block);
}
/**
* F.1.5: ECB-AES256.Encrypt
*
* Key 603deb1015ca71be2b73aef0857d7781
* 1f352c073b6108d72d9810a30914dff4
*
* Block No. 1
* Plaintext 6bc1bee22e409f96e93d7e117393172a
* Input Block 6bc1bee22e409f96e93d7e117393172a
* Output Block f3eed1bdb5d2a03c064b5a7e3db181f8
* Ciphertext f3eed1bdb5d2a03c064b5a7e3db181f8
*
* Block No. 2
* Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
* Input Block ae2d8a571e03ac9c9eb76fac45af8e51
* Output Block 591ccb10d410ed26dc5ba74a31362870
* Ciphertext 591ccb10d410ed26dc5ba74a31362870
*
* Block No. 3
* Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
* Input Block 30c81c46a35ce411e5fbc1191a0a52ef
* Output Block b6ed21b99ca6f4f9f153e7b1beafed1d
* Ciphertext b6ed21b99ca6f4f9f153e7b1beafed1d
*
* Block No. 4
* Plaintext f69f2445df4f9b17ad2b417be66c3710
* Input Block f69f2445df4f9b17ad2b417be66c3710
* Output Block 23304b7a39f9f3ff067d8d8f9e24ecc7
* Ciphertext 23304b7a39f9f3ff067d8d8f9e24ecc7
*/
TEST(aes256, testNistEcbRijndael) {
struct Rijndael ctx;
aes_block_t k1, k2, block;
unhexbuf(&k1, 16, "603deb1015ca71be2b73aef0857d7781");
unhexbuf(&k2, 16, "1f352c073b6108d72d9810a30914dff4");
rijndaelinit(&ctx, 14, k1, k2);
unhexbuf(&block, 16, "6bc1bee22e409f96e93d7e117393172a");
block = rijndael(14, block, &ctx);
EXPECT_BINEQ("f3eed1bdb5d2a03c064b5a7e3db181f8", &block);
unhexbuf(&block, 16, "ae2d8a571e03ac9c9eb76fac45af8e51");
block = rijndael(14, block, &ctx);
EXPECT_BINEQ("591ccb10d410ed26dc5ba74a31362870", &block);
unhexbuf(&block, 16, "30c81c46a35ce411e5fbc1191a0a52ef");
block = rijndael(14, block, &ctx);
EXPECT_BINEQ("b6ed21b99ca6f4f9f153e7b1beafed1d", &block);
unhexbuf(&block, 16, "f69f2445df4f9b17ad2b417be66c3710");
block = rijndael(14, block, &ctx);
EXPECT_BINEQ("23304b7a39f9f3ff067d8d8f9e24ecc7", &block);
}
/**
* F.1.6: ECB-AES256.Decrypt
*
* Key 603deb1015ca71be2b73aef0857d7781
* 1f352c073b6108d72d9810a30914dff4
*
* Block No. 1
* Input Block f3eed1bdb5d2a03c064b5a7e3db181f8
* Plaintext f3eed1bdb5d2a03c064b5a7e3db181f8
* Ciphertext 6bc1bee22e409f96e93d7e117393172a
* Output Block 6bc1bee22e409f96e93d7e117393172a
*
* Block No. 2
* Input Block 591ccb10d410ed26dc5ba74a31362870
* Plaintext 591ccb10d410ed26dc5ba74a31362870
* Ciphertext ae2d8a571e03ac9c9eb76fac45af8e51
* Output Block ae2d8a571e03ac9c9eb76fac45af8e51
*
* Block No. 3
* Input Block b6ed21b99ca6f4f9f153e7b1beafed1d
* Plaintext b6ed21b99ca6f4f9f153e7b1beafed1d
* Ciphertext 30c81c46a35ce411e5fbc1191a0a52ef
* Output Block 30c81c46a35ce411e5fbc1191a0a52ef
*
* Block No. 4
* Input Block 23304b7a39f9f3ff067d8d8f9e24ecc7
* Plaintext 23304b7a39f9f3ff067d8d8f9e24ecc7
* Ciphertext f69f2445df4f9b17ad2b417be66c3710
* Output Block f69f2445df4f9b17ad2b417be66c3710
*/
TEST(aes256, testNistEcbUnrijndael) {
struct Rijndael ctx;
aes_block_t k1, k2, block;
unhexbuf(&k1, 16, "603deb1015ca71be2b73aef0857d7781");
unhexbuf(&k2, 16, "1f352c073b6108d72d9810a30914dff4");
unrijndaelinit(&ctx, 14, k1, k2);
unhexbuf(&block, 16, "f3eed1bdb5d2a03c064b5a7e3db181f8");
block = unrijndael(14, block, &ctx);
EXPECT_BINEQ("6bc1bee22e409f96e93d7e117393172a", &block);
unhexbuf(&block, 16, "591ccb10d410ed26dc5ba74a31362870");
block = unrijndael(14, block, &ctx);
EXPECT_BINEQ("ae2d8a571e03ac9c9eb76fac45af8e51", &block);
unhexbuf(&block, 16, "b6ed21b99ca6f4f9f153e7b1beafed1d");
block = unrijndael(14, block, &ctx);
EXPECT_BINEQ("30c81c46a35ce411e5fbc1191a0a52ef", &block);
unhexbuf(&block, 16, "23304b7a39f9f3ff067d8d8f9e24ecc7");
block = unrijndael(14, block, &ctx);
EXPECT_BINEQ("f69f2445df4f9b17ad2b417be66c3710", &block);
}

View file

@ -1,52 +0,0 @@
#-*-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 += TEST_LIBC_CRYPTO
TEST_LIBC_CRYPTO_SRCS := $(wildcard test/libc/crypto/*.c)
TEST_LIBC_CRYPTO_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_CRYPTO_SRCS))
TEST_LIBC_CRYPTO_COMS = $(TEST_LIBC_CRYPTO_OBJS:%.o=%.com)
TEST_LIBC_CRYPTO_OBJS = \
$(TEST_LIBC_CRYPTO_SRCS:%.c=o/$(MODE)/%.o)
TEST_LIBC_CRYPTO_BINS = \
$(TEST_LIBC_CRYPTO_COMS) \
$(TEST_LIBC_CRYPTO_COMS:%=%.dbg)
TEST_LIBC_CRYPTO_TESTS = \
$(TEST_LIBC_CRYPTO_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)
TEST_LIBC_CRYPTO_CHECKS = \
$(TEST_LIBC_CRYPTO_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
TEST_LIBC_CRYPTO_DIRECTDEPS = \
LIBC_CRYPTO \
LIBC_FMT \
LIBC_INTRIN \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \
LIBC_TESTLIB
TEST_LIBC_CRYPTO_DEPS := \
$(call uniq,$(foreach x,$(TEST_LIBC_CRYPTO_DIRECTDEPS),$($(x))))
o/$(MODE)/test/libc/crypto/crypto.pkg: \
$(TEST_LIBC_CRYPTO_OBJS) \
$(foreach x,$(TEST_LIBC_CRYPTO_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/test/libc/crypto/%.com.dbg: \
$(TEST_LIBC_CRYPTO_DEPS) \
o/$(MODE)/test/libc/crypto/%.o \
o/$(MODE)/test/libc/crypto/crypto.pkg \
$(LIBC_TESTMAIN) \
$(CRT) \
$(APE)
@$(APELINK)
.PHONY: o/$(MODE)/test/libc/crypto
o/$(MODE)/test/libc/crypto: \
$(TEST_LIBC_CRYPTO_BINS) \
$(TEST_LIBC_CRYPTO_CHECKS)

View file

@ -48,20 +48,19 @@ TEST(ParseHostsTxt, testCorrectlyTokenizesAndSorts) {
ASSERT_EQ(1, fwrite(kInput, strlen(kInput), 1, f));
rewind(f);
ASSERT_EQ(0, ParseHostsTxt(ht, f));
SortHostsTxt(ht);
ASSERT_EQ(4, ht->entries.i);
EXPECT_STREQ("cat.example.", &ht->strings.p[ht->entries.p[0].name]);
EXPECT_STREQ("cat.example.", &ht->strings.p[ht->entries.p[0].canon]);
EXPECT_STREQ("203.0.113.2", ParseIp(ht->entries.p[0].ip));
EXPECT_STREQ("lol.example.", &ht->strings.p[ht->entries.p[1].name]);
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("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("cat", &ht->strings.p[ht->entries.p[2].name]);
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("lol", &ht->strings.p[ht->entries.p[3].name]);
EXPECT_STREQ("lol.example.", &ht->strings.p[ht->entries.p[3].canon]);
EXPECT_STREQ("203.0.113.1", ParseIp(ht->entries.p[3].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));
FreeHostsTxt(&ht);
fclose(f);
}

View file

@ -0,0 +1,77 @@
/*-*- 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/dns/hoststxt.h"
#include "libc/sysv/consts/af.h"
#include "libc/testlib/testlib.h"
TEST(ParseHostsTxt, testNotFound) {
const char kInput[] = "# this is a comment\n"
"# IP HOST1 HOST2\n"
"203.0.113.1 lol.example lol\n"
"203.0.113.2 cat.example cat\n";
char name[256];
uint8_t ip[4] = {127, 0, 113, 1};
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
FILE *f = fmemopen(NULL, BUFSIZ, "r+");
ASSERT_EQ(1, fwrite(kInput, strlen(kInput), 1, f));
rewind(f);
ASSERT_EQ(0, ParseHostsTxt(ht, f));
ASSERT_EQ(4, ht->entries.i);
ASSERT_EQ(0, ResolveHostsReverse(ht, AF_INET, ip, name, sizeof(name)));
FreeHostsTxt(&ht);
fclose(f);
}
TEST(ParseHostsTxt, testFirstLookup) {
const char kInput[] = "# this is a comment\n"
"# IP HOST1 HOST2\n"
"203.0.113.1 lol.example lol\n"
"203.0.113.2 cat.example cat\n";
char name[256];
uint8_t ip[4] = {203, 0, 113, 1};
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
FILE *f = fmemopen(NULL, BUFSIZ, "r+");
ASSERT_EQ(1, fwrite(kInput, strlen(kInput), 1, f));
rewind(f);
ASSERT_EQ(0, ParseHostsTxt(ht, f));
ASSERT_EQ(4, ht->entries.i);
ASSERT_EQ(1, ResolveHostsReverse(ht, AF_INET, ip, name, sizeof(name)));
EXPECT_STREQ("lol.example", name);
FreeHostsTxt(&ht);
fclose(f);
}
TEST(ParseHostsTxt, testSecondLookup) {
const char kInput[] = "# this is a comment\n"
"# IP HOST1 HOST2\n"
"203.0.113.1 lol.example lol\n"
"203.0.113.2 cat.example cat\n";
char name[256];
uint8_t ip[4] = {203, 0, 113, 2};
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
FILE *f = fmemopen(NULL, BUFSIZ, "r+");
ASSERT_EQ(1, fwrite(kInput, strlen(kInput), 1, f));
rewind(f);
ASSERT_EQ(0, ParseHostsTxt(ht, f));
ASSERT_EQ(4, ht->entries.i);
ASSERT_EQ(1, ResolveHostsReverse(ht, AF_INET, ip, name, sizeof(name)));
EXPECT_STREQ("cat.example", name);
FreeHostsTxt(&ht);
fclose(f);
}

View file

@ -49,7 +49,6 @@ TEST(ResolveHostsTxt, testBasicLookups) {
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
FILE *f = fmemopen(kInput, strlen(kInput), "r+");
ASSERT_EQ(0, ParseHostsTxt(ht, f));
SortHostsTxt(ht);
ASSERT_EQ(5, ht->entries.i);
EXPECT_STREQ("127.0.0.1", EzIp4Lookup(ht, "localhost"));
EXPECT_STREQ("203.0.113.1", EzIp4Lookup(ht, "lol"));
@ -66,7 +65,6 @@ TEST(ResolveHostsTxt, testCanonicalize) {
struct HostsTxt *ht = calloc(1, sizeof(struct HostsTxt));
FILE *f = fmemopen(kInput, strlen(kInput), "r+");
ASSERT_EQ(0, ParseHostsTxt(ht, f));
SortHostsTxt(ht);
ASSERT_EQ(5, ht->entries.i);
EXPECT_STREQ("localhost", EzCanonicalize(ht, "localhost"));
EXPECT_STREQ("lol.example.", EzCanonicalize(ht, "lol"));

View file

@ -22,18 +22,12 @@
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
TEST(devrand, test) {
if (IsWindows()) return;
const size_t kSize = 8;
void *A = malloc(kSize);
void *B = malloc(kSize);
memset(A, 0, kSize);
memset(B, 0, kSize);
EXPECT_EQ(0, devrand(A, kSize));
EXPECT_EQ(0, devrand(B, kSize));
TEST(getrandom, test) {
void *A = gc(calloc(1, 8));
void *B = gc(calloc(1, 8));
EXPECT_EQ(8, getrandom(A, 8, 0));
EXPECT_EQ(8, getrandom(B, 8, 0));
EXPECT_BINNE(u"        ", A);
EXPECT_BINNE(u"        ", B);
EXPECT_NE(0, memcmp(A, B, kSize));
free(B);
free(A);
EXPECT_NE(0, memcmp(A, B, 8));
}

View file

@ -0,0 +1,237 @@
/*-*- 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/log/check.h"
#include "libc/math.h"
#include "libc/rand/lcg.internal.h"
#include "libc/rand/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/grnd.h"
#include "libc/testlib/testlib.h"
/* JustReturnZero */
/* entropy: 0 */
/* chi-square: 2.55e+07 */
/* chi-square percent: 0 */
/* mean: 0 */
/* monte-carlo-pi: 27.324 */
/* serial-correlation: -100000 */
/* JustIncrement */
/* entropy: 2.63951 */
/* chi-square: 1.443e+07 */
/* chi-square percent: 0 */
/* mean: 18.8803 */
/* monte-carlo-pi: 27.324 */
/* serial-correlation: 0.0092003 */
/* UNIX Sixth Edition */
/* entropy: 8 */
/* chi-square: 0.1536 */
/* chi-square percent: 1 */
/* mean: 127.502 */
/* monte-carlo-pi: 3.4192 */
/* serial-correlation: -0.470645 */
/* UNIX Seventh Edition */
/* entropy: 7.99818 */
/* chi-square: 251.843 */
/* chi-square percent: 0.544128 */
/* mean: 127.955 */
/* monte-carlo-pi: 0.675703 */
/* serial-correlation: -0.00207669 */
/* KnuthLcg */
/* entropy: 7.99835 */
/* chi-square: 228.383 */
/* chi-square percent: 0.883476 */
/* mean: 127.1 */
/* monte-carlo-pi: 0.561935 */
/* serial-correlation: -0.0038954 */
/* rand64 */
/* entropy: 7.99832 */
/* chi-square: 233.267 */
/* chi-square percent: 0.831821 */
/* mean: 127.427 */
/* monte-carlo-pi: 0.0271532 */
/* serial-correlation: -0.00255319 */
/* Rand64LowByte */
/* entropy: 7.99798 */
/* chi-square: 278.344 */
/* chi-square percent: 0.150796 */
/* mean: 127.88 */
/* monte-carlo-pi: 0.00340573 */
/* serial-correlation: 0.00162231 */
/* GetRandomNoSystem */
/* entropy: 7.99819 */
/* chi-square: 249.743 */
/* chi-square percent: 0.58114 */
/* mean: 127.124 */
/* monte-carlo-pi: 0.293716 */
/* serial-correlation: 0.00198516 */
/* GetRandomNoRdrrnd */
/* entropy: 7.99816 */
/* chi-square: 254.797 */
/* chi-square percent: 0.491811 */
/* mean: 127.308 */
/* monte-carlo-pi: 0.0118738 */
/* serial-correlation: 0.000197669 */
/* GetRandom */
/* entropy: 7.99808 */
/* chi-square: 266.737 */
/* chi-square percent: 0.294131 */
/* mean: 127.178 */
/* monte-carlo-pi: 0.0577122 */
/* serial-correlation: 0.00598793 */
typedef uint64_t (*random_f)(void);
static uint32_t randx = 1;
uint64_t JustReturnZero(void) {
return 0;
}
uint64_t JustIncrement(void) {
static uint64_t x;
return x++;
}
uint16_t SixthEditionRand(void) {
static int16_t gorp;
gorp = (gorp + 625) & 077777;
return gorp;
}
uint64_t SixthEditionLowByte(void) {
unsigned i;
uint64_t x;
for (x = i = 0; i < 8; ++i) {
x <<= 8;
x |= SixthEditionRand() & 255;
}
return x;
}
uint32_t SeventhEditionRand(void) {
return ((randx = randx * 1103515245 + 12345) >> 16) & 077777;
}
uint64_t SeventhEditionLowByte(void) {
unsigned i;
uint64_t x;
for (x = i = 0; i < 8; ++i) {
x <<= 8;
x |= SeventhEditionRand() & 255;
}
return x;
}
uint64_t KnuthLcg(void) {
unsigned i;
uint64_t x;
for (x = i = 0; i < 8; ++i) {
x <<= 8;
x |= rand() & 255;
}
return x;
}
uint64_t Rand64LowByte(void) {
unsigned i;
uint64_t x;
for (x = i = 0; i < 8; ++i) {
x <<= 8;
x |= rand64() & 255;
}
return x;
}
uint64_t GetRandomNoRdrrnd(void) {
uint64_t x;
ASSERT_EQ(8, getrandom(&x, 8, GRND_NORDRND));
return x;
}
uint64_t GetRandomNoSystem(void) {
uint64_t x;
ASSERT_EQ(8, getrandom(&x, 8, GRND_NOSYSTEM));
return x;
}
uint64_t GetRandom(void) {
uint64_t x;
ASSERT_EQ(8, getrandom(&x, 8, 0));
return x;
}
static const struct RandomFunction {
const char *s;
random_f f;
bool r;
} kRandomFunctions[] = {
{"JustReturnZero", JustReturnZero, false}, //
{"JustIncrement", JustIncrement, false}, //
{"SixthEditionLowByte", SixthEditionLowByte, false}, //
{"SeventhEditionLowByte", SeventhEditionLowByte, false}, //
{"KnuthLcg", KnuthLcg, false}, //
{"rand64", rand64, true}, //
{"Rand64LowByte", Rand64LowByte, true}, //
{"GetRandomNoRdrrnd", GetRandomNoRdrrnd, true}, //
{"GetRandomNoSystem", GetRandomNoSystem, true}, //
{"GetRandom", GetRandom, true}, //
};
TEST(getrandom, sanityTest) {
uint64_t q;
size_t i, j, k;
double montepi, chip, scc, ent, mean, chisq;
for (k = 0; k < 1; ++k) {
for (j = 0; j < ARRAYLEN(kRandomFunctions); ++j) {
rt_init(0);
for (i = 0; i + 8 <= 100000; i += 8) {
q = kRandomFunctions[j].f();
rt_add(&q, 8);
}
rt_end(&ent, &chisq, &mean, &montepi, &scc);
chip = pochisq(chisq, 255);
#if 0
fprintf(stderr, "\n");
fprintf(stderr, "/* %-32s */\n", kRandomFunctions[j].s);
fprintf(stderr, "/* entropy: %-12g */\n", ent);
fprintf(stderr, "/* chi-square: %-12g */\n", chisq);
fprintf(stderr, "/* chi-square percent: %-12g */\n", chip);
fprintf(stderr, "/* mean: %-12g */\n", mean);
fprintf(stderr, "/* monte-carlo-pi: %-12g */\n",
100 * fabs(M_PI - montepi) / M_PI);
fprintf(stderr, "/* serial-correlation: %-12g */\n", scc);
#endif
if (kRandomFunctions[j].r) {
CHECK_GE(chisq, 180, "%s", kRandomFunctions[j].s);
CHECK_GE(ent * 10, 78, "%s", kRandomFunctions[j].s);
CHECK_LT(fabs(scc) * 100, 5, "%s", kRandomFunctions[j].s);
CHECK_LT(fabs(128 - mean), 3, "%s", kRandomFunctions[j].s);
}
}
}
}

View file

@ -16,7 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/rand/rand.h"
#include "libc/testlib/hyperion.h"
#include "libc/testlib/testlib.h"
TEST(rand002, alwaysReturnsPositiveNumbers) {
@ -34,11 +36,18 @@ TEST(rand003, srandSmokeTest) {
ASSERT_EQ(1059165278, rand());
}
TEST(rand004, rand32SmokeTest) {
ASSERT_TRUE(rand32() != rand32() || rand32() != rand32() ||
rand32() != rand32() || rand32() != rand32());
}
TEST(rand005, rand64SmokeTest) {
ASSERT_TRUE(rand64() != rand64() || rand64() != rand64());
}
TEST(rand64, test) {
char *p;
size_t i;
uint64_t x;
p = memcpy(malloc(kHyperionSize), kHyperion, kHyperionSize);
for (i = 0; i < kHyperionSize / 8; ++i) {
x = rand64();
WRITE64LE(p + i * 8, x);
}
free(p);
}

View file

@ -21,15 +21,20 @@ TEST_LIBC_RAND_CHECKS = \
TEST_LIBC_RAND_DIRECTDEPS = \
LIBC_FMT \
LIBC_INTRIN \
LIBC_TINYMATH \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RAND \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_STR \
LIBC_STUBS \
LIBC_LOG \
LIBC_SYSV \
LIBC_TESTLIB \
LIBC_X
LIBC_UNICODE \
LIBC_X \
THIRD_PARTY_GDTOA
TEST_LIBC_RAND_DEPS := \
$(call uniq,$(foreach x,$(TEST_LIBC_RAND_DIRECTDEPS),$($(x))))

View file

@ -54,3 +54,47 @@ TEST(inet_ntop, testNoSpace) {
ASSERT_STREQ("", buf);
free(buf);
}
TEST(inet_ntop, ipv6_testMin_isJustColons) {
char buf[72];
uint8_t ip[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
EXPECT_STREQ("::", inet_ntop(AF_INET6, ip, buf, sizeof(buf)));
}
TEST(inet_ntop, ipv6_testMax) {
char buf[72];
uint8_t ip[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
EXPECT_STREQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
inet_ntop(AF_INET6, ip, buf, sizeof(buf)));
}
TEST(inet_ntop, ipv6_loopback_isColonsThenJustOne) {
char buf[72];
uint8_t ip[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
EXPECT_STREQ("::1", inet_ntop(AF_INET6, ip, buf, sizeof(buf)));
}
TEST(inet_ntop, ipv6_rfc4291example) {
char buf[72];
uint8_t ip[16] = {0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x08, 0x00, 0x20, 0x0C, 0x41, 0x7A};
EXPECT_STREQ("2001:db8::8:800:200c:417a",
inet_ntop(AF_INET6, ip, buf, sizeof(buf)));
}
TEST(inet_ntop, ipv6_leading) {
char buf[72];
uint8_t ip[16] = {0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
EXPECT_STREQ("1::", inet_ntop(AF_INET6, ip, buf, sizeof(buf)));
}
TEST(inet_ntop, ipv6_kindOfLeading) {
char buf[72];
uint8_t ip[16] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
EXPECT_STREQ("100::", inet_ntop(AF_INET6, ip, buf, sizeof(buf)));
}

View file

@ -31,6 +31,15 @@ TEST(inet_pton, testLocalhost) {
EXPECT_EQ(1, addr[3]);
}
TEST(inet_pton, testAny) {
uint8_t addr[4] = {255, 255, 255, 255};
EXPECT_EQ(1, inet_pton(AF_INET, "0.0.0.0", &addr));
EXPECT_EQ(0, addr[0]);
EXPECT_EQ(0, addr[1]);
EXPECT_EQ(0, addr[2]);
EXPECT_EQ(0, addr[3]);
}
TEST(inet_pton, testShortAddress_doesntFillFullValue) {
uint8_t addr[4] = {255, 255, 255, 255};
EXPECT_EQ(0, inet_pton(AF_INET, "127.0.0", &addr));

View file

@ -25,17 +25,18 @@
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
STATIC_YOINK("zip_uri_support");
TEST(dirstream, test) {
DIR *dir;
struct dirent *ent;
char *dpath, *file1, *file2;
dpath = gc(xasprintf("%s%s%lu", kTmpPath, "dirstream", rand32()));
dpath = gc(xasprintf("%s%s%lu", kTmpPath, "dirstream", rand64()));
file1 = gc(xasprintf("%s/%s", dpath, "foo"));
file2 = gc(xasprintf("%s/%s", dpath, "bar"));
EXPECT_NE(-1, mkdir(dpath, 0755));
EXPECT_NE(-1, touch(file1, 0644));
EXPECT_NE(-1, touch(file2, 0644));
EXPECT_TRUE(NULL != (dir = opendir(dpath)));
bool hasfoo = false;
bool hasbar = false;
@ -46,8 +47,21 @@ TEST(dirstream, test) {
EXPECT_TRUE(hasfoo);
EXPECT_TRUE(hasbar);
EXPECT_NE(-1, closedir(dir));
EXPECT_NE(-1, unlink(file2));
EXPECT_NE(-1, unlink(file1));
EXPECT_NE(-1, rmdir(dpath));
}
TEST(dirstream, zipTest) {
bool foundNewYork = false;
DIR *d;
struct dirent *e;
const char *path = "zip:usr/share/zoneinfo/";
ASSERT_NE(0, _gc(xiso8601ts(NULL)));
ASSERT_NE(NULL, (d = opendir(path)));
while ((e = readdir(d))) {
foundNewYork |= !strcmp(e->d_name, "New_York");
}
closedir(d);
EXPECT_TRUE(foundNewYork);
}

View file

@ -36,8 +36,10 @@ TEST_LIBC_STDIO_DIRECTDEPS = \
LIBC_STUBS \
LIBC_SYSV \
LIBC_TESTLIB \
LIBC_TIME \
LIBC_UNICODE \
LIBC_X
LIBC_X \
LIBC_ZIPOS
TEST_LIBC_STDIO_DEPS := \
$(call uniq,$(foreach x,$(TEST_LIBC_STDIO_DIRECTDEPS),$($(x))))

View file

@ -40,6 +40,7 @@ TEST_LIBC_STR_DIRECTDEPS = \
LIBC_UNICODE \
LIBC_X \
LIBC_ZIPOS \
THIRD_PARTY_MBEDTLS \
THIRD_PARTY_REGEX \
THIRD_PARTY_ZLIB

View file

@ -6,7 +6,6 @@ o/$(MODE)/test/libc: \
o/$(MODE)/test/libc/alg \
o/$(MODE)/test/libc/bits \
o/$(MODE)/test/libc/calls \
o/$(MODE)/test/libc/crypto \
o/$(MODE)/test/libc/dns \
o/$(MODE)/test/libc/fmt \
o/$(MODE)/test/libc/intrin \