use std::sync::Arc;
use tokio::sync::Mutex;
use tracing::{debug, error, info};
use crate::api::common::config::SrtpProfile;
use crate::api::common::error::SecurityError;
use crate::dtls::DtlsConnection;
use crate::srtp::crypto::SrtpCryptoKey;
use crate::srtp::{
SrtpContext, SrtpCryptoSuite, SRTP_AEAD_AES_128_GCM, SRTP_AEAD_AES_256_GCM,
SRTP_AES128_CM_SHA1_32, SRTP_AES128_CM_SHA1_80,
};
pub async fn extract_srtp_keys(
connection: &Arc<Mutex<Option<DtlsConnection>>>,
srtp_context: &Arc<Mutex<Option<SrtpContext>>>,
handshake_completed: &Arc<Mutex<bool>>,
) -> Result<(), SecurityError> {
let mut conn_guard = connection.lock().await;
if let Some(conn) = conn_guard.as_mut() {
if conn.state() != crate::dtls::connection::ConnectionState::Connected {
return Err(SecurityError::HandshakeError(
"DTLS handshake not complete, cannot extract SRTP keys".to_string(),
));
}
match conn.extract_srtp_keys() {
Ok(dtls_srtp_context) => {
let client_key = dtls_srtp_context.get_key_for_role(true).clone();
debug!("Successfully extracted SRTP keys");
let profile = dtls_srtp_context.profile.clone();
match create_srtp_context(profile, client_key) {
Ok(ctx) => {
let mut srtp_guard = srtp_context.lock().await;
*srtp_guard = Some(ctx);
let mut completed = handshake_completed.lock().await;
*completed = true;
info!("DTLS handshake completed and SRTP keys extracted");
Ok(())
}
Err(e) => {
error!("Failed to create SRTP context from extracted keys: {}", e);
Err(e)
}
}
}
Err(e) => {
error!("Failed to extract SRTP keys: {}", e);
Err(SecurityError::Handshake(format!(
"Failed to extract SRTP keys: {}",
e
)))
}
}
} else {
Err(SecurityError::NotInitialized(
"DTLS connection not initialized".to_string(),
))
}
}
pub fn profile_to_suite(profile: SrtpProfile) -> SrtpCryptoSuite {
match profile {
SrtpProfile::AesCm128HmacSha1_80 => SRTP_AES128_CM_SHA1_80,
SrtpProfile::AesCm128HmacSha1_32 => SRTP_AES128_CM_SHA1_32,
SrtpProfile::AesGcm128 => SRTP_AEAD_AES_128_GCM,
SrtpProfile::AesGcm256 => SRTP_AEAD_AES_256_GCM,
}
}
pub fn create_srtp_context(
suite: SrtpCryptoSuite,
key: SrtpCryptoKey,
) -> Result<SrtpContext, SecurityError> {
match SrtpContext::new(suite, key) {
Ok(context) => Ok(context),
Err(e) => Err(SecurityError::Internal(format!(
"Failed to create SRTP context: {}",
e
))),
}
}