Skip to main content

orbit_rustls/session/
client_v24.rs

1//! rustls 0.24 fleet-shared client-session adapter.
2
3use rustls_0_24::client::{ClientSessionKey, ClientSessionStore, Tls12Session, Tls13Session};
4use rustls_0_24::crypto::kx::NamedGroup;
5use rustls_0_24::pki_types::ServerName;
6
7use super::OrbitClientSessionStorage;
8use super::store::CLIENT_TLS13_TICKETS_PER_SERVER;
9
10const KX_HINT: u8 = 1;
11const TLS12_SESSION: u8 = 2;
12const TLS13_TICKET: u8 = 3;
13const DNS_NAME: u8 = 1;
14const IP_ADDRESS: u8 = 2;
15
16impl ClientSessionStore for OrbitClientSessionStorage {
17    fn set_kx_hint(
18        &self,
19        key: ClientSessionKey<'static>,
20        group: NamedGroup
21    ) {
22        let Some((domain, server)) = storage_key(&key, KX_HINT) else {
23            return;
24        };
25        let value = u16::from(group).to_be_bytes();
26        let _ = self.primitive.put(&domain, &server, &value, self.ttl());
27    }
28
29    fn kx_hint(
30        &self,
31        key: &ClientSessionKey<'_>
32    ) -> Option<NamedGroup> {
33        let (domain, server) = storage_key(key, KX_HINT)?;
34        let value = self.primitive.get(&domain, &server).ok()??;
35        let value: [u8; 2] = value.try_into().ok()?;
36        Some(NamedGroup::from(u16::from_be_bytes(value)))
37    }
38
39    fn set_tls12_session(
40        &self,
41        key: ClientSessionKey<'static>,
42        value: Tls12Session
43    ) {
44        let Some((domain, server)) = storage_key(&key, TLS12_SESSION) else {
45            return;
46        };
47        let mut encoded = Vec::new();
48        value.encode(&mut encoded);
49        let _ = self.primitive.put(&domain, &server, &encoded, self.ttl());
50    }
51
52    fn tls12_session(
53        &self,
54        key: &ClientSessionKey<'_>
55    ) -> Option<Tls12Session> {
56        let (domain, server) = storage_key(key, TLS12_SESSION)?;
57        let encoded = self.primitive.get(&domain, &server).ok()??;
58        match Tls12Session::from_slice(&encoded, &self.provider) {
59            Ok(value) => Some(value),
60            Err(error) => {
61                let _ = self.primitive.take(&domain, &server);
62                tracing::trace!(
63                    target: "orbit_rustls::client_session_cache",
64                    operation = "decode_tls12",
65                    %error,
66                    "discarding incompatible rustls client session"
67                );
68                None
69            }
70        }
71    }
72
73    fn remove_tls12_session(
74        &self,
75        key: &ClientSessionKey<'static>
76    ) {
77        let Some((domain, server)) = storage_key(key, TLS12_SESSION) else {
78            return;
79        };
80        let _ = self.primitive.take(&domain, &server);
81    }
82
83    fn insert_tls13_ticket(
84        &self,
85        key: ClientSessionKey<'static>,
86        value: Tls13Session
87    ) {
88        let Some((domain, server)) = storage_key(&key, TLS13_TICKET) else {
89            return;
90        };
91        let mut encoded = Vec::new();
92        value.encode(&mut encoded);
93        let _ = self.primitive.push(
94            &domain,
95            &server,
96            &encoded,
97            self.ttl(),
98            CLIENT_TLS13_TICKETS_PER_SERVER
99        );
100    }
101
102    fn take_tls13_ticket(
103        &self,
104        key: &ClientSessionKey<'static>
105    ) -> Option<Tls13Session> {
106        let (domain, server) = storage_key(key, TLS13_TICKET)?;
107        for _ in 0..CLIENT_TLS13_TICKETS_PER_SERVER {
108            let encoded = match self.primitive.take(&domain, &server) {
109                Ok(Some(encoded)) => encoded,
110                Ok(None) | Err(_) => return None
111            };
112            match Tls13Session::from_slice(&encoded, &self.provider) {
113                Ok(value) => return Some(value),
114                Err(error) => {
115                    tracing::trace!(
116                        target: "orbit_rustls::client_session_cache",
117                        operation = "decode_tls13",
118                        %error,
119                        "discarding incompatible rustls client ticket"
120                    );
121                }
122            }
123        }
124        None
125    }
126}
127
128fn storage_key(
129    key: &ClientSessionKey<'_>,
130    record: u8
131) -> Option<([u8; 33], Vec<u8>)> {
132    let mut domain = [0_u8; 33];
133    domain[0] = record;
134    domain[1..].copy_from_slice(&key.config_hash);
135
136    let mut server = Vec::new();
137    server.push(match &key.server_name {
138        ServerName::DnsName(_) => DNS_NAME,
139        ServerName::IpAddress(_) => IP_ADDRESS,
140        _ => return None
141    });
142    server.extend_from_slice(key.server_name.to_str().as_bytes());
143    Some((domain, server))
144}