1 | use alloc::borrow::ToOwned; |
2 | use alloc::boxed::Box; |
3 | use alloc::vec::Vec; |
4 | |
5 | use pki_types::DnsName; |
6 | |
7 | use super::server_conn::ServerConnectionData; |
8 | #[cfg (feature = "tls12" )] |
9 | use super::tls12; |
10 | use crate::common_state::{KxState, Protocol, State}; |
11 | use crate::conn::ConnectionRandoms; |
12 | use crate::crypto::SupportedKxGroup; |
13 | use crate::enums::{ |
14 | AlertDescription, CipherSuite, HandshakeType, ProtocolVersion, SignatureAlgorithm, |
15 | SignatureScheme, |
16 | }; |
17 | use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; |
18 | use crate::hash_hs::{HandshakeHash, HandshakeHashBuffer}; |
19 | use crate::log::{debug, trace}; |
20 | use crate::msgs::enums::{CertificateType, Compression, ExtensionType, NamedGroup}; |
21 | #[cfg (feature = "tls12" )] |
22 | use crate::msgs::handshake::SessionId; |
23 | use crate::msgs::handshake::{ |
24 | ClientHelloPayload, ConvertProtocolNameList, ConvertServerNameList, HandshakePayload, |
25 | KeyExchangeAlgorithm, Random, ServerExtension, |
26 | }; |
27 | use crate::msgs::message::{Message, MessagePayload}; |
28 | use crate::msgs::persist; |
29 | use crate::server::common::ActiveCertifiedKey; |
30 | use crate::server::{ClientHello, ServerConfig, tls13}; |
31 | use crate::sync::Arc; |
32 | use crate::{SupportedCipherSuite, suites}; |
33 | |
34 | pub(super) type NextState<'a> = Box<dyn State<ServerConnectionData> + 'a>; |
35 | pub(super) type NextStateOrError<'a> = Result<NextState<'a>, Error>; |
36 | pub(super) type ServerContext<'a> = crate::common_state::Context<'a, ServerConnectionData>; |
37 | |
38 | pub(super) fn can_resume( |
39 | suite: SupportedCipherSuite, |
40 | sni: &Option<DnsName<'_>>, |
41 | using_ems: bool, |
42 | resumedata: &persist::ServerSessionValue, |
43 | ) -> bool { |
44 | // The RFCs underspecify what happens if we try to resume to |
45 | // an unoffered/varying suite. We merely don't resume in weird cases. |
46 | // |
47 | // RFC 6066 says "A server that implements this extension MUST NOT accept |
48 | // the request to resume the session if the server_name extension contains |
49 | // a different name. Instead, it proceeds with a full handshake to |
50 | // establish a new session." |
51 | resumedata.cipher_suite == suite.suite() |
52 | && (resumedata.extended_ms == using_ems || (resumedata.extended_ms && !using_ems)) |
53 | && &resumedata.sni == sni |
54 | } |
55 | |
56 | #[derive (Default)] |
57 | pub(super) struct ExtensionProcessing { |
58 | // extensions to reply with |
59 | pub(super) exts: Vec<ServerExtension>, |
60 | #[cfg (feature = "tls12" )] |
61 | pub(super) send_ticket: bool, |
62 | } |
63 | |
64 | impl ExtensionProcessing { |
65 | pub(super) fn new() -> Self { |
66 | Default::default() |
67 | } |
68 | |
69 | pub(super) fn process_common( |
70 | &mut self, |
71 | config: &ServerConfig, |
72 | cx: &mut ServerContext<'_>, |
73 | ocsp_response: &mut Option<&[u8]>, |
74 | hello: &ClientHelloPayload, |
75 | resumedata: Option<&persist::ServerSessionValue>, |
76 | extra_exts: Vec<ServerExtension>, |
77 | ) -> Result<(), Error> { |
78 | // ALPN |
79 | let our_protocols = &config.alpn_protocols; |
80 | let maybe_their_protocols = hello.alpn_extension(); |
81 | if let Some(their_protocols) = maybe_their_protocols { |
82 | let their_protocols = their_protocols.to_slices(); |
83 | |
84 | if their_protocols |
85 | .iter() |
86 | .any(|protocol| protocol.is_empty()) |
87 | { |
88 | return Err(PeerMisbehaved::OfferedEmptyApplicationProtocol.into()); |
89 | } |
90 | |
91 | cx.common.alpn_protocol = our_protocols |
92 | .iter() |
93 | .find(|protocol| their_protocols.contains(&protocol.as_slice())) |
94 | .cloned(); |
95 | if let Some(selected_protocol) = &cx.common.alpn_protocol { |
96 | debug!("Chosen ALPN protocol {:?}" , selected_protocol); |
97 | self.exts |
98 | .push(ServerExtension::make_alpn(&[selected_protocol])); |
99 | } else if !our_protocols.is_empty() { |
100 | return Err(cx.common.send_fatal_alert( |
101 | AlertDescription::NoApplicationProtocol, |
102 | Error::NoApplicationProtocol, |
103 | )); |
104 | } |
105 | } |
106 | |
107 | if cx.common.is_quic() { |
108 | // QUIC has strict ALPN, unlike TLS's more backwards-compatible behavior. RFC 9001 |
109 | // says: "The server MUST treat the inability to select a compatible application |
110 | // protocol as a connection error of type 0x0178". We judge that ALPN was desired |
111 | // (rather than some out-of-band protocol negotiation mechanism) if and only if any ALPN |
112 | // protocols were configured locally or offered by the client. This helps prevent |
113 | // successful establishment of connections between peers that can't understand |
114 | // each other. |
115 | if cx.common.alpn_protocol.is_none() |
116 | && (!our_protocols.is_empty() || maybe_their_protocols.is_some()) |
117 | { |
118 | return Err(cx.common.send_fatal_alert( |
119 | AlertDescription::NoApplicationProtocol, |
120 | Error::NoApplicationProtocol, |
121 | )); |
122 | } |
123 | |
124 | match hello.quic_params_extension() { |
125 | Some(params) => cx.common.quic.params = Some(params), |
126 | None => { |
127 | return Err(cx |
128 | .common |
129 | .missing_extension(PeerMisbehaved::MissingQuicTransportParameters)); |
130 | } |
131 | } |
132 | } |
133 | |
134 | let for_resume = resumedata.is_some(); |
135 | // SNI |
136 | if !for_resume && hello.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 | self.validate_server_cert_type_extension(hello, config, cx)?; |
160 | self.validate_client_cert_type_extension(hello, config, cx)?; |
161 | |
162 | self.exts.extend(extra_exts); |
163 | |
164 | Ok(()) |
165 | } |
166 | |
167 | #[cfg (feature = "tls12" )] |
168 | pub(super) fn process_tls12( |
169 | &mut self, |
170 | config: &ServerConfig, |
171 | hello: &ClientHelloPayload, |
172 | using_ems: bool, |
173 | ) { |
174 | // Renegotiation. |
175 | // (We don't do reneg at all, but would support the secure version if we did.) |
176 | let secure_reneg_offered = hello |
177 | .find_extension(ExtensionType::RenegotiationInfo) |
178 | .is_some() |
179 | || hello |
180 | .cipher_suites |
181 | .contains(&CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV); |
182 | |
183 | if secure_reneg_offered { |
184 | self.exts |
185 | .push(ServerExtension::make_empty_renegotiation_info()); |
186 | } |
187 | |
188 | // Tickets: |
189 | // If we get any SessionTicket extension and have tickets enabled, |
190 | // we send an ack. |
191 | if hello |
192 | .find_extension(ExtensionType::SessionTicket) |
193 | .is_some() |
194 | && config.ticketer.enabled() |
195 | { |
196 | self.send_ticket = true; |
197 | self.exts |
198 | .push(ServerExtension::SessionTicketAck); |
199 | } |
200 | |
201 | // Confirm use of EMS if offered. |
202 | if using_ems { |
203 | self.exts |
204 | .push(ServerExtension::ExtendedMasterSecretAck); |
205 | } |
206 | } |
207 | |
208 | fn validate_server_cert_type_extension( |
209 | &mut self, |
210 | hello: &ClientHelloPayload, |
211 | config: &ServerConfig, |
212 | cx: &mut ServerContext<'_>, |
213 | ) -> Result<(), Error> { |
214 | let client_supports = hello |
215 | .server_certificate_extension() |
216 | .map(|certificate_types| certificate_types.to_vec()) |
217 | .unwrap_or_default(); |
218 | |
219 | self.process_cert_type_extension( |
220 | client_supports, |
221 | config |
222 | .cert_resolver |
223 | .only_raw_public_keys(), |
224 | ExtensionType::ServerCertificateType, |
225 | cx, |
226 | ) |
227 | } |
228 | |
229 | fn validate_client_cert_type_extension( |
230 | &mut self, |
231 | hello: &ClientHelloPayload, |
232 | config: &ServerConfig, |
233 | cx: &mut ServerContext<'_>, |
234 | ) -> Result<(), Error> { |
235 | let client_supports = hello |
236 | .client_certificate_extension() |
237 | .map(|certificate_types| certificate_types.to_vec()) |
238 | .unwrap_or_default(); |
239 | |
240 | self.process_cert_type_extension( |
241 | client_supports, |
242 | config |
243 | .verifier |
244 | .requires_raw_public_keys(), |
245 | ExtensionType::ClientCertificateType, |
246 | cx, |
247 | ) |
248 | } |
249 | |
250 | fn process_cert_type_extension( |
251 | &mut self, |
252 | client_supports: Vec<CertificateType>, |
253 | requires_raw_keys: bool, |
254 | extension_type: ExtensionType, |
255 | cx: &mut ServerContext<'_>, |
256 | ) -> Result<(), Error> { |
257 | debug_assert!( |
258 | extension_type == ExtensionType::ClientCertificateType |
259 | || extension_type == ExtensionType::ServerCertificateType |
260 | ); |
261 | let raw_key_negotation_result = match ( |
262 | requires_raw_keys, |
263 | client_supports.contains(&CertificateType::RawPublicKey), |
264 | client_supports.contains(&CertificateType::X509), |
265 | ) { |
266 | (true, true, _) => Ok((extension_type, CertificateType::RawPublicKey)), |
267 | (false, _, true) => Ok((extension_type, CertificateType::X509)), |
268 | (false, true, false) => Err(Error::PeerIncompatible( |
269 | PeerIncompatible::IncorrectCertificateTypeExtension, |
270 | )), |
271 | (true, false, _) => Err(Error::PeerIncompatible( |
272 | PeerIncompatible::IncorrectCertificateTypeExtension, |
273 | )), |
274 | (false, false, false) => return Ok(()), |
275 | }; |
276 | |
277 | match raw_key_negotation_result { |
278 | Ok((ExtensionType::ClientCertificateType, cert_type)) => { |
279 | self.exts |
280 | .push(ServerExtension::ClientCertType(cert_type)); |
281 | } |
282 | Ok((ExtensionType::ServerCertificateType, cert_type)) => { |
283 | self.exts |
284 | .push(ServerExtension::ServerCertType(cert_type)); |
285 | } |
286 | Err(err) => { |
287 | return Err(cx |
288 | .common |
289 | .send_fatal_alert(AlertDescription::HandshakeFailure, err)); |
290 | } |
291 | Ok((_, _)) => unreachable!(), |
292 | } |
293 | Ok(()) |
294 | } |
295 | } |
296 | |
297 | pub(super) struct ExpectClientHello { |
298 | pub(super) config: Arc<ServerConfig>, |
299 | pub(super) extra_exts: Vec<ServerExtension>, |
300 | pub(super) transcript: HandshakeHashOrBuffer, |
301 | #[cfg (feature = "tls12" )] |
302 | pub(super) session_id: SessionId, |
303 | #[cfg (feature = "tls12" )] |
304 | pub(super) using_ems: bool, |
305 | pub(super) done_retry: bool, |
306 | pub(super) send_tickets: usize, |
307 | } |
308 | |
309 | impl ExpectClientHello { |
310 | pub(super) fn new(config: Arc<ServerConfig>, extra_exts: Vec<ServerExtension>) -> Self { |
311 | let mut transcript_buffer = HandshakeHashBuffer::new(); |
312 | |
313 | if config.verifier.offer_client_auth() { |
314 | transcript_buffer.set_client_auth_enabled(); |
315 | } |
316 | |
317 | Self { |
318 | config, |
319 | extra_exts, |
320 | transcript: HandshakeHashOrBuffer::Buffer(transcript_buffer), |
321 | #[cfg (feature = "tls12" )] |
322 | session_id: SessionId::empty(), |
323 | #[cfg (feature = "tls12" )] |
324 | using_ems: false, |
325 | done_retry: false, |
326 | send_tickets: 0, |
327 | } |
328 | } |
329 | |
330 | /// Continues handling of a `ClientHello` message once config and certificate are available. |
331 | pub(super) fn with_certified_key( |
332 | self, |
333 | mut sig_schemes: Vec<SignatureScheme>, |
334 | client_hello: &ClientHelloPayload, |
335 | m: &Message<'_>, |
336 | cx: &mut ServerContext<'_>, |
337 | ) -> NextStateOrError<'static> { |
338 | let tls13_enabled = self |
339 | .config |
340 | .supports_version(ProtocolVersion::TLSv1_3); |
341 | let tls12_enabled = self |
342 | .config |
343 | .supports_version(ProtocolVersion::TLSv1_2); |
344 | |
345 | // Are we doing TLS1.3? |
346 | let maybe_versions_ext = client_hello.versions_extension(); |
347 | let version = if let Some(versions) = maybe_versions_ext { |
348 | if versions.contains(&ProtocolVersion::TLSv1_3) && tls13_enabled { |
349 | ProtocolVersion::TLSv1_3 |
350 | } else if !versions.contains(&ProtocolVersion::TLSv1_2) || !tls12_enabled { |
351 | return Err(cx.common.send_fatal_alert( |
352 | AlertDescription::ProtocolVersion, |
353 | PeerIncompatible::Tls12NotOfferedOrEnabled, |
354 | )); |
355 | } else if cx.common.is_quic() { |
356 | return Err(cx.common.send_fatal_alert( |
357 | AlertDescription::ProtocolVersion, |
358 | PeerIncompatible::Tls13RequiredForQuic, |
359 | )); |
360 | } else { |
361 | ProtocolVersion::TLSv1_2 |
362 | } |
363 | } else if u16::from(client_hello.client_version) < u16::from(ProtocolVersion::TLSv1_2) { |
364 | return Err(cx.common.send_fatal_alert( |
365 | AlertDescription::ProtocolVersion, |
366 | PeerIncompatible::Tls12NotOffered, |
367 | )); |
368 | } else if !tls12_enabled && tls13_enabled { |
369 | return Err(cx.common.send_fatal_alert( |
370 | AlertDescription::ProtocolVersion, |
371 | PeerIncompatible::SupportedVersionsExtensionRequired, |
372 | )); |
373 | } else if cx.common.is_quic() { |
374 | return Err(cx.common.send_fatal_alert( |
375 | AlertDescription::ProtocolVersion, |
376 | PeerIncompatible::Tls13RequiredForQuic, |
377 | )); |
378 | } else { |
379 | ProtocolVersion::TLSv1_2 |
380 | }; |
381 | |
382 | cx.common.negotiated_version = Some(version); |
383 | |
384 | // We communicate to the upper layer what kind of key they should choose |
385 | // via the sigschemes value. Clients tend to treat this extension |
386 | // orthogonally to offered ciphersuites (even though, in TLS1.2 it is not). |
387 | // So: reduce the offered sigschemes to those compatible with the |
388 | // intersection of ciphersuites. |
389 | let client_suites = self |
390 | .config |
391 | .provider |
392 | .cipher_suites |
393 | .iter() |
394 | .copied() |
395 | .filter(|scs| { |
396 | client_hello |
397 | .cipher_suites |
398 | .contains(&scs.suite()) |
399 | }) |
400 | .collect::<Vec<_>>(); |
401 | |
402 | sig_schemes |
403 | .retain(|scheme| suites::compatible_sigscheme_for_suites(*scheme, &client_suites)); |
404 | |
405 | // We adhere to the TLS 1.2 RFC by not exposing this to the cert resolver if TLS version is 1.2 |
406 | let certificate_authorities = match version { |
407 | ProtocolVersion::TLSv1_2 => None, |
408 | _ => client_hello.certificate_authorities_extension(), |
409 | }; |
410 | // Choose a certificate. |
411 | let certkey = { |
412 | let client_hello = ClientHello { |
413 | server_name: &cx.data.sni, |
414 | signature_schemes: &sig_schemes, |
415 | alpn: client_hello.alpn_extension(), |
416 | client_cert_types: client_hello.server_certificate_extension(), |
417 | server_cert_types: client_hello.client_certificate_extension(), |
418 | cipher_suites: &client_hello.cipher_suites, |
419 | certificate_authorities, |
420 | }; |
421 | trace!("Resolving server certificate: {client_hello:#?}" ); |
422 | |
423 | let certkey = self |
424 | .config |
425 | .cert_resolver |
426 | .resolve(client_hello); |
427 | |
428 | certkey.ok_or_else(|| { |
429 | cx.common.send_fatal_alert( |
430 | AlertDescription::AccessDenied, |
431 | Error::General("no server certificate chain resolved" .to_owned()), |
432 | ) |
433 | })? |
434 | }; |
435 | let certkey = ActiveCertifiedKey::from_certified_key(&certkey); |
436 | |
437 | let (suite, skxg) = self |
438 | .choose_suite_and_kx_group( |
439 | version, |
440 | certkey.get_key().algorithm(), |
441 | cx.common.protocol, |
442 | client_hello |
443 | .namedgroups_extension() |
444 | .unwrap_or(&[]), |
445 | &client_hello.cipher_suites, |
446 | ) |
447 | .map_err(|incompat| { |
448 | cx.common |
449 | .send_fatal_alert(AlertDescription::HandshakeFailure, incompat) |
450 | })?; |
451 | |
452 | debug!("decided upon suite {:?}" , suite); |
453 | cx.common.suite = Some(suite); |
454 | cx.common.kx_state = KxState::Start(skxg); |
455 | |
456 | // Start handshake hash. |
457 | let starting_hash = suite.hash_provider(); |
458 | let transcript = match self.transcript { |
459 | HandshakeHashOrBuffer::Buffer(inner) => inner.start_hash(starting_hash), |
460 | HandshakeHashOrBuffer::Hash(inner) |
461 | if inner.algorithm() == starting_hash.algorithm() => |
462 | { |
463 | inner |
464 | } |
465 | _ => { |
466 | return Err(cx.common.send_fatal_alert( |
467 | AlertDescription::IllegalParameter, |
468 | PeerMisbehaved::HandshakeHashVariedAfterRetry, |
469 | )); |
470 | } |
471 | }; |
472 | |
473 | // Save their Random. |
474 | let randoms = ConnectionRandoms::new( |
475 | client_hello.random, |
476 | Random::new(self.config.provider.secure_random)?, |
477 | ); |
478 | match suite { |
479 | SupportedCipherSuite::Tls13(suite) => tls13::CompleteClientHelloHandling { |
480 | config: self.config, |
481 | transcript, |
482 | suite, |
483 | randoms, |
484 | done_retry: self.done_retry, |
485 | send_tickets: self.send_tickets, |
486 | extra_exts: self.extra_exts, |
487 | } |
488 | .handle_client_hello(cx, certkey, m, client_hello, skxg, sig_schemes), |
489 | #[cfg (feature = "tls12" )] |
490 | SupportedCipherSuite::Tls12(suite) => tls12::CompleteClientHelloHandling { |
491 | config: self.config, |
492 | transcript, |
493 | session_id: self.session_id, |
494 | suite, |
495 | using_ems: self.using_ems, |
496 | randoms, |
497 | send_ticket: self.send_tickets > 0, |
498 | extra_exts: self.extra_exts, |
499 | } |
500 | .handle_client_hello( |
501 | cx, |
502 | certkey, |
503 | m, |
504 | client_hello, |
505 | skxg, |
506 | sig_schemes, |
507 | tls13_enabled, |
508 | ), |
509 | } |
510 | } |
511 | |
512 | fn choose_suite_and_kx_group( |
513 | &self, |
514 | selected_version: ProtocolVersion, |
515 | sig_key_algorithm: SignatureAlgorithm, |
516 | protocol: Protocol, |
517 | client_groups: &[NamedGroup], |
518 | client_suites: &[CipherSuite], |
519 | ) -> Result<(SupportedCipherSuite, &'static dyn SupportedKxGroup), PeerIncompatible> { |
520 | // Determine which `KeyExchangeAlgorithm`s are theoretically possible, based |
521 | // on the offered and supported groups. |
522 | let mut ecdhe_possible = false; |
523 | let mut ffdhe_possible = false; |
524 | let mut ffdhe_offered = false; |
525 | let mut supported_groups = Vec::with_capacity(client_groups.len()); |
526 | |
527 | for offered_group in client_groups { |
528 | let supported = self |
529 | .config |
530 | .provider |
531 | .kx_groups |
532 | .iter() |
533 | .find(|skxg| { |
534 | skxg.usable_for_version(selected_version) && skxg.name() == *offered_group |
535 | }); |
536 | |
537 | match offered_group.key_exchange_algorithm() { |
538 | KeyExchangeAlgorithm::DHE => { |
539 | ffdhe_possible |= supported.is_some(); |
540 | ffdhe_offered = true; |
541 | } |
542 | KeyExchangeAlgorithm::ECDHE => { |
543 | ecdhe_possible |= supported.is_some(); |
544 | } |
545 | } |
546 | |
547 | supported_groups.push(supported); |
548 | } |
549 | |
550 | let first_supported_dhe_kxg = if selected_version == ProtocolVersion::TLSv1_2 { |
551 | // https://datatracker.ietf.org/doc/html/rfc7919#section-4 (paragraph 2) |
552 | let first_supported_dhe_kxg = self |
553 | .config |
554 | .provider |
555 | .kx_groups |
556 | .iter() |
557 | .find(|skxg| skxg.name().key_exchange_algorithm() == KeyExchangeAlgorithm::DHE); |
558 | ffdhe_possible |= !ffdhe_offered && first_supported_dhe_kxg.is_some(); |
559 | first_supported_dhe_kxg |
560 | } else { |
561 | // In TLS1.3, the server may only directly negotiate a group. |
562 | None |
563 | }; |
564 | |
565 | if !ecdhe_possible && !ffdhe_possible { |
566 | return Err(PeerIncompatible::NoKxGroupsInCommon); |
567 | } |
568 | |
569 | let mut suitable_suites_iter = self |
570 | .config |
571 | .provider |
572 | .cipher_suites |
573 | .iter() |
574 | .filter(|suite| { |
575 | // Reduce our supported ciphersuites by the certified key's algorithm. |
576 | suite.usable_for_signature_algorithm(sig_key_algorithm) |
577 | // And version |
578 | && suite.version().version == selected_version |
579 | // And protocol |
580 | && suite.usable_for_protocol(protocol) |
581 | // And support one of key exchange groups |
582 | && (ecdhe_possible && suite.usable_for_kx_algorithm(KeyExchangeAlgorithm::ECDHE) |
583 | || ffdhe_possible && suite.usable_for_kx_algorithm(KeyExchangeAlgorithm::DHE)) |
584 | }); |
585 | |
586 | // RFC 7919 (https://datatracker.ietf.org/doc/html/rfc7919#section-4) requires us to send |
587 | // the InsufficientSecurity alert in case we don't recognize client's FFDHE groups (i.e., |
588 | // `suitable_suites` becomes empty). But that does not make a lot of sense (e.g., client |
589 | // proposes FFDHE4096 and we only support FFDHE2048), so we ignore that requirement here, |
590 | // and continue to send HandshakeFailure. |
591 | |
592 | let suite = if self.config.ignore_client_order { |
593 | suitable_suites_iter.find(|suite| client_suites.contains(&suite.suite())) |
594 | } else { |
595 | let suitable_suites = suitable_suites_iter.collect::<Vec<_>>(); |
596 | client_suites |
597 | .iter() |
598 | .find_map(|client_suite| { |
599 | suitable_suites |
600 | .iter() |
601 | .find(|x| *client_suite == x.suite()) |
602 | }) |
603 | .copied() |
604 | } |
605 | .ok_or(PeerIncompatible::NoCipherSuitesInCommon)?; |
606 | |
607 | // Finally, choose a key exchange group that is compatible with the selected cipher |
608 | // suite. |
609 | let maybe_skxg = supported_groups |
610 | .iter() |
611 | .find_map(|maybe_skxg| match maybe_skxg { |
612 | Some(skxg) => suite |
613 | .usable_for_kx_algorithm(skxg.name().key_exchange_algorithm()) |
614 | .then_some(*skxg), |
615 | None => None, |
616 | }); |
617 | |
618 | if selected_version == ProtocolVersion::TLSv1_3 { |
619 | // This unwrap is structurally guaranteed by the early return for `!ffdhe_possible && !ecdhe_possible` |
620 | return Ok((*suite, *maybe_skxg.unwrap())); |
621 | } |
622 | |
623 | // For TLS1.2, the server can unilaterally choose a DHE group if it has one and |
624 | // there was no better option. |
625 | match maybe_skxg { |
626 | Some(skxg) => Ok((*suite, *skxg)), |
627 | None if suite.usable_for_kx_algorithm(KeyExchangeAlgorithm::DHE) => { |
628 | // If kx for the selected cipher suite is DHE and no DHE groups are specified in the extension, |
629 | // the server is free to choose DHE params, we choose the first DHE kx group of the provider. |
630 | if let Some(server_selected_ffdhe_skxg) = first_supported_dhe_kxg { |
631 | Ok((*suite, *server_selected_ffdhe_skxg)) |
632 | } else { |
633 | Err(PeerIncompatible::NoKxGroupsInCommon) |
634 | } |
635 | } |
636 | None => Err(PeerIncompatible::NoKxGroupsInCommon), |
637 | } |
638 | } |
639 | } |
640 | |
641 | impl State<ServerConnectionData> for ExpectClientHello { |
642 | fn handle<'m>( |
643 | self: Box<Self>, |
644 | cx: &mut ServerContext<'_>, |
645 | m: Message<'m>, |
646 | ) -> NextStateOrError<'m> |
647 | where |
648 | Self: 'm, |
649 | { |
650 | let (client_hello: &ClientHelloPayload, sig_schemes: Vec) = process_client_hello(&m, self.done_retry, cx)?; |
651 | self.with_certified_key(sig_schemes, client_hello, &m, cx) |
652 | } |
653 | |
654 | fn into_owned(self: Box<Self>) -> NextState<'static> { |
655 | self |
656 | } |
657 | } |
658 | |
659 | /// Configuration-independent validation of a `ClientHello` message. |
660 | /// |
661 | /// This represents the first part of the `ClientHello` handling, where we do all validation that |
662 | /// doesn't depend on a `ServerConfig` being available and extract everything needed to build a |
663 | /// [`ClientHello`] value for a [`ResolvesServerCert`]. |
664 | /// |
665 | /// Note that this will modify `data.sni` even if config or certificate resolution fail. |
666 | /// |
667 | /// [`ResolvesServerCert`]: crate::server::ResolvesServerCert |
668 | pub(super) fn process_client_hello<'m>( |
669 | m: &'m Message<'m>, |
670 | done_retry: bool, |
671 | cx: &mut ServerContext<'_>, |
672 | ) -> Result<(&'m ClientHelloPayload, Vec<SignatureScheme>), Error> { |
673 | let client_hello = |
674 | require_handshake_msg!(m, HandshakeType::ClientHello, HandshakePayload::ClientHello)?; |
675 | trace!("we got a clienthello {:?}" , client_hello); |
676 | |
677 | if !client_hello |
678 | .compression_methods |
679 | .contains(&Compression::Null) |
680 | { |
681 | return Err(cx.common.send_fatal_alert( |
682 | AlertDescription::IllegalParameter, |
683 | PeerIncompatible::NullCompressionRequired, |
684 | )); |
685 | } |
686 | |
687 | if client_hello.has_duplicate_extension() { |
688 | return Err(cx.common.send_fatal_alert( |
689 | AlertDescription::DecodeError, |
690 | PeerMisbehaved::DuplicateClientHelloExtensions, |
691 | )); |
692 | } |
693 | |
694 | // No handshake messages should follow this one in this flight. |
695 | cx.common.check_aligned_handshake()?; |
696 | |
697 | // Extract and validate the SNI DNS name, if any, before giving it to |
698 | // the cert resolver. In particular, if it is invalid then we should |
699 | // send an Illegal Parameter alert instead of the Internal Error alert |
700 | // (or whatever) that we'd send if this were checked later or in a |
701 | // different way. |
702 | let sni: Option<DnsName<'_>> = match client_hello.sni_extension() { |
703 | Some(sni) => { |
704 | if sni.has_duplicate_names_for_type() { |
705 | return Err(cx.common.send_fatal_alert( |
706 | AlertDescription::DecodeError, |
707 | PeerMisbehaved::DuplicateServerNameTypes, |
708 | )); |
709 | } |
710 | |
711 | if let Some(hostname) = sni.single_hostname() { |
712 | Some(hostname.to_lowercase_owned()) |
713 | } else { |
714 | return Err(cx.common.send_fatal_alert( |
715 | AlertDescription::IllegalParameter, |
716 | PeerMisbehaved::ServerNameMustContainOneHostName, |
717 | )); |
718 | } |
719 | } |
720 | None => None, |
721 | }; |
722 | |
723 | // save only the first SNI |
724 | if let (Some(sni), false) = (&sni, done_retry) { |
725 | // Save the SNI into the session. |
726 | // The SNI hostname is immutable once set. |
727 | assert!(cx.data.sni.is_none()); |
728 | cx.data.sni = Some(sni.clone()); |
729 | } else if cx.data.sni != sni { |
730 | return Err(PeerMisbehaved::ServerNameDifferedOnRetry.into()); |
731 | } |
732 | |
733 | let sig_schemes = client_hello |
734 | .sigalgs_extension() |
735 | .ok_or_else(|| { |
736 | cx.common.send_fatal_alert( |
737 | AlertDescription::HandshakeFailure, |
738 | PeerIncompatible::SignatureAlgorithmsExtensionRequired, |
739 | ) |
740 | })?; |
741 | |
742 | Ok((client_hello, sig_schemes.to_owned())) |
743 | } |
744 | |
745 | pub(crate) enum HandshakeHashOrBuffer { |
746 | Buffer(HandshakeHashBuffer), |
747 | Hash(HandshakeHash), |
748 | } |
749 | |