diff --git a/Cargo.lock b/Cargo.lock index 2e60289a52..c82115bdf4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3423,26 +3423,23 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.21" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "once_cell", "ring", - "rustls-pki-types", "rustls-webpki", - "subtle", - "zeroize", + "sct", ] [[package]] name = "rustls-pemfile" -version = "2.2.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "rustls-pki-types", + "base64 0.21.7", ] [[package]] @@ -3453,12 +3450,11 @@ checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" [[package]] name = "rustls-webpki" -version = "0.102.8" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", - "rustls-pki-types", "untrusted", ] @@ -3480,6 +3476,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "semver" version = "1.0.25" @@ -3622,12 +3628,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - [[package]] name = "symbolic-common" version = "12.13.3" @@ -3874,9 +3874,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.1" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", @@ -4498,12 +4498,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - [[package]] name = "zerovec" version = "0.10.4" diff --git a/Cargo.toml b/Cargo.toml index 5f65dfabc5..f5c7edfdca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,10 +104,6 @@ http-body = { version = "0.4" } hyper = { version = "0.14.32", default-features = false } prost = { version = "0.12" } prost-types = { version = "0.12" } -tokio-rustls = { version = "0.26", default-features = false, features = [ - "ring", - "logging", -] } tonic = { version = "0.10", default-features = false } tonic-build = { version = "0.10", default-features = false } diff --git a/linkerd/app/integration/Cargo.toml b/linkerd/app/integration/Cargo.toml index 6b615ede73..3cea1e2e53 100644 --- a/linkerd/app/integration/Cargo.toml +++ b/linkerd/app/integration/Cargo.toml @@ -47,8 +47,8 @@ regex = "1" socket2 = "0.5" tokio = { version = "1", features = ["io-util", "net", "rt", "macros"] } tokio-stream = { version = "0.1", features = ["sync"] } -tokio-rustls = { workspace = true } -rustls-pemfile = "2.2" +tokio-rustls = "0.24" +rustls-pemfile = "1.0" tower = { version = "0.4", default-features = false } tonic = { workspace = true, features = ["transport"], default-features = false } tracing = "0.1" diff --git a/linkerd/app/integration/src/client.rs b/linkerd/app/integration/src/client.rs index 5351d1ca60..ed5c5763f3 100644 --- a/linkerd/app/integration/src/client.rs +++ b/linkerd/app/integration/src/client.rs @@ -2,7 +2,8 @@ use super::*; use linkerd_app_core::proxy::http::TracingExecutor; use parking_lot::Mutex; use std::io; -use tokio::{net::TcpStream, task::JoinHandle}; +use tokio::net::TcpStream; +use tokio::task::JoinHandle; use tokio_rustls::rustls::{self, ClientConfig}; use tracing::info_span; @@ -14,13 +15,12 @@ type Sender = mpsc::UnboundedSender<(Request, oneshot::Sender, - name: rustls::pki_types::ServerName<'static>, + name: rustls::ServerName, } impl TlsConfig { - pub fn new(client_config: Arc, name: &'static str) -> Self { - let name = - rustls::pki_types::ServerName::try_from(name).expect("name must be a valid DNS name"); + pub fn new(client_config: Arc, name: &str) -> Self { + let name = rustls::ServerName::try_from(name).expect("name must be a valid DNS name"); TlsConfig { client_config, name, diff --git a/linkerd/app/integration/src/identity.rs b/linkerd/app/integration/src/identity.rs index afc373852b..f2ba49766c 100644 --- a/linkerd/app/integration/src/identity.rs +++ b/linkerd/app/integration/src/identity.rs @@ -8,7 +8,7 @@ use std::{ }; use linkerd2_proxy_api::identity as pb; -use tokio_rustls::rustls::{self, pki_types::CertificateDer, server::WebPkiClientVerifier}; +use tokio_rustls::rustls; use tonic as grpc; pub struct Identity { @@ -36,7 +36,7 @@ type Certify = Box< static TLS_VERSIONS: &[&rustls::SupportedProtocolVersion] = &[&rustls::version::TLS13]; static TLS_SUPPORTED_CIPHERSUITES: &[rustls::SupportedCipherSuite] = - &[rustls::crypto::ring::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]; + &[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]; struct Certificates { pub leaf: Vec, @@ -50,17 +50,11 @@ impl Certificates { { let f = fs::File::open(p)?; let mut r = io::BufReader::new(f); - let mut certs = rustls_pemfile::certs(&mut r); - let leaf = certs - .next() - .expect("no leaf cert in pemfile") - .map_err(|_| io::Error::new(io::ErrorKind::Other, "rustls error reading certs"))? - .as_ref() - .to_vec(); - let intermediates = certs - .map(|cert| cert.map(|cert| cert.as_ref().to_vec())) - .collect::, _>>() + let mut certs = rustls_pemfile::certs(&mut r) .map_err(|_| io::Error::new(io::ErrorKind::Other, "rustls error reading certs"))?; + let mut certs = certs.drain(..); + let leaf = certs.next().expect("no leaf cert in pemfile"); + let intermediates = certs.collect(); Ok(Certificates { leaf, @@ -68,14 +62,11 @@ impl Certificates { }) } - pub fn chain(&self) -> Vec> { + pub fn chain(&self) -> Vec { let mut chain = Vec::with_capacity(self.intermediates.len() + 1); chain.push(self.leaf.clone()); chain.extend(self.intermediates.clone()); - chain - .into_iter() - .map(rustls::pki_types::CertificateDer::from) - .collect() + chain.into_iter().map(rustls::Certificate).collect() } pub fn response(&self) -> pb::CertifyResponse { @@ -88,49 +79,43 @@ impl Certificates { } impl Identity { - fn load_key

(p: P) -> rustls::pki_types::PrivateKeyDer<'static> + fn load_key

(p: P) -> rustls::PrivateKey where P: AsRef, { let p8 = fs::read(&p).expect("read key"); - rustls::pki_types::PrivateKeyDer::try_from(p8).expect("decode key") + rustls::PrivateKey(p8) } fn configs( trust_anchors: &str, certs: &Certificates, - key: rustls::pki_types::PrivateKeyDer<'static>, + key: rustls::PrivateKey, ) -> (Arc, Arc) { use std::io::Cursor; let mut roots = rustls::RootCertStore::empty(); - let trust_anchors = rustls_pemfile::certs(&mut Cursor::new(trust_anchors)) - .map(|bytes| bytes.map(CertificateDer::from)) - .collect::, _>>() - .expect("error parsing pemfile"); - let (added, skipped) = roots.add_parsable_certificates(trust_anchors); + let trust_anchors = + rustls_pemfile::certs(&mut Cursor::new(trust_anchors)).expect("error parsing pemfile"); + let (added, skipped) = roots.add_parsable_certificates(&trust_anchors[..]); assert_ne!(added, 0, "trust anchors must include at least one cert"); assert_eq!(skipped, 0, "no certs in pemfile should be invalid"); - let mut provider = rustls::crypto::ring::default_provider(); - provider.cipher_suites = TLS_SUPPORTED_CIPHERSUITES.to_vec(); - let provider = Arc::new(provider); - - let client_config = rustls::ClientConfig::builder_with_provider(provider.clone()) + let client_config = rustls::ClientConfig::builder() + .with_cipher_suites(TLS_SUPPORTED_CIPHERSUITES) + .with_safe_default_kx_groups() .with_protocol_versions(TLS_VERSIONS) .expect("client config must be valid") .with_root_certificates(roots.clone()) .with_no_client_auth(); - let client_cert_verifier = - WebPkiClientVerifier::builder_with_provider(Arc::new(roots), provider.clone()) - .allow_unauthenticated() - .build() - .expect("server verifier must be valid"); - - let server_config = rustls::ServerConfig::builder_with_provider(provider) + let server_config = rustls::ServerConfig::builder() + .with_cipher_suites(TLS_SUPPORTED_CIPHERSUITES) + .with_safe_default_kx_groups() .with_protocol_versions(TLS_VERSIONS) .expect("server config must be valid") - .with_client_cert_verifier(client_cert_verifier) + .with_client_cert_verifier(Arc::new( + rustls::server::AllowAnyAnonymousOrAuthenticatedClient::new(roots), + )) .with_single_cert(certs.chain(), key) .unwrap(); diff --git a/linkerd/app/outbound/Cargo.toml b/linkerd/app/outbound/Cargo.toml index cfa7103d60..36168fbc1e 100644 --- a/linkerd/app/outbound/Cargo.toml +++ b/linkerd/app/outbound/Cargo.toml @@ -56,7 +56,7 @@ futures-util = "0.3" http-body = { workspace = true } hyper = { workspace = true, features = ["backports", "deprecated", "http1", "http2"] } tokio = { version = "1", features = ["macros", "sync", "time"] } -tokio-rustls = { workspace = true } +tokio-rustls = "0.24" tokio-test = "0.4" tower-test = "0.4" diff --git a/linkerd/app/outbound/src/tls/logical/tests.rs b/linkerd/app/outbound/src/tls/logical/tests.rs index 036c3d1ae5..4bde3435c0 100644 --- a/linkerd/app/outbound/src/tls/logical/tests.rs +++ b/linkerd/app/outbound/src/tls/logical/tests.rs @@ -17,7 +17,6 @@ use std::{ time::Duration, }; use tokio::sync::watch; -use tokio_rustls::rustls::pki_types::DnsName; mod basic; @@ -172,37 +171,28 @@ fn generate_client_hello(sni: &str) -> Vec { use tokio_rustls::rustls::{ internal::msgs::{ base::Payload, - codec::{Codec, Reader}, enums::Compression, handshake::{ ClientExtension, ClientHelloPayload, HandshakeMessagePayload, HandshakePayload, - Random, ServerName, SessionId, + Random, SessionId, }, message::{MessagePayload, PlainMessage}, }, + server::DnsName, CipherSuite, ContentType, HandshakeType, ProtocolVersion, }; let sni = DnsName::try_from(sni.to_string()).unwrap(); - let sni = trim_hostname_trailing_dot_for_sni(&sni); - - let mut server_name_bytes = vec![]; - 0u8.encode(&mut server_name_bytes); // encode the type first - (sni.as_ref().len() as u16).encode(&mut server_name_bytes); // then the length as u16 - server_name_bytes.extend_from_slice(sni.as_ref().as_bytes()); // then the server name itself - - let server_name = - ServerName::read(&mut Reader::init(&server_name_bytes)).expect("Server name is valid"); let hs_payload = HandshakeMessagePayload { typ: HandshakeType::ClientHello, payload: HandshakePayload::ClientHello(ClientHelloPayload { client_version: ProtocolVersion::TLSv1_2, random: Random::from([0; 32]), - session_id: SessionId::read(&mut Reader::init(&[0])).unwrap(), + session_id: SessionId::empty(), cipher_suites: vec![CipherSuite::TLS_NULL_WITH_NULL_NULL], compression_methods: vec![Compression::Null], - extensions: vec![ClientExtension::ServerName(vec![server_name])], + extensions: vec![ClientExtension::make_sni(sni.borrow())], }), }; @@ -212,21 +202,8 @@ fn generate_client_hello(sni: &str) -> Vec { let message = PlainMessage { typ: ContentType::Handshake, version: ProtocolVersion::TLSv1_2, - payload: Payload::Owned(hs_payload_bytes), + payload: Payload(hs_payload_bytes), }; message.into_unencrypted_opaque().encode() } - -fn trim_hostname_trailing_dot_for_sni(dns_name: &DnsName<'_>) -> DnsName<'static> { - let dns_name_str = dns_name.as_ref(); - - // RFC6066: "The hostname is represented as a byte string using - // ASCII encoding without a trailing dot" - if dns_name_str.ends_with('.') { - let trimmed = &dns_name_str[0..dns_name_str.len() - 1]; - DnsName::try_from(trimmed).unwrap().to_owned() - } else { - dns_name.to_owned() - } -} diff --git a/linkerd/meshtls/rustls/Cargo.toml b/linkerd/meshtls/rustls/Cargo.toml index b13ec1455f..cb2fd01925 100644 --- a/linkerd/meshtls/rustls/Cargo.toml +++ b/linkerd/meshtls/rustls/Cargo.toml @@ -12,11 +12,11 @@ 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.102.8", features = ["std"] } +rustls-pemfile = "1.0" +rustls-webpki = { version = "0.101.5", features = ["std"] } thiserror = "2" tokio = { version = "1", features = ["macros", "rt", "sync"] } -tokio-rustls = { workspace = true } +tokio-rustls = { version = "0.24", features = ["dangerous_configuration"] } tracing = "0.1" linkerd-dns-name = { path = "../../dns/name" } diff --git a/linkerd/meshtls/rustls/src/client.rs b/linkerd/meshtls/rustls/src/client.rs index 9856d38998..962135d42d 100644 --- a/linkerd/meshtls/rustls/src/client.rs +++ b/linkerd/meshtls/rustls/src/client.rs @@ -6,7 +6,7 @@ use linkerd_stack::{NewService, Service}; use linkerd_tls::{client::AlpnProtocols, ClientTls, NegotiatedProtocolRef}; use std::{convert::TryFrom, pin::Pin, sync::Arc, task::Context}; use tokio::sync::watch; -use tokio_rustls::rustls::{self, pki_types::CertificateDer, ClientConfig}; +use tokio_rustls::rustls::{self, ClientConfig}; /// A `NewService` that produces `Connect` services from a dynamic TLS configuration. #[derive(Clone)] @@ -18,7 +18,7 @@ pub struct NewClient { #[derive(Clone)] pub struct Connect { server_id: id::Id, - server_name: rustls::pki_types::ServerName<'static>, + server_name: rustls::ServerName, config: Arc, } @@ -68,9 +68,8 @@ impl Connect { } }; - let server_name = - rustls::pki_types::ServerName::try_from(client_tls.server_name.to_string()) - .expect("identity must be a valid DNS name"); + let server_name = rustls::ServerName::try_from(client_tls.server_name.as_str()) + .expect("identity must be a valid DNS name"); Self { server_id: client_tls.server_id.into(), @@ -80,7 +79,7 @@ impl Connect { } } -fn extract_cert(c: &rustls::ClientConnection) -> io::Result<&CertificateDer<'_>> { +fn extract_cert(c: &rustls::ClientConnection) -> io::Result<&rustls::Certificate> { match c.peer_certificates().and_then(|certs| certs.first()) { Some(leaf_cert) => io::Result::Ok(leaf_cert), None => Err(io::Error::new(io::ErrorKind::Other, "missing tls end cert")), @@ -114,7 +113,7 @@ where let s = s?; let (_, conn) = s.get_ref(); let end_cert = extract_cert(conn)?; - verifier::verify_id(end_cert, &server_id)?; + verifier::verify_id(&end_cert.0, &server_id)?; Ok(ClientIo(s)) }), ) diff --git a/linkerd/meshtls/rustls/src/creds.rs b/linkerd/meshtls/rustls/src/creds.rs index cd0fe7f2c1..cd8332534e 100644 --- a/linkerd/meshtls/rustls/src/creds.rs +++ b/linkerd/meshtls/rustls/src/creds.rs @@ -10,7 +10,7 @@ use ring::error::KeyRejected; use std::sync::Arc; use thiserror::Error; use tokio::sync::watch; -use tokio_rustls::rustls::{self, crypto::CryptoProvider}; +use tokio_rustls::rustls; use tracing::warn; #[derive(Debug, Error)] @@ -27,9 +27,7 @@ pub fn watch( roots_pem: &str, ) -> Result<(Store, Receiver)> { let mut roots = rustls::RootCertStore::empty(); - let certs = match rustls_pemfile::certs(&mut std::io::Cursor::new(roots_pem)) - .collect::, _>>() - { + let certs = match rustls_pemfile::certs(&mut std::io::Cursor::new(roots_pem)) { Err(error) => { warn!(%error, "invalid trust anchors file"); return Err(error.into()); @@ -41,7 +39,7 @@ pub fn watch( Ok(certs) => certs, }; - let (added, skipped) = roots.add_parsable_certificates(certs); + let (added, skipped) = roots.add_parsable_certificates(&certs[..]); if skipped != 0 { warn!("Skipped {} invalid trust anchors", skipped); } @@ -90,12 +88,6 @@ pub fn watch( Ok((store, rx)) } -fn default_provider() -> CryptoProvider { - let mut provider = rustls::crypto::ring::default_provider(); - provider.cipher_suites = params::TLS_SUPPORTED_CIPHERSUITES.to_vec(); - provider -} - #[cfg(feature = "test-util")] pub fn for_test(ent: &linkerd_tls_test_util::Entity) -> (Store, Receiver) { watch( @@ -112,7 +104,7 @@ pub fn default_for_test() -> (Store, Receiver) { } mod params { - use tokio_rustls::rustls::{self, crypto::WebPkiSupportedAlgorithms}; + use tokio_rustls::rustls; // These must be kept in sync: pub static SIGNATURE_ALG_RING_SIGNING: &ring::signature::EcdsaSigningAlgorithm = @@ -121,14 +113,7 @@ mod params { rustls::SignatureScheme::ECDSA_NISTP256_SHA256; pub const SIGNATURE_ALG_RUSTLS_ALGORITHM: rustls::SignatureAlgorithm = rustls::SignatureAlgorithm::ECDSA; - pub static SUPPORTED_SIG_ALGS: &WebPkiSupportedAlgorithms = &WebPkiSupportedAlgorithms { - all: &[webpki::ring::ECDSA_P256_SHA256], - mapping: &[( - SIGNATURE_ALG_RUSTLS_SCHEME, - &[webpki::ring::ECDSA_P256_SHA256], - )], - }; 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]; + &[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]; } diff --git a/linkerd/meshtls/rustls/src/creds/receiver.rs b/linkerd/meshtls/rustls/src/creds/receiver.rs index fd451fbef8..1c06f87c1c 100644 --- a/linkerd/meshtls/rustls/src/creds/receiver.rs +++ b/linkerd/meshtls/rustls/src/creds/receiver.rs @@ -70,13 +70,10 @@ 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_safe_defaults() + .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 +82,10 @@ 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_safe_defaults() + .with_root_certificates(rustls::RootCertStore::empty()) + .with_no_client_auth() } #[tokio::test] diff --git a/linkerd/meshtls/rustls/src/creds/store.rs b/linkerd/meshtls/rustls/src/creds/store.rs index ee1f686a4c..b0a692856e 100644 --- a/linkerd/meshtls/rustls/src/creds/store.rs +++ b/linkerd/meshtls/rustls/src/creds/store.rs @@ -1,4 +1,5 @@ -use super::{default_provider, params::*, InvalidKey}; +use super::params::*; +use super::InvalidKey; use linkerd_dns_name as dns; use linkerd_error::Result; use linkerd_identity as id; @@ -6,12 +7,12 @@ use linkerd_meshtls_verifier as verifier; use ring::{rand, signature::EcdsaKeyPair}; use std::{convert::TryFrom, sync::Arc}; use tokio::sync::watch; -use tokio_rustls::rustls::{self, pki_types::UnixTime, server::WebPkiClientVerifier}; +use tokio_rustls::rustls; use tracing::debug; pub struct Store { roots: rustls::RootCertStore, - server_cert_verifier: Arc, + server_cert_verifier: Arc, server_id: id::Id, server_name: dns::Name, client_tx: watch::Sender>, @@ -19,16 +20,18 @@ pub struct Store { random: ring::rand::SystemRandom, } -#[derive(Clone, Debug)] +#[derive(Clone)] struct Key(Arc); -#[derive(Clone, Debug)] +#[derive(Clone)] struct CertResolver(Arc); pub(super) fn client_config_builder( - cert_verifier: Arc, + cert_verifier: Arc, ) -> rustls::ConfigBuilder { - rustls::ClientConfig::builder_with_provider(Arc::new(default_provider())) + rustls::ClientConfig::builder() + .with_cipher_suites(TLS_SUPPORTED_CIPHERSUITES) + .with_safe_default_kx_groups() .with_protocol_versions(TLS_VERSIONS) .expect("client config must be valid") // XXX: Rustls's built-in verifiers don't let us tweak things as fully @@ -41,7 +44,6 @@ pub(super) fn client_config_builder( // builder API does internally. However, we want to share the verifier // with the `Store` so that it can be used in `Store::validate` which // requires using this API. - .dangerous() .with_custom_certificate_verifier(cert_verifier) } @@ -55,15 +57,12 @@ pub(super) fn server_config( // controlling the set of trusted signature algorithms), but they provide good enough // defaults for now. // TODO: lock down the verification further. - let provider = Arc::new(default_provider()); - - let client_cert_verifier = - WebPkiClientVerifier::builder_with_provider(Arc::new(roots), provider.clone()) - .allow_unauthenticated() - .build() - .expect("server verifier must be valid"); - - rustls::ServerConfig::builder_with_provider(provider) + let client_cert_verifier = Arc::new( + rustls::server::AllowAnyAnonymousOrAuthenticatedClient::new(roots), + ); + rustls::ServerConfig::builder() + .with_cipher_suites(TLS_SUPPORTED_CIPHERSUITES) + .with_safe_default_kx_groups() .with_protocol_versions(TLS_VERSIONS) .expect("server config must be valid") .with_client_cert_verifier(client_cert_verifier) @@ -77,7 +76,7 @@ impl Store { #[allow(clippy::too_many_arguments)] pub(super) fn new( roots: rustls::RootCertStore, - server_cert_verifier: Arc, + server_cert_verifier: Arc, server_id: id::Id, server_name: dns::Name, client_tx: watch::Sender>, @@ -108,23 +107,25 @@ impl Store { /// Ensures the certificate is valid for the services we terminate for TLS. This assumes that /// server cert validation does the same or more validation than client cert validation. - fn validate(&self, certs: &[rustls::pki_types::CertificateDer<'_>]) -> Result<()> { - let name = rustls::pki_types::ServerName::try_from(self.server_name.as_str()) + fn validate(&self, certs: &[rustls::Certificate]) -> Result<()> { + let name = rustls::ServerName::try_from(self.server_name.as_str()) .expect("server name must be a valid DNS name"); static NO_OCSP: &[u8] = &[]; let end_entity = &certs[0]; let intermediates = &certs[1..]; - let now = UnixTime::now(); + let no_scts = &mut std::iter::empty(); + let now = std::time::SystemTime::now(); self.server_cert_verifier.verify_server_cert( end_entity, intermediates, &name, + no_scts, NO_OCSP, now, )?; // verify the id as the cert verifier does not do that (on purpose) - verifier::verify_id(end_entity, &self.server_id).map_err(Into::into) + verifier::verify_id(&end_entity.0, &self.server_id).map_err(Into::into) } } impl id::Credentials for Store { @@ -137,11 +138,11 @@ impl id::Credentials for Store { _expiry: std::time::SystemTime, ) -> Result<()> { let mut chain = Vec::with_capacity(intermediates.len() + 1); - chain.push(rustls::pki_types::CertificateDer::from(leaf)); + chain.push(rustls::Certificate(leaf)); chain.extend( intermediates .into_iter() - .map(|id::DerX509(der)| rustls::pki_types::CertificateDer::from(der)), + .map(|id::DerX509(der)| rustls::Certificate(der)), ); // Use the client's verifier to validate the certificate for our local name. diff --git a/linkerd/meshtls/rustls/src/creds/verify.rs b/linkerd/meshtls/rustls/src/creds/verify.rs index 42adeb75e2..be7058bf57 100644 --- a/linkerd/meshtls/rustls/src/creds/verify.rs +++ b/linkerd/meshtls/rustls/src/creds/verify.rs @@ -1,34 +1,26 @@ -use crate::creds::params::SUPPORTED_SIG_ALGS; -use std::{convert::TryFrom, sync::Arc}; +use std::convert::TryFrom; +use std::sync::Arc; +use std::time::SystemTime; use tokio_rustls::rustls::{ self, - client::{ - self, - danger::{ServerCertVerified, ServerCertVerifier}, - }, - pki_types::{CertificateDer, ServerName, UnixTime}, + client::{self, ServerCertVerified, ServerCertVerifier}, server::ParsedCertificate, - RootCertStore, + Certificate, RootCertStore, ServerName, }; use tracing::trace; -#[derive(Debug)] -pub(crate) struct AnySanVerifier { - roots: Arc, -} +pub(crate) struct AnySanVerifier(Arc); impl AnySanVerifier { pub(crate) fn new(roots: impl Into>) -> Self { - Self { - roots: roots.into(), - } + Self(roots.into()) } } -// This is derived from `rustls::client::WebPkiServerVerifier`. +// This is derived from `rustls::client::WebPkiVerifier`. // // Copyright (c) 2016, Joseph Birr-Pixton -// https://github.com/rustls/rustls/blob/v/0.23.15/rustls/src/webpki/server_verifier.rs#L134 +// https://github.com/rustls/rustls/blob/ccb79947a4811412ee7dcddcd0f51ea56bccf101/rustls/src/webpki/server_verifier.rs#L239 // // The only difference is that we omit the step that performs // DNS SAN validation. The reason for that stems from the fact that @@ -40,21 +32,16 @@ impl ServerCertVerifier for AnySanVerifier { /// - Not Expired fn verify_server_cert( &self, - end_entity: &CertificateDer<'_>, - intermediates: &[CertificateDer<'_>], - _: &ServerName<'_>, + end_entity: &Certificate, + intermediates: &[Certificate], + _: &ServerName, + _: &mut dyn Iterator, ocsp_response: &[u8], - now: UnixTime, + now: SystemTime, ) -> Result { let cert = ParsedCertificate::try_from(end_entity)?; - client::verify_server_cert_signed_by_trust_anchor( - &cert, - &self.roots, - intermediates, - now, - SUPPORTED_SIG_ALGS.all, - )?; + client::verify_server_cert_signed_by_trust_anchor(&cert, &self.0, intermediates, now)?; if !ocsp_response.is_empty() { trace!("Unvalidated OCSP response: {ocsp_response:?}"); @@ -62,26 +49,4 @@ impl ServerCertVerifier for AnySanVerifier { Ok(ServerCertVerified::assertion()) } - - fn verify_tls12_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &rustls::DigitallySignedStruct, - ) -> Result { - tokio_rustls::rustls::crypto::verify_tls12_signature(message, cert, dss, SUPPORTED_SIG_ALGS) - } - - fn verify_tls13_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &rustls::DigitallySignedStruct, - ) -> Result { - tokio_rustls::rustls::crypto::verify_tls13_signature(message, cert, dss, SUPPORTED_SIG_ALGS) - } - - fn supported_verify_schemes(&self) -> Vec { - SUPPORTED_SIG_ALGS.supported_schemes() - } } diff --git a/linkerd/meshtls/rustls/src/server.rs b/linkerd/meshtls/rustls/src/server.rs index 844830e1ee..cac87589f7 100644 --- a/linkerd/meshtls/rustls/src/server.rs +++ b/linkerd/meshtls/rustls/src/server.rs @@ -7,7 +7,7 @@ use linkerd_tls::{ClientId, NegotiatedProtocol, NegotiatedProtocolRef, ServerNam use std::{pin::Pin, sync::Arc, task::Context}; use thiserror::Error; use tokio::sync::watch; -use tokio_rustls::rustls::{pki_types::CertificateDer, ServerConfig}; +use tokio_rustls::rustls::{Certificate, ServerConfig}; use tracing::debug; /// A Service that terminates TLS connections using a dynamically updated server configuration. @@ -129,7 +129,7 @@ where fn client_identity(tls: &tokio_rustls::server::TlsStream) -> Option { let (_io, session) = tls.get_ref(); let certs = session.peer_certificates()?; - let c = certs.first().map(CertificateDer::as_ref)?; + let c = certs.first().map(Certificate::as_ref)?; verifier::client_identity(c).map(ClientId) }