Skip to main content

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