BearSSL is Thomas Pornin’s full TLS 1.0-1.2 stack in portable
C99: no malloc, no asm, no external deps. The vendored set
under demos/bearssl/ is a curated subset (hash + MAC + KDF
primitives plus the codec / int helpers they pull in); the
full upstream tree carries ~300 .c files including AES
hardware-accelerated variants (aes_x86ni, aes_pwr8), the
TLS record-layer state machines, and an X.509 minimal
validator.
Pinned at upstream’s 0.6 release. Pulled through the badc
vendor-deps mirror – see setup.py.
smoke.py builds the focused BearSSL set + a
hand-written driver through badc in four flavours (amalgamation
-O and no--O), plus an
archive flavour, and runs each binary. Four scenarios:| Scenario | What it asserts |
|---|---|
SHA-256("abc") |
FIPS 180-2 / RFC 4634 vector: digest matches the published 32-byte answer. |
SHA-224("abc") |
FIPS 180-2 vector: 28-byte digest matches the published answer. |
| HMAC-SHA-256 (RFC 4231) | Test case 1: 20-byte key (0x0b * 20), message "Hi There", 32-byte MAC matches the published value. |
| HKDF-SHA-256 (RFC 5869) | Test case 1: 42-byte OKM derived from the published IKM / salt / info matches the reference bit-for-bit. |
Already-closed gaps that the BearSSL bringup surfaced:
((ULONG_MAX >> 31) >> 31) == 3 (BearSSL’s 64-bit host
probe in src/inner.h) requires (a) parsing the bare
18446744073709551615 literal in a #if expression and (b)
using logical right shift on bit-pattern values. Regression:
preprocessor_uint64_literal.c.&func in static initializers (C99 6.3.2.1p4).
Upstream BearSSL spells vtable entries as
(void (*)(...))&br_sha224_init. The bare-identifier form
was already accepted; the &-prefixed form now routes
through the same code-reloc path.extern const T v; allocates storage at sym.val;
any in-TU code emitted before the defining const T v = { ... };
bakes that offset into its machine code. The merge must REUSE that
storage so the defining initializer lands at the same offset.
Deferred-size array externs (extern T x[];) still allocate
fresh because the extern path leaves them without storage.
Regression: extern_decl_then_define.c.setup.py – fetch the vendored tar.gz from the badc
vendor-deps release and extract the curated subset
(inc/*, src/inner.h, src/config.h, the hash / mac /
kdf / codec / int .c files); idempotent.inc/*.h, src/**/*.c, src/inner.h, src/config.h –
vendored upstream (gitignored out of band; setup.py is
the source of truth for what they are).