use crate::api::client::security::{ClientSecurityContext, DefaultClientSecurityContext};
use crate::api::common::config::{SecurityConfig, SecurityMode};
use crate::api::common::error::SecurityError;
use crate::api::server::security::{
DefaultServerSecurityContext, ServerSecurityContext, SocketHandle,
};
use std::net::SocketAddr;
use std::sync::Arc;
use tokio::net::UdpSocket;
pub struct SecurityManager {
config: SecurityConfig,
client_context: Option<Arc<dyn ClientSecurityContext>>,
server_context: Option<Arc<dyn ServerSecurityContext>>,
}
impl SecurityManager {
pub fn new(config: SecurityConfig) -> Self {
Self {
config,
client_context: None,
server_context: None,
}
}
pub fn webrtc_compatible() -> Self {
Self::new(SecurityConfig::webrtc_compatible())
}
pub fn unsecured() -> Self {
Self::new(SecurityConfig::unsecured())
}
pub fn with_srtp_key(key: Vec<u8>) -> Self {
Self::new(SecurityConfig::srtp_with_key(key))
}
pub async fn setup_server(
&mut self,
socket_addr: SocketAddr,
) -> Result<Arc<dyn ServerSecurityContext>, SecurityError> {
let server_security_config = match self.config.mode {
SecurityMode::None => {
return Err(SecurityError::Configuration(
"Cannot set up security for 'None' mode".to_string(),
));
}
SecurityMode::Srtp => {
crate::api::server::security::ServerSecurityConfig {
security_mode: SecurityMode::Srtp,
fingerprint_algorithm: self.config.fingerprint_algorithm.clone(),
srtp_profiles: self.config.srtp_profiles.clone(),
certificate_path: None,
private_key_path: None,
require_client_certificate: false,
srtp_key: self.config.srtp_key.clone(),
}
}
SecurityMode::DtlsSrtp => {
crate::api::server::security::ServerSecurityConfig {
security_mode: SecurityMode::DtlsSrtp,
fingerprint_algorithm: self.config.fingerprint_algorithm.clone(),
srtp_profiles: self.config.srtp_profiles.clone(),
certificate_path: self.config.certificate_path.clone(),
private_key_path: self.config.private_key_path.clone(),
require_client_certificate: self.config.require_client_certificate,
srtp_key: None, }
}
SecurityMode::SdesSrtp | SecurityMode::MikeySrtp | SecurityMode::ZrtpSrtp => {
return Err(SecurityError::Configuration(
"SIP-derived SRTP methods should use SecurityContextManager".to_string(),
));
}
};
let server_ctx = DefaultServerSecurityContext::new(server_security_config).await?;
let socket =
Arc::new(UdpSocket::bind(socket_addr).await.map_err(|e| {
SecurityError::Configuration(format!("Failed to bind socket: {}", e))
})?);
let socket_handle = SocketHandle {
socket: socket.clone(),
remote_addr: None,
};
server_ctx.set_socket(socket_handle).await?;
server_ctx.start_listening().await?;
if self.config.mode == SecurityMode::DtlsSrtp {
server_ctx.start_packet_handler().await?;
}
self.server_context = Some(server_ctx.clone());
Ok(server_ctx)
}
pub async fn setup_server_with_socket(
&mut self,
socket: Arc<UdpSocket>,
) -> Result<Arc<dyn ServerSecurityContext>, SecurityError> {
let server_security_config = match self.config.mode {
SecurityMode::None => {
return Err(SecurityError::Configuration(
"Cannot set up security for 'None' mode".to_string(),
));
}
SecurityMode::Srtp => {
crate::api::server::security::ServerSecurityConfig {
security_mode: SecurityMode::Srtp,
fingerprint_algorithm: self.config.fingerprint_algorithm.clone(),
srtp_profiles: self.config.srtp_profiles.clone(),
certificate_path: None,
private_key_path: None,
require_client_certificate: false,
srtp_key: self.config.srtp_key.clone(),
}
}
SecurityMode::DtlsSrtp => {
crate::api::server::security::ServerSecurityConfig {
security_mode: SecurityMode::DtlsSrtp,
fingerprint_algorithm: self.config.fingerprint_algorithm.clone(),
srtp_profiles: self.config.srtp_profiles.clone(),
certificate_path: self.config.certificate_path.clone(),
private_key_path: self.config.private_key_path.clone(),
require_client_certificate: self.config.require_client_certificate,
srtp_key: None, }
}
SecurityMode::SdesSrtp | SecurityMode::MikeySrtp | SecurityMode::ZrtpSrtp => {
return Err(SecurityError::Configuration(
"SIP-derived SRTP methods should use SecurityContextManager".to_string(),
));
}
};
let server_ctx = DefaultServerSecurityContext::new(server_security_config).await?;
let socket_handle = SocketHandle {
socket: socket.clone(),
remote_addr: None,
};
server_ctx.set_socket(socket_handle).await?;
server_ctx.start_listening().await?;
if self.config.mode == SecurityMode::DtlsSrtp {
server_ctx.start_packet_handler().await?;
}
self.server_context = Some(server_ctx.clone());
Ok(server_ctx)
}
pub async fn setup_client(
&mut self,
remote_addr: SocketAddr,
) -> Result<Arc<dyn ClientSecurityContext>, SecurityError> {
let client_security_config = match self.config.mode {
SecurityMode::None => {
return Err(SecurityError::Configuration(
"Cannot set up security for 'None' mode".to_string(),
));
}
SecurityMode::Srtp => {
crate::api::client::security::ClientSecurityConfig {
security_mode: SecurityMode::Srtp,
fingerprint_algorithm: self.config.fingerprint_algorithm.clone(),
remote_fingerprint: None,
remote_fingerprint_algorithm: None,
validate_fingerprint: false,
srtp_profiles: self.config.srtp_profiles.clone(),
certificate_path: None,
private_key_path: None,
srtp_key: self.config.srtp_key.clone(),
}
}
SecurityMode::DtlsSrtp => {
crate::api::client::security::ClientSecurityConfig {
security_mode: SecurityMode::DtlsSrtp,
fingerprint_algorithm: self.config.fingerprint_algorithm.clone(),
remote_fingerprint: self.config.remote_fingerprint.clone(),
remote_fingerprint_algorithm: self.config.remote_fingerprint_algorithm.clone(),
validate_fingerprint: true,
srtp_profiles: self.config.srtp_profiles.clone(),
certificate_path: self.config.certificate_path.clone(),
private_key_path: self.config.private_key_path.clone(),
srtp_key: None, }
}
SecurityMode::SdesSrtp | SecurityMode::MikeySrtp | SecurityMode::ZrtpSrtp => {
return Err(SecurityError::Configuration(
"SIP-derived SRTP methods should use SecurityContextManager".to_string(),
));
}
};
let client_ctx = DefaultClientSecurityContext::new(client_security_config).await?;
let local_addr = SocketAddr::new(remote_addr.ip(), 0); let socket =
Arc::new(UdpSocket::bind(local_addr).await.map_err(|e| {
SecurityError::Configuration(format!("Failed to bind socket: {}", e))
})?);
let socket_handle = SocketHandle {
socket: socket.clone(),
remote_addr: Some(remote_addr),
};
client_ctx.set_socket(socket_handle).await?;
client_ctx.set_remote_address(remote_addr).await?;
client_ctx.initialize().await?;
self.client_context = Some(client_ctx.clone());
Ok(client_ctx)
}
pub async fn setup_client_with_socket(
&mut self,
socket: Arc<UdpSocket>,
remote_addr: SocketAddr,
) -> Result<Arc<dyn ClientSecurityContext>, SecurityError> {
let client_security_config = match self.config.mode {
SecurityMode::None => {
return Err(SecurityError::Configuration(
"Cannot set up security for 'None' mode".to_string(),
));
}
SecurityMode::Srtp => {
crate::api::client::security::ClientSecurityConfig {
security_mode: SecurityMode::Srtp,
fingerprint_algorithm: self.config.fingerprint_algorithm.clone(),
remote_fingerprint: None,
remote_fingerprint_algorithm: None,
validate_fingerprint: false,
srtp_profiles: self.config.srtp_profiles.clone(),
certificate_path: None,
private_key_path: None,
srtp_key: self.config.srtp_key.clone(),
}
}
SecurityMode::DtlsSrtp => {
crate::api::client::security::ClientSecurityConfig {
security_mode: SecurityMode::DtlsSrtp,
fingerprint_algorithm: self.config.fingerprint_algorithm.clone(),
remote_fingerprint: self.config.remote_fingerprint.clone(),
remote_fingerprint_algorithm: self.config.remote_fingerprint_algorithm.clone(),
validate_fingerprint: true,
srtp_profiles: self.config.srtp_profiles.clone(),
certificate_path: self.config.certificate_path.clone(),
private_key_path: self.config.private_key_path.clone(),
srtp_key: None, }
}
SecurityMode::SdesSrtp | SecurityMode::MikeySrtp | SecurityMode::ZrtpSrtp => {
return Err(SecurityError::Configuration(
"SIP-derived SRTP methods should use SecurityContextManager".to_string(),
));
}
};
let client_ctx = DefaultClientSecurityContext::new(client_security_config).await?;
let socket_handle = SocketHandle {
socket: socket.clone(),
remote_addr: Some(remote_addr),
};
client_ctx.set_socket(socket_handle).await?;
client_ctx.set_remote_address(remote_addr).await?;
client_ctx.initialize().await?;
self.client_context = Some(client_ctx.clone());
Ok(client_ctx)
}
pub async fn perform_handshake(
&self,
remote_fingerprint: Option<String>,
) -> Result<(), SecurityError> {
if self.config.mode != SecurityMode::DtlsSrtp {
return Err(SecurityError::Configuration(
"Handshake only applicable for DTLS-SRTP mode".to_string(),
));
}
let client_ctx = match &self.client_context {
Some(ctx) => ctx,
None => {
return Err(SecurityError::NotInitialized(
"Client context not initialized".to_string(),
))
}
};
let server_ctx = match &self.server_context {
Some(ctx) => ctx,
None => {
return self
.perform_client_handshake(client_ctx, remote_fingerprint)
.await;
}
};
println!("SecurityManager: Performing local handshake (client and server in same process)");
if let Some(fingerprint) =
remote_fingerprint.or_else(|| self.config.remote_fingerprint.clone())
{
let algorithm = self
.config
.remote_fingerprint_algorithm
.clone()
.unwrap_or_else(|| self.config.fingerprint_algorithm.clone());
client_ctx
.set_remote_fingerprint(&fingerprint, &algorithm)
.await?;
}
println!("SecurityManager: Starting server packet handler");
server_ctx.start_packet_handler().await?;
if !server_ctx.is_ready().await? {
println!("SecurityManager: Waiting for server to be ready...");
let max_attempts = 30; for _ in 0..max_attempts {
if server_ctx.is_ready().await? {
break;
}
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
}
if !server_ctx.is_ready().await? {
return Err(SecurityError::Timeout(
"Server not ready after waiting".to_string(),
));
}
}
println!("SecurityManager: Server is ready to receive handshake messages");
println!("SecurityManager: Starting client packet handler");
client_ctx.start_packet_handler().await?;
if !client_ctx.is_ready().await? {
println!("SecurityManager: Waiting for client to be ready...");
let max_attempts = 30; for _ in 0..max_attempts {
if client_ctx.is_ready().await? {
break;
}
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
}
if !client_ctx.is_ready().await? {
return Err(SecurityError::Timeout(
"Client not ready after waiting".to_string(),
));
}
}
println!("SecurityManager: Client is ready to start handshake");
println!("SecurityManager: Starting client handshake");
client_ctx.start_handshake().await?;
let start_time = std::time::Instant::now();
let handshake_timeout = std::time::Duration::from_secs(15);
println!("SecurityManager: Waiting for handshake to complete");
while !client_ctx.is_handshake_complete().await? {
if start_time.elapsed() > handshake_timeout {
return Err(SecurityError::Timeout(
"Handshake timed out after 15 seconds".to_string(),
));
}
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
let elapsed_secs = start_time.elapsed().as_secs();
if elapsed_secs > 0 && elapsed_secs % 5 == 0 {
println!(
"SecurityManager: Handshake in progress... ({:?} elapsed)",
start_time.elapsed()
);
}
}
println!("SecurityManager: DTLS handshake completed successfully");
return Ok(());
}
async fn perform_client_handshake(
&self,
client_ctx: &Arc<dyn ClientSecurityContext>,
remote_fingerprint: Option<String>,
) -> Result<(), SecurityError> {
if let Some(fingerprint) =
remote_fingerprint.or_else(|| self.config.remote_fingerprint.clone())
{
let algorithm = self
.config
.remote_fingerprint_algorithm
.clone()
.unwrap_or_else(|| self.config.fingerprint_algorithm.clone());
client_ctx
.set_remote_fingerprint(&fingerprint, &algorithm)
.await?;
}
println!("SecurityManager: Starting client packet handler");
client_ctx.start_packet_handler().await?;
if !client_ctx.is_ready().await? {
println!("SecurityManager: Waiting for client to be ready...");
let max_attempts = 30; for _ in 0..max_attempts {
if client_ctx.is_ready().await? {
break;
}
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
}
if !client_ctx.is_ready().await? {
return Err(SecurityError::Timeout(
"Client not ready after waiting".to_string(),
));
}
}
println!("SecurityManager: Client is ready to start handshake");
println!("SecurityManager: Starting client handshake");
client_ctx.start_handshake().await?;
let start_time = std::time::Instant::now();
let handshake_timeout = std::time::Duration::from_secs(15);
println!("SecurityManager: Waiting for handshake to complete");
while !client_ctx.is_handshake_complete().await? {
if start_time.elapsed() > handshake_timeout {
return Err(SecurityError::Timeout(
"Handshake timed out after 15 seconds".to_string(),
));
}
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
let elapsed_secs = start_time.elapsed().as_secs();
if elapsed_secs > 0 && elapsed_secs % 5 == 0 {
println!(
"SecurityManager: Handshake in progress... ({:?} elapsed)",
start_time.elapsed()
);
}
}
println!("SecurityManager: DTLS handshake completed successfully");
return Ok(());
}
pub async fn get_client_fingerprint(&self) -> Result<String, SecurityError> {
match &self.client_context {
Some(ctx) => ctx.get_fingerprint().await,
None => Err(SecurityError::NotInitialized(
"Client context not initialized".to_string(),
)),
}
}
pub async fn get_server_fingerprint(&self) -> Result<String, SecurityError> {
match &self.server_context {
Some(ctx) => ctx.get_fingerprint().await,
None => Err(SecurityError::NotInitialized(
"Server context not initialized".to_string(),
)),
}
}
}