Skip to content
File

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

rust160 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 crypto = dimpl::crypto::rust_crypto::default_provider();
44 create_instance(cert, now, dtls_version, mtu, crypto, self.is_test())
45 }
46}
47 
48/// Construct DTLS with an application-selected dimpl crypto provider.
49/// Normal authentication, provider validation and OS randomness remain enabled.
50pub fn with_crypto_provider(
51 cert: &DtlsCert,
52 now: Instant,
53 dtls_version: DtlsVersion,
54 mtu: Option<usize>,
55 crypto: dimpl::crypto::CryptoProvider,
56) -> Result<Box<dyn DtlsInstance>, CryptoError> {
57 create_instance(cert, now, dtls_version, mtu, crypto, false)
58}
59 
60fn create_instance(
61 cert: &DtlsCert,
62 now: Instant,
63 dtls_version: DtlsVersion,
64 mtu: Option<usize>,
65 crypto: dimpl::crypto::CryptoProvider,
66 is_test: bool,
67) -> Result<Box<dyn DtlsInstance>, CryptoError> {
68 let dimpl_cert = dimpl::DtlsCertificate {
69 certificate: cert.certificate.clone(),
70 private_key: cert.private_key.clone(),
71 };
72 
73 // Create a dimpl Config with the explicitly selected crypto provider.
74 // ICE verifies return routability before DTLS, making server cookies redundant.
75 let mut builder = dimpl::Config::builder()
76 .with_crypto_provider(crypto)
77 .use_server_cookie(false);
78 if let Some(mtu) = mtu {
79 builder = builder.mtu(mtu);
80 }
81 if is_test {
82 // We need the DTLS impl to be deterministic for the BWE tests.
83 builder = builder.dangerously_set_rng_seed(42);
84 }
85 
86 let config = builder
87 .build()
88 .map_err(|e| CryptoError::Other(format!("dimpl config creation failed: {}", e)))?;
89 
90 let config = Arc::new(config);
91 let dtls = match dtls_version {
92 DtlsVersion::Dtls12 => dimpl::Dtls::new_12(config, dimpl_cert, now),
93 DtlsVersion::Dtls13 => dimpl::Dtls::new_13(config, dimpl_cert, now),
94 DtlsVersion::Auto => dimpl::Dtls::new_auto(config, dimpl_cert, now),
95 _ => {
96 return Err(CryptoError::Other(format!(
97 "Unsupported DTLS version: {dtls_version}"
98 )));
99 }
100 };
101 
102 Ok(Box::new(RustCryptoDtlsInstance { dtls }))
103}
104 
105// ============================================================================
106// DTLS Instance Wrapper
107// ============================================================================
108 
109struct RustCryptoDtlsInstance {
110 dtls: dimpl::Dtls,
111}
112 
113impl std::fmt::Debug for RustCryptoDtlsInstance {
114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 f.debug_struct("RustCryptoDtlsInstance").finish()
116 }
117}
118 
119impl DtlsInstance for RustCryptoDtlsInstance {
120 fn set_active(&mut self, active: bool) {
121 self.dtls.set_active(active);
122 }
123 
124 fn handle_packet(&mut self, packet: &[u8]) -> Result<(), DtlsImplError> {
125 self.dtls.handle_packet(packet)
126 }
127 
128 fn poll_output<'a>(&mut self, buf: &'a mut [u8]) -> DtlsOutput<'a> {
129 self.dtls.poll_output(buf)
130 }
131 
132 fn handle_timeout(&mut self, now: Instant) -> Result<(), DtlsImplError> {
133 self.dtls.handle_timeout(now)
134 }
135 
136 fn send_application_data(&mut self, data: &[u8]) -> Result<(), DtlsImplError> {
137 self.dtls.send_application_data(data)
138 }
139 
140 fn is_active(&self) -> bool {
141 self.dtls.is_active()
142 }
143 
144 fn protocol_version(&self) -> Option<ProtocolVersion> {
145 self.dtls.protocol_version()
146 }
147 
148 fn is_closing(&self) -> bool {
149 self.dtls.is_closing()
150 }
151 
152 fn is_closed(&self) -> bool {
153 self.dtls.is_closed()
154 }
155 
156 fn close(&mut self) -> Result<(), DtlsImplError> {
157 self.dtls.close()
158 }
159}