rustls/conn/
unbuffered.rs

1//! Unbuffered connection API
2
3use alloc::vec::Vec;
4use core::num::NonZeroUsize;
5use core::{fmt, mem};
6#[cfg(feature = "std")]
7use std::error::Error as StdError;
8
9use super::UnbufferedConnectionCommon;
10use crate::Error;
11use crate::client::ClientConnectionData;
12use crate::msgs::deframer::buffers::DeframerSliceBuffer;
13use crate::server::ServerConnectionData;
14
15impl UnbufferedConnectionCommon<ClientConnectionData> {
16    /// Processes the TLS records in `incoming_tls` buffer until a new [`UnbufferedStatus`] is
17    /// reached.
18    pub fn process_tls_records<'c, 'i>(
19        &'c mut self,
20        incoming_tls: &'i mut [u8],
21    ) -> UnbufferedStatus<'c, 'i, ClientConnectionData> {
22        self.process_tls_records_common(incoming_tls, |_| false, |_, _| unreachable!())
23    }
24}
25
26impl UnbufferedConnectionCommon<ServerConnectionData> {
27    /// Processes the TLS records in `incoming_tls` buffer until a new [`UnbufferedStatus`] is
28    /// reached.
29    pub fn process_tls_records<'c, 'i>(
30        &'c mut self,
31        incoming_tls: &'i mut [u8],
32    ) -> UnbufferedStatus<'c, 'i, ServerConnectionData> {
33        self.process_tls_records_common(
34            incoming_tls,
35            |conn| conn.peek_early_data().is_some(),
36            |conn, incoming_tls| ReadEarlyData::new(conn, incoming_tls).into(),
37        )
38    }
39}
40
41impl<Data> UnbufferedConnectionCommon<Data> {
42    fn process_tls_records_common<'c, 'i>(
43        &'c mut self,
44        incoming_tls: &'i mut [u8],
45        mut early_data_available: impl FnMut(&mut Self) -> bool,
46        early_data_state: impl FnOnce(&'c mut Self, &'i mut [u8]) -> ConnectionState<'c, 'i, Data>,
47    ) -> UnbufferedStatus<'c, 'i, Data> {
48        let mut buffer = DeframerSliceBuffer::new(incoming_tls);
49        let mut buffer_progress = self.core.hs_deframer.progress();
50
51        let (discard, state) = loop {
52            if early_data_available(self) {
53                break (
54                    buffer.pending_discard(),
55                    early_data_state(self, incoming_tls),
56                );
57            }
58
59            if !self
60                .core
61                .common_state
62                .received_plaintext
63                .is_empty()
64            {
65                break (
66                    buffer.pending_discard(),
67                    ReadTraffic::new(self, incoming_tls).into(),
68                );
69            }
70
71            if let Some(chunk) = self
72                .core
73                .common_state
74                .sendable_tls
75                .pop()
76            {
77                break (
78                    buffer.pending_discard(),
79                    EncodeTlsData::new(self, chunk).into(),
80                );
81            }
82
83            let deframer_output = if self
84                .core
85                .common_state
86                .has_received_close_notify
87            {
88                None
89            } else {
90                match self
91                    .core
92                    .deframe(None, buffer.filled_mut(), &mut buffer_progress)
93                {
94                    Err(err) => {
95                        buffer.queue_discard(buffer_progress.take_discard());
96                        return UnbufferedStatus {
97                            discard: buffer.pending_discard(),
98                            state: Err(err),
99                        };
100                    }
101                    Ok(r) => r,
102                }
103            };
104
105            if let Some(msg) = deframer_output {
106                let mut state =
107                    match mem::replace(&mut self.core.state, Err(Error::HandshakeNotComplete)) {
108                        Ok(state) => state,
109                        Err(e) => {
110                            buffer.queue_discard(buffer_progress.take_discard());
111                            self.core.state = Err(e.clone());
112                            return UnbufferedStatus {
113                                discard: buffer.pending_discard(),
114                                state: Err(e),
115                            };
116                        }
117                    };
118
119                match self.core.process_msg(msg, state, None) {
120                    Ok(new) => state = new,
121
122                    Err(e) => {
123                        buffer.queue_discard(buffer_progress.take_discard());
124                        self.core.state = Err(e.clone());
125                        return UnbufferedStatus {
126                            discard: buffer.pending_discard(),
127                            state: Err(e),
128                        };
129                    }
130                }
131
132                buffer.queue_discard(buffer_progress.take_discard());
133
134                self.core.state = Ok(state);
135            } else if self.wants_write {
136                break (
137                    buffer.pending_discard(),
138                    TransmitTlsData { conn: self }.into(),
139                );
140            } else if self
141                .core
142                .common_state
143                .has_received_close_notify
144                && !self.emitted_peer_closed_state
145            {
146                self.emitted_peer_closed_state = true;
147                break (buffer.pending_discard(), ConnectionState::PeerClosed);
148            } else if self
149                .core
150                .common_state
151                .has_received_close_notify
152                && self
153                    .core
154                    .common_state
155                    .has_sent_close_notify
156            {
157                break (buffer.pending_discard(), ConnectionState::Closed);
158            } else if self
159                .core
160                .common_state
161                .may_send_application_data
162            {
163                break (
164                    buffer.pending_discard(),
165                    ConnectionState::WriteTraffic(WriteTraffic { conn: self }),
166                );
167            } else {
168                break (buffer.pending_discard(), ConnectionState::BlockedHandshake);
169            }
170        };
171
172        UnbufferedStatus {
173            discard,
174            state: Ok(state),
175        }
176    }
177}
178
179/// The current status of the `UnbufferedConnection*`
180#[must_use]
181#[derive(Debug)]
182pub struct UnbufferedStatus<'c, 'i, Data> {
183    /// Number of bytes to discard
184    ///
185    /// After the `state` field of this object has been handled, `discard` bytes must be
186    /// removed from the *front* of the `incoming_tls` buffer that was passed to
187    /// the [`UnbufferedConnectionCommon::process_tls_records`] call that returned this object.
188    ///
189    /// This discard operation MUST happen *before*
190    /// [`UnbufferedConnectionCommon::process_tls_records`] is called again.
191    pub discard: usize,
192
193    /// The current state of the handshake process
194    ///
195    /// This value MUST be handled prior to calling
196    /// [`UnbufferedConnectionCommon::process_tls_records`] again. See the documentation on the
197    /// variants of [`ConnectionState`] for more details.
198    pub state: Result<ConnectionState<'c, 'i, Data>, Error>,
199}
200
201/// The state of the [`UnbufferedConnectionCommon`] object
202#[non_exhaustive] // for forwards compatibility; to support caller-side certificate verification
203pub enum ConnectionState<'c, 'i, Data> {
204    /// One, or more, application data records are available
205    ///
206    /// See [`ReadTraffic`] for more details on how to use the enclosed object to access
207    /// the received data.
208    ReadTraffic(ReadTraffic<'c, 'i, Data>),
209
210    /// Connection has been cleanly closed by the peer.
211    ///
212    /// This state is encountered at most once by each connection -- it is
213    /// "edge" triggered, rather than "level" triggered.
214    ///
215    /// It delimits the data received from the peer, meaning you can be sure you
216    /// have received all the data the peer sent.
217    ///
218    /// No further application data will be received from the peer, so no further
219    /// `ReadTraffic` states will be produced.
220    ///
221    /// However, it is possible to _send_ further application data via `WriteTraffic`
222    /// states, or close the connection cleanly by calling
223    /// [`WriteTraffic::queue_close_notify()`].
224    PeerClosed,
225
226    /// Connection has been cleanly closed by both us and the peer.
227    ///
228    /// This is a terminal state.  No other states will be produced for this
229    /// connection.
230    Closed,
231
232    /// One, or more, early (RTT-0) data records are available
233    ReadEarlyData(ReadEarlyData<'c, 'i, Data>),
234
235    /// A Handshake record is ready for encoding
236    ///
237    /// Call [`EncodeTlsData::encode`] on the enclosed object, providing an `outgoing_tls`
238    /// buffer to store the encoding
239    EncodeTlsData(EncodeTlsData<'c, Data>),
240
241    /// Previously encoded handshake records need to be transmitted
242    ///
243    /// Transmit the contents of the `outgoing_tls` buffer that was passed to previous
244    /// [`EncodeTlsData::encode`] calls to the peer.
245    ///
246    /// After transmitting the contents, call [`TransmitTlsData::done`] on the enclosed object.
247    /// The transmitted contents MUST not be sent to the peer more than once so they SHOULD be
248    /// discarded at this point.
249    ///
250    /// At some stages of the handshake process, it's possible to send application-data alongside
251    /// handshake records. Call [`TransmitTlsData::may_encrypt_app_data`] on the enclosed
252    /// object to probe if that's allowed.
253    TransmitTlsData(TransmitTlsData<'c, Data>),
254
255    /// More TLS data is needed to continue with the handshake
256    ///
257    /// Request more data from the peer and append the contents to the `incoming_tls` buffer that
258    /// was passed to [`UnbufferedConnectionCommon::process_tls_records`].
259    BlockedHandshake,
260
261    /// The handshake process has been completed.
262    ///
263    /// [`WriteTraffic::encrypt`] can be called on the enclosed object to encrypt application
264    /// data into an `outgoing_tls` buffer. Similarly, [`WriteTraffic::queue_close_notify`] can
265    /// be used to encrypt a close_notify alert message into a buffer to signal the peer that the
266    /// connection is being closed. Data written into `outgoing_buffer` by either method MAY be
267    /// transmitted to the peer during this state.
268    ///
269    /// Once this state has been reached, data MAY be requested from the peer and appended to an
270    /// `incoming_tls` buffer that will be passed to a future
271    /// [`UnbufferedConnectionCommon::process_tls_records`] invocation. When enough data has been
272    /// appended to `incoming_tls`, [`UnbufferedConnectionCommon::process_tls_records`] will yield
273    /// the [`ConnectionState::ReadTraffic`] state.
274    WriteTraffic(WriteTraffic<'c, Data>),
275}
276
277impl<'c, 'i, Data> From<ReadTraffic<'c, 'i, Data>> for ConnectionState<'c, 'i, Data> {
278    fn from(v: ReadTraffic<'c, 'i, Data>) -> Self {
279        Self::ReadTraffic(v)
280    }
281}
282
283impl<'c, 'i, Data> From<ReadEarlyData<'c, 'i, Data>> for ConnectionState<'c, 'i, Data> {
284    fn from(v: ReadEarlyData<'c, 'i, Data>) -> Self {
285        Self::ReadEarlyData(v)
286    }
287}
288
289impl<'c, Data> From<EncodeTlsData<'c, Data>> for ConnectionState<'c, '_, Data> {
290    fn from(v: EncodeTlsData<'c, Data>) -> Self {
291        Self::EncodeTlsData(v)
292    }
293}
294
295impl<'c, Data> From<TransmitTlsData<'c, Data>> for ConnectionState<'c, '_, Data> {
296    fn from(v: TransmitTlsData<'c, Data>) -> Self {
297        Self::TransmitTlsData(v)
298    }
299}
300
301impl<Data> fmt::Debug for ConnectionState<'_, '_, Data> {
302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        match self {
304            Self::ReadTraffic(..) => f.debug_tuple("ReadTraffic").finish(),
305
306            Self::PeerClosed => write!(f, "PeerClosed"),
307
308            Self::Closed => write!(f, "Closed"),
309
310            Self::ReadEarlyData(..) => f.debug_tuple("ReadEarlyData").finish(),
311
312            Self::EncodeTlsData(..) => f.debug_tuple("EncodeTlsData").finish(),
313
314            Self::TransmitTlsData(..) => f
315                .debug_tuple("TransmitTlsData")
316                .finish(),
317
318            Self::BlockedHandshake => f
319                .debug_tuple("BlockedHandshake")
320                .finish(),
321
322            Self::WriteTraffic(..) => f.debug_tuple("WriteTraffic").finish(),
323        }
324    }
325}
326
327/// Application data is available
328pub struct ReadTraffic<'c, 'i, Data> {
329    conn: &'c mut UnbufferedConnectionCommon<Data>,
330    // for forwards compatibility; to support in-place decryption in the future
331    _incoming_tls: &'i mut [u8],
332
333    // owner of the latest chunk obtained in `next_record`, as borrowed by
334    // `AppDataRecord`
335    chunk: Option<Vec<u8>>,
336}
337
338impl<'c, 'i, Data> ReadTraffic<'c, 'i, Data> {
339    fn new(conn: &'c mut UnbufferedConnectionCommon<Data>, _incoming_tls: &'i mut [u8]) -> Self {
340        Self {
341            conn,
342            _incoming_tls,
343            chunk: None,
344        }
345    }
346
347    /// Decrypts and returns the next available app-data record
348    // TODO deprecate in favor of `Iterator` implementation, which requires in-place decryption
349    pub fn next_record(&mut self) -> Option<Result<AppDataRecord<'_>, Error>> {
350        self.chunk = self
351            .conn
352            .core
353            .common_state
354            .received_plaintext
355            .pop();
356        self.chunk.as_ref().map(|chunk| {
357            Ok(AppDataRecord {
358                discard: 0,
359                payload: chunk,
360            })
361        })
362    }
363
364    /// Returns the payload size of the next app-data record *without* decrypting it
365    ///
366    /// Returns `None` if there are no more app-data records
367    pub fn peek_len(&self) -> Option<NonZeroUsize> {
368        self.conn
369            .core
370            .common_state
371            .received_plaintext
372            .peek()
373            .and_then(|ch| NonZeroUsize::new(ch.len()))
374    }
375}
376
377/// Early application-data is available.
378pub struct ReadEarlyData<'c, 'i, Data> {
379    conn: &'c mut UnbufferedConnectionCommon<Data>,
380
381    // for forwards compatibility; to support in-place decryption in the future
382    _incoming_tls: &'i mut [u8],
383
384    // owner of the latest chunk obtained in `next_record`, as borrowed by
385    // `AppDataRecord`
386    chunk: Option<Vec<u8>>,
387}
388
389impl<'c, 'i> ReadEarlyData<'c, 'i, ServerConnectionData> {
390    fn new(
391        conn: &'c mut UnbufferedConnectionCommon<ServerConnectionData>,
392        _incoming_tls: &'i mut [u8],
393    ) -> Self {
394        Self {
395            conn,
396            _incoming_tls,
397            chunk: None,
398        }
399    }
400
401    /// decrypts and returns the next available app-data record
402    // TODO deprecate in favor of `Iterator` implementation, which requires in-place decryption
403    pub fn next_record(&mut self) -> Option<Result<AppDataRecord<'_>, Error>> {
404        self.chunk = self.conn.pop_early_data();
405        self.chunk.as_ref().map(|chunk| {
406            Ok(AppDataRecord {
407                discard: 0,
408                payload: chunk,
409            })
410        })
411    }
412
413    /// returns the payload size of the next app-data record *without* decrypting it
414    ///
415    /// returns `None` if there are no more app-data records
416    pub fn peek_len(&self) -> Option<NonZeroUsize> {
417        self.conn
418            .peek_early_data()
419            .and_then(|ch| NonZeroUsize::new(ch.len()))
420    }
421}
422
423/// A decrypted application-data record
424pub struct AppDataRecord<'i> {
425    /// Number of additional bytes to discard
426    ///
427    /// This number MUST be added to the value of [`UnbufferedStatus.discard`] *prior* to the
428    /// discard operation. See [`UnbufferedStatus.discard`] for more details
429    pub discard: usize,
430
431    /// The payload of the app-data record
432    pub payload: &'i [u8],
433}
434
435/// Allows encrypting app-data
436pub struct WriteTraffic<'c, Data> {
437    conn: &'c mut UnbufferedConnectionCommon<Data>,
438}
439
440impl<Data> WriteTraffic<'_, Data> {
441    /// Encrypts `application_data` into the `outgoing_tls` buffer
442    ///
443    /// Returns the number of bytes that were written into `outgoing_tls`, or an error if
444    /// the provided buffer is too small. In the error case, `outgoing_tls` is not modified
445    pub fn encrypt(
446        &mut self,
447        application_data: &[u8],
448        outgoing_tls: &mut [u8],
449    ) -> Result<usize, EncryptError> {
450        self.conn
451            .core
452            .maybe_refresh_traffic_keys();
453        self.conn
454            .core
455            .common_state
456            .write_plaintext(application_data.into(), outgoing_tls)
457    }
458
459    /// Encrypts a close_notify warning alert in `outgoing_tls`
460    ///
461    /// Returns the number of bytes that were written into `outgoing_tls`, or an error if
462    /// the provided buffer is too small. In the error case, `outgoing_tls` is not modified
463    pub fn queue_close_notify(&mut self, outgoing_tls: &mut [u8]) -> Result<usize, EncryptError> {
464        self.conn
465            .core
466            .common_state
467            .eager_send_close_notify(outgoing_tls)
468    }
469
470    /// Arranges for a TLS1.3 `key_update` to be sent.
471    ///
472    /// This consumes the `WriteTraffic` state:  to actually send the message,
473    /// call [`UnbufferedConnectionCommon::process_tls_records`] again which will
474    /// return a `ConnectionState::EncodeTlsData` that emits the `key_update`
475    /// message.
476    ///
477    /// See [`ConnectionCommon::refresh_traffic_keys()`] for full documentation,
478    /// including why you might call this and in what circumstances it will fail.
479    ///
480    /// [`ConnectionCommon::refresh_traffic_keys()`]: crate::ConnectionCommon::refresh_traffic_keys
481    pub fn refresh_traffic_keys(self) -> Result<(), Error> {
482        self.conn.core.refresh_traffic_keys()
483    }
484}
485
486/// A handshake record must be encoded
487pub struct EncodeTlsData<'c, Data> {
488    conn: &'c mut UnbufferedConnectionCommon<Data>,
489    chunk: Option<Vec<u8>>,
490}
491
492impl<'c, Data> EncodeTlsData<'c, Data> {
493    fn new(conn: &'c mut UnbufferedConnectionCommon<Data>, chunk: Vec<u8>) -> Self {
494        Self {
495            conn,
496            chunk: Some(chunk),
497        }
498    }
499
500    /// Encodes a handshake record into the `outgoing_tls` buffer
501    ///
502    /// Returns the number of bytes that were written into `outgoing_tls`, or an error if
503    /// the provided buffer is too small. In the error case, `outgoing_tls` is not modified
504    pub fn encode(&mut self, outgoing_tls: &mut [u8]) -> Result<usize, EncodeError> {
505        let Some(chunk) = self.chunk.take() else {
506            return Err(EncodeError::AlreadyEncoded);
507        };
508
509        let required_size = chunk.len();
510
511        if required_size > outgoing_tls.len() {
512            self.chunk = Some(chunk);
513            Err(InsufficientSizeError { required_size }.into())
514        } else {
515            let written = chunk.len();
516            outgoing_tls[..written].copy_from_slice(&chunk);
517
518            self.conn.wants_write = true;
519
520            Ok(written)
521        }
522    }
523}
524
525/// Previously encoded TLS data must be transmitted
526pub struct TransmitTlsData<'c, Data> {
527    pub(crate) conn: &'c mut UnbufferedConnectionCommon<Data>,
528}
529
530impl<Data> TransmitTlsData<'_, Data> {
531    /// Signals that the previously encoded TLS data has been transmitted
532    pub fn done(self) {
533        self.conn.wants_write = false;
534    }
535
536    /// Returns an adapter that allows encrypting application data
537    ///
538    /// If allowed at this stage of the handshake process
539    pub fn may_encrypt_app_data(&mut self) -> Option<WriteTraffic<'_, Data>> {
540        if self
541            .conn
542            .core
543            .common_state
544            .may_send_application_data
545        {
546            Some(WriteTraffic { conn: self.conn })
547        } else {
548            None
549        }
550    }
551}
552
553/// Errors that may arise when encoding a handshake record
554#[derive(Debug)]
555pub enum EncodeError {
556    /// Provided buffer was too small
557    InsufficientSize(InsufficientSizeError),
558
559    /// The handshake record has already been encoded; do not call `encode` again
560    AlreadyEncoded,
561}
562
563impl From<InsufficientSizeError> for EncodeError {
564    fn from(v: InsufficientSizeError) -> Self {
565        Self::InsufficientSize(v)
566    }
567}
568
569impl fmt::Display for EncodeError {
570    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
571        match self {
572            Self::InsufficientSize(InsufficientSizeError { required_size }) => write!(
573                f,
574                "cannot encode due to insufficient size, {required_size} bytes are required"
575            ),
576            Self::AlreadyEncoded => "cannot encode, data has already been encoded".fmt(f),
577        }
578    }
579}
580
581#[cfg(feature = "std")]
582impl StdError for EncodeError {}
583
584/// Errors that may arise when encrypting application data
585#[derive(Debug)]
586pub enum EncryptError {
587    /// Provided buffer was too small
588    InsufficientSize(InsufficientSizeError),
589
590    /// Encrypter has been exhausted
591    EncryptExhausted,
592}
593
594impl From<InsufficientSizeError> for EncryptError {
595    fn from(v: InsufficientSizeError) -> Self {
596        Self::InsufficientSize(v)
597    }
598}
599
600impl fmt::Display for EncryptError {
601    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
602        match self {
603            Self::InsufficientSize(InsufficientSizeError { required_size }) => write!(
604                f,
605                "cannot encrypt due to insufficient size, {required_size} bytes are required"
606            ),
607            Self::EncryptExhausted => f.write_str("encrypter has been exhausted"),
608        }
609    }
610}
611
612#[cfg(feature = "std")]
613impl StdError for EncryptError {}
614
615/// Provided buffer was too small
616#[derive(Clone, Copy, Debug)]
617pub struct InsufficientSizeError {
618    /// buffer must be at least this size
619    pub required_size: usize,
620}