use async_trait::async_trait;
use std::any::Any;
use std::net::SocketAddr;
use crate::api::common::config::{SecurityInfo, SecurityMode, SrtpProfile};
use crate::api::common::error::SecurityError;
use crate::api::server::security::SocketHandle;
use crate::dtls::{DtlsConfig, DtlsRole};
pub mod default;
pub mod dtls;
pub mod fingerprint;
pub mod packet;
pub mod srtp;
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;
}