rustls/client/
hs.rs

1#[cfg(feature = "logging")]
2use crate::bs_debug;
3use crate::check::inappropriate_handshake_message;
4use crate::common_state::{CommonState, State};
5use crate::conn::ConnectionRandoms;
6use crate::enums::{AlertDescription, CipherSuite, ContentType, HandshakeType, ProtocolVersion};
7use crate::error::{Error, PeerIncompatible, PeerMisbehaved};
8use crate::hash_hs::HandshakeHashBuffer;
9use crate::kx;
10#[cfg(feature = "logging")]
11use crate::log::{debug, trace};
12use crate::msgs::base::Payload;
13use crate::msgs::enums::{Compression, ExtensionType};
14use crate::msgs::enums::{ECPointFormat, PSKKeyExchangeMode};
15use crate::msgs::handshake::ConvertProtocolNameList;
16use crate::msgs::handshake::{CertificateStatusRequest, ClientSessionTicket, Sct};
17use crate::msgs::handshake::{ClientExtension, HasServerExtensions};
18use crate::msgs::handshake::{ClientHelloPayload, HandshakeMessagePayload, HandshakePayload};
19use crate::msgs::handshake::{HelloRetryRequest, KeyShareEntry};
20use crate::msgs::handshake::{Random, SessionId};
21use crate::msgs::message::{Message, MessagePayload};
22use crate::msgs::persist;
23use crate::ticketer::TimeBase;
24use crate::tls13::key_schedule::KeyScheduleEarly;
25use crate::SupportedCipherSuite;
26
27#[cfg(feature = "tls12")]
28use super::tls12;
29use super::Tls12Resumption;
30use crate::client::client_conn::ClientConnectionData;
31use crate::client::common::ClientHelloDetails;
32use crate::client::{tls13, ClientConfig, ServerName};
33
34use std::ops::Deref;
35use std::sync::Arc;
36
37pub(super) type NextState = Box<dyn State<ClientConnectionData>>;
38pub(super) type NextStateOrError = Result<NextState, Error>;
39pub(super) type ClientContext<'a> = crate::common_state::Context<'a, ClientConnectionData>;
40
41fn find_session(
42    server_name: &ServerName,
43    config: &ClientConfig,
44    #[cfg(feature = "quic")] cx: &mut ClientContext<'_>,
45) -> Option<persist::Retrieved<ClientSessionValue>> {
46    #[allow(clippy::let_and_return, clippy::unnecessary_lazy_evaluations)]
47    let found = config
48        .resumption
49        .store
50        .take_tls13_ticket(server_name)
51        .map(ClientSessionValue::Tls13)
52        .or_else(|| {
53            #[cfg(feature = "tls12")]
54            {
55                config
56                    .resumption
57                    .store
58                    .tls12_session(server_name)
59                    .map(ClientSessionValue::Tls12)
60            }
61
62            #[cfg(not(feature = "tls12"))]
63            None
64        })
65        .and_then(|resuming| {
66            let retrieved = persist::Retrieved::new(resuming, TimeBase::now().ok()?);
67            match retrieved.has_expired() {
68                false => Some(retrieved),
69                true => None,
70            }
71        })
72        .or_else(|| {
73            debug!("No cached session for {:?}", server_name);
74            None
75        });
76
77    #[cfg(feature = "quic")]
78    if let Some(resuming) = &found {
79        if cx.common.is_quic() {
80            cx.common.quic.params = resuming
81                .tls13()
82                .map(|v| v.quic_params());
83        }
84    }
85
86    found
87}
88
89pub(super) fn start_handshake(
90    server_name: ServerName,
91    extra_exts: Vec<ClientExtension>,
92    config: Arc<ClientConfig>,
93    cx: &mut ClientContext<'_>,
94) -> NextStateOrError {
95    let mut transcript_buffer = HandshakeHashBuffer::new();
96    if config
97        .client_auth_cert_resolver
98        .has_certs()
99    {
100        transcript_buffer.set_client_auth_enabled();
101    }
102
103    let mut resuming = find_session(
104        &server_name,
105        &config,
106        #[cfg(feature = "quic")]
107        cx,
108    );
109
110    let key_share = if config.supports_version(ProtocolVersion::TLSv1_3) {
111        Some(tls13::initial_key_share(&config, &server_name)?)
112    } else {
113        None
114    };
115
116    #[cfg_attr(not(feature = "tls12"), allow(unused_mut))]
117    let mut session_id = None;
118    if let Some(_resuming) = &mut resuming {
119        #[cfg(feature = "tls12")]
120        if let ClientSessionValue::Tls12(inner) = &mut _resuming.value {
121            // If we have a ticket, we use the sessionid as a signal that
122            // we're  doing an abbreviated handshake.  See section 3.4 in
123            // RFC5077.
124            if !inner.ticket().is_empty() {
125                inner.session_id = SessionId::random()?;
126            }
127            session_id = Some(inner.session_id);
128        }
129
130        debug!("Resuming session");
131    } else {
132        debug!("Not resuming any session");
133    }
134
135    // https://tools.ietf.org/html/rfc8446#appendix-D.4
136    // https://tools.ietf.org/html/draft-ietf-quic-tls-34#section-8.4
137    let session_id = match session_id {
138        Some(session_id) => session_id,
139        None if cx.common.is_quic() => SessionId::empty(),
140        None if !config.supports_version(ProtocolVersion::TLSv1_3) => SessionId::empty(),
141        None => SessionId::random()?,
142    };
143
144    let may_send_sct_list = config.verifier.request_scts();
145    Ok(emit_client_hello_for_retry(
146        transcript_buffer,
147        None,
148        key_share,
149        extra_exts,
150        may_send_sct_list,
151        None,
152        ClientHelloInput {
153            config,
154            resuming,
155            random: Random::new()?,
156            #[cfg(feature = "tls12")]
157            using_ems: false,
158            sent_tls13_fake_ccs: false,
159            hello: ClientHelloDetails::new(),
160            session_id,
161            server_name,
162        },
163        cx,
164    ))
165}
166
167struct ExpectServerHello {
168    input: ClientHelloInput,
169    transcript_buffer: HandshakeHashBuffer,
170    early_key_schedule: Option<KeyScheduleEarly>,
171    offered_key_share: Option<kx::KeyExchange>,
172    suite: Option<SupportedCipherSuite>,
173}
174
175struct ExpectServerHelloOrHelloRetryRequest {
176    next: ExpectServerHello,
177    extra_exts: Vec<ClientExtension>,
178}
179
180struct ClientHelloInput {
181    config: Arc<ClientConfig>,
182    resuming: Option<persist::Retrieved<ClientSessionValue>>,
183    random: Random,
184    #[cfg(feature = "tls12")]
185    using_ems: bool,
186    sent_tls13_fake_ccs: bool,
187    hello: ClientHelloDetails,
188    session_id: SessionId,
189    server_name: ServerName,
190}
191
192fn emit_client_hello_for_retry(
193    mut transcript_buffer: HandshakeHashBuffer,
194    retryreq: Option<&HelloRetryRequest>,
195    key_share: Option<kx::KeyExchange>,
196    extra_exts: Vec<ClientExtension>,
197    may_send_sct_list: bool,
198    suite: Option<SupportedCipherSuite>,
199    mut input: ClientHelloInput,
200    cx: &mut ClientContext<'_>,
201) -> NextState {
202    let config = &input.config;
203    let support_tls12 = config.supports_version(ProtocolVersion::TLSv1_2) && !cx.common.is_quic();
204    let support_tls13 = config.supports_version(ProtocolVersion::TLSv1_3);
205
206    let mut supported_versions = Vec::new();
207    if support_tls13 {
208        supported_versions.push(ProtocolVersion::TLSv1_3);
209    }
210
211    if support_tls12 {
212        supported_versions.push(ProtocolVersion::TLSv1_2);
213    }
214
215    // should be unreachable thanks to config builder
216    assert!(!supported_versions.is_empty());
217
218    let mut exts = vec![
219        ClientExtension::SupportedVersions(supported_versions),
220        ClientExtension::ECPointFormats(ECPointFormat::SUPPORTED.to_vec()),
221        ClientExtension::NamedGroups(
222            config
223                .kx_groups
224                .iter()
225                .map(|skxg| skxg.name)
226                .collect(),
227        ),
228        ClientExtension::SignatureAlgorithms(
229            config
230                .verifier
231                .supported_verify_schemes(),
232        ),
233        ClientExtension::ExtendedMasterSecretRequest,
234        ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()),
235    ];
236
237    if let (Some(sni_name), true) = (input.server_name.for_sni(), config.enable_sni) {
238        exts.push(ClientExtension::make_sni(sni_name));
239    }
240
241    if may_send_sct_list {
242        exts.push(ClientExtension::SignedCertificateTimestampRequest);
243    }
244
245    if let Some(key_share) = &key_share {
246        debug_assert!(support_tls13);
247        let key_share = KeyShareEntry::new(key_share.group(), key_share.pubkey.as_ref());
248        exts.push(ClientExtension::KeyShare(vec![key_share]));
249    }
250
251    if let Some(cookie) = retryreq.and_then(HelloRetryRequest::get_cookie) {
252        exts.push(ClientExtension::Cookie(cookie.clone()));
253    }
254
255    if support_tls13 {
256        // We could support PSK_KE here too. Such connections don't
257        // have forward secrecy, and are similar to TLS1.2 resumption.
258        let psk_modes = vec![PSKKeyExchangeMode::PSK_DHE_KE];
259        exts.push(ClientExtension::PresharedKeyModes(psk_modes));
260    }
261
262    if !config.alpn_protocols.is_empty() {
263        exts.push(ClientExtension::Protocols(Vec::from_slices(
264            &config
265                .alpn_protocols
266                .iter()
267                .map(|proto| &proto[..])
268                .collect::<Vec<_>>(),
269        )));
270    }
271
272    // Extra extensions must be placed before the PSK extension
273    exts.extend(extra_exts.iter().cloned());
274
275    // Do we have a SessionID or ticket cached for this host?
276    let tls13_session = prepare_resumption(&input.resuming, &mut exts, suite, cx, config);
277
278    // Note what extensions we sent.
279    input.hello.sent_extensions = exts
280        .iter()
281        .map(ClientExtension::get_type)
282        .collect();
283
284    let mut cipher_suites: Vec<_> = config
285        .cipher_suites
286        .iter()
287        .map(|cs| cs.suite())
288        .collect();
289    // We don't do renegotiation at all, in fact.
290    cipher_suites.push(CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
291
292    let mut chp = HandshakeMessagePayload {
293        typ: HandshakeType::ClientHello,
294        payload: HandshakePayload::ClientHello(ClientHelloPayload {
295            client_version: ProtocolVersion::TLSv1_2,
296            random: input.random,
297            session_id: input.session_id,
298            cipher_suites,
299            compression_methods: vec![Compression::Null],
300            extensions: exts,
301        }),
302    };
303
304    let early_key_schedule = if let Some(resuming) = tls13_session {
305        let schedule = tls13::fill_in_psk_binder(&resuming, &transcript_buffer, &mut chp);
306        Some((resuming.suite(), schedule))
307    } else {
308        None
309    };
310
311    let ch = Message {
312        // "This value MUST be set to 0x0303 for all records generated
313        //  by a TLS 1.3 implementation other than an initial ClientHello
314        //  (i.e., one not generated after a HelloRetryRequest)"
315        version: if retryreq.is_some() {
316            ProtocolVersion::TLSv1_2
317        } else {
318            ProtocolVersion::TLSv1_0
319        },
320        payload: MessagePayload::handshake(chp),
321    };
322
323    if retryreq.is_some() {
324        // send dummy CCS to fool middleboxes prior
325        // to second client hello
326        tls13::emit_fake_ccs(&mut input.sent_tls13_fake_ccs, cx.common);
327    }
328
329    trace!("Sending ClientHello {:#?}", ch);
330
331    transcript_buffer.add_message(&ch);
332    cx.common.send_msg(ch, false);
333
334    // Calculate the hash of ClientHello and use it to derive EarlyTrafficSecret
335    let early_key_schedule = early_key_schedule.map(|(resuming_suite, schedule)| {
336        if !cx.data.early_data.is_enabled() {
337            return schedule;
338        }
339
340        tls13::derive_early_traffic_secret(
341            &*config.key_log,
342            cx,
343            resuming_suite,
344            &schedule,
345            &mut input.sent_tls13_fake_ccs,
346            &transcript_buffer,
347            &input.random.0,
348        );
349        schedule
350    });
351
352    let next = ExpectServerHello {
353        input,
354        transcript_buffer,
355        early_key_schedule,
356        offered_key_share: key_share,
357        suite,
358    };
359
360    if support_tls13 && retryreq.is_none() {
361        Box::new(ExpectServerHelloOrHelloRetryRequest { next, extra_exts })
362    } else {
363        Box::new(next)
364    }
365}
366
367/// Prepare resumption with the session state retrieved from storage.
368///
369/// This function will push onto `exts` to
370///
371/// (a) request a new ticket if we don't have one,
372/// (b) send our TLS 1.2 ticket after retrieving an 1.2 session,
373/// (c) send a request for 1.3 early data if allowed and
374/// (d) send a 1.3 preshared key if we have one.
375///
376/// For resumption to work, the currently negotiated cipher suite (if available) must be
377/// able to resume from the resuming session's cipher suite.
378///
379/// If 1.3 resumption can continue, returns the 1.3 session value for further processing.
380fn prepare_resumption<'a>(
381    resuming: &'a Option<persist::Retrieved<ClientSessionValue>>,
382    exts: &mut Vec<ClientExtension>,
383    suite: Option<SupportedCipherSuite>,
384    cx: &mut ClientContext<'_>,
385    config: &ClientConfig,
386) -> Option<persist::Retrieved<&'a persist::Tls13ClientSessionValue>> {
387    // Check whether we're resuming with a non-empty ticket.
388    let resuming = match resuming {
389        Some(resuming) if !resuming.ticket().is_empty() => resuming,
390        _ => {
391            if config.supports_version(ProtocolVersion::TLSv1_3)
392                || config.resumption.tls12_resumption == Tls12Resumption::SessionIdOrTickets
393            {
394                // If we don't have a ticket, request one.
395                exts.push(ClientExtension::SessionTicket(ClientSessionTicket::Request));
396            }
397            return None;
398        }
399    };
400
401    let tls13 = match resuming.map(|csv| csv.tls13()) {
402        Some(tls13) => tls13,
403        None => {
404            // TLS 1.2; send the ticket if we have support this protocol version
405            if config.supports_version(ProtocolVersion::TLSv1_2)
406                && config.resumption.tls12_resumption == Tls12Resumption::SessionIdOrTickets
407            {
408                exts.push(ClientExtension::SessionTicket(ClientSessionTicket::Offer(
409                    Payload::new(resuming.ticket()),
410                )));
411            }
412            return None; // TLS 1.2, so nothing to return here
413        }
414    };
415
416    if !config.supports_version(ProtocolVersion::TLSv1_3) {
417        return None;
418    }
419
420    // If the server selected TLS 1.2, we can't resume.
421    let suite = match suite {
422        Some(SupportedCipherSuite::Tls13(suite)) => Some(suite),
423        #[cfg(feature = "tls12")]
424        Some(SupportedCipherSuite::Tls12(_)) => return None,
425        None => None,
426    };
427
428    // If the selected cipher suite can't select from the session's, we can't resume.
429    if let Some(suite) = suite {
430        suite.can_resume_from(tls13.suite())?;
431    }
432
433    tls13::prepare_resumption(config, cx, &tls13, exts, suite.is_some());
434    Some(tls13)
435}
436
437pub(super) fn process_alpn_protocol(
438    common: &mut CommonState,
439    config: &ClientConfig,
440    proto: Option<&[u8]>,
441) -> Result<(), Error> {
442    common.alpn_protocol = proto.map(ToOwned::to_owned);
443
444    if let Some(alpn_protocol) = &common.alpn_protocol {
445        if !config
446            .alpn_protocols
447            .contains(alpn_protocol)
448        {
449            return Err(common.send_fatal_alert(
450                AlertDescription::IllegalParameter,
451                PeerMisbehaved::SelectedUnofferedApplicationProtocol,
452            ));
453        }
454    }
455
456    #[cfg(feature = "quic")]
457    {
458        // RFC 9001 says: "While ALPN only specifies that servers use this alert, QUIC clients MUST
459        // use error 0x0178 to terminate a connection when ALPN negotiation fails." We judge that
460        // the user intended to use ALPN (rather than some out-of-band protocol negotiation
461        // mechanism) iff any ALPN protocols were configured. This defends against badly-behaved
462        // servers which accept a connection that requires an application-layer protocol they do not
463        // understand.
464        if common.is_quic() && common.alpn_protocol.is_none() && !config.alpn_protocols.is_empty() {
465            return Err(common.send_fatal_alert(
466                AlertDescription::NoApplicationProtocol,
467                Error::NoApplicationProtocol,
468            ));
469        }
470    }
471
472    debug!(
473        "ALPN protocol is {:?}",
474        common
475            .alpn_protocol
476            .as_ref()
477            .map(|v| bs_debug::BsDebug(v))
478    );
479    Ok(())
480}
481
482pub(super) fn sct_list_is_invalid(scts: &[Sct]) -> bool {
483    scts.is_empty()
484        || scts
485            .iter()
486            .any(|sct| sct.as_ref().is_empty())
487}
488
489impl State<ClientConnectionData> for ExpectServerHello {
490    fn handle(mut self: Box<Self>, cx: &mut ClientContext<'_>, m: Message) -> NextStateOrError {
491        let server_hello =
492            require_handshake_msg!(m, HandshakeType::ServerHello, HandshakePayload::ServerHello)?;
493        trace!("We got ServerHello {:#?}", server_hello);
494
495        use crate::ProtocolVersion::{TLSv1_2, TLSv1_3};
496        let config = &self.input.config;
497        let tls13_supported = config.supports_version(TLSv1_3);
498
499        let server_version = if server_hello.legacy_version == TLSv1_2 {
500            server_hello
501                .get_supported_versions()
502                .unwrap_or(server_hello.legacy_version)
503        } else {
504            server_hello.legacy_version
505        };
506
507        let version = match server_version {
508            TLSv1_3 if tls13_supported => TLSv1_3,
509            TLSv1_2 if config.supports_version(TLSv1_2) => {
510                if cx.data.early_data.is_enabled() && cx.common.early_traffic {
511                    // The client must fail with a dedicated error code if the server
512                    // responds with TLS 1.2 when offering 0-RTT.
513                    return Err(PeerMisbehaved::OfferedEarlyDataWithOldProtocolVersion.into());
514                }
515
516                if server_hello
517                    .get_supported_versions()
518                    .is_some()
519                {
520                    return Err({
521                        cx.common.send_fatal_alert(
522                            AlertDescription::IllegalParameter,
523                            PeerMisbehaved::SelectedTls12UsingTls13VersionExtension,
524                        )
525                    });
526                }
527
528                TLSv1_2
529            }
530            _ => {
531                let reason = match server_version {
532                    TLSv1_2 | TLSv1_3 => PeerIncompatible::ServerTlsVersionIsDisabledByOurConfig,
533                    _ => PeerIncompatible::ServerDoesNotSupportTls12Or13,
534                };
535                return Err(cx
536                    .common
537                    .send_fatal_alert(AlertDescription::ProtocolVersion, reason));
538            }
539        };
540
541        if server_hello.compression_method != Compression::Null {
542            return Err({
543                cx.common.send_fatal_alert(
544                    AlertDescription::IllegalParameter,
545                    PeerMisbehaved::SelectedUnofferedCompression,
546                )
547            });
548        }
549
550        if server_hello.has_duplicate_extension() {
551            return Err(cx.common.send_fatal_alert(
552                AlertDescription::DecodeError,
553                PeerMisbehaved::DuplicateServerHelloExtensions,
554            ));
555        }
556
557        let allowed_unsolicited = [ExtensionType::RenegotiationInfo];
558        if self
559            .input
560            .hello
561            .server_sent_unsolicited_extensions(&server_hello.extensions, &allowed_unsolicited)
562        {
563            return Err(cx.common.send_fatal_alert(
564                AlertDescription::UnsupportedExtension,
565                PeerMisbehaved::UnsolicitedServerHelloExtension,
566            ));
567        }
568
569        cx.common.negotiated_version = Some(version);
570
571        // Extract ALPN protocol
572        if !cx.common.is_tls13() {
573            process_alpn_protocol(cx.common, config, server_hello.get_alpn_protocol())?;
574        }
575
576        // If ECPointFormats extension is supplied by the server, it must contain
577        // Uncompressed.  But it's allowed to be omitted.
578        if let Some(point_fmts) = server_hello.get_ecpoints_extension() {
579            if !point_fmts.contains(&ECPointFormat::Uncompressed) {
580                return Err(cx.common.send_fatal_alert(
581                    AlertDescription::HandshakeFailure,
582                    PeerMisbehaved::ServerHelloMustOfferUncompressedEcPoints,
583                ));
584            }
585        }
586
587        let suite = config
588            .find_cipher_suite(server_hello.cipher_suite)
589            .ok_or_else(|| {
590                cx.common.send_fatal_alert(
591                    AlertDescription::HandshakeFailure,
592                    PeerMisbehaved::SelectedUnofferedCipherSuite,
593                )
594            })?;
595
596        if version != suite.version().version {
597            return Err({
598                cx.common.send_fatal_alert(
599                    AlertDescription::IllegalParameter,
600                    PeerMisbehaved::SelectedUnusableCipherSuiteForVersion,
601                )
602            });
603        }
604
605        match self.suite {
606            Some(prev_suite) if prev_suite != suite => {
607                return Err({
608                    cx.common.send_fatal_alert(
609                        AlertDescription::IllegalParameter,
610                        PeerMisbehaved::SelectedDifferentCipherSuiteAfterRetry,
611                    )
612                });
613            }
614            _ => {
615                debug!("Using ciphersuite {:?}", suite);
616                self.suite = Some(suite);
617                cx.common.suite = Some(suite);
618            }
619        }
620
621        // Start our handshake hash, and input the server-hello.
622        let mut transcript = self
623            .transcript_buffer
624            .start_hash(suite.hash_algorithm());
625        transcript.add_message(&m);
626
627        let randoms = ConnectionRandoms::new(self.input.random, server_hello.random);
628        // For TLS1.3, start message encryption using
629        // handshake_traffic_secret.
630        match suite {
631            SupportedCipherSuite::Tls13(suite) => {
632                #[allow(clippy::bind_instead_of_map)]
633                let resuming_session = self
634                    .input
635                    .resuming
636                    .and_then(|resuming| match resuming.value {
637                        ClientSessionValue::Tls13(inner) => Some(inner),
638                        #[cfg(feature = "tls12")]
639                        ClientSessionValue::Tls12(_) => None,
640                    });
641
642                tls13::handle_server_hello(
643                    self.input.config,
644                    cx,
645                    server_hello,
646                    resuming_session,
647                    self.input.server_name,
648                    randoms,
649                    suite,
650                    transcript,
651                    self.early_key_schedule,
652                    self.input.hello,
653                    // We always send a key share when TLS 1.3 is enabled.
654                    self.offered_key_share.unwrap(),
655                    self.input.sent_tls13_fake_ccs,
656                )
657            }
658            #[cfg(feature = "tls12")]
659            SupportedCipherSuite::Tls12(suite) => {
660                let resuming_session = self
661                    .input
662                    .resuming
663                    .and_then(|resuming| match resuming.value {
664                        ClientSessionValue::Tls12(inner) => Some(inner),
665                        ClientSessionValue::Tls13(_) => None,
666                    });
667
668                tls12::CompleteServerHelloHandling {
669                    config: self.input.config,
670                    resuming_session,
671                    server_name: self.input.server_name,
672                    randoms,
673                    using_ems: self.input.using_ems,
674                    transcript,
675                }
676                .handle_server_hello(cx, suite, server_hello, tls13_supported)
677            }
678        }
679    }
680}
681
682impl ExpectServerHelloOrHelloRetryRequest {
683    fn into_expect_server_hello(self) -> NextState {
684        Box::new(self.next)
685    }
686
687    fn handle_hello_retry_request(
688        self,
689        cx: &mut ClientContext<'_>,
690        m: Message,
691    ) -> NextStateOrError {
692        let hrr = require_handshake_msg!(
693            m,
694            HandshakeType::HelloRetryRequest,
695            HandshakePayload::HelloRetryRequest
696        )?;
697        trace!("Got HRR {:?}", hrr);
698
699        cx.common.check_aligned_handshake()?;
700
701        let cookie = hrr.get_cookie();
702        let req_group = hrr.get_requested_key_share_group();
703
704        // We always send a key share when TLS 1.3 is enabled.
705        let offered_key_share = self.next.offered_key_share.unwrap();
706
707        // A retry request is illegal if it contains no cookie and asks for
708        // retry of a group we already sent.
709        if cookie.is_none() && req_group == Some(offered_key_share.group()) {
710            return Err({
711                cx.common.send_fatal_alert(
712                    AlertDescription::IllegalParameter,
713                    PeerMisbehaved::IllegalHelloRetryRequestWithOfferedGroup,
714                )
715            });
716        }
717
718        // Or has an empty cookie.
719        if let Some(cookie) = cookie {
720            if cookie.0.is_empty() {
721                return Err({
722                    cx.common.send_fatal_alert(
723                        AlertDescription::IllegalParameter,
724                        PeerMisbehaved::IllegalHelloRetryRequestWithEmptyCookie,
725                    )
726                });
727            }
728        }
729
730        // Or has something unrecognised
731        if hrr.has_unknown_extension() {
732            return Err(cx.common.send_fatal_alert(
733                AlertDescription::UnsupportedExtension,
734                PeerIncompatible::ServerSentHelloRetryRequestWithUnknownExtension,
735            ));
736        }
737
738        // Or has the same extensions more than once
739        if hrr.has_duplicate_extension() {
740            return Err({
741                cx.common.send_fatal_alert(
742                    AlertDescription::IllegalParameter,
743                    PeerMisbehaved::DuplicateHelloRetryRequestExtensions,
744                )
745            });
746        }
747
748        // Or asks us to change nothing.
749        if cookie.is_none() && req_group.is_none() {
750            return Err({
751                cx.common.send_fatal_alert(
752                    AlertDescription::IllegalParameter,
753                    PeerMisbehaved::IllegalHelloRetryRequestWithNoChanges,
754                )
755            });
756        }
757
758        // Or does not echo the session_id from our ClientHello:
759        //
760        // > the HelloRetryRequest has the same format as a ServerHello message,
761        // > and the legacy_version, legacy_session_id_echo, cipher_suite, and
762        // > legacy_compression_method fields have the same meaning
763        // <https://www.rfc-editor.org/rfc/rfc8446#section-4.1.4>
764        //
765        // and
766        //
767        // > A client which receives a legacy_session_id_echo field that does not
768        // > match what it sent in the ClientHello MUST abort the handshake with an
769        // > "illegal_parameter" alert.
770        // <https://www.rfc-editor.org/rfc/rfc8446#section-4.1.3>
771        if hrr.session_id != self.next.input.session_id {
772            return Err({
773                cx.common.send_fatal_alert(
774                    AlertDescription::IllegalParameter,
775                    PeerMisbehaved::IllegalHelloRetryRequestWithWrongSessionId,
776                )
777            });
778        }
779
780        // Or asks us to talk a protocol we didn't offer, or doesn't support HRR at all.
781        match hrr.get_supported_versions() {
782            Some(ProtocolVersion::TLSv1_3) => {
783                cx.common.negotiated_version = Some(ProtocolVersion::TLSv1_3);
784            }
785            _ => {
786                return Err({
787                    cx.common.send_fatal_alert(
788                        AlertDescription::IllegalParameter,
789                        PeerMisbehaved::IllegalHelloRetryRequestWithUnsupportedVersion,
790                    )
791                });
792            }
793        }
794
795        // Or asks us to use a ciphersuite we didn't offer.
796        let config = &self.next.input.config;
797        let cs = match config.find_cipher_suite(hrr.cipher_suite) {
798            Some(cs) => cs,
799            None => {
800                return Err({
801                    cx.common.send_fatal_alert(
802                        AlertDescription::IllegalParameter,
803                        PeerMisbehaved::IllegalHelloRetryRequestWithUnofferedCipherSuite,
804                    )
805                });
806            }
807        };
808
809        // HRR selects the ciphersuite.
810        cx.common.suite = Some(cs);
811
812        // This is the draft19 change where the transcript became a tree
813        let transcript = self
814            .next
815            .transcript_buffer
816            .start_hash(cs.hash_algorithm());
817        let mut transcript_buffer = transcript.into_hrr_buffer();
818        transcript_buffer.add_message(&m);
819
820        // Early data is not allowed after HelloRetryrequest
821        if cx.data.early_data.is_enabled() {
822            cx.data.early_data.rejected();
823        }
824
825        let may_send_sct_list = self
826            .next
827            .input
828            .hello
829            .server_may_send_sct_list();
830
831        let key_share = match req_group {
832            Some(group) if group != offered_key_share.group() => {
833                let group = kx::KeyExchange::choose(group, &config.kx_groups).ok_or_else(|| {
834                    cx.common.send_fatal_alert(
835                        AlertDescription::IllegalParameter,
836                        PeerMisbehaved::IllegalHelloRetryRequestWithUnofferedNamedGroup,
837                    )
838                })?;
839                kx::KeyExchange::start(group).ok_or(Error::FailedToGetRandomBytes)?
840            }
841            _ => offered_key_share,
842        };
843
844        Ok(emit_client_hello_for_retry(
845            transcript_buffer,
846            Some(hrr),
847            Some(key_share),
848            self.extra_exts,
849            may_send_sct_list,
850            Some(cs),
851            self.next.input,
852            cx,
853        ))
854    }
855}
856
857impl State<ClientConnectionData> for ExpectServerHelloOrHelloRetryRequest {
858    fn handle(self: Box<Self>, cx: &mut ClientContext<'_>, m: Message) -> NextStateOrError {
859        match m.payload {
860            MessagePayload::Handshake {
861                parsed:
862                    HandshakeMessagePayload {
863                        payload: HandshakePayload::ServerHello(..),
864                        ..
865                    },
866                ..
867            } => self
868                .into_expect_server_hello()
869                .handle(cx, m),
870            MessagePayload::Handshake {
871                parsed:
872                    HandshakeMessagePayload {
873                        payload: HandshakePayload::HelloRetryRequest(..),
874                        ..
875                    },
876                ..
877            } => self.handle_hello_retry_request(cx, m),
878            payload => Err(inappropriate_handshake_message(
879                &payload,
880                &[ContentType::Handshake],
881                &[HandshakeType::ServerHello, HandshakeType::HelloRetryRequest],
882            )),
883        }
884    }
885}
886
887enum ClientSessionValue {
888    Tls13(persist::Tls13ClientSessionValue),
889    #[cfg(feature = "tls12")]
890    Tls12(persist::Tls12ClientSessionValue),
891}
892
893impl ClientSessionValue {
894    fn common(&self) -> &persist::ClientSessionCommon {
895        match self {
896            Self::Tls13(inner) => &inner.common,
897            #[cfg(feature = "tls12")]
898            Self::Tls12(inner) => &inner.common,
899        }
900    }
901
902    fn tls13(&self) -> Option<&persist::Tls13ClientSessionValue> {
903        match self {
904            Self::Tls13(v) => Some(v),
905            #[cfg(feature = "tls12")]
906            Self::Tls12(_) => None,
907        }
908    }
909}
910
911impl Deref for ClientSessionValue {
912    type Target = persist::ClientSessionCommon;
913
914    fn deref(&self) -> &Self::Target {
915        self.common()
916    }
917}