use std::sync::Arc;
use std::time::Instant;
use str0m_proto::crypto::CryptoError;
use str0m_proto::crypto::DtlsVersion;
use str0m_proto::crypto::dtls::{DtlsCert, DtlsImplError, DtlsInstance, DtlsOutput, DtlsProvider};
#[derive(Debug)]
pub(super) struct RustCryptoDtlsProvider;
impl DtlsProvider for RustCryptoDtlsProvider {
fn generate_certificate(&self) -> Option<DtlsCert> {
dimpl::certificate::generate_self_signed_certificate()
.ok()
.map(|cert| DtlsCert {
certificate: cert.certificate,
private_key: cert.private_key,
})
}
fn new_dtls(
&self,
cert: &DtlsCert,
now: Instant,
dtls_version: DtlsVersion,
) -> Result<Box<dyn DtlsInstance>, CryptoError> {
let dimpl_cert = dimpl::DtlsCertificate {
certificate: cert.certificate.clone(),
private_key: cert.private_key.clone(),
};
let mut builder = dimpl::Config::builder().use_server_cookie(false);
if self.is_test() {
builder = builder.dangerously_set_rng_seed(42);
}
let config = builder
.build()
.map_err(|e| CryptoError::Other(format!("dimpl config creation failed: {}", e)))?;
let config = Arc::new(config);
let dtls = match dtls_version {
DtlsVersion::Dtls12 => dimpl::Dtls::new_12(config, dimpl_cert, now),
DtlsVersion::Dtls13 => dimpl::Dtls::new_13(config, dimpl_cert, now),
DtlsVersion::Auto => dimpl::Dtls::new_auto(config, dimpl_cert, now),
_ => {
return Err(CryptoError::Other(format!(
"Unsupported DTLS version: {dtls_version}"
)));
}
};
Ok(Box::new(RustCryptoDtlsInstance { dtls }))
}
}
struct RustCryptoDtlsInstance {
dtls: dimpl::Dtls,
}
impl std::fmt::Debug for RustCryptoDtlsInstance {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RustCryptoDtlsInstance").finish()
}
}
impl DtlsInstance for RustCryptoDtlsInstance {
fn set_active(&mut self, active: bool) {
self.dtls.set_active(active);
}
fn handle_packet(&mut self, packet: &[u8]) -> Result<(), DtlsImplError> {
self.dtls.handle_packet(packet)
}
fn poll_output<'a>(&mut self, buf: &'a mut [u8]) -> DtlsOutput<'a> {
self.dtls.poll_output(buf)
}
fn handle_timeout(&mut self, now: Instant) -> Result<(), DtlsImplError> {
self.dtls.handle_timeout(now)
}
fn send_application_data(&mut self, data: &[u8]) -> Result<(), DtlsImplError> {
self.dtls.send_application_data(data)
}
fn is_active(&self) -> bool {
self.dtls.is_active()
}
}