1use crate::error::TransportError;
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub enum Level {
16 Initial = 0,
17 Handshake = 1,
18 OneRtt = 2,
19}
20
21impl Level {
22 pub const ALL: [Level; 3] = [Level::Initial, Level::Handshake, Level::OneRtt];
23}
24
25pub trait PacketKey: Send {
27 fn seal(&self, pn: u64, header: &[u8], payload: &mut [u8], tag: &mut [u8]);
29 fn open(&self, pn: u64, header: &[u8], payload_and_tag: &mut [u8]) -> Result<usize, ()>;
31 fn tag_len(&self) -> usize;
32 fn confidentiality_limit(&self) -> u64;
34 fn integrity_limit(&self) -> u64;
36}
37
38pub trait HeaderKey: Send {
40 fn mask(&self, sample: &[u8]) -> [u8; 5];
42}
43
44pub struct DirectionalKeys {
46 pub packet: Box<dyn PacketKey>,
47 pub header: Box<dyn HeaderKey>,
48}
49
50pub struct Keys {
52 pub local: DirectionalKeys,
53 pub remote: DirectionalKeys,
54}
55
56pub trait NextSecrets: Send {
58 fn next_packet_keys(&mut self) -> (Box<dyn PacketKey>, Box<dyn PacketKey>);
60}
61
62pub enum KeyChange {
64 Handshake { keys: Keys },
65 OneRtt { keys: Keys, next: Box<dyn NextSecrets> },
66}
67
68#[derive(Clone, Copy, Debug, PartialEq, Eq)]
70pub struct CryptoError {
71 pub alert: u8,
72 pub reason: &'static str,
73}
74
75impl From<CryptoError> for TransportError {
76 fn from(e: CryptoError) -> Self {
77 TransportError::new(crate::error::CRYPTO_ERROR + e.alert as u64, e.reason)
78 }
79}
80
81pub trait CryptoSession: Send {
83 fn read_handshake(&mut self, level: Level, data: &[u8]) -> Result<(), CryptoError>;
85 fn write_handshake(&mut self, out: &mut Vec<u8>) -> Option<KeyChange>;
88 fn peer_transport_params(&self) -> Option<&[u8]>;
90 fn alpn_protocol(&self) -> Option<&[u8]>;
92 fn is_handshaking(&self) -> bool;
93 fn set_version(&mut self, _version: u32) {}
96 fn server_name(&self) -> Option<&str> {
98 None
99 }
100 fn cipher_suite(&self) -> Option<u16> {
102 None
103 }
104 fn peer_certificates(&self) -> &[Vec<u8>] {
106 &[]
107 }
108}
109
110pub trait CryptoProvider: Send + Sync {
112 fn initial_keys(&self, version: u32, dcid: &[u8], is_server: bool) -> Keys;
114 fn retry_tag(&self, version: u32, pseudo_packet: &[u8]) -> [u8; 16];
116 fn hmac(&self, key: &[u8; 32], parts: &[&[u8]]) -> [u8; 32];
118 fn fill_random(&self, buf: &mut [u8]);
120 fn server_session(&self, version: u32, transport_params: Vec<u8>) -> Result<Box<dyn CryptoSession>, TransportError>;
122 fn client_session(
124 &self,
125 version: u32,
126 server_name: &str,
127 transport_params: Vec<u8>,
128 ) -> Result<Box<dyn CryptoSession>, TransportError>;
129}
130
131pub fn ct_eq(a: &[u8], b: &[u8]) -> bool {
133 if a.len() != b.len() {
134 return false;
135 }
136 let mut d = 0u8;
137 for (x, y) in a.iter().zip(b) {
138 d |= x ^ y;
139 }
140 d == 0
141}
142
143pub mod null {
150 use super::*;
151 use std::sync::atomic::{AtomicU64, Ordering};
152
153 #[inline]
154 fn mix(mut x: u64) -> u64 {
155 x ^= x >> 30;
156 x = x.wrapping_mul(0xbf58476d1ce4e5b9);
157 x ^= x >> 27;
158 x = x.wrapping_mul(0x94d049bb133111eb);
159 x ^ (x >> 31)
160 }
161
162 fn hash(seed: u64, parts: &[&[u8]]) -> u64 {
163 let mut h = mix(seed ^ 0x9e3779b97f4a7c15);
164 for p in parts {
165 let mut chunks = p.chunks_exact(8);
166 for c in &mut chunks {
167 let w = u64::from_le_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]]);
168 h = (h ^ w).wrapping_mul(0x100000001b3).rotate_left(29);
169 }
170 for &b in chunks.remainder() {
171 h = (h ^ b as u64).wrapping_mul(0x100000001b3);
172 }
173 h = mix(h ^ p.len() as u64);
174 }
175 h
176 }
177
178 struct NullPacketKey(u64, bool);
179
180 impl PacketKey for NullPacketKey {
181 fn seal(&self, pn: u64, header: &[u8], payload: &mut [u8], tag: &mut [u8]) {
182 let a = hash(self.0 ^ pn, &[header, payload]);
183 tag[..8].copy_from_slice(&a.to_le_bytes());
184 tag[8..16].copy_from_slice(&mix(a ^ self.0).to_le_bytes());
185 }
186 fn open(&self, pn: u64, header: &[u8], payload_and_tag: &mut [u8]) -> Result<usize, ()> {
187 if payload_and_tag.len() < 16 {
188 return Err(());
189 }
190 let n = payload_and_tag.len() - 16;
191 let mut tag = [0u8; 16];
192 self.seal(pn, header, &mut payload_and_tag[..n], &mut tag);
193 if self.1 || ct_eq(&tag, &payload_and_tag[n..]) {
194 Ok(n)
195 } else {
196 Err(())
197 }
198 }
199 fn tag_len(&self) -> usize {
200 16
201 }
202 fn confidentiality_limit(&self) -> u64 {
203 1 << 23
204 }
205 fn integrity_limit(&self) -> u64 {
206 1 << 36
207 }
208 }
209
210 struct NullHeaderKey(u64);
211
212 impl HeaderKey for NullHeaderKey {
213 fn mask(&self, sample: &[u8]) -> [u8; 5] {
214 let h = hash(self.0, &[sample]).to_le_bytes();
215 [h[0], h[1], h[2], h[3], h[4]]
216 }
217 }
218
219 fn dir(seed: u64, lax: bool) -> DirectionalKeys {
220 DirectionalKeys { packet: Box::new(NullPacketKey(seed, lax)), header: Box::new(NullHeaderKey(mix(seed))) }
221 }
222
223 fn keys(c2s: u64, s2c: u64, is_server: bool, lax: bool) -> Keys {
225 if is_server {
226 Keys { local: dir(s2c, lax), remote: dir(c2s, lax) }
227 } else {
228 Keys { local: dir(c2s, lax), remote: dir(s2c, lax) }
229 }
230 }
231
232 struct NullSecrets {
233 local: u64,
234 remote: u64,
235 lax: bool,
236 }
237
238 impl NextSecrets for NullSecrets {
239 fn next_packet_keys(&mut self) -> (Box<dyn PacketKey>, Box<dyn PacketKey>) {
240 self.local = mix(self.local ^ 0x6b75);
241 self.remote = mix(self.remote ^ 0x6b75);
242 (Box::new(NullPacketKey(self.local, self.lax)), Box::new(NullPacketKey(self.remote, self.lax)))
243 }
244 }
245
246 const CLIENT_HELLO: u8 = 1;
247 const SERVER_HELLO: u8 = 2;
248 const ENCRYPTED_EXTENSIONS: u8 = 8;
249 const CERTIFICATE: u8 = 11;
250 const FINISHED: u8 = 20;
251 pub const ALERT_UNEXPECTED: u8 = 10;
253 pub const ALERT_NO_APPLICATION_PROTOCOL: u8 = 120;
254
255 fn put_msg(out: &mut Vec<u8>, ty: u8, body: &[u8]) {
256 out.push(ty);
257 out.extend_from_slice(&(body.len() as u32).to_be_bytes()[1..]);
258 out.extend_from_slice(body);
259 }
260
261 fn put_blob(out: &mut Vec<u8>, b: &[u8]) {
262 out.extend_from_slice(&(b.len() as u16).to_be_bytes());
263 out.extend_from_slice(b);
264 }
265
266 fn get_blob<'a>(b: &mut &'a [u8]) -> Result<&'a [u8], CryptoError> {
267 let bad = CryptoError { alert: 50, reason: "mock: bad message" };
268 if b.len() < 2 {
269 return Err(bad);
270 }
271 let n = u16::from_be_bytes([b[0], b[1]]) as usize;
272 if b.len() < 2 + n {
273 return Err(bad);
274 }
275 let v = &b[2..2 + n];
276 *b = &b[2 + n..];
277 Ok(v)
278 }
279
280 #[derive(PartialEq, Clone, Copy, Debug)]
281 enum State {
282 Start,
283 SentHello,
284 GotServerHello,
285 HandshakeKeysGiven,
286 GotServerFinished,
287 Done,
288 WaitHello,
290 GotHello,
291 SentServerHello,
292 SentFinished,
293 }
294
295 pub struct NullSession {
297 is_server: bool,
298 state: State,
299 tp: Vec<u8>,
300 peer_tp: Option<Vec<u8>>,
301 alpn_offer: Vec<Vec<u8>>,
302 alpn: Option<Vec<u8>>,
303 buf: [Vec<u8>; 3],
304 seed: u64,
305 hello_padding: usize,
306 lax: bool,
307 }
308
309 impl NullSession {
310 fn take_msg(&mut self, level: Level) -> Option<(u8, Vec<u8>)> {
311 let b = &mut self.buf[level as usize];
312 if b.len() < 4 {
313 return None;
314 }
315 let n = u32::from_be_bytes([0, b[1], b[2], b[3]]) as usize;
316 if b.len() < 4 + n {
317 return None;
318 }
319 let ty = b[0];
320 let body = b[4..4 + n].to_vec();
321 b.drain(..4 + n);
322 Some((ty, body))
323 }
324 }
325
326 impl CryptoSession for NullSession {
327 fn read_handshake(&mut self, level: Level, data: &[u8]) -> Result<(), CryptoError> {
328 let unexpected = CryptoError { alert: ALERT_UNEXPECTED, reason: "mock: unexpected message" };
329 if level == Level::OneRtt {
330 return Err(unexpected);
331 }
332 self.buf[level as usize].extend_from_slice(data);
333 if self.buf[level as usize].len() > 1 << 20 {
334 return Err(unexpected);
335 }
336 while let Some((ty, body)) = self.take_msg(level) {
337 match (self.is_server, self.state, level, ty) {
338 (true, State::WaitHello, Level::Initial, CLIENT_HELLO) => {
339 let mut b = &body[..];
340 let alpns = get_blob(&mut b)?;
341 let tp = get_blob(&mut b)?;
342 self.peer_tp = Some(tp.to_vec());
343 let mut a = alpns;
344 while !a.is_empty() {
345 let p = get_blob(&mut a)?;
346 if self.alpn.is_none() && self.alpn_offer.iter().any(|o| o == p) {
347 self.alpn = Some(p.to_vec());
348 }
349 }
350 if self.alpn.is_none() && !self.alpn_offer.is_empty() {
351 return Err(CryptoError {
352 alert: ALERT_NO_APPLICATION_PROTOCOL,
353 reason: "mock: no common ALPN",
354 });
355 }
356 self.seed = hash(0x5eed, &[&body]);
357 self.state = State::GotHello;
358 }
359 (false, State::SentHello, Level::Initial, SERVER_HELLO) => {
360 let mut b = &body[..];
361 let alpn = get_blob(&mut b)?;
362 let seed = get_blob(&mut b)?;
363 if seed.len() != 8 {
364 return Err(unexpected);
365 }
366 self.seed = u64::from_le_bytes(seed.try_into().unwrap());
367 if !alpn.is_empty() {
368 self.alpn = Some(alpn.to_vec());
369 }
370 self.state = State::GotServerHello;
371 }
372 (false, State::HandshakeKeysGiven, Level::Handshake, CERTIFICATE) => {}
373 (false, State::HandshakeKeysGiven, Level::Handshake, ENCRYPTED_EXTENSIONS) => {
374 self.peer_tp = Some(body);
375 }
376 (false, State::HandshakeKeysGiven, Level::Handshake, FINISHED) if self.peer_tp.is_some() => {
377 self.state = State::GotServerFinished;
378 }
379 (true, State::SentFinished, Level::Handshake, FINISHED) => {
380 self.state = State::Done;
381 }
382 _ => return Err(unexpected),
383 }
384 }
385 Ok(())
386 }
387
388 fn write_handshake(&mut self, out: &mut Vec<u8>) -> Option<KeyChange> {
389 let s = self.seed;
390 let lax = self.lax;
391 let hs = || keys(mix(s ^ 1), mix(s ^ 2), self.is_server, lax);
392 let one = || keys(mix(s ^ 3), mix(s ^ 4), self.is_server, lax);
393 let secrets = || {
394 let (c, sv) = (mix(s ^ 3), mix(s ^ 4));
395 let (local, remote) = if self.is_server { (sv, c) } else { (c, sv) };
396 Box::new(NullSecrets { local, remote, lax }) as Box<dyn NextSecrets>
397 };
398 match self.state {
399 State::Start => {
400 let mut body = Vec::new();
401 let mut alpns = Vec::new();
402 for a in &self.alpn_offer {
403 put_blob(&mut alpns, a);
404 }
405 put_blob(&mut body, &alpns);
406 put_blob(&mut body, &self.tp);
407 body.resize(body.len() + self.hello_padding, 0);
408 put_msg(out, CLIENT_HELLO, &body);
409 self.state = State::SentHello;
410 None
411 }
412 State::GotServerHello => {
413 self.state = State::HandshakeKeysGiven;
414 Some(KeyChange::Handshake { keys: hs() })
415 }
416 State::GotServerFinished => {
417 put_msg(out, FINISHED, &[]);
418 self.state = State::Done;
419 Some(KeyChange::OneRtt { keys: one(), next: secrets() })
420 }
421 State::GotHello => {
422 let mut body = Vec::new();
423 put_blob(&mut body, self.alpn.as_deref().unwrap_or(&[]));
424 put_blob(&mut body, &s.to_le_bytes());
425 put_msg(out, SERVER_HELLO, &body);
426 self.state = State::SentServerHello;
427 Some(KeyChange::Handshake { keys: hs() })
428 }
429 State::SentServerHello => {
430 put_msg(out, ENCRYPTED_EXTENSIONS, &self.tp);
431 if self.hello_padding > 0 {
432 put_msg(out, CERTIFICATE, &vec![0x55; self.hello_padding]);
433 }
434 put_msg(out, FINISHED, &[]);
435 self.state = State::SentFinished;
436 Some(KeyChange::OneRtt { keys: one(), next: secrets() })
437 }
438 _ => None,
439 }
440 }
441
442 fn peer_transport_params(&self) -> Option<&[u8]> {
443 self.peer_tp.as_deref()
444 }
445 fn alpn_protocol(&self) -> Option<&[u8]> {
446 self.alpn.as_deref()
447 }
448 fn is_handshaking(&self) -> bool {
449 self.state != State::Done
450 }
451 }
452
453 pub struct NullProvider {
455 rng: AtomicU64,
456 pub alpn: Vec<Vec<u8>>,
457 pub hello_padding: usize,
459 pub server_flight: usize,
461 pub accept_any_tag: bool,
463 }
464
465 impl NullProvider {
466 pub fn new(seed: u64) -> Self {
467 NullProvider { rng: AtomicU64::new(seed | 1), alpn: vec![b"h3".to_vec()], hello_padding: 0, server_flight: 0, accept_any_tag: false }
468 }
469 }
470
471 impl CryptoProvider for NullProvider {
472 fn initial_keys(&self, version: u32, dcid: &[u8], is_server: bool) -> Keys {
473 let s = hash(version as u64, &[dcid]);
474 keys(mix(s ^ 0xc), mix(s ^ 0x5), is_server, self.accept_any_tag)
475 }
476 fn retry_tag(&self, version: u32, pseudo_packet: &[u8]) -> [u8; 16] {
477 let a = hash(0x7e7 ^ version as u64, &[pseudo_packet]);
478 let mut t = [0u8; 16];
479 t[..8].copy_from_slice(&a.to_le_bytes());
480 t[8..].copy_from_slice(&mix(a).to_le_bytes());
481 t
482 }
483 fn hmac(&self, key: &[u8; 32], parts: &[&[u8]]) -> [u8; 32] {
484 let k = hash(0, &[key]);
485 let mut out = [0u8; 32];
486 let mut h = hash(k, parts);
487 for c in out.chunks_mut(8) {
488 c.copy_from_slice(&h.to_le_bytes());
489 h = mix(h ^ k);
490 }
491 out
492 }
493 fn fill_random(&self, buf: &mut [u8]) {
494 for c in buf.chunks_mut(8) {
495 let v = mix(self.rng.fetch_add(0x9e3779b97f4a7c15, Ordering::Relaxed));
496 c.copy_from_slice(&v.to_le_bytes()[..c.len()]);
497 }
498 }
499 fn server_session(&self, _version: u32, tp: Vec<u8>) -> Result<Box<dyn CryptoSession>, TransportError> {
500 Ok(Box::new(NullSession {
501 is_server: true,
502 state: State::WaitHello,
503 tp,
504 peer_tp: None,
505 alpn_offer: self.alpn.clone(),
506 alpn: None,
507 buf: Default::default(),
508 seed: 0,
509 hello_padding: self.server_flight,
510 lax: self.accept_any_tag,
511 }))
512 }
513 fn client_session(&self, _version: u32, _name: &str, tp: Vec<u8>) -> Result<Box<dyn CryptoSession>, TransportError> {
514 Ok(Box::new(NullSession {
515 is_server: false,
516 state: State::Start,
517 tp,
518 peer_tp: None,
519 alpn_offer: self.alpn.clone(),
520 alpn: None,
521 buf: Default::default(),
522 seed: 0,
523 hello_padding: self.hello_padding,
524 lax: self.accept_any_tag,
525 }))
526 }
527 }
528}