Clause
← All documentation

Crypto: OpenSSL integration, build configuration and FIPS

Clause implements the Erlang/OTP crypto module using OpenSSL's libcrypto. This document specifies OpenSSL version requirements, dependency resolution, source builds, executable linking and FIPS mode configuration. See builtins for the builtin interface, library for the library module, and differences for observable differences from Erlang/OTP. The public_key module uses crypto for key and signature operations.

OpenSSL versions

OpenSSL is licensed under Apache-2.0. OpenSSL source files are not committed to the Clause repository.

OpenSSL dependency resolution

CMake resolves libcrypto for the crypto runtime archive through cmake/OpenSSLDependencies.cmake, in the following order:

  1. Explicit path: -DCLAUSE_OPENSSL_ROOT=<path> selects an installation prefix containing include/openssl/opensslv.h, or a source tree containing Configure and VERSION.dat. Source trees use the build procedure described below.
  2. System installation: when CLAUSE_OPENSSL_SYSTEM is enabled, find_package(OpenSSL) searches for OpenSSL 3.1.2 or later and prefers static libcrypto. This option defaults to ON except on Windows.
  3. Pinned source release: Clause downloads and extracts openssl-4.1.0.tar.gz into thirdparty/openssl-4.1.0 after verifying its SHA-256 digest: 50c17baf54cb008f6ce42d50deb4b28050a1aad711636cabd4b241c7e90cc2fd. The installation is cached at thirdparty/openssl-4.1.0-<arch>-<crt>/install and rebuilt when the compiler or build options change. -DCLAUSE_DOWNLOAD_OPENSSL=OFF disables the download.

-DCLAUSE_RUNTIME_CRYPTO=OFF excludes the crypto runtime archive from the build. When tests are enabled, configuration also downloads openssl-3.1.2.tar.gz into thirdparty/openssl-3.1.2 for the full test suite. Its SHA-256 digest is a0ce69b8b97ea6a35b96875235aa453b966ba3cba8af2de23657d8b6767d6539. -DCLAUSE_TEST_OPENSSL_MINIMUM=OFF disables this download and the associated tests.

Building OpenSSL from source

Source builds produce static libcrypto with the legacy provider included. The crypto builtins load this provider during initialization, matching OTP. The build procedure uses these commands, with options filtered for the selected OpenSSL version:

Configure <target> no-shared no-module no-tests no-docs no-makedepend enable-ec_explicit_curves
          [enable-static-vcruntime] [--debug] --prefix=<install> --openssldir=<install>/ssl --libdir=lib
make build_libs && make install_dev

Build constraints and workarounds

Linking programs

The crypto builtins are compiled into clause_runtime_crypto, a separate archive from clause_runtime. Programs that do not use crypto do not link this archive or libcrypto. Linking libcrypto with its providers increases executable size by approximately 4.5 MB.

FIPS

Runtime FIPS mode selection

The first crypto call attempts to load OpenSSL's fips provider. OpenSSL uses OPENSSL_MODULES to locate provider modules and OPENSSL_CONF to locate a configuration that includes the fipsmodule.cnf generated by openssl fipsinstall and activates the provider.

Each algorithm table entry retains a separate fetch result obtained with fips=yes. FIPS mode uses this result to select the FIPS provider's implementation. Public key operations fetch algorithms using OpenSSL's default properties, which select the FIPS provider's implementations when FIPS mode is enabled. In this mode, eddsa raises "Unsupported algorithm in FIPS mode" and SRP raises notsup, matching OTP.

Clause does not read OTP's fips_mode application variable: it does not implement on_load, and programs do not use sys.config. Programs must call crypto:enable_fips_mode/1 or use the mandatory FIPS mode build option described below.

Mandatory FIPS mode: clau --fips=PATH

--fips=PATH builds an executable that requires FIPS mode and a user-supplied FIPS provider. PATH must identify either a directory containing the provider module and fipsmodule.cnf, or an OpenSSL installation. Each file is searched for directly in PATH, then in the listed subdirectories:

FileSearch subdirectories, in order
fips.dll (Windows), fips.so (Linux), fips.dylib (macOS)lib/ossl-modules, lib64/ossl-modules, lib/<triplet>/ossl-modules
fipsmodule.cnfssl/, etc/ssl/

FIPS provider requirements

Clause does not build FIPS providers for deployment. A provider used for validated operation must come from a validated release, such as OpenSSL 3.1.2, and be built according to its security policy, or be supplied by an operating system vendor. OpenSSL permits a validated provider to be used with other OpenSSL releases; a provider built from a non-validated release does not qualify as a validated provider. Run the provider's openssl fipsinstall on the target machine when required by its security policy.

The OpenSSL 3.1.2 FIPS provider loads into the pinned OpenSSL 4.1 libcrypto. The full test suite builds this provider exclusively for testing and executes programs with both mandatory and runtime-selectable FIPS modes.

Tests

TestSuiteCoverage
executables_crypto_digests, executables_crypto_ciphersfastOTP 29.1.1 golden fixtures: vectors, states, errors, detected algorithm lists and info_fips without a provider
linking_cryptofastConditional archive linking, --with-crypto[=PATH], CLAUSE_OPENSSL_ROOT and invalid input rejection
linking_fipsfastInvalid --fips argument rejection, build failures for missing or malformed providers, deployment file copying and startup failures
linking_crypto_sourcefullInitial build and cache reuse for the OpenSSL 4.1.0 source tree selected by --with-crypto=SOURCE
linking_crypto_minimumfullCrypto fixture output matches the golden output when linked against libcrypto built from OpenSSL 3.1.2 source
linking_fips_realfullOpenSSL 3.1.2 FIPS provider built with enable-fips for testing: mandatory FIPS mode enforcement, forbidden algorithms, startup failure after module modification, and runtime mode selection through OPENSSL_MODULES and OPENSSL_CONF