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