use std::ffi::{c_char, CStr};
use crate::config::Config;
use crate::error::Result;
use crate::log_debug;
use crate::pkcs11::*;
use crate::slot::Slot;
use crate::STATE;
#[inline(always)]
fn initialize(init_args: CK_VOID_PTR) -> Result<()> {
let mut conf = crate::CONFIG.wlock()?;
if !init_args.is_null() {
let args = unsafe { *(init_args as *const CK_C_INITIALIZE_ARGS) };
if !args.pReserved.is_null() {
let reserved =
unsafe { CStr::from_ptr(args.pReserved as *const _) };
let init_arg = match reserved.to_str() {
Ok(s) => s,
Err(_) => return Err(CKR_ARGUMENTS_BAD)?,
};
conf.from_init_args(init_arg)?;
}
}
if conf.slots.is_empty() {
match Config::default_config() {
Ok(defconf) => *conf = defconf,
Err(_) => return Err(CKR_TOKEN_NOT_PRESENT)?,
}
}
conf.load_env_vars_overrides();
let mut wstate = STATE.wlock_noinitcheck()?;
let mut already_init = false;
if wstate.is_initialized() {
already_init = true;
} else {
wstate.initialize();
}
for slot in &conf.slots {
let slotnum =
CK_SLOT_ID::try_from(slot.slot).map_err(|_| CKR_GENERAL_ERROR)?;
match Slot::new(slot) {
Ok(s) => match wstate.add_slot(slotnum, s) {
Ok(_) => (),
Err(e) => {
let rv = e.rv();
if rv != CKR_CRYPTOKI_ALREADY_INITIALIZED {
return Err(e)?;
}
already_init = true;
}
},
Err(e) => return Err(e)?,
}
}
if already_init {
return Err(CKR_CRYPTOKI_ALREADY_INITIALIZED)?;
}
Ok(())
}
pub extern "C" fn fn_initialize(init_args: CK_VOID_PTR) -> CK_RV {
log_debug!("C_Initialize: init_args={:?}", init_args);
let rv = match initialize(init_args) {
Ok(()) => CKR_OK,
Err(e) => e.rv(),
};
log_debug!("C_Initialize: ret={}", rv);
rv
}
#[inline(always)]
fn finalize(_reserved: CK_VOID_PTR) -> Result<()> {
let ret = STATE.wlock()?.finalize();
let mut conf = crate::CONFIG.wlock()?;
*conf = Config::new();
if ret != CKR_OK {
return Err(ret)?;
}
Ok(())
}
pub extern "C" fn fn_finalize(reserved: CK_VOID_PTR) -> CK_RV {
log_debug!("C_Finalize: reserved={:?}", reserved);
let rv = match finalize(reserved) {
Ok(()) => CKR_OK,
Err(e) => e.rv(),
};
log_debug!("C_Finalize: ret={}", rv);
rv
}
#[inline(always)]
fn get_info(info: CK_INFO_PTR) -> Result<()> {
if info.is_null() {
return Err(CKR_ARGUMENTS_BAD)?;
}
unsafe {
*info = crate::MODULE_INFO;
}
Ok(())
}
pub extern "C" fn fn_get_info(info: CK_INFO_PTR) -> CK_RV {
log_debug!("C_GetInfo: info={:?}", info);
let rv = match get_info(info) {
Ok(()) => CKR_OK,
Err(e) => e.rv(),
};
log_debug!("C_GetInfo: ret={}", rv);
rv
}
#[inline(always)]
fn get_function_list(fnlist: CK_FUNCTION_LIST_PTR_PTR) -> Result<()> {
if fnlist.is_null() {
return Err(CKR_ARGUMENTS_BAD)?;
}
unsafe {
*fnlist = &crate::FNLIST_240 as *const _ as *mut _;
};
Ok(())
}
pub extern "C" fn fn_get_function_list(
fnlist: CK_FUNCTION_LIST_PTR_PTR,
) -> CK_RV {
log_debug!("C_GetFunctionList: fnlist={:?}", fnlist);
let rv = match get_function_list(fnlist) {
Ok(()) => CKR_OK,
Err(e) => e.rv(),
};
log_debug!("C_GetFunctionList: ret={}", rv);
rv
}
#[inline(always)]
fn get_interface_list(
interfaces_list: CK_INTERFACE_PTR,
count: CK_ULONG_PTR,
) -> Result<()> {
if count.is_null() {
return Err(CKR_ARGUMENTS_BAD)?;
}
let iflen = CK_ULONG::try_from((*crate::INTERFACE_SET).len())
.map_err(|_| CKR_GENERAL_ERROR)?;
if interfaces_list.is_null() {
unsafe {
*count = iflen;
}
return Ok(());
}
unsafe {
if *count < iflen {
return Err(CKR_BUFFER_TOO_SMALL)?;
}
}
for i in 0..(*crate::INTERFACE_SET).len() {
let offset = isize::try_from(i).map_err(|_| CKR_GENERAL_ERROR)?;
unsafe {
core::ptr::write(
interfaces_list.offset(offset) as *mut CK_INTERFACE,
*((*crate::INTERFACE_SET)[i].interface),
);
}
}
unsafe {
*count = iflen;
}
Ok(())
}
pub extern "C" fn fn_get_interface_list(
interfaces_list: CK_INTERFACE_PTR,
count: CK_ULONG_PTR,
) -> CK_RV {
log_debug!(
"C_GetInterfaceList: interfaces_list={:?} count={:?}",
interfaces_list,
count
);
let rv = match get_interface_list(interfaces_list, count) {
Ok(()) => CKR_OK,
Err(e) => e.rv(),
};
log_debug!("C_GetInterfaceList: ret={}", rv);
rv
}
#[inline(always)]
fn get_interface(
interface_name: CK_UTF8CHAR_PTR,
version: CK_VERSION_PTR,
interface: CK_INTERFACE_PTR_PTR,
flags: CK_FLAGS,
) -> Result<()> {
if interface.is_null() {
return Err(CKR_ARGUMENTS_BAD)?;
}
if flags != 0 {
return Err(CKR_ARGUMENTS_BAD)?;
}
let ver: CK_VERSION = if version.is_null() {
crate::IMPLEMENTED_VERSION
} else {
unsafe { *version }
};
let request_name: *const CK_UTF8CHAR = if interface_name.is_null() {
crate::INTERFACE_NAME_STD_NUL.as_ptr()
} else {
interface_name
};
for intf in (*crate::INTERFACE_SET).iter() {
let found: bool = unsafe {
let name = (*intf.interface).pInterfaceName as *const c_char;
libc::strcmp(request_name as *const c_char, name) == 0
};
if found {
if ver.major != intf.version.major {
continue;
}
if ver.minor != intf.version.minor {
continue;
}
unsafe { *interface = intf.interface as *mut _ }
return Ok(());
}
}
Err(CKR_ARGUMENTS_BAD)?
}
pub extern "C" fn fn_get_interface(
interface_name: CK_UTF8CHAR_PTR,
version: CK_VERSION_PTR,
interface: CK_INTERFACE_PTR_PTR,
flags: CK_FLAGS,
) -> CK_RV {
log_debug!(
"C_GetInterface: interface_name={:?} version={:?} interface={:?} flags={}",
interface_name,
version,
interface,
flags
);
let rv = match get_interface(interface_name, version, interface, flags) {
Ok(()) => CKR_OK,
Err(e) => e.rv(),
};
log_debug!("C_GetInterface: ret={}", rv);
rv
}