quinn_boring2/
lib.rs

1mod aead;
2mod alert;
3mod alpn;
4mod bffi_ext;
5mod client;
6mod error;
7mod handshake_token;
8mod hkdf;
9mod hmac;
10mod key;
11mod key_log;
12mod macros;
13mod retry;
14mod secret;
15mod server;
16mod session_cache;
17mod session_state;
18mod suite;
19mod version;
20
21// Export the public interface.
22pub use bffi_ext::*;
23pub use client::Config as ClientConfig;
24pub use error::{Error, Result};
25pub use handshake_token::HandshakeTokenKey;
26pub use hmac::HmacKey;
27pub use key_log::*;
28pub use server::Config as ServerConfig;
29pub use session_cache::*;
30pub use version::QuicVersion;
31
32/// Information available from [quinn_proto::crypto::Session::handshake_data] once the handshake has completed.
33#[derive(Clone, Debug)]
34pub struct HandshakeData {
35    /// The negotiated application protocol, if ALPN is in use
36    ///
37    /// Guaranteed to be set if a nonempty list of protocols was specified for this connection.
38    pub protocol: Option<Vec<u8>>,
39
40    /// The server name specified by the client, if any
41    ///
42    /// Always `None` for outgoing connections
43    pub server_name: Option<String>,
44}
45
46pub mod helpers {
47    use super::*;
48    use quinn_proto::crypto;
49    use std::sync::Arc;
50
51    /// Create a server config with the given [`crypto::ServerConfig`]
52    ///
53    /// Uses a randomized handshake token key.
54    pub fn server_config(crypto: Arc<dyn crypto::ServerConfig>) -> Result<quinn::ServerConfig> {
55        Ok(quinn::ServerConfig::new(
56            crypto,
57            Arc::new(HandshakeTokenKey::new()?),
58        ))
59    }
60
61    /// Returns a default endpoint configuration for BoringSSL.
62    pub fn default_endpoint_config() -> quinn::EndpointConfig {
63        let mut cfg = quinn::EndpointConfig::new(Arc::new(HmacKey::sha256()));
64        cfg.supported_versions(QuicVersion::default_supported_versions());
65        cfg
66    }
67
68    /// Helper to construct an endpoint for use with outgoing connections only
69    ///
70    /// Note that `addr` is the *local* address to bind to, which should usually be a wildcard
71    /// address like `0.0.0.0:0` or `[::]:0`, which allow communication with any reachable IPv4 or
72    /// IPv6 address respectively from an OS-assigned port.
73    ///
74    /// Platform defaults for dual-stack sockets vary. For example, any socket bound to a wildcard
75    /// IPv6 address on Windows will not by default be able to communicate with IPv4
76    /// addresses. Portable applications should bind an address that matches the family they wish to
77    /// communicate within.
78    #[cfg(feature = "runtime-tokio")]
79    pub fn client_endpoint(addr: std::net::SocketAddr) -> std::io::Result<quinn::Endpoint> {
80        let socket = std::net::UdpSocket::bind(addr)?;
81        quinn::Endpoint::new(
82            default_endpoint_config(),
83            None,
84            socket,
85            Arc::new(quinn::TokioRuntime),
86        )
87    }
88
89    /// Helper to construct an endpoint for use with both incoming and outgoing connections
90    ///
91    /// Platform defaults for dual-stack sockets vary. For example, any socket bound to a wildcard
92    /// IPv6 address on Windows will not by default be able to communicate with IPv4
93    /// addresses. Portable applications should bind an address that matches the family they wish to
94    /// communicate within.
95    #[cfg(feature = "runtime-tokio")]
96    pub fn server_endpoint(
97        config: quinn::ServerConfig,
98        addr: std::net::SocketAddr,
99    ) -> std::io::Result<quinn::Endpoint> {
100        let socket = std::net::UdpSocket::bind(addr)?;
101        quinn::Endpoint::new(
102            default_endpoint_config(),
103            Some(config),
104            socket,
105            Arc::new(quinn::TokioRuntime),
106        )
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    use crate::error::Result;
115    use crate::secret::{Secret, Secrets};
116    use crate::suite::CipherSuite;
117    use bytes::BytesMut;
118    use hex_literal::hex;
119    use quinn_proto::crypto::PacketKey;
120    use quinn_proto::{ConnectionId, Side};
121
122    /// Copied from quiche.
123    #[test]
124    fn test_initial_keys_v1() -> Result<()> {
125        let dcid: &[u8] = &hex!("8394c8f03e515708");
126        let version = QuicVersion::V1;
127        let suite = CipherSuite::aes128_gcm_sha256();
128
129        let s = Secrets::initial(version, &ConnectionId::new(dcid), Side::Client)?;
130
131        let expected_enc_key: &[u8] = &hex!("1f369613dd76d5467730efcbe3b1a22d");
132        assert_eq!(
133            s.local.packet_key(version, suite)?.key().slice(),
134            expected_enc_key
135        );
136        let expected_enc_iv: &[u8] = &hex!("fa044b2f42a3fd3b46fb255c");
137        assert_eq!(
138            s.local.packet_key(version, suite)?.iv().slice(),
139            expected_enc_iv
140        );
141        let expected_enc_hdr_key: &[u8] = &hex!("9f50449e04a0e810283a1e9933adedd2");
142        assert_eq!(
143            s.local.header_key(version, suite)?.key().slice(),
144            expected_enc_hdr_key
145        );
146        let expected_dec_key: &[u8] = &hex!("cf3a5331653c364c88f0f379b6067e37");
147        assert_eq!(
148            s.remote.packet_key(version, suite)?.key().slice(),
149            expected_dec_key
150        );
151        let expected_dec_iv: &[u8] = &hex!("0ac1493ca1905853b0bba03e");
152        assert_eq!(
153            s.remote.packet_key(version, suite)?.iv().slice(),
154            expected_dec_iv
155        );
156        let expected_dec_hdr_key: &[u8] = &hex!("c206b8d9b9f0f37644430b490eeaa314");
157        assert_eq!(
158            s.remote.header_key(version, suite)?.key().slice(),
159            expected_dec_hdr_key
160        );
161
162        Ok(())
163    }
164
165    /// Copied from rustls.
166    #[test]
167    fn short_packet_header_protection() {
168        // https://www.rfc-editor.org/rfc/rfc9001.html#name-chacha20-poly1305-short-hea
169
170        const PN: u64 = 654360564;
171        const SECRET: &[u8] =
172            &hex!("9ac312a7f877468ebe69422748ad00a15443f18203a07d6060f688f30f21632b");
173
174        let version = QuicVersion::V1;
175        let suite = CipherSuite::chacha20_poly1305_sha256();
176
177        let secret = Secret::from(SECRET);
178        let hpk = secret
179            .header_key(version, suite)
180            .unwrap()
181            .as_crypto()
182            .unwrap();
183        let packet = secret.packet_key(version, suite).unwrap();
184
185        const PLAIN: &[u8] = &[0x42, 0x00, 0xbf, 0xf4, b'h', b'e', b'l', b'l', b'o'];
186
187        let mut buf = PLAIN.to_vec();
188        // Make space for the output tag.
189        buf.extend_from_slice(&[0u8; 16]);
190        packet.encrypt(PN, &mut buf, 4);
191
192        let pn_offset = 1;
193        hpk.encrypt(pn_offset, &mut buf);
194
195        const PROTECTED: &[u8] = &hex!("593b46220c4d504a9f1857793356400fc4a784ee309dff98b2");
196
197        assert_eq!(&buf, PROTECTED);
198
199        hpk.decrypt(pn_offset, &mut buf);
200
201        let (header, payload_tag) = buf.split_at(4);
202        let mut payload_tag = BytesMut::from(payload_tag);
203        packet.decrypt(PN, header, &mut payload_tag).unwrap();
204        let plain = payload_tag.as_ref();
205        assert_eq!(plain, &PLAIN[4..]);
206    }
207
208    /// Copied from rustls.
209    #[test]
210    fn key_update_test_vector() {
211        let version = QuicVersion::V1;
212        let suite = CipherSuite::aes128_gcm_sha256();
213        let mut secrets = Secrets {
214            version,
215            suite,
216            local: Secret::from(&hex!(
217                "b8767708f8772358a6ea9fc43e4add2c961b3f5287a6d1467ee0aeab33724dbf"
218            )),
219            remote: Secret::from(&hex!(
220                "42dc972140e0f2e39845b767613439dc6758ca43259b878506824eb1e438d855"
221            )),
222        };
223        secrets.update().unwrap();
224
225        let expected = Secrets {
226            version,
227            suite,
228            local: Secret::from(&hex!(
229                "42cac8c91cd5eb40682e432edf2d2be9f41a52ca6b22d8e6cdb1e8aca9061fce"
230            )),
231            remote: Secret::from(&hex!(
232                "eb7f5e2a123f407db499e361cae590d4d992e14b7ace03c244e0422115b6d38a"
233            )),
234        };
235
236        assert_eq!(expected, secrets);
237    }
238
239    #[test]
240    fn client_encrypt_header() {
241        let dcid = ConnectionId::new(&hex!("06b858ec6f80452b"));
242
243        let secrets = Secrets::initial(QuicVersion::V1, &dcid, Side::Client).unwrap();
244        let client = secrets.keys().unwrap().as_crypto().unwrap();
245
246        // Client (encrypt)
247        let mut packet: [u8; 51] = hex!(
248            "c0000000010806b858ec6f80452b0000402100c8fb7ffd97230e38b70d86e7ff148afdf88fc21c4426c7d1cec79914c8785757"
249        );
250        let packet_number = 0;
251        let packet_number_pos = 18;
252        let header_len = 19;
253
254        // Encrypt the payload.
255        client
256            .packet
257            .local
258            .encrypt(packet_number, &mut packet, header_len);
259        let expected_after_packet_encrypt: [u8; 51] = hex!(
260            "c0000000010806b858ec6f80452b0000402100f60e77fa2f629f9921fae64125c5632cf769d801a4693af6b949af37c2c45399"
261        );
262        assert_eq!(packet, expected_after_packet_encrypt);
263
264        // Encrypt the header.
265        client.header.local.encrypt(packet_number_pos, &mut packet);
266        let expected_after_header_encrypt: [u8; 51] = hex!(
267            "cd000000010806b858ec6f80452b000040210bf60e77fa2f629f9921fae64125c5632cf769d801a4693af6b949af37c2c45399"
268        );
269        assert_eq!(packet, expected_after_header_encrypt);
270    }
271
272    #[test]
273    fn server_decrypt_header() {
274        let dcid = ConnectionId::new(&hex!("06b858ec6f80452b"));
275        let secrets = Secrets::initial(QuicVersion::V1, &dcid, Side::Server).unwrap();
276        let server = secrets.keys().unwrap().as_crypto().unwrap();
277
278        let mut packet = BytesMut::from(&hex!(
279            "c8000000010806b858ec6f80452b00004021be3ef50807b84191a196f760a6dad1e9d1c430c48952cba0148250c21c0a6a70e1"
280        )[..]);
281        let packet_number = 0;
282        let packet_number_pos = 18;
283        let header_len = 19;
284
285        // Decrypt the header.
286        server.header.remote.decrypt(packet_number_pos, &mut packet);
287        let expected_header: [u8; 19] = hex!("c0000000010806b858ec6f80452b0000402100");
288        assert_eq!(packet[..header_len], expected_header);
289
290        // Decrypt the payload.
291        let mut header = packet;
292        let mut packet = header.split_off(header_len);
293        server
294            .packet
295            .remote
296            .decrypt(packet_number, &header, &mut packet)
297            .unwrap();
298        assert_eq!(packet[..], [0; 16]);
299    }
300}