Skip to main content

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}