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