use std::net::SocketAddr;
use std::sync::Arc;
use std::any::Any;
use async_trait::async_trait;
use tokio::net::UdpSocket;
use crate::api::common::error::SecurityError;
use crate::api::common::config::{SecurityInfo, SecurityMode, SrtpProfile};
use crate::api::server::security::SocketHandle;
use crate::dtls::{DtlsConfig, DtlsRole};
pub mod default;
pub mod dtls;
pub mod srtp;
pub mod fingerprint;
pub mod packet;
pub use default::DefaultClientSecurityContext;
#[derive(Debug, Clone)]
pub struct ClientSecurityConfig {
pub security_mode: SecurityMode,
pub fingerprint_algorithm: String,
pub remote_fingerprint: Option<String>,
pub remote_fingerprint_algorithm: Option<String>,
pub validate_fingerprint: bool,
pub srtp_profiles: Vec<SrtpProfile>,
pub certificate_path: Option<String>,
pub private_key_path: Option<String>,
pub srtp_key: Option<Vec<u8>>,
}
impl Default for ClientSecurityConfig {
fn default() -> Self {
Self {
security_mode: SecurityMode::DtlsSrtp,
fingerprint_algorithm: "sha-256".to_string(),
remote_fingerprint: None,
remote_fingerprint_algorithm: None,
validate_fingerprint: true,
srtp_profiles: vec![
SrtpProfile::AesCm128HmacSha1_80,
SrtpProfile::AesGcm128,
],
certificate_path: None,
private_key_path: None,
srtp_key: None,
}
}
}
pub(crate) fn convert_to_dtls_profile(profile: SrtpProfile) -> crate::dtls::message::extension::SrtpProtectionProfile {
match profile {
SrtpProfile::AesCm128HmacSha1_80 => crate::dtls::message::extension::SrtpProtectionProfile::Aes128CmSha1_80,
SrtpProfile::AesCm128HmacSha1_32 => crate::dtls::message::extension::SrtpProtectionProfile::Aes128CmSha1_32,
SrtpProfile::AesGcm128 => crate::dtls::message::extension::SrtpProtectionProfile::AeadAes128Gcm,
SrtpProfile::AesGcm256 => crate::dtls::message::extension::SrtpProtectionProfile::AeadAes256Gcm,
}
}
pub(crate) fn create_dtls_config(config: &ClientSecurityConfig) -> DtlsConfig {
if config.srtp_profiles.is_empty() {
panic!("No SRTP profiles specified in client security config");
}
let dtls_profiles: Vec<crate::dtls::message::extension::SrtpProtectionProfile> = config.srtp_profiles.iter()
.map(|p| convert_to_dtls_profile(*p))
.collect();
let mut dtls_config = DtlsConfig::default();
dtls_config.role = DtlsRole::Client;
let crypto_suites: Vec<crate::srtp::SrtpCryptoSuite> = dtls_profiles.iter()
.map(|profile| match profile {
&crate::dtls::message::extension::SrtpProtectionProfile::Aes128CmSha1_80 =>
crate::srtp::SRTP_AES128_CM_SHA1_80,
&crate::dtls::message::extension::SrtpProtectionProfile::Aes128CmSha1_32 =>
crate::srtp::SRTP_AES128_CM_SHA1_32,
&crate::dtls::message::extension::SrtpProtectionProfile::AeadAes128Gcm =>
crate::srtp::SRTP_AEAD_AES_128_GCM,
&crate::dtls::message::extension::SrtpProtectionProfile::AeadAes256Gcm =>
crate::srtp::SRTP_AEAD_AES_256_GCM,
&crate::dtls::message::extension::SrtpProtectionProfile::Unknown(_) =>
panic!("Unknown SRTP protection profile specified"), })
.collect();
if crypto_suites.is_empty() {
panic!("Failed to map any SRTP profiles to crypto suites");
}
dtls_config.srtp_profiles = crypto_suites;
dtls_config.mtu = 1200;
dtls_config.max_retransmissions = 5;
dtls_config
}
#[async_trait]
pub trait ClientSecurityContext: Send + Sync {
async fn initialize(&self) -> Result<(), SecurityError>;
async fn start_handshake(&self) -> Result<(), SecurityError>;
async fn is_handshake_complete(&self) -> Result<bool, SecurityError>;
async fn wait_for_handshake(&self) -> Result<(), SecurityError>;
async fn set_remote_address(&self, addr: SocketAddr) -> Result<(), SecurityError>;
async fn set_socket(&self, socket: SocketHandle) -> Result<(), SecurityError>;
async fn set_remote_fingerprint(&self, fingerprint: &str, algorithm: &str) -> Result<(), SecurityError>;
async fn complete_handshake(&self, remote_addr: SocketAddr, remote_fingerprint: &str) -> Result<(), SecurityError>;
async fn process_packet(&self, data: &[u8]) -> Result<(), SecurityError>;
async fn start_packet_handler(&self) -> Result<(), SecurityError>;
async fn get_security_info(&self) -> Result<SecurityInfo, SecurityError>;
async fn close(&self) -> Result<(), SecurityError>;
async fn is_ready(&self) -> Result<bool, SecurityError>;
fn is_secure(&self) -> bool;
fn get_security_info_sync(&self) -> SecurityInfo;
async fn get_fingerprint(&self) -> Result<String, SecurityError>;
async fn get_fingerprint_algorithm(&self) -> Result<String, SecurityError>;
async fn has_transport(&self) -> Result<bool, SecurityError>;
async fn process_dtls_packet(&self, data: &[u8]) -> Result<(), SecurityError>;
fn get_config(&self) -> &ClientSecurityConfig;
fn as_any(&self) -> &dyn Any;
}