ant_quic/
crypto.rs

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