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