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