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::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}