use std::ffi::CStr;
use std::os::raw::c_char;
use std::path::PathBuf;
use crate::HddsError;
pub(crate) struct SecurityConfigInner {
pub identity_certificate: Option<PathBuf>,
pub private_key: Option<PathBuf>,
pub ca_certificates: Option<PathBuf>,
pub governance_xml: Option<PathBuf>,
pub permissions_xml: Option<PathBuf>,
pub enable_encryption: bool,
pub enable_audit_log: bool,
pub audit_log_path: Option<PathBuf>,
pub require_authentication: bool,
pub check_certificate_revocation: bool,
}
impl SecurityConfigInner {
fn new() -> Self {
Self {
identity_certificate: None,
private_key: None,
ca_certificates: None,
governance_xml: None,
permissions_xml: None,
enable_encryption: false,
enable_audit_log: false,
audit_log_path: None,
require_authentication: true,
check_certificate_revocation: false,
}
}
}
#[repr(C)]
pub struct HddsSecurityConfig {
_private: [u8; 0],
}
#[no_mangle]
pub unsafe extern "C" fn hdds_security_config_create() -> *mut HddsSecurityConfig {
let inner = SecurityConfigInner::new();
Box::into_raw(Box::new(inner)).cast::<HddsSecurityConfig>()
}
#[no_mangle]
pub unsafe extern "C" fn hdds_security_config_destroy(config: *mut HddsSecurityConfig) {
if !config.is_null() {
let _ = Box::from_raw(config.cast::<SecurityConfigInner>());
}
}
#[no_mangle]
pub unsafe extern "C" fn hdds_security_config_set_identity_cert(
config: *mut HddsSecurityConfig,
path: *const c_char,
) -> HddsError {
if config.is_null() || path.is_null() {
return HddsError::HddsInvalidArgument;
}
let Ok(path_str) = CStr::from_ptr(path).to_str() else {
return HddsError::HddsInvalidArgument;
};
let inner = &mut *config.cast::<SecurityConfigInner>();
inner.identity_certificate = Some(PathBuf::from(path_str));
HddsError::HddsOk
}
#[no_mangle]
pub unsafe extern "C" fn hdds_security_config_set_private_key(
config: *mut HddsSecurityConfig,
path: *const c_char,
) -> HddsError {
if config.is_null() || path.is_null() {
return HddsError::HddsInvalidArgument;
}
let Ok(path_str) = CStr::from_ptr(path).to_str() else {
return HddsError::HddsInvalidArgument;
};
let inner = &mut *config.cast::<SecurityConfigInner>();
inner.private_key = Some(PathBuf::from(path_str));
HddsError::HddsOk
}
#[no_mangle]
pub unsafe extern "C" fn hdds_security_config_set_ca_cert(
config: *mut HddsSecurityConfig,
path: *const c_char,
) -> HddsError {
if config.is_null() || path.is_null() {
return HddsError::HddsInvalidArgument;
}
let Ok(path_str) = CStr::from_ptr(path).to_str() else {
return HddsError::HddsInvalidArgument;
};
let inner = &mut *config.cast::<SecurityConfigInner>();
inner.ca_certificates = Some(PathBuf::from(path_str));
HddsError::HddsOk
}
#[no_mangle]
pub unsafe extern "C" fn hdds_security_config_set_governance_xml(
config: *mut HddsSecurityConfig,
path: *const c_char,
) -> HddsError {
if config.is_null() || path.is_null() {
return HddsError::HddsInvalidArgument;
}
let Ok(path_str) = CStr::from_ptr(path).to_str() else {
return HddsError::HddsInvalidArgument;
};
let inner = &mut *config.cast::<SecurityConfigInner>();
inner.governance_xml = Some(PathBuf::from(path_str));
HddsError::HddsOk
}
#[no_mangle]
pub unsafe extern "C" fn hdds_security_config_set_permissions_xml(
config: *mut HddsSecurityConfig,
path: *const c_char,
) -> HddsError {
if config.is_null() || path.is_null() {
return HddsError::HddsInvalidArgument;
}
let Ok(path_str) = CStr::from_ptr(path).to_str() else {
return HddsError::HddsInvalidArgument;
};
let inner = &mut *config.cast::<SecurityConfigInner>();
inner.permissions_xml = Some(PathBuf::from(path_str));
HddsError::HddsOk
}
#[no_mangle]
pub unsafe extern "C" fn hdds_security_config_enable_encryption(
config: *mut HddsSecurityConfig,
enabled: bool,
) -> HddsError {
if config.is_null() {
return HddsError::HddsInvalidArgument;
}
let inner = &mut *config.cast::<SecurityConfigInner>();
inner.enable_encryption = enabled;
HddsError::HddsOk
}
#[no_mangle]
pub unsafe extern "C" fn hdds_security_config_enable_audit_log(
config: *mut HddsSecurityConfig,
enabled: bool,
) -> HddsError {
if config.is_null() {
return HddsError::HddsInvalidArgument;
}
let inner = &mut *config.cast::<SecurityConfigInner>();
inner.enable_audit_log = enabled;
HddsError::HddsOk
}
#[no_mangle]
pub unsafe extern "C" fn hdds_security_config_set_audit_log_path(
config: *mut HddsSecurityConfig,
path: *const c_char,
) -> HddsError {
if config.is_null() || path.is_null() {
return HddsError::HddsInvalidArgument;
}
let Ok(path_str) = CStr::from_ptr(path).to_str() else {
return HddsError::HddsInvalidArgument;
};
let inner = &mut *config.cast::<SecurityConfigInner>();
inner.audit_log_path = Some(PathBuf::from(path_str));
HddsError::HddsOk
}
#[no_mangle]
pub unsafe extern "C" fn hdds_security_config_require_authentication(
config: *mut HddsSecurityConfig,
required: bool,
) -> HddsError {
if config.is_null() {
return HddsError::HddsInvalidArgument;
}
let inner = &mut *config.cast::<SecurityConfigInner>();
inner.require_authentication = required;
HddsError::HddsOk
}
#[no_mangle]
pub unsafe extern "C" fn hdds_security_config_check_revocation(
config: *mut HddsSecurityConfig,
enabled: bool,
) -> HddsError {
if config.is_null() {
return HddsError::HddsInvalidArgument;
}
let inner = &mut *config.cast::<SecurityConfigInner>();
inner.check_certificate_revocation = enabled;
HddsError::HddsOk
}
#[cfg(test)]
mod tests {
use super::*;
use std::ffi::CString;
use std::ptr;
#[test]
fn test_security_config_create_destroy() {
unsafe {
let config = hdds_security_config_create();
assert!(!config.is_null());
hdds_security_config_destroy(config);
}
}
#[test]
fn test_security_config_null_safety() {
unsafe {
hdds_security_config_destroy(ptr::null_mut());
assert_eq!(
hdds_security_config_set_identity_cert(ptr::null_mut(), ptr::null()),
HddsError::HddsInvalidArgument,
);
assert_eq!(
hdds_security_config_set_private_key(ptr::null_mut(), ptr::null()),
HddsError::HddsInvalidArgument,
);
assert_eq!(
hdds_security_config_set_ca_cert(ptr::null_mut(), ptr::null()),
HddsError::HddsInvalidArgument,
);
assert_eq!(
hdds_security_config_enable_encryption(ptr::null_mut(), true),
HddsError::HddsInvalidArgument,
);
}
}
#[test]
fn test_security_config_setters() {
unsafe {
let config = hdds_security_config_create();
let cert = CString::new("/certs/participant1.pem").unwrap();
let key = CString::new("/certs/participant1_key.pem").unwrap();
let ca = CString::new("/certs/ca.pem").unwrap();
let gov = CString::new("/certs/governance.xml").unwrap();
let perms = CString::new("/certs/permissions.xml").unwrap();
let audit = CString::new("/var/log/hdds_audit.log").unwrap();
assert_eq!(
hdds_security_config_set_identity_cert(config, cert.as_ptr()),
HddsError::HddsOk,
);
assert_eq!(
hdds_security_config_set_private_key(config, key.as_ptr()),
HddsError::HddsOk,
);
assert_eq!(
hdds_security_config_set_ca_cert(config, ca.as_ptr()),
HddsError::HddsOk,
);
assert_eq!(
hdds_security_config_set_governance_xml(config, gov.as_ptr()),
HddsError::HddsOk,
);
assert_eq!(
hdds_security_config_set_permissions_xml(config, perms.as_ptr()),
HddsError::HddsOk,
);
assert_eq!(
hdds_security_config_enable_encryption(config, true),
HddsError::HddsOk,
);
assert_eq!(
hdds_security_config_enable_audit_log(config, true),
HddsError::HddsOk,
);
assert_eq!(
hdds_security_config_set_audit_log_path(config, audit.as_ptr()),
HddsError::HddsOk,
);
assert_eq!(
hdds_security_config_require_authentication(config, false),
HddsError::HddsOk,
);
assert_eq!(
hdds_security_config_check_revocation(config, true),
HddsError::HddsOk,
);
let inner = &*config.cast::<SecurityConfigInner>();
assert_eq!(
inner
.identity_certificate
.as_ref()
.unwrap()
.to_str()
.unwrap(),
"/certs/participant1.pem",
);
assert_eq!(
inner.private_key.as_ref().unwrap().to_str().unwrap(),
"/certs/participant1_key.pem",
);
assert_eq!(
inner.ca_certificates.as_ref().unwrap().to_str().unwrap(),
"/certs/ca.pem",
);
assert!(inner.enable_encryption);
assert!(inner.enable_audit_log);
assert!(!inner.require_authentication);
assert!(inner.check_certificate_revocation);
hdds_security_config_destroy(config);
}
}
}