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