rustls/server/
hs.rs

1use crate::common_state::State;
2use crate::conn::ConnectionRandoms;
3use crate::dns_name::DnsName;
4#[cfg(feature = "tls12")]
5use crate::enums::CipherSuite;
6use crate::enums::{AlertDescription, HandshakeType, ProtocolVersion, SignatureScheme};
7use crate::error::{Error, PeerIncompatible, PeerMisbehaved};
8use crate::hash_hs::{HandshakeHash, HandshakeHashBuffer};
9#[cfg(feature = "logging")]
10use crate::log::{debug, trace};
11use crate::msgs::enums::{Compression, ExtensionType};
12#[cfg(feature = "tls12")]
13use crate::msgs::handshake::SessionId;
14use crate::msgs::handshake::{ClientHelloPayload, Random, ServerExtension};
15use crate::msgs::handshake::{ConvertProtocolNameList, ConvertServerNameList, HandshakePayload};
16use crate::msgs::message::{Message, MessagePayload};
17use crate::msgs::persist;
18use crate::server::{ClientHello, ServerConfig};
19use crate::suites;
20use crate::SupportedCipherSuite;
21
22use super::server_conn::ServerConnectionData;
23#[cfg(feature = "tls12")]
24use super::tls12;
25use crate::server::common::ActiveCertifiedKey;
26use crate::server::tls13;
27
28use std::sync::Arc;
29
30pub(super) type NextState = Box<dyn State<ServerConnectionData>>;
31pub(super) type NextStateOrError = Result<NextState, Error>;
32pub(super) type ServerContext<'a> = crate::common_state::Context<'a, ServerConnectionData>;
33
34pub(super) fn can_resume(
35    suite: SupportedCipherSuite,
36    sni: &Option<DnsName>,
37    using_ems: bool,
38    resumedata: &persist::ServerSessionValue,
39) -> bool {
40    // The RFCs underspecify what happens if we try to resume to
41    // an unoffered/varying suite.  We merely don't resume in weird cases.
42    //
43    // RFC 6066 says "A server that implements this extension MUST NOT accept
44    // the request to resume the session if the server_name extension contains
45    // a different name. Instead, it proceeds with a full handshake to
46    // establish a new session."
47    resumedata.cipher_suite == suite.suite()
48        && (resumedata.extended_ms == using_ems || (resumedata.extended_ms && !using_ems))
49        && &resumedata.sni == sni
50}
51
52#[derive(Default)]
53pub(super) struct ExtensionProcessing {
54    // extensions to reply with
55    pub(super) exts: Vec<ServerExtension>,
56    #[cfg(feature = "tls12")]
57    pub(super) send_ticket: bool,
58}
59
60impl ExtensionProcessing {
61    pub(super) fn new() -> Self {
62        Default::default()
63    }
64
65    pub(super) fn process_common(
66        &mut self,
67        config: &ServerConfig,
68        cx: &mut ServerContext<'_>,
69        ocsp_response: &mut Option<&[u8]>,
70        sct_list: &mut Option<&[u8]>,
71        hello: &ClientHelloPayload,
72        resumedata: Option<&persist::ServerSessionValue>,
73        extra_exts: Vec<ServerExtension>,
74    ) -> Result<(), Error> {
75        // ALPN
76        let our_protocols = &config.alpn_protocols;
77        let maybe_their_protocols = hello.get_alpn_extension();
78        if let Some(their_protocols) = maybe_their_protocols {
79            let their_protocols = their_protocols.to_slices();
80
81            if their_protocols
82                .iter()
83                .any(|protocol| protocol.is_empty())
84            {
85                return Err(PeerMisbehaved::OfferedEmptyApplicationProtocol.into());
86            }
87
88            cx.common.alpn_protocol = our_protocols
89                .iter()
90                .find(|protocol| their_protocols.contains(&protocol.as_slice()))
91                .cloned();
92            if let Some(ref selected_protocol) = cx.common.alpn_protocol {
93                debug!("Chosen ALPN protocol {:?}", selected_protocol);
94                self.exts
95                    .push(ServerExtension::make_alpn(&[selected_protocol]));
96            } else if !our_protocols.is_empty() {
97                return Err(cx.common.send_fatal_alert(
98                    AlertDescription::NoApplicationProtocol,
99                    Error::NoApplicationProtocol,
100                ));
101            }
102        }
103
104        #[cfg(feature = "quic")]
105        {
106            if cx.common.is_quic() {
107                // QUIC has strict ALPN, unlike TLS's more backwards-compatible behavior. RFC 9001
108                // says: "The server MUST treat the inability to select a compatible application
109                // protocol as a connection error of type 0x0178". We judge that ALPN was desired
110                // (rather than some out-of-band protocol negotiation mechanism) iff any ALPN
111                // protocols were configured locally or offered by the client. This helps prevent
112                // successful establishment of connections between peers that can't understand
113                // each other.
114                if cx.common.alpn_protocol.is_none()
115                    && (!our_protocols.is_empty() || maybe_their_protocols.is_some())
116                {
117                    return Err(cx.common.send_fatal_alert(
118                        AlertDescription::NoApplicationProtocol,
119                        Error::NoApplicationProtocol,
120                    ));
121                }
122
123                match hello.get_quic_params_extension() {
124                    Some(params) => cx.common.quic.params = Some(params),
125                    None => {
126                        return Err(cx
127                            .common
128                            .missing_extension(PeerMisbehaved::MissingQuicTransportParameters));
129                    }
130                }
131            }
132        }
133
134        let for_resume = resumedata.is_some();
135        // SNI
136        if !for_resume && hello.get_sni_extension().is_some() {
137            self.exts
138                .push(ServerExtension::ServerNameAck);
139        }
140
141        // Send status_request response if we have one.  This is not allowed
142        // if we're resuming, and is only triggered if we have an OCSP response
143        // to send.
144        if !for_resume
145            && hello
146                .find_extension(ExtensionType::StatusRequest)
147                .is_some()
148        {
149            if ocsp_response.is_some() && !cx.common.is_tls13() {
150                // Only TLS1.2 sends confirmation in ServerHello
151                self.exts
152                    .push(ServerExtension::CertificateStatusAck);
153            }
154        } else {
155            // Throw away any OCSP response so we don't try to send it later.
156            ocsp_response.take();
157        }
158
159        if !for_resume
160            && hello
161                .find_extension(ExtensionType::SCT)
162                .is_some()
163        {
164            if !cx.common.is_tls13() {
165                // Take the SCT list, if any, so we don't send it later,
166                // and put it in the legacy extension.
167                if let Some(sct_list) = sct_list.take() {
168                    self.exts
169                        .push(ServerExtension::make_sct(sct_list.to_vec()));
170                }
171            }
172        } else {
173            // Throw away any SCT list so we don't send it later.
174            sct_list.take();
175        }
176
177        self.exts.extend(extra_exts);
178
179        Ok(())
180    }
181
182    #[cfg(feature = "tls12")]
183    pub(super) fn process_tls12(
184        &mut self,
185        config: &ServerConfig,
186        hello: &ClientHelloPayload,
187        using_ems: bool,
188    ) {
189        // Renegotiation.
190        // (We don't do reneg at all, but would support the secure version if we did.)
191        let secure_reneg_offered = hello
192            .find_extension(ExtensionType::RenegotiationInfo)
193            .is_some()
194            || hello
195                .cipher_suites
196                .contains(&CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
197
198        if secure_reneg_offered {
199            self.exts
200                .push(ServerExtension::make_empty_renegotiation_info());
201        }
202
203        // Tickets:
204        // If we get any SessionTicket extension and have tickets enabled,
205        // we send an ack.
206        if hello
207            .find_extension(ExtensionType::SessionTicket)
208            .is_some()
209            && config.ticketer.enabled()
210        {
211            self.send_ticket = true;
212            self.exts
213                .push(ServerExtension::SessionTicketAck);
214        }
215
216        // Confirm use of EMS if offered.
217        if using_ems {
218            self.exts
219                .push(ServerExtension::ExtendedMasterSecretAck);
220        }
221    }
222}
223
224pub(super) struct ExpectClientHello {
225    pub(super) config: Arc<ServerConfig>,
226    pub(super) extra_exts: Vec<ServerExtension>,
227    pub(super) transcript: HandshakeHashOrBuffer,
228    #[cfg(feature = "tls12")]
229    pub(super) session_id: SessionId,
230    #[cfg(feature = "tls12")]
231    pub(super) using_ems: bool,
232    pub(super) done_retry: bool,
233    pub(super) send_tickets: usize,
234}
235
236impl ExpectClientHello {
237    pub(super) fn new(config: Arc<ServerConfig>, extra_exts: Vec<ServerExtension>) -> Self {
238        let mut transcript_buffer = HandshakeHashBuffer::new();
239
240        if config.verifier.offer_client_auth() {
241            transcript_buffer.set_client_auth_enabled();
242        }
243
244        Self {
245            config,
246            extra_exts,
247            transcript: HandshakeHashOrBuffer::Buffer(transcript_buffer),
248            #[cfg(feature = "tls12")]
249            session_id: SessionId::empty(),
250            #[cfg(feature = "tls12")]
251            using_ems: false,
252            done_retry: false,
253            send_tickets: 0,
254        }
255    }
256
257    /// Continues handling of a `ClientHello` message once config and certificate are available.
258    pub(super) fn with_certified_key(
259        self,
260        mut sig_schemes: Vec<SignatureScheme>,
261        client_hello: &ClientHelloPayload,
262        m: &Message,
263        cx: &mut ServerContext<'_>,
264    ) -> NextStateOrError {
265        let tls13_enabled = self
266            .config
267            .supports_version(ProtocolVersion::TLSv1_3);
268        let tls12_enabled = self
269            .config
270            .supports_version(ProtocolVersion::TLSv1_2);
271
272        // Are we doing TLS1.3?
273        let maybe_versions_ext = client_hello.get_versions_extension();
274        let version = if let Some(versions) = maybe_versions_ext {
275            if versions.contains(&ProtocolVersion::TLSv1_3) && tls13_enabled {
276                ProtocolVersion::TLSv1_3
277            } else if !versions.contains(&ProtocolVersion::TLSv1_2) || !tls12_enabled {
278                return Err(cx.common.send_fatal_alert(
279                    AlertDescription::ProtocolVersion,
280                    PeerIncompatible::Tls12NotOfferedOrEnabled,
281                ));
282            } else if cx.common.is_quic() {
283                return Err(cx.common.send_fatal_alert(
284                    AlertDescription::ProtocolVersion,
285                    PeerIncompatible::Tls13RequiredForQuic,
286                ));
287            } else {
288                ProtocolVersion::TLSv1_2
289            }
290        } else if client_hello.client_version.get_u16() < ProtocolVersion::TLSv1_2.get_u16() {
291            return Err(cx.common.send_fatal_alert(
292                AlertDescription::ProtocolVersion,
293                PeerIncompatible::Tls12NotOffered,
294            ));
295        } else if !tls12_enabled && tls13_enabled {
296            return Err(cx.common.send_fatal_alert(
297                AlertDescription::ProtocolVersion,
298                PeerIncompatible::SupportedVersionsExtensionRequired,
299            ));
300        } else if cx.common.is_quic() {
301            return Err(cx.common.send_fatal_alert(
302                AlertDescription::ProtocolVersion,
303                PeerIncompatible::Tls13RequiredForQuic,
304            ));
305        } else {
306            ProtocolVersion::TLSv1_2
307        };
308
309        cx.common.negotiated_version = Some(version);
310
311        // We communicate to the upper layer what kind of key they should choose
312        // via the sigschemes value.  Clients tend to treat this extension
313        // orthogonally to offered ciphersuites (even though, in TLS1.2 it is not).
314        // So: reduce the offered sigschemes to those compatible with the
315        // intersection of ciphersuites.
316        let client_suites = self
317            .config
318            .cipher_suites
319            .iter()
320            .copied()
321            .filter(|scs| {
322                client_hello
323                    .cipher_suites
324                    .contains(&scs.suite())
325            })
326            .collect::<Vec<_>>();
327
328        sig_schemes
329            .retain(|scheme| suites::compatible_sigscheme_for_suites(*scheme, &client_suites));
330
331        // Choose a certificate.
332        let certkey = {
333            let client_hello = ClientHello::new(
334                &cx.data.sni,
335                &sig_schemes,
336                client_hello.get_alpn_extension(),
337                &client_hello.cipher_suites,
338            );
339
340            let certkey = self
341                .config
342                .cert_resolver
343                .resolve(client_hello);
344
345            certkey.ok_or_else(|| {
346                cx.common.send_fatal_alert(
347                    AlertDescription::AccessDenied,
348                    Error::General("no server certificate chain resolved".to_owned()),
349                )
350            })?
351        };
352        let certkey = ActiveCertifiedKey::from_certified_key(&certkey);
353
354        // Reduce our supported ciphersuites by the certificate.
355        // (no-op for TLS1.3)
356        let suitable_suites =
357            suites::reduce_given_sigalg(&self.config.cipher_suites, certkey.get_key().algorithm());
358
359        // And version
360        let suitable_suites = suites::reduce_given_version(&suitable_suites, version);
361
362        let suite = if self.config.ignore_client_order {
363            suites::choose_ciphersuite_preferring_server(
364                &client_hello.cipher_suites,
365                &suitable_suites,
366            )
367        } else {
368            suites::choose_ciphersuite_preferring_client(
369                &client_hello.cipher_suites,
370                &suitable_suites,
371            )
372        }
373        .ok_or_else(|| {
374            cx.common.send_fatal_alert(
375                AlertDescription::HandshakeFailure,
376                PeerIncompatible::NoCipherSuitesInCommon,
377            )
378        })?;
379
380        debug!("decided upon suite {:?}", suite);
381        cx.common.suite = Some(suite);
382
383        // Start handshake hash.
384        let starting_hash = suite.hash_algorithm();
385        let transcript = match self.transcript {
386            HandshakeHashOrBuffer::Buffer(inner) => inner.start_hash(starting_hash),
387            HandshakeHashOrBuffer::Hash(inner) if inner.algorithm() == starting_hash => inner,
388            _ => {
389                return Err(cx.common.send_fatal_alert(
390                    AlertDescription::IllegalParameter,
391                    PeerMisbehaved::HandshakeHashVariedAfterRetry,
392                ));
393            }
394        };
395
396        // Save their Random.
397        let randoms = ConnectionRandoms::new(client_hello.random, Random::new()?);
398        match suite {
399            SupportedCipherSuite::Tls13(suite) => tls13::CompleteClientHelloHandling {
400                config: self.config,
401                transcript,
402                suite,
403                randoms,
404                done_retry: self.done_retry,
405                send_tickets: self.send_tickets,
406                extra_exts: self.extra_exts,
407            }
408            .handle_client_hello(cx, certkey, m, client_hello, sig_schemes),
409            #[cfg(feature = "tls12")]
410            SupportedCipherSuite::Tls12(suite) => tls12::CompleteClientHelloHandling {
411                config: self.config,
412                transcript,
413                session_id: self.session_id,
414                suite,
415                using_ems: self.using_ems,
416                randoms,
417                send_ticket: self.send_tickets > 0,
418                extra_exts: self.extra_exts,
419            }
420            .handle_client_hello(
421                cx,
422                certkey,
423                m,
424                client_hello,
425                sig_schemes,
426                tls13_enabled,
427            ),
428        }
429    }
430}
431
432impl State<ServerConnectionData> for ExpectClientHello {
433    fn handle(self: Box<Self>, cx: &mut ServerContext<'_>, m: Message) -> NextStateOrError {
434        let (client_hello, sig_schemes) = process_client_hello(&m, self.done_retry, cx)?;
435        self.with_certified_key(sig_schemes, client_hello, &m, cx)
436    }
437}
438
439/// Configuration-independent validation of a `ClientHello` message.
440///
441/// This represents the first part of the `ClientHello` handling, where we do all validation that
442/// doesn't depend on a `ServerConfig` being available and extract everything needed to build a
443/// [`ClientHello`] value for a [`ResolvesServerConfig`]/`ResolvesServerCert`].
444///
445/// Note that this will modify `data.sni` even if config or certificate resolution fail.
446pub(super) fn process_client_hello<'a>(
447    m: &'a Message,
448    done_retry: bool,
449    cx: &mut ServerContext,
450) -> Result<(&'a ClientHelloPayload, Vec<SignatureScheme>), Error> {
451    let client_hello =
452        require_handshake_msg!(m, HandshakeType::ClientHello, HandshakePayload::ClientHello)?;
453    trace!("we got a clienthello {:?}", client_hello);
454
455    if !client_hello
456        .compression_methods
457        .contains(&Compression::Null)
458    {
459        return Err(cx.common.send_fatal_alert(
460            AlertDescription::IllegalParameter,
461            PeerIncompatible::NullCompressionRequired,
462        ));
463    }
464
465    if client_hello.has_duplicate_extension() {
466        return Err(cx.common.send_fatal_alert(
467            AlertDescription::DecodeError,
468            PeerMisbehaved::DuplicateClientHelloExtensions,
469        ));
470    }
471
472    // No handshake messages should follow this one in this flight.
473    cx.common.check_aligned_handshake()?;
474
475    // Extract and validate the SNI DNS name, if any, before giving it to
476    // the cert resolver. In particular, if it is invalid then we should
477    // send an Illegal Parameter alert instead of the Internal Error alert
478    // (or whatever) that we'd send if this were checked later or in a
479    // different way.
480    let sni: Option<DnsName> = match client_hello.get_sni_extension() {
481        Some(sni) => {
482            if sni.has_duplicate_names_for_type() {
483                return Err(cx.common.send_fatal_alert(
484                    AlertDescription::DecodeError,
485                    PeerMisbehaved::DuplicateServerNameTypes,
486                ));
487            }
488
489            if let Some(hostname) = sni.get_single_hostname() {
490                Some(hostname.to_lowercase_owned())
491            } else {
492                return Err(cx.common.send_fatal_alert(
493                    AlertDescription::IllegalParameter,
494                    PeerMisbehaved::ServerNameMustContainOneHostName,
495                ));
496            }
497        }
498        None => None,
499    };
500
501    // save only the first SNI
502    if let (Some(sni), false) = (&sni, done_retry) {
503        // Save the SNI into the session.
504        // The SNI hostname is immutable once set.
505        assert!(cx.data.sni.is_none());
506        cx.data.sni = Some(sni.clone());
507    } else if cx.data.sni != sni {
508        return Err(PeerMisbehaved::ServerNameDifferedOnRetry.into());
509    }
510
511    let sig_schemes = client_hello
512        .get_sigalgs_extension()
513        .ok_or_else(|| {
514            cx.common.send_fatal_alert(
515                AlertDescription::HandshakeFailure,
516                PeerIncompatible::SignatureAlgorithmsExtensionRequired,
517            )
518        })?;
519
520    Ok((client_hello, sig_schemes.to_owned()))
521}
522
523#[allow(clippy::large_enum_variant)]
524pub(crate) enum HandshakeHashOrBuffer {
525    Buffer(HandshakeHashBuffer),
526    Hash(HandshakeHash),
527}