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
22pub 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 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 let mut ctx = builder.build();
42
43 ctx.verify_peer(false);
45
46 ctx.enable_early_data(true);
48
49 ctx.set_alpn_select_cb(Some(Session::alpn_select_callback));
52
53 ctx.set_server_name_cb(Some(Session::server_name_callback));
55
56 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 pub fn ctx(&self) -> &SslContext {
72 &self.ctx
73 }
74
75 pub fn ctx_mut(&mut self) -> &mut SslContext {
82 &mut self.ctx
83 }
84
85 pub fn verify_peer(&mut self, verify: bool) {
89 self.ctx.verify_peer(verify)
90 }
91
92 pub fn set_alpn(&mut self, alpn_protocols: &[Vec<u8>]) -> Result<()> {
97 self.alpn_protocols = alpn_protocols.into();
98 Ok(())
99 }
100
101 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
138struct 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 ssl.set_quic_use_legacy_codepoint(version.uses_legacy_extension());
156
157 ssl.set_accept_state();
159
160 ssl.set_quic_transport_params(&encode_params(params))
162 .unwrap();
163
164 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 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 #[inline]
196 fn on_alpn_select<'a>(&mut self, offered: &'a [u8]) -> Result<&'a [u8]> {
197 self.handshake_data_available = true;
199
200 self.alpn.select(offered)
201 }
202
203 #[inline]
206 fn on_server_name(&mut self, _: *mut c_int) -> c_int {
207 self.handshake_data_available = true;
209
210 bffi::SSL_TLSEXT_ERR_OK
213 }
214}
215
216impl 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 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}