use crate::ffi::errors::{ErrorHandle, Status};
use crate::ffi::{borrow, borrow_text, Buffer, Slice};
use crate::tls::{EchConfigList, EchKeys, Identity};
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_identity_new(certificates: *const Slice, certificate_count: usize, key: *const u8, key_len: usize) -> *mut Identity {
if certificates.is_null() {
return std::ptr::null_mut();
}
let Some(key) = (unsafe { borrow(key, key_len) }) else {
return std::ptr::null_mut();
};
let mut chain = Vec::with_capacity(certificate_count);
for index in 0..certificate_count {
let slice = unsafe { *certificates.add(index) };
let Some(blob) = (unsafe { borrow(slice.data, slice.len) }) else {
return std::ptr::null_mut();
};
chain.push(blob.to_vec());
}
Box::into_raw(Box::new(Identity::new(chain, key.to_vec())))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_identity_from_pkcs12(data: *const u8, data_len: usize, passphrase: *const u8, passphrase_len: usize, out: *mut *mut Identity, error: *mut *mut ErrorHandle) -> Status {
if out.is_null() {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
}
let (Some(data), Some(passphrase)) = (unsafe { borrow(data, data_len) }, unsafe { borrow_text(passphrase, passphrase_len) }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
match Identity::from_pkcs12(data, passphrase) {
Ok(identity) => {
unsafe { *out = Box::into_raw(Box::new(identity)) };
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_identity_free(identity: *mut Identity) {
if !identity.is_null() {
drop(unsafe { Box::from_raw(identity) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_ech_keys_generate(public_name: *const u8, public_name_len: usize, config_id: u8, out: *mut *mut EchKeys, error: *mut *mut ErrorHandle) -> Status {
if out.is_null() {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
}
let Some(public_name) = (unsafe { borrow_text(public_name, public_name_len) }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
if public_name.len() > 255 {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
}
match EchKeys::generate(public_name, config_id) {
Ok(keys) => {
unsafe { *out = Box::into_raw(Box::new(keys)) };
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_ech_keys_new(config: *const u8, config_len: usize, private_key: *const u8, private_key_len: usize) -> *mut EchKeys {
let (Some(config), Some(private_key)) = (unsafe { borrow(config, config_len) }, unsafe { borrow(private_key, private_key_len) }) else {
return std::ptr::null_mut();
};
Box::into_raw(Box::new(EchKeys { config: config.to_vec(), private_key: private_key.to_vec() }))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_ech_keys_free(keys: *mut EchKeys) {
if !keys.is_null() {
drop(unsafe { Box::from_raw(keys) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_ech_keys_config(keys: *const EchKeys) -> Slice {
match unsafe { keys.as_ref() } {
Some(keys) => Slice::new(&keys.config),
None => Slice::ABSENT,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_ech_keys_private_key(keys: *const EchKeys) -> Slice {
match unsafe { keys.as_ref() } {
Some(keys) => Slice::new(&keys.private_key),
None => Slice::ABSENT,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_ech_keys_config_list(keys: *const EchKeys) -> Buffer {
match unsafe { keys.as_ref() } {
Some(keys) => Buffer::new(keys.config_list()),
None => Buffer::EMPTY,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_ech_config_list_parse(data: *const u8, data_len: usize, out: *mut *mut EchConfigList, error: *mut *mut ErrorHandle) -> Status {
if out.is_null() {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
}
let Some(data) = (unsafe { borrow(data, data_len) }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
match EchConfigList::parse(data) {
Ok(list) => {
unsafe { *out = Box::into_raw(Box::new(list)) };
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_ech_config_list_free(list: *mut EchConfigList) {
if !list.is_null() {
drop(unsafe { Box::from_raw(list) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_ech_config_list_count(list: *const EchConfigList) -> usize {
unsafe { list.as_ref() }.map_or(0, |list| list.configs.len())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_ech_config_version(list: *const EchConfigList, index: usize) -> u16 {
unsafe { list.as_ref() }.and_then(|list| list.configs.get(index)).map_or(0, |config| config.version)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_ech_config_public_name(list: *const EchConfigList, index: usize) -> Slice {
Slice::maybe(unsafe { list.as_ref() }.and_then(|list| list.configs.get(index)).map(|config| config.public_name.as_str()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_ech_config_maximum_name_length(list: *const EchConfigList, index: usize) -> i32 {
unsafe { list.as_ref() }
.and_then(|list| list.configs.get(index))
.map_or(-1, |config| config.maximum_name_length as i32)
}