use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
use core::time::Duration;
pub(crate) use server_hello::TLS12_HANDLER;
use subtle::ConstantTimeEq;
use super::config::{ClientConfig, ClientSessionKey};
use super::hs::ClientState;
use super::{ClientAuthDetails, ServerCertDetails, Tls12Session};
use crate::ConnectionTrafficSecrets;
use crate::check::{inappropriate_handshake_message, inappropriate_message};
use crate::common_state::{HandshakeKind, Output, OutputEvent, Side};
use crate::conn::kernel::KernelState;
use crate::conn::{ConnectionRandoms, Input};
use crate::crypto::cipher::{MessageDecrypter, MessageEncrypter, Payload};
use crate::crypto::kx::KeyExchangeAlgorithm;
use crate::crypto::{Identity, Signer};
use crate::enums::{CertificateType, ContentType, HandshakeType, ProtocolVersion};
use crate::error::{ApiMisuse, Error, InvalidMessage, PeerIncompatible, PeerMisbehaved};
use crate::hash_hs::HandshakeHash;
use crate::log::{debug, trace, warn};
use crate::msgs::{
CertificateChain, ChangeCipherSpecPayload, ClientDhParams, ClientEcdhParams,
ClientKeyExchangeParams, HandshakeAlignedProof, HandshakeMessagePayload, HandshakePayload,
Message, MessagePayload, NewSessionTicketPayload, NewSessionTicketPayloadTls13,
ServerKeyExchangeParams, SessionId, SizedPayload,
};
use crate::suites::{PartiallyExtractedSecrets, Suite};
use crate::sync::Arc;
use crate::tls12::{self, ConnectionSecrets, Tls12CipherSuite};
use crate::tls13::key_schedule::KeyScheduleTrafficSend;
use crate::verify::{self, DigitallySignedStruct, ServerIdentity, SignatureVerificationInput};
#[expect(private_interfaces)]
pub(crate) enum Tls12State {
Certificate(Box<ExpectCertificate>),
CertificateStatusOrServerKx(Box<ExpectCertificateStatusOrServerKx>),
ServerKx(Box<ExpectServerKx>),
ServerDoneOrCertReq(Box<ExpectServerDoneOrCertReq>),
ServerDone(Box<ExpectServerDone>),
NewTicket(Box<ExpectNewTicket>),
ChangeCipherSpec(Box<ExpectCcs>),
Finished(Box<ExpectFinished>),
Traffic(Box<ExpectTraffic>),
}
impl Tls12State {
pub(crate) fn handle<'m>(
self,
input: Input<'m>,
output: &mut dyn Output<'m>,
) -> Result<ClientState, Error> {
match self {
Self::Certificate(e) => e.handle(input, output),
Self::CertificateStatusOrServerKx(e) => e.handle(input, output),
Self::ServerKx(e) => e.handle(input, output),
Self::ServerDoneOrCertReq(e) => e.handle(input, output),
Self::ServerDone(e) => e.handle(input, output),
Self::NewTicket(e) => e.handle(input, output),
Self::ChangeCipherSpec(e) => e.handle(input, output),
Self::Finished(e) => e.handle(input, output),
Self::Traffic(e) => e.handle(input, output),
}
}
}
mod server_hello {
use super::*;
use crate::client::hs::{
ClientHandler, ClientHelloInput, ClientSessionValue, ClientState, ExpectServerHello,
};
use crate::msgs::ServerHelloPayload;
use crate::sealed::Sealed;
pub(crate) static TLS12_HANDLER: &dyn ClientHandler<Tls12CipherSuite> = &Handler;
#[derive(Debug)]
struct Handler;
impl ClientHandler<Tls12CipherSuite> for Handler {
fn handle_server_hello(
&self,
suite: &'static Tls12CipherSuite,
server_hello: &ServerHelloPayload,
Input { message, .. }: &Input<'_>,
st: ExpectServerHello,
output: &mut dyn Output<'_>,
) -> Result<ClientState, Error> {
let mut transcript = st
.transcript_buffer
.start_hash(suite.common.hash_provider);
transcript.add_message(message);
let mut randoms = ConnectionRandoms::new(st.input.random, server_hello.random);
randoms
.server
.clone_from_slice(&server_hello.random.0[..]);
let has_downgrade_marker = randoms.server[24..] == tls12::DOWNGRADE_SENTINEL;
if st
.input
.config
.supports_version(ProtocolVersion::TLSv1_3)
&& has_downgrade_marker
{
return Err(PeerMisbehaved::AttemptedDowngradeToTls12WhenTls13IsSupported.into());
}
if st.input.resuming.is_none()
&& !st.input.session_id.is_empty()
&& st.input.session_id == server_hello.session_id
{
return Err(PeerMisbehaved::ServerEchoedCompatibilitySessionId.into());
}
let ClientHelloInput {
config,
session_key,
..
} = st.input;
let resuming_session = st
.input
.resuming
.and_then(|resuming| match resuming.value {
ClientSessionValue::Tls12(inner) => Some(inner),
ClientSessionValue::Tls13(_) => None,
});
let using_ems = server_hello
.extended_master_secret_ack
.is_some();
if config.require_ems && !using_ems {
return Err(PeerIncompatible::ExtendedMasterSecretExtensionRequired.into());
}
let must_issue_new_ticket = if server_hello
.session_ticket_ack
.is_some()
{
debug!("Server supports tickets");
true
} else {
false
};
let may_send_cert_status = server_hello
.certificate_status_request_ack
.is_some();
if may_send_cert_status {
debug!("Server may staple OCSP response");
}
if let Some(resuming) = resuming_session {
if resuming.session_id == server_hello.session_id {
debug!("Server agreed to resume");
if resuming.suite != suite {
return Err(PeerMisbehaved::ResumptionOfferedWithVariedCipherSuite.into());
}
if resuming.extended_ms != using_ems {
return Err(PeerMisbehaved::ResumptionOfferedWithVariedEms.into());
}
let secrets =
ConnectionSecrets::new_resume(randoms, suite, &resuming.master_secret);
config.key_log.log(
"CLIENT_RANDOM",
&secrets.randoms.client,
secrets.master_secret(),
);
let (dec, enc) = secrets.make_cipher_pair(Side::Client);
output.output(OutputEvent::HandshakeKind(HandshakeKind::Resumed));
let cert_verified = verify::PeerVerified::assertion();
let sig_verified = verify::HandshakeSignatureValid::assertion();
let hs = HandshakeState {
config,
session_id: server_hello.session_id,
session_key,
using_ems,
transcript,
};
return if must_issue_new_ticket {
Ok(Box::new(ExpectNewTicket {
hs,
secrets,
peer_identity: resuming.peer_identity().clone(),
resuming: Some((resuming, enc)),
pending_decrypter: dec,
cert_verified,
sig_verified,
})
.into())
} else {
Ok(Box::new(ExpectCcs {
hs,
secrets,
peer_identity: resuming.peer_identity().clone(),
resuming: Some((resuming, enc)),
pending_decrypter: dec,
ticket: None,
cert_verified,
sig_verified,
})
.into())
};
}
}
output.output(OutputEvent::HandshakeKind(HandshakeKind::Full));
Ok(Box::new(ExpectCertificate {
hs: HandshakeState {
config,
session_id: server_hello.session_id,
session_key,
using_ems,
transcript,
},
randoms,
suite,
may_send_cert_status,
must_issue_new_ticket,
negotiated_client_type: server_hello.client_certificate_type,
})
.into())
}
}
impl Sealed for Handler {}
}
struct ExpectCertificate {
hs: HandshakeState,
randoms: ConnectionRandoms,
suite: &'static Tls12CipherSuite,
may_send_cert_status: bool,
must_issue_new_ticket: bool,
negotiated_client_type: Option<CertificateType>,
}
impl ExpectCertificate {
fn handle(
mut self: Box<Self>,
Input { message, .. }: Input<'_>,
_output: &mut dyn Output<'_>,
) -> Result<ClientState, Error> {
self.hs.transcript.add_message(&message);
let server_cert_chain = require_handshake_msg_move!(
message,
HandshakeType::Certificate,
HandshakePayload::Certificate
)?;
if self.may_send_cert_status {
Ok(Box::new(ExpectCertificateStatusOrServerKx {
hs: self.hs,
randoms: self.randoms,
suite: self.suite,
server_cert_chain: server_cert_chain.into_owned(),
must_issue_new_ticket: self.must_issue_new_ticket,
negotiated_client_type: self.negotiated_client_type,
})
.into())
} else {
Ok(Box::new(ExpectServerKx {
hs: self.hs,
randoms: self.randoms,
suite: self.suite,
server_cert: ServerCertDetails::new(server_cert_chain.into_owned(), vec![]),
must_issue_new_ticket: self.must_issue_new_ticket,
negotiated_client_type: self.negotiated_client_type,
})
.into())
}
}
}
impl From<Box<ExpectCertificate>> for ClientState {
fn from(value: Box<ExpectCertificate>) -> Self {
Self::Tls12(Tls12State::Certificate(value))
}
}
struct ExpectCertificateStatusOrServerKx {
hs: HandshakeState,
randoms: ConnectionRandoms,
suite: &'static Tls12CipherSuite,
server_cert_chain: CertificateChain<'static>,
must_issue_new_ticket: bool,
negotiated_client_type: Option<CertificateType>,
}
impl ExpectCertificateStatusOrServerKx {
fn handle(
self: Box<Self>,
input: Input<'_>,
_output: &mut dyn Output<'_>,
) -> Result<ClientState, Error> {
match input.message.payload {
MessagePayload::Handshake {
parsed: HandshakeMessagePayload(HandshakePayload::ServerKeyExchange(..)),
..
} => ExpectServerKx {
hs: self.hs,
randoms: self.randoms,
suite: self.suite,
server_cert: ServerCertDetails::new(self.server_cert_chain, vec![]),
must_issue_new_ticket: self.must_issue_new_ticket,
negotiated_client_type: self.negotiated_client_type,
}
.handle_input(input),
MessagePayload::Handshake {
parsed: HandshakeMessagePayload(HandshakePayload::CertificateStatus(..)),
..
} => ExpectCertificateStatus {
hs: self.hs,
randoms: self.randoms,
suite: self.suite,
server_cert_chain: self.server_cert_chain,
must_issue_new_ticket: self.must_issue_new_ticket,
negotiated_client_type: self.negotiated_client_type,
}
.handle_input(input),
payload => Err(inappropriate_handshake_message(
&payload,
&[ContentType::Handshake],
&[
HandshakeType::ServerKeyExchange,
HandshakeType::CertificateStatus,
],
)),
}
}
}
impl From<Box<ExpectCertificateStatusOrServerKx>> for ClientState {
fn from(value: Box<ExpectCertificateStatusOrServerKx>) -> Self {
Self::Tls12(Tls12State::CertificateStatusOrServerKx(value))
}
}
struct ExpectCertificateStatus {
hs: HandshakeState,
randoms: ConnectionRandoms,
suite: &'static Tls12CipherSuite,
server_cert_chain: CertificateChain<'static>,
must_issue_new_ticket: bool,
negotiated_client_type: Option<CertificateType>,
}
impl ExpectCertificateStatus {
fn handle_input(mut self, Input { message, .. }: Input<'_>) -> Result<ClientState, Error> {
self.hs.transcript.add_message(&message);
let server_cert_ocsp_response = require_handshake_msg_move!(
message,
HandshakeType::CertificateStatus,
HandshakePayload::CertificateStatus
)?
.into_inner();
trace!(
"Server stapled OCSP response is {:?}",
server_cert_ocsp_response
);
let server_cert = ServerCertDetails::new(self.server_cert_chain, server_cert_ocsp_response);
Ok(Box::new(ExpectServerKx {
hs: self.hs,
randoms: self.randoms,
suite: self.suite,
server_cert,
must_issue_new_ticket: self.must_issue_new_ticket,
negotiated_client_type: self.negotiated_client_type,
})
.into())
}
}
struct ExpectServerKx {
hs: HandshakeState,
randoms: ConnectionRandoms,
suite: &'static Tls12CipherSuite,
server_cert: ServerCertDetails,
must_issue_new_ticket: bool,
negotiated_client_type: Option<CertificateType>,
}
impl ExpectServerKx {
fn handle_input(mut self, Input { message, .. }: Input<'_>) -> Result<ClientState, Error> {
let opaque_kx = require_handshake_msg!(
message,
HandshakeType::ServerKeyExchange,
HandshakePayload::ServerKeyExchange
)?;
self.hs.transcript.add_message(&message);
let kx = opaque_kx
.unwrap_given_kxa(self.suite.kx)
.ok_or(InvalidMessage::MissingKeyExchange)?;
let mut kx_params = Vec::new();
kx.params.encode(&mut kx_params);
let server_kx = ServerKxDetails::new(kx_params, kx.dss);
match &kx.params {
ServerKeyExchangeParams::Ecdh(ecdhe) => {
debug!("ECDHE curve is {:?}", ecdhe.curve_params)
}
ServerKeyExchangeParams::Dh(dhe) => {
debug!("DHE params are p = {:?}, g = {:?}", dhe.dh_p, dhe.dh_g)
}
}
Ok(Box::new(ExpectServerDoneOrCertReq {
hs: self.hs,
randoms: self.randoms,
suite: self.suite,
server_cert: self.server_cert,
server_kx,
must_issue_new_ticket: self.must_issue_new_ticket,
negotiated_client_type: self.negotiated_client_type,
})
.into())
}
}
impl ExpectServerKx {
fn handle(
self: Box<Self>,
input: Input<'_>,
_output: &mut dyn Output<'_>,
) -> Result<ClientState, Error> {
self.handle_input(input)
}
}
impl From<Box<ExpectServerKx>> for ClientState {
fn from(value: Box<ExpectServerKx>) -> Self {
Self::Tls12(Tls12State::ServerKx(value))
}
}
fn emit_certificate(
transcript: &mut HandshakeHash,
cert_chain: CertificateChain<'_>,
output: &mut dyn Output<'_>,
) {
let cert = Message {
version: ProtocolVersion::TLSv1_2,
payload: MessagePayload::handshake(HandshakeMessagePayload(HandshakePayload::Certificate(
cert_chain,
))),
};
transcript.add_message(&cert);
output.send_msg(cert, false);
}
fn emit_client_kx(
transcript: &mut HandshakeHash,
kxa: KeyExchangeAlgorithm,
output: &mut dyn Output<'_>,
pub_key: &[u8],
) {
let mut buf = Vec::new();
match kxa {
KeyExchangeAlgorithm::ECDHE => ClientKeyExchangeParams::Ecdh(ClientEcdhParams {
public: pub_key.to_vec().into(),
}),
KeyExchangeAlgorithm::DHE => ClientKeyExchangeParams::Dh(ClientDhParams {
public: SizedPayload::from(Payload::new(pub_key.to_vec())),
}),
}
.encode(&mut buf);
let pubkey = Payload::new(buf);
let ckx = Message {
version: ProtocolVersion::TLSv1_2,
payload: MessagePayload::handshake(HandshakeMessagePayload(
HandshakePayload::ClientKeyExchange(pubkey),
)),
};
transcript.add_message(&ckx);
output.send_msg(ckx, false);
}
fn emit_certverify(
transcript: &mut HandshakeHash,
signer: Box<dyn Signer>,
output: &mut dyn Output<'_>,
) -> Result<(), Error> {
let message = transcript
.take_handshake_buf()
.ok_or_else(|| Error::General("Expected transcript".to_owned()))?;
let scheme = signer.scheme();
let sig = signer.sign(&message)?;
let body = DigitallySignedStruct::new(scheme, sig);
let m = Message {
version: ProtocolVersion::TLSv1_2,
payload: MessagePayload::handshake(HandshakeMessagePayload(
HandshakePayload::CertificateVerify(body),
)),
};
transcript.add_message(&m);
output.send_msg(m, false);
Ok(())
}
fn emit_ccs(output: &mut dyn Output<'_>) {
output.send_msg(
Message {
version: ProtocolVersion::TLSv1_2,
payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}),
},
false,
);
}
fn emit_finished(
secrets: &ConnectionSecrets,
transcript: &mut HandshakeHash,
output: &mut dyn Output<'_>,
proof: &HandshakeAlignedProof,
) {
let vh = transcript.current_hash();
let verify_data = secrets.client_verify_data(&vh, proof);
let verify_data_payload = Payload::Borrowed(&verify_data);
let f = Message {
version: ProtocolVersion::TLSv1_2,
payload: MessagePayload::handshake(HandshakeMessagePayload(HandshakePayload::Finished(
verify_data_payload,
))),
};
transcript.add_message(&f);
output.send_msg(f, true);
}
struct ServerKxDetails {
kx_params: Vec<u8>,
kx_sig: DigitallySignedStruct,
}
impl ServerKxDetails {
fn new(params: Vec<u8>, sig: DigitallySignedStruct) -> Self {
Self {
kx_params: params,
kx_sig: sig,
}
}
}
struct ExpectServerDoneOrCertReq {
hs: HandshakeState,
randoms: ConnectionRandoms,
suite: &'static Tls12CipherSuite,
server_cert: ServerCertDetails,
server_kx: ServerKxDetails,
must_issue_new_ticket: bool,
negotiated_client_type: Option<CertificateType>,
}
impl ExpectServerDoneOrCertReq {
fn handle(
mut self: Box<Self>,
input: Input<'_>,
output: &mut dyn Output<'_>,
) -> Result<ClientState, Error> {
if matches!(
input.message.payload,
MessagePayload::Handshake {
parsed: HandshakeMessagePayload(HandshakePayload::CertificateRequest(_)),
..
}
) {
ExpectCertificateRequest {
hs: self.hs,
randoms: self.randoms,
suite: self.suite,
server_cert: self.server_cert,
server_kx: self.server_kx,
must_issue_new_ticket: self.must_issue_new_ticket,
negotiated_client_type: self.negotiated_client_type,
}
.handle_input(input)
} else {
self.hs.transcript.abandon_client_auth();
ExpectServerDone {
hs: self.hs,
randoms: self.randoms,
suite: self.suite,
server_cert: self.server_cert,
server_kx: self.server_kx,
client_auth: None,
must_issue_new_ticket: self.must_issue_new_ticket,
}
.handle_input(input, output)
}
}
}
impl From<Box<ExpectServerDoneOrCertReq>> for ClientState {
fn from(value: Box<ExpectServerDoneOrCertReq>) -> Self {
Self::Tls12(Tls12State::ServerDoneOrCertReq(value))
}
}
struct ExpectCertificateRequest {
hs: HandshakeState,
randoms: ConnectionRandoms,
suite: &'static Tls12CipherSuite,
server_cert: ServerCertDetails,
server_kx: ServerKxDetails,
must_issue_new_ticket: bool,
negotiated_client_type: Option<CertificateType>,
}
impl ExpectCertificateRequest {
fn handle_input(mut self, Input { message, .. }: Input<'_>) -> Result<ClientState, Error> {
let certreq = require_handshake_msg!(
message,
HandshakeType::CertificateRequest,
HandshakePayload::CertificateRequest
)?;
self.hs.transcript.add_message(&message);
debug!("Got CertificateRequest {certreq:?}");
const NO_CONTEXT: Option<Vec<u8>> = None; let no_compression = None; let client_auth = ClientAuthDetails::resolve(
self.negotiated_client_type
.unwrap_or(CertificateType::X509),
self.hs.config.resolver().as_ref(),
Some(&certreq.canames),
&certreq.sigschemes,
NO_CONTEXT,
no_compression,
);
Ok(Box::new(ExpectServerDone {
hs: self.hs,
randoms: self.randoms,
suite: self.suite,
server_cert: self.server_cert,
server_kx: self.server_kx,
client_auth: Some(client_auth),
must_issue_new_ticket: self.must_issue_new_ticket,
})
.into())
}
}
struct ExpectServerDone {
hs: HandshakeState,
randoms: ConnectionRandoms,
suite: &'static Tls12CipherSuite,
server_cert: ServerCertDetails,
server_kx: ServerKxDetails,
client_auth: Option<ClientAuthDetails>,
must_issue_new_ticket: bool,
}
impl ExpectServerDone {
fn handle_input(
mut self,
input: Input<'_>,
output: &mut dyn Output<'_>,
) -> Result<ClientState, Error> {
match input.message.payload {
MessagePayload::Handshake {
parsed: HandshakeMessagePayload(HandshakePayload::ServerHelloDone),
..
} => {}
payload => {
return Err(inappropriate_handshake_message(
&payload,
&[ContentType::Handshake],
&[HandshakeType::ServerHelloDone],
));
}
}
self.hs
.transcript
.add_message(&input.message);
let proof = input.check_aligned_handshake()?;
trace!("Server cert is {:?}", self.server_cert.cert_chain);
debug!("Server DNS name is {:?}", self.hs.session_key.server_name);
let suite = self.suite;
let identity = Identity::from_peer(self.server_cert.cert_chain.0, CertificateType::X509)?
.ok_or(PeerMisbehaved::NoCertificatesPresented)?;
let cert_verified = self
.hs
.config
.verifier()
.verify_identity(&ServerIdentity {
identity: &identity,
server_name: &self.hs.session_key.server_name,
ocsp_response: &self.server_cert.ocsp_response,
now: self.hs.config.current_time()?,
})?;
let sig_verified = {
let mut message = Vec::new();
message.extend_from_slice(&self.randoms.client);
message.extend_from_slice(&self.randoms.server);
message.extend_from_slice(&self.server_kx.kx_params);
let signature = &self.server_kx.kx_sig;
if !suite.usable_for_signature_scheme(signature.scheme) {
warn!(
"peer signed kx with wrong algorithm (got {:?} expect {:?})",
signature.scheme.algorithm(),
suite.sign
);
return Err(PeerMisbehaved::SignedKxWithWrongAlgorithm.into());
}
self.hs
.config
.verifier()
.verify_tls12_signature(&SignatureVerificationInput {
message: &message,
signer: &identity.as_signer(),
signature,
})?
};
if let Some(client_auth) = &self.client_auth {
let certs = match client_auth {
ClientAuthDetails::Empty { .. } => CertificateChain::default(),
ClientAuthDetails::Verify { credentials, .. } => {
CertificateChain::from_signer(credentials)
}
};
emit_certificate(&mut self.hs.transcript, certs, output);
}
let kx_params = tls12::decode_kx_params::<ServerKeyExchangeParams>(
self.suite.kx,
&self.server_kx.kx_params,
)?;
let maybe_skxg = match &kx_params {
ServerKeyExchangeParams::Ecdh(ecdh) => self
.hs
.config
.provider()
.find_kx_group(ecdh.curve_params.named_group, ProtocolVersion::TLSv1_2),
ServerKeyExchangeParams::Dh(dh) => {
let ffdhe_group = dh.as_ffdhe_group();
self.hs
.config
.provider()
.kx_groups
.iter()
.find(|kxg| kxg.ffdhe_group() == Some(ffdhe_group))
.copied()
}
};
let Some(skxg) = maybe_skxg else {
return Err(PeerMisbehaved::SelectedUnofferedKxGroup.into());
};
let kx = skxg.start()?.into_single();
emit_client_kx(&mut self.hs.transcript, self.suite.kx, output, kx.pub_key());
let ems_seed = self
.hs
.using_ems
.then(|| self.hs.transcript.current_hash());
if let Some(ClientAuthDetails::Verify { credentials, .. }) = self.client_auth {
emit_certverify(&mut self.hs.transcript, credentials.signer, output)?;
}
let secrets = ConnectionSecrets::from_key_exchange(
kx,
kx_params.pub_key(),
ems_seed,
self.randoms,
suite,
)?;
output.output(OutputEvent::KeyExchangeGroup(skxg));
emit_ccs(output);
self.hs.config.key_log.log(
"CLIENT_RANDOM",
&secrets.randoms.client,
secrets.master_secret(),
);
let (dec, encrypter) = secrets.make_cipher_pair(Side::Client);
output.send().set_encrypter(
encrypter,
secrets
.suite()
.common
.confidentiality_limit,
);
emit_finished(&secrets, &mut self.hs.transcript, output, &proof);
if self.must_issue_new_ticket {
Ok(Box::new(ExpectNewTicket {
hs: self.hs,
secrets,
peer_identity: identity,
resuming: None,
pending_decrypter: dec,
cert_verified,
sig_verified,
})
.into())
} else {
Ok(Box::new(ExpectCcs {
hs: self.hs,
secrets,
peer_identity: identity,
resuming: None,
pending_decrypter: dec,
ticket: None,
cert_verified,
sig_verified,
})
.into())
}
}
}
impl ExpectServerDone {
fn handle(
self: Box<Self>,
input: Input<'_>,
output: &mut dyn Output<'_>,
) -> Result<ClientState, Error> {
self.handle_input(input, output)
}
}
impl From<Box<ExpectServerDone>> for ClientState {
fn from(value: Box<ExpectServerDone>) -> Self {
Self::Tls12(Tls12State::ServerDone(value))
}
}
struct ExpectNewTicket {
hs: HandshakeState,
secrets: ConnectionSecrets,
peer_identity: Identity<'static>,
resuming: Option<(Tls12Session, Box<dyn MessageEncrypter>)>,
pending_decrypter: Box<dyn MessageDecrypter>,
cert_verified: verify::PeerVerified,
sig_verified: verify::HandshakeSignatureValid,
}
impl ExpectNewTicket {
fn handle(
mut self: Box<Self>,
Input { message, .. }: Input<'_>,
_output: &mut dyn Output<'_>,
) -> Result<ClientState, Error> {
self.hs.transcript.add_message(&message);
let nst = require_handshake_msg_move!(
message,
HandshakeType::NewSessionTicket,
HandshakePayload::NewSessionTicket
)?;
Ok(Box::new(ExpectCcs {
hs: self.hs,
secrets: self.secrets,
resuming: self.resuming,
peer_identity: self.peer_identity,
pending_decrypter: self.pending_decrypter,
ticket: Some(nst),
cert_verified: self.cert_verified,
sig_verified: self.sig_verified,
})
.into())
}
}
impl From<Box<ExpectNewTicket>> for ClientState {
fn from(value: Box<ExpectNewTicket>) -> Self {
Self::Tls12(Tls12State::NewTicket(value))
}
}
struct ExpectCcs {
hs: HandshakeState,
secrets: ConnectionSecrets,
peer_identity: Identity<'static>,
resuming: Option<(Tls12Session, Box<dyn MessageEncrypter>)>,
pending_decrypter: Box<dyn MessageDecrypter>,
ticket: Option<NewSessionTicketPayload>,
cert_verified: verify::PeerVerified,
sig_verified: verify::HandshakeSignatureValid,
}
impl ExpectCcs {
fn handle(
self: Box<Self>,
input: Input<'_>,
output: &mut dyn Output<'_>,
) -> Result<ClientState, Error> {
match input.message.payload {
MessagePayload::ChangeCipherSpec(..) => {}
payload => {
return Err(inappropriate_message(
&payload,
&[ContentType::ChangeCipherSpec],
));
}
}
let proof = input.check_aligned_handshake()?;
output
.receive()
.decrypt_state
.set_message_decrypter(self.pending_decrypter, &proof);
Ok(Box::new(ExpectFinished {
hs: self.hs,
peer_identity: self.peer_identity,
resuming: self.resuming,
ticket: self.ticket,
secrets: self.secrets,
cert_verified: self.cert_verified,
sig_verified: self.sig_verified,
})
.into())
}
}
impl From<Box<ExpectCcs>> for ClientState {
fn from(value: Box<ExpectCcs>) -> Self {
Self::Tls12(Tls12State::ChangeCipherSpec(value))
}
}
pub(super) struct ExpectFinished {
hs: HandshakeState,
peer_identity: Identity<'static>,
resuming: Option<(Tls12Session, Box<dyn MessageEncrypter>)>,
ticket: Option<NewSessionTicketPayload>,
secrets: ConnectionSecrets,
cert_verified: verify::PeerVerified,
sig_verified: verify::HandshakeSignatureValid,
}
impl ExpectFinished {
fn save_session(&mut self) {
let (mut ticket, lifetime) = match self.ticket.take() {
Some(nst) => (nst.ticket, nst.lifetime_hint),
None => (
Arc::new(SizedPayload::from(Payload::new(Vec::new()))),
Duration::ZERO,
),
};
if ticket.is_empty() {
if let Some((resuming_session, _)) = &mut self.resuming {
ticket = resuming_session.ticket.clone();
}
}
if self.hs.session_id.is_empty() && ticket.is_empty() {
debug!("Session not saved: server didn't allocate id or ticket");
return;
}
let Ok(now) = self.hs.config.current_time() else {
debug!("Could not get current time");
return;
};
let session_value = Tls12Session::new(
self.secrets.suite(),
self.hs.session_id,
ticket,
self.secrets.master_secret(),
self.peer_identity.clone(),
now,
lifetime,
self.hs.using_ems,
);
self.hs
.config
.resumption
.store
.set_tls12_session(self.hs.session_key.clone(), session_value);
}
}
impl ExpectFinished {
fn handle(
self: Box<Self>,
input: Input<'_>,
output: &mut dyn Output<'_>,
) -> Result<ClientState, Error> {
let mut st = *self;
let finished = require_handshake_msg!(
input.message,
HandshakeType::Finished,
HandshakePayload::Finished
)?;
let proof = input.check_aligned_handshake()?;
let vh = st.hs.transcript.current_hash();
let expect_verify_data = st
.secrets
.server_verify_data(&vh, &proof);
let fin_verified =
match ConstantTimeEq::ct_eq(&expect_verify_data[..], finished.bytes()).into() {
true => verify::FinishedMessageVerified::assertion(),
false => {
return Err(PeerMisbehaved::IncorrectFinished.into());
}
};
st.hs
.transcript
.add_message(&input.message);
st.save_session();
if let Some((_, encrypter)) = st.resuming.take() {
emit_ccs(output);
output.send().set_encrypter(
encrypter,
st.secrets
.suite()
.common
.confidentiality_limit,
);
emit_finished(&st.secrets, &mut st.hs.transcript, output, &proof);
}
let extracted_secrets = st
.hs
.config
.enable_secret_extraction
.then(|| st.secrets.extract_secrets(Side::Client));
output.output(OutputEvent::PeerIdentity(st.peer_identity));
output.output(OutputEvent::ExtendedMasterSecret(st.hs.using_ems));
output.output(OutputEvent::Exporter(st.secrets.into_exporter()));
output.start_traffic();
Ok(Box::new(ExpectTraffic {
extracted_secrets,
_cert_verified: st.cert_verified,
_sig_verified: st.sig_verified,
_fin_verified: fin_verified,
})
.into())
}
pub(super) fn handle_decrypt_error(&self) {
if self.resuming.is_some() {
self.hs
.config
.resumption
.store
.remove_tls12_session(&self.hs.session_key);
}
}
}
impl From<Box<ExpectFinished>> for ClientState {
fn from(value: Box<ExpectFinished>) -> Self {
Self::Tls12(Tls12State::Finished(value))
}
}
struct HandshakeState {
config: Arc<ClientConfig>,
session_id: SessionId,
session_key: ClientSessionKey<'static>,
using_ems: bool,
transcript: HandshakeHash,
}
pub(super) struct ExpectTraffic {
extracted_secrets: Option<Result<PartiallyExtractedSecrets, Error>>,
_cert_verified: verify::PeerVerified,
_sig_verified: verify::HandshakeSignatureValid,
_fin_verified: verify::FinishedMessageVerified,
}
impl ExpectTraffic {
fn handle<'m>(
self: Box<Self>,
Input { message, .. }: Input<'m>,
output: &mut dyn Output<'m>,
) -> Result<ClientState, Error> {
match message.payload {
MessagePayload::ApplicationData(payload) => output.received_plaintext(payload),
payload => {
return Err(inappropriate_message(
&payload,
&[ContentType::ApplicationData],
));
}
}
Ok(self.into())
}
pub(super) fn into_external_state(
mut self: Box<Self>,
_send_keys: &Option<Box<KeyScheduleTrafficSend>>,
) -> Result<(PartiallyExtractedSecrets, Box<dyn KernelState + 'static>), Error> {
match self.extracted_secrets.take() {
Some(extracted_secrets) => Ok((extracted_secrets?, self)),
None => Err(ApiMisuse::SecretExtractionRequiresPriorOptIn.into()),
}
}
}
impl KernelState for ExpectTraffic {
fn update_rx_secret(&mut self) -> Result<ConnectionTrafficSecrets, Error> {
Err(ApiMisuse::KeyUpdateNotAvailableForTls12.into())
}
#[cfg_attr(coverage_nightly, coverage(off))]
fn handle_new_session_ticket(
&self,
_message: &NewSessionTicketPayloadTls13,
) -> Result<(), Error> {
Err(Error::Unreachable(
"TLS 1.2 session tickets may not be sent once the handshake has completed",
))
}
}
impl From<Box<ExpectTraffic>> for ClientState {
fn from(value: Box<ExpectTraffic>) -> Self {
Self::Tls12(Tls12State::Traffic(value))
}
}