/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-0.23.23/src/server/hs.rs
Line | Count | Source |
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::{tls13, ClientHello, ServerConfig}; |
31 | | use crate::sync::Arc; |
32 | | use crate::{suites, SupportedCipherSuite}; |
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 | 0 | pub(super) fn can_resume( |
39 | 0 | suite: SupportedCipherSuite, |
40 | 0 | sni: &Option<DnsName<'_>>, |
41 | 0 | using_ems: bool, |
42 | 0 | resumedata: &persist::ServerSessionValue, |
43 | 0 | ) -> 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 | 0 | resumedata.cipher_suite == suite.suite() |
52 | 0 | && (resumedata.extended_ms == using_ems || (resumedata.extended_ms && !using_ems)) |
53 | 0 | && &resumedata.sni == sni |
54 | 0 | } |
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 | 0 | pub(super) fn new() -> Self { |
66 | 0 | Default::default() |
67 | 0 | } |
68 | | |
69 | 0 | pub(super) fn process_common( |
70 | 0 | &mut self, |
71 | 0 | config: &ServerConfig, |
72 | 0 | cx: &mut ServerContext<'_>, |
73 | 0 | ocsp_response: &mut Option<&[u8]>, |
74 | 0 | hello: &ClientHelloPayload, |
75 | 0 | resumedata: Option<&persist::ServerSessionValue>, |
76 | 0 | extra_exts: Vec<ServerExtension>, |
77 | 0 | ) -> Result<(), Error> { |
78 | | // ALPN |
79 | 0 | let our_protocols = &config.alpn_protocols; |
80 | 0 | let maybe_their_protocols = hello.alpn_extension(); |
81 | 0 | if let Some(their_protocols) = maybe_their_protocols { |
82 | 0 | let their_protocols = their_protocols.to_slices(); |
83 | | |
84 | 0 | if their_protocols |
85 | 0 | .iter() |
86 | 0 | .any(|protocol| protocol.is_empty()) |
87 | | { |
88 | 0 | return Err(PeerMisbehaved::OfferedEmptyApplicationProtocol.into()); |
89 | 0 | } |
90 | | |
91 | 0 | cx.common.alpn_protocol = our_protocols |
92 | 0 | .iter() |
93 | 0 | .find(|protocol| their_protocols.contains(&protocol.as_slice())) |
94 | 0 | .cloned(); |
95 | 0 | if let Some(ref selected_protocol) = cx.common.alpn_protocol { |
96 | 0 | debug!("Chosen ALPN protocol {:?}", selected_protocol); |
97 | 0 | self.exts |
98 | 0 | .push(ServerExtension::make_alpn(&[selected_protocol])); |
99 | 0 | } else if !our_protocols.is_empty() { |
100 | 0 | return Err(cx.common.send_fatal_alert( |
101 | 0 | AlertDescription::NoApplicationProtocol, |
102 | 0 | Error::NoApplicationProtocol, |
103 | 0 | )); |
104 | 0 | } |
105 | 0 | } |
106 | | |
107 | 0 | 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 | 0 | if cx.common.alpn_protocol.is_none() |
116 | 0 | && (!our_protocols.is_empty() || maybe_their_protocols.is_some()) |
117 | | { |
118 | 0 | return Err(cx.common.send_fatal_alert( |
119 | 0 | AlertDescription::NoApplicationProtocol, |
120 | 0 | Error::NoApplicationProtocol, |
121 | 0 | )); |
122 | 0 | } |
123 | | |
124 | 0 | match hello.quic_params_extension() { |
125 | 0 | Some(params) => cx.common.quic.params = Some(params), |
126 | | None => { |
127 | 0 | return Err(cx |
128 | 0 | .common |
129 | 0 | .missing_extension(PeerMisbehaved::MissingQuicTransportParameters)); |
130 | | } |
131 | | } |
132 | 0 | } |
133 | | |
134 | 0 | let for_resume = resumedata.is_some(); |
135 | | // SNI |
136 | 0 | if !for_resume && hello.sni_extension().is_some() { |
137 | 0 | self.exts |
138 | 0 | .push(ServerExtension::ServerNameAck); |
139 | 0 | } |
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 | 0 | if !for_resume |
145 | 0 | && hello |
146 | 0 | .find_extension(ExtensionType::StatusRequest) |
147 | 0 | .is_some() |
148 | | { |
149 | 0 | if ocsp_response.is_some() && !cx.common.is_tls13() { |
150 | 0 | // Only TLS1.2 sends confirmation in ServerHello |
151 | 0 | self.exts |
152 | 0 | .push(ServerExtension::CertificateStatusAck); |
153 | 0 | } |
154 | 0 | } else { |
155 | 0 | // Throw away any OCSP response so we don't try to send it later. |
156 | 0 | ocsp_response.take(); |
157 | 0 | } |
158 | | |
159 | 0 | self.validate_server_cert_type_extension(hello, config, cx)?; |
160 | 0 | self.validate_client_cert_type_extension(hello, config, cx)?; |
161 | | |
162 | 0 | self.exts.extend(extra_exts); |
163 | | |
164 | 0 | Ok(()) |
165 | 0 | } |
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 | 0 | fn validate_server_cert_type_extension( |
209 | 0 | &mut self, |
210 | 0 | hello: &ClientHelloPayload, |
211 | 0 | config: &ServerConfig, |
212 | 0 | cx: &mut ServerContext<'_>, |
213 | 0 | ) -> Result<(), Error> { |
214 | 0 | let client_supports = hello |
215 | 0 | .server_certificate_extension() |
216 | 0 | .map(|certificate_types| certificate_types.to_vec()) |
217 | 0 | .unwrap_or_default(); |
218 | | |
219 | 0 | self.process_cert_type_extension( |
220 | 0 | client_supports, |
221 | 0 | config |
222 | 0 | .cert_resolver |
223 | 0 | .only_raw_public_keys(), |
224 | 0 | ExtensionType::ServerCertificateType, |
225 | 0 | cx, |
226 | | ) |
227 | 0 | } |
228 | | |
229 | 0 | fn validate_client_cert_type_extension( |
230 | 0 | &mut self, |
231 | 0 | hello: &ClientHelloPayload, |
232 | 0 | config: &ServerConfig, |
233 | 0 | cx: &mut ServerContext<'_>, |
234 | 0 | ) -> Result<(), Error> { |
235 | 0 | let client_supports = hello |
236 | 0 | .client_certificate_extension() |
237 | 0 | .map(|certificate_types| certificate_types.to_vec()) |
238 | 0 | .unwrap_or_default(); |
239 | | |
240 | 0 | self.process_cert_type_extension( |
241 | 0 | client_supports, |
242 | 0 | config |
243 | 0 | .verifier |
244 | 0 | .requires_raw_public_keys(), |
245 | 0 | ExtensionType::ClientCertificateType, |
246 | 0 | cx, |
247 | | ) |
248 | 0 | } |
249 | | |
250 | 0 | fn process_cert_type_extension( |
251 | 0 | &mut self, |
252 | 0 | client_supports: Vec<CertificateType>, |
253 | 0 | requires_raw_keys: bool, |
254 | 0 | extension_type: ExtensionType, |
255 | 0 | cx: &mut ServerContext<'_>, |
256 | 0 | ) -> Result<(), Error> { |
257 | 0 | debug_assert!( |
258 | 0 | extension_type == ExtensionType::ClientCertificateType |
259 | 0 | || extension_type == ExtensionType::ServerCertificateType |
260 | | ); |
261 | 0 | let raw_key_negotation_result = match ( |
262 | 0 | requires_raw_keys, |
263 | 0 | client_supports.contains(&CertificateType::RawPublicKey), |
264 | 0 | client_supports.contains(&CertificateType::X509), |
265 | 0 | ) { |
266 | 0 | (true, true, _) => Ok((extension_type, CertificateType::RawPublicKey)), |
267 | 0 | (false, _, true) => Ok((extension_type, CertificateType::X509)), |
268 | 0 | (false, true, false) => Err(Error::PeerIncompatible( |
269 | 0 | PeerIncompatible::IncorrectCertificateTypeExtension, |
270 | 0 | )), |
271 | 0 | (true, false, _) => Err(Error::PeerIncompatible( |
272 | 0 | PeerIncompatible::IncorrectCertificateTypeExtension, |
273 | 0 | )), |
274 | 0 | (false, false, false) => return Ok(()), |
275 | | }; |
276 | | |
277 | 0 | match raw_key_negotation_result { |
278 | 0 | Ok((ExtensionType::ClientCertificateType, cert_type)) => { |
279 | 0 | self.exts |
280 | 0 | .push(ServerExtension::ClientCertType(cert_type)); |
281 | 0 | } |
282 | 0 | Ok((ExtensionType::ServerCertificateType, cert_type)) => { |
283 | 0 | self.exts |
284 | 0 | .push(ServerExtension::ServerCertType(cert_type)); |
285 | 0 | } |
286 | 0 | Err(err) => { |
287 | 0 | return Err(cx |
288 | 0 | .common |
289 | 0 | .send_fatal_alert(AlertDescription::HandshakeFailure, err)); |
290 | | } |
291 | 0 | Ok((_, _)) => unreachable!(), |
292 | | } |
293 | 0 | Ok(()) |
294 | 0 | } |
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 | 0 | pub(super) fn new(config: Arc<ServerConfig>, extra_exts: Vec<ServerExtension>) -> Self { |
311 | 0 | let mut transcript_buffer = HandshakeHashBuffer::new(); |
312 | | |
313 | 0 | if config.verifier.offer_client_auth() { |
314 | 0 | transcript_buffer.set_client_auth_enabled(); |
315 | 0 | } |
316 | | |
317 | 0 | Self { |
318 | 0 | config, |
319 | 0 | extra_exts, |
320 | 0 | transcript: HandshakeHashOrBuffer::Buffer(transcript_buffer), |
321 | 0 | #[cfg(feature = "tls12")] |
322 | 0 | session_id: SessionId::empty(), |
323 | 0 | #[cfg(feature = "tls12")] |
324 | 0 | using_ems: false, |
325 | 0 | done_retry: false, |
326 | 0 | send_tickets: 0, |
327 | 0 | } |
328 | 0 | } |
329 | | |
330 | | /// Continues handling of a `ClientHello` message once config and certificate are available. |
331 | 0 | pub(super) fn with_certified_key( |
332 | 0 | self, |
333 | 0 | mut sig_schemes: Vec<SignatureScheme>, |
334 | 0 | client_hello: &ClientHelloPayload, |
335 | 0 | m: &Message<'_>, |
336 | 0 | cx: &mut ServerContext<'_>, |
337 | 0 | ) -> NextStateOrError<'static> { |
338 | 0 | let tls13_enabled = self |
339 | 0 | .config |
340 | 0 | .supports_version(ProtocolVersion::TLSv1_3); |
341 | 0 | let tls12_enabled = self |
342 | 0 | .config |
343 | 0 | .supports_version(ProtocolVersion::TLSv1_2); |
344 | | |
345 | | // Are we doing TLS1.3? |
346 | 0 | let maybe_versions_ext = client_hello.versions_extension(); |
347 | 0 | let version = if let Some(versions) = maybe_versions_ext { |
348 | 0 | if versions.contains(&ProtocolVersion::TLSv1_3) && tls13_enabled { |
349 | 0 | ProtocolVersion::TLSv1_3 |
350 | 0 | } else if !versions.contains(&ProtocolVersion::TLSv1_2) || !tls12_enabled { |
351 | 0 | return Err(cx.common.send_fatal_alert( |
352 | 0 | AlertDescription::ProtocolVersion, |
353 | 0 | PeerIncompatible::Tls12NotOfferedOrEnabled, |
354 | 0 | )); |
355 | 0 | } else if cx.common.is_quic() { |
356 | 0 | return Err(cx.common.send_fatal_alert( |
357 | 0 | AlertDescription::ProtocolVersion, |
358 | 0 | PeerIncompatible::Tls13RequiredForQuic, |
359 | 0 | )); |
360 | | } else { |
361 | 0 | ProtocolVersion::TLSv1_2 |
362 | | } |
363 | 0 | } else if u16::from(client_hello.client_version) < u16::from(ProtocolVersion::TLSv1_2) { |
364 | 0 | return Err(cx.common.send_fatal_alert( |
365 | 0 | AlertDescription::ProtocolVersion, |
366 | 0 | PeerIncompatible::Tls12NotOffered, |
367 | 0 | )); |
368 | 0 | } else if !tls12_enabled && tls13_enabled { |
369 | 0 | return Err(cx.common.send_fatal_alert( |
370 | 0 | AlertDescription::ProtocolVersion, |
371 | 0 | PeerIncompatible::SupportedVersionsExtensionRequired, |
372 | 0 | )); |
373 | 0 | } else if cx.common.is_quic() { |
374 | 0 | return Err(cx.common.send_fatal_alert( |
375 | 0 | AlertDescription::ProtocolVersion, |
376 | 0 | PeerIncompatible::Tls13RequiredForQuic, |
377 | 0 | )); |
378 | | } else { |
379 | 0 | ProtocolVersion::TLSv1_2 |
380 | | }; |
381 | | |
382 | 0 | 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 | 0 | let client_suites = self |
390 | 0 | .config |
391 | 0 | .provider |
392 | 0 | .cipher_suites |
393 | 0 | .iter() |
394 | 0 | .copied() |
395 | 0 | .filter(|scs| { |
396 | 0 | client_hello |
397 | 0 | .cipher_suites |
398 | 0 | .contains(&scs.suite()) |
399 | 0 | }) |
400 | 0 | .collect::<Vec<_>>(); |
401 | | |
402 | 0 | sig_schemes |
403 | 0 | .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 | 0 | let certificate_authorities = match version { |
407 | 0 | ProtocolVersion::TLSv1_2 => None, |
408 | 0 | _ => client_hello.certificate_authorities_extension(), |
409 | | }; |
410 | | // Choose a certificate. |
411 | 0 | let certkey = { |
412 | 0 | let client_hello = ClientHello { |
413 | 0 | server_name: &cx.data.sni, |
414 | 0 | signature_schemes: &sig_schemes, |
415 | 0 | alpn: client_hello.alpn_extension(), |
416 | 0 | client_cert_types: client_hello.server_certificate_extension(), |
417 | 0 | server_cert_types: client_hello.client_certificate_extension(), |
418 | 0 | cipher_suites: &client_hello.cipher_suites, |
419 | 0 | certificate_authorities, |
420 | 0 | }; |
421 | 0 | trace!("Resolving server certificate: {client_hello:#?}"); |
422 | | |
423 | 0 | let certkey = self |
424 | 0 | .config |
425 | 0 | .cert_resolver |
426 | 0 | .resolve(client_hello); |
427 | | |
428 | 0 | certkey.ok_or_else(|| { |
429 | 0 | cx.common.send_fatal_alert( |
430 | 0 | AlertDescription::AccessDenied, |
431 | 0 | Error::General("no server certificate chain resolved".to_owned()), |
432 | | ) |
433 | 0 | })? |
434 | | }; |
435 | 0 | let certkey = ActiveCertifiedKey::from_certified_key(&certkey); |
436 | | |
437 | 0 | let (suite, skxg) = self |
438 | 0 | .choose_suite_and_kx_group( |
439 | 0 | version, |
440 | 0 | certkey.get_key().algorithm(), |
441 | 0 | cx.common.protocol, |
442 | 0 | client_hello |
443 | 0 | .namedgroups_extension() |
444 | 0 | .unwrap_or(&[]), |
445 | 0 | &client_hello.cipher_suites, |
446 | | ) |
447 | 0 | .map_err(|incompat| { |
448 | 0 | cx.common |
449 | 0 | .send_fatal_alert(AlertDescription::HandshakeFailure, incompat) |
450 | 0 | })?; |
451 | | |
452 | 0 | debug!("decided upon suite {:?}", suite); |
453 | 0 | cx.common.suite = Some(suite); |
454 | 0 | cx.common.kx_state = KxState::Start(skxg); |
455 | | |
456 | | // Start handshake hash. |
457 | 0 | let starting_hash = suite.hash_provider(); |
458 | 0 | let transcript = match self.transcript { |
459 | 0 | HandshakeHashOrBuffer::Buffer(inner) => inner.start_hash(starting_hash), |
460 | 0 | HandshakeHashOrBuffer::Hash(inner) |
461 | 0 | if inner.algorithm() == starting_hash.algorithm() => |
462 | | { |
463 | 0 | inner |
464 | | } |
465 | | _ => { |
466 | 0 | return Err(cx.common.send_fatal_alert( |
467 | 0 | AlertDescription::IllegalParameter, |
468 | 0 | PeerMisbehaved::HandshakeHashVariedAfterRetry, |
469 | 0 | )); |
470 | | } |
471 | | }; |
472 | | |
473 | | // Save their Random. |
474 | 0 | let randoms = ConnectionRandoms::new( |
475 | 0 | client_hello.random, |
476 | 0 | Random::new(self.config.provider.secure_random)?, |
477 | | ); |
478 | 0 | match suite { |
479 | 0 | SupportedCipherSuite::Tls13(suite) => tls13::CompleteClientHelloHandling { |
480 | 0 | config: self.config, |
481 | 0 | transcript, |
482 | 0 | suite, |
483 | 0 | randoms, |
484 | 0 | done_retry: self.done_retry, |
485 | 0 | send_tickets: self.send_tickets, |
486 | 0 | extra_exts: self.extra_exts, |
487 | 0 | } |
488 | 0 | .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 | 0 | } |
511 | | |
512 | 0 | fn choose_suite_and_kx_group( |
513 | 0 | &self, |
514 | 0 | selected_version: ProtocolVersion, |
515 | 0 | sig_key_algorithm: SignatureAlgorithm, |
516 | 0 | protocol: Protocol, |
517 | 0 | client_groups: &[NamedGroup], |
518 | 0 | client_suites: &[CipherSuite], |
519 | 0 | ) -> Result<(SupportedCipherSuite, &'static dyn SupportedKxGroup), PeerIncompatible> { |
520 | | // Determine which `KeyExchangeAlgorithm`s are theoretically possible, based |
521 | | // on the offered and supported groups. |
522 | 0 | let mut ecdhe_possible = false; |
523 | 0 | let mut ffdhe_possible = false; |
524 | 0 | let mut ffdhe_offered = false; |
525 | 0 | let mut supported_groups = Vec::with_capacity(client_groups.len()); |
526 | | |
527 | 0 | for offered_group in client_groups { |
528 | 0 | let supported = self |
529 | 0 | .config |
530 | 0 | .provider |
531 | 0 | .kx_groups |
532 | 0 | .iter() |
533 | 0 | .find(|skxg| { |
534 | 0 | skxg.usable_for_version(selected_version) && skxg.name() == *offered_group |
535 | 0 | }); |
536 | | |
537 | 0 | match offered_group.key_exchange_algorithm() { |
538 | 0 | KeyExchangeAlgorithm::DHE => { |
539 | 0 | ffdhe_possible |= supported.is_some(); |
540 | 0 | ffdhe_offered = true; |
541 | 0 | } |
542 | 0 | KeyExchangeAlgorithm::ECDHE => { |
543 | 0 | ecdhe_possible |= supported.is_some(); |
544 | 0 | } |
545 | | } |
546 | | |
547 | 0 | supported_groups.push(supported); |
548 | | } |
549 | | |
550 | 0 | let first_supported_dhe_kxg = if selected_version == ProtocolVersion::TLSv1_2 { |
551 | | // https://datatracker.ietf.org/doc/html/rfc7919#section-4 (paragraph 2) |
552 | 0 | let first_supported_dhe_kxg = self |
553 | 0 | .config |
554 | 0 | .provider |
555 | 0 | .kx_groups |
556 | 0 | .iter() |
557 | 0 | .find(|skxg| skxg.name().key_exchange_algorithm() == KeyExchangeAlgorithm::DHE); |
558 | 0 | ffdhe_possible |= !ffdhe_offered && first_supported_dhe_kxg.is_some(); |
559 | 0 | first_supported_dhe_kxg |
560 | | } else { |
561 | | // In TLS1.3, the server may only directly negotiate a group. |
562 | 0 | None |
563 | | }; |
564 | | |
565 | 0 | if !ecdhe_possible && !ffdhe_possible { |
566 | 0 | return Err(PeerIncompatible::NoKxGroupsInCommon); |
567 | 0 | } |
568 | | |
569 | 0 | let mut suitable_suites_iter = self |
570 | 0 | .config |
571 | 0 | .provider |
572 | 0 | .cipher_suites |
573 | 0 | .iter() |
574 | 0 | .filter(|suite| { |
575 | | // Reduce our supported ciphersuites by the certified key's algorithm. |
576 | 0 | suite.usable_for_signature_algorithm(sig_key_algorithm) |
577 | | // And version |
578 | 0 | && suite.version().version == selected_version |
579 | | // And protocol |
580 | 0 | && suite.usable_for_protocol(protocol) |
581 | | // And support one of key exchange groups |
582 | 0 | && (ecdhe_possible && suite.usable_for_kx_algorithm(KeyExchangeAlgorithm::ECDHE) |
583 | 0 | || ffdhe_possible && suite.usable_for_kx_algorithm(KeyExchangeAlgorithm::DHE)) |
584 | 0 | }); |
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 | 0 | let suite = if self.config.ignore_client_order { |
593 | 0 | suitable_suites_iter.find(|suite| client_suites.contains(&suite.suite())) |
594 | | } else { |
595 | 0 | let suitable_suites = suitable_suites_iter.collect::<Vec<_>>(); |
596 | 0 | client_suites |
597 | 0 | .iter() |
598 | 0 | .find_map(|client_suite| { |
599 | 0 | suitable_suites |
600 | 0 | .iter() |
601 | 0 | .find(|x| *client_suite == x.suite()) |
602 | 0 | }) |
603 | 0 | .copied() |
604 | | } |
605 | 0 | .ok_or(PeerIncompatible::NoCipherSuitesInCommon)?; |
606 | | |
607 | | // Finally, choose a key exchange group that is compatible with the selected cipher |
608 | | // suite. |
609 | 0 | let maybe_skxg = supported_groups |
610 | 0 | .iter() |
611 | 0 | .find_map(|maybe_skxg| match maybe_skxg { |
612 | 0 | Some(skxg) => suite |
613 | 0 | .usable_for_kx_algorithm(skxg.name().key_exchange_algorithm()) |
614 | 0 | .then_some(*skxg), |
615 | 0 | None => None, |
616 | 0 | }); |
617 | | |
618 | 0 | if selected_version == ProtocolVersion::TLSv1_3 { |
619 | | // This unwrap is structurally guaranteed by the early return for `!ffdhe_possible && !ecdhe_possible` |
620 | 0 | return Ok((*suite, *maybe_skxg.unwrap())); |
621 | 0 | } |
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 | 0 | match maybe_skxg { |
626 | 0 | Some(skxg) => Ok((*suite, *skxg)), |
627 | 0 | 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 | 0 | if let Some(server_selected_ffdhe_skxg) = first_supported_dhe_kxg { |
631 | 0 | Ok((*suite, *server_selected_ffdhe_skxg)) |
632 | | } else { |
633 | 0 | Err(PeerIncompatible::NoKxGroupsInCommon) |
634 | | } |
635 | | } |
636 | 0 | None => Err(PeerIncompatible::NoKxGroupsInCommon), |
637 | | } |
638 | 0 | } |
639 | | } |
640 | | |
641 | | impl State<ServerConnectionData> for ExpectClientHello { |
642 | 0 | fn handle<'m>( |
643 | 0 | self: Box<Self>, |
644 | 0 | cx: &mut ServerContext<'_>, |
645 | 0 | m: Message<'m>, |
646 | 0 | ) -> NextStateOrError<'m> |
647 | 0 | where |
648 | 0 | Self: 'm, |
649 | | { |
650 | 0 | let (client_hello, sig_schemes) = process_client_hello(&m, self.done_retry, cx)?; |
651 | 0 | self.with_certified_key(sig_schemes, client_hello, &m, cx) |
652 | 0 | } |
653 | | |
654 | 0 | fn into_owned(self: Box<Self>) -> NextState<'static> { |
655 | 0 | self |
656 | 0 | } |
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 | 0 | pub(super) fn process_client_hello<'m>( |
669 | 0 | m: &'m Message<'m>, |
670 | 0 | done_retry: bool, |
671 | 0 | cx: &mut ServerContext<'_>, |
672 | 0 | ) -> Result<(&'m ClientHelloPayload, Vec<SignatureScheme>), Error> { |
673 | 0 | let client_hello = |
674 | 0 | require_handshake_msg!(m, HandshakeType::ClientHello, HandshakePayload::ClientHello)?; |
675 | 0 | trace!("we got a clienthello {:?}", client_hello); |
676 | | |
677 | 0 | if !client_hello |
678 | 0 | .compression_methods |
679 | 0 | .contains(&Compression::Null) |
680 | | { |
681 | 0 | return Err(cx.common.send_fatal_alert( |
682 | 0 | AlertDescription::IllegalParameter, |
683 | 0 | PeerIncompatible::NullCompressionRequired, |
684 | 0 | )); |
685 | 0 | } |
686 | | |
687 | 0 | if client_hello.has_duplicate_extension() { |
688 | 0 | return Err(cx.common.send_fatal_alert( |
689 | 0 | AlertDescription::DecodeError, |
690 | 0 | PeerMisbehaved::DuplicateClientHelloExtensions, |
691 | 0 | )); |
692 | 0 | } |
693 | | |
694 | | // No handshake messages should follow this one in this flight. |
695 | 0 | 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 | 0 | let sni: Option<DnsName<'_>> = match client_hello.sni_extension() { |
703 | 0 | Some(sni) => { |
704 | 0 | if sni.has_duplicate_names_for_type() { |
705 | 0 | return Err(cx.common.send_fatal_alert( |
706 | 0 | AlertDescription::DecodeError, |
707 | 0 | PeerMisbehaved::DuplicateServerNameTypes, |
708 | 0 | )); |
709 | 0 | } |
710 | | |
711 | 0 | if let Some(hostname) = sni.single_hostname() { |
712 | 0 | Some(hostname.to_lowercase_owned()) |
713 | | } else { |
714 | 0 | return Err(cx.common.send_fatal_alert( |
715 | 0 | AlertDescription::IllegalParameter, |
716 | 0 | PeerMisbehaved::ServerNameMustContainOneHostName, |
717 | 0 | )); |
718 | | } |
719 | | } |
720 | 0 | None => None, |
721 | | }; |
722 | | |
723 | | // save only the first SNI |
724 | 0 | if let (Some(sni), false) = (&sni, done_retry) { |
725 | | // Save the SNI into the session. |
726 | | // The SNI hostname is immutable once set. |
727 | 0 | assert!(cx.data.sni.is_none()); |
728 | 0 | cx.data.sni = Some(sni.clone()); |
729 | 0 | } else if cx.data.sni != sni { |
730 | 0 | return Err(PeerMisbehaved::ServerNameDifferedOnRetry.into()); |
731 | 0 | } |
732 | | |
733 | 0 | let sig_schemes = client_hello |
734 | 0 | .sigalgs_extension() |
735 | 0 | .ok_or_else(|| { |
736 | 0 | cx.common.send_fatal_alert( |
737 | 0 | AlertDescription::HandshakeFailure, |
738 | 0 | PeerIncompatible::SignatureAlgorithmsExtensionRequired, |
739 | | ) |
740 | 0 | })?; |
741 | | |
742 | 0 | Ok((client_hello, sig_schemes.to_owned())) |
743 | 0 | } |
744 | | |
745 | | pub(crate) enum HandshakeHashOrBuffer { |
746 | | Buffer(HandshakeHashBuffer), |
747 | | Hash(HandshakeHash), |
748 | | } |