NO-SNOW: FIPS phases 1-2: make fips reachable, consolidate TLS on aws-lc - #1345
NO-SNOW: FIPS phases 1-2: make fips reachable, consolidate TLS on aws-lc#1345zeroshade wants to merge 1 commit into
fips reachable, consolidate TLS on aws-lc#1345Conversation
There was a problem hiding this comment.
Pull request overview
This pull request advances the FIPS compliance plan by making the fips feature selectable from shipped binding crates and by consolidating the TLS stack onto rustls + aws-lc (with explicit provider installation) to prevent accidental fallback to non-FIPS crypto backends.
Changes:
- Forward
sf_core’sfipsfeature throughodbc,jdbc_bridge,python_bridge, andnodejs_bridge, and document the broader multi-phase compliance plan. - Switch reqwest usage to
rustls-tls-*-no-providerand addtls::ensure_crypto_provider()call sites so reqwest clients can’t silently resolve toring. - Route AWS STS calls (platform detection + WIF) through the driver’s shared reqwest transport to ensure connection TLS policy (roots/proxy/version/CRL) is consistently applied.
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
sf_core/tests/integration/mod.rs |
Installs a default rustls provider early for integration tests that build ad-hoc reqwest clients. |
sf_core/src/tls/mod.rs |
Adds ensure_crypto_provider() and FIPS-mode runtime assertions/tests. |
sf_core/src/tls/client.rs |
Ensures provider installation occurs before any reqwest client/builder is constructed (including insecure paths). |
sf_core/src/telemetry/platform_detection/mod.rs |
Pins crypto provider before early platform-probe HTTP client creation; threads shared client into AWS identity probe. |
sf_core/src/telemetry/platform_detection/aws.rs |
Routes STS GetCallerIdentity through the shared reqwest transport and updates provider trait signature. |
sf_core/src/rest/snowflake/workload_identity/aws.rs |
Routes AWS SDK STS usage through shared reqwest transport; ensures provider before IMDS probe; threads client through credential resolution/assume-role. |
sf_core/src/lib.rs |
Installs default provider in unit-test builds to avoid order-dependent “No provider set” panics. |
sf_core/src/crl/cache.rs |
Pins provider before CRL HTTP client construction (including fallback minimal cache). |
sf_core/src/apis/database_driver_v1/global_state.rs |
Installs crypto provider at driver construction chokepoint (with_providers). |
sf_core/Cargo.toml |
Makes fips feature explicit (rustls/fips + aws-lc-rs/fips), switches reqwest features to -no-provider, disables oauth2 defaults, removes rustls-webpki 0.102, adds dev-deps for test harness provider installs. |
python_bridge/Cargo.toml |
Adds fips = ["sf_core/fips"] passthrough feature. |
odbc/Cargo.toml |
Adds fips = ["sf_core/fips"] passthrough feature. |
nodejs_bridge/Cargo.toml |
Adds fips = ["sf_core/fips"] passthrough feature. |
jdbc_bridge/Cargo.toml |
Adds fips = ["sf_core/fips"] passthrough feature. |
docs/design/fips-compliance.md |
Adds the FIPS gap analysis and phased remediation plan/design note. |
Cargo.lock |
Updates lockfile for new/removed deps (notably adding ctor 0.2.x and removing rustls-webpki 0.102.x / quinn-related entries). |
.github/workflows/test-rust-core.yml |
Updates Windows ARM64 non-FIPS lane notes about fips-gated test coverage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
38ff2f1 to
a8e4272
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
sf_core/src/tls/mod.rs:60
fips_mode_activeis currentlypub, which makes it part ofsf_core's public API (sincetlsis a public module). It doesn’t appear to be used outsidetls, so consider reducing visibility to avoid committing to a new stable API surface.
pub fn fips_mode_active() -> bool {
sf_core/Cargo.toml:195
sf_coreadds a direct dev-dependency onctor = "0.2", but the workspace already pulls inctor 1.x(e.g., via napi), which results in multiplectorversions inCargo.lock. If the macro usage is compatible, consider usingctor = "1"here to reduce duplicate dependencies.
ctor = "0.2"
a8e4272 to
98cb4c7
Compare
98cb4c7 to
6e008ec
Compare
6e008ec to
0ecb291
Compare
0ecb291 to
20eff6a
Compare
20eff6a to
3783798
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 19 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
sf_core/Cargo.toml:197
rustlsis already a normal dependency ofsf_core(with the requiredaws_lc_rsfeature), so adding it again as a dev-dependency is redundant and can unintentionally enable additional default features for test builds. Keeping onlyctorhere should be sufficient for the test-only provider ctors.
rustls = "0.23"
ctor = "1"
3783798 to
bd176d0
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 24 out of 25 changed files in this pull request and generated 4 comments.
Suppressed comments (1)
sf_core/src/rest/snowflake/mod.rs:793
- Using a fresh
CrlWorker::new_lazy()here defeats the shared worker already used to build the connection client. With CRL checking enabled,CrlServerCertVerifierinitializes this handle during the STS handshake, so each AWS WIF login/retry can spawn a separatecrl-workerthread and then tear it down, creating thread churn under concurrent authentication. Thread the existingSharedCrlWorkerthrough the login/auth-data path and pass it here instead.
crate::crl::worker::CrlWorker::new_lazy(),
08ccf27 to
9316fc0
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 24 out of 25 changed files in this pull request and generated 2 comments.
Suppressed comments (1)
sf_core/src/rest/snowflake/mod.rs:794
- This client is built for every WIF provider, although only the AWS branch consumes
aws_sdk_http. Azure/GCP/OIDC therefore pay for a second TLS/CRL client on each login, and a failure in this AWS-only setup can abort non-AWS attestation before its provider runs. Construct it only whencfg.provider == WifProvider::Awsand pass the resulting option through.
let aws_sdk_http = crate::tls::aws_http_client::AwsSdkReqwestClient::build(
&login_parameters.client_info.tls_config,
Some(&login_parameters.client_info.proxy_config),
crate::crl::worker::CrlWorker::new_lazy(),
)
9316fc0 to
20fcd3a
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 27 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
sf_core/src/tls/aws_http_client.rs:10
- The module-level claim that every AWS SDK consumer inherits the connection TLS policy is inaccurate:
with_default_tls()is intentionally used by platform detection and the no-connection WIF RPC, so those calls have no connectionTlsConfig, CRL worker, or explicit proxy. Limit this claim to connection-scoped consumers or document the default-TLS exception.
//! stack that Azure and GCS transfers build via [`configure_tls_builder`], so every
//! AWS SDK consumer (S3 transfers, the WIF STS calls, platform detection's STS
//! probe) inherits one implementation of the connection's TLS policy (version
//! window, CRL, custom root store) and proxy handling (`proxy_host`/
20fcd3a to
8abdb82
Compare
8abdb82 to
4de56af
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 29 changed files in this pull request and generated no new comments.
Suppressed comments (1)
sf_core/src/tls/mod.rs:92
- The new FIPS tests cover only the successful aws-lc/provider/config path; they do not exercise this fail-closed branch when an embedding process has already installed a non-FIPS provider. Because the rustls provider is process-global, please add an isolated test binary/subprocess that installs the non-FIPS provider first and verifies TLS client construction returns
FipsModeUnavailableinstead of serving traffic.
pub(crate) fn require_fips_provider() -> Result<(), error::TlsError> {
#[cfg(feature = "fips")]
if !fips_mode_active() {
return Err(error::FipsModeUnavailableSnafu.build());
sfc-gh-pfus
left a comment
There was a problem hiding this comment.
Strong PR. Two things stand out as genuinely subtle catches: hoisting ensure_crypto_provider() above the insecure early-returns closes a path where a verify_certificates=false client built first in a process would have silently resolved to ring, and spotting that oauth2's default features forward to reqwest/rustls-tls — re-arming __rustls-ring for the whole build through feature unification — is not obvious from reading either manifest.
The require_fips_provider() / ensure_crypto_provider() split is also the right shape: fail closed where there's an error channel, log where unwinding beneath FFI would be undefined behaviour.
One substantive request (the fips feature guard, inline on sf_core/Cargo.toml) — happy for that to be a follow-up PR rather than here, as long as it lands before we start building FIPS release artifacts. Everything else is a note or a nit.
| # aws-lc module reports FIPS mode, and the installed rustls provider / | ||
| # ClientConfig are FIPS (approved cipher suites only). All of that is | ||
| # meaningless on this non-fips lane by construction, so | ||
| # skipping them here loses no coverage. Every other test runs identically with |
There was a problem hiding this comment.
Just so this isn't confusing to read: nothing in this repo currently executes tls::fips_tests — lines 125 and 136 are cargo build and cargo test --no-run, so the tests compile but never assert. That's expected given how CI is split here, and adding the FIPS build and test lanes is on our side after this merges.
No action needed from you; flagging only so a future reader doesn't assume the assertions are already gating anything.
There was a problem hiding this comment.
Understood, and I have made it explicit in the file rather than leaving it to be re-derived: the comment above the compile step now records that these two lanes are the only places fips-tls is turned on, that neither executes a test, and that the assertions therefore compile but never assert until the FIPS lanes exist on your side.
Flagging one consequence for whoever writes those lanes: tls::fips_tests asserts on the installed process-default provider, so it has to run in a binary where ensure_crypto_provider() has run — the test calls it, so cargo test --features fips-tls --lib is sufficient, but a lane that only builds proves nothing.
There was a problem hiding this comment.
Follow-up: an automated reviewer independently flagged this same gap on the rebased commit (the --no-run lane not executing tls::fips_tests). I closed it pointing at your comment, since the lane needs the pinned GCC 13 toolchain for aws-lc-fips-sys and is yours to add — recording it here so the agreement is visible on the thread rather than only in my tooling.
| /// Scope: this gates the clients that carry connection traffic (everything | ||
| /// built through `build_tls_client_and_rustls_config` / `configure_tls_builder`). | ||
| /// Auxiliary raw clients -- telemetry, CRL fetch, IMDS -- have no error channel | ||
| /// to fail into and still rely on the logged mismatch. |
There was a problem hiding this comment.
The scope note is exactly right, and thanks for making it explicit rather than leaving it implicit in the call sites. Noting for our side: we'll carry this into the compliance exception list, since telemetry / CRL fetch / IMDS proceeding on a non-FIPS provider with only a log line is the kind of thing that needs a written position rather than living in a code comment.
For what it's worth I think it's defensible as written — the exposure only materialises when an embedding application wins the provider race, and CRL fetch retrieves publicly signed data rather than protecting secrets.
There was a problem hiding this comment.
Thanks — and agreed the compliance exception list is the right home for it rather than a code comment. The scope note is written to be the thing you can lift into that list: the three clients are named, and the reason they cannot fail closed (no error channel beneath an FFI boundary where unwinding is UB) is stated rather than implied, so the exception can be justified rather than just recorded.
One correction to carry over, since it changed after you read this: WIF attestation is no longer in that set. It now fails closed at the create_attestation entry point, which covers the wif_create_attestation RPC path that does not go through the TLS factories. The remaining exceptions are exactly telemetry, CRL fetch and IMDS. Your read on the residual exposure matches mine — it needs an embedding application to win the provider race, and CRL fetch retrieves publicly signed data.
| # storage clients already use rustls). The root store is bundled webpki roots | ||
| # plus the OS trust store: `rustls-tls-webpki-roots-no-provider` + | ||
| # `rustls-tls-native-roots-no-provider` is the same composition the previous | ||
| # `rustls-tls` (an alias for `rustls-tls-webpki-roots`) + `rustls-tls-native-roots` |
There was a problem hiding this comment.
Agreed this preserves the previous composition exactly, and preserving it is the right call for a PR scoped like this one. Flagging rather than requesting a change: the effect is that we trust the bundled webpki roots union the OS trust store, so an enterprise that removes a CA from its OS store still has us trusting it via the Mozilla bundle.
That's a behaviour question rather than a FIPS one, and it needs a decision on our side before anyone changes it — but I'd rather it be an open question than settle quietly as documented-intent, since FIPS-conscious customers are exactly the population that curates its trust store.
There was a problem hiding this comment.
Agreed on both counts — preserved deliberately here, and worth a real decision rather than quiet inheritance. To be precise about what is inherited: rustls-tls-webpki-roots-no-provider + rustls-tls-native-roots-no-provider is the same union the previous rustls-tls + rustls-tls-native-roots selection produced, so this PR changes the provider underneath, not the trust set.
Your framing of the risk is the sharp one: an enterprise that removes a CA from its OS store does not thereby stop us trusting it, because the Mozilla bundle still carries it — and removal, not addition, is how a curated store expresses distrust. The narrowing change would be dropping the webpki bundle and going OS-only, which is a behaviour change with real blast radius (the bundle is what makes us work on hosts with a thin or stale store). I have not touched it, and I would rather it be decided on its own merits than as a side effect of a FIPS PR. Happy to file it as a separate issue if you want it tracked somewhere more durable than this thread.
4de56af to
608ce86
Compare
…on aws-lc
Phase 1 -- make the FIPS-validated TLS backend reachable from shipped
artifacts. The feature existed on sf_core but no binding crate forwarded
it, so it was physically unreachable from everything we ship:
- Add a `fips-tls` passthrough to odbc, jdbc_bridge, python_bridge and
nodejs_bridge.
- Name it `fips-tls`, not `fips`: it swaps the TLS backend only. JWT
signing, stage file encryption, DPoP and key parsing still run on
OpenSSL, which has no FIPS-validated provider -- and under
`vendored-openssl` that unvalidated copy is statically linked where a
customer cannot replace it. The narrow name is what stops a partial
build from being shipped as a FIPS artifact; `fips` is left unclaimed
for the complete thing. A `compile_error!` on the `fips` +
`vendored-openssl` pair was considered and rejected: `--all-features`
enables both by definition, so it would break the repo's pre-commit
clippy/check hooks and the put/get lane.
- Make sf_core's feature explicit: `["rustls/fips", "aws-lc-rs/fips"]`.
tls::x509_utils calls aws_lc_rs::signature::* directly for CRL
verification, and those calls must reach the FIPS module by
declaration rather than by cargo feature unification happening to
line up.
- Remove dead `rustls-webpki 0.102` (declared, never imported; dragged a
second ring-backed webpki into the graph).
- Add runtime FIPS assertions: try_fips_mode() succeeds, the installed
process-default provider reports fips() with only approved suites, and
ClientConfig::fips() survives the builder chain. Nothing in this repo
executes them yet -- the lanes that will arrive with the FIPS release
pipelines.
Phase 2 -- eliminate non-FIPS crypto reachability in the TLS stack:
- Switch reqwest to the `rustls-tls-*-no-provider` feature variants and
oauth2 to `default-features = false`. oauth2's default `rustls-tls`
forwards to reqwest/rustls-tls, which re-armed the silent `ring`
fallback for the entire build through feature unification. rustls 0.23
is now aws-lc-only, and a client built before a provider install
panics ("No provider set") instead of silently degrading to ring.
- Add tls::ensure_crypto_provider(): a Once-guarded aws-lc install
called from the driver-constructor chokepoint and from every bare
client site (telemetry platform detection, CRL cache, IMDS). It logs
rather than panics, because it runs beneath an FFI boundary where
unwinding is undefined behaviour, and it honours a provider that an
embedding application installed first.
- Fail closed wherever there is an error channel to fail into.
tls::require_fips_provider() is called from
build_tls_client_and_rustls_config, configure_tls_builder,
AwsSdkReqwestClient::build and the WIF attestation entry point, all of
which return Result. A `fips-tls` build whose process-global provider
is not FIPS refuses to construct a TLS client, surfacing
TlsError::FipsModeUnavailable through the existing FFI error path
rather than serving traffic on a non-approved module. Auxiliary raw
clients (telemetry, CRL fetch, IMDS) have no error channel and still
rely on the logged mismatch.
- tls::fips_mode_active() reports on the installed provider and is
always compiled rather than feature-gated. The wrappers will surface
it as a customer-facing accessor, and one that is absent without the
feature would make "you installed the wrong artifact" look identical
to "your driver is too old to have it".
- Route AWS SDK traffic through the driver's own transport. WIF's STS
calls and platform detection's STS probe went through
aws_config::defaults() and honoured none of the connection's
TlsConfig: no CRL checking, no version window, no custom roots, no
proxy. Independent of FIPS, that was a live TLS-policy hole.
- Enforce the SDK-owned transport constraints structurally. Those SDK
calls need redirect following, gzip auto-decompression and HTTP/2
turned off, which are builder-level properties that cannot be applied
to an already-built client. `build_s3_reqwest_client` became the
`AwsSdkReqwestClient` newtype, whose constructors are the only way to
obtain the type the SDK adapter accepts -- an unadjusted client is now
unrepresentable in the SDK transport. The login path builds a
connection-scoped one from client_info, reusing the driver's shared
CRL worker (threaded through snowflake_login_with_client /
auth_request_data) instead of spawning one per login, and builds it
only for the AWS provider, since Azure/GCP/OIDC never touch it and
should not be able to fail on its construction.
Deliberately not done: no release-workflow FIPS lanes. Without phase 3 --
porting the non-TLS crypto off vendored OpenSSL -- a shipped "FIPS"
artifact would invite a compliance claim the code does not support.
Test-harness note: with the `-no-provider` reqwest features, any test
binary that builds raw reqwest clients must install a provider itself
before the first one is constructed. `#[ctor]` initializers in
src/lib.rs (cfg(test)) and tests/common/crypto_provider.rs cover the
lib, integration and logging_query targets. New dev-deps: rustls, ctor.
Verified: 2084 default / 2087 fips-tls lib tests pass; the integration
suite's failing set is byte-identical to main's; clippy sits at main's
own warning baseline; fmt clean; all four bindings build with and
without the feature; `--all-features` still compiles. The fips-tls build
was verified end to end (aws_lc_rs::try_fips_mode() active at runtime)
using the GCC 13 toolchain that aws-lc-fips-sys 0.13.x requires. The two
secondary lockfiles pinning sf_core (python/Cargo.lock.sdist and the
perf-app lock) are regenerated and pass --locked.
608ce86 to
860a47e
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 29 changed files in this pull request and generated 2 comments.
Suppressed comments (5)
sf_core/src/protobuf/apis/database_driver_v1/mod.rs:1282
- The feature is intentionally named
fips-tls, whilefipsis reserved for the future complete artifact. This new comment should use the actual feature name so it does not document an unavailable configuration.
// in a `fips` build.
sf_core/src/rest/snowflake/workload_identity/mod.rs:80
- The feature is intentionally named
fips-tls, whilefipsis reserved for the future complete artifact. This new error documentation also says every provider exchanges material over the supplied clients, but the OIDC provider makes no request; please use the actual feature name and qualify this as applying to networked providers.
/// Raised before any provider is dispatched, in `fips` builds whose
/// process-global rustls provider is not FIPS. All providers exchange
/// authentication material over the caller-supplied clients, so the same
/// fail-closed gate the TLS factories apply belongs here too -- notably
sf_core/src/rest/snowflake/workload_identity/mod.rs:175
- OIDC does not make a network request (the RPC path documents this below), so the statement that every provider exchanges authentication material over the supplied clients is inaccurate. Please qualify this explanation as applying to networked providers while retaining the separate process-wide gate.
// Every provider exchanges authentication material over the supplied
// clients. Pinning and gating the crypto backend at this single entry
// point gives a caller-built plain client (the `wif_create_attestation`
// RPC) the same fail-closed FIPS behaviour as clients built by the TLS
// factories, which run both calls in `configure_tls_builder`. Redundant
sf_core/src/tls/client.rs:66
- The feature is intentionally named
fips-tls, whilefipsis reserved for the future complete artifact. This comment therefore refers to a nonexistent or ambiguous feature; please use the actual feature name here.
// Fail closed rather than serve traffic on a non-approved module: in `fips`
// builds this refuses to build a client when the provider that won the
// process-global slot is not FIPS. Compiles away without the feature.
sf_core/src/tls/mod.rs:27
- With the
-no-providerreqwest features selected above, a client built beforeensure_crypto_provider()panics withNo provider set; it cannot silently resolve to another backend. This new documentation should describe the fail-fast behavior so future call sites are not audited against a fallback that no longer exists.
/// than ad hoc next to each client, is what stops a client built early in the
/// process (telemetry, CRL prefetch, cloud transfers) from silently resolving
/// to a different backend than the one carrying the session's own traffic --
/// under `--features fips-tls` that difference is the whole compliance claim.
| # Which also means the `fips-tls` assertions in tls::fips_tests are compiled | ||
| # here but never executed: this step and the build above are the only places | ||
| # the feature is turned on, and neither runs a test. Nothing in this repo | ||
| # currently asserts FIPS-ness at runtime; the lanes that will are added with | ||
| # the FIPS release pipelines. |
| /// from standard builds would make "you installed the wrong artifact" look | ||
| /// identical to "you are running a driver too old to have the accessor at | ||
| /// all". Always present, answering `false`, keeps those two distinguishable. | ||
| pub fn fips_mode_active() -> bool { |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 29 changed files in this pull request and generated 4 comments.
Suppressed comments (4)
.github/workflows/test-rust-core.yml:142
- The only runtime FIPS assertions added by this PR are compiled here but never executed: this step uses
--no-run, and the remaining test matrix is non-FIPS. A regression in provider installation orClientConfig::fips()can therefore pass CI; run the focusedtls::fips_tests(or add an equivalent executing FIPS lane) instead of compile-only coverage.
run: cargo test --locked --no-run --lib --package sf_core --no-default-features --features fips-tls
.github/workflows/test-rust-core.yml:399
- These newly added CI comments still describe the comparison as being 'with and without fips', although the feature renamed in this PR is
fips-tlsandfipsis intentionally unclaimed. Use the actual feature name so the ARM64 rationale remains searchable and accurate.
# and without fips; only the linked TLS crypto backend differs
sf_core/Cargo.toml:27
- The feature rename leaves
docs/woa64/ADR-woa64.md:136describing the workaround as dropping the oldfipsfeature. After this manifest change that troubleshooting guidance points at a flag that is no longer declared; update the ADR (and related wording) to refer tofips-tlsor FIPS TLS.
fips-tls = ["rustls/fips", "aws-lc-rs/fips"]
sf_core/src/tls/mod.rs:72
- This helper is exposed as
pub fnfrom the already-publictlsmodule, creating a newsf_coreAPI before the Phase 4 wrapper exists. The function is only an internal provider check in this phase; keep itpub(crate)and introduce the supported wrapper surface when that phase is implemented, rather than committing this low-level helper as API.
pub fn fips_mode_active() -> bool {
| // plain client cannot carry attestation traffic on a non-FIPS provider | ||
| // in a `fips` build. |
| #[snafu(implicit)] | ||
| location: Location, | ||
| }, | ||
| /// Raised before any provider is dispatched, in `fips` builds whose |
| #[derive(Clone, Debug)] | ||
| pub(crate) struct AwsSdkReqwestClient(reqwest::Client); |
| // to, so a client built before the provider is installed panics with | ||
| // "No provider set". | ||
| super::ensure_crypto_provider(); | ||
| // Fail closed rather than serve traffic on a non-approved module: in `fips` |
What
Phases 1 and 2 of the internal FIPS compliance plan.
Phase 1 — make the FIPS TLS backend reachable. The feature existed on
sf_corebut no binding crate forwarded it, so it was physically unreachable from every shipped artifact. This addsfips-tls = ["sf_core/fips-tls"]passthroughs toodbc,jdbc_bridge,python_bridge, andnodejs_bridge, makessf_core's feature explicit (["rustls/fips", "aws-lc-rs/fips"]—x509_utilscallsaws_lc_rsdirectly and shouldn't rely on feature unification), removes the deadrustls-webpki 0.102dependency, and adds runtime FIPS assertion tests (try_fips_mode(),provider.fips(),ClientConfig::fips()).The feature is named
fips-tls, notfips, because it swaps the TLS backend and nothing else: JWT signing, stage file encryption, DPoP and key parsing still run on OpenSSL, which has no FIPS-validated provider — and undervendored-openssl(which our release builds pass) that unvalidated copy is statically linked where a customer cannot replace it. A build combining the two is not a FIPS artifact, and the narrow name is what keeps it from being shipped as one;fipsstays unclaimed for the complete thing after Phase 3. Acompile_error!on thefips+vendored-opensslpair was the other candidate and was rejected for a mechanical reason:--all-featuresenables both by definition, so it would break the repo's own pre-commitclippy/checkhooks and thefull_put_get_testslane.Phase 2 — eliminate non-FIPS crypto reachability in the TLS stack.
TlsConfig(no CRL checking, no version window, no custom roots, no proxy). The SDK-backing client is the newAwsSdkReqwestClientnewtype (formerlybuild_s3_reqwest_client), which applies the three SDK-owned transport adjustments (no redirects, no gzip auto-decompression, HTTP/1.1) and is the only type the SDK adapter accepts -- an unadjusted general-purpose client cannot back SigV4-signed SDK calls. In the login path it is built only when the configured WIF provider is AWS (the other providers never touch it), and it reuses the connection's shared CRL worker, threaded throughsnowflake_login_with_client/auth_request_dataas a newSharedCrlWorkerparameter, instead of spawning a per-login worker.tls::ensure_crypto_provider()—Once-guarded aws-lc provider install at the driver-constructor chokepoint and every bare client-construction site.tls::fips_mode_active()is always compiled rather than feature-gated, and reports on the installed provider (falsein a standard build). Phase 4 surfaces it through the wrappers as a customer-facing accessor, and an accessor that is absent without the feature would make "you installed the wrong artifact" indistinguishable from "your driver is too old to have it".fips-tlsbuilds:workload_identity::create_attestationrunsensure_crypto_provider()+require_fips_provider()at its entry, before any provider dispatch, surfacing a non-FIPS process-global provider as the newAttestationError::CryptoProvider— this also covers thewif_create_attestationRPC's plain client, which is not built through the TLS factories. The function is nowpub(crate)(no external callers; keeping a public wrapper would preserve exactly the ungated path this closes).rustls-tls-*-no-providerfeature variants andoauth2todefault-features = false(its defaultrustls-tlsre-armed reqwest's silent ring fallback via feature unification). rustls 0.23 is now aws-lc-only; a client built before a provider install now panics loudly instead of silently degrading toring. The trust-store composition (webpki + OS native roots) is unchanged.What this deliberately does NOT do
No release-workflow FIPS lanes are added: shipping a "FIPS" artifact before the non-TLS crypto (JWT signing, stage encryption, DPoP, key parsing) is ported off vendored OpenSSL would invite a compliance claim the code does not support.
Verification
All numbers are current as of the rebase onto
main@ 7c0ce98:cargo test -p sf_core --lib: 2084 passed / 0 failedcargo test -p sf_core --test integration_tests: 283 passed / 67 failed / 6 ignored — byte-identical failing-test list on cleanmain(re-verified post-rebase); the 67 are pre-existing env-dependent tests (dead-proxy sims, credential-requiring auth)cargo test -p sf_core --features fips-tls --lib: 2087 passed / 0 failed (the +3 are the FIPS-gated assertion tests; requires a GCC 13 toolchain foraws-lc-fips-sys 0.13.x— GCC 14+/clang 20 cannot build it, aws-lc-rs#569)cargo checkclean with and without the feature;--all-featuresstill compiles; fmt clean; clippy atmain's own warning baselinesf_core(python/Cargo.lock.sdist,tests/performance/drivers/core/app/Cargo.lock) are regenerated and passcargo metadata --lockedReview notes
-no-providerswitch means any test binary building rawreqwest::Clients must install a provider first;#[ctor]initializers insrc/lib.rs(unit tests) andtests/common/crypto_provider.rshandle this -- the latter is picked up byintegration_testsviatests/common/mod.rsand included directly bylogging_query_tests. New dev-deps:rustls,ctor.fips-tlsbuilds, TLS client construction now fails closed:tls::require_fips_provider()is called frombuild_tls_client_and_rustls_config,configure_tls_builder,AwsSdkReqwestClient::build, and the WIF attestation entry point, so afips-tlsbuild whose process-global provider is not FIPS returnsTlsError::FipsModeUnavailablethrough the normal FFI error path instead of serving traffic on a non-approved module.ensure_crypto_provider()itself still only logs, because it runs from constructors and paths with no error channel beneath an FFI boundary where unwinding is UB. Auxiliary raw clients (telemetry, CRL, IMDS) have no error channel and still rely on the logged mismatch.