/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-0.23.35/src/server/tls12.rs
Line | Count | Source |
1 | | use alloc::boxed::Box; |
2 | | use alloc::string::ToString; |
3 | | use alloc::vec; |
4 | | use alloc::vec::Vec; |
5 | | |
6 | | pub(super) use client_hello::CompleteClientHelloHandling; |
7 | | use pki_types::UnixTime; |
8 | | use subtle::ConstantTimeEq; |
9 | | |
10 | | use super::common::ActiveCertifiedKey; |
11 | | use super::hs::{self, ServerContext}; |
12 | | use super::server_conn::{ProducesTickets, ServerConfig, ServerConnectionData}; |
13 | | use crate::check::inappropriate_message; |
14 | | use crate::common_state::{CommonState, HandshakeFlightTls12, HandshakeKind, Side, State}; |
15 | | use crate::conn::ConnectionRandoms; |
16 | | use crate::conn::kernel::{Direction, KernelContext, KernelState}; |
17 | | use crate::crypto::ActiveKeyExchange; |
18 | | use crate::enums::{AlertDescription, ContentType, HandshakeType, ProtocolVersion}; |
19 | | use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; |
20 | | use crate::hash_hs::HandshakeHash; |
21 | | use crate::log::{debug, trace}; |
22 | | use crate::msgs::base::Payload; |
23 | | use crate::msgs::ccs::ChangeCipherSpecPayload; |
24 | | use crate::msgs::codec::Codec; |
25 | | use crate::msgs::handshake::{ |
26 | | CertificateChain, ClientKeyExchangeParams, HandshakeMessagePayload, HandshakePayload, |
27 | | NewSessionTicketPayload, NewSessionTicketPayloadTls13, SessionId, |
28 | | }; |
29 | | use crate::msgs::message::{Message, MessagePayload}; |
30 | | use crate::msgs::persist; |
31 | | use crate::suites::PartiallyExtractedSecrets; |
32 | | use crate::sync::Arc; |
33 | | use crate::tls12::{self, ConnectionSecrets, Tls12CipherSuite}; |
34 | | use crate::{ConnectionTrafficSecrets, verify}; |
35 | | |
36 | | mod client_hello { |
37 | | use pki_types::CertificateDer; |
38 | | |
39 | | use super::*; |
40 | | use crate::common_state::KxState; |
41 | | use crate::crypto::SupportedKxGroup; |
42 | | use crate::enums::SignatureScheme; |
43 | | use crate::msgs::enums::{ClientCertificateType, Compression}; |
44 | | use crate::msgs::handshake::{ |
45 | | CertificateRequestPayload, CertificateStatus, ClientHelloPayload, ClientSessionTicket, |
46 | | Random, ServerExtensionsInput, ServerHelloPayload, ServerKeyExchange, |
47 | | ServerKeyExchangeParams, ServerKeyExchangePayload, |
48 | | }; |
49 | | use crate::sign; |
50 | | use crate::verify::DigitallySignedStruct; |
51 | | |
52 | | pub(in crate::server) struct CompleteClientHelloHandling { |
53 | | pub(in crate::server) config: Arc<ServerConfig>, |
54 | | pub(in crate::server) transcript: HandshakeHash, |
55 | | pub(in crate::server) session_id: SessionId, |
56 | | pub(in crate::server) suite: &'static Tls12CipherSuite, |
57 | | pub(in crate::server) using_ems: bool, |
58 | | pub(in crate::server) randoms: ConnectionRandoms, |
59 | | pub(in crate::server) send_ticket: bool, |
60 | | pub(in crate::server) extra_exts: ServerExtensionsInput<'static>, |
61 | | } |
62 | | |
63 | | impl CompleteClientHelloHandling { |
64 | 0 | pub(in crate::server) fn handle_client_hello( |
65 | 0 | mut self, |
66 | 0 | cx: &mut ServerContext<'_>, |
67 | 0 | server_key: ActiveCertifiedKey<'_>, |
68 | 0 | chm: &Message<'_>, |
69 | 0 | client_hello: &ClientHelloPayload, |
70 | 0 | selected_kxg: &'static dyn SupportedKxGroup, |
71 | 0 | sigschemes_ext: Vec<SignatureScheme>, |
72 | 0 | tls13_enabled: bool, |
73 | 0 | ) -> hs::NextStateOrError<'static> { |
74 | | // -- TLS1.2 only from hereon in -- |
75 | 0 | self.transcript.add_message(chm); |
76 | | |
77 | 0 | if client_hello |
78 | 0 | .extended_master_secret_request |
79 | 0 | .is_some() |
80 | 0 | { |
81 | 0 | self.using_ems = true; |
82 | 0 | } else if self.config.require_ems { |
83 | 0 | return Err(cx.common.send_fatal_alert( |
84 | 0 | AlertDescription::HandshakeFailure, |
85 | 0 | PeerIncompatible::ExtendedMasterSecretExtensionRequired, |
86 | 0 | )); |
87 | 0 | } |
88 | | |
89 | | // "RFC 4492 specified that if this extension is missing, |
90 | | // it means that only the uncompressed point format is |
91 | | // supported" |
92 | | // - <https://datatracker.ietf.org/doc/html/rfc8422#section-5.1.2> |
93 | 0 | let supported_ec_point_formats = client_hello |
94 | 0 | .ec_point_formats |
95 | 0 | .unwrap_or_default(); |
96 | | |
97 | 0 | trace!("ecpoints {supported_ec_point_formats:?}"); |
98 | | |
99 | 0 | if !supported_ec_point_formats.uncompressed { |
100 | 0 | return Err(cx.common.send_fatal_alert( |
101 | 0 | AlertDescription::IllegalParameter, |
102 | 0 | PeerIncompatible::UncompressedEcPointsRequired, |
103 | 0 | )); |
104 | 0 | } |
105 | | |
106 | | // -- If TLS1.3 is enabled, signal the downgrade in the server random |
107 | 0 | if tls13_enabled { |
108 | 0 | self.randoms.server[24..].copy_from_slice(&tls12::DOWNGRADE_SENTINEL); |
109 | 0 | } |
110 | | |
111 | | // -- Check for resumption -- |
112 | | // We can do this either by (in order of preference): |
113 | | // 1. receiving a ticket that decrypts |
114 | | // 2. receiving a sessionid that is in our cache |
115 | | // |
116 | | // If we receive a ticket, the sessionid won't be in our |
117 | | // cache, so don't check. |
118 | | // |
119 | | // If either works, we end up with a ServerConnectionValue |
120 | | // which is passed to start_resumption and concludes |
121 | | // our handling of the ClientHello. |
122 | | // |
123 | 0 | let mut ticket_received = false; |
124 | 0 | let resume_data = client_hello |
125 | 0 | .session_ticket |
126 | 0 | .as_ref() |
127 | 0 | .and_then(|ticket_ext| match ticket_ext { |
128 | 0 | ClientSessionTicket::Offer(ticket) => Some(ticket), |
129 | 0 | _ => None, |
130 | 0 | }) |
131 | 0 | .and_then(|ticket| { |
132 | 0 | ticket_received = true; |
133 | 0 | debug!("Ticket received"); |
134 | 0 | let data = self |
135 | 0 | .config |
136 | 0 | .ticketer |
137 | 0 | .decrypt(ticket.bytes()); |
138 | 0 | if data.is_none() { |
139 | 0 | debug!("Ticket didn't decrypt"); |
140 | 0 | } |
141 | 0 | data |
142 | 0 | }) |
143 | 0 | .or_else(|| { |
144 | | // Perhaps resume? If we received a ticket, the sessionid |
145 | | // does not correspond to a real session. |
146 | 0 | if client_hello.session_id.is_empty() || ticket_received { |
147 | 0 | return None; |
148 | 0 | } |
149 | | |
150 | 0 | self.config |
151 | 0 | .session_storage |
152 | 0 | .get(client_hello.session_id.as_ref()) |
153 | 0 | }) |
154 | 0 | .and_then(|x| persist::ServerSessionValue::read_bytes(&x).ok()) |
155 | 0 | .filter(|resumedata| { |
156 | 0 | hs::can_resume(self.suite.into(), &cx.data.sni, self.using_ems, resumedata) |
157 | 0 | }); |
158 | | |
159 | 0 | if let Some(data) = resume_data { |
160 | 0 | return self.start_resumption(cx, client_hello, &client_hello.session_id, data); |
161 | 0 | } |
162 | | |
163 | | // Now we have chosen a ciphersuite, we can make kx decisions. |
164 | 0 | let sigschemes = self |
165 | 0 | .suite |
166 | 0 | .resolve_sig_schemes(&sigschemes_ext); |
167 | | |
168 | 0 | if sigschemes.is_empty() { |
169 | 0 | return Err(cx.common.send_fatal_alert( |
170 | 0 | AlertDescription::HandshakeFailure, |
171 | 0 | PeerIncompatible::NoSignatureSchemesInCommon, |
172 | 0 | )); |
173 | 0 | } |
174 | | |
175 | 0 | let mut ocsp_response = server_key.get_ocsp(); |
176 | | |
177 | | // If we're not offered a ticket or a potential session ID, allocate a session ID. |
178 | 0 | if !self.config.session_storage.can_cache() { |
179 | 0 | self.session_id = SessionId::empty(); |
180 | 0 | } else if self.session_id.is_empty() && !ticket_received { |
181 | 0 | self.session_id = SessionId::random(self.config.provider.secure_random)?; |
182 | 0 | } |
183 | | |
184 | 0 | cx.common.kx_state = KxState::Start(selected_kxg); |
185 | 0 | cx.common.handshake_kind = Some(HandshakeKind::Full); |
186 | | |
187 | 0 | let mut flight = HandshakeFlightTls12::new(&mut self.transcript); |
188 | | |
189 | 0 | self.send_ticket = emit_server_hello( |
190 | 0 | &mut flight, |
191 | 0 | &self.config, |
192 | 0 | cx, |
193 | 0 | self.session_id, |
194 | 0 | self.suite, |
195 | 0 | self.using_ems, |
196 | 0 | &mut ocsp_response, |
197 | 0 | client_hello, |
198 | 0 | None, |
199 | 0 | &self.randoms, |
200 | 0 | self.extra_exts, |
201 | 0 | )?; |
202 | 0 | emit_certificate(&mut flight, server_key.get_cert()); |
203 | 0 | if let Some(ocsp_response) = ocsp_response { |
204 | 0 | emit_cert_status(&mut flight, ocsp_response); |
205 | 0 | } |
206 | 0 | let server_kx = emit_server_kx( |
207 | 0 | &mut flight, |
208 | 0 | sigschemes, |
209 | 0 | selected_kxg, |
210 | 0 | server_key.get_key(), |
211 | 0 | &self.randoms, |
212 | 0 | )?; |
213 | 0 | let doing_client_auth = emit_certificate_req(&mut flight, &self.config)?; |
214 | 0 | emit_server_hello_done(&mut flight); |
215 | | |
216 | 0 | flight.finish(cx.common); |
217 | | |
218 | 0 | if doing_client_auth { |
219 | 0 | Ok(Box::new(ExpectCertificate { |
220 | 0 | config: self.config, |
221 | 0 | transcript: self.transcript, |
222 | 0 | randoms: self.randoms, |
223 | 0 | session_id: self.session_id, |
224 | 0 | suite: self.suite, |
225 | 0 | using_ems: self.using_ems, |
226 | 0 | server_kx, |
227 | 0 | send_ticket: self.send_ticket, |
228 | 0 | })) |
229 | | } else { |
230 | 0 | Ok(Box::new(ExpectClientKx { |
231 | 0 | config: self.config, |
232 | 0 | transcript: self.transcript, |
233 | 0 | randoms: self.randoms, |
234 | 0 | session_id: self.session_id, |
235 | 0 | suite: self.suite, |
236 | 0 | using_ems: self.using_ems, |
237 | 0 | server_kx, |
238 | 0 | client_cert: None, |
239 | 0 | send_ticket: self.send_ticket, |
240 | 0 | })) |
241 | | } |
242 | 0 | } |
243 | | |
244 | 0 | fn start_resumption( |
245 | 0 | mut self, |
246 | 0 | cx: &mut ServerContext<'_>, |
247 | 0 | client_hello: &ClientHelloPayload, |
248 | 0 | id: &SessionId, |
249 | 0 | resumedata: persist::ServerSessionValue, |
250 | 0 | ) -> hs::NextStateOrError<'static> { |
251 | 0 | debug!("Resuming connection"); |
252 | | |
253 | 0 | if resumedata.extended_ms && !self.using_ems { |
254 | 0 | return Err(cx.common.send_fatal_alert( |
255 | 0 | AlertDescription::IllegalParameter, |
256 | 0 | PeerMisbehaved::ResumptionAttemptedWithVariedEms, |
257 | 0 | )); |
258 | 0 | } |
259 | | |
260 | 0 | self.session_id = *id; |
261 | 0 | let mut flight = HandshakeFlightTls12::new(&mut self.transcript); |
262 | 0 | self.send_ticket = emit_server_hello( |
263 | 0 | &mut flight, |
264 | 0 | &self.config, |
265 | 0 | cx, |
266 | 0 | self.session_id, |
267 | 0 | self.suite, |
268 | 0 | self.using_ems, |
269 | 0 | &mut None, |
270 | 0 | client_hello, |
271 | 0 | Some(&resumedata), |
272 | 0 | &self.randoms, |
273 | 0 | self.extra_exts, |
274 | 0 | )?; |
275 | 0 | flight.finish(cx.common); |
276 | | |
277 | 0 | let secrets = ConnectionSecrets::new_resume( |
278 | 0 | self.randoms, |
279 | 0 | self.suite, |
280 | 0 | &resumedata.master_secret.0, |
281 | | ); |
282 | 0 | self.config.key_log.log( |
283 | 0 | "CLIENT_RANDOM", |
284 | 0 | &secrets.randoms.client, |
285 | 0 | &secrets.master_secret, |
286 | 0 | ); |
287 | 0 | cx.common |
288 | 0 | .start_encryption_tls12(&secrets, Side::Server); |
289 | 0 | cx.common.peer_certificates = resumedata.client_cert_chain; |
290 | 0 | cx.common.handshake_kind = Some(HandshakeKind::Resumed); |
291 | | |
292 | 0 | if self.send_ticket { |
293 | 0 | let now = self.config.current_time()?; |
294 | | |
295 | 0 | emit_ticket( |
296 | 0 | &secrets, |
297 | 0 | &mut self.transcript, |
298 | 0 | self.using_ems, |
299 | 0 | cx, |
300 | 0 | &*self.config.ticketer, |
301 | 0 | now, |
302 | 0 | )?; |
303 | 0 | } |
304 | 0 | emit_ccs(cx.common); |
305 | 0 | cx.common |
306 | 0 | .record_layer |
307 | 0 | .start_encrypting(); |
308 | 0 | emit_finished(&secrets, &mut self.transcript, cx.common); |
309 | | |
310 | 0 | Ok(Box::new(ExpectCcs { |
311 | 0 | config: self.config, |
312 | 0 | secrets, |
313 | 0 | transcript: self.transcript, |
314 | 0 | session_id: self.session_id, |
315 | 0 | using_ems: self.using_ems, |
316 | 0 | resuming: true, |
317 | 0 | send_ticket: self.send_ticket, |
318 | 0 | })) |
319 | 0 | } |
320 | | } |
321 | | |
322 | 0 | fn emit_server_hello( |
323 | 0 | flight: &mut HandshakeFlightTls12<'_>, |
324 | 0 | config: &ServerConfig, |
325 | 0 | cx: &mut ServerContext<'_>, |
326 | 0 | session_id: SessionId, |
327 | 0 | suite: &'static Tls12CipherSuite, |
328 | 0 | using_ems: bool, |
329 | 0 | ocsp_response: &mut Option<&[u8]>, |
330 | 0 | hello: &ClientHelloPayload, |
331 | 0 | resumedata: Option<&persist::ServerSessionValue>, |
332 | 0 | randoms: &ConnectionRandoms, |
333 | 0 | extra_exts: ServerExtensionsInput<'static>, |
334 | 0 | ) -> Result<bool, Error> { |
335 | 0 | let mut ep = hs::ExtensionProcessing::new(extra_exts); |
336 | 0 | ep.process_common(config, cx, ocsp_response, hello, resumedata)?; |
337 | 0 | ep.process_tls12(config, hello, using_ems); |
338 | | |
339 | 0 | let sh = HandshakeMessagePayload(HandshakePayload::ServerHello(ServerHelloPayload { |
340 | 0 | legacy_version: ProtocolVersion::TLSv1_2, |
341 | 0 | random: Random::from(randoms.server), |
342 | 0 | session_id, |
343 | 0 | cipher_suite: suite.common.suite, |
344 | 0 | compression_method: Compression::Null, |
345 | 0 | extensions: ep.extensions, |
346 | 0 | })); |
347 | 0 | trace!("sending server hello {sh:?}"); |
348 | 0 | flight.add(sh); |
349 | | |
350 | 0 | Ok(ep.send_ticket) |
351 | 0 | } |
352 | | |
353 | 0 | fn emit_certificate( |
354 | 0 | flight: &mut HandshakeFlightTls12<'_>, |
355 | 0 | cert_chain: &[CertificateDer<'static>], |
356 | 0 | ) { |
357 | 0 | flight.add(HandshakeMessagePayload(HandshakePayload::Certificate( |
358 | 0 | CertificateChain(cert_chain.to_vec()), |
359 | 0 | ))); |
360 | 0 | } |
361 | | |
362 | 0 | fn emit_cert_status(flight: &mut HandshakeFlightTls12<'_>, ocsp: &[u8]) { |
363 | 0 | flight.add(HandshakeMessagePayload( |
364 | 0 | HandshakePayload::CertificateStatus(CertificateStatus::new(ocsp)), |
365 | 0 | )); |
366 | 0 | } |
367 | | |
368 | 0 | fn emit_server_kx( |
369 | 0 | flight: &mut HandshakeFlightTls12<'_>, |
370 | 0 | sigschemes: Vec<SignatureScheme>, |
371 | 0 | selected_group: &'static dyn SupportedKxGroup, |
372 | 0 | signing_key: &dyn sign::SigningKey, |
373 | 0 | randoms: &ConnectionRandoms, |
374 | 0 | ) -> Result<Box<dyn ActiveKeyExchange>, Error> { |
375 | 0 | let kx = selected_group.start()?; |
376 | 0 | let kx_params = ServerKeyExchangeParams::new(&*kx); |
377 | | |
378 | 0 | let mut msg = Vec::new(); |
379 | 0 | msg.extend(randoms.client); |
380 | 0 | msg.extend(randoms.server); |
381 | 0 | kx_params.encode(&mut msg); |
382 | | |
383 | 0 | let signer = signing_key |
384 | 0 | .choose_scheme(&sigschemes) |
385 | 0 | .ok_or_else(|| Error::General("incompatible signing key".to_string()))?; |
386 | 0 | let sigscheme = signer.scheme(); |
387 | 0 | let sig = signer.sign(&msg)?; |
388 | | |
389 | 0 | let skx = ServerKeyExchangePayload::from(ServerKeyExchange { |
390 | 0 | params: kx_params, |
391 | 0 | dss: DigitallySignedStruct::new(sigscheme, sig), |
392 | 0 | }); |
393 | | |
394 | 0 | flight.add(HandshakeMessagePayload( |
395 | 0 | HandshakePayload::ServerKeyExchange(skx), |
396 | 0 | )); |
397 | 0 | Ok(kx) |
398 | 0 | } |
399 | | |
400 | 0 | fn emit_certificate_req( |
401 | 0 | flight: &mut HandshakeFlightTls12<'_>, |
402 | 0 | config: &ServerConfig, |
403 | 0 | ) -> Result<bool, Error> { |
404 | 0 | let client_auth = &config.verifier; |
405 | | |
406 | 0 | if !client_auth.offer_client_auth() { |
407 | 0 | return Ok(false); |
408 | 0 | } |
409 | | |
410 | 0 | let verify_schemes = client_auth.supported_verify_schemes(); |
411 | | |
412 | 0 | let names = config |
413 | 0 | .verifier |
414 | 0 | .root_hint_subjects() |
415 | 0 | .to_vec(); |
416 | | |
417 | 0 | let cr = CertificateRequestPayload { |
418 | 0 | certtypes: vec![ |
419 | 0 | ClientCertificateType::RSASign, |
420 | 0 | ClientCertificateType::ECDSASign, |
421 | 0 | ], |
422 | 0 | sigschemes: verify_schemes, |
423 | 0 | canames: names, |
424 | 0 | }; |
425 | | |
426 | 0 | let creq = HandshakeMessagePayload(HandshakePayload::CertificateRequest(cr)); |
427 | | |
428 | 0 | trace!("Sending CertificateRequest {creq:?}"); |
429 | 0 | flight.add(creq); |
430 | 0 | Ok(true) |
431 | 0 | } |
432 | | |
433 | 0 | fn emit_server_hello_done(flight: &mut HandshakeFlightTls12<'_>) { |
434 | 0 | flight.add(HandshakeMessagePayload(HandshakePayload::ServerHelloDone)); |
435 | 0 | } |
436 | | } |
437 | | |
438 | | // --- Process client's Certificate for client auth --- |
439 | | struct ExpectCertificate { |
440 | | config: Arc<ServerConfig>, |
441 | | transcript: HandshakeHash, |
442 | | randoms: ConnectionRandoms, |
443 | | session_id: SessionId, |
444 | | suite: &'static Tls12CipherSuite, |
445 | | using_ems: bool, |
446 | | server_kx: Box<dyn ActiveKeyExchange>, |
447 | | send_ticket: bool, |
448 | | } |
449 | | |
450 | | impl State<ServerConnectionData> for ExpectCertificate { |
451 | 0 | fn handle<'m>( |
452 | 0 | mut self: Box<Self>, |
453 | 0 | cx: &mut ServerContext<'_>, |
454 | 0 | m: Message<'m>, |
455 | 0 | ) -> hs::NextStateOrError<'m> |
456 | 0 | where |
457 | 0 | Self: 'm, |
458 | | { |
459 | 0 | self.transcript.add_message(&m); |
460 | 0 | let cert_chain = require_handshake_msg_move!( |
461 | | m, |
462 | | HandshakeType::Certificate, |
463 | | HandshakePayload::Certificate |
464 | 0 | )?; |
465 | | |
466 | | // If we can't determine if the auth is mandatory, abort |
467 | 0 | let mandatory = self |
468 | 0 | .config |
469 | 0 | .verifier |
470 | 0 | .client_auth_mandatory(); |
471 | | |
472 | 0 | trace!("certs {cert_chain:?}"); |
473 | | |
474 | 0 | let client_cert = match cert_chain.split_first() { |
475 | 0 | None if mandatory => { |
476 | 0 | return Err(cx.common.send_fatal_alert( |
477 | 0 | AlertDescription::CertificateRequired, |
478 | 0 | Error::NoCertificatesPresented, |
479 | 0 | )); |
480 | | } |
481 | | None => { |
482 | 0 | debug!("client auth requested but no certificate supplied"); |
483 | 0 | self.transcript.abandon_client_auth(); |
484 | 0 | None |
485 | | } |
486 | 0 | Some((end_entity, intermediates)) => { |
487 | 0 | let now = self.config.current_time()?; |
488 | | |
489 | 0 | self.config |
490 | 0 | .verifier |
491 | 0 | .verify_client_cert(end_entity, intermediates, now) |
492 | 0 | .map_err(|err| { |
493 | 0 | cx.common |
494 | 0 | .send_cert_verify_error_alert(err) |
495 | 0 | })?; |
496 | | |
497 | 0 | Some(cert_chain) |
498 | | } |
499 | | }; |
500 | | |
501 | 0 | Ok(Box::new(ExpectClientKx { |
502 | 0 | config: self.config, |
503 | 0 | transcript: self.transcript, |
504 | 0 | randoms: self.randoms, |
505 | 0 | session_id: self.session_id, |
506 | 0 | suite: self.suite, |
507 | 0 | using_ems: self.using_ems, |
508 | 0 | server_kx: self.server_kx, |
509 | 0 | client_cert, |
510 | 0 | send_ticket: self.send_ticket, |
511 | 0 | })) |
512 | 0 | } |
513 | | |
514 | 0 | fn into_owned(self: Box<Self>) -> hs::NextState<'static> { |
515 | 0 | self |
516 | 0 | } |
517 | | } |
518 | | |
519 | | // --- Process client's KeyExchange --- |
520 | | struct ExpectClientKx<'a> { |
521 | | config: Arc<ServerConfig>, |
522 | | transcript: HandshakeHash, |
523 | | randoms: ConnectionRandoms, |
524 | | session_id: SessionId, |
525 | | suite: &'static Tls12CipherSuite, |
526 | | using_ems: bool, |
527 | | server_kx: Box<dyn ActiveKeyExchange>, |
528 | | client_cert: Option<CertificateChain<'a>>, |
529 | | send_ticket: bool, |
530 | | } |
531 | | |
532 | | impl State<ServerConnectionData> for ExpectClientKx<'_> { |
533 | 0 | fn handle<'m>( |
534 | 0 | mut self: Box<Self>, |
535 | 0 | cx: &mut ServerContext<'_>, |
536 | 0 | m: Message<'m>, |
537 | 0 | ) -> hs::NextStateOrError<'m> |
538 | 0 | where |
539 | 0 | Self: 'm, |
540 | | { |
541 | 0 | let client_kx = require_handshake_msg!( |
542 | | m, |
543 | | HandshakeType::ClientKeyExchange, |
544 | | HandshakePayload::ClientKeyExchange |
545 | 0 | )?; |
546 | 0 | self.transcript.add_message(&m); |
547 | 0 | let ems_seed = self |
548 | 0 | .using_ems |
549 | 0 | .then(|| self.transcript.current_hash()); |
550 | | |
551 | | // Complete key agreement, and set up encryption with the |
552 | | // resulting premaster secret. |
553 | 0 | let peer_kx_params = tls12::decode_kx_params::<ClientKeyExchangeParams>( |
554 | 0 | self.suite.kx, |
555 | 0 | cx.common, |
556 | 0 | client_kx.bytes(), |
557 | 0 | )?; |
558 | 0 | let secrets = ConnectionSecrets::from_key_exchange( |
559 | 0 | self.server_kx, |
560 | 0 | peer_kx_params.pub_key(), |
561 | 0 | ems_seed, |
562 | 0 | self.randoms, |
563 | 0 | self.suite, |
564 | | ) |
565 | 0 | .map_err(|err| { |
566 | 0 | cx.common |
567 | 0 | .send_fatal_alert(AlertDescription::IllegalParameter, err) |
568 | 0 | })?; |
569 | 0 | cx.common.kx_state.complete(); |
570 | | |
571 | 0 | self.config.key_log.log( |
572 | 0 | "CLIENT_RANDOM", |
573 | 0 | &secrets.randoms.client, |
574 | 0 | &secrets.master_secret, |
575 | 0 | ); |
576 | 0 | cx.common |
577 | 0 | .start_encryption_tls12(&secrets, Side::Server); |
578 | | |
579 | 0 | match self.client_cert { |
580 | 0 | Some(client_cert) => Ok(Box::new(ExpectCertificateVerify { |
581 | 0 | config: self.config, |
582 | 0 | secrets, |
583 | 0 | transcript: self.transcript, |
584 | 0 | session_id: self.session_id, |
585 | 0 | using_ems: self.using_ems, |
586 | 0 | client_cert, |
587 | 0 | send_ticket: self.send_ticket, |
588 | 0 | })), |
589 | 0 | _ => Ok(Box::new(ExpectCcs { |
590 | 0 | config: self.config, |
591 | 0 | secrets, |
592 | 0 | transcript: self.transcript, |
593 | 0 | session_id: self.session_id, |
594 | 0 | using_ems: self.using_ems, |
595 | 0 | resuming: false, |
596 | 0 | send_ticket: self.send_ticket, |
597 | 0 | })), |
598 | | } |
599 | 0 | } |
600 | | |
601 | 0 | fn into_owned(self: Box<Self>) -> hs::NextState<'static> { |
602 | 0 | Box::new(ExpectClientKx { |
603 | 0 | config: self.config, |
604 | 0 | transcript: self.transcript, |
605 | 0 | randoms: self.randoms, |
606 | 0 | session_id: self.session_id, |
607 | 0 | suite: self.suite, |
608 | 0 | using_ems: self.using_ems, |
609 | 0 | server_kx: self.server_kx, |
610 | 0 | client_cert: self |
611 | 0 | .client_cert |
612 | 0 | .map(|cert| cert.into_owned()), |
613 | 0 | send_ticket: self.send_ticket, |
614 | | }) |
615 | 0 | } |
616 | | } |
617 | | |
618 | | // --- Process client's certificate proof --- |
619 | | struct ExpectCertificateVerify<'a> { |
620 | | config: Arc<ServerConfig>, |
621 | | secrets: ConnectionSecrets, |
622 | | transcript: HandshakeHash, |
623 | | session_id: SessionId, |
624 | | using_ems: bool, |
625 | | client_cert: CertificateChain<'a>, |
626 | | send_ticket: bool, |
627 | | } |
628 | | |
629 | | impl State<ServerConnectionData> for ExpectCertificateVerify<'_> { |
630 | 0 | fn handle<'m>( |
631 | 0 | mut self: Box<Self>, |
632 | 0 | cx: &mut ServerContext<'_>, |
633 | 0 | m: Message<'m>, |
634 | 0 | ) -> hs::NextStateOrError<'m> |
635 | 0 | where |
636 | 0 | Self: 'm, |
637 | | { |
638 | 0 | let rc = { |
639 | 0 | let sig = require_handshake_msg!( |
640 | | m, |
641 | | HandshakeType::CertificateVerify, |
642 | | HandshakePayload::CertificateVerify |
643 | 0 | )?; |
644 | | |
645 | 0 | match self.transcript.take_handshake_buf() { |
646 | 0 | Some(msgs) => { |
647 | 0 | let certs = &self.client_cert; |
648 | 0 | self.config |
649 | 0 | .verifier |
650 | 0 | .verify_tls12_signature(&msgs, &certs[0], sig) |
651 | | } |
652 | | None => { |
653 | | // This should be unreachable; the handshake buffer was initialized with |
654 | | // client authentication if the verifier wants to offer it. |
655 | | // `transcript.abandon_client_auth()` can extract it, but its only caller in |
656 | | // this flow will also set `ExpectClientKx::client_cert` to `None`, making it |
657 | | // impossible to reach this state. |
658 | 0 | return Err(cx.common.send_fatal_alert( |
659 | 0 | AlertDescription::AccessDenied, |
660 | 0 | Error::General("client authentication not set up".into()), |
661 | 0 | )); |
662 | | } |
663 | | } |
664 | | }; |
665 | | |
666 | 0 | if let Err(e) = rc { |
667 | 0 | return Err(cx |
668 | 0 | .common |
669 | 0 | .send_cert_verify_error_alert(e)); |
670 | 0 | } |
671 | | |
672 | 0 | trace!("client CertificateVerify OK"); |
673 | 0 | cx.common.peer_certificates = Some(self.client_cert.into_owned()); |
674 | | |
675 | 0 | self.transcript.add_message(&m); |
676 | 0 | Ok(Box::new(ExpectCcs { |
677 | 0 | config: self.config, |
678 | 0 | secrets: self.secrets, |
679 | 0 | transcript: self.transcript, |
680 | 0 | session_id: self.session_id, |
681 | 0 | using_ems: self.using_ems, |
682 | 0 | resuming: false, |
683 | 0 | send_ticket: self.send_ticket, |
684 | 0 | })) |
685 | 0 | } |
686 | | |
687 | 0 | fn into_owned(self: Box<Self>) -> hs::NextState<'static> { |
688 | 0 | Box::new(ExpectCertificateVerify { |
689 | 0 | config: self.config, |
690 | 0 | secrets: self.secrets, |
691 | 0 | transcript: self.transcript, |
692 | 0 | session_id: self.session_id, |
693 | 0 | using_ems: self.using_ems, |
694 | 0 | client_cert: self.client_cert.into_owned(), |
695 | 0 | send_ticket: self.send_ticket, |
696 | 0 | }) |
697 | 0 | } |
698 | | } |
699 | | |
700 | | // --- Process client's ChangeCipherSpec --- |
701 | | struct ExpectCcs { |
702 | | config: Arc<ServerConfig>, |
703 | | secrets: ConnectionSecrets, |
704 | | transcript: HandshakeHash, |
705 | | session_id: SessionId, |
706 | | using_ems: bool, |
707 | | resuming: bool, |
708 | | send_ticket: bool, |
709 | | } |
710 | | |
711 | | impl State<ServerConnectionData> for ExpectCcs { |
712 | 0 | fn handle<'m>( |
713 | 0 | self: Box<Self>, |
714 | 0 | cx: &mut ServerContext<'_>, |
715 | 0 | m: Message<'m>, |
716 | 0 | ) -> hs::NextStateOrError<'m> |
717 | 0 | where |
718 | 0 | Self: 'm, |
719 | | { |
720 | 0 | match m.payload { |
721 | 0 | MessagePayload::ChangeCipherSpec(..) => {} |
722 | 0 | payload => { |
723 | 0 | return Err(inappropriate_message( |
724 | 0 | &payload, |
725 | 0 | &[ContentType::ChangeCipherSpec], |
726 | 0 | )); |
727 | | } |
728 | | } |
729 | | |
730 | | // CCS should not be received interleaved with fragmented handshake-level |
731 | | // message. |
732 | 0 | cx.common.check_aligned_handshake()?; |
733 | | |
734 | 0 | cx.common |
735 | 0 | .record_layer |
736 | 0 | .start_decrypting(); |
737 | 0 | Ok(Box::new(ExpectFinished { |
738 | 0 | config: self.config, |
739 | 0 | secrets: self.secrets, |
740 | 0 | transcript: self.transcript, |
741 | 0 | session_id: self.session_id, |
742 | 0 | using_ems: self.using_ems, |
743 | 0 | resuming: self.resuming, |
744 | 0 | send_ticket: self.send_ticket, |
745 | 0 | })) |
746 | 0 | } |
747 | | |
748 | 0 | fn into_owned(self: Box<Self>) -> hs::NextState<'static> { |
749 | 0 | self |
750 | 0 | } |
751 | | } |
752 | | |
753 | | // --- Process client's Finished --- |
754 | 0 | fn get_server_connection_value_tls12( |
755 | 0 | secrets: &ConnectionSecrets, |
756 | 0 | using_ems: bool, |
757 | 0 | cx: &ServerContext<'_>, |
758 | 0 | time_now: UnixTime, |
759 | 0 | ) -> persist::ServerSessionValue { |
760 | 0 | let version = ProtocolVersion::TLSv1_2; |
761 | | |
762 | 0 | let mut v = persist::ServerSessionValue::new( |
763 | 0 | cx.data.sni.as_ref(), |
764 | 0 | version, |
765 | 0 | secrets.suite().common.suite, |
766 | 0 | secrets.master_secret(), |
767 | 0 | cx.common.peer_certificates.clone(), |
768 | 0 | cx.common.alpn_protocol.clone(), |
769 | 0 | cx.data.resumption_data.clone(), |
770 | 0 | time_now, |
771 | | 0, |
772 | | ); |
773 | | |
774 | 0 | if using_ems { |
775 | 0 | v.set_extended_ms_used(); |
776 | 0 | } |
777 | | |
778 | 0 | v |
779 | 0 | } |
780 | | |
781 | 0 | fn emit_ticket( |
782 | 0 | secrets: &ConnectionSecrets, |
783 | 0 | transcript: &mut HandshakeHash, |
784 | 0 | using_ems: bool, |
785 | 0 | cx: &mut ServerContext<'_>, |
786 | 0 | ticketer: &dyn ProducesTickets, |
787 | 0 | now: UnixTime, |
788 | 0 | ) -> Result<(), Error> { |
789 | 0 | let plain = get_server_connection_value_tls12(secrets, using_ems, cx, now).get_encoding(); |
790 | | |
791 | | // If we can't produce a ticket for some reason, we can't |
792 | | // report an error. Send an empty one. |
793 | 0 | let ticket = ticketer |
794 | 0 | .encrypt(&plain) |
795 | 0 | .unwrap_or_default(); |
796 | 0 | let ticket_lifetime = ticketer.lifetime(); |
797 | | |
798 | 0 | let m = Message { |
799 | 0 | version: ProtocolVersion::TLSv1_2, |
800 | 0 | payload: MessagePayload::handshake(HandshakeMessagePayload( |
801 | 0 | HandshakePayload::NewSessionTicket(NewSessionTicketPayload::new( |
802 | 0 | ticket_lifetime, |
803 | 0 | ticket, |
804 | 0 | )), |
805 | 0 | )), |
806 | 0 | }; |
807 | | |
808 | 0 | transcript.add_message(&m); |
809 | 0 | cx.common.send_msg(m, false); |
810 | 0 | Ok(()) |
811 | 0 | } |
812 | | |
813 | 0 | fn emit_ccs(common: &mut CommonState) { |
814 | 0 | let m = Message { |
815 | 0 | version: ProtocolVersion::TLSv1_2, |
816 | 0 | payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), |
817 | 0 | }; |
818 | | |
819 | 0 | common.send_msg(m, false); |
820 | 0 | } |
821 | | |
822 | 0 | fn emit_finished( |
823 | 0 | secrets: &ConnectionSecrets, |
824 | 0 | transcript: &mut HandshakeHash, |
825 | 0 | common: &mut CommonState, |
826 | 0 | ) { |
827 | 0 | let vh = transcript.current_hash(); |
828 | 0 | let verify_data = secrets.server_verify_data(&vh); |
829 | 0 | let verify_data_payload = Payload::new(verify_data); |
830 | | |
831 | 0 | let f = Message { |
832 | 0 | version: ProtocolVersion::TLSv1_2, |
833 | 0 | payload: MessagePayload::handshake(HandshakeMessagePayload(HandshakePayload::Finished( |
834 | 0 | verify_data_payload, |
835 | 0 | ))), |
836 | 0 | }; |
837 | | |
838 | 0 | transcript.add_message(&f); |
839 | 0 | common.send_msg(f, true); |
840 | 0 | } |
841 | | |
842 | | struct ExpectFinished { |
843 | | config: Arc<ServerConfig>, |
844 | | secrets: ConnectionSecrets, |
845 | | transcript: HandshakeHash, |
846 | | session_id: SessionId, |
847 | | using_ems: bool, |
848 | | resuming: bool, |
849 | | send_ticket: bool, |
850 | | } |
851 | | |
852 | | impl State<ServerConnectionData> for ExpectFinished { |
853 | 0 | fn handle<'m>( |
854 | 0 | mut self: Box<Self>, |
855 | 0 | cx: &mut ServerContext<'_>, |
856 | 0 | m: Message<'m>, |
857 | 0 | ) -> hs::NextStateOrError<'m> |
858 | 0 | where |
859 | 0 | Self: 'm, |
860 | | { |
861 | 0 | let finished = |
862 | 0 | require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; |
863 | | |
864 | 0 | cx.common.check_aligned_handshake()?; |
865 | | |
866 | 0 | let vh = self.transcript.current_hash(); |
867 | 0 | let expect_verify_data = self.secrets.client_verify_data(&vh); |
868 | | |
869 | 0 | let _fin_verified = |
870 | 0 | match ConstantTimeEq::ct_eq(&expect_verify_data[..], finished.bytes()).into() { |
871 | 0 | true => verify::FinishedMessageVerified::assertion(), |
872 | | false => { |
873 | 0 | return Err(cx |
874 | 0 | .common |
875 | 0 | .send_fatal_alert(AlertDescription::DecryptError, Error::DecryptError)); |
876 | | } |
877 | | }; |
878 | | |
879 | | // Save connection, perhaps |
880 | 0 | if !self.resuming && !self.session_id.is_empty() { |
881 | 0 | let now = self.config.current_time()?; |
882 | | |
883 | 0 | let value = get_server_connection_value_tls12(&self.secrets, self.using_ems, cx, now); |
884 | | |
885 | 0 | let worked = self |
886 | 0 | .config |
887 | 0 | .session_storage |
888 | 0 | .put(self.session_id.as_ref().to_vec(), value.get_encoding()); |
889 | | #[cfg_attr(not(feature = "logging"), allow(clippy::if_same_then_else))] |
890 | 0 | if worked { |
891 | 0 | debug!("Session saved"); |
892 | 0 | } else { |
893 | 0 | debug!("Session not saved"); |
894 | 0 | } |
895 | 0 | } |
896 | | |
897 | | // Send our CCS and Finished. |
898 | 0 | self.transcript.add_message(&m); |
899 | 0 | if !self.resuming { |
900 | 0 | if self.send_ticket { |
901 | 0 | let now = self.config.current_time()?; |
902 | 0 | emit_ticket( |
903 | 0 | &self.secrets, |
904 | 0 | &mut self.transcript, |
905 | 0 | self.using_ems, |
906 | 0 | cx, |
907 | 0 | &*self.config.ticketer, |
908 | 0 | now, |
909 | 0 | )?; |
910 | 0 | } |
911 | 0 | emit_ccs(cx.common); |
912 | 0 | cx.common |
913 | 0 | .record_layer |
914 | 0 | .start_encrypting(); |
915 | 0 | emit_finished(&self.secrets, &mut self.transcript, cx.common); |
916 | 0 | } |
917 | | |
918 | 0 | cx.common |
919 | 0 | .start_traffic(&mut cx.sendable_plaintext); |
920 | 0 | Ok(Box::new(ExpectTraffic { |
921 | 0 | secrets: self.secrets, |
922 | 0 | _fin_verified, |
923 | 0 | })) |
924 | 0 | } |
925 | | |
926 | 0 | fn into_owned(self: Box<Self>) -> hs::NextState<'static> { |
927 | 0 | self |
928 | 0 | } |
929 | | } |
930 | | |
931 | | // --- Process traffic --- |
932 | | struct ExpectTraffic { |
933 | | secrets: ConnectionSecrets, |
934 | | _fin_verified: verify::FinishedMessageVerified, |
935 | | } |
936 | | |
937 | | impl ExpectTraffic {} |
938 | | |
939 | | impl State<ServerConnectionData> for ExpectTraffic { |
940 | 0 | fn handle<'m>( |
941 | 0 | self: Box<Self>, |
942 | 0 | cx: &mut ServerContext<'_>, |
943 | 0 | m: Message<'m>, |
944 | 0 | ) -> hs::NextStateOrError<'m> |
945 | 0 | where |
946 | 0 | Self: 'm, |
947 | | { |
948 | 0 | match m.payload { |
949 | 0 | MessagePayload::ApplicationData(payload) => cx |
950 | 0 | .common |
951 | 0 | .take_received_plaintext(payload), |
952 | 0 | payload => { |
953 | 0 | return Err(inappropriate_message( |
954 | 0 | &payload, |
955 | 0 | &[ContentType::ApplicationData], |
956 | 0 | )); |
957 | | } |
958 | | } |
959 | 0 | Ok(self) |
960 | 0 | } |
961 | | |
962 | 0 | fn export_keying_material( |
963 | 0 | &self, |
964 | 0 | output: &mut [u8], |
965 | 0 | label: &[u8], |
966 | 0 | context: Option<&[u8]>, |
967 | 0 | ) -> Result<(), Error> { |
968 | 0 | self.secrets |
969 | 0 | .export_keying_material(output, label, context); |
970 | 0 | Ok(()) |
971 | 0 | } |
972 | | |
973 | 0 | fn extract_secrets(&self) -> Result<PartiallyExtractedSecrets, Error> { |
974 | 0 | self.secrets |
975 | 0 | .extract_secrets(Side::Server) |
976 | 0 | } |
977 | | |
978 | 0 | fn into_external_state(self: Box<Self>) -> Result<Box<dyn KernelState + 'static>, Error> { |
979 | 0 | Ok(self) |
980 | 0 | } |
981 | | |
982 | 0 | fn into_owned(self: Box<Self>) -> hs::NextState<'static> { |
983 | 0 | self |
984 | 0 | } |
985 | | } |
986 | | |
987 | | impl KernelState for ExpectTraffic { |
988 | 0 | fn update_secrets(&mut self, _: Direction) -> Result<ConnectionTrafficSecrets, Error> { |
989 | 0 | Err(Error::General( |
990 | 0 | "TLS 1.2 connections do not support traffic secret updates".into(), |
991 | 0 | )) |
992 | 0 | } |
993 | | |
994 | 0 | fn handle_new_session_ticket( |
995 | 0 | &mut self, |
996 | 0 | _cx: &mut KernelContext<'_>, |
997 | 0 | _message: &NewSessionTicketPayloadTls13, |
998 | 0 | ) -> Result<(), Error> { |
999 | 0 | unreachable!( |
1000 | | "server connections should never have handle_new_session_ticket called on them" |
1001 | | ) |
1002 | | } |
1003 | | } |