File
Blob: archive/str0m-probe/vendor/str0m-rust-crypto/src/dtls.rs
| 1 | //! DTLS implementation using dimpl with RustCrypto backend. |
| 2 | |
| 3 | use std::sync::Arc; |
| 4 | use std::time::Instant; |
| 5 | |
| 6 | use str0m_proto::crypto::CryptoError; |
| 7 | use str0m_proto::crypto::DtlsVersion; |
| 8 | use str0m_proto::crypto::dtls::ProtocolVersion; |
| 9 | use str0m_proto::crypto::dtls::{DtlsCert, DtlsImplError, DtlsInstance, DtlsOutput, DtlsProvider}; |
| 10 | |
| 11 | // ============================================================================ |
| 12 | // DTLS Provider Implementation |
| 13 | // ============================================================================ |
| 14 | |
| 15 | #[derive(Debug)] |
| 16 | pub(super) struct RustCryptoDtlsProvider; |
| 17 | |
| 18 | impl 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 | |
| 85 | struct RustCryptoDtlsInstance { |
| 86 | dtls: dimpl::Dtls, |
| 87 | } |
| 88 | |
| 89 | impl 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 | |
| 95 | impl 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 | } |