use std::cell::Cell;
use std::ffi::{c_char, c_int};
use crate::config::FipsBehavior;
use crate::error::Result;
use crate::mechanism::Mechanisms;
use crate::object::{ObjectFactories, ObjectType};
use crate::pkcs11::*;
use ossl::{bindings, fips};
pub(crate) mod indicators;
pub(crate) mod kats;
pub(crate) mod provider;
pub const FIPS_VALIDATION_OBJ: CK_ULONG = 1;
pub fn set_fips_error_state() {
fips::set_error_state();
}
pub fn check_fips_state_ok() -> bool {
return fips::check_state_ok();
}
pub fn register(_: &mut Mechanisms, ot: &mut ObjectFactories) {
ot.add_factory(
ObjectType::new(CKO_VALIDATION, 0),
&(*indicators::VALIDATION_FACTORY),
);
}
pub fn check_key_template(
template: &[CK_ATTRIBUTE],
fips_opts: &FipsBehavior,
) -> Result<()> {
if !fips_opts.keys_always_sensitive {
return Ok(());
}
match template.iter().find(|a| a.type_ == CKA_SENSITIVE) {
Some(a) => {
if a.to_bool()? == false {
Err(CKR_ATTRIBUTE_VALUE_INVALID)?
} else {
Ok(())
}
}
None => Ok(()),
}
}
#[used]
#[cfg_attr(target_os = "linux", unsafe(link_section = ".init_array"))]
pub static INITIALIZE_FIPS: extern "C" fn() = init_fips;
#[unsafe(no_mangle)]
pub extern "C" fn init_fips() {
provider::set_fips_indicator_callback(Some(fips_indicator_callback));
}
thread_local! {
static FIPS_INDICATOR: Cell<u32> = Cell::new(0);
}
unsafe extern "C" fn fips_indicator_callback(
_type_: *const c_char,
_desc: *const c_char,
_params: *const bindings::OSSL_PARAM,
) -> c_int {
FIPS_INDICATOR.set(1);
return 1;
}
#[derive(Debug)]
pub struct FipsApproval {
approved: Option<bool>,
}
impl FipsApproval {
fn clear_indicator() {
FIPS_INDICATOR.set(0);
}
fn check_indicator() -> bool {
FIPS_INDICATOR.get() != 0
}
pub fn init() -> FipsApproval {
Self::clear_indicator();
FipsApproval { approved: None }
}
pub fn reset(&mut self) {
self.approved = None;
}
pub fn clear(&self) {
Self::clear_indicator();
}
pub fn update(&mut self) {
if Self::check_indicator() {
self.approved = Some(false);
}
}
pub fn approval(&self) -> Option<bool> {
self.approved
}
#[allow(dead_code)]
pub fn is_approved(&self) -> bool {
if self.approved.is_some_and(|b| b == true) {
return true;
}
return false;
}
pub fn is_not_approved(&self) -> bool {
if self.approved.is_some_and(|b| b == false) {
return true;
}
return false;
}
pub fn set(&mut self, b: bool) {
if self.approved.is_some_and(|b| b == false) {
return;
}
self.approved = Some(b);
}
pub fn finalize(&mut self) {
self.update();
self.set(true);
}
}