use std::collections::VecDeque;
use std::sync::Arc;
use std::time::Instant;
use arrayvec::ArrayVec;
use subtle::ConstantTimeEq;
use crate::buffer::{Buf, ToBuf};
use crate::crypto::SrtpProfile;
use crate::dtls12::Client;
use crate::dtls12::client::LocalEvent;
use crate::dtls12::context::AuthMode;
use crate::dtls12::engine::Engine;
use crate::dtls12::message::ECPointFormatsExtension;
use crate::dtls12::message::PskParams;
use crate::dtls12::message::{Body, CertificateRequest, CertificateTypeVec, Dtls12CipherSuite};
use crate::dtls12::message::{ClientCertificateType, CompressionMethod, ContentType};
use crate::dtls12::message::{Cookie, CurveType, DistinguishedName, ExchangeKeys, ExtensionType};
use crate::dtls12::message::{HashAlgorithm, HelloVerifyRequest, KeyExchangeAlgorithm};
use crate::dtls12::message::{MessageType, NamedGroup, NamedGroupVec, ProtocolVersion, Random};
use crate::dtls12::message::{ServerHello, SessionId, SignatureAlgorithm};
use crate::dtls12::message::{SignatureAlgorithmsExtension, SignatureAndHashAlgorithm};
use crate::dtls12::message::{SignatureAndHashAlgorithmVec, SrtpProfileId};
use crate::dtls12::message::{SrtpProfileVec, SupportedGroupsExtension, UseSrtpExtension};
use crate::{Config, Error, InternalError, Output};
const DUMMY_PSK_LEN: usize = 32;
pub struct Server {
state: State,
engine: Engine,
random: Option<Random>,
session_id: Option<SessionId>,
cookie_secret: [u8; 32],
extension_data: Buf,
negotiated_srtp_profile: Option<SrtpProfile>,
client_supported_groups: Option<NamedGroupVec>,
client_signature_algorithms: Option<SignatureAndHashAlgorithmVec>,
client_random: Option<Random>,
client_certificates: Vec<Buf>,
defragment_buffer: Buf,
captured_session_hash: Option<Buf>,
psk_valid: Option<bool>,
last_now: Instant,
local_events: VecDeque<LocalEvent>,
queued_data: Vec<Buf>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum State {
AwaitClientHello,
SendServerHello,
SendCertificate,
SendServerKeyExchange,
SendCertificateRequest,
SendServerHelloDone,
AwaitCertificate,
AwaitClientKeyExchange,
AwaitCertificateVerify,
AwaitChangeCipherSpec,
AwaitFinished,
SendChangeCipherSpec,
SendFinished,
AwaitApplicationData,
Closed,
}
impl Server {
pub fn new(config: Arc<Config>, certificate: crate::DtlsCertificate, now: Instant) -> Server {
assert!(
!certificate.certificate.is_empty(),
"Server certificate cannot be empty"
);
let private_key = config
.crypto_provider()
.key_provider
.load_private_key(&certificate.private_key)
.expect("Failed to parse server private key");
let auth = AuthMode::Certificate {
certificate: certificate.certificate,
private_key,
};
let engine = Engine::new(config, auth);
Self::new_with_engine(engine, now)
}
pub fn new_psk(config: Arc<Config>, now: Instant) -> Server {
let engine = Engine::new(config, AuthMode::Psk);
Self::new_with_engine(engine, now)
}
pub(crate) fn new_with_engine(mut engine: Engine, now: Instant) -> Server {
engine.set_client(false);
let cookie_secret: [u8; 32] = engine.rng.random();
Server {
state: State::AwaitClientHello,
engine,
random: None,
session_id: None,
cookie_secret,
extension_data: Buf::new(),
negotiated_srtp_profile: None,
client_supported_groups: None,
client_signature_algorithms: None,
client_random: None,
client_certificates: Vec::with_capacity(3),
defragment_buffer: Buf::new(),
captured_session_hash: None,
psk_valid: None,
last_now: now,
local_events: VecDeque::new(),
queued_data: Vec::new(),
}
}
pub fn into_client(self) -> Client {
Client::new_with_engine(self.engine, self.last_now)
}
pub(crate) fn state_name(&self) -> &'static str {
self.state.name()
}
pub fn is_closing(&self) -> bool {
self.state == State::Closed && !self.is_closed()
}
pub fn is_closed(&self) -> bool {
self.state == State::Closed
&& self.local_events.is_empty()
&& !self.engine.has_pending_close_output()
}
pub fn handle_packet(&mut self, packet: &[u8]) -> Result<(), Error> {
match self
.engine
.parse_packet(packet)
.and_then(|_| self.make_progress())
{
Ok(()) => Ok(()),
Err(e) => e.into_public_error().map_or(Ok(()), Err),
}
}
pub fn poll_output<'a>(&mut self, buf: &'a mut [u8]) -> Output<'a> {
if let Some(event) = self.local_events.pop_front() {
return event.into_output(buf, &self.client_certificates);
}
self.engine.poll_output(buf, self.last_now)
}
pub fn handle_timeout(&mut self, now: Instant) -> Result<(), Error> {
self.last_now = now;
if self.random.is_none() {
self.random = Some(Random::new_with_time(now, &mut self.engine.rng));
}
self.engine.handle_timeout(now)?;
match self.make_progress() {
Ok(()) => Ok(()),
Err(e) => e.into_public_error().map_or(Ok(()), Err),
}
}
pub fn send_application_data(&mut self, data: &[u8]) -> Result<(), Error> {
if self.state == State::Closed {
return Err(Error::ConnectionClosed);
}
if self.state != State::AwaitApplicationData {
self.queued_data.push(data.to_buf());
return Ok(());
}
self.engine
.create_record(ContentType::ApplicationData, 1, false, |body| {
body.extend_from_slice(data);
})?;
Ok(())
}
pub fn close(&mut self) -> Result<(), Error> {
if self.state == State::Closed {
return Ok(());
}
if self.state != State::AwaitApplicationData {
self.engine.abort();
self.state = State::Closed;
return Ok(());
}
self.engine
.create_record(ContentType::Alert, 1, false, |body| {
body.push(1); body.push(0); })?;
self.state = State::Closed;
Ok(())
}
fn make_progress(&mut self) -> Result<(), InternalError> {
loop {
let prev_state = self.state;
let new_state = prev_state.make_progress(self)?;
if prev_state != new_state {
self.state = new_state;
trace!("{:?} -> {:?}", prev_state, new_state);
} else {
break;
}
}
Ok(())
}
}
impl State {
fn name(&self) -> &'static str {
match self {
State::AwaitClientHello => "AwaitClientHello",
State::SendServerHello => "SendServerHello",
State::SendCertificate => "SendCertificate",
State::SendServerKeyExchange => "SendServerKeyExchange",
State::SendCertificateRequest => "SendCertificateRequest",
State::SendServerHelloDone => "SendServerHelloDone",
State::AwaitCertificate => "AwaitCertificate",
State::AwaitClientKeyExchange => "AwaitClientKeyExchange",
State::AwaitCertificateVerify => "AwaitCertificateVerify",
State::AwaitChangeCipherSpec => "AwaitChangeCipherSpec",
State::AwaitFinished => "AwaitFinished",
State::SendChangeCipherSpec => "SendChangeCipherSpec",
State::SendFinished => "SendFinished",
State::AwaitApplicationData => "AwaitApplicationData",
State::Closed => "Closed",
}
}
fn make_progress(self, server: &mut Server) -> Result<Self, InternalError> {
match self {
State::AwaitClientHello => self.await_client_hello(server),
State::SendServerHello => self.send_server_hello(server),
State::SendCertificate => self.send_certificate(server),
State::SendServerKeyExchange => self.send_server_key_exchange(server),
State::SendCertificateRequest => self.send_certificate_request(server),
State::SendServerHelloDone => self.send_server_hello_done(server),
State::AwaitCertificate => self.await_certificate(server),
State::AwaitClientKeyExchange => self.await_client_key_exchange(server),
State::AwaitCertificateVerify => self.await_certificate_verify(server),
State::AwaitChangeCipherSpec => self.await_change_cipher_spec(server),
State::AwaitFinished => self.await_finished(server),
State::SendChangeCipherSpec => self.send_change_cipher_spec(server),
State::SendFinished => self.send_finished(server),
State::AwaitApplicationData => self.await_application_data(server),
State::Closed => Ok(self),
}
}
fn await_client_hello(self, server: &mut Server) -> Result<Self, InternalError> {
let maybe = server
.engine
.next_handshake(MessageType::ClientHello, &mut server.defragment_buffer)?;
let Some(handshake) = maybe else {
return Ok(self);
};
let Body::ClientHello(ch) = handshake.body else {
unreachable!()
};
if ch.client_version != ProtocolVersion::DTLS1_2 {
return Err(
Error::SecurityError(crate::SecurityError::UnsupportedClientVersion(
ch.client_version,
))
.into(),
);
}
let has_null = ch.compression_methods.contains(&CompressionMethod::Null);
if !has_null {
return Err(
Error::SecurityError(crate::SecurityError::UnsupportedClientCompression).into(),
);
}
trace!(
"ClientHello: cookie_len={}, offered_suites={}",
ch.cookie.len(),
ch.cipher_suites.len()
);
let client_random = ch.random;
let hmac_provider = server.engine.config().crypto_provider().hmac_provider;
let need_cookie = server.engine.config().use_server_cookie();
let cookie_valid = !need_cookie
|| verify_cookie(
hmac_provider,
&server.cookie_secret,
client_random,
ch.cookie,
);
if !cookie_valid {
debug!("Invalid/missing cookie; sending HelloVerifyRequest");
let cookie = compute_cookie(hmac_provider, &server.cookie_secret, client_random)?;
server.engine.flight_begin(2);
server
.engine
.create_handshake(MessageType::HelloVerifyRequest, |body, _engine| {
let hvr = HelloVerifyRequest::new(ProtocolVersion::DTLS1_0, cookie);
hvr.serialize(body);
Ok(())
})?;
server.engine.reset_server_for_hello_verify_request();
return Ok(self);
}
trace!("Accepted ClientHello cookie; proceeding with handshake");
let mut selected: Option<Dtls12CipherSuite> = None;
for s in ch.cipher_suites.iter() {
let is_allowed = server.engine.is_cipher_suite_allowed(*s);
let is_compatible = server
.engine
.crypto_context()
.is_cipher_suite_compatible(*s);
if is_allowed && is_compatible {
selected = Some(*s);
break;
}
}
let Some(cs) = selected else {
return Err((Error::SecurityError(
crate::SecurityError::NoMutuallyAcceptableCipherSuite,
))
.into());
};
server.engine.set_cipher_suite(cs);
server.client_random = Some(client_random);
debug!("Selected cipher suite: {:?}", cs);
let mut client_offers_ems = false;
let mut client_srtp_profiles: Option<SrtpProfileVec> = None;
let mut client_supported_groups: Option<NamedGroupVec> = None;
let mut client_signature_algorithms: Option<SignatureAndHashAlgorithmVec> = None;
for ext in ch.extensions {
match ext.extension_type {
ExtensionType::UseSrtp => {
let ext_data = ext.extension_data(&server.defragment_buffer);
let (_, use_srtp) =
UseSrtpExtension::parse(ext_data).map_err(InternalError::from)?;
client_srtp_profiles = Some(use_srtp.profiles);
}
ExtensionType::ExtendedMasterSecret => {
client_offers_ems = true;
}
ExtensionType::SupportedGroups => {
let ext_data = ext.extension_data(&server.defragment_buffer);
let (_, groups) =
SupportedGroupsExtension::parse(ext_data).map_err(InternalError::from)?;
client_supported_groups = Some(groups.groups);
}
ExtensionType::EcPointFormats => {
let ext_data = ext.extension_data(&server.defragment_buffer);
let _ =
ECPointFormatsExtension::parse(ext_data).map_err(InternalError::from)?;
}
ExtensionType::SignatureAlgorithms => {
let ext_data = ext.extension_data(&server.defragment_buffer);
if let Ok((_, sigs)) = SignatureAlgorithmsExtension::parse(ext_data) {
client_signature_algorithms = Some(sigs.supported_signature_algorithms);
} else {
warn!("Failed to parse SignatureAlgorithms extension");
}
}
_ => {}
}
}
if !client_offers_ems {
return Err(Error::SecurityError(
crate::SecurityError::ExtendedMasterSecretNotNegotiated,
)
.into());
}
if let Some(profiles) = client_srtp_profiles {
let mut selected_profile: Option<SrtpProfile> = None;
for preferred in [
SrtpProfile::AEAD_AES_256_GCM,
SrtpProfile::AEAD_AES_128_GCM,
SrtpProfile::AES128_CM_SHA1_80,
] {
if profiles.iter().any(|pid| preferred == (*pid).into()) {
selected_profile = Some(preferred);
break;
}
}
server.negotiated_srtp_profile = selected_profile;
if let Some(profile) = server.negotiated_srtp_profile {
debug!("Negotiated SRTP profile: {:?}", profile);
}
}
server.client_supported_groups = client_supported_groups;
server.client_signature_algorithms = client_signature_algorithms;
trace!("Extended Master Secret enabled");
Ok(Self::SendServerHello)
}
fn send_server_hello(self, server: &mut Server) -> Result<Self, InternalError> {
trace!("Sending ServerHello");
server.engine.flight_begin(4);
let session_id = server.session_id.unwrap_or_else(SessionId::empty);
let random = server.random.unwrap();
let negotiated_srtp_profile = server.negotiated_srtp_profile;
let extension_data = &mut server.extension_data;
server
.engine
.create_handshake(MessageType::ServerHello, move |body, engine| {
handshake_create_server_hello(
body,
engine,
random,
session_id,
negotiated_srtp_profile,
extension_data,
)
})?;
let cs = server.engine.cipher_suite().ok_or(Error::InvalidState(
crate::InvalidStateError::NoCipherSuiteSelected,
))?;
if cs.is_psk() {
Ok(Self::SendServerKeyExchange)
} else {
Ok(Self::SendCertificate)
}
}
fn send_certificate(self, server: &mut Server) -> Result<Self, InternalError> {
trace!("Sending Certificate");
server
.engine
.create_handshake(MessageType::Certificate, handshake_create_certificate)?;
Ok(Self::SendServerKeyExchange)
}
fn send_server_key_exchange(self, server: &mut Server) -> Result<Self, InternalError> {
trace!("Sending ServerKeyExchange");
let cs = server.engine.cipher_suite().ok_or(Error::InvalidState(
crate::InvalidStateError::NoCipherSuiteSelected,
))?;
if cs.is_psk() {
return self.send_server_key_exchange_psk(server);
}
let client_random = server.client_random.ok_or(Error::InvalidState(
crate::InvalidStateError::NoClientRandom,
))?;
let server_random = server.random.unwrap();
let allowed_named_groups: Vec<NamedGroup> = server
.engine
.config()
.kx_groups()
.map(|g| g.name())
.collect();
let selected_named_group = select_named_group(
server.client_supported_groups.as_ref(),
&allowed_named_groups,
)
.ok_or_else(|| {
if server.client_supported_groups.is_some() {
Error::SecurityError(crate::SecurityError::NoCommonKeyExchangeGroup)
} else {
Error::CryptoError(crate::CryptoError::NoDtls12KeyExchangeGroupsConfigured)
}
})?;
let selected_signature = select_ske_signature_algorithm(
server.client_signature_algorithms.as_ref(),
server
.engine
.crypto_context()
.signature_algorithm()
.unwrap(),
server
.engine
.crypto_context()
.private_key_default_hash_algorithm()
.unwrap(),
server
.engine
.crypto_context()
.private_key_supported_hash_algorithms(),
);
debug!(
"ServerKeyExchange params: group={:?}, signature_alg={:?}",
selected_named_group, selected_signature
);
server
.engine
.create_handshake(MessageType::ServerKeyExchange, |body, engine| {
handshake_create_server_key_exchange(
body,
engine,
client_random,
server_random,
selected_named_group,
selected_signature,
)
})?;
if server.engine.config().require_client_certificate() {
Ok(Self::SendCertificateRequest)
} else {
Ok(Self::SendServerHelloDone)
}
}
fn send_server_key_exchange_psk(self, server: &mut Server) -> Result<Self, InternalError> {
let Some(hint) = server
.engine
.config()
.psk_identity_hint()
.map(<[u8]>::to_vec)
else {
return Ok(Self::SendServerHelloDone);
};
server
.engine
.create_handshake(MessageType::ServerKeyExchange, move |body, _engine| {
PskParams::serialize_from_bytes(&hint, body);
Ok(())
})?;
Ok(Self::SendServerHelloDone)
}
fn send_certificate_request(self, server: &mut Server) -> Result<Self, InternalError> {
debug!("Sending CertificateRequest");
let sig_algs =
select_certificate_request_sig_algs(server.client_signature_algorithms.as_ref());
debug!(
"CertificateRequest will advertise {} signature algorithms",
sig_algs.len()
);
server
.engine
.create_handshake(MessageType::CertificateRequest, move |body, _| {
handshake_serialize_certificate_request(body, &sig_algs)
})?;
Ok(Self::SendServerHelloDone)
}
fn send_server_hello_done(self, server: &mut Server) -> Result<Self, InternalError> {
trace!("Sending ServerHelloDone");
server
.engine
.create_handshake(MessageType::ServerHelloDone, |_, _| Ok(()))?;
let cs = server.engine.cipher_suite().ok_or(Error::InvalidState(
crate::InvalidStateError::NoCipherSuiteSelected,
))?;
if cs.is_psk() {
return Ok(Self::AwaitClientKeyExchange);
}
if server.engine.config().require_client_certificate() {
Ok(Self::AwaitCertificate)
} else {
Ok(Self::AwaitClientKeyExchange)
}
}
fn await_certificate(self, server: &mut Server) -> Result<Self, InternalError> {
let maybe = server
.engine
.next_handshake(MessageType::Certificate, &mut server.defragment_buffer)?;
let Some(ref handshake) = maybe else {
return Ok(self);
};
let Body::Certificate(certificate) = &handshake.body else {
unreachable!()
};
let cert_ranges: ArrayVec<_, 32> = certificate
.certificate_list
.iter()
.map(|cert| cert.0.clone())
.collect();
drop(maybe);
if cert_ranges.is_empty() {
} else {
debug!(
"Received client certificate chain with {} certificate(s)",
cert_ranges.len()
);
for (i, range) in cert_ranges.iter().enumerate() {
let cert_data = &server.defragment_buffer[range.clone()];
trace!(
"Client Certificate #{} size: {} bytes",
i + 1,
cert_data.len()
);
server.client_certificates.push(cert_data.to_buf());
}
server.local_events.push_back(LocalEvent::PeerCert);
}
Ok(Self::AwaitClientKeyExchange)
}
fn await_client_key_exchange(self, server: &mut Server) -> Result<Self, InternalError> {
let maybe = server.engine.next_handshake(
MessageType::ClientKeyExchange,
&mut server.defragment_buffer,
)?;
let Some(ref handshake) = maybe else {
return Ok(self);
};
let Body::ClientKeyExchange(ckx) = &handshake.body else {
unreachable!()
};
let suite = server.engine.cipher_suite().ok_or(Error::InvalidState(
crate::InvalidStateError::NoCipherSuiteSelected,
))?;
if suite.is_psk() {
let identity_range = match &ckx.exchange_keys {
ExchangeKeys::Psk(keys) => keys.identity_range.clone(),
_ => {
return Err(Error::UnexpectedMessage(
crate::UnexpectedMessageError::EcdheClientKeyExchangeInPskPath,
)
.into());
}
};
drop(maybe);
let identity = &server.defragment_buffer[identity_range];
trace!("PSK identity ({} bytes)", identity.len());
let resolved = server
.engine
.config()
.psk_resolver()
.ok_or(Error::PskError(crate::PskError::NoPskResolverConfigured))?
.resolve(identity);
let (psk, psk_valid) = match resolved {
Some(key) => (key, true),
None => {
let dummy: [u8; DUMMY_PSK_LEN] = server.engine.rng.random();
(dummy.to_vec(), false)
}
};
server.psk_valid = Some(psk_valid);
let crypto = server.engine.crypto_context_mut();
crypto.set_psk(psk);
crypto
.compute_psk_pre_master_secret()
.map_err(Error::CryptoError)?;
} else {
let public_key_range = match &ckx.exchange_keys {
ExchangeKeys::Ecdh(keys) => keys.public_key_range.clone(),
ExchangeKeys::Psk(_) => {
return Err(Error::UnexpectedMessage(
crate::UnexpectedMessageError::PskClientKeyExchangeInEcdhePath,
)
.into());
}
};
drop(maybe);
let client_pub = &server.defragment_buffer[public_key_range];
let mut buf = server.engine.pop_buffer();
server
.engine
.crypto_context_mut()
.compute_shared_secret(client_pub, &mut buf)
.map_err(Error::CryptoError)?;
server.engine.push_buffer(buf);
}
let suite_hash = suite.hash_algorithm();
let mut buf = server.engine.pop_buffer();
server.engine.transcript_hash(suite_hash, &mut buf);
server.captured_session_hash = Some(buf);
let client_random_buf = {
let mut b = Buf::new();
server.client_random.unwrap().serialize(&mut b);
b
};
let server_random_buf = {
let mut b = Buf::new();
server.random.unwrap().serialize(&mut b);
b
};
let session_hash = server
.captured_session_hash
.as_ref()
.ok_or(Error::InvalidState(
crate::InvalidStateError::ExtendedMasterSecretSessionHashMissing,
))?;
let mut out = server.engine.pop_buffer();
let mut scratch = server.engine.pop_buffer();
server
.engine
.crypto_context_mut()
.derive_extended_master_secret(session_hash, suite_hash, &mut out, &mut scratch)
.map_err(Error::CryptoError)?;
server
.engine
.crypto_context_mut()
.derive_keys(
suite,
&client_random_buf,
&server_random_buf,
&mut out,
&mut scratch,
)
.map_err(Error::CryptoError)?;
server.engine.push_buffer(out);
server.engine.push_buffer(scratch);
trace!(
"Captured session hash length for EMS: {}",
session_hash.len()
);
trace!("Derived session keys (EMS) and ready to verify Finished");
if !server.client_certificates.is_empty() {
Ok(Self::AwaitCertificateVerify)
} else {
Ok(Self::AwaitChangeCipherSpec)
}
}
fn await_certificate_verify(self, server: &mut Server) -> Result<Self, InternalError> {
let data = server.engine.transcript().to_buf();
let maybe = server.engine.next_handshake(
MessageType::CertificateVerify,
&mut server.defragment_buffer,
)?;
if maybe.is_none() {
return Ok(self);
};
let (signature_range, signature_algorithm) = {
let handshake = maybe.as_ref().unwrap();
let Body::CertificateVerify(cv) = &handshake.body else {
unreachable!()
};
(cv.signed.signature_range.clone(), cv.signed.algorithm)
};
drop(maybe);
let signature_bytes = &server.defragment_buffer[signature_range];
if server.client_certificates.is_empty() {
return Err(Error::CertificateError(
crate::CertificateError::NoClientCertificateForVerification,
)
.into());
}
let temp_signed = crate::dtls12::message::DigitallySigned {
algorithm: signature_algorithm,
signature_range: 0..signature_bytes.len(),
};
server
.engine
.crypto_context()
.verify_signature(
&data,
&temp_signed,
signature_bytes,
&server.client_certificates[0],
)
.map_err(Error::CryptoError)?;
debug!("Client CertificateVerify verified successfully");
Ok(Self::AwaitChangeCipherSpec)
}
fn await_change_cipher_spec(self, server: &mut Server) -> Result<Self, InternalError> {
let maybe = server.engine.next_record(ContentType::ChangeCipherSpec);
let Some(_) = maybe else {
return Ok(self);
};
trace!("Dropping any pending CCS resends from peer");
server.engine.drop_pending_ccs();
trace!("Received ChangeCipherSpec; enabling peer encryption");
server.engine.enable_peer_encryption()?;
Ok(Self::AwaitFinished)
}
fn await_finished(self, server: &mut Server) -> Result<Self, InternalError> {
let expected = server.engine.generate_verify_data(true )?;
let maybe = server
.engine
.next_handshake(MessageType::Finished, &mut server.defragment_buffer)?;
if maybe.is_none() {
return Ok(self);
}
let verify_data_range = if let Some(ref handshake) = maybe {
if let Body::Finished(finished) = &handshake.body {
finished.verify_data_range.clone()
} else {
panic!("Finished message should have been parsed");
}
} else {
unreachable!()
};
drop(maybe);
let verify_data = &server.defragment_buffer[verify_data_range];
let is_eq: bool = verify_data.ct_eq(expected.as_slice()).into();
if !is_eq {
return Err((Error::SecurityError(
crate::SecurityError::ClientFinishedVerificationFailed,
))
.into());
}
if server.engine.cipher_suite().is_some_and(|cs| cs.is_psk()) {
assert!(
server.psk_valid.is_some(),
"PSK handshake reached Finished without processing ClientKeyExchange"
);
}
if server.psk_valid == Some(false) {
return Err((Error::SecurityError(
crate::SecurityError::ClientFinishedVerificationFailed,
))
.into());
}
trace!("Client Finished verified successfully");
Ok(Self::SendChangeCipherSpec)
}
fn send_change_cipher_spec(self, server: &mut Server) -> Result<Self, InternalError> {
trace!("Sending ChangeCipherSpec");
server.engine.flight_begin(6);
server
.engine
.create_record(ContentType::ChangeCipherSpec, 0, true, |body| {
body.push(1);
})?;
Ok(Self::SendFinished)
}
fn send_finished(self, server: &mut Server) -> Result<Self, InternalError> {
trace!("Sending Finished message to complete handshake");
server
.engine
.create_handshake(MessageType::Finished, |body, engine| {
let verify_data = engine.generate_verify_data(false )?;
trace!("Finished.verify_data length: {}", verify_data.len());
body.extend_from_slice(&verify_data);
Ok(())
})?;
server.engine.flight_stop_resend_timers();
debug!("Handshake complete; ready for application data");
server.local_events.push_back(LocalEvent::Connected);
if let Some(profile) = server.negotiated_srtp_profile {
let suite_hash = server.engine.cipher_suite().unwrap().hash_algorithm();
let mut out = server.engine.pop_buffer();
let mut scratch = server.engine.pop_buffer();
if let Ok(keying_material) = server
.engine
.crypto_context()
.extract_srtp_keying_material(profile, suite_hash, &mut out, &mut scratch)
{
server.engine.push_buffer(out);
server.engine.push_buffer(scratch);
debug!(
"SRTP keying material extracted ({} bytes) for profile: {:?}",
keying_material.len(),
profile
);
let profile = server
.negotiated_srtp_profile
.expect("SRTP profile should be negotiated");
server
.local_events
.push_back(LocalEvent::KeyingMaterial(keying_material, profile));
} else {
server.engine.push_buffer(out);
server.engine.push_buffer(scratch);
}
}
server.engine.release_application_data();
Ok(Self::AwaitApplicationData)
}
fn await_application_data(self, server: &mut Server) -> Result<Self, InternalError> {
if server.engine.close_notify_received() {
server.engine.discard_pending_writes();
server
.engine
.create_record(ContentType::Alert, 1, false, |body| {
body.push(1); body.push(0); })?;
return Ok(State::Closed);
}
if !server.queued_data.is_empty() {
debug!(
"Sending queued application data: {}",
server.queued_data.len()
);
for data in server.queued_data.drain(..) {
server
.engine
.create_record(ContentType::ApplicationData, 1, false, |body| {
body.extend_from_slice(&data);
})?;
}
}
Ok(self)
}
}
fn compute_cookie(
hmac_provider: &dyn crate::crypto::HmacProvider,
secret: &[u8],
client_random: Random,
) -> Result<Cookie, Error> {
let mut buf = Buf::new();
client_random.serialize(&mut buf);
let tag = hmac_provider
.hmac_sha256(secret, &buf)
.map_err(Error::CryptoError)?;
let cookie = Cookie::try_new(&tag).map_err(|_| {
Error::CryptoError(crate::CryptoError::OperationFailed(
crate::CryptoOperation::ComputeCookie,
))
})?;
Ok(cookie)
}
fn verify_cookie(
hmac_provider: &dyn crate::crypto::HmacProvider,
secret: &[u8],
client_random: Random,
cookie: Cookie,
) -> bool {
if cookie.len() != 32 {
return false;
}
match compute_cookie(hmac_provider, secret, client_random) {
Ok(expected) => expected.as_ref().ct_eq(cookie.as_ref()).into(),
Err(_) => false,
}
}
fn handshake_create_certificate(body: &mut Buf, engine: &mut Engine) -> Result<(), Error> {
let crypto = engine.crypto_context();
crypto.serialize_client_certificate(body);
Ok(())
}
fn handshake_create_server_hello(
body: &mut Buf,
engine: &mut Engine,
random: Random,
session_id: SessionId,
negotiated_srtp_profile: Option<SrtpProfile>,
extension_data: &mut Buf,
) -> Result<(), Error> {
let server_version = ProtocolVersion::DTLS1_2;
let cs = engine
.cipher_suite()
.ok_or(Error::InvalidState(crate::InvalidStateError::NoCipherSuite))?;
let srtp_pid = negotiated_srtp_profile.map(|p| match p {
SrtpProfile::AEAD_AES_256_GCM => SrtpProfileId::SRTP_AEAD_AES_256_GCM,
SrtpProfile::AEAD_AES_128_GCM => SrtpProfileId::SRTP_AEAD_AES_128_GCM,
SrtpProfile::AES128_CM_SHA1_80 => SrtpProfileId::SRTP_AES128_CM_SHA1_80,
});
let sh = ServerHello::new(
server_version,
random,
session_id,
cs,
CompressionMethod::Null,
None,
)
.with_extensions(extension_data, srtp_pid);
sh.serialize(extension_data, body);
Ok(())
}
fn handshake_create_server_key_exchange(
body: &mut Buf,
engine: &mut Engine,
client_random: Random,
server_random: Random,
named_group: NamedGroup,
algorithm: SignatureAndHashAlgorithm,
) -> Result<(), Error> {
let Some(cipher_suite) = engine.cipher_suite() else {
return Err(Error::InvalidState(
crate::InvalidStateError::NoCipherSuiteSelected,
));
};
let key_exchange_algorithm = cipher_suite.as_key_exchange_algorithm();
debug!("Using key exchange algorithm: {:?}", key_exchange_algorithm);
let hash_alg = algorithm.hash;
match key_exchange_algorithm {
KeyExchangeAlgorithm::EECDH => {
let (curve_type, named_group) = (CurveType::NamedCurve, named_group);
let mut kx_buf = engine.pop_buffer();
let pubkey = engine
.crypto_context_mut()
.init_ecdh_server(named_group, &mut kx_buf)
.map_err(Error::CryptoError)?;
trace!(
"SKE ECDHE: group={:?}, pubkey_len={}",
named_group,
pubkey.len()
);
let mut signed_data = Buf::new();
client_random.serialize(&mut signed_data);
server_random.serialize(&mut signed_data);
signed_data.push(curve_type.as_u8());
signed_data.extend_from_slice(&named_group.as_u16().to_be_bytes());
signed_data.push(pubkey.len() as u8);
signed_data.extend_from_slice(pubkey);
engine.push_buffer(kx_buf);
let mut signature = engine.pop_buffer();
trace!("SKE signature hash: {:?}", hash_alg);
engine
.crypto_context
.sign_data(&signed_data, hash_alg, &mut signature)
.map_err(Error::CryptoError)?;
let pubkey = engine
.crypto_context_mut()
.maybe_init_key_exchange()
.unwrap();
body.push(curve_type.as_u8());
body.extend_from_slice(&named_group.as_u16().to_be_bytes());
body.push(pubkey.len() as u8);
body.extend_from_slice(pubkey);
body.extend_from_slice(&algorithm.as_u16().to_be_bytes());
body.extend_from_slice(&(signature.len() as u16).to_be_bytes());
body.extend_from_slice(&signature);
engine.push_buffer(signature);
Ok(())
}
_ => Err(Error::SecurityError(
crate::SecurityError::UnsupportedKeyExchangeAlgorithm,
)),
}
}
fn handshake_serialize_certificate_request(
body: &mut Buf,
sig_algs: &SignatureAndHashAlgorithmVec,
) -> Result<(), Error> {
let mut cert_types = CertificateTypeVec::new();
cert_types.push(ClientCertificateType::ECDSA_SIGN);
let mut selected = SignatureAndHashAlgorithmVec::new();
if sig_algs.is_empty() {
let fallback = SignatureAndHashAlgorithm::supported();
for alg in fallback.iter() {
selected.push(*alg);
}
} else {
for alg in sig_algs.iter() {
selected.push(*alg);
}
}
let cert_auths: ArrayVec<DistinguishedName, 32> = ArrayVec::new();
let cr = CertificateRequest::new(cert_types, selected, cert_auths);
cr.serialize(&[], body);
Ok(())
}
fn select_named_group(
client_groups: Option<&NamedGroupVec>,
server_groups: &[NamedGroup],
) -> Option<NamedGroup> {
if let Some(groups) = client_groups {
for sg in server_groups {
if groups.iter().any(|g| g == sg) {
return Some(*sg);
}
}
return None;
}
server_groups.first().copied()
}
fn select_ske_signature_algorithm(
client_algs: Option<&SignatureAndHashAlgorithmVec>,
our_sig: SignatureAlgorithm,
our_hash: HashAlgorithm,
supported_hashes: &[HashAlgorithm],
) -> SignatureAndHashAlgorithm {
let hash_pref = match our_hash {
HashAlgorithm::SHA384 => [HashAlgorithm::SHA384, HashAlgorithm::SHA256],
_ => [HashAlgorithm::SHA256, HashAlgorithm::SHA384],
};
if let Some(list) = client_algs {
for h in hash_pref.iter() {
if !supported_hashes.contains(h) {
continue;
}
if let Some(chosen) = list
.iter()
.find(|alg| alg.signature == our_sig && alg.hash == *h)
{
return *chosen;
}
}
}
SignatureAndHashAlgorithm::new(our_hash, our_sig)
}
fn select_certificate_request_sig_algs(
client_algs: Option<&SignatureAndHashAlgorithmVec>,
) -> SignatureAndHashAlgorithmVec {
let ours = SignatureAndHashAlgorithm::supported();
let mut out = ArrayVec::new();
if let Some(list) = client_algs {
for alg in list.iter() {
if ours
.iter()
.any(|a| a.hash == alg.hash && a.signature == alg.signature)
{
out.push(*alg);
}
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
fn named_group_vec(groups: &[NamedGroup]) -> NamedGroupVec {
let mut out = NamedGroupVec::new();
for g in groups {
out.push(*g);
}
out
}
#[test]
fn select_named_group_prefers_x25519_when_available() {
let client = named_group_vec(&[
NamedGroup::Secp256r1,
NamedGroup::X25519,
NamedGroup::Secp384r1,
]);
let provider = [NamedGroup::X25519, NamedGroup::Secp256r1];
let selected = select_named_group(Some(&client), &provider);
assert_eq!(selected, Some(NamedGroup::X25519));
}
#[test]
fn select_named_group_respects_provider_capabilities() {
let client = named_group_vec(&[NamedGroup::X25519, NamedGroup::Secp256r1]);
let provider = [NamedGroup::Secp256r1];
let selected = select_named_group(Some(&client), &provider);
assert_eq!(selected, Some(NamedGroup::Secp256r1));
}
#[test]
fn select_named_group_falls_back_to_provider_when_client_missing() {
let provider = [NamedGroup::Secp384r1];
let selected = select_named_group(None, &provider);
assert_eq!(selected, Some(NamedGroup::Secp384r1));
}
#[test]
fn select_named_group_rejects_when_client_has_no_overlap() {
let client = named_group_vec(&[NamedGroup::X25519]);
let provider = [NamedGroup::Secp256r1];
let selected = select_named_group(Some(&client), &provider);
assert_eq!(selected, None);
}
#[test]
fn certificate_request_does_not_select_rsa_signatures() {
let mut client = SignatureAndHashAlgorithmVec::new();
client.push(SignatureAndHashAlgorithm::new(
HashAlgorithm::SHA256,
SignatureAlgorithm::ECDSA,
));
client.push(SignatureAndHashAlgorithm::new(
HashAlgorithm::SHA256,
SignatureAlgorithm::RSA,
));
let selected = select_certificate_request_sig_algs(Some(&client));
assert_eq!(selected.len(), 1);
assert_eq!(selected[0].signature, SignatureAlgorithm::ECDSA);
assert_eq!(selected[0].hash, HashAlgorithm::SHA256);
}
#[test]
fn certificate_request_rejects_rsa_only_signatures() {
let mut client = SignatureAndHashAlgorithmVec::new();
client.push(SignatureAndHashAlgorithm::new(
HashAlgorithm::SHA256,
SignatureAlgorithm::RSA,
));
let selected = select_certificate_request_sig_algs(Some(&client));
assert!(selected.is_empty());
}
}