use std::sync::Arc;
use tokio::sync::Mutex;
use tracing::debug;
use crate::api::common::error::SecurityError;
use crate::api::server::security::srtp::keys;
use crate::api::server::security::util::conversion;
use crate::api::server::security::{ConnectionRole, ServerSecurityConfig, SocketHandle};
use crate::dtls::{DtlsConfig, DtlsConnection};
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)))
}