1use crate::tls::client::config::{
2 AllowedTlsVersionsConfig, CertificateVerificationConfig, CryptoProviderConfig, RootCertificate,
3 RootCertificateFileEncoding,
4};
5
6use super::TlsClientPolicyConfig;
7use anyhow::{Context, bail, ensure};
8use rustls::{
9 ClientConfig, Error as TlsError, RootCertStore, SupportedProtocolVersion,
10 client::{
11 WebPkiServerVerifier,
12 danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
13 },
14 crypto::CryptoProvider,
15 pki_types::{
16 CertificateDer, ServerName,
17 pem::{PemObject, SectionKind},
18 },
19 version::{TLS12, TLS13},
20};
21use std::sync::Arc;
22
23impl TryFrom<&TlsClientPolicyConfig> for ClientConfig {
24 type Error = Rustls023ConfigError;
25
26 fn try_from(value: &TlsClientPolicyConfig) -> Result<Self, Self::Error> {
27 value.rustls_0_23_config()
28 }
29}
30
31#[derive(Debug, thiserror::Error)]
32#[error(transparent)]
33pub struct Rustls023ConfigError(anyhow::Error);
36
37impl TlsClientPolicyConfig {
38 pub fn rustls_0_23_config(&self) -> Result<ClientConfig, Rustls023ConfigError> {
40 fn _config(policy: &TlsClientPolicyConfig) -> Result<ClientConfig, anyhow::Error> {
41 let provider = Arc::new(crypto_provider(&policy.crypto_provider)?);
42 let builder = ClientConfig::builder_with_provider(provider.clone())
43 .with_protocol_versions(supported_versions(policy.allowed_versions)?)?;
44
45 let config = if policy.insecure.skip_verification {
46 builder
47 .dangerous()
48 .with_custom_certificate_verifier(Arc::new(NoVerify { provider }))
49 } else {
50 let certificate_verifier =
51 certificate_verifier(provider, &policy.certificate_verification)?;
52 builder
53 .dangerous()
54 .with_custom_certificate_verifier(certificate_verifier)
55 }
56 .with_no_client_auth();
57
58 Ok(config)
59 }
60
61 _config(self).map_err(Rustls023ConfigError)
62 }
63}
64
65fn crypto_provider(p: &CryptoProviderConfig) -> Result<CryptoProvider, anyhow::Error> {
66 match p {
67 #[cfg(not(feature = "tls_crypto_provider_aws_lc_rs"))]
68 CryptoProviderConfig::AwsLcRs => {
69 bail!(
70 "Your TLS client configuration wants to use `aws_lc_rs` as its cryptography stack, but the corresponding `cargo` feature is not enabled.\n\
71 Add `tls_crypto_provider_aws_lc_rs` to the `features` array for `pavex` in your Cargo.toml manifest."
72 );
73 }
74 #[cfg(feature = "tls_crypto_provider_aws_lc_rs")]
75 CryptoProviderConfig::AwsLcRs => Ok(rustls::crypto::aws_lc_rs::default_provider()),
76 #[cfg(feature = "tls_crypto_provider_aws_lc_rs")]
77 CryptoProviderConfig::AwsLcRsFips => {
78 let prov = rustls::crypto::aws_lc_rs::default_provider();
79
80 if !prov.fips() {
81 bail!(
82 "FIPS requested but the `fips` feature is not enabled. Add `fips` to the `features` array for `pavex` in your Cargo.toml manifest."
83 );
84 }
85 Ok(prov)
86 }
87 #[cfg(not(feature = "tls_crypto_provider_aws_lc_rs"))]
88 CryptoProviderConfig::AwsLcRsFips => {
89 bail!(
90 "Your TLS client configuration wants to use `aws_lc_rs_fips` as its cryptography stack, but the corresponding `cargo` feature is not enabled.\n\
91 Add `tls_crypto_provider_aws_lc_rs` and `fips` to the `features` array for `pavex` in your Cargo.toml manifest."
92 );
93 }
94 #[cfg(feature = "tls_crypto_provider_ring")]
95 CryptoProviderConfig::Ring => Ok(rustls::crypto::ring::default_provider()),
96 #[cfg(not(feature = "tls_crypto_provider_ring"))]
97 CryptoProviderConfig::Ring => bail!(
98 "Your TLS client configuration wants to use `ring` as its cryptography stack, but the corresponding `cargo` feature is not enabled.\n\
99 Add `tls_crypto_provider_ring` to the `features` array for `pavex` in your Cargo.toml manifest."
100 ),
101 }
102}
103
104fn certificate_verifier(
105 crypto_provider: Arc<CryptoProvider>,
106 config: &CertificateVerificationConfig,
107) -> Result<Arc<dyn ServerCertVerifier>, anyhow::Error> {
108 if !config.use_os_verifier && config.additional_roots.is_empty() {
109 anyhow::bail!(
110 "You disabled OS server certificate verification without providing a list of additional root certificates to trust.\n\
111 This configuration is invalid: it would cause **all** TLS connections to fail.\n\
112 Please enable OS certificate verification or provide a list of root certificates to trust. Check out the documentation \
113 of `pavex::tls::client::CertificateVerificationConfig` for more information."
114 )
115 }
116 let additional_roots = additional_roots(&config.additional_roots)?;
117 if config.use_os_verifier {
118 let verifier = rustls_platform_verifier::Verifier::new_with_extra_roots(
119 additional_roots,
120 crypto_provider,
121 )
122 .context("Failed to initialize the server certificate verifier")?;
123 Ok(Arc::new(verifier))
124 } else {
125 let mut root_cert_store = RootCertStore::empty();
126 for root in additional_roots {
127 root_cert_store
128 .add(root)
129 .context("One of your additional root certificates is invalid")?;
130 }
131 let verifier =
132 WebPkiServerVerifier::builder_with_provider(Arc::new(root_cert_store), crypto_provider)
133 .build()
134 .context("Failed to initialize the server certificate verifier")?;
135 Ok(verifier)
136 }
137}
138
139fn supported_versions(
140 config: AllowedTlsVersionsConfig,
141) -> Result<&'static [&'static SupportedProtocolVersion], anyhow::Error> {
142 static ALL: [&SupportedProtocolVersion; 2] = [&TLS12, &TLS13];
143 static ONLY_TLS12: [&SupportedProtocolVersion; 1] = [&TLS12];
144 static ONLY_TLS13: [&SupportedProtocolVersion; 1] = [&TLS13];
145
146 match (config.v1_2, config.v1_3) {
147 (true, true) => Ok(&ALL),
148 (true, false) => Ok(&ONLY_TLS12),
149 (false, true) => Ok(&ONLY_TLS13),
150 (false, false) => {
151 bail!("You disabled both TLS 1.2 and TLS 1.3. At least one of them must be enabled.");
152 }
153 }
154}
155
156fn additional_roots(
157 root_sources: &[RootCertificate],
158) -> Result<Vec<CertificateDer<'static>>, anyhow::Error> {
159 let mut roots = Vec::with_capacity(root_sources.len());
160 for (i, source) in root_sources.iter().enumerate() {
161 parse_additional_root(&mut roots, source).with_context(|| {
162 format!(
163 "Failed to parse the root certificate at index {i} in your list of `additional_roots`",
164 )
165 })?;
166 }
167 Ok(roots)
168}
169
170fn parse_additional_root(
171 roots: &mut Vec<CertificateDer<'static>>,
172 source: &RootCertificate,
173) -> Result<(), anyhow::Error> {
174 match source {
175 RootCertificate::File { encoding, path } => {
176 let contents = fs_err::read(path).context("Failed to read root certificate file")?;
177 match encoding {
178 RootCertificateFileEncoding::Der => {
179 roots.push(CertificateDer::from(contents));
180 }
181 RootCertificateFileEncoding::Pem => {
182 roots.extend(parse_certificates_from_pem_bytes(&contents)?);
183 }
184 }
185 }
186 RootCertificate::Inline { data } => {
187 roots.extend(parse_certificates_from_pem_bytes(data.as_bytes())?);
188 }
189 }
190 Ok(())
191}
192
193fn parse_certificates_from_pem_bytes(
194 data: &[u8],
195) -> Result<Vec<CertificateDer<'static>>, anyhow::Error> {
196 let mut certs = Vec::new();
197 for outcome in <(SectionKind, Vec<u8>) as PemObject>::pem_slice_iter(data) {
198 let (section_kind, section_data) =
199 outcome.context("Failed to parse a section of your PEM-encoded root certificate")?;
200 if section_kind != SectionKind::Certificate {
201 anyhow::bail!(
202 "Expected a PEM-encoded root certificate, but found a {} section",
203 kind2str(section_kind)
204 )
205 }
206 certs.push(CertificateDer::from(section_data));
207 }
208 ensure!(
209 !certs.is_empty(),
210 "Your PEM bundle doesn't contain any root certificate. There should be at least one `BEGIN CERTIFICATE` block"
211 );
212 Ok(certs)
213}
214
215fn kind2str(kind: SectionKind) -> &'static str {
216 match kind {
217 SectionKind::Certificate => "CERTIFICATE",
218 SectionKind::PublicKey => "PUBLIC KEY",
219 SectionKind::RsaPrivateKey => "RSA PRIVATE KEY",
220 SectionKind::PrivateKey => "PRIVATE KEY",
221 SectionKind::EcPrivateKey => "EC PRIVATE KEY",
222 SectionKind::Crl => "X509 CRL",
223 SectionKind::Csr => "CERTIFICATE REQUEST",
224 SectionKind::EchConfigList => "ECHCONFIG",
225 _ => "unknown",
226 }
227}
228
229#[derive(Debug, Clone)]
230struct NoVerify {
232 provider: Arc<CryptoProvider>,
233}
234
235impl ServerCertVerifier for NoVerify {
236 fn verify_tls12_signature(
237 &self,
238 _message: &[u8],
239 _cert: &CertificateDer<'_>,
240 _dss: &rustls::DigitallySignedStruct,
241 ) -> std::result::Result<rustls::client::danger::HandshakeSignatureValid, TlsError> {
242 Ok(HandshakeSignatureValid::assertion())
243 }
244
245 fn verify_tls13_signature(
246 &self,
247 _message: &[u8],
248 _cert: &CertificateDer<'_>,
249 _dss: &rustls::DigitallySignedStruct,
250 ) -> std::result::Result<rustls::client::danger::HandshakeSignatureValid, TlsError> {
251 Ok(HandshakeSignatureValid::assertion())
252 }
253
254 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
255 self.provider
256 .signature_verification_algorithms
257 .supported_schemes()
258 }
259
260 fn verify_server_cert(
261 &self,
262 _end_entity: &CertificateDer<'_>,
263 _intermediates: &[CertificateDer<'_>],
264 _server_name: &ServerName<'_>,
265 _ocsp_response: &[u8],
266 _now: rustls::pki_types::UnixTime,
267 ) -> std::result::Result<ServerCertVerified, TlsError> {
268 Ok(ServerCertVerified::assertion())
269 }
270}