rustls/client/
handy.rs

1use core::hash::Hasher;
2
3use super::{ClientSessionKey, CredentialRequest};
4use crate::client;
5use crate::crypto::SelectedCredential;
6use crate::crypto::kx::NamedGroup;
7use crate::enums::CertificateType;
8use crate::msgs::persist;
9
10/// An implementer of `ClientSessionStore` which does nothing.
11#[derive(Debug)]
12pub(super) struct NoClientSessionStorage;
13
14impl client::ClientSessionStore for NoClientSessionStorage {
15    fn set_kx_hint(&self, _: ClientSessionKey<'static>, _: NamedGroup) {}
16
17    fn kx_hint(&self, _: &ClientSessionKey<'_>) -> Option<NamedGroup> {
18        None
19    }
20
21    fn set_tls12_session(&self, _: ClientSessionKey<'static>, _: persist::Tls12ClientSessionValue) {
22    }
23
24    fn tls12_session(&self, _: &ClientSessionKey<'_>) -> Option<persist::Tls12ClientSessionValue> {
25        None
26    }
27
28    fn remove_tls12_session(&self, _: &ClientSessionKey<'_>) {}
29
30    fn insert_tls13_ticket(
31        &self,
32        _: ClientSessionKey<'static>,
33        _: persist::Tls13ClientSessionValue,
34    ) {
35    }
36
37    fn take_tls13_ticket(
38        &self,
39        _: &ClientSessionKey<'_>,
40    ) -> Option<persist::Tls13ClientSessionValue> {
41        None
42    }
43}
44
45#[cfg(any(feature = "std", feature = "hashbrown"))]
46mod cache {
47    use alloc::collections::VecDeque;
48    use core::fmt;
49
50    use super::ClientSessionKey;
51    use crate::crypto::kx::NamedGroup;
52    use crate::limited_cache;
53    use crate::lock::Mutex;
54    use crate::msgs::persist;
55
56    const MAX_TLS13_TICKETS_PER_SERVER: usize = 8;
57
58    struct ServerData {
59        kx_hint: Option<NamedGroup>,
60
61        // Zero or one TLS1.2 sessions.
62        tls12: Option<persist::Tls12ClientSessionValue>,
63
64        // Up to MAX_TLS13_TICKETS_PER_SERVER TLS1.3 tickets, oldest first.
65        tls13: VecDeque<persist::Tls13ClientSessionValue>,
66    }
67
68    impl Default for ServerData {
69        fn default() -> Self {
70            Self {
71                kx_hint: None,
72                tls12: None,
73                tls13: VecDeque::with_capacity(MAX_TLS13_TICKETS_PER_SERVER),
74            }
75        }
76    }
77
78    /// An implementer of `ClientSessionStore` that stores everything
79    /// in memory.
80    ///
81    /// It enforces a limit on the number of entries to bound memory usage.
82    pub struct ClientSessionMemoryCache {
83        servers: Mutex<limited_cache::LimitedCache<ClientSessionKey<'static>, ServerData>>,
84    }
85
86    impl ClientSessionMemoryCache {
87        /// Make a new ClientSessionMemoryCache.  `size` is the
88        /// maximum number of stored sessions.
89        #[cfg(feature = "std")]
90        pub fn new(size: usize) -> Self {
91            let max_servers = size.saturating_add(MAX_TLS13_TICKETS_PER_SERVER - 1)
92                / MAX_TLS13_TICKETS_PER_SERVER;
93            Self {
94                servers: Mutex::new(limited_cache::LimitedCache::new(max_servers)),
95            }
96        }
97
98        /// Make a new ClientSessionMemoryCache.  `size` is the
99        /// maximum number of stored sessions.
100        #[cfg(not(feature = "std"))]
101        pub fn new<M: crate::lock::MakeMutex>(size: usize) -> Self {
102            let max_servers = size.saturating_add(MAX_TLS13_TICKETS_PER_SERVER - 1)
103                / MAX_TLS13_TICKETS_PER_SERVER;
104            Self {
105                servers: Mutex::new::<M>(limited_cache::LimitedCache::new(max_servers)),
106            }
107        }
108    }
109
110    impl super::client::ClientSessionStore for ClientSessionMemoryCache {
111        fn set_kx_hint(&self, key: ClientSessionKey<'static>, group: NamedGroup) {
112            self.servers
113                .lock()
114                .unwrap()
115                .get_or_insert_default_and_edit(key, |data| data.kx_hint = Some(group));
116        }
117
118        fn kx_hint(&self, key: &ClientSessionKey<'_>) -> Option<NamedGroup> {
119            self.servers
120                .lock()
121                .unwrap()
122                .get(key)
123                .and_then(|sd| sd.kx_hint)
124        }
125
126        fn set_tls12_session(
127            &self,
128            key: ClientSessionKey<'static>,
129            value: persist::Tls12ClientSessionValue,
130        ) {
131            self.servers
132                .lock()
133                .unwrap()
134                .get_or_insert_default_and_edit(key.clone(), |data| data.tls12 = Some(value));
135        }
136
137        fn tls12_session(
138            &self,
139            key: &ClientSessionKey<'_>,
140        ) -> Option<persist::Tls12ClientSessionValue> {
141            self.servers
142                .lock()
143                .unwrap()
144                .get(key)
145                .and_then(|sd| sd.tls12.as_ref().cloned())
146        }
147
148        fn remove_tls12_session(&self, key: &ClientSessionKey<'static>) {
149            self.servers
150                .lock()
151                .unwrap()
152                .get_mut(key)
153                .and_then(|data| data.tls12.take());
154        }
155
156        fn insert_tls13_ticket(
157            &self,
158            key: ClientSessionKey<'static>,
159            value: persist::Tls13ClientSessionValue,
160        ) {
161            self.servers
162                .lock()
163                .unwrap()
164                .get_or_insert_default_and_edit(key.clone(), |data| {
165                    if data.tls13.len() == data.tls13.capacity() {
166                        data.tls13.pop_front();
167                    }
168                    data.tls13.push_back(value);
169                });
170        }
171
172        fn take_tls13_ticket(
173            &self,
174            key: &ClientSessionKey<'static>,
175        ) -> Option<persist::Tls13ClientSessionValue> {
176            self.servers
177                .lock()
178                .unwrap()
179                .get_mut(key)
180                .and_then(|data| data.tls13.pop_back())
181        }
182    }
183
184    impl fmt::Debug for ClientSessionMemoryCache {
185        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186            // Note: we omit self.servers as it may contain sensitive data.
187            f.debug_struct("ClientSessionMemoryCache")
188                .finish()
189        }
190    }
191}
192
193#[cfg(any(feature = "std", feature = "hashbrown"))]
194pub use cache::ClientSessionMemoryCache;
195
196#[derive(Debug)]
197pub(super) struct FailResolveClientCert {}
198
199impl client::ClientCredentialResolver for FailResolveClientCert {
200    fn resolve(&self, _: &CredentialRequest<'_>) -> Option<SelectedCredential> {
201        None
202    }
203
204    fn supported_certificate_types(&self) -> &'static [CertificateType] {
205        &[]
206    }
207
208    fn hash_config(&self, _: &mut dyn Hasher) {}
209}
210
211#[cfg(test)]
212mod tests {
213    use core::time::Duration;
214    use std::prelude::v1::*;
215
216    use pki_types::{CertificateDer, ServerName, UnixTime};
217
218    use super::NoClientSessionStorage;
219    use crate::TEST_PROVIDERS;
220    use crate::client::{ClientSessionKey, ClientSessionStore};
221    use crate::crypto::kx::NamedGroup;
222    use crate::crypto::{CertificateIdentity, CipherSuite, Identity, tls12_suite, tls13_suite};
223    use crate::msgs::base::PayloadU16;
224    use crate::msgs::handshake::SessionId;
225    use crate::msgs::persist::{Tls12ClientSessionValue, Tls13ClientSessionValue};
226    use crate::sync::Arc;
227
228    #[test]
229    fn test_noclientsessionstorage_does_nothing() {
230        let c = NoClientSessionStorage {};
231        let server_name = ServerName::try_from("example.com").unwrap();
232        let key = ClientSessionKey {
233            config_hash: Default::default(),
234            server_name,
235        };
236        let now = UnixTime::now();
237
238        c.set_kx_hint(key.clone(), NamedGroup::X25519);
239        assert_eq!(None, c.kx_hint(&key));
240
241        for provider in TEST_PROVIDERS {
242            {
243                c.set_tls12_session(
244                    key.clone(),
245                    Tls12ClientSessionValue::new(
246                        tls12_suite(
247                            CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
248                            provider,
249                        ),
250                        SessionId::empty(),
251                        Arc::new(PayloadU16::empty()),
252                        &[0u8; 48],
253                        Identity::X509(CertificateIdentity {
254                            end_entity: CertificateDer::from(&[][..]),
255                            intermediates: Vec::new(),
256                        }),
257                        now,
258                        Duration::ZERO,
259                        true,
260                    ),
261                );
262                assert!(c.tls12_session(&key).is_none());
263                c.remove_tls12_session(&key);
264            }
265
266            c.insert_tls13_ticket(
267                key.clone(),
268                Tls13ClientSessionValue::new(
269                    tls13_suite(CipherSuite::TLS13_AES_256_GCM_SHA384, provider),
270                    Arc::new(PayloadU16::empty()),
271                    &[],
272                    Identity::X509(CertificateIdentity {
273                        end_entity: CertificateDer::from(&[][..]),
274                        intermediates: Vec::new(),
275                    }),
276                    now,
277                    Duration::ZERO,
278                    0,
279                    0,
280                ),
281            );
282
283            assert!(c.take_tls13_ticket(&key).is_none());
284        }
285    }
286}