1use crate::crypto::{
6 CryptoError, CryptoProvider, CryptoSession, DirectionalKeys, HeaderKey, KeyChange, Keys, Level, NextSecrets, PacketKey,
7};
8use crate::error::TransportError;
9use simoom_tls::crypto::{rng, sha2::HashAlg};
10use simoom_tls::quic as tq;
11#[cfg(feature = "client")]
12use simoom_tls::ClientConfig;
13use simoom_tls::ServerConfig;
14use std::sync::Arc;
15
16struct Pk(tq::PacketKey);
17
18impl PacketKey for Pk {
19 fn seal(&self, pn: u64, header: &[u8], payload: &mut [u8], tag: &mut [u8]) {
20 let t: &mut [u8; 16] = tag.try_into().expect("16-byte tag");
21 self.0.seal_in_place(pn, header, payload, t);
22 }
23 fn open(&self, pn: u64, header: &[u8], payload_and_tag: &mut [u8]) -> Result<usize, ()> {
24 self.0.open_in_place(pn, header, payload_and_tag).map(|p| p.len()).map_err(|_| ())
25 }
26 fn tag_len(&self) -> usize {
27 self.0.tag_len()
28 }
29 fn confidentiality_limit(&self) -> u64 {
30 self.0.confidentiality_limit()
31 }
32 fn integrity_limit(&self) -> u64 {
33 self.0.integrity_limit()
34 }
35}
36
37struct Hk(tq::HeaderProtectionKey);
38
39impl HeaderKey for Hk {
40 fn mask(&self, sample: &[u8]) -> [u8; 5] {
41 self.0.mask(sample)
42 }
43}
44
45struct Ns(tq::Secrets);
46
47impl NextSecrets for Ns {
48 fn next_packet_keys(&mut self) -> (Box<dyn PacketKey>, Box<dyn PacketKey>) {
49 let (l, r) = self.0.next_packet_keys();
50 (Box::new(Pk(l)), Box::new(Pk(r)))
51 }
52}
53
54fn dir(k: tq::DirectionalKeys) -> DirectionalKeys {
55 DirectionalKeys { packet: Box::new(Pk(k.packet)), header: Box::new(Hk(k.header)) }
56}
57
58fn keys(k: tq::Keys) -> Keys {
59 Keys { local: dir(k.local), remote: dir(k.remote) }
60}
61
62fn level(l: Level) -> simoom_tls::Level {
63 match l {
64 Level::Initial => simoom_tls::Level::Initial,
65 Level::Handshake => simoom_tls::Level::Handshake,
66 Level::OneRtt => simoom_tls::Level::OneRtt,
67 }
68}
69
70struct Session(tq::QuicConnection);
71
72impl CryptoSession for Session {
73 fn read_handshake(&mut self, l: Level, data: &[u8]) -> Result<(), CryptoError> {
74 self.0.read_handshake(level(l), data).map_err(|e| CryptoError {
75 alert: e.alert().unwrap_or(simoom_tls::alert::INTERNAL_ERROR),
76 reason: "TLS handshake failed",
77 })
78 }
79 fn write_handshake(&mut self, out: &mut Vec<u8>) -> Option<KeyChange> {
80 Some(match self.0.write_handshake(out)? {
81 tq::KeyChange::Handshake { keys: k } => KeyChange::Handshake { keys: keys(k) },
82 tq::KeyChange::OneRtt { keys: k, next } => KeyChange::OneRtt { keys: keys(k), next: Box::new(Ns(next)) },
83 })
84 }
85 fn peer_transport_params(&self) -> Option<&[u8]> {
86 self.0.peer_transport_params()
87 }
88 fn alpn_protocol(&self) -> Option<&[u8]> {
89 self.0.alpn_protocol()
90 }
91 fn is_handshaking(&self) -> bool {
92 self.0.is_handshaking()
93 }
94 fn set_version(&mut self, version: u32) {
95 self.0.set_version(version);
96 }
97 fn server_name(&self) -> Option<&str> {
98 self.0.server_name()
99 }
100 fn cipher_suite(&self) -> Option<u16> {
101 self.0.negotiated_cipher_suite().map(|s| s.id())
102 }
103 fn peer_certificates(&self) -> &[Vec<u8>] {
104 self.0.peer_certificates()
105 }
106}
107
108#[cfg(feature = "client")]
111type StartClient = fn(&Arc<ClientConfig>, u32, &str, Vec<u8>) -> Result<Box<dyn CryptoSession>, TransportError>;
112
113pub struct TlsProvider {
118 pub server: Option<Arc<ServerConfig>>,
119 #[cfg(feature = "client")]
120 pub client: Option<Arc<ClientConfig>>,
121 #[cfg(feature = "client")]
122 start_client: Option<StartClient>,
123}
124
125#[cfg(feature = "client")]
126fn start_client(cfg: &Arc<ClientConfig>, version: u32, name: &str, tp: Vec<u8>) -> Result<Box<dyn CryptoSession>, TransportError> {
127 let mut c = tq::QuicConnection::new_client(cfg.clone(), name, tp)
128 .map_err(|_| TransportError::new(crate::error::INTERNAL_ERROR, "TLS client configuration rejected"))?;
129 c.set_version(version);
130 Ok(Box::new(Session(c)))
131}
132
133impl TlsProvider {
134 pub fn server(cfg: Arc<ServerConfig>) -> Self {
135 TlsProvider {
136 server: Some(cfg),
137 #[cfg(feature = "client")]
138 client: None,
139 #[cfg(feature = "client")]
140 start_client: None,
141 }
142 }
143 #[cfg(feature = "client")]
144 pub fn client(cfg: Arc<ClientConfig>) -> Self {
145 TlsProvider { server: None, client: None, start_client: None }.with_client(cfg)
146 }
147 #[cfg(feature = "client")]
149 pub fn with_client(mut self, cfg: Arc<ClientConfig>) -> Self {
150 self.client = Some(cfg);
151 self.start_client = Some(start_client);
152 self
153 }
154}
155
156impl CryptoProvider for TlsProvider {
157 fn initial_keys(&self, version: u32, dcid: &[u8], is_server: bool) -> Keys {
158 keys(tq::initial_keys(version, dcid, is_server))
159 }
160 fn retry_tag(&self, version: u32, pseudo: &[u8]) -> [u8; 16] {
161 let n = pseudo[0] as usize;
162 tq::retry_integrity_tag(version, &pseudo[1..1 + n], &pseudo[1 + n..])
163 }
164 fn hmac(&self, key: &[u8; 32], parts: &[&[u8]]) -> [u8; 32] {
165 let out = HashAlg::Sha256.hmac(key, parts);
166 out[..32].try_into().unwrap()
167 }
168 fn fill_random(&self, buf: &mut [u8]) {
169 rng::fill(buf);
170 }
171 fn server_session(&self, version: u32, tp: Vec<u8>) -> Result<Box<dyn CryptoSession>, TransportError> {
172 let cfg = self.server.clone().ok_or(TransportError::new(crate::error::INTERNAL_ERROR, "no TLS server configuration"))?;
173 let mut c = tq::QuicConnection::new_server(cfg, tp);
174 c.set_version(version);
175 Ok(Box::new(Session(c)))
176 }
177 fn client_session(&self, version: u32, name: &str, tp: Vec<u8>) -> Result<Box<dyn CryptoSession>, TransportError> {
178 #[cfg(feature = "client")]
179 if let (Some(cfg), Some(start)) = (&self.client, self.start_client) {
180 return start(cfg, version, name, tp);
181 }
182 let _ = (version, name, tp);
183 Err(TransportError::new(crate::error::INTERNAL_ERROR, "no TLS client configuration"))
184 }
185}