use std::net::SocketAddr;
use std::sync::Arc;
use tokio::sync::Mutex;
use tracing::{debug, error, warn};
use crate::api::common::error::SecurityError;
use crate::api::common::config::{SrtpProfile};
use crate::api::server::security::{ServerSecurityConfig, SocketHandle, ConnectionConfig, ConnectionRole};
use crate::dtls::{DtlsConnection, DtlsConfig, DtlsRole};
use crate::api::server::security::srtp::keys;
use crate::api::server::security::util::conversion;
pub async fn create_server_connection(
config: &ServerSecurityConfig,
) -> Result<DtlsConnection, SecurityError> {
let dtls_config = DtlsConfig {
role: conversion::role_to_dtls_role(ConnectionRole::Server),
version: crate::dtls::DtlsVersion::Dtls12,
mtu: 1500,
max_retransmissions: 5,
srtp_profiles: keys::convert_profiles(&config.srtp_profiles),
};
let connection = DtlsConnection::new(dtls_config);
let cert = if let (Some(cert_path), Some(key_path)) = (&config.certificate_path, &config.private_key_path) {
debug!("Loading certificate from {} and key from {}", cert_path, key_path);
let cert_data = match std::fs::read_to_string(cert_path) {
Ok(data) => data,
Err(e) => return Err(SecurityError::Configuration(
format!("Failed to read certificate file {}: {}", cert_path, e)
))
};
let key_data = match std::fs::read_to_string(key_path) {
Ok(data) => data,
Err(e) => return Err(SecurityError::Configuration(
format!("Failed to read private key file {}: {}", key_path, e)
))
};
debug!("PEM files found but using generated certificate for now");
match crate::dtls::crypto::verify::generate_self_signed_certificate() {
Ok(cert) => cert,
Err(e) => return Err(SecurityError::Configuration(
format!("Failed to generate certificate: {}", e)
))
}
} else {
debug!("Generating self-signed certificate with proper crypto parameters");
match crate::dtls::crypto::verify::generate_self_signed_certificate() {
Ok(cert) => cert,
Err(e) => return Err(SecurityError::Configuration(
format!("Failed to generate certificate: {}", e)
))
}
};
Ok(connection)
}
pub async fn initialize_connection_template(
config: &ServerSecurityConfig,
connection_template: &Arc<Mutex<Option<DtlsConnection>>>,
) -> Result<(), SecurityError> {
if config.srtp_profiles.is_empty() {
return Err(SecurityError::Configuration("No SRTP profiles specified in server config".to_string()));
}
let mut connection = create_server_connection(config).await?;
let cert = if let (Some(cert_path), Some(key_path)) = (&config.certificate_path, &config.private_key_path) {
debug!("Loading certificate from {} and key from {}", cert_path, key_path);
match crate::dtls::crypto::verify::generate_self_signed_certificate() {
Ok(cert) => cert,
Err(e) => return Err(SecurityError::Configuration(
format!("Failed to generate certificate: {}", e)
))
}
} else {
debug!("Generating self-signed certificate");
match crate::dtls::crypto::verify::generate_self_signed_certificate() {
Ok(cert) => cert,
Err(e) => return Err(SecurityError::Configuration(
format!("Failed to generate certificate: {}", e)
))
}
};
connection.set_certificate(cert);
let mut template = connection_template.lock().await;
*template = Some(connection);
Ok(())
}
pub async fn get_fingerprint_from_connection(
connection: &DtlsConnection,
) -> Result<String, SecurityError> {
if let Some(cert) = connection.local_certificate() {
let mut cert_copy = cert.clone();
match cert_copy.fingerprint("SHA-256") {
Ok(fingerprint) => Ok(fingerprint),
Err(e) => Err(SecurityError::Internal(format!("Failed to get fingerprint: {}", e))),
}
} else {
Err(SecurityError::Configuration("No certificate available".to_string()))
}
}
pub async fn create_dtls_transport(
socket: &SocketHandle,
) -> Result<Arc<Mutex<crate::dtls::transport::udp::UdpTransport>>, SecurityError> {
let transport = match crate::dtls::transport::udp::UdpTransport::new(socket.socket.clone(), 1500).await {
Ok(mut t) => {
if let Err(e) = t.start().await {
return Err(SecurityError::Configuration(format!("Failed to start DTLS transport: {}", e)));
}
t
},
Err(e) => return Err(SecurityError::Configuration(format!("Failed to create DTLS transport: {}", e))),
};
Ok(Arc::new(Mutex::new(transport)))
}