FIPS 140-3
Government deployments need every cryptographic primitive to flow through a FIPS-validated module. The tetrapus-fips facade wraps the four primitives Tetrapus actually uses (SHA-256, HMAC-SHA-256, AES-256-GCM, RNG) so the validated provider can be swapped in via a single cargo feature.
Status
We ship the FIPS-validated module integration — the build matrix, the lint, the startup self-test, and the API surface. Formal certification (the customer's NIST-recognised lab walking the boundary) is an ongoing process and is part of a customer engagement, not a shrink-wrap claim.
Backend swap
The cargo feature fips swaps the default RustCrypto stack (sha2, hmac, aes-gcm, rand) for aws-lc-rs backed by aws-lc-fips-sys. The public Rust API is identical in both modes — calling code never branches on is_fips_mode() to choose primitives, only to surface posture in /health output.
cargo build --release -p tetrapus-server --features fips
./target/release/tetrapus-server --version
# tetrapus-server 0.3.0 (fips) forbid-ring lint
A cargo-deny rule blocks any direct dependency on ring in the FIPS build profile. Transitive pulls are quarantined to the FIPS-validated provider crate. CI fails the FIPS matrix job if a pull request reintroduces a non-validated path.
[bans]
deny = [
{ name = "ring", reason = "use aws-lc-rs in fips builds" },
{ name = "rustls", wrappers = ["aws-lc-rs"] },
] Startup self-test
tetrapus_fips::fips_self_test() is called once at process boot. It runs a known-answer test against each primitive and, in FIPS mode, surfaces the underlying provider's power-on integrity self-test (POST). Failure returns CryptoError::IntegritySelfTest and the process exits non-zero — there is no graceful continuation.
| Primitive | Default backend | FIPS backend | KAT |
|---|---|---|---|
| SHA-256 | sha2 | aws-lc-rs | "abc" → ba7816bf… |
| HMAC-SHA-256 | hmac + sha2 | aws-lc-rs | empty key, empty msg |
| AES-256-GCM | aes-gcm | aws-lc-rs | round-trip "tetrapus-kat" |
| RNG | rand | aws-lc-rs CTR_DRBG | smoke (provider POST) |
Build matrix
Every PR runs both backends in CI so a FIPS regression in shared code is caught before merge.
strategy:
matrix:
profile: [default, fips]
include:
- profile: default
features: ""
- profile: fips
features: "--features fips"
deny: "deny.toml"
steps:
- run: cargo build --release ${{ matrix.features }}
- run: cargo test --workspace ${{ matrix.features }}
- if: matrix.profile == 'fips'
run: cargo deny --config ${{ matrix.deny }} check bans Crates that use the facade
Anything in Tetrapus that needs SHA-256, HMAC, AES-GCM, or random bytes must route through tetrapus-fips. The current consumers:
tetrapus-audit— hash-chained audit row digeststetrapus-attestation— Merkle leaf and inner-node hashingtetrapus-cmek— AES-256-GCM at-rest envelope encryptiontetrapus-auth— refresh-token and session-id randomnesstetrapus-server— boot-timefips_self_test()
Note that the KMS clients (tetrapus-kms) do their cryptographic work inside the remote provider — AWS KMS, GCP KMS, and Vault Transit are themselves FIPS-validated services, and the local code path only does signature transport.
Related
- – KMS Backends — hardware-rooted signing
- – Compliance Matrix — FedRAMP / IL4 control mapping
- – Back to Enterprise
Questions?
Reach out for help with integration, deployment, or custom domain codecs.