use std::fmt::Debug;
use std::sync::LazyLock;
use crate::attribute::Attribute;
use crate::error::Result;
use crate::ffdh_groups;
use crate::mechanism::{Derive, Mechanism, Mechanisms};
use crate::misc::bytes_to_vec;
use crate::object::*;
use crate::ossl::ffdh::FFDHOperation;
use crate::pkcs11::*;
pub const MIN_DH_SIZE_BITS: CK_ULONG = 2048;
pub const MAX_DH_SIZE_BITS: CK_ULONG = 8192;
static FFDH_MECHS: LazyLock<[Box<dyn Mechanism>; 2]> = LazyLock::new(|| {
[
Box::new(FFDHMechanism {
info: CK_MECHANISM_INFO {
ulMinKeySize: CK_ULONG::try_from(MIN_DH_SIZE_BITS).unwrap(),
ulMaxKeySize: CK_ULONG::try_from(MAX_DH_SIZE_BITS).unwrap(),
flags: CKF_DERIVE,
},
}),
Box::new(FFDHMechanism {
info: CK_MECHANISM_INFO {
ulMinKeySize: CK_ULONG::try_from(MIN_DH_SIZE_BITS).unwrap(),
ulMaxKeySize: CK_ULONG::try_from(MAX_DH_SIZE_BITS).unwrap(),
flags: CKF_GENERATE_KEY_PAIR,
},
}),
]
});
static PUBLIC_KEY_FACTORY: LazyLock<Box<dyn ObjectFactory>> =
LazyLock::new(|| Box::new(FFDHPubFactory::new()));
static PRIVATE_KEY_FACTORY: LazyLock<Box<dyn ObjectFactory>> =
LazyLock::new(|| Box::new(FFDHPrivFactory::new()));
pub fn register(mechs: &mut Mechanisms, ot: &mut ObjectFactories) {
mechs.add_mechanism(CKM_DH_PKCS_DERIVE, &(*FFDH_MECHS)[0]);
mechs.add_mechanism(CKM_DH_PKCS_KEY_PAIR_GEN, &(*FFDH_MECHS)[1]);
ot.add_factory(
ObjectType::new(CKO_PUBLIC_KEY, CKK_DH),
&(*PUBLIC_KEY_FACTORY),
);
ot.add_factory(
ObjectType::new(CKO_PRIVATE_KEY, CKK_DH),
&(*PRIVATE_KEY_FACTORY),
);
}
#[derive(Debug, Default)]
pub struct FFDHPubFactory {
data: ObjectFactoryData,
}
impl FFDHPubFactory {
pub fn new() -> FFDHPubFactory {
let mut factory: FFDHPubFactory = Default::default();
factory.add_common_public_key_attrs();
let attributes = factory.data.get_attributes_mut();
attributes.push(attr_element!(
CKA_PRIME; OAFlags::AlwaysRequired | OAFlags::Unchangeable;
Attribute::from_bytes; val Vec::new()));
attributes.push(attr_element!(
CKA_BASE; OAFlags::AlwaysRequired | OAFlags::Unchangeable;
Attribute::from_bytes; val Vec::new()));
attributes.push(attr_element!(
CKA_VALUE; OAFlags::RequiredOnCreate
| OAFlags::SettableOnlyOnCreate | OAFlags::Unchangeable;
Attribute::from_bytes; val Vec::new()));
factory.data.finalize();
factory
}
}
impl ObjectFactory for FFDHPubFactory {
fn create(&self, template: &[CK_ATTRIBUTE]) -> Result<Object> {
let obj = self.default_object_create(template)?;
let _ = ffdh_groups::get_group_name(&obj)?;
Ok(obj)
}
fn get_data(&self) -> &ObjectFactoryData {
&self.data
}
fn get_data_mut(&mut self) -> &mut ObjectFactoryData {
&mut self.data
}
}
impl CommonKeyFactory for FFDHPubFactory {}
impl PubKeyFactory for FFDHPubFactory {}
#[derive(Debug, Default)]
pub struct FFDHPrivFactory {
data: ObjectFactoryData,
}
impl FFDHPrivFactory {
pub fn new() -> FFDHPrivFactory {
let mut factory: FFDHPrivFactory = Default::default();
factory.add_common_private_key_attrs();
let attributes = factory.data.get_attributes_mut();
attributes.push(attr_element!(
CKA_PRIME; OAFlags::RequiredOnCreate | OAFlags::Unchangeable;
Attribute::from_bytes; val Vec::new()));
attributes.push(attr_element!(
CKA_BASE; OAFlags::RequiredOnCreate | OAFlags::Unchangeable;
Attribute::from_bytes; val Vec::new()));
attributes.push(attr_element!(
CKA_VALUE; OAFlags::RequiredOnCreate
| OAFlags::SettableOnlyOnCreate | OAFlags::Unchangeable;
Attribute::from_bytes; val Vec::new()));
attributes.push(attr_element!(
CKA_VALUE_BITS;
OAFlags::SettableOnlyOnCreate | OAFlags::Unchangeable;
Attribute::from_ulong; val 0));
factory.data.finalize();
factory
}
}
impl ObjectFactory for FFDHPrivFactory {
fn create(&self, template: &[CK_ATTRIBUTE]) -> Result<Object> {
let obj = self.default_object_create(template)?;
let _ = ffdh_groups::get_group_name(&obj)?;
Ok(obj)
}
fn export_for_wrapping(&self, key: &Object) -> Result<Vec<u8>> {
PrivKeyFactory::export_for_wrapping(self, key)
}
fn import_from_wrapped(
&self,
data: Vec<u8>,
template: &[CK_ATTRIBUTE],
) -> Result<Object> {
PrivKeyFactory::import_from_wrapped(self, data, template)
}
fn get_data(&self) -> &ObjectFactoryData {
&self.data
}
fn get_data_mut(&mut self) -> &mut ObjectFactoryData {
&mut self.data
}
}
impl CommonKeyFactory for FFDHPrivFactory {}
impl PrivKeyFactory for FFDHPrivFactory {}
#[derive(Debug)]
pub struct FFDHMechanism {
info: CK_MECHANISM_INFO,
}
impl Mechanism for FFDHMechanism {
fn info(&self) -> &CK_MECHANISM_INFO {
&self.info
}
fn derive_operation(&self, mech: &CK_MECHANISM) -> Result<Box<dyn Derive>> {
if self.info.flags & CKF_DERIVE != CKF_DERIVE {
return Err(CKR_MECHANISM_INVALID)?;
}
let kdf = match mech.mechanism {
CKM_DH_PKCS_DERIVE => {
let peerpub =
bytes_to_vec!(mech.pParameter, mech.ulParameterLen);
FFDHOperation::derive_new(mech.mechanism, peerpub)?
}
_ => return Err(CKR_MECHANISM_INVALID)?,
};
Ok(Box::new(kdf))
}
fn generate_keypair(
&self,
mech: &CK_MECHANISM,
pubkey_template: &[CK_ATTRIBUTE],
prikey_template: &[CK_ATTRIBUTE],
) -> Result<(Object, Object)> {
let mut pubkey =
PUBLIC_KEY_FACTORY.default_object_generate(pubkey_template)?;
if !pubkey.check_or_set_attr(Attribute::from_ulong(
CKA_CLASS,
CKO_PUBLIC_KEY,
))? {
return Err(CKR_TEMPLATE_INCONSISTENT)?;
}
if !pubkey
.check_or_set_attr(Attribute::from_ulong(CKA_KEY_TYPE, CKK_DH))?
{
return Err(CKR_TEMPLATE_INCONSISTENT)?;
}
let mut privkey =
PRIVATE_KEY_FACTORY.default_object_generate(prikey_template)?;
if !privkey.check_or_set_attr(Attribute::from_ulong(
CKA_CLASS,
CKO_PRIVATE_KEY,
))? {
return Err(CKR_TEMPLATE_INCONSISTENT)?;
}
if !privkey
.check_or_set_attr(Attribute::from_ulong(CKA_KEY_TYPE, CKK_DH))?
{
return Err(CKR_TEMPLATE_INCONSISTENT)?;
}
let prime = match pubkey.get_attr_as_bytes(CKA_PRIME) {
Ok(p) => p.clone(),
Err(_) => return Err(CKR_ATTRIBUTE_VALUE_INVALID)?,
};
if !privkey
.check_or_set_attr(Attribute::from_bytes(CKA_PRIME, prime))?
{
return Err(CKR_TEMPLATE_INCONSISTENT)?;
}
let base = match pubkey.get_attr_as_bytes(CKA_BASE) {
Ok(b) => b.clone(),
Err(_) => return Err(CKR_ATTRIBUTE_VALUE_INVALID)?,
};
if !privkey.check_or_set_attr(Attribute::from_bytes(CKA_BASE, base))? {
return Err(CKR_TEMPLATE_INCONSISTENT)?;
}
let group = ffdh_groups::get_group_name(&privkey)?;
FFDHOperation::generate_keypair(group, &mut pubkey, &mut privkey)?;
default_key_attributes(&mut privkey, mech.mechanism)?;
default_key_attributes(&mut pubkey, mech.mechanism)?;
Ok((pubkey, privkey))
}
}