blob: 614978fc2cf631bb7e2357c57ceba6e28a4aca7a [file] [edit]
# syntax=docker/dockerfile:1
#
# CI base image for LibJWT: debian:forky with every backend usable.
#
# * OpenSSL - from forky apt (3.6.x, >= 3.5 so the OpenSSL ML-DSA path works)
# * GnuTLS - built FROM SOURCE --with-leancrypto so the ML-DSA
# (FIPS 204 / RFC 9964, kty="AKP") SUCCESS path works
# * leancrypto - built FROM SOURCE; the PQC provider GnuTLS links against
# * MbedTLS - built FROM SOURCE (3.6.x LTS, the tested baseline; the
# PSA-based backend also builds against MbedTLS 4.x)
# * jansson + json-c - both JSON backends, from apt
# * libcurl, check, bats, jq, lcov, valgrind - from apt
#
# Only the three components that genuinely need a custom/newer build are built
# from source; every build-dependency comes from native Debian apt.
#
# We deliberately do NOT install forky's libgnutls28-dev or libmbedtls-dev:
# their gnutls.pc / mbedcrypto.pc under /usr/lib/<triplet>/pkgconfig would
# shadow our from-source .pc files and make CMake link the apt (no-leancrypto)
# libraries instead of ours. forky's apt GnuTLS is *also* 3.8.13, so the only
# reliable discriminator is the install prefix (/usr/local) + ML-DSA capability.
#
# Published at: ghcr.io/benmcollins/libjwt/gnutls-leancrypto-mbedtls
# Rebuilt by: .github/workflows/ci-image.yml
#
FROM debian:forky
LABEL org.opencontainers.image.source="https://github.com/benmcollins/libjwt"
LABEL org.opencontainers.image.description="LibJWT CI base: debian:forky + OpenSSL (apt), GnuTLS built --with-leancrypto (ML-DSA success path), MbedTLS 3.6.x LTS from source, jansson + json-c, libcurl, check, bats, jq, lcov, valgrind."
LABEL org.opencontainers.image.licenses="MPL-2.0"
# ---- Pinned from-source versions (confirmed latest as of 2026-06-16) --------
ARG LEANCRYPTO_VERSION=v1.7.2
ARG GNUTLS_VERSION=3.8.13
ARG MBEDTLS_VERSION=3.6.6
# GnuTLS tarballs are laid out by major.minor; keep this in sync with the
# major.minor of GNUTLS_VERSION when bumping.
ARG GNUTLS_SERIES=v3.8
ENV DEBIAN_FRONTEND=noninteractive \
LC_ALL=C.UTF-8 \
LANG=C.UTF-8
# All three from-source installs use --libdir=lib, so their .pc files land in
# /usr/local/lib/pkgconfig and their .so files in /usr/local/lib (NOT Debian's
# multiarch lib/<triplet>). That keeps discovery arch-agnostic: this same
# Dockerfile builds correctly on amd64 and arm64. The apt deps' .pc files live
# on pkg-config's default system search path and need no help here.
ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
# ---------------------------------------------------------------------------
# 1. apt dependencies: libjwt's own build/test deps + everything needed to
# compile leancrypto, GnuTLS, and MbedTLS from source (all build-deps from
# native Debian). NOTE: libgnutls28-dev and libmbedtls-dev are intentionally
# absent so their apt .pc files cannot shadow our from-source ones.
# ---------------------------------------------------------------------------
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates git curl xz-utils \
build-essential cmake pkg-config \
gettext autoconf automake libtool \
meson ninja-build nasm \
python3 python3-jinja2 python3-jsonschema perl \
nettle-dev libgmp-dev libtasn1-6-dev libidn2-dev libunistring-dev zlib1g-dev \
libssl-dev libjansson-dev libjson-c-dev libcurl4-openssl-dev \
check bats jq lcov valgrind; \
rm -rf /var/lib/apt/lists/*
# Search /usr/local/lib first at run time so our from-source GnuTLS/MbedTLS/
# leancrypto win over any apt-provided copy.
RUN set -eux; \
echo '/usr/local/lib' > /etc/ld.so.conf.d/000-usrlocal.conf; \
ldconfig
# ---------------------------------------------------------------------------
# 2. leancrypto (PQC provider) -> /usr/local
# -Ddefault_library=both: GnuTLS STATIC-links the provider (no dlopen), so a
# static archive must exist; the shared lib is kept for completeness.
# --libdir=lib puts leancrypto.pc on the default pkg-config path.
# -Dtests=disabled skips the (large) test-binary suite we don't need; the
# algorithm self-tests (enable_selftests, default on) stay enabled.
# ---------------------------------------------------------------------------
RUN set -eux; \
git clone --depth 1 --branch "${LEANCRYPTO_VERSION}" \
https://github.com/smuellerDD/leancrypto.git /tmp/leancrypto; \
meson setup /tmp/leancrypto/build /tmp/leancrypto \
--prefix=/usr/local --libdir=lib --buildtype=release \
-Ddefault_library=both -Dtests=disabled; \
meson compile -C /tmp/leancrypto/build; \
meson install -C /tmp/leancrypto/build; \
ldconfig; \
pkg-config --exists leancrypto; \
echo "leancrypto $(pkg-config --modversion leancrypto) installed"; \
rm -rf /tmp/leancrypto
# ---------------------------------------------------------------------------
# 3. GnuTLS --with-leancrypto -> /usr/local
# leancrypto.pc MUST be discoverable now (it is, via PKG_CONFIG_PATH), or
# ./configure aborts in PKG_CHECK_MODULES([LEANCRYPTO],[leancrypto >= 1.2.0]).
# Tools (certtool/gnutls-cli) are kept on purpose: certtool is the ML-DSA
# smoke test below and some BATS tests may shell out to them. We use the apt
# libtasn1 / libunistring (native build-deps), not GnuTLS's bundled copies.
# ---------------------------------------------------------------------------
RUN set -eux; \
cd /tmp; \
curl -fLO "https://www.gnupg.org/ftp/gcrypt/gnutls/${GNUTLS_SERIES}/gnutls-${GNUTLS_VERSION}.tar.xz"; \
tar xf "gnutls-${GNUTLS_VERSION}.tar.xz"; \
cd "gnutls-${GNUTLS_VERSION}"; \
./configure \
--prefix=/usr/local \
--with-leancrypto \
--without-p11-kit \
--without-tpm2 \
--disable-doc \
--disable-tests \
--disable-guile \
--disable-libdane \
--enable-shared \
--enable-static; \
make -j"$(nproc)"; \
make install; \
ldconfig; \
rm -rf "/tmp/gnutls-${GNUTLS_VERSION}" "/tmp/gnutls-${GNUTLS_VERSION}.tar.xz"
# ---------------------------------------------------------------------------
# 4. MbedTLS 3.6.x LTS -> /usr/local
# Use the NAMED release asset (.tar.bz2) - it is self-contained (no
# framework/ submodule). The default config is sufficient for libjwt's
# JWS/JWK/JWE, so do NOT set MBEDTLS_CONFIG_FILE. The stock build installs
# mbedcrypto.pc (+ mbedtls.pc, mbedx509.pc) to lib/pkgconfig.
# ---------------------------------------------------------------------------
RUN set -eux; \
cd /tmp; \
curl -fsSL -o "mbedtls-${MBEDTLS_VERSION}.tar.bz2" \
"https://github.com/Mbed-TLS/mbedtls/releases/download/mbedtls-${MBEDTLS_VERSION}/mbedtls-${MBEDTLS_VERSION}.tar.bz2"; \
tar xjf "mbedtls-${MBEDTLS_VERSION}.tar.bz2"; \
cd "mbedtls-${MBEDTLS_VERSION}"; \
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_SHARED_MBEDTLS_LIBRARY=On \
-DUSE_STATIC_MBEDTLS_LIBRARY=Off \
-DENABLE_TESTING=Off \
-DENABLE_PROGRAMS=Off \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_INSTALL_LIBDIR=lib \
-DMBEDTLS_FATAL_WARNINGS=Off; \
cmake --build build -j"$(nproc)"; \
cmake --install build; \
ldconfig; \
rm -rf "/tmp/mbedtls-${MBEDTLS_VERSION}" "/tmp/mbedtls-${MBEDTLS_VERSION}.tar.bz2"
# ---------------------------------------------------------------------------
# 5. Build-time verification - fail the image build if any guarantee is broken.
# ---------------------------------------------------------------------------
RUN set -eux; \
# 5a. pkg-config resolves the FROM-SOURCE installs (prefix == /usr/local), \
# not an apt copy (forky's apt GnuTLS reports the same 3.8.13 version). \
test "$(pkg-config --variable=prefix gnutls)" = "/usr/local"; \
test "$(pkg-config --variable=prefix mbedcrypto)" = "/usr/local"; \
# 5b. Versions satisfy libjwt's pkg_check_modules floors (and ML-DSA gates). \
pkg-config --atleast-version=3.8.10 gnutls; \
pkg-config --atleast-version=3.6.0 mbedcrypto; \
pkg-config --atleast-version=1.2.0 leancrypto; \
pkg-config --atleast-version=3.5.0 openssl; \
echo "openssl $(pkg-config --modversion openssl)"; \
echo "gnutls $(pkg-config --modversion gnutls)"; \
echo "mbedcrypto $(pkg-config --modversion mbedcrypto)"; \
echo "leancrypto $(pkg-config --modversion leancrypto)"; \
# 5c. GnuTLS's static link line resolves its private deps (leancrypto, \
# nettle, ...) without error. \
pkg-config --static --libs gnutls >/dev/null; \
# 5d. Runtime linker resolves our /usr/local GnuTLS, not the apt one. \
ldd /usr/local/bin/gnutls-cli | grep -E 'libgnutls\.so' | grep -q '/usr/local/lib'; \
# 5e. THE decisive check: GnuTLS actually has a PQC provider (leancrypto). \
# A stock GnuTLS with no provider fails ML-DSA key-gen with error -106. \
# The token is the non-hyphenated 'mldsa87' (certtool figure_key_type). \
/usr/local/bin/certtool --generate-privkey \
--key-type=mldsa87 --outfile=/tmp/mldsa87.key; \
test -s /tmp/mldsa87.key; \
rm -f /tmp/mldsa87.key; \
echo "OK: GnuTLS ML-DSA / leancrypto provider verified"
# Sensible default working directory for CI checkouts.
WORKDIR /src
CMD ["/bin/bash"]