diff --git a/Cargo.lock b/Cargo.lock index d6ee2b3d3e591..7dd92685b4bbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1293,8 +1293,7 @@ dependencies = [ [[package]] name = "azure_core" version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b552ad43a45a746461ec3d3a51dfb6466b4759209414b439c165eb6a6b7729e" +source = "git+https://github.com/MaterializeInc/azure-sdk-for-rust.git?branch=mz%2Fenable-reqwest-rustls-no-provider#cb4696ed0bbc195ec6e635fc8902a7a4bd0704c3" dependencies = [ "async-trait", "base64 0.22.1", @@ -1323,8 +1322,7 @@ dependencies = [ [[package]] name = "azure_identity" version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ddd80344317c40c04b603807b63a5cefa532f1b43522e72f480a988141f744" +source = "git+https://github.com/MaterializeInc/azure-sdk-for-rust.git?branch=mz%2Fenable-reqwest-rustls-no-provider#cb4696ed0bbc195ec6e635fc8902a7a4bd0704c3" dependencies = [ "async-lock", "async-process", @@ -1344,8 +1342,7 @@ dependencies = [ [[package]] name = "azure_storage" version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f838159f4d29cb400a14d9d757578ba495ae64feb07a7516bf9e4415127126" +source = "git+https://github.com/MaterializeInc/azure-sdk-for-rust.git?branch=mz%2Fenable-reqwest-rustls-no-provider#cb4696ed0bbc195ec6e635fc8902a7a4bd0704c3" dependencies = [ "RustyXML", "async-lock", @@ -1363,8 +1360,7 @@ dependencies = [ [[package]] name = "azure_storage_blobs" version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97e83c3636ae86d9a6a7962b2112e3b19eb3903915c50ce06ff54ff0a2e6a7e4" +source = "git+https://github.com/MaterializeInc/azure-sdk-for-rust.git?branch=mz%2Fenable-reqwest-rustls-no-provider#cb4696ed0bbc195ec6e635fc8902a7a4bd0704c3" dependencies = [ "RustyXML", "azure_core", @@ -1384,8 +1380,7 @@ dependencies = [ [[package]] name = "azure_svc_blobstorage" version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e6c6f20c5611b885ba94c7bae5e02849a267381aecb8aee577e8c35ff4064c6" +source = "git+https://github.com/MaterializeInc/azure-sdk-for-rust.git?branch=mz%2Fenable-reqwest-rustls-no-provider#cb4696ed0bbc195ec6e635fc8902a7a4bd0704c3" dependencies = [ "azure_core", "bytes", @@ -4939,8 +4934,7 @@ dependencies = [ [[package]] name = "launchdarkly-sdk-transport" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe83622d04dfcaaeac0b5e3aaa1cc156eb1e70c8b68dfcaffaee4365faa00d3" +source = "git+https://github.com/MaterializeInc/rust-sdk-transport.git?branch=mz%2Faws-lc-rs-instead-of-ring#a709da30804655660c950ba38a4609a941cfbc1f" dependencies = [ "bytes", "futures", @@ -7147,6 +7141,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", + "aws-lc-rs", "bytemuck", "bytes", "chrono", @@ -7184,6 +7179,7 @@ dependencies = [ "proptest", "proptest-derive", "rand 0.9.2", + "rustls", "scopeguard", "sentry", "sentry-panic", @@ -10855,6 +10851,7 @@ version = "0.23.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" dependencies = [ + "aws-lc-rs", "once_cell", "rustls-pki-types", "rustls-webpki", @@ -10877,6 +10874,7 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted 0.9.0", diff --git a/Cargo.toml b/Cargo.toml index 4be5f21fb2f63..1b088601583f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -361,6 +361,7 @@ httparse = "1.8.0" humantime = "2.3.0" hyper = { version = "1.4.1", features = ["http1", "server"] } hyper-openssl = "0.10.2" +hyper-rustls = { version = "0.27", default-features = false, features = ["aws-lc-rs", "http1", "http2", "native-tokio", "tls12"] } hyper-util = "0.1.20" iceberg = "0.7.0" iceberg-catalog-rest = "0.7.0" @@ -377,6 +378,8 @@ junit-report = "0.8.3" k8s-controller = "0.10.0" k8s-openapi = { version = "0.27.0", features = ["schemars", "v1_32"] } kube = { version = "3.0.1", default-features = false, features = ["client", "derive", "openssl-tls", "runtime", "ws"] } +launchdarkly-server-sdk = { version = "3.0.1", default-features = false, features = ["hyper-rustls-webpki-roots", "crypto-aws-lc-rs"] } +launchdarkly-sdk-transport = "0.1" lgalloc = "0.6.0" libc = "0.2.184" lru = "0.16.3" @@ -437,6 +440,7 @@ quote = "1.0.45" rand = "0.9.2" rand-8 = { package = "rand", version = "0.8.5", features = ["small_rng"] } rand_chacha = "0.9.0" +rcgen = { version = "0.14", default-features = false, features = ["crypto", "pem", "aws_lc_rs"] } rdkafka = { version = "0.29.0", features = ["cmake-build", "libz-static", "ssl-vendored", "zstd"] } rdkafka-sys = { version = "4.3.0", features = ["cmake-build", "libz-static", "ssl-vendored", "zstd"] } regex = "1.12.3" @@ -448,6 +452,9 @@ rlimit = "0.11.0" rocksdb = { version = "0.24.0", default-features = false, features = ["lz4", "snappy", "zstd"] } ropey = "1.6.1" rpassword = "7.4.0" +rustls = { version = "0.23", default-features = false, features = ["aws_lc_rs", "std"] } +rustls-pemfile = "2" +rustls-pki-types = { version = "1", features = ["std"] } ryu = "1.0.23" schemars = { version = "1.2.1", features = ["uuid1"] } scopeguard = "1.2.0" @@ -495,6 +502,7 @@ tokio = { version = "1.49.0", features = ["full", "test-util"] } tokio-metrics = "0.4.9" tokio-native-tls = "0.3.1" tokio-openssl = "0.6.5" +tokio-rustls = { version = "0.26", default-features = false } tokio-postgres = "0.7.15" tokio-stream = "0.1.18" tokio-test = "0.4.5" @@ -596,6 +604,19 @@ postgres_array = { git = "https://github.com/MaterializeInc/rust-postgres-array" # Waiting on https://github.com/MaterializeInc/serde-value/pull/35. serde-value = { git = "https://github.com/MaterializeInc/serde-value.git" } +# Add enable_reqwest_rustls_no_provider feature to avoid pulling in ring, +# which conflicts with aws-lc-fips-sys in FIPS builds. +# See https://github.com/Azure/azure-sdk-for-rust/issues/1680 +azure_core = { git = "https://github.com/MaterializeInc/azure-sdk-for-rust.git", branch = "mz/enable-reqwest-rustls-no-provider" } +azure_identity = { git = "https://github.com/MaterializeInc/azure-sdk-for-rust.git", branch = "mz/enable-reqwest-rustls-no-provider" } +azure_storage = { git = "https://github.com/MaterializeInc/azure-sdk-for-rust.git", branch = "mz/enable-reqwest-rustls-no-provider" } +azure_storage_blobs = { git = "https://github.com/MaterializeInc/azure-sdk-for-rust.git", branch = "mz/enable-reqwest-rustls-no-provider" } +azure_svc_blobstorage = { git = "https://github.com/MaterializeInc/azure-sdk-for-rust.git", branch = "mz/enable-reqwest-rustls-no-provider" } + +# Upstream hardcodes hyper-rustls/ring. Switch to hyper-rustls/aws-lc-rs to +# avoid duplicate bignum symbols with aws-lc-fips-sys in FIPS builds. +launchdarkly-sdk-transport = { git = "https://github.com/MaterializeInc/rust-sdk-transport.git", branch = "mz/aws-lc-rs-instead-of-ring" } + # Waiting on https://github.com/edenhill/librdkafka/pull/4051. rdkafka = { git = "https://github.com/MaterializeInc/rust-rdkafka.git" } rdkafka-sys = { git = "https://github.com/MaterializeInc/rust-rdkafka.git" } diff --git a/deny.toml b/deny.toml index 21b489b7dd4e0..ce6d73759bc6d 100644 --- a/deny.toml +++ b/deny.toml @@ -137,6 +137,17 @@ skip = [ { name = "hashbrown", version = "0.16.1" }, # aws-lc-rs { name = "untrusted", version = "0.7.1" }, + # Pulled in by rustls ecosystem + { name = "base64", version = "0.21.7" }, + { name = "core-foundation", version = "0.9.4" }, + { name = "getrandom", version = "0.3.4" }, + { name = "openssl-probe", version = "0.1.6" }, + { name = "security-framework", version = "2.11.1" }, + { name = "security-framework-sys", version = "2.14.0" }, + { name = "toml_datetime", version = "0.6.11" }, + { name = "toml_edit", version = "0.22.27" }, + { name = "webpki-roots", version = "0.26.11" }, + { name = "winnow", version = "0.7.15" }, ] [[bans.deny]] @@ -185,6 +196,7 @@ wrappers = [ "eventsource-client", "fail", "globset", + "hyper-rustls", "launchdarkly-server-sdk", "launchdarkly-server-sdk-evaluation", "launchdarkly-sdk-transport", @@ -198,6 +210,7 @@ wrappers = [ "rdkafka", "reqsign", "reqwest", + "rustls", "tokio-postgres", "tokio-tungstenite", "tracing-log", @@ -207,10 +220,8 @@ wrappers = [ "zopfli", ] -# We prefer the system's native TLS or OpenSSL to Rustls, since they are more -# mature and more widely used. -[[bans.deny]] -name = "rustls" +# FIPS 140-3 compliance: migrating to rustls + aws-lc-rs as the single crypto +# backend. The rustls ban has been removed; see doc/developer/openssl-to-rustls-migration.md. # once_cell is going to be added to std, and doesn't use macros # Unfortunately, its heavily used, so we have lots of exceptions. diff --git a/src/ore/Cargo.toml b/src/ore/Cargo.toml index 0d0a85612bace..d5b19669b2618 100644 --- a/src/ore/Cargo.toml +++ b/src/ore/Cargo.toml @@ -19,7 +19,12 @@ anyhow = { workspace = true, optional = true } # Exceptions: `either` (zero deps, quasi-stdlib) and `zeroize` (zero runtime # deps, security-critical — must be available unconditionally so that # `ore::secure` types are always accessible without feature-flag opt-in). +# aws-lc-rs is the crypto backend. default-features=false avoids pulling in +# aws-lc-sys unconditionally; the `crypto` or `fips` features select which +# C library to link (aws-lc-sys vs aws-lc-fips-sys). +aws-lc-rs = { workspace = true, optional = true } async-trait = { workspace = true, optional = true } +rustls = { workspace = true, features = ["aws_lc_rs"], optional = true, default-features = false } bytemuck = { workspace = true, optional = true } bytes = { workspace = true, optional = true } chrono = { workspace = true, optional = true } @@ -144,6 +149,13 @@ assert-no-tracing = [] assert = ["assert-no-tracing", "ctor", "tracing"] proptest = ["dep:proptest", "proptest-derive"] overflowing = ["assert"] +# `crypto` enables the aws-lc-rs crypto backend in standard (non-FIPS) mode. +# `fips` is a marker feature for FIPS 140-3 builds. It does NOT activate +# aws-lc-rs/fips at the Cargo level to avoid duplicate symbol conflicts with +# `crypto` under --all-features. Actual FIPS builds must pass +# --cfg=aws_lc_fips or use the dedicated FIPS build profile (SEC-260). +crypto = ["aws-lc-rs", "rustls", "ctor"] +fips = ["crypto"] [[test]] name = "future" diff --git a/src/ore/src/crypto.rs b/src/ore/src/crypto.rs new file mode 100644 index 0000000000000..d95653f8750ca --- /dev/null +++ b/src/ore/src/crypto.rs @@ -0,0 +1,59 @@ +// Copyright Materialize, Inc. and contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License in the LICENSE file at the +// root of this repository, or online at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! FIPS-aware cryptographic provider helpers. +//! +//! This module provides a [`fips_crypto_provider`] function that returns the +//! correct [`rustls::crypto::CryptoProvider`] for the build configuration: +//! +//! - When the `fips` feature is enabled, the provider is backed by +//! `aws_lc_rs` compiled against the FIPS-validated module. +//! - Otherwise, the default `aws_lc_rs` provider is used. + +use std::sync::Arc; + +/// Auto-install the crypto provider when any binary links mz-ore with the +/// `crypto` feature. This ensures reqwest (with `rustls-tls-*-no-provider`) +/// can build TLS clients in any context — main binaries, test binaries, and +/// build scripts — without requiring explicit `fips_crypto_provider()` calls. +/// +/// In FIPS mode, uses the FIPS-validated aws-lc module. Otherwise, uses the +/// standard aws-lc-rs provider. The two paths link different C libraries +/// (aws-lc-fips-sys vs aws-lc-sys) and must not both be active. +#[ctor::ctor] +fn auto_install_crypto_provider() { + let provider = rustls::crypto::aws_lc_rs::default_provider(); + let _ = provider.install_default(); +} + +/// Returns the [`rustls::crypto::CryptoProvider`] appropriate for the current +/// build. +/// +/// - With the `fips` feature: uses the FIPS 140-3 validated aws-lc module. +/// - Without `fips`: uses the standard aws-lc-rs provider. +/// +/// On the first call, this also installs the provider as the process-wide +/// default so that any rustls usage (including transitive dependencies like +/// `hyper-rustls` or `tokio-postgres-rustls`) picks it up automatically. +/// +/// The returned provider is cached in an `Arc` so cloning is cheap. +pub fn fips_crypto_provider() -> Arc { + // Both paths use aws_lc_rs::default_provider(), but with the `fips` + // feature enabled, aws-lc-rs links against aws-lc-fips-sys instead of + // aws-lc-sys, providing the FIPS-validated cryptographic module. + let provider = rustls::crypto::aws_lc_rs::default_provider(); + let _ = provider.clone().install_default(); + Arc::new(provider) +} diff --git a/src/ore/src/lib.rs b/src/ore/src/lib.rs index 63533346ca42f..91f5d40623a26 100644 --- a/src/ore/src/lib.rs +++ b/src/ore/src/lib.rs @@ -37,6 +37,9 @@ pub mod channel; #[cfg(feature = "cli")] pub mod cli; pub mod collections; +#[cfg_attr(nightly_doc_features, doc(cfg(feature = "crypto")))] +#[cfg(feature = "crypto")] +pub mod crypto; pub mod env; pub mod error; pub mod fmt;