---
status: accepted
date: 2026-05-13
decision-makers: Constructor Fabric Steering Committee
---

# Windows FIPS 140-3 via `rustls-cng-crypto`

**ID**: `cpt-toolkit-adr-windows-fips-cng-crypto`

## Table of Contents

<!-- generated by `cypilot toc` -->

## Background

This ADR addresses the **Windows third** of the cross-OS FIPS strategy laid out in the [FIPS PRD](../PRD.md). Per PRD §3.3, Microsoft Windows CNG is the only path to a Windows FIPS claim — Microsoft does not submit third-party modules under their OE, and no community Rust crypto module has CMVP listing covering Windows. The question this ADR decides is **which Rust integration to use** to route `rustls 0.23` through CNG.

Linux+aws-lc-fips and macOS+corecrypto were already shipping (PRD §6.1, §6.2); Windows was the explicit gap left open by [ADR 0001](0001-macos-fips-via-corecrypto-provider.md).

## Considered Options

* **Option A** — `rustls-cng-crypto` (community, `tofay/rustls-cng-crypto`) — **chosen**
* **Option B** — `rustls-symcrypt` (Microsoft, `microsoft/rustls-symcrypt`)
* **Option C** — Wait (no Windows FIPS support; ship Linux + macOS only)
* **Option D** — In-tree custom `CryptoProvider` over CNG

## Decision Outcome

Chosen option: **Option A — `rustls-cng-crypto`**, caret-pinned to `0.1.x`.

Key reasons:

* **Only crate with a CMVP chain-of-trust today.** Thin FFI wrapper over Windows CNG, which Microsoft itself validates per OS release. Chain-of-trust terminates at CNG, the same posture as `cf-gears-rustls-corecrypto-provider` over Apple corecrypto.
* **Pure FFI, no `build.rs` toolchain.** Links directly against `bcrypt.dll` via `windows-sys`. Cross-compile from Linux/macOS works with `rustup target add x86_64-pc-windows-msvc` (plus `cargo-xwin` on non-Windows hosts for the MSVC sysroot).
* **Option B (`rustls-symcrypt`) is rejected today** because SymCrypt is not on the CMVP Validated Modules list as of 2026-05. Using it would create the same failure mode we eliminated for macOS in ADR 0001 — a FIPS-mode-flagged binary routing through a non-CMVP-validated module. If/when SymCrypt obtains a CMVP cert, swap is two files (`crypto.rs` + `tls.rs`) plus a workspace dep alias.
* **Option C is rejected** because cross-OS FIPS is a stated product requirement (PRD §2 F-1, F-4).
* **Option D is rejected on cost/benefit**: ~1500 LOC of CNG FFI work duplicates what `rustls-cng-crypto` already does, with no audit-trail advantage — CNG itself is the CMVP-validated artifact, the FFI wrapper is reviewable in isolation either way. Reserve for emergency use if upstream is abandoned.

### Consequences

* **System-wide FIPS-mode requirement on Windows**: CNG enforces FIPS-Approved algorithms only when `HKLM\System\CurrentControlSet\Control\Lsa\FipsAlgorithmPolicy = 1` (set via Group Policy + reboot). `rustls_cng_crypto::fips_provider()` documents an idiomatic fail-closed contract: when Windows is not in FIPS mode it returns an empty `CryptoProvider`. Our `init_crypto_provider` detects this shape and refuses to start with `CryptoProviderError::SystemFipsModeNotEnabled`. The conservative reading of the FIPS claim disallows silent degradation.
* **Dependency maturity risk**: young crate (first release 2024-12, single maintainer). Mitigations: caret-pin to `0.1.x` (no auto-`0.2` upgrade), dep-graph regression gate (must contain `cng-crypto`, must NOT contain `aws-lc-fips-sys`), explicit re-evaluation at each minor release.
* **Migration path documented**: if `rustls-symcrypt` obtains CMVP validation before `rustls-cng-crypto` matures, the swap is local to two dispatch tables plus one workspace dep alias.
* **No CI runtime coverage on Windows**. The `make check-windows-fips` target catches build-graph / cfg regressions via cross-compile but does not execute Windows code. Handshake verification is a manual release-gate runbook in `examples/cf-gears-fips-probe/README.md`.

### Confirmation

Following the verification gates in [PRD §9](../PRD.md#9-acceptance-criteria):

* **Cross-compile gate** (CI): `make check-windows-fips` → `cargo xwin check --target x86_64-pc-windows-msvc -p cf-gears-example-server --features fips`.
* **Dep-graph regression** (PRD §9 acceptance criteria + [ADR 0005](0005-fips-dependency-policy.md)): Windows graph must contain `rustls-cng-crypto`, must not contain `aws-lc-fips-sys`.
* **Manual smoke on Windows host** (release gate): per `examples/cf-gears-fips-probe/README.md` "Verify on Windows". Positive (FIPS-mode on → AES-GCM-only `ClientHello`), negative (FIPS-mode off → `SystemFipsModeNotEnabled` refusal). Runtime OE-validation against the CMVP cert build table is not yet implemented for Windows; tracked in PRD §10 TODO-8.

## Pros and Cons of the Options

### Option A — `rustls-cng-crypto` (chosen)

* Good: chain-of-trust terminates at Windows CNG, current CMVP validations per OS release.
* Good: architecturally symmetric to `cf-gears-rustls-corecrypto-provider` (macOS) and `aws-lc-fips-sys` (Linux) — one rustls state machine, three swappable backends.
* Good: pure FFI (`windows-sys`), no `build.rs` C toolchain on Windows.
* Good: `fips_provider()` is feature-gated and idiomatically fail-closed (empty provider when FIPS-mode off).
* Bad: young crate, single maintainer — upstream-stagnation risk, not correctness risk.
* Bad: not itself on the CMVP Validated Modules list. (Neither is our corecrypto provider; both rely on the OS-native module.)

### Option B — `rustls-symcrypt`

* Good: Microsoft-maintained, aligned with Microsoft's crypto roadmap.
* Good: identical architectural shape to Option A.
* Bad: **not currently CMVP-validated**. Using it for the FIPS path would create a void claim.
* Future trigger: becomes the strictly better choice once SymCrypt obtains a CMVP cert.

### Option C — Wait

* Good: zero implementation cost.
* Bad: violates PRD F-4 (FIPS on all three OSes).
* Bad: Windows-targeted deployments have no compliant build.

### Option D — In-tree custom over CNG

* Good: full audit-trail control over every FFI call.
* Good: zero upstream-stagnation risk.
* Bad: reimplements ~1500 LOC of existing crate for no security advantage — CNG itself is the CMVP-validated module either way.
* Reserve for: emergency use if `rustls-cng-crypto` is abandoned AND `rustls-symcrypt` still lacks CMVP cert.

## More Information

* Crate: <https://crates.io/crates/rustls-cng-crypto> / <https://github.com/tofay/rustls-cng-crypto>
* Microsoft FIPS-mode reference: <https://learn.microsoft.com/en-us/windows/security/security-foundations/certification/fips-140-validation>
* Wire-level smoke runbook: [`examples/cf-gears-fips-probe/README.md`](../../../../examples/cf-gears-fips-probe/README.md) — "Verify on Windows".

## Traceability

- **DESIGN**: [`libs/toolkit/src/bootstrap/crypto.rs`](../../../../libs/toolkit/src/bootstrap/crypto.rs), [`libs/toolkit-http/src/tls.rs`](../../../../libs/toolkit-http/src/tls.rs)
- **Related**: [ADR 0001](0001-macos-fips-via-corecrypto-provider.md) (macOS counterpart), [ADR 0002](0002-fips-feature-target-conditional-shim.md) (per-target shim, extended to also exclude Windows from `rustls/fips`).
- **Strategy doc**: [FIPS PRD](../PRD.md) — full cross-OS architecture, requirements, and verification gates.

This decision directly addresses:

* `cpt-toolkit-nfr-fips-cross-os` — Valid FIPS 140-3 claim on Linux **and** macOS **and** Windows.
* `cpt-toolkit-design-tls-uniformity` — Single rustls-based TLS stack across all supported OSes.
