1 | use crate::common_state::State; |
2 | use crate::conn::ConnectionRandoms; |
3 | #[cfg (feature = "tls12" )] |
4 | use crate::enums::CipherSuite; |
5 | use crate::enums::{AlertDescription, HandshakeType, ProtocolVersion, SignatureScheme}; |
6 | use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; |
7 | use crate::hash_hs::{HandshakeHash, HandshakeHashBuffer}; |
8 | #[cfg (feature = "logging" )] |
9 | use crate::log::{debug, trace}; |
10 | use crate::msgs::enums::{Compression, ExtensionType}; |
11 | #[cfg (feature = "tls12" )] |
12 | use crate::msgs::handshake::SessionId; |
13 | use crate::msgs::handshake::{ClientHelloPayload, Random, ServerExtension}; |
14 | use crate::msgs::handshake::{ConvertProtocolNameList, ConvertServerNameList, HandshakePayload}; |
15 | use crate::msgs::message::{Message, MessagePayload}; |
16 | use crate::msgs::persist; |
17 | use crate::server::{ClientHello, ServerConfig}; |
18 | use crate::suites; |
19 | use crate::SupportedCipherSuite; |
20 | |
21 | use super::server_conn::ServerConnectionData; |
22 | #[cfg (feature = "tls12" )] |
23 | use super::tls12; |
24 | use crate::server::common::ActiveCertifiedKey; |
25 | use crate::server::tls13; |
26 | |
27 | use pki_types::DnsName; |
28 | |
29 | use alloc::borrow::ToOwned; |
30 | use alloc::boxed::Box; |
31 | use alloc::sync::Arc; |
32 | use alloc::vec::Vec; |
33 | |
34 | pub(super) type NextState = Box<dyn State<ServerConnectionData>>; |
35 | pub(super) type NextStateOrError = Result<NextState, 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.get_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(ref 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) iff 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.get_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.get_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.exts.extend(extra_exts); |
160 | |
161 | Ok(()) |
162 | } |
163 | |
164 | #[cfg (feature = "tls12" )] |
165 | pub(super) fn process_tls12( |
166 | &mut self, |
167 | config: &ServerConfig, |
168 | hello: &ClientHelloPayload, |
169 | using_ems: bool, |
170 | ) { |
171 | // Renegotiation. |
172 | // (We don't do reneg at all, but would support the secure version if we did.) |
173 | let secure_reneg_offered = hello |
174 | .find_extension(ExtensionType::RenegotiationInfo) |
175 | .is_some() |
176 | || hello |
177 | .cipher_suites |
178 | .contains(&CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV); |
179 | |
180 | if secure_reneg_offered { |
181 | self.exts |
182 | .push(ServerExtension::make_empty_renegotiation_info()); |
183 | } |
184 | |
185 | // Tickets: |
186 | // If we get any SessionTicket extension and have tickets enabled, |
187 | // we send an ack. |
188 | if hello |
189 | .find_extension(ExtensionType::SessionTicket) |
190 | .is_some() |
191 | && config.ticketer.enabled() |
192 | { |
193 | self.send_ticket = true; |
194 | self.exts |
195 | .push(ServerExtension::SessionTicketAck); |
196 | } |
197 | |
198 | // Confirm use of EMS if offered. |
199 | if using_ems { |
200 | self.exts |
201 | .push(ServerExtension::ExtendedMasterSecretAck); |
202 | } |
203 | } |
204 | } |
205 | |
206 | pub(super) struct ExpectClientHello { |
207 | pub(super) config: Arc<ServerConfig>, |
208 | pub(super) extra_exts: Vec<ServerExtension>, |
209 | pub(super) transcript: HandshakeHashOrBuffer, |
210 | #[cfg (feature = "tls12" )] |
211 | pub(super) session_id: SessionId, |
212 | #[cfg (feature = "tls12" )] |
213 | pub(super) using_ems: bool, |
214 | pub(super) done_retry: bool, |
215 | pub(super) send_tickets: usize, |
216 | } |
217 | |
218 | impl ExpectClientHello { |
219 | pub(super) fn new(config: Arc<ServerConfig>, extra_exts: Vec<ServerExtension>) -> Self { |
220 | let mut transcript_buffer = HandshakeHashBuffer::new(); |
221 | |
222 | if config.verifier.offer_client_auth() { |
223 | transcript_buffer.set_client_auth_enabled(); |
224 | } |
225 | |
226 | Self { |
227 | config, |
228 | extra_exts, |
229 | transcript: HandshakeHashOrBuffer::Buffer(transcript_buffer), |
230 | #[cfg (feature = "tls12" )] |
231 | session_id: SessionId::empty(), |
232 | #[cfg (feature = "tls12" )] |
233 | using_ems: false, |
234 | done_retry: false, |
235 | send_tickets: 0, |
236 | } |
237 | } |
238 | |
239 | /// Continues handling of a `ClientHello` message once config and certificate are available. |
240 | pub(super) fn with_certified_key( |
241 | self, |
242 | mut sig_schemes: Vec<SignatureScheme>, |
243 | client_hello: &ClientHelloPayload, |
244 | m: &Message, |
245 | cx: &mut ServerContext<'_>, |
246 | ) -> NextStateOrError { |
247 | let tls13_enabled = self |
248 | .config |
249 | .supports_version(ProtocolVersion::TLSv1_3); |
250 | let tls12_enabled = self |
251 | .config |
252 | .supports_version(ProtocolVersion::TLSv1_2); |
253 | |
254 | // Are we doing TLS1.3? |
255 | let maybe_versions_ext = client_hello.get_versions_extension(); |
256 | let version = if let Some(versions) = maybe_versions_ext { |
257 | if versions.contains(&ProtocolVersion::TLSv1_3) && tls13_enabled { |
258 | ProtocolVersion::TLSv1_3 |
259 | } else if !versions.contains(&ProtocolVersion::TLSv1_2) || !tls12_enabled { |
260 | return Err(cx.common.send_fatal_alert( |
261 | AlertDescription::ProtocolVersion, |
262 | PeerIncompatible::Tls12NotOfferedOrEnabled, |
263 | )); |
264 | } else if cx.common.is_quic() { |
265 | return Err(cx.common.send_fatal_alert( |
266 | AlertDescription::ProtocolVersion, |
267 | PeerIncompatible::Tls13RequiredForQuic, |
268 | )); |
269 | } else { |
270 | ProtocolVersion::TLSv1_2 |
271 | } |
272 | } else if client_hello.client_version.get_u16() < ProtocolVersion::TLSv1_2.get_u16() { |
273 | return Err(cx.common.send_fatal_alert( |
274 | AlertDescription::ProtocolVersion, |
275 | PeerIncompatible::Tls12NotOffered, |
276 | )); |
277 | } else if !tls12_enabled && tls13_enabled { |
278 | return Err(cx.common.send_fatal_alert( |
279 | AlertDescription::ProtocolVersion, |
280 | PeerIncompatible::SupportedVersionsExtensionRequired, |
281 | )); |
282 | } else if cx.common.is_quic() { |
283 | return Err(cx.common.send_fatal_alert( |
284 | AlertDescription::ProtocolVersion, |
285 | PeerIncompatible::Tls13RequiredForQuic, |
286 | )); |
287 | } else { |
288 | ProtocolVersion::TLSv1_2 |
289 | }; |
290 | |
291 | cx.common.negotiated_version = Some(version); |
292 | |
293 | // We communicate to the upper layer what kind of key they should choose |
294 | // via the sigschemes value. Clients tend to treat this extension |
295 | // orthogonally to offered ciphersuites (even though, in TLS1.2 it is not). |
296 | // So: reduce the offered sigschemes to those compatible with the |
297 | // intersection of ciphersuites. |
298 | let client_suites = self |
299 | .config |
300 | .provider |
301 | .cipher_suites |
302 | .iter() |
303 | .copied() |
304 | .filter(|scs| { |
305 | client_hello |
306 | .cipher_suites |
307 | .contains(&scs.suite()) |
308 | }) |
309 | .collect::<Vec<_>>(); |
310 | |
311 | sig_schemes |
312 | .retain(|scheme| suites::compatible_sigscheme_for_suites(*scheme, &client_suites)); |
313 | |
314 | // Choose a certificate. |
315 | let certkey = { |
316 | let client_hello = ClientHello::new( |
317 | &cx.data.sni, |
318 | &sig_schemes, |
319 | client_hello.get_alpn_extension(), |
320 | &client_hello.cipher_suites, |
321 | ); |
322 | |
323 | let certkey = self |
324 | .config |
325 | .cert_resolver |
326 | .resolve(client_hello); |
327 | |
328 | certkey.ok_or_else(|| { |
329 | cx.common.send_fatal_alert( |
330 | AlertDescription::AccessDenied, |
331 | Error::General("no server certificate chain resolved" .to_owned()), |
332 | ) |
333 | })? |
334 | }; |
335 | let certkey = ActiveCertifiedKey::from_certified_key(&certkey); |
336 | |
337 | // Reduce our supported ciphersuites by the certificate. |
338 | // (no-op for TLS1.3) |
339 | let suitable_suites = suites::reduce_given_sigalg( |
340 | &self.config.provider.cipher_suites, |
341 | certkey.get_key().algorithm(), |
342 | ); |
343 | |
344 | // And version |
345 | let suitable_suites = suites::reduce_given_version_and_protocol( |
346 | &suitable_suites, |
347 | version, |
348 | cx.common.protocol, |
349 | ); |
350 | |
351 | let suite = if self.config.ignore_client_order { |
352 | suites::choose_ciphersuite_preferring_server( |
353 | &client_hello.cipher_suites, |
354 | &suitable_suites, |
355 | ) |
356 | } else { |
357 | suites::choose_ciphersuite_preferring_client( |
358 | &client_hello.cipher_suites, |
359 | &suitable_suites, |
360 | ) |
361 | } |
362 | .ok_or_else(|| { |
363 | cx.common.send_fatal_alert( |
364 | AlertDescription::HandshakeFailure, |
365 | PeerIncompatible::NoCipherSuitesInCommon, |
366 | ) |
367 | })?; |
368 | |
369 | debug!("decided upon suite {:?}" , suite); |
370 | cx.common.suite = Some(suite); |
371 | |
372 | // Start handshake hash. |
373 | let starting_hash = suite.hash_provider(); |
374 | let transcript = match self.transcript { |
375 | HandshakeHashOrBuffer::Buffer(inner) => inner.start_hash(starting_hash), |
376 | HandshakeHashOrBuffer::Hash(inner) |
377 | if inner.algorithm() == starting_hash.algorithm() => |
378 | { |
379 | inner |
380 | } |
381 | _ => { |
382 | return Err(cx.common.send_fatal_alert( |
383 | AlertDescription::IllegalParameter, |
384 | PeerMisbehaved::HandshakeHashVariedAfterRetry, |
385 | )); |
386 | } |
387 | }; |
388 | |
389 | // Save their Random. |
390 | let randoms = ConnectionRandoms::new( |
391 | client_hello.random, |
392 | Random::new(self.config.provider.secure_random)?, |
393 | ); |
394 | match suite { |
395 | SupportedCipherSuite::Tls13(suite) => tls13::CompleteClientHelloHandling { |
396 | config: self.config, |
397 | transcript, |
398 | suite, |
399 | randoms, |
400 | done_retry: self.done_retry, |
401 | send_tickets: self.send_tickets, |
402 | extra_exts: self.extra_exts, |
403 | } |
404 | .handle_client_hello(cx, certkey, m, client_hello, sig_schemes), |
405 | #[cfg (feature = "tls12" )] |
406 | SupportedCipherSuite::Tls12(suite) => tls12::CompleteClientHelloHandling { |
407 | config: self.config, |
408 | transcript, |
409 | session_id: self.session_id, |
410 | suite, |
411 | using_ems: self.using_ems, |
412 | randoms, |
413 | send_ticket: self.send_tickets > 0, |
414 | extra_exts: self.extra_exts, |
415 | } |
416 | .handle_client_hello( |
417 | cx, |
418 | certkey, |
419 | m, |
420 | client_hello, |
421 | sig_schemes, |
422 | tls13_enabled, |
423 | ), |
424 | } |
425 | } |
426 | } |
427 | |
428 | impl State<ServerConnectionData> for ExpectClientHello { |
429 | fn handle(self: Box<Self>, cx: &mut ServerContext<'_>, m: Message) -> NextStateOrError { |
430 | let (client_hello: &ClientHelloPayload, sig_schemes: Vec) = process_client_hello(&m, self.done_retry, cx)?; |
431 | self.with_certified_key(sig_schemes, client_hello, &m, cx) |
432 | } |
433 | } |
434 | |
435 | /// Configuration-independent validation of a `ClientHello` message. |
436 | /// |
437 | /// This represents the first part of the `ClientHello` handling, where we do all validation that |
438 | /// doesn't depend on a `ServerConfig` being available and extract everything needed to build a |
439 | /// [`ClientHello`] value for a [`ResolvesServerCert`]. |
440 | /// |
441 | /// Note that this will modify `data.sni` even if config or certificate resolution fail. |
442 | /// |
443 | /// [`ResolvesServerCert`]: crate::server::ResolvesServerCert |
444 | pub(super) fn process_client_hello<'a>( |
445 | m: &'a Message, |
446 | done_retry: bool, |
447 | cx: &mut ServerContext, |
448 | ) -> Result<(&'a ClientHelloPayload, Vec<SignatureScheme>), Error> { |
449 | let client_hello = |
450 | require_handshake_msg!(m, HandshakeType::ClientHello, HandshakePayload::ClientHello)?; |
451 | trace!("we got a clienthello {:?}" , client_hello); |
452 | |
453 | if !client_hello |
454 | .compression_methods |
455 | .contains(&Compression::Null) |
456 | { |
457 | return Err(cx.common.send_fatal_alert( |
458 | AlertDescription::IllegalParameter, |
459 | PeerIncompatible::NullCompressionRequired, |
460 | )); |
461 | } |
462 | |
463 | if client_hello.has_duplicate_extension() { |
464 | return Err(cx.common.send_fatal_alert( |
465 | AlertDescription::DecodeError, |
466 | PeerMisbehaved::DuplicateClientHelloExtensions, |
467 | )); |
468 | } |
469 | |
470 | // No handshake messages should follow this one in this flight. |
471 | cx.common.check_aligned_handshake()?; |
472 | |
473 | // Extract and validate the SNI DNS name, if any, before giving it to |
474 | // the cert resolver. In particular, if it is invalid then we should |
475 | // send an Illegal Parameter alert instead of the Internal Error alert |
476 | // (or whatever) that we'd send if this were checked later or in a |
477 | // different way. |
478 | let sni: Option<DnsName> = match client_hello.get_sni_extension() { |
479 | Some(sni) => { |
480 | if sni.has_duplicate_names_for_type() { |
481 | return Err(cx.common.send_fatal_alert( |
482 | AlertDescription::DecodeError, |
483 | PeerMisbehaved::DuplicateServerNameTypes, |
484 | )); |
485 | } |
486 | |
487 | if let Some(hostname) = sni.get_single_hostname() { |
488 | Some(hostname.to_lowercase_owned()) |
489 | } else { |
490 | return Err(cx.common.send_fatal_alert( |
491 | AlertDescription::IllegalParameter, |
492 | PeerMisbehaved::ServerNameMustContainOneHostName, |
493 | )); |
494 | } |
495 | } |
496 | None => None, |
497 | }; |
498 | |
499 | // save only the first SNI |
500 | if let (Some(sni), false) = (&sni, done_retry) { |
501 | // Save the SNI into the session. |
502 | // The SNI hostname is immutable once set. |
503 | assert!(cx.data.sni.is_none()); |
504 | cx.data.sni = Some(sni.clone()); |
505 | } else if cx.data.sni != sni { |
506 | return Err(PeerMisbehaved::ServerNameDifferedOnRetry.into()); |
507 | } |
508 | |
509 | let sig_schemes = client_hello |
510 | .get_sigalgs_extension() |
511 | .ok_or_else(|| { |
512 | cx.common.send_fatal_alert( |
513 | AlertDescription::HandshakeFailure, |
514 | PeerIncompatible::SignatureAlgorithmsExtensionRequired, |
515 | ) |
516 | })?; |
517 | |
518 | Ok((client_hello, sig_schemes.to_owned())) |
519 | } |
520 | |
521 | #[allow (clippy::large_enum_variant)] |
522 | pub(crate) enum HandshakeHashOrBuffer { |
523 | Buffer(HandshakeHashBuffer), |
524 | Hash(HandshakeHash), |
525 | } |
526 | |