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