aws_smithy_http_client/client/
tls.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5use crate::cfg::{cfg_rustls, cfg_s2n_tls};
6use crate::HttpClientError;
7
8/// Choice of underlying cryptography library
9#[derive(Debug, Eq, PartialEq, Clone)]
10#[non_exhaustive]
11pub enum Provider {
12    #[cfg(any(
13        feature = "rustls-aws-lc",
14        feature = "rustls-aws-lc-fips",
15        feature = "rustls-ring"
16    ))]
17    /// TLS provider based on [rustls](https://github.com/rustls/rustls)
18    Rustls(rustls_provider::CryptoMode),
19    /// TLS provider based on [s2n-tls](https://github.com/aws/s2n-tls)
20    #[cfg(feature = "s2n-tls")]
21    S2nTls,
22}
23
24/// TLS related configuration object
25#[derive(Debug, Clone)]
26pub struct TlsContext {
27    #[allow(unused)]
28    trust_store: TrustStore,
29}
30
31impl TlsContext {
32    /// Create a new [TlsContext] builder
33    pub fn builder() -> TlsContextBuilder {
34        TlsContextBuilder::new()
35    }
36}
37
38impl Default for TlsContext {
39    fn default() -> Self {
40        TlsContext::builder().build().expect("valid default config")
41    }
42}
43
44/// Builder for TLS related configuration
45#[derive(Debug)]
46pub struct TlsContextBuilder {
47    trust_store: TrustStore,
48}
49
50impl TlsContextBuilder {
51    fn new() -> Self {
52        TlsContextBuilder {
53            trust_store: TrustStore::default(),
54        }
55    }
56
57    /// Configure the trust store to use for the TLS context
58    pub fn with_trust_store(mut self, trust_store: TrustStore) -> Self {
59        self.trust_store = trust_store;
60        self
61    }
62
63    /// Build a new [TlsContext]
64    pub fn build(self) -> Result<TlsContext, HttpClientError> {
65        Ok(TlsContext {
66            trust_store: self.trust_store,
67        })
68    }
69}
70
71/// PEM encoded certificate
72#[allow(unused)]
73#[derive(Debug, Clone)]
74struct CertificatePEM(Vec<u8>);
75
76impl From<&[u8]> for CertificatePEM {
77    fn from(value: &[u8]) -> Self {
78        CertificatePEM(value.to_vec())
79    }
80}
81
82/// Container for root certificates able to provide a root-of-trust for connection authentication
83///
84/// Platform native root certificates are enabled by default. To start with a clean trust
85/// store use [TrustStore::empty]
86#[derive(Debug, Clone)]
87pub struct TrustStore {
88    enable_native_roots: bool,
89    custom_certs: Vec<CertificatePEM>,
90}
91
92impl TrustStore {
93    /// Create a new empty trust store
94    pub fn empty() -> Self {
95        Self {
96            enable_native_roots: false,
97            custom_certs: Vec::new(),
98        }
99    }
100
101    /// Enable or disable using the platform's native trusted root certificate store
102    ///
103    /// Default: true
104    pub fn with_native_roots(mut self, enable_native_roots: bool) -> Self {
105        self.enable_native_roots = enable_native_roots;
106        self
107    }
108
109    /// Add the PEM encoded certificate to the trust store
110    ///
111    /// This may be called more than once to add multiple certificates.
112    /// NOTE: PEM certificate contents are not validated until passed to the configured
113    /// TLS provider.
114    pub fn with_pem_certificate(mut self, pem_bytes: impl Into<Vec<u8>>) -> Self {
115        // ideally we'd validate here but rustls-pki-types converts to DER when loading and S2N
116        // still expects PEM encoding. Store the raw bytes and let the TLS implementation validate
117        self.custom_certs.push(CertificatePEM(pem_bytes.into()));
118        self
119    }
120
121    /// Add the PEM encoded certificate to the trust store
122    ///
123    /// This may be called more than once to add multiple certificates.
124    /// NOTE: PEM certificate contents are not validated until passed to the configured
125    /// TLS provider.
126    pub fn add_pem_certificate(&mut self, pem_bytes: impl Into<Vec<u8>>) -> &mut Self {
127        self.custom_certs.push(CertificatePEM(pem_bytes.into()));
128        self
129    }
130}
131
132impl Default for TrustStore {
133    fn default() -> Self {
134        Self {
135            enable_native_roots: true,
136            custom_certs: Vec::new(),
137        }
138    }
139}
140
141cfg_rustls! {
142    /// rustls based support and adapters
143    pub mod rustls_provider;
144}
145
146cfg_s2n_tls! {
147    /// s2n-tls based support and adapters
148    pub(crate) mod s2n_tls_provider;
149}