ant_quic/
crypto.rs

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