1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
//! Traits and implementations for the QUIC cryptography protocol //! //! The protocol logic in Quinn is contained in types that abstract over the actual //! cryptographic protocol used. This module contains the traits used for this //! abstraction layer as well as a single implementation of these traits that uses //! *ring* and rustls to implement the TLS protocol support. //! //! Note that usage of any protocol (version) other than TLS 1.3 does not conform to any //! published versions of the specification, and will not be supported in QUIC v1. use std::str; use bytes::BytesMut; use crate::{ config::ConfigError, shared::ConnectionId, transport_parameters::TransportParameters, ConnectError, Side, TransportError, }; /// Cryptography interface based on *ring* #[cfg(feature = "ring")] pub(crate) mod ring; /// TLS interface based on rustls #[cfg(feature = "rustls")] pub mod rustls; /// Public interface TLS types #[cfg(feature = "rustls")] pub(crate) mod types; /// A cryptographic session (commonly TLS) pub trait Session: Send + Sized { /// Parameters determined when the handshake begins, e.g. server name and/or application /// protocol type HandshakeData; /// Cryptographic identity of the peer type Identity: Sized; /// Type used to hold configuration for client sessions type ClientConfig: ClientConfig<Self>; /// Type used to sign various values type HmacKey: HmacKey; /// Key used to generate one-time-use handshake token keys type HandshakeTokenKey: HandshakeTokenKey; /// Type of keys used to protect packet headers type HeaderKey: HeaderKey; /// Type used to represent packet protection keys type PacketKey: PacketKey; /// Type used to hold configuration for server sessions type ServerConfig: ServerConfig<Self>; /// Create the initial set of keys given the client's initial destination ConnectionId fn initial_keys(dst_cid: &ConnectionId, side: Side) -> Keys<Self>; /// Get data negotiated during the handshake, if available /// /// Returns `None` until the connection emits `HandshakeDataReady`. fn handshake_data(&self) -> Option<Self::HandshakeData>; /// Get the peer's identity, if available fn peer_identity(&self) -> Option<Self::Identity>; /// Get the 0-RTT keys if available (clients only) /// /// On the client side, this method can be used to see if 0-RTT key material is available /// to start sending data before the protocol handshake has completed. /// /// Returns `None` if the key material is not available. This might happen if you have /// not connected to this server before. fn early_crypto(&self) -> Option<(Self::HeaderKey, Self::PacketKey)>; /// If the 0-RTT-encrypted data has been accepted by the peer fn early_data_accepted(&self) -> Option<bool>; /// Returns `true` until the connection is fully established. fn is_handshaking(&self) -> bool; /// Read bytes of handshake data /// /// This should be called with the contents of `CRYPTO` frames. If it returns `Ok`, the /// caller should call `write_handshake()` to check if the crypto protocol has anything /// to send to the peer. /// /// On success, returns `true` iff `self.handshake_data()` has been populated. fn read_handshake(&mut self, buf: &[u8]) -> Result<bool, TransportError>; /// The peer's QUIC transport parameters /// /// These are only available after the first flight from the peer has been received. fn transport_parameters(&self) -> Result<Option<TransportParameters>, TransportError>; /// Writes handshake bytes into the given buffer and optionally returns the negotiated keys /// /// When the handshake proceeds to the next phase, this method will return a new set of /// keys to encrypt data with. fn write_handshake(&mut self, buf: &mut Vec<u8>) -> Option<Keys<Self>>; /// Compute keys for the next key update fn next_1rtt_keys(&mut self) -> KeyPair<Self::PacketKey>; /// Generate the integrity tag for a retry packet fn retry_tag(orig_dst_cid: &ConnectionId, packet: &[u8]) -> [u8; 16]; /// Verify the integrity of a retry packet fn is_valid_retry(orig_dst_cid: &ConnectionId, header: &[u8], payload: &[u8]) -> bool; /// Fill `output` with `output.len()` bytes of keying material derived /// from the [Session]'s secrets, using `label` and `context` for domain /// separation. /// /// This function will fail, returning [ExportKeyingMaterialError], /// if the requested output length is too large. fn export_keying_material( &self, output: &mut [u8], label: &[u8], context: &[u8], ) -> Result<(), ExportKeyingMaterialError>; } /// A pair of keys for bidirectional communication pub struct KeyPair<T> { /// Key for encrypting data pub local: T, /// Key for decrypting data pub remote: T, } /// A complete set of keys for a certain packet space pub struct Keys<S> where S: Session, { /// Header protection keys pub header: KeyPair<S::HeaderKey>, /// Packet protection keys pub packet: KeyPair<S::PacketKey>, } /// Client-side configuration for the crypto protocol pub trait ClientConfig<S>: Clone where S: Session, { /// Construct the default configuration fn new() -> Self where Self: Sized; /// Start a client session with this configuration fn start_session( &self, server_name: &str, params: &TransportParameters, ) -> Result<S, ConnectError>; } /// Server-side configuration for the crypto protocol pub trait ServerConfig<S>: Clone + Send + Sync where S: Session, { /// Construct the default configuration fn new() -> Self where Self: Sized; /// Start a server session with this configuration fn start_session(&self, params: &TransportParameters) -> S; } /// Keys used to protect packet payloads pub trait PacketKey: Send { /// Encrypt the packet payload with the given packet number fn encrypt(&self, packet: u64, buf: &mut [u8], header_len: usize); /// Decrypt the packet payload with the given packet number fn decrypt( &self, packet: u64, header: &[u8], payload: &mut BytesMut, ) -> Result<(), CryptoError>; /// The length of the AEAD tag appended to packets on encryption fn tag_len(&self) -> usize; /// Maximum number of packets that may be sent using a single key fn confidentiality_limit(&self) -> u64; /// Maximum number of incoming packets that may fail decryption before the connection must be /// abandoned fn integrity_limit(&self) -> u64; } /// Keys used to protect packet headers pub trait HeaderKey: Send { /// Decrypt the given packet's header fn decrypt(&self, pn_offset: usize, packet: &mut [u8]); /// Encrypt the given packet's header fn encrypt(&self, pn_offset: usize, packet: &mut [u8]); /// The sample size used for this key's algorithm fn sample_size(&self) -> usize; } /// A key for signing with HMAC-based algorithms pub trait HmacKey: Send + Sized + Sync { /// Length of the key input const KEY_LEN: usize; /// Type of the signatures created by `sign()` type Signature: AsRef<[u8]>; /// Method for creating a key fn new(key: &[u8]) -> Result<Self, ConfigError>; /// Method for signing a message fn sign(&self, data: &[u8]) -> Self::Signature; /// Method for verifying a message fn verify(&self, data: &[u8], signature: &[u8]) -> Result<(), CryptoError>; } /// Error returned by [Session::export_keying_material]. /// /// This error occurs if the requested output length is too large. #[derive(Debug, PartialEq, Eq)] pub struct ExportKeyingMaterialError; /// A pseudo random key for HKDF pub trait HandshakeTokenKey: Send + Sized + Sync { /// AEAD key type type AeadKey: AeadKey; /// Derive AEAD using hkdf fn aead_from_hkdf(&self, random_bytes: &[u8]) -> Self::AeadKey; /// Method to build pseudo random key from existing bytes fn from_secret(secret: &[u8]) -> Self; } /// A key for sealing data with AEAD-based algorithms pub trait AeadKey { /// Length of AEAD Key const KEY_LEN: usize; // fn from_hkdf(master_key: &impl PseudoRandomKey, random_bytes: &[u8]) -> Self; /// Method for sealing message `data` fn seal(&self, data: &mut Vec<u8>, additional_data: &[u8]) -> Result<(), CryptoError>; /// Method for opening a sealed message `data` fn open<'a>( &self, data: &'a mut [u8], additional_data: &[u8], ) -> Result<&'a mut [u8], CryptoError>; } /// Generic crypto errors #[derive(Debug)] pub struct CryptoError;