quinn_boring/
server.rs

1use crate::alpn::AlpnProtocols;
2use crate::bffi_ext::QuicSsl;
3use crate::error::{map_result, Result};
4use crate::secret::Secrets;
5use crate::session_state::{SessionState, QUIC_METHOD};
6use crate::version::QuicVersion;
7use crate::{retry, KeyLog, NoKeyLog, QuicSslContext};
8use boring::ssl::{Ssl, SslContext, SslContextBuilder, SslMethod, SslVersion};
9use boring_sys as bffi;
10use bytes::{Bytes, BytesMut};
11use foreign_types_shared::ForeignType;
12use once_cell::sync::Lazy;
13use quinn_proto::{
14    crypto, transport_parameters::TransportParameters, ConnectionId, Side, TransportError,
15};
16use std::any::Any;
17use std::ffi::{c_int, c_uint, c_void};
18use std::result::Result as StdResult;
19use std::slice;
20use std::sync::Arc;
21
22/// Configuration for a server-side QUIC. Wraps around a BoringSSL [SslContext].
23pub struct Config {
24    ctx: SslContext,
25    alpn_protocols: AlpnProtocols,
26    key_log: Option<Arc<dyn KeyLog>>,
27}
28
29impl Config {
30    pub fn new() -> Result<Self> {
31        let mut builder = SslContextBuilder::new(SslMethod::tls())?;
32
33        // QUIC requires TLS 1.3.
34        builder.set_min_proto_version(Some(SslVersion::TLS1_3))?;
35        builder.set_max_proto_version(Some(SslVersion::TLS1_3))?;
36
37        builder.set_default_verify_paths()?;
38
39        // We build the context early, since we are not allowed to further mutate the context
40        // in start_session.
41        let mut ctx = builder.build();
42
43        // Disable verification of the client by default.
44        ctx.verify_peer(false);
45
46        // By default, enable early data (used for 0-RTT).
47        ctx.enable_early_data(true);
48
49        // Configure default ALPN protocols accepted by the server.QUIC requires ALPN be
50        // configured (see https://www.rfc-editor.org/rfc/rfc9001.html#section-8.1).
51        ctx.set_alpn_select_cb(Some(Session::alpn_select_callback));
52
53        // Set the callback for receipt of the Server Name Indication (SNI) extension.
54        ctx.set_server_name_cb(Some(Session::server_name_callback));
55
56        // Set callbacks for the SessionState.
57        ctx.set_quic_method(&QUIC_METHOD)?;
58        ctx.set_info_callback(Some(SessionState::info_callback));
59        ctx.set_keylog_callback(Some(SessionState::keylog_callback));
60
61        ctx.set_options(bffi::SSL_OP_CIPHER_SERVER_PREFERENCE as u32);
62
63        Ok(Self {
64            ctx,
65            alpn_protocols: AlpnProtocols::default(),
66            key_log: None,
67        })
68    }
69
70    /// Returns the underlying [SslContext] backing all created sessions.
71    pub fn ctx(&self) -> &SslContext {
72        &self.ctx
73    }
74
75    /// Returns the underlying [SslContext] backing all created sessions. Wherever possible use
76    /// the provided methods to modify settings rather than accessing this directly.
77    ///
78    /// Care should be taken to avoid overriding required behavior. In particular, this
79    /// configuration will set callbacks for QUIC events, alpn selection, server name,
80    /// as well as info and key logging.
81    pub fn ctx_mut(&mut self) -> &mut SslContext {
82        &mut self.ctx
83    }
84
85    /// Sets whether or not the peer certificate should be verified. If `true`, any error
86    /// during verification will be fatal. If not called, verification of the client is
87    /// disabled by default.
88    pub fn verify_peer(&mut self, verify: bool) {
89        self.ctx.verify_peer(verify)
90    }
91
92    /// Sets the ALPN protocols that will be accepted by the server. QUIC requires that
93    /// ALPN be used (see <https://www.rfc-editor.org/rfc/rfc9001.html#section-8.1>).
94    ///
95    /// If this method is not called, the server will default to accepting "h3".
96    pub fn set_alpn(&mut self, alpn_protocols: &[Vec<u8>]) -> Result<()> {
97        self.alpn_protocols = alpn_protocols.into();
98        Ok(())
99    }
100
101    /// Sets the key logger.
102    pub fn set_key_log(&mut self, key_log: Option<Arc<dyn KeyLog>>) {
103        self.key_log = key_log;
104    }
105}
106
107impl crypto::ServerConfig for Config {
108    fn initial_keys(
109        &self,
110        version: u32,
111        dcid: &ConnectionId,
112        side: Side,
113    ) -> StdResult<crypto::Keys, crypto::UnsupportedVersion> {
114        let version = QuicVersion::parse(version)?;
115        let secrets = Secrets::initial(version, dcid, side).unwrap();
116        Ok(secrets.keys().unwrap().as_crypto().unwrap())
117    }
118
119    fn retry_tag(&self, version: u32, orig_dst_cid: &ConnectionId, packet: &[u8]) -> [u8; 16] {
120        let version = QuicVersion::parse(version).unwrap();
121        retry::retry_tag(&version, orig_dst_cid, packet)
122    }
123
124    fn start_session(
125        self: Arc<Self>,
126        version: u32,
127        params: &TransportParameters,
128    ) -> Box<dyn crypto::Session> {
129        let version = QuicVersion::parse(version).unwrap();
130        Session::new(self, version, params).unwrap()
131    }
132}
133
134static SESSION_INDEX: Lazy<c_int> = Lazy::new(|| unsafe {
135    bffi::SSL_get_ex_new_index(0, std::ptr::null_mut(), std::ptr::null_mut(), None, None)
136});
137
138/// The [crypto::Session] implementation for BoringSSL.
139struct Session {
140    state: Box<SessionState>,
141    alpn: AlpnProtocols,
142    handshake_data_available: bool,
143    handshake_data_sent: bool,
144}
145
146impl Session {
147    fn new(
148        cfg: Arc<Config>,
149        version: QuicVersion,
150        params: &TransportParameters,
151    ) -> Result<Box<Self>> {
152        let mut ssl = Ssl::new(&cfg.ctx).unwrap();
153
154        // Configure the TLS extension based on the QUIC version used.
155        ssl.set_quic_use_legacy_codepoint(version.uses_legacy_extension());
156
157        // Configure the SSL to be a server.
158        ssl.set_accept_state();
159
160        // Set the transport parameters.
161        ssl.set_quic_transport_params(&encode_params(params))
162            .unwrap();
163
164        // Need to se
165        ssl.set_quic_early_data_context(b"quinn-boring").unwrap();
166
167        let mut session = Box::new(Self {
168            state: SessionState::new(
169                ssl,
170                Side::Server,
171                version,
172                cfg.key_log
173                    .as_ref()
174                    .map_or(Arc::new(NoKeyLog), |key_log| key_log.clone()),
175            )?,
176            alpn: cfg.alpn_protocols.clone(),
177            handshake_data_available: false,
178            handshake_data_sent: false,
179        });
180
181        // Register the instance in SSL ex_data. This allows the static callbacks to
182        // reference the instance.
183        unsafe {
184            map_result(bffi::SSL_set_ex_data(
185                session.state.ssl.as_ptr(),
186                *SESSION_INDEX,
187                &mut *session as *mut Self as *mut _,
188            ))?;
189        }
190
191        Ok(session)
192    }
193
194    /// Server-side only callback from BoringSSL to select the ALPN protocol.
195    #[inline]
196    fn on_alpn_select<'a>(&mut self, offered: &'a [u8]) -> Result<&'a [u8]> {
197        // Indicate that we now have handshake data available.
198        self.handshake_data_available = true;
199
200        self.alpn.select(offered)
201    }
202
203    /// Server-side only callback from BoringSSL indicating that the Server Name Indication (SNI)
204    /// extension in the client hello was successfully parsed.
205    #[inline]
206    fn on_server_name(&mut self, _: *mut c_int) -> c_int {
207        // Indicate that we now have handshake data available.
208        self.handshake_data_available = true;
209
210        // SSL_TLSEXT_ERR_OK causes the server_name extension to be acked in
211        // ServerHello.
212        bffi::SSL_TLSEXT_ERR_OK
213    }
214}
215
216// Raw callbacks from BoringSSL
217impl Session {
218    #[inline]
219    fn get_instance(ssl: *const bffi::SSL) -> &'static mut Session {
220        unsafe {
221            let data = bffi::SSL_get_ex_data(ssl, *SESSION_INDEX);
222            if data.is_null() {
223                panic!("BUG: Session instance missing")
224            }
225            &mut *(data as *mut Session)
226        }
227    }
228
229    extern "C" fn alpn_select_callback(
230        ssl: *mut bffi::SSL,
231        out: *mut *const u8,
232        out_len: *mut u8,
233        in_: *const u8,
234        in_len: c_uint,
235        _: *mut c_void,
236    ) -> c_int {
237        let inst = Self::get_instance(ssl);
238
239        unsafe {
240            let protos = slice::from_raw_parts(in_, in_len as _);
241            match inst.on_alpn_select(protos) {
242                Ok(proto) => {
243                    *out = proto.as_ptr() as _;
244                    *out_len = proto.len() as _;
245                    bffi::SSL_TLSEXT_ERR_OK
246                }
247                Err(_) => bffi::SSL_TLSEXT_ERR_ALERT_FATAL,
248            }
249        }
250    }
251
252    extern "C" fn server_name_callback(
253        ssl: *mut bffi::SSL,
254        out_alert: *mut c_int,
255        _: *mut c_void,
256    ) -> c_int {
257        let inst = Self::get_instance(ssl);
258        inst.on_server_name(out_alert)
259    }
260}
261
262impl crypto::Session for Session {
263    fn initial_keys(&self, dcid: &ConnectionId, side: Side) -> crypto::Keys {
264        self.state.initial_keys(dcid, side)
265    }
266
267    fn handshake_data(&self) -> Option<Box<dyn Any>> {
268        self.state.handshake_data()
269    }
270
271    fn peer_identity(&self) -> Option<Box<dyn Any>> {
272        self.state.peer_identity()
273    }
274
275    fn early_crypto(&self) -> Option<(Box<dyn crypto::HeaderKey>, Box<dyn crypto::PacketKey>)> {
276        self.state.early_crypto()
277    }
278
279    fn early_data_accepted(&self) -> Option<bool> {
280        None
281    }
282
283    fn is_handshaking(&self) -> bool {
284        self.state.is_handshaking()
285    }
286
287    fn read_handshake(&mut self, plaintext: &[u8]) -> StdResult<bool, TransportError> {
288        self.state.read_handshake(plaintext)?;
289
290        // Only indicate that handshake data is available once.
291        if !self.handshake_data_sent && self.handshake_data_available {
292            self.handshake_data_sent = true;
293            return Ok(true);
294        }
295
296        Ok(false)
297    }
298
299    fn transport_parameters(&self) -> StdResult<Option<TransportParameters>, TransportError> {
300        self.state.transport_parameters()
301    }
302
303    fn write_handshake(&mut self, buf: &mut Vec<u8>) -> Option<crypto::Keys> {
304        self.state.write_handshake(buf)
305    }
306
307    fn next_1rtt_keys(&mut self) -> Option<crypto::KeyPair<Box<dyn crypto::PacketKey>>> {
308        self.state.next_1rtt_keys()
309    }
310
311    fn is_valid_retry(&self, orig_dst_cid: &ConnectionId, header: &[u8], payload: &[u8]) -> bool {
312        self.state.is_valid_retry(orig_dst_cid, header, payload)
313    }
314
315    fn export_keying_material(
316        &self,
317        output: &mut [u8],
318        label: &[u8],
319        context: &[u8],
320    ) -> StdResult<(), crypto::ExportKeyingMaterialError> {
321        self.state.export_keying_material(output, label, context)
322    }
323}
324
325fn encode_params(params: &TransportParameters) -> Bytes {
326    let mut out = BytesMut::with_capacity(128);
327    params.write(&mut out);
328    out.freeze()
329}