Skip to content
File

Blob: archive/str0m-probe/vendor/str0m-rust-crypto/src/dtls.rs

rust136 lines
1//! DTLS implementation using dimpl with RustCrypto backend.
2 
3use std::sync::Arc;
4use std::time::Instant;
5 
6use str0m_proto::crypto::CryptoError;
7use str0m_proto::crypto::DtlsVersion;
8use str0m_proto::crypto::dtls::ProtocolVersion;
9use str0m_proto::crypto::dtls::{DtlsCert, DtlsImplError, DtlsInstance, DtlsOutput, DtlsProvider};
10 
11// ============================================================================
12// DTLS Provider Implementation
13// ============================================================================
14 
15#[derive(Debug)]
16pub(super) struct RustCryptoDtlsProvider;
17 
18impl DtlsProvider for RustCryptoDtlsProvider {
19 fn generate_certificate(&self) -> Option<DtlsCert> {
20 #[cfg(feature = "generate-cert")]
21 {
22 dimpl::certificate::generate_self_signed_certificate()
23 .ok()
24 .map(|cert| DtlsCert {
25 certificate: cert.certificate,
26 private_key: cert.private_key,
27 })
28 }
29 #[cfg(not(feature = "generate-cert"))]
30 {
31 // The application supplies its certificate through RtcConfig.
32 None
33 }
34 }
35 
36 fn new_dtls(
37 &self,
38 cert: &DtlsCert,
39 now: Instant,
40 dtls_version: DtlsVersion,
41 mtu: Option<usize>,
42 ) -> Result<Box<dyn DtlsInstance>, CryptoError> {
43 let dimpl_cert = dimpl::DtlsCertificate {
44 certificate: cert.certificate.clone(),
45 private_key: cert.private_key.clone(),
46 };
47 
48 // Create a default dimpl Config with RustCrypto crypto provider
49 // ICE verifies return routability before DTLS, making server cookies redundant.
50 let mut builder = dimpl::Config::builder()
51 .with_crypto_provider(dimpl::crypto::rust_crypto::default_provider())
52 .use_server_cookie(false);
53 if let Some(mtu) = mtu {
54 builder = builder.mtu(mtu);
55 }
56 if self.is_test() {
57 // We need the DTLS impl to be deterministic for the BWE tests.
58 builder = builder.dangerously_set_rng_seed(42);
59 }
60 
61 let config = builder
62 .build()
63 .map_err(|e| CryptoError::Other(format!("dimpl config creation failed: {}", e)))?;
64 
65 let config = Arc::new(config);
66 let dtls = match dtls_version {
67 DtlsVersion::Dtls12 => dimpl::Dtls::new_12(config, dimpl_cert, now),
68 DtlsVersion::Dtls13 => dimpl::Dtls::new_13(config, dimpl_cert, now),
69 DtlsVersion::Auto => dimpl::Dtls::new_auto(config, dimpl_cert, now),
70 _ => {
71 return Err(CryptoError::Other(format!(
72 "Unsupported DTLS version: {dtls_version}"
73 )));
74 }
75 };
76 
77 Ok(Box::new(RustCryptoDtlsInstance { dtls }))
78 }
79}
80 
81// ============================================================================
82// DTLS Instance Wrapper
83// ============================================================================
84 
85struct RustCryptoDtlsInstance {
86 dtls: dimpl::Dtls,
87}
88 
89impl std::fmt::Debug for RustCryptoDtlsInstance {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 f.debug_struct("RustCryptoDtlsInstance").finish()
92 }
93}
94 
95impl DtlsInstance for RustCryptoDtlsInstance {
96 fn set_active(&mut self, active: bool) {
97 self.dtls.set_active(active);
98 }
99 
100 fn handle_packet(&mut self, packet: &[u8]) -> Result<(), DtlsImplError> {
101 self.dtls.handle_packet(packet)
102 }
103 
104 fn poll_output<'a>(&mut self, buf: &'a mut [u8]) -> DtlsOutput<'a> {
105 self.dtls.poll_output(buf)
106 }
107 
108 fn handle_timeout(&mut self, now: Instant) -> Result<(), DtlsImplError> {
109 self.dtls.handle_timeout(now)
110 }
111 
112 fn send_application_data(&mut self, data: &[u8]) -> Result<(), DtlsImplError> {
113 self.dtls.send_application_data(data)
114 }
115 
116 fn is_active(&self) -> bool {
117 self.dtls.is_active()
118 }
119 
120 fn protocol_version(&self) -> Option<ProtocolVersion> {
121 self.dtls.protocol_version()
122 }
123 
124 fn is_closing(&self) -> bool {
125 self.dtls.is_closing()
126 }
127 
128 fn is_closed(&self) -> bool {
129 self.dtls.is_closed()
130 }
131 
132 fn close(&mut self) -> Result<(), DtlsImplError> {
133 self.dtls.close()
134 }
135}