rvoip_rtp_core/api/client/security/
mod.rs

1//! Client security API
2//!
3//! This module provides security-related interfaces for the client-side media transport.
4
5use std::net::SocketAddr;
6use std::sync::Arc;
7use std::any::Any;
8use async_trait::async_trait;
9use tokio::net::UdpSocket;
10
11use crate::api::common::error::SecurityError;
12use crate::api::common::config::{SecurityInfo, SecurityMode, SrtpProfile};
13use crate::api::server::security::SocketHandle;
14use crate::dtls::{DtlsConfig, DtlsRole};
15
16// Export modules
17pub mod default;
18pub mod dtls;
19pub mod srtp;
20pub mod fingerprint;
21pub mod packet;
22
23// Re-export public implementation
24pub use default::DefaultClientSecurityContext;
25
26/// Client security configuration
27#[derive(Debug, Clone)]
28pub struct ClientSecurityConfig {
29    /// Security mode to use
30    pub security_mode: SecurityMode,
31    /// DTLS fingerprint algorithm
32    pub fingerprint_algorithm: String,
33    /// Remote DTLS fingerprint (if known)
34    pub remote_fingerprint: Option<String>,
35    /// Remote fingerprint algorithm (if known)
36    pub remote_fingerprint_algorithm: Option<String>,
37    /// Whether to validate remote fingerprint
38    pub validate_fingerprint: bool,
39    /// SRTP profiles supported (in order of preference)
40    pub srtp_profiles: Vec<SrtpProfile>,
41    /// Path to certificate file (PEM format)
42    pub certificate_path: Option<String>,
43    /// Path to private key file (PEM format)
44    pub private_key_path: Option<String>,
45    /// Pre-shared SRTP key (for SRTP mode)
46    pub srtp_key: Option<Vec<u8>>,
47}
48
49impl Default for ClientSecurityConfig {
50    fn default() -> Self {
51        Self {
52            security_mode: SecurityMode::DtlsSrtp,
53            fingerprint_algorithm: "sha-256".to_string(),
54            remote_fingerprint: None,
55            remote_fingerprint_algorithm: None,
56            validate_fingerprint: true,
57            srtp_profiles: vec![
58                SrtpProfile::AesCm128HmacSha1_80,
59                SrtpProfile::AesGcm128,
60            ],
61            certificate_path: None,
62            private_key_path: None,
63            srtp_key: None,
64        }
65    }
66}
67
68/// Convert API SrtpProfile to internal DTLS SrtpProtectionProfile
69pub(crate) fn convert_to_dtls_profile(profile: SrtpProfile) -> crate::dtls::message::extension::SrtpProtectionProfile {
70    match profile {
71        SrtpProfile::AesCm128HmacSha1_80 => crate::dtls::message::extension::SrtpProtectionProfile::Aes128CmSha1_80,
72        SrtpProfile::AesCm128HmacSha1_32 => crate::dtls::message::extension::SrtpProtectionProfile::Aes128CmSha1_32,
73        SrtpProfile::AesGcm128 => crate::dtls::message::extension::SrtpProtectionProfile::AeadAes128Gcm,
74        SrtpProfile::AesGcm256 => crate::dtls::message::extension::SrtpProtectionProfile::AeadAes256Gcm,
75    }
76}
77
78/// Create a DtlsConfig from API ClientSecurityConfig
79pub(crate) fn create_dtls_config(config: &ClientSecurityConfig) -> DtlsConfig {
80    // Verify that SRTP profiles are specified
81    if config.srtp_profiles.is_empty() {
82        panic!("No SRTP profiles specified in client security config");
83    }
84
85    // Convert our API profiles to DTLS profiles
86    let dtls_profiles: Vec<crate::dtls::message::extension::SrtpProtectionProfile> = config.srtp_profiles.iter()
87        .map(|p| convert_to_dtls_profile(*p))
88        .collect();
89    
90    // Create DTLS config with client role
91    let mut dtls_config = DtlsConfig::default();
92    dtls_config.role = DtlsRole::Client;
93    
94    // We need to convert the SrtpProtectionProfile values to SrtpCryptoSuite values
95    let crypto_suites: Vec<crate::srtp::SrtpCryptoSuite> = dtls_profiles.iter()
96        .map(|profile| match profile {
97            &crate::dtls::message::extension::SrtpProtectionProfile::Aes128CmSha1_80 => 
98                crate::srtp::SRTP_AES128_CM_SHA1_80,
99            &crate::dtls::message::extension::SrtpProtectionProfile::Aes128CmSha1_32 => 
100                crate::srtp::SRTP_AES128_CM_SHA1_32,
101            &crate::dtls::message::extension::SrtpProtectionProfile::AeadAes128Gcm => 
102                crate::srtp::SRTP_AEAD_AES_128_GCM,
103            &crate::dtls::message::extension::SrtpProtectionProfile::AeadAes256Gcm => 
104                crate::srtp::SRTP_AEAD_AES_256_GCM,
105            &crate::dtls::message::extension::SrtpProtectionProfile::Unknown(_) => 
106                panic!("Unknown SRTP protection profile specified"), // Don't silently default
107        })
108        .collect();
109    
110    // Never use a default - if no crypto suites were mapped, that's an error
111    if crypto_suites.is_empty() {
112        panic!("Failed to map any SRTP profiles to crypto suites");
113    }
114    
115    // Set the mapped crypto suites
116    dtls_config.srtp_profiles = crypto_suites;
117    
118    // Set appropriate mtu and timeout values
119    dtls_config.mtu = 1200;
120    dtls_config.max_retransmissions = 5;
121    
122    dtls_config
123}
124
125/// Client security context interface
126///
127/// This trait defines the interface for client-side security operations,
128/// including the DTLS handshake and SRTP key extraction.
129#[async_trait]
130pub trait ClientSecurityContext: Send + Sync {
131    /// Initialize the security context
132    async fn initialize(&self) -> Result<(), SecurityError>;
133    
134    /// Start the DTLS handshake with the server
135    async fn start_handshake(&self) -> Result<(), SecurityError>;
136    
137    /// Check if the security handshake is complete
138    async fn is_handshake_complete(&self) -> Result<bool, SecurityError>;
139    
140    /// Wait for the DTLS handshake to complete
141    async fn wait_for_handshake(&self) -> Result<(), SecurityError>;
142    
143    /// Set the remote address for the security context
144    async fn set_remote_address(&self, addr: SocketAddr) -> Result<(), SecurityError>;
145    
146    /// Set the socket handle to use for security operations
147    async fn set_socket(&self, socket: SocketHandle) -> Result<(), SecurityError>;
148    
149    /// Set the remote fingerprint for DTLS verification
150    async fn set_remote_fingerprint(&self, fingerprint: &str, algorithm: &str) -> Result<(), SecurityError>;
151    
152    /// Perform a complete handshake in a single call
153    /// This combines setting the remote fingerprint, starting handshake, and waiting for completion
154    async fn complete_handshake(&self, remote_addr: SocketAddr, remote_fingerprint: &str) -> Result<(), SecurityError>;
155    
156    /// Process a DTLS packet manually
157    /// This allows for explicit processing of received DTLS packets
158    async fn process_packet(&self, data: &[u8]) -> Result<(), SecurityError>;
159    
160    /// Start automatic packet handler to process incoming DTLS packets
161    /// This creates a background task that receives packets from the socket
162    /// and automatically passes them to process_packet
163    async fn start_packet_handler(&self) -> Result<(), SecurityError>;
164    
165    /// Get security information for SDP exchange
166    async fn get_security_info(&self) -> Result<SecurityInfo, SecurityError>;
167    
168    /// Close the security context and clean up resources
169    async fn close(&self) -> Result<(), SecurityError>;
170    
171    /// Check if the security context is fully initialized and ready to start a handshake
172    /// This verifies that all prerequisites (socket, transport, etc.) are set
173    async fn is_ready(&self) -> Result<bool, SecurityError>;
174    
175    /// Is the client using secure transport?
176    fn is_secure(&self) -> bool;
177    
178    /// Get basic security information synchronously 
179    /// (for use during initialization when async isn't available)
180    fn get_security_info_sync(&self) -> SecurityInfo;
181    
182    /// Get the local fingerprint (client's fingerprint)
183    async fn get_fingerprint(&self) -> Result<String, SecurityError>;
184    
185    /// Get the local fingerprint algorithm (client's algorithm)
186    async fn get_fingerprint_algorithm(&self) -> Result<String, SecurityError>;
187    
188    /// Check if transport is set
189    async fn has_transport(&self) -> Result<bool, SecurityError>;
190    
191    /// Process a DTLS packet received from the server
192    async fn process_dtls_packet(&self, data: &[u8]) -> Result<(), SecurityError>;
193    
194    /// Get the security configuration
195    fn get_config(&self) -> &ClientSecurityConfig;
196    
197    /// Allow downcasting for internal implementation details
198    fn as_any(&self) -> &dyn Any;
199}