| 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 | |