Skip to main content

Crate oxicrypt_module

Crate oxicrypt_module 

Source
Expand description

FIPS 140-3 Level 1 module boundary.

This crate defines the cryptographic module boundary per FIPS 140-3 Section 7.2 and the service-gating plumbing every other crate in the workspace depends on. No algorithm is permitted to produce output until the power-up self-tests have run and the module has entered the Operational state; on any self-test failure the module latches into a terminal Error state and rejects every subsequent call for the remainder of the process lifetime.

§State machine (FIPS 140-3 §7.2)

   ┌──────────┐  initialize_with_tests()  ┌───────────┐  all KATs pass  ┌──────────────┐
   │ PowerOff │───────────────────────────▶│ SelfTest  │────────────────▶│ Operational  │
   └──────────┘                            └───────────┘                 └──────────────┘
                                                  │                              │
                                              KAT failure                conditional self-test
                                                  │                            failure
                                                  ▼                              │
                                             ┌─────────┐◀───────────────────────┘
                                             │  Error  │
                                             └─────────┘

§What this crate ships

  • State and the transition machine (PowerOff → SelfTest → Operational | Error).
  • initialize_with_tests — the canonical one-shot entry point that the top-level caller uses to run the integrity test and every approved algorithm’s power-up KAT before opening the service interface.
  • require_operational — the gate that every approved service in every other crate calls on entry. Returns Error::NotOperational (with the observed state) on any pre-Operational or post-Error call.
  • enter_error_state — irreversible transition into the terminal error state, called by conditional self-tests (pairwise consistency, DRBG health) when they detect a failure.
  • KatEntry and the SelfTest trait — the registry shape that algorithm crates use to expose their power-up KATs.
  • AlgorithmProfile — runtime selection of an algorithm restriction policy (Unrestricted, CNSA 2.0, CNSA 1.0, Migration). Set once at initialization via initialize_with_profile.
  • Service — per-algorithm-and-parameter enumeration of every approved service in the module. Used with require_allowed to enforce profile restrictions.

The test registry is not assembled by linker-section tricks: callers pass an explicit &[KatEntry] slice. That means the full set of power-up tests is visible in source at every call site, which makes it straightforward to audit the module’s power-up inventory against the Security Policy.

§Algorithm profiles

A single binary serves general FIPS 140-3 consumers and CNSA-restricted deployments via a runtime AlgorithmProfile selection. The operator passes the desired profile to initialize_with_profile; subsequent calls to require_allowed enforce it. Services not permitted by the active profile return Error::AlgorithmRestricted.

Four profiles are defined:

  • Unrestricted — all FIPS-approved algorithms are available. This is the default, matching the behavior of initialize_with_tests.
  • CNSA 2.0 — CNSSP-15 (March 2025) Annex B: AES-256, SHA-384 or SHA-512, ML-KEM-1024, ML-DSA-87, and the SP 800-208 stateful hash-based signatures for software and firmware signing, together with the supporting services those need at matching strength. Every approved LMS parameter set is permitted; Annex B places no subset restriction on LMS. No Keccak-family hash or XOF is permitted: the suite names none for a software module, and the policy states that algorithms using SHA3 as a component do not thereby make SHA3 an approved hash function. No SLH-DSA parameter set is permitted — CNSSP-15 lists none.
  • CNSA 1.0 — CNSSP-15 (October 2016) Annex B: AES-256, ECDH and ECDSA on P-384, SHA-384, and Diffie-Hellman and RSA at a minimum 3072-bit modulus, with the supporting services those need at matching strength. SHA-256 is refused: the suite admits it only under a near-term allowance scoped to UNCLASSIFIED data, a condition the module cannot evaluate.
  • Migration — both suites at once, for a deployment moving between them. It is not a CNSA profile and no standard defines it; it is the union of the two above, and is narrower than Unrestricted, which refuses nothing.

The profiles do not nest. Neither CNSA suite contains the other: CNSA 1.0 admits ECDSA, RSA and Diffie-Hellman that CNSA 2.0 refuses, and CNSA 2.0 admits the post-quantum and stateful hash-based algorithms that CNSA 1.0 refuses. The two overlap in AES-256 and SHA-384 and their matching-strength support, and nowhere else. KATs still run all algorithms regardless of profile — the profile only restricts post-initialization service access.

§Sensitive security parameters (SSPs)

This crate holds no SSPs of its own. It only gates access to other crates that do. Secret material lives in the algorithm crates that own it (e.g. oxicrypt-rsa’s RsaPrivateKey2048, oxicrypt-drbg’s DRBG states). The error latch here does not perform SSP zeroization on its own — each owning crate is responsible for ensuring its SSPs are dropped when the process restarts following a transition into the Error state.

§FIPS 140-3 / SP 800-140B mapping

SP 800-140B / IG clauseImplementation
§7.10 power-up self-testsinitialize_with_tests runs every registered KatEntry sequentially; the first failure latches State::Error.
§7.10 conditional self-testsAlgorithm crates call enter_error_state on detecting a pairwise-consistency or DRBG-health failure.
IG 9.5.A approved-mode indicatoris_operational / state — queryable at runtime.
§7.10.2.2 software integrityDelegated to oxicrypt-integrity (separate crate), whose KATS the top-level caller runs first: the technique’s own CAST, then the integrity test.

§Thread safety

State is stored in a single AtomicU8 and is safe to read from any thread. initialize_with_tests uses a compare-and-swap to guarantee the self-test phase runs exactly once per process lifetime even under concurrent first-calls; racing losers spin on the SelfTest state byte so they do not observe the transient phase and then receive Error::AlreadyInitialized.

Structs§

KatEntry
A power-up KAT registered with the module.
SelfTestFailure
Marker returned by a failing SelfTest::run.

Enums§

AlgorithmProfile
Algorithm restriction profile selected at module initialization.
Error
Errors surfaced by the module boundary.
Service
Enumeration of every approved service in the module, at the algorithm-and-parameter level.
State
Module lifecycle state per FIPS 140-3 Section 7.2.

Traits§

SelfTest
A single power-up self-test.

Functions§

active_profile
Returns the active algorithm profile.
enter_error_state
Forces the module into the terminal Error state.
initialize_with_profile
Initializes the module with a specific algorithm profile and runs every supplied power-up KAT.
initialize_with_tests
Initializes the module and runs every supplied power-up KAT.
is_operational
Returns true iff the module has passed its power-up self-tests and is currently in the Operational state.
require_allowed
Guard used at the entry point of every approved service, after require_operational, to enforce the active algorithm profile.
require_operational
Guard used at the entry point of every approved service. Returns Ok(()) only when the module is Operational; otherwise returns a Error::NotOperational describing the current state so callers cannot accidentally ignore it.
state
Returns the current module state.