feat(meshtls): Add aws-lc-rs as optional rustls backend (#3883)

This has a few benefits. Primarily this gives us a reasonable path to creating FIPS-enabled builds on architectures other than x86-64, as well as a path away from using BoringSSL as a backend.

Additionally, rustls has been using the aws-lc-rs library as the default backend for a little while now, so this gives us the opportunity to stay in line with the most widely used option in the ecosystem.

Signed-off-by: Scott Fleener <scott@buoyant.io>
This commit is contained in:
Scott Fleener 2025-04-28 08:38:40 -04:00 committed by GitHub
parent b4fb4277d4
commit 577a67b2c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 277 additions and 65 deletions

View File

@ -170,6 +170,44 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "aws-lc-fips-sys"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d9c2e952a1f57e8cbc78b058a968639e70c4ce8b9c0a5e6363d4e5670eed795"
dependencies = [
"bindgen 0.69.5",
"cc",
"cmake",
"dunce",
"fs_extra",
"regex",
]
[[package]]
name = "aws-lc-rs"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b756939cb2f8dc900aa6dcd505e6e2428e9cae7ff7b028c49e3946efa70878"
dependencies = [
"aws-lc-fips-sys",
"aws-lc-sys",
"zeroize",
]
[[package]]
name = "aws-lc-sys"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa9b6986f250236c27e5a204062434a773a13243d2ffc2955f37bdba4c5c6a1"
dependencies = [
"bindgen 0.69.5",
"cc",
"cmake",
"dunce",
"fs_extra",
]
[[package]]
name = "axum"
version = "0.7.9"
@ -244,6 +282,29 @@ version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
[[package]]
name = "bindgen"
version = "0.69.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
dependencies = [
"bitflags 2.4.2",
"cexpr",
"clang-sys",
"itertools",
"lazy_static",
"lazycell",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
"which",
]
[[package]]
name = "bindgen"
version = "0.70.1"
@ -303,7 +364,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c9a2a6a85b9cdadd64a1856ac5632afe0816518e20aadd372f4e4172aa94e2a"
dependencies = [
"autocfg",
"bindgen",
"bindgen 0.70.1",
"cmake",
"fs_extra",
"fslock",
@ -537,6 +598,12 @@ version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04"
[[package]]
name = "dunce"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
name = "either"
version = "1.15.0"
@ -972,6 +1039,15 @@ dependencies = [
"tracing",
]
[[package]]
name = "home"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "hostname"
version = "0.4.1"
@ -1399,6 +1475,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.172"
@ -3721,6 +3803,7 @@ version = "0.23.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0"
dependencies = [
"aws-lc-rs",
"log",
"once_cell",
"ring",
@ -3751,6 +3834,7 @@ version = "0.103.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03"
dependencies = [
"aws-lc-rs",
"ring",
"rustls-pki-types",
"untrusted",
@ -4555,6 +4639,18 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix 0.38.44",
]
[[package]]
name = "widestring"
version = "1.2.0"
@ -4671,6 +4767,15 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.48.5"

View File

@ -29,6 +29,14 @@ exceptions = [
"MIT",
"OpenSSL",
], name = "ring", version = "*" },
{ allow = [
"ISC",
"OpenSSL",
], name = "aws-lc-sys", version = "*" },
{ allow = [
"ISC",
"OpenSSL",
], name = "aws-lc-fips-sys", version = "*" },
]
[[licenses.clarify]]
@ -66,6 +74,8 @@ skip-tree = [
{ name = "rustix", version = "0.38" },
# `pprof` uses a number of old dependencies. for now, we skip its subtree.
{ name = "pprof" },
# aws-lc-rs uses a slightly outdated version of bindgen
{ name = "bindgen", version = "0.69.5" },
]
[sources]

View File

@ -8,6 +8,9 @@ publish = { workspace = true }
[features]
rustls = ["linkerd-meshtls-rustls", "__has_any_tls_impls"]
rustls-aws-lc = ["rustls", "linkerd-meshtls-rustls/aws-lc"]
rustls-aws-lc-fips = ["rustls-aws-lc", "linkerd-meshtls-rustls/aws-lc-fips"]
rustls-ring = ["rustls", "linkerd-meshtls-rustls/ring"]
boring = ["linkerd-meshtls-boring", "__has_any_tls_impls"]
boring-fips = ["boring", "linkerd-meshtls-boring/fips"]
# Enabled if *any* TLS impl is enabled.

View File

@ -7,13 +7,17 @@ edition = "2018"
publish = { workspace = true }
[features]
default = ["ring"]
ring = ["tokio-rustls/ring", "rustls-webpki/ring"]
aws-lc = ["tokio-rustls/aws-lc-rs", "rustls-webpki/aws-lc-rs"]
aws-lc-fips = ["aws-lc", "tokio-rustls/fips"]
test-util = ["linkerd-tls-test-util"]
[dependencies]
futures = { version = "0.3", default-features = false }
ring = { version = "0.17", features = ["std"] }
rustls-pemfile = "2.2"
rustls-webpki = { version = "0.103.1", features = ["std"] }
rustls-webpki = { version = "0.103.1", default-features = false, features = ["std"] }
thiserror = "2"
tokio = { version = "1", features = ["macros", "rt", "sync"] }
tokio-rustls = { workspace = true }

View File

@ -0,0 +1,11 @@
#[cfg(feature = "aws-lc")]
mod aws_lc;
#[cfg(feature = "ring")]
mod ring;
#[cfg(feature = "aws-lc")]
pub use aws_lc::{default_provider, SUPPORTED_SIG_ALGS, TLS_SUPPORTED_CIPHERSUITES};
#[cfg(all(not(feature = "aws-lc"), feature = "ring"))]
pub use ring::{default_provider, SUPPORTED_SIG_ALGS, TLS_SUPPORTED_CIPHERSUITES};
#[cfg(all(not(feature = "aws-lc"), not(feature = "ring")))]
compile_error!("No rustls backend enabled. Enabled one of the \"ring\" or \"aws-lc\" features");

View File

@ -0,0 +1,63 @@
pub use aws_lc_rs::default_provider;
use tokio_rustls::rustls::{
self,
crypto::{aws_lc_rs, WebPkiSupportedAlgorithms},
};
pub static TLS_SUPPORTED_CIPHERSUITES: &[rustls::SupportedCipherSuite] =
&[rustls::crypto::aws_lc_rs::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256];
pub static SUPPORTED_SIG_ALGS: &WebPkiSupportedAlgorithms = &WebPkiSupportedAlgorithms {
all: &[
webpki::aws_lc_rs::ECDSA_P256_SHA256,
webpki::aws_lc_rs::ECDSA_P256_SHA384,
webpki::aws_lc_rs::ECDSA_P384_SHA256,
webpki::aws_lc_rs::ECDSA_P384_SHA384,
webpki::aws_lc_rs::ECDSA_P521_SHA256,
webpki::aws_lc_rs::ECDSA_P521_SHA384,
webpki::aws_lc_rs::ECDSA_P521_SHA512,
webpki::aws_lc_rs::ED25519,
webpki::aws_lc_rs::RSA_PKCS1_2048_8192_SHA256,
webpki::aws_lc_rs::RSA_PKCS1_2048_8192_SHA384,
webpki::aws_lc_rs::RSA_PKCS1_2048_8192_SHA512,
webpki::aws_lc_rs::RSA_PKCS1_3072_8192_SHA384,
],
mapping: &[
// Note: for TLS1.2 the curve is not fixed by SignatureScheme. For TLS1.3 it is.
(
rustls::SignatureScheme::ECDSA_NISTP384_SHA384,
&[
webpki::aws_lc_rs::ECDSA_P384_SHA384,
webpki::aws_lc_rs::ECDSA_P256_SHA384,
webpki::aws_lc_rs::ECDSA_P521_SHA384,
],
),
(
rustls::SignatureScheme::ECDSA_NISTP256_SHA256,
&[
webpki::aws_lc_rs::ECDSA_P256_SHA256,
webpki::aws_lc_rs::ECDSA_P384_SHA256,
webpki::aws_lc_rs::ECDSA_P521_SHA256,
],
),
(
rustls::SignatureScheme::ECDSA_NISTP521_SHA512,
&[webpki::aws_lc_rs::ECDSA_P521_SHA512],
),
(
rustls::SignatureScheme::ED25519,
&[webpki::aws_lc_rs::ED25519],
),
(
rustls::SignatureScheme::RSA_PKCS1_SHA512,
&[webpki::aws_lc_rs::RSA_PKCS1_2048_8192_SHA512],
),
(
rustls::SignatureScheme::RSA_PKCS1_SHA384,
&[webpki::aws_lc_rs::RSA_PKCS1_2048_8192_SHA384],
),
(
rustls::SignatureScheme::RSA_PKCS1_SHA256,
&[webpki::aws_lc_rs::RSA_PKCS1_2048_8192_SHA256],
),
],
};

View File

@ -0,0 +1,52 @@
pub use ring::default_provider;
use tokio_rustls::rustls::{
self,
crypto::{ring, WebPkiSupportedAlgorithms},
};
pub static TLS_SUPPORTED_CIPHERSUITES: &[rustls::SupportedCipherSuite] =
&[rustls::crypto::ring::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256];
// A subset of the algorithms supported by rustls+ring, imported from
// https://github.com/rustls/rustls/blob/v/0.23.21/rustls/src/crypto/ring/mod.rs#L107
pub static SUPPORTED_SIG_ALGS: &WebPkiSupportedAlgorithms = &WebPkiSupportedAlgorithms {
all: &[
webpki::ring::ECDSA_P256_SHA256,
webpki::ring::ECDSA_P256_SHA384,
webpki::ring::ECDSA_P384_SHA256,
webpki::ring::ECDSA_P384_SHA384,
webpki::ring::ED25519,
webpki::ring::RSA_PKCS1_2048_8192_SHA256,
webpki::ring::RSA_PKCS1_2048_8192_SHA384,
webpki::ring::RSA_PKCS1_2048_8192_SHA512,
webpki::ring::RSA_PKCS1_3072_8192_SHA384,
],
mapping: &[
(
rustls::SignatureScheme::ECDSA_NISTP384_SHA384,
&[
webpki::ring::ECDSA_P384_SHA384,
webpki::ring::ECDSA_P256_SHA384,
],
),
(
rustls::SignatureScheme::ECDSA_NISTP256_SHA256,
&[
webpki::ring::ECDSA_P256_SHA256,
webpki::ring::ECDSA_P384_SHA256,
],
),
(rustls::SignatureScheme::ED25519, &[webpki::ring::ED25519]),
(
rustls::SignatureScheme::RSA_PKCS1_SHA512,
&[webpki::ring::RSA_PKCS1_2048_8192_SHA512],
),
(
rustls::SignatureScheme::RSA_PKCS1_SHA384,
&[webpki::ring::RSA_PKCS1_2048_8192_SHA384],
),
(
rustls::SignatureScheme::RSA_PKCS1_SHA256,
&[webpki::ring::RSA_PKCS1_2048_8192_SHA256],
),
],
};

View File

@ -2,6 +2,8 @@ mod receiver;
mod store;
pub(crate) mod verify;
use crate::backend;
pub use self::{receiver::Receiver, store::Store};
use linkerd_dns_name as dns;
use linkerd_error::Result;
@ -91,7 +93,7 @@ pub fn watch(
}
fn default_provider() -> CryptoProvider {
let mut provider = rustls::crypto::ring::default_provider();
let mut provider = backend::default_provider();
provider.cipher_suites = params::TLS_SUPPORTED_CIPHERSUITES.to_vec();
provider
}
@ -112,6 +114,7 @@ pub fn default_for_test() -> (Store, Receiver) {
}
mod params {
use crate::backend;
use tokio_rustls::rustls::{self, crypto::WebPkiSupportedAlgorithms};
// These must be kept in sync:
@ -121,51 +124,8 @@ mod params {
rustls::SignatureScheme::ECDSA_NISTP256_SHA256;
pub const SIGNATURE_ALG_RUSTLS_ALGORITHM: rustls::SignatureAlgorithm =
rustls::SignatureAlgorithm::ECDSA;
// A subset of the algorithms supported by rustls+ring, imported from
// https://github.com/rustls/rustls/blob/v/0.23.21/rustls/src/crypto/ring/mod.rs#L107
pub static SUPPORTED_SIG_ALGS: &WebPkiSupportedAlgorithms = &WebPkiSupportedAlgorithms {
all: &[
webpki::ring::ECDSA_P256_SHA256,
webpki::ring::ECDSA_P256_SHA384,
webpki::ring::ECDSA_P384_SHA256,
webpki::ring::ECDSA_P384_SHA384,
webpki::ring::ED25519,
webpki::ring::RSA_PKCS1_2048_8192_SHA256,
webpki::ring::RSA_PKCS1_2048_8192_SHA384,
webpki::ring::RSA_PKCS1_2048_8192_SHA512,
webpki::ring::RSA_PKCS1_3072_8192_SHA384,
],
mapping: &[
(
rustls::SignatureScheme::ECDSA_NISTP384_SHA384,
&[
webpki::ring::ECDSA_P384_SHA384,
webpki::ring::ECDSA_P256_SHA384,
],
),
(
rustls::SignatureScheme::ECDSA_NISTP256_SHA256,
&[
webpki::ring::ECDSA_P256_SHA256,
webpki::ring::ECDSA_P384_SHA256,
],
),
(rustls::SignatureScheme::ED25519, &[webpki::ring::ED25519]),
(
rustls::SignatureScheme::RSA_PKCS1_SHA512,
&[webpki::ring::RSA_PKCS1_2048_8192_SHA512],
),
(
rustls::SignatureScheme::RSA_PKCS1_SHA384,
&[webpki::ring::RSA_PKCS1_2048_8192_SHA384],
),
(
rustls::SignatureScheme::RSA_PKCS1_SHA256,
&[webpki::ring::RSA_PKCS1_2048_8192_SHA256],
),
],
};
pub static SUPPORTED_SIG_ALGS: &WebPkiSupportedAlgorithms = backend::SUPPORTED_SIG_ALGS;
pub static TLS_VERSIONS: &[&rustls::SupportedProtocolVersion] = &[&rustls::version::TLS13];
pub static TLS_SUPPORTED_CIPHERSUITES: &[rustls::SupportedCipherSuite] =
&[rustls::crypto::ring::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256];
backend::TLS_SUPPORTED_CIPHERSUITES;
}

View File

@ -70,13 +70,11 @@ mod tests {
/// incoming handshakes, but that doesn't matter for these tests, where we
/// don't actually do any TLS.
fn empty_server_config() -> rustls::ServerConfig {
rustls::ServerConfig::builder_with_provider(Arc::new(
rustls::crypto::ring::default_provider(),
))
.with_protocol_versions(rustls::ALL_VERSIONS)
.expect("client config must be valid")
.with_client_cert_verifier(Arc::new(rustls::server::NoClientAuth))
.with_cert_resolver(Arc::new(rustls::server::ResolvesServerCertUsingSni::new()))
rustls::ServerConfig::builder_with_provider(Arc::new(crate::backend::default_provider()))
.with_protocol_versions(rustls::ALL_VERSIONS)
.expect("client config must be valid")
.with_client_cert_verifier(Arc::new(rustls::server::NoClientAuth))
.with_cert_resolver(Arc::new(rustls::server::ResolvesServerCertUsingSni::new()))
}
/// Returns the simplest default rustls client config.
@ -85,13 +83,11 @@ mod tests {
/// it doesn't trust any root certificates. However, that doesn't actually
/// matter for these tests, which don't actually do TLS.
fn empty_client_config() -> rustls::ClientConfig {
rustls::ClientConfig::builder_with_provider(Arc::new(
rustls::crypto::ring::default_provider(),
))
.with_protocol_versions(rustls::ALL_VERSIONS)
.expect("client config must be valid")
.with_root_certificates(rustls::RootCertStore::empty())
.with_no_client_auth()
rustls::ClientConfig::builder_with_provider(Arc::new(crate::backend::default_provider()))
.with_protocol_versions(rustls::ALL_VERSIONS)
.expect("client config must be valid")
.with_root_certificates(rustls::RootCertStore::empty())
.with_no_client_auth()
}
#[tokio::test]

View File

@ -1,6 +1,7 @@
#![deny(rust_2018_idioms, clippy::disallowed_methods, clippy::disallowed_types)]
#![forbid(unsafe_code)]
mod backend;
mod client;
pub mod creds;
mod server;

View File

@ -8,10 +8,12 @@ publish = { workspace = true }
description = "The main proxy executable"
[features]
default = ["meshtls-rustls"]
default = ["meshtls-rustls-ring"]
meshtls-boring = ["linkerd-meshtls/boring"]
meshtls-boring-fips = ["linkerd-meshtls/boring-fips"]
meshtls-rustls = ["linkerd-meshtls/rustls"]
meshtls-rustls-aws-lc = ["linkerd-meshtls/rustls-aws-lc"]
meshtls-rustls-aws-lc-fips = ["linkerd-meshtls/rustls-aws-lc-fips"]
meshtls-rustls-ring = ["linkerd-meshtls/rustls-ring"]
log-streaming = ["linkerd-app/log-streaming"]
pprof = ["linkerd-app/pprof"]

View File

@ -6,7 +6,12 @@
// Emit a compile-time error if no TLS implementations are enabled. When adding
// new implementations, add their feature flags here!
#[cfg(not(any(feature = "meshtls-boring", feature = "meshtls-rustls")))]
#[cfg(not(any(
feature = "meshtls-boring",
feature = "meshtls-rustls-ring",
feature = "meshtls-rustls-aws-lc",
feature = "meshtls-rustls-aws-lc-fips"
)))]
compile_error!(
"at least one of the following TLS implementations must be enabled: 'meshtls-boring', 'meshtls-rustls'"
);