ant_quic/
crypto.rs

1//! Traits and implementations for the QUIC cryptography protocol
2#![allow(rustdoc::bare_urls)]
3//!
4//! The protocol logic in Quinn is contained in types that abstract over the actual
5//! cryptographic protocol used. This module contains the traits used for this
6//! abstraction layer as well as a single implementation of these traits that uses
7//! *ring* and rustls to implement the TLS protocol support.
8//!
9//! Note that usage of any protocol (version) other than TLS 1.3 does not conform to any
10//! published versions of the specification, and will not be supported in QUIC v1.
11
12use std::{any::Any, str, sync::Arc};
13
14use bytes::BytesMut;
15
16use crate::{
17    ConnectError, Side, TransportError, shared::ConnectionId,
18    transport_parameters::TransportParameters,
19};
20
21/// Cryptography interface based on *ring*
22#[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
23pub(crate) mod ring_like;
24/// TLS interface based on rustls
25#[cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]
26pub mod rustls;
27
28/// Certificate management
29#[cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]
30pub mod certificate_manager;
31
32/// RFC 7250 Raw Public Keys support
33#[cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]
34pub mod raw_public_keys;
35
36/// Ed25519 key pair implementation
37pub mod raw_keys;
38
39/// Post-Quantum Cryptography support - always available
40pub mod pqc;
41
42// NOTE: The following modules were removed because they were written as external
43// integrations with Quinn, but ant-quic IS a fork of Quinn, not something that
44// integrates with it. These need to be rewritten as part of the Quinn implementation
45// if their functionality is needed.
46
47// Removed modules:
48// - rpk_integration (tried to integrate RPK with Quinn from outside)
49// - quinn_integration (tried to wrap Quinn endpoints)
50// - bootstrap_support (tried to add bootstrap support on top of Quinn)
51// - peer_discovery (distributed discovery layered on Quinn)
52// - enterprise_cert_mgmt (enterprise features added on top)
53// - performance_monitoring (monitoring Quinn from outside)
54// - performance_optimization (optimizing Quinn externally)
55// - zero_rtt_rpk (0-RTT features added on top)
56// - nat_rpk_integration (NAT traversal integration)
57
58/// TLS Extensions for RFC 7250 certificate type negotiation
59pub mod tls_extensions;
60
61/// TLS Extension Simulation for RFC 7250 Raw Public Keys
62pub mod tls_extension_simulation;
63
64/// rustls Extension Handlers for certificate type negotiation
65pub mod extension_handlers;
66
67/// Certificate Type Negotiation Protocol Implementation
68pub mod certificate_negotiation;
69
70/// Test module for TLS extension simulation
71#[cfg(test)]
72mod test_tls_simulation;
73
74/// A cryptographic session (commonly TLS)
75pub trait Session: Send + Sync + 'static {
76    /// Create the initial set of keys given the client's initial destination ConnectionId
77    fn initial_keys(&self, dst_cid: &ConnectionId, side: Side) -> Keys;
78
79    /// Get data negotiated during the handshake, if available
80    ///
81    /// Returns `None` until the connection emits `HandshakeDataReady`.
82    fn handshake_data(&self) -> Option<Box<dyn Any>>;
83
84    /// Get the peer's identity, if available
85    fn peer_identity(&self) -> Option<Box<dyn Any>>;
86
87    /// Get the 0-RTT keys if available (clients only)
88    ///
89    /// On the client side, this method can be used to see if 0-RTT key material is available
90    /// to start sending data before the protocol handshake has completed.
91    ///
92    /// Returns `None` if the key material is not available. This might happen if you have
93    /// not connected to this server before.
94    fn early_crypto(&self) -> Option<(Box<dyn HeaderKey>, Box<dyn PacketKey>)>;
95
96    /// If the 0-RTT-encrypted data has been accepted by the peer
97    fn early_data_accepted(&self) -> Option<bool>;
98
99    /// Returns `true` until the connection is fully established.
100    fn is_handshaking(&self) -> bool;
101
102    /// Read bytes of handshake data
103    ///
104    /// This should be called with the contents of `CRYPTO` frames. If it returns `Ok`, the
105    /// caller should call `write_handshake()` to check if the crypto protocol has anything
106    /// to send to the peer. This method will only return `true` the first time that
107    /// handshake data is available. Future calls will always return false.
108    ///
109    /// On success, returns `true` iff `self.handshake_data()` has been populated.
110    fn read_handshake(&mut self, buf: &[u8]) -> Result<bool, TransportError>;
111
112    /// The peer's QUIC transport parameters
113    ///
114    /// These are only available after the first flight from the peer has been received.
115    fn transport_parameters(&self) -> Result<Option<TransportParameters>, TransportError>;
116
117    /// Writes handshake bytes into the given buffer and optionally returns the negotiated keys
118    ///
119    /// When the handshake proceeds to the next phase, this method will return a new set of
120    /// keys to encrypt data with.
121    fn write_handshake(&mut self, buf: &mut Vec<u8>) -> Option<Keys>;
122
123    /// Compute keys for the next key update
124    fn next_1rtt_keys(&mut self) -> Option<KeyPair<Box<dyn PacketKey>>>;
125
126    /// Verify the integrity of a retry packet
127    fn is_valid_retry(&self, orig_dst_cid: &ConnectionId, header: &[u8], payload: &[u8]) -> bool;
128
129    /// Fill `output` with `output.len()` bytes of keying material derived
130    /// from the [Session]'s secrets, using `label` and `context` for domain
131    /// separation.
132    ///
133    /// This function will fail, returning [ExportKeyingMaterialError],
134    /// if the requested output length is too large.
135    fn export_keying_material(
136        &self,
137        output: &mut [u8],
138        label: &[u8],
139        context: &[u8],
140    ) -> Result<(), ExportKeyingMaterialError>;
141}
142
143/// A pair of keys for bidirectional communication
144pub struct KeyPair<T> {
145    /// Key for encrypting data
146    pub local: T,
147    /// Key for decrypting data
148    pub remote: T,
149}
150
151/// A complete set of keys for a certain packet space
152pub struct Keys {
153    /// Header protection keys
154    pub header: KeyPair<Box<dyn HeaderKey>>,
155    /// Packet protection keys
156    pub packet: KeyPair<Box<dyn PacketKey>>,
157}
158
159/// Client-side configuration for the crypto protocol
160pub trait ClientConfig: Send + Sync {
161    /// Start a client session with this configuration
162    fn start_session(
163        self: Arc<Self>,
164        version: u32,
165        server_name: &str,
166        params: &TransportParameters,
167    ) -> Result<Box<dyn Session>, ConnectError>;
168}
169
170/// Server-side configuration for the crypto protocol
171pub trait ServerConfig: Send + Sync {
172    /// Create the initial set of keys given the client's initial destination ConnectionId
173    fn initial_keys(
174        &self,
175        version: u32,
176        dst_cid: &ConnectionId,
177    ) -> Result<Keys, UnsupportedVersion>;
178
179    /// Generate the integrity tag for a retry packet
180    ///
181    /// Never called if `initial_keys` rejected `version`.
182    fn retry_tag(&self, version: u32, orig_dst_cid: &ConnectionId, packet: &[u8]) -> [u8; 16];
183
184    /// Start a server session with this configuration
185    ///
186    /// Never called if `initial_keys` rejected `version`.
187    fn start_session(
188        self: Arc<Self>,
189        version: u32,
190        params: &TransportParameters,
191    ) -> Box<dyn Session>;
192}
193
194/// Keys used to protect packet payloads
195pub trait PacketKey: Send + Sync {
196    /// Encrypt the packet payload with the given packet number
197    fn encrypt(&self, packet: u64, buf: &mut [u8], header_len: usize);
198    /// Decrypt the packet payload with the given packet number
199    fn decrypt(
200        &self,
201        packet: u64,
202        header: &[u8],
203        payload: &mut BytesMut,
204    ) -> Result<(), CryptoError>;
205    /// The length of the AEAD tag appended to packets on encryption
206    fn tag_len(&self) -> usize;
207    /// Maximum number of packets that may be sent using a single key
208    fn confidentiality_limit(&self) -> u64;
209    /// Maximum number of incoming packets that may fail decryption before the connection must be
210    /// abandoned
211    fn integrity_limit(&self) -> u64;
212}
213
214/// Keys used to protect packet headers
215pub trait HeaderKey: Send + Sync {
216    /// Decrypt the given packet's header
217    fn decrypt(&self, pn_offset: usize, packet: &mut [u8]);
218    /// Encrypt the given packet's header
219    fn encrypt(&self, pn_offset: usize, packet: &mut [u8]);
220    /// The sample size used for this key's algorithm
221    fn sample_size(&self) -> usize;
222}
223
224/// A key for signing with HMAC-based algorithms
225pub trait HmacKey: Send + Sync {
226    /// Method for signing a message
227    fn sign(&self, data: &[u8], signature_out: &mut [u8]);
228    /// Length of `sign`'s output
229    fn signature_len(&self) -> usize;
230    /// Method for verifying a message
231    fn verify(&self, data: &[u8], signature: &[u8]) -> Result<(), CryptoError>;
232}
233
234/// Error returned by [Session::export_keying_material].
235///
236/// This error occurs if the requested output length is too large.
237#[derive(Debug, PartialEq, Eq)]
238pub struct ExportKeyingMaterialError;
239
240/// A pseudo random key for HKDF
241pub trait HandshakeTokenKey: Send + Sync {
242    /// Derive AEAD using hkdf
243    fn aead_from_hkdf(&self, random_bytes: &[u8]) -> Box<dyn AeadKey>;
244}
245
246/// A key for sealing data with AEAD-based algorithms
247pub trait AeadKey {
248    /// Method for sealing message `data`
249    fn seal(&self, data: &mut Vec<u8>, additional_data: &[u8]) -> Result<(), CryptoError>;
250    /// Method for opening a sealed message `data`
251    fn open<'a>(
252        &self,
253        data: &'a mut [u8],
254        additional_data: &[u8],
255    ) -> Result<&'a mut [u8], CryptoError>;
256}
257
258/// Generic crypto errors
259#[derive(Debug)]
260pub struct CryptoError;
261
262/// Error indicating that the specified QUIC version is not supported
263#[derive(Debug)]
264pub struct UnsupportedVersion;
265
266impl From<UnsupportedVersion> for ConnectError {
267    fn from(_: UnsupportedVersion) -> Self {
268        Self::UnsupportedVersion
269    }
270}