rustls/conn/split.rs
1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::fmt;
4use core::ops::{DerefMut, Range};
5use std::sync::MutexGuard;
6
7use super::receive::{Discard, JoinOutput};
8use crate::client::ClientSide;
9use crate::common_state::UnborrowedPayload;
10use crate::conn::kernel::KernelConnection;
11use crate::conn::{
12 ConnectionCommon, MessageIter, ReceivePath, SendOutput, SendPath, TlsInputBuffer,
13};
14use crate::crypto::cipher::{MessageEncrypter, OutboundPlain};
15use crate::enums::ProtocolVersion;
16use crate::error::{AlertDescription, ErrorWithAlert};
17use crate::lock::Mutex;
18use crate::msgs::{AlertLevel, Delocator, Message};
19use crate::sync::Arc;
20use crate::tls13::key_schedule::KeyScheduleTrafficSend;
21use crate::{ConnectionOutputs, Error, ExtractedSecrets, SideData};
22
23/// A post-handshake connection which has been split by direction.
24///
25/// Typically you will immediately destructure this type, and give the components
26/// to different threads/handlers to progress separately.
27#[expect(clippy::exhaustive_structs)]
28#[derive(Debug)]
29pub struct SplitConnection<Side: SideData> {
30 /// The ability to encrypt data to be sent.
31 pub send: SendTraffic,
32 /// The ability to decrypt received data.
33 pub receive: ReceiveTraffic<Side>,
34 /// Facts about the connection established during the handshake.
35 pub outputs: ConnectionOutputs,
36}
37
38impl<Side: SideData> SplitConnection<Side> {
39 /// Extract secrets and a [`KernelConnection`], so they can be used when
40 /// configuring kTLS, for example.
41 ///
42 /// Should be used with care as it exposes secret key material.
43 ///
44 /// The returned [`KernelConnection`] continues to own the connection's
45 /// secrets, so it can compute new traffic secrets on key update and (for
46 /// client connections) accept session tickets. See the [`kernel`] module
47 /// documentation for the details.
48 ///
49 /// This fails if the connection was not made with [`enable_secret_extraction`] set.
50 ///
51 /// [`kernel`]: crate::kernel
52 /// [`enable_secret_extraction`]: crate::ClientConfig::enable_secret_extraction
53 pub fn dangerous_into_kernel_connection(
54 self,
55 ) -> Result<(ExtractedSecrets, KernelConnection<Side>), Error> {
56 let Self {
57 send,
58 receive,
59 outputs,
60 } = self;
61
62 // drop our handle on the send path, so `receive` holds the only one.
63 drop(send);
64
65 let ReceiveTraffic {
66 state, recv, send, ..
67 } = receive;
68
69 ConnectionCommon::<Side>::from_parts_into_kernel_connection(
70 &mut send.lock().unwrap(),
71 recv,
72 outputs,
73 state,
74 )
75 }
76}
77
78impl<Side: SideData> TryFrom<ConnectionCommon<Side>> for SplitConnection<Side> {
79 type Error = Error;
80
81 fn try_from(conn: ConnectionCommon<Side>) -> Result<Self, Error> {
82 let send = Arc::new(Mutex::new(conn.common.send));
83 let state = conn.state?;
84
85 Ok(Self {
86 send: SendTraffic(send.clone()),
87 receive: ReceiveTraffic {
88 state,
89 recv: conn.common.recv,
90 send,
91 pending_flush_sender: false,
92 },
93 outputs: conn.common.outputs,
94 })
95 }
96}
97
98/// The send-side of a connection, after a successful handshake.
99///
100/// You can use this object to send data to the peer.
101pub struct SendTraffic(pub(crate) Arc<Mutex<SendPath>>);
102
103impl SendTraffic {
104 /// Write application data to the peer.
105 ///
106 /// The TLS data to send to the peer is written into `tls`. This data should then be
107 /// communicated to the peer.
108 ///
109 /// When you need to handle a [`ReceiveTrafficState::FlushSender`] state, you can call this
110 /// method with [`OutboundPlain::new_empty()`] to flush any pending TLS data to the peer.
111 pub fn write(&mut self, application_data: OutboundPlain<'_>, tls: &mut Vec<u8>) {
112 let mut inner = self.0.lock().unwrap();
113 inner.send_appdata_encrypt(application_data, tls);
114 }
115
116 /// Conclude sending traffic by sending a `close_notify` alert.
117 ///
118 /// The alert is written into `tls` along with any pending data.
119 /// This data should then be communicated to the peer.
120 ///
121 /// This is the final possible operation with a [`SendTraffic`].
122 pub fn close(self, tls: &mut Vec<u8>) {
123 let mut inner = self.0.lock().unwrap();
124 inner.send_close_notify(tls);
125 drop(inner);
126 }
127
128 /// Writes a TLS 1.3 `key_update` message into `tls` to refresh a connection's keys.
129 ///
130 /// The main reason to call this manually is to roll keys when it is known
131 /// a connection will be idle for a long period.
132 ///
133 /// rustls implicitly and automatically refreshes traffic keys when needed
134 /// according to the selected cipher suite's cryptographic constraints. There
135 /// is therefore no need to call this manually to avoid cryptographic keys
136 /// "wearing out".
137 ///
138 /// This call refreshes our encryption keys. Once the peer receives the message,
139 /// it refreshes _its_ encryption and decryption keys and sends a response.
140 /// Once we receive that response, we refresh our decryption keys to match.
141 /// At the end of this process, keys in both directions have been refreshed.
142 ///
143 /// This returns an error if a version prior to TLS1.3 is negotiated.
144 ///
145 /// # Usage advice
146 /// Note that other implementations (including rustls) may enforce limits on
147 /// the number of `key_update` messages allowed on a given connection to prevent
148 /// denial of service. Therefore, this should be called sparingly.
149 ///
150 /// rustls only allows one outstanding request at a time; this function succeeds
151 /// but sends nothing if a request is already in-flight.
152 pub fn refresh_traffic_keys(&mut self, tls: &mut Vec<u8>) -> Result<(), Error> {
153 self.0
154 .lock()
155 .unwrap()
156 .refresh_traffic_keys(tls)
157 }
158}
159
160impl fmt::Debug for SendTraffic {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 f.debug_tuple("SendTraffic")
163 .finish_non_exhaustive()
164 }
165}
166
167/// The receive-side of a connection, after a successful handshake.
168///
169/// You can use this object to receive data from the peer.
170pub struct ReceiveTraffic<Side: SideData> {
171 pub(crate) state: Side::State,
172 pub(crate) recv: ReceivePath,
173 pub(crate) send: Arc<Mutex<SendPath>>,
174 pub(crate) pending_flush_sender: bool,
175}
176
177impl<Side: SideData> ReceiveTraffic<Side> {
178 /// Receive application data from the peer.
179 ///
180 /// `received_tls` is an instance of the receive buffer abstraction containing
181 /// TLS-protected data received from the peer.
182 ///
183 /// A [`ReceiveTrafficState`] is returned on success.
184 ///
185 /// An error from this function permanently breaks the ability to receive
186 /// data from the peer. The error may be accompanied by a TLS alert,
187 /// which can be obtained from the returned [`ErrorWithAlert`] and sent
188 /// to the peer. Following this, the underlying IO medium should be
189 /// closed by the application.
190 pub fn read<'a, 't>(
191 self,
192 input: &'a mut impl TlsInputBuffer,
193 tls: &'t mut Vec<u8>,
194 ) -> Result<ReceiveTrafficState<'a, Side>, ErrorWithAlert<'t>> {
195 let Self {
196 state,
197 mut recv,
198 send,
199 mut pending_flush_sender,
200 } = self;
201
202 let mut send_adapter = SendAdapter::Unlocked(&send);
203 let mut state = Ok(state);
204 let output = JoinOutput {
205 outputs: &mut Discard,
206 quic: None,
207 send: &mut send_adapter,
208 side: &mut Discard,
209 };
210
211 let mut iter = MessageIter::<Side, _>::receive(input, tls, &mut state, &mut recv, output);
212 let received_plain = match iter.next() {
213 Some(Ok(payload)) => Some(payload),
214 Some(Err(error)) => {
215 return Err(ErrorWithAlert::new(
216 error,
217 send_adapter
218 .as_locked(false)
219 .deref_mut(),
220 tls,
221 ));
222 }
223 None => None,
224 };
225
226 // nb. state consumed only on error.
227 let state = state.unwrap();
228
229 if let Some(unborrowed) = received_plain {
230 let pending_discard = recv.deframer.take_discard();
231 let UnborrowedPayload::Unborrowed(range) = unborrowed else {
232 return Err(ErrorWithAlert::new(
233 Error::Unreachable("decrypted data should be borrowed"),
234 send_adapter
235 .as_locked(false)
236 .deref_mut(),
237 tls,
238 ));
239 };
240
241 if let SendAdapter::Locked { send_required, .. } = send_adapter {
242 pending_flush_sender |= send_required;
243 }
244
245 drop(send_adapter);
246 return Ok(ReceiveTrafficState::Available(ReceivedApplicationData {
247 range,
248 input,
249 pending_discard,
250 rt: Self {
251 state,
252 recv,
253 send,
254 pending_flush_sender,
255 },
256 }));
257 }
258
259 input.discard(recv.deframer.take_discard());
260
261 // `SendAdapter` records whether a send-side action may be needed after the above
262 // receive-side processing. If the sender was not locked no change could be made to it.
263 if let SendAdapter::Locked { send_required, .. } = send_adapter {
264 pending_flush_sender |= send_required;
265 }
266
267 drop(send_adapter);
268
269 let mut rt = Self {
270 state,
271 recv,
272 send,
273 pending_flush_sender,
274 };
275
276 if core::mem::take(&mut rt.pending_flush_sender) {
277 return Ok(ReceiveTrafficState::FlushSender(FlushSender { rt }));
278 }
279
280 Ok(match rt.recv.has_received_close_notify {
281 true => ReceiveTrafficState::CloseNotify,
282 false => ReceiveTrafficState::ReadMore(rt),
283 })
284 }
285}
286
287impl ReceiveTraffic<ClientSide> {
288 /// Returns the number of TLS1.3 tickets that have been received.
289 pub fn tls13_tickets_received(&self) -> u32 {
290 self.recv.tls13_tickets_received
291 }
292}
293
294impl<Side: SideData> fmt::Debug for ReceiveTraffic<Side> {
295 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296 f.debug_struct("ReceiveTraffic")
297 .finish_non_exhaustive()
298 }
299}
300
301/// A state machine that cycles between requiring further received TLS data
302/// and discharging received application data.
303///
304/// Each call to [`ReceiveTraffic::read()`] returns one of these states, and each
305/// non-terminal state lets you obtain the next one: [`ReadMore`] by supplying more
306/// input and calling [`read()`] again, and [`FlushSender`] / [`Available`]
307/// through their `into_next()` methods. [`CloseNotify`] is terminal.
308///
309/// ```text
310/// ╭────────────────╮
311/// ╭───────▶│ ReceiveTraffic │
312/// │ ╰───────┬────────╯
313/// ReadMore │ read(&mut input)
314/// │ ▼
315/// ╰────╭───────────────────────╮
316/// │ ReceiveTrafficState │──── CloseNotify ────▶ (terminal)
317/// ╭───▶╰──┬────────────────────╯
318/// │ │ │
319/// │ FlushSender Available
320/// │ .into_next() .into_next()
321/// │ │ │
322/// ╰───────┴──────────────╯
323/// ```
324///
325/// - [`ReadMore`]: more TLS input is required. The variant holds the
326/// `ReceiveTraffic`; collect more input and call [`read()`] on it again.
327/// - [`FlushSender`]: receiving may have produced data to send. Make a note to
328/// perform IO with the matching [`SendTraffic`], and then call
329/// [`FlushSender::into_next()`] for the next state.
330/// - [`Available`]: application data was received. Read it via
331/// [`ReceivedApplicationData::data()`], then call
332/// [`ReceivedApplicationData::into_next()`]: this discards the consumed input
333/// and returns the next state.
334/// - [`CloseNotify`]: the peer closed the receive direction cleanly. Terminal.
335///
336/// [`read()`]: ReceiveTraffic::read
337/// [`ReadMore`]: ReceiveTrafficState::ReadMore
338/// [`FlushSender`]: ReceiveTrafficState::FlushSender
339/// [`Available`]: ReceiveTrafficState::Available
340/// [`CloseNotify`]: ReceiveTrafficState::CloseNotify
341#[expect(clippy::exhaustive_enums)]
342pub enum ReceiveTrafficState<'a, Side: SideData> {
343 /// More input is required.
344 ///
345 /// Collect it into your input buffer, and then call [`ReceiveTraffic::read()`] again.
346 ReadMore(ReceiveTraffic<Side>),
347
348 /// The sender may have new data to send.
349 FlushSender(FlushSender<Side>),
350
351 /// Some application data has been received.
352 Available(ReceivedApplicationData<'a, Side>),
353
354 /// We received a `close_notify` alert from the peer.
355 ///
356 /// This means the receive path is closed cleanly.
357 CloseNotify,
358}
359
360impl<Side: SideData> fmt::Debug for ReceiveTrafficState<'_, Side> {
361 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362 match self {
363 Self::ReadMore(_) => f
364 .debug_tuple("ReadMore")
365 .finish_non_exhaustive(),
366 Self::FlushSender(_) => f
367 .debug_tuple("FlushSender")
368 .finish_non_exhaustive(),
369 Self::Available(_) => f
370 .debug_tuple("Available")
371 .finish_non_exhaustive(),
372 Self::CloseNotify => write!(f, "CloseNotify"),
373 }
374 }
375}
376
377/// Received application data.
378pub struct ReceivedApplicationData<'a, Side: SideData> {
379 /// The source buffer for the data.
380 input: &'a mut dyn TlsInputBuffer,
381
382 /// The span within the `received_tls` buffer holding the received data.
383 range: Range<usize>,
384
385 /// How many bytes on the front of the original input buffer are associated
386 /// with this data.
387 ///
388 /// This value is added to the discard count of the original input
389 /// buffer via [`TlsInputBuffer::discard()`].
390 pending_discard: usize,
391
392 rt: ReceiveTraffic<Side>,
393}
394
395impl<Side: SideData> ReceivedApplicationData<'_, Side> {
396 /// Return the application data bytes.
397 pub fn data(&mut self) -> &[u8] {
398 Delocator::new(self.input.slice_mut()).slice_from_range(&self.range)
399 }
400
401 /// Finish processing this received data.
402 ///
403 /// This acts upon the source buffer (used with the [`ReceiveTraffic::read()`] call) to
404 /// discard the received data.
405 ///
406 /// Returns the next [`ReceiveTrafficState`] state.
407 pub fn into_next(mut self) -> ReceiveTrafficState<'static, Side> {
408 self.input.discard(self.pending_discard);
409
410 if core::mem::take(&mut self.rt.pending_flush_sender) {
411 return ReceiveTrafficState::FlushSender(FlushSender { rt: self.rt });
412 }
413
414 match self.rt.recv.has_received_close_notify {
415 true => ReceiveTrafficState::CloseNotify,
416 false => ReceiveTrafficState::ReadMore(self.rt),
417 }
418 }
419}
420
421/// Notification that receiving data may have changed the state of the associated [`SendTraffic`]
422///
423/// The caller may wish to check whether there is any IO necessary on the send side. If it does
424/// not, and ignores this state, any pending new data to send will be included in the next
425/// attempt to send data.
426pub struct FlushSender<Side: SideData> {
427 rt: ReceiveTraffic<Side>,
428}
429
430impl<Side: SideData> FlushSender<Side> {
431 /// Obtain the next receive-side state.
432 pub fn into_next(self) -> ReceiveTrafficState<'static, Side> {
433 match self.rt.recv.has_received_close_notify {
434 true => ReceiveTrafficState::CloseNotify,
435 false => ReceiveTrafficState::ReadMore(self.rt),
436 }
437 }
438}
439
440/// Allows the receive-side of the connection to manipulate the send-side.
441///
442/// It is important for performance and concurrency that the receive-side
443/// does not regularly lock the send-side, so this is delayed until this
444/// proves to be actually required (via [`SendOutput`] methods).
445///
446/// It is important for analysis that the lock, once taken, remains taken
447/// for the remainder of the processing. This means that, for example,
448/// a sequence of sent messages is not interleaved with others from another
449/// thread.
450pub(super) enum SendAdapter<'a> {
451 Unlocked(&'a Mutex<SendPath>),
452 Locked {
453 guard: MutexGuard<'a, SendPath>,
454 send_required: bool,
455 },
456}
457
458impl<'a> SendAdapter<'a> {
459 fn as_locked<'b>(&'b mut self, may_send: bool) -> &'b mut MutexGuard<'a, SendPath> {
460 if let Self::Unlocked(m) = self {
461 *self = Self::Locked {
462 guard: m.lock().unwrap(),
463 send_required: false,
464 };
465 }
466 let Self::Locked {
467 guard,
468 send_required,
469 } = self
470 else {
471 unreachable!();
472 };
473 *send_required |= may_send;
474 guard
475 }
476}
477
478impl SendOutput for SendAdapter<'_> {
479 fn negotiated_version(&mut self, version: ProtocolVersion) {
480 self.as_locked(false)
481 .negotiated_version(version);
482 }
483
484 fn queue_requested_key_update(&mut self) {
485 // waking the sender here is a policy decision to encourage timely execution of
486 // the write-side key update, it is not strictly required at a protocol level.
487 self.as_locked(true)
488 .queue_requested_key_update();
489 }
490
491 fn note_key_update_response(&mut self) {
492 self.as_locked(false)
493 .note_key_update_response();
494 }
495
496 fn set_encrypter(&mut self, cipher: Box<dyn MessageEncrypter>, max_messages: u64) {
497 self.as_locked(false)
498 .set_encrypter(cipher, max_messages);
499 }
500
501 fn update_key_schedule(&mut self, schedule: Box<KeyScheduleTrafficSend>) {
502 self.as_locked(false)
503 .update_key_schedule(schedule);
504 }
505
506 fn send_alert(&mut self, level: AlertLevel, desc: AlertDescription, tls: &mut Vec<u8>) {
507 self.as_locked(true)
508 .send_alert(level, desc, tls)
509 }
510
511 fn start_traffic(&mut self) {
512 self.as_locked(false).start_traffic();
513 }
514
515 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool, tls: &mut Vec<u8>) {
516 self.as_locked(true)
517 .send_msg(m, must_encrypt, tls)
518 }
519}
520
521#[cfg(test)]
522mod tests {
523 use super::*;
524 use crate::crypto::test_provider::Tls13Cipher;
525
526 #[test]
527 fn send_adapter_flag() {
528 let mut tls = Vec::new();
529 assert!(!send_flag_for(
530 |adapter| adapter.negotiated_version(ProtocolVersion::TLSv1_3)
531 ));
532 assert!(send_flag_for(|adapter| adapter.queue_requested_key_update()));
533 assert!(!send_flag_for(|adapter| adapter.note_key_update_response()));
534 assert!(!send_flag_for(
535 |adapter| adapter.set_encrypter(Box::new(Tls13Cipher), 1234)
536 ));
537 // update_key_schedule too hard
538 assert!(send_flag_for(|adapter| adapter.send_alert(
539 AlertLevel::Fatal,
540 AlertDescription::CertificateUnknown,
541 &mut tls,
542 )));
543 assert!(!send_flag_for(|adapter| adapter.start_traffic()));
544 assert!(send_flag_for(|adapter| adapter.send_msg(
545 Message::build_key_update_notify(),
546 false,
547 &mut tls,
548 )));
549 }
550
551 fn send_flag_for(f: impl FnOnce(&mut SendAdapter<'_>)) -> bool {
552 let mut send = SendPath::default();
553 send.set_encrypter(Box::new(Tls13Cipher), 1234);
554
555 let send = Mutex::new(send);
556
557 let mut adapter = SendAdapter::Unlocked(&send);
558 f(&mut adapter);
559 let SendAdapter::Locked { send_required, .. } = adapter else {
560 panic!("expected to find SendAdapter::Locked");
561 };
562 send_required
563 }
564}