Skip to main content

rustls/conn/
handshake.rs

1//! Transport-generic handshake machinery.
2//!
3//! [`Accepted`] and [`VerifyPeerIdentity`] are public and generic over [`Transport`].
4//!
5//! The remaining public handshake types (`rustls::{NeedsInput, ClientHandshake,
6//! ServerHandshake}` and their `rustls::quic` counterparts) are thin shims over the types
7//! in this module.  The shims own the public signatures and documentation; the shared
8//! underlying logic lives here, parameterised by [`Transport`].
9
10use alloc::boxed::Box;
11use alloc::vec::Vec;
12use core::{fmt, mem};
13
14use super::{
15    Connection, NeedsInput, SideCommonOutput, SideData, StateMachine, VerifySidePeerIdentity,
16};
17use crate::client::{ClientSide, ClientState};
18use crate::common_state::{Protocol, maybe_send_fatal_alert};
19use crate::crypto::VerifiedIdentity;
20use crate::error::Error;
21use crate::msgs::ServerExtensionsInput;
22use crate::quic::{FromConn, Quic, QuicEvent, QuicOutput};
23use crate::server::{
24    ChooseConfig, ClientHello, ServerConfig, ServerHandshake, ServerSide, ServerState,
25};
26use crate::sync::Arc;
27use crate::tracing::trace;
28
29/// The result of processing handshake input.
30pub(crate) enum Processed<Side: SideData, T: Transport> {
31    /// The handshake progressed as far as the available input allows.
32    Progress(Connection<Side, T>),
33
34    /// A piece of early data was received.
35    EarlyData {
36        conn: Connection<Side, T>,
37        data: Vec<u8>,
38    },
39}
40
41impl<Side: SideData, T: Transport> Processed<Side, T> {
42    /// Returns the connection, for transports or sides that never receive early data.
43    pub(crate) fn into_progress(self) -> Result<Connection<Side, T>, Error> {
44        match self {
45            Self::Progress(conn) => Ok(conn),
46            Self::EarlyData { .. } => Err(Error::Unreachable("unexpected early data")),
47        }
48    }
49}
50
51/// The states a server handshake can be in, for any transport.
52pub(crate) enum ServerNext<T: Transport> {
53    NeedsInput(Connection<ServerSide, T>),
54    ChooseConfig(Accepted<T>),
55    VerifyClientIdentity(VerifyPeerIdentity<ServerSide, T>),
56    Complete(Connection<ServerSide, T>),
57}
58
59impl<T: Transport> TryFrom<Connection<ServerSide, T>> for ServerNext<T> {
60    type Error = Error;
61
62    fn try_from(mut conn: Connection<ServerSide, T>) -> Result<Self, Error> {
63        const MISUSED: Error = Error::Unreachable("forgot to restore state");
64
65        Ok(match mem::replace(&mut conn.state, Err(MISUSED))? {
66            ServerState::ChooseConfig(choose_config) => Self::ChooseConfig(Accepted {
67                conn,
68                choose_config,
69            }),
70
71            ServerState::VerifyClientIdentity(verify_identity) => {
72                Self::VerifyClientIdentity(VerifyPeerIdentity {
73                    conn,
74                    verify_identity,
75                })
76            }
77
78            state if state.is_traffic() => {
79                conn.state = Ok(state);
80                Self::Complete(conn)
81            }
82
83            state => {
84                conn.state = Ok(state);
85                Self::NeedsInput(conn)
86            }
87        })
88    }
89}
90
91/// The states a client handshake can be in, for any transport.
92pub(crate) enum ClientNext<T: Transport> {
93    NeedsInput(Connection<ClientSide, T>),
94    VerifyServerIdentity(VerifyPeerIdentity<ClientSide, T>),
95    Complete(Connection<ClientSide, T>),
96}
97
98impl<T: Transport> TryFrom<Connection<ClientSide, T>> for ClientNext<T> {
99    type Error = Error;
100
101    fn try_from(mut conn: Connection<ClientSide, T>) -> Result<Self, Error> {
102        const MISUSED: Error = Error::Unreachable("forgot to restore state");
103
104        Ok(match mem::replace(&mut conn.state, Err(MISUSED))? {
105            ClientState::VerifyServerIdentity(verify_identity) => {
106                Self::VerifyServerIdentity(VerifyPeerIdentity {
107                    conn,
108                    verify_identity,
109                })
110            }
111
112            state if state.is_traffic() => {
113                conn.state = Ok(state);
114                Self::Complete(conn)
115            }
116
117            state => {
118                conn.state = Ok(state);
119                Self::NeedsInput(conn)
120            }
121        })
122    }
123}
124
125/// Represents that a `ClientHello` message has been received.
126///
127/// The handshake can be progressed by choosing a [`ServerConfig`] based on
128/// [`Self::client_hello()`] and providing it to [`Self::choose_config()`].
129pub struct Accepted<T: Transport> {
130    // invariant: `core.inner.state` is `Err(_)` and requires restoring
131    pub(crate) conn: Connection<ServerSide, T>,
132    choose_config: Box<ChooseConfig>,
133}
134
135impl<T: Transport> Accepted<T> {
136    /// Get the [`ClientHello`] for this connection.
137    pub fn client_hello(&self) -> ClientHello<'_> {
138        let ch = self.choose_config.client_hello();
139        trace!("Accepted::client_hello(): {ch:#?}");
140        ch
141    }
142
143    pub(crate) fn partial_choose_config(
144        self,
145        config: Arc<ServerConfig>,
146        exts: ServerExtensionsInput,
147        tls: &mut Vec<u8>,
148    ) -> Result<Connection<ServerSide, T>, Error> {
149        let Self {
150            mut conn,
151            choose_config,
152        } = self;
153
154        let result = conn.accepted(choose_config, exts, config, tls);
155
156        let send_path = &mut conn.common.send;
157
158        if let Err(err) = &result {
159            maybe_send_fatal_alert(send_path, err, tls)?;
160        }
161
162        result?;
163        Ok(conn)
164    }
165}
166
167impl Accepted<Tcp> {
168    /// Choose a [`ServerConfig`] to progress the handshake.
169    ///
170    /// Output to send to the peer is appended to `tls`.  Typically, this is the `ServerHello`,
171    /// but it may also be an `Alert` if an error is returned.
172    ///
173    /// Returns an error if configuration-dependent validation of the received `ClientHello` message fails.
174    pub fn choose_config(
175        self,
176        config: Arc<ServerConfig>,
177        tls: &mut Vec<u8>,
178    ) -> Result<ServerHandshake, Error> {
179        Ok(ServerHandshake::NeedsInput(NeedsInput(
180            self.partial_choose_config(config, ServerExtensionsInput::default(), tls)?,
181        )))
182    }
183}
184
185impl<T: Transport> fmt::Debug for Accepted<T> {
186    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187        f.debug_struct("Accepted")
188            .finish_non_exhaustive()
189    }
190}
191
192/// The peer's presented identity must be verified.
193///
194/// The caller has three choices:
195///
196/// - Call [`Self::with_config()`].  This calls the configured verifier trait
197///   ([`ClientVerifier::verify_identity()`][] or [`ServerVerifier::verify_identity()`][])
198///   synchronously.
199///
200/// - Call [`Self::presented_identity()`] to obtain the peer's presented identity,
201///   verify that outside the library (perhaps asynchronously), and then continue the handshake with
202///   [`Self::continue_with()`].
203///
204///   Sessions established this way are stored for resumption exactly as if the configured verifier
205///   had been used.  The external verification must therefore be equivalent to the configured verifier.
206///   If it applies a different policy, use a separate config with separate resumption storage.
207///
208///   If the verification fails, the error can be passed into [`Self::continue_with()`] to follow
209///   a uniform error handling path.
210///
211/// - Abandon the handshake by discarding this object.
212///
213/// The returned object is a further handshake state for this side.  Commonly this will
214/// contain a [`ServerHandshake::NeedsInput`][], [`ClientHandshake::NeedsInput`][],
215/// [`quic::ServerHandshake::NeedsInput`][] or [`quic::ClientHandshake::NeedsInput`][]
216/// which will accept and process further data.
217///
218/// [`ClientVerifier::verify_identity()`]: crate::verify::ClientVerifier::verify_identity
219/// [`ServerVerifier::verify_identity()`]: crate::verify::ServerVerifier::verify_identity
220/// [`ServerHandshake::NeedsInput`]: crate::server::ServerHandshake::NeedsInput
221/// [`ClientHandshake::NeedsInput`]: crate::client::ClientHandshake::NeedsInput
222/// [`quic::ServerHandshake::NeedsInput`]: crate::quic::ServerHandshake::NeedsInput
223/// [`quic::ClientHandshake::NeedsInput`]: crate::quic::ClientHandshake::NeedsInput
224pub struct VerifyPeerIdentity<Side: SideData, T: Transport> {
225    // invariant: `core.inner.state` is `Err(_)` and requires restoring
226    conn: Connection<Side, T>,
227    verify_identity: Box<dyn VerifySidePeerIdentity<Side>>,
228}
229
230impl<Side: SideData, T: Transport> VerifyPeerIdentity<Side, T> {
231    /// Inspect the identity that the peer has provided.
232    pub fn presented_identity(&self) -> Result<Side::PeerIdentity<'_>, Error> {
233        self.verify_identity
234            .presented_identity()
235    }
236}
237
238impl<Side: SideData> VerifyPeerIdentity<Side, Tcp> {
239    /// Progress the handshake by calling the pre-configured certificate verification trait.
240    pub fn with_config(self, tls: &mut Vec<u8>) -> Result<Side::Handshake, Error> {
241        let result = self
242            .verify_identity
243            .verify_with_config();
244        self.continue_with(result, tls)
245    }
246
247    /// Progress the handshake by incorporating the result of an external verification.
248    ///
249    /// Further data to send to the peer may be appended to `tls`.
250    ///
251    /// See [`VerifyPeerIdentity`] for important requirements related to resumption safety.
252    ///
253    /// If `verification_result` is an error, this error is returned and the handshake terminates.
254    /// An alert may be appended to `tls` for sending to the peer.
255    pub fn continue_with(
256        self,
257        verification_result: Result<VerifiedIdentity<'static>, Error>,
258        tls: &mut Vec<u8>,
259    ) -> Result<Side::Handshake, Error> {
260        self.partial_continue_with(verification_result, tls)?
261            .into_handshake()
262    }
263}
264
265impl<Side: SideData> VerifyPeerIdentity<Side, Quic> {
266    /// Progress the handshake by calling the pre-configured certificate verification trait.
267    pub fn with_config(self, output: &mut Vec<QuicEvent>) -> Result<Side::QuicHandshake, Error> {
268        let result = self
269            .verify_identity
270            .verify_with_config();
271        self.continue_with(result, output)
272    }
273
274    /// Progress the handshake by incorporating the result of an external verification.
275    ///
276    /// See [`VerifyPeerIdentity`] for important requirements related to resumption safety.
277    ///
278    /// If `verification_result` is an error, this error is returned and the handshake terminates.
279    ///
280    /// Events are appended to `output`.
281    pub fn continue_with(
282        self,
283        verification_result: Result<VerifiedIdentity<'static>, Error>,
284        output: &mut Vec<QuicEvent>,
285    ) -> Result<Side::QuicHandshake, Error> {
286        Side::QuicHandshake::from_conn(
287            self.partial_continue_with(verification_result, &mut Vec::new())?,
288            output,
289        )
290    }
291}
292
293impl<Side: SideData, T: Transport> VerifyPeerIdentity<Side, T> {
294    fn partial_continue_with(
295        self,
296        verification_result: Result<VerifiedIdentity<'static>, Error>,
297        tls: &mut Vec<u8>,
298    ) -> Result<Connection<Side, T>, Error> {
299        let Self {
300            mut conn,
301            verify_identity,
302        } = self;
303
304        let result = verification_result.and_then(|verified| {
305            verify_identity.continue_with(
306                verified,
307                &mut SideCommonOutput {
308                    side: &mut conn.side,
309                    quic: T::quic(&mut conn.transport),
310                    common: &mut conn.common,
311                    tls,
312                },
313            )
314        });
315
316        if let Err(err) = &result {
317            maybe_send_fatal_alert(&mut conn.common.send, err, tls)?;
318        }
319
320        conn.state = result;
321        Ok(conn)
322    }
323}
324
325impl<Side: SideData, T: Transport> fmt::Debug for VerifyPeerIdentity<Side, T> {
326    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
327        f.debug_struct("VerifyPeerIdentity")
328            .finish_non_exhaustive()
329    }
330}
331
332/// The aspects of a handshake that depend on the underlying transport.
333#[expect(private_bounds)]
334pub trait Transport: Sized + sealed::Transport {}
335
336pub(crate) mod sealed {
337    use super::QuicOutput;
338    use crate::Protocol;
339
340    pub(crate) trait Transport {
341        fn protocol(&self) -> Protocol;
342
343        /// The sink for QUIC-specific events.
344        fn quic(&mut self) -> Option<&mut dyn QuicOutput>;
345    }
346}
347
348/// TLS over TCP.
349#[expect(clippy::exhaustive_structs)]
350pub struct Tcp;
351
352impl Transport for Tcp {}
353
354impl sealed::Transport for Tcp {
355    fn protocol(&self) -> Protocol {
356        Protocol::Tcp
357    }
358
359    fn quic(&mut self) -> Option<&mut dyn QuicOutput> {
360        None
361    }
362}