use std::fmt::Debug;
use std::sync::LazyLock;
use crate::attribute::{Attribute, CkAttrs};
use crate::error::Result;
use crate::hash::INVALID_HASH_SIZE;
use crate::hmac::hmac_size;
use crate::mechanism::{Derive, Mac, MechOperation, Mechanism, Mechanisms};
use crate::misc::{bytes_to_vec, common_derive_key_object, zeromem};
use crate::native::hmac::HMACOperation;
use crate::object::{Object, ObjectFactories};
use crate::pkcs11::*;
static IKE_MECH: LazyLock<Box<dyn Mechanism>> = LazyLock::new(|| {
Box::new(IkeMechanism {
info: CK_MECHANISM_INFO {
ulMinKeySize: 0,
ulMaxKeySize: CK_ULONG::try_from(u32::MAX).unwrap(),
flags: CKF_DERIVE,
},
})
});
pub fn register(mechs: &mut Mechanisms, _: &mut ObjectFactories) {
for ckm in &[
CKM_IKE_PRF_DERIVE,
CKM_IKE1_PRF_DERIVE,
CKM_IKE1_EXTENDED_DERIVE,
CKM_IKE2_PRF_PLUS_DERIVE,
] {
mechs.add_mechanism(*ckm, &IKE_MECH);
}
}
fn prf_len(prf_mech: CK_MECHANISM_TYPE) -> Result<usize> {
match hmac_size(prf_mech) {
INVALID_HASH_SIZE => Err(CKR_MECHANISM_PARAM_INVALID)?,
len => Ok(len),
}
}
fn prf_key_type(prf_mech: CK_MECHANISM_TYPE) -> Result<CK_KEY_TYPE> {
match prf_mech {
CKM_SHA_1_HMAC => Ok(CKK_SHA_1_HMAC),
CKM_SHA224_HMAC => Ok(CKK_SHA224_HMAC),
CKM_SHA256_HMAC => Ok(CKK_SHA256_HMAC),
CKM_SHA384_HMAC => Ok(CKK_SHA384_HMAC),
CKM_SHA512_HMAC => Ok(CKK_SHA512_HMAC),
CKM_SHA3_224_HMAC => Ok(CKK_SHA3_224_HMAC),
CKM_SHA3_256_HMAC => Ok(CKK_SHA3_256_HMAC),
CKM_SHA3_384_HMAC => Ok(CKK_SHA3_384_HMAC),
CKM_SHA3_512_HMAC => Ok(CKK_SHA3_512_HMAC),
CKM_SHA512_224_HMAC => Ok(CKK_SHA512_224_HMAC),
CKM_SHA512_256_HMAC => Ok(CKK_SHA512_256_HMAC),
_ => Err(CKR_MECHANISM_PARAM_INVALID)?,
}
}
fn require_prf_base_key_type(
mech: CK_MECHANISM_TYPE,
key: &Object,
) -> Result<()> {
let expected = prf_key_type(mech)?;
if key.get_attr_as_ulong(CKA_KEY_TYPE)? == expected {
Ok(())
} else {
Err(CKR_KEY_TYPE_INCONSISTENT)?
}
}
fn prf(
hmac: &mut HMACOperation,
parts: &[&[u8]],
out: &mut [u8],
) -> Result<()> {
if hmac.finalized() {
hmac.reset()?;
}
for part in parts {
hmac.mac_update(part)?;
}
hmac.mac_final(out)
}
fn ike_derive_setup(
finalized: &mut bool,
prf_mech: CK_MECHANISM_TYPE,
key: &Object,
template: &[CK_ATTRIBUTE],
objfactories: &ObjectFactories,
default_len: usize,
default_key_type: Option<CK_KEY_TYPE>,
) -> Result<(Object, usize)> {
if *finalized {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
*finalized = true;
if let Some(kt) = default_key_type {
let default_class = CKO_SECRET_KEY;
let mut tmpl = CkAttrs::from(template);
tmpl.add_missing_ulong(CKA_CLASS, &default_class);
tmpl.add_missing_ulong(CKA_KEY_TYPE, &kt);
let mut obj =
objfactories.derive_key_from_template(key, tmpl.as_slice())?;
let value_len = match obj.get_attr_as_ulong(CKA_VALUE_LEN) {
Ok(val) => usize::try_from(val)?,
Err(_) => {
if default_len == 0 {
return Err(CKR_TEMPLATE_INCOMPLETE)?;
}
obj.set_attr(Attribute::from_ulong(
CKA_VALUE_LEN,
CK_ULONG::try_from(default_len)?,
))?;
default_len
}
};
Ok((obj, value_len))
} else {
common_derive_key_object(key, template, objfactories, default_len)
}
}
#[derive(Debug)]
struct IkeMechanism {
info: CK_MECHANISM_INFO,
}
impl Mechanism for IkeMechanism {
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)?;
}
match mech.mechanism {
CKM_IKE_PRF_DERIVE => Ok(Box::new(IkePrfOperation::new(mech)?)),
CKM_IKE1_PRF_DERIVE => Ok(Box::new(Ike1PrfOperation::new(mech)?)),
CKM_IKE1_EXTENDED_DERIVE => {
Ok(Box::new(Ike1ExtendedOperation::new(mech)?))
}
CKM_IKE2_PRF_PLUS_DERIVE => {
Ok(Box::new(Ike2PrfPlusOperation::new(mech)?))
}
_ => Err(CKR_MECHANISM_INVALID)?,
}
}
}
fn opt_bytes(ptr: *mut CK_BYTE, len: CK_ULONG) -> Result<Option<Vec<u8>>> {
match (ptr.is_null(), len) {
(true, 0) => Ok(None),
(true, _) | (false, 0) => Err(CKR_MECHANISM_PARAM_INVALID)?,
(false, _) => {
Ok(Some(bytes_to_vec(ptr as *const u8, usize::try_from(len)?)))
}
}
}
fn check_ni_nr(
p_a: *mut CK_BYTE,
len_a: CK_ULONG,
p_b: *mut CK_BYTE,
len_b: CK_ULONG,
min_each: usize,
) -> Result<Vec<u8>> {
let la = usize::try_from(len_a)?;
let lb = usize::try_from(len_b)?;
if p_a.is_null() || la < min_each || p_b.is_null() || lb < min_each {
return Err(CKR_MECHANISM_PARAM_INVALID)?;
}
let mut out = Vec::with_capacity(la + lb);
out.extend_from_slice(unsafe {
std::slice::from_raw_parts(p_a as *const u8, la)
});
out.extend_from_slice(unsafe {
std::slice::from_raw_parts(p_b as *const u8, lb)
});
Ok(out)
}
#[derive(Debug)]
struct IkePrfOperation {
finalized: bool,
prf: CK_MECHANISM_TYPE,
prf_len: usize,
data_as_key: bool,
ni_nr: Vec<u8>, new_key_handle: CK_OBJECT_HANDLE, new_key: Option<Vec<u8>>,
}
impl IkePrfOperation {
fn new(mech: &CK_MECHANISM) -> Result<IkePrfOperation> {
let params = mech.get_parameters::<CK_IKE_PRF_DERIVE_PARAMS>()?;
let data_as_key = params.bDataAsKey != CK_FALSE;
let rekey = params.bRekey != CK_FALSE;
if data_as_key && rekey {
return Err(CKR_MECHANISM_PARAM_INVALID)?;
}
let new_key_handle = if rekey {
if params.hNewKey == CK_INVALID_HANDLE {
return Err(CKR_MECHANISM_PARAM_INVALID)?;
}
params.hNewKey
} else {
CK_INVALID_HANDLE
};
Ok(IkePrfOperation {
finalized: false,
prf: params.prfMechanism,
prf_len: prf_len(params.prfMechanism)?,
data_as_key,
ni_nr: check_ni_nr(
params.pNi,
params.ulNiLen,
params.pNr,
params.ulNrLen,
16,
)?,
new_key_handle,
new_key: None,
})
}
}
impl Drop for IkePrfOperation {
fn drop(&mut self) {
zeromem(&mut self.ni_nr);
if let Some(ref mut v) = self.new_key {
zeromem(v);
}
}
}
impl MechOperation for IkePrfOperation {
fn mechanism(&self) -> Result<CK_MECHANISM_TYPE> {
Ok(CKM_IKE_PRF_DERIVE)
}
fn finalized(&self) -> bool {
self.finalized
}
fn requires_objects(&self) -> Result<&[CK_OBJECT_HANDLE]> {
if self.new_key_handle != CK_INVALID_HANDLE {
Ok(std::slice::from_ref(&self.new_key_handle))
} else {
Err(CKR_OK)?
}
}
fn receives_objects(&mut self, objs: &[&Object]) -> Result<()> {
if objs.len() != 1 {
return Err(CKR_GENERAL_ERROR)?;
}
if objs[0].get_attr_as_ulong(CKA_KEY_TYPE)? != CKK_GENERIC_SECRET {
return Err(CKR_KEY_TYPE_INCONSISTENT)?;
}
self.new_key = Some(objs[0].get_attr_as_bytes(CKA_VALUE)?.clone());
Ok(())
}
}
impl Derive for IkePrfOperation {
fn derive(
&mut self,
key: &Object,
template: &[CK_ATTRIBUTE],
_: &Mechanisms,
objfactories: &ObjectFactories,
) -> Result<Vec<Object>> {
if self.data_as_key {
if key.get_attr_as_ulong(CKA_KEY_TYPE)? != CKK_GENERIC_SECRET {
return Err(CKR_KEY_TYPE_INCONSISTENT)?;
}
} else {
require_prf_base_key_type(self.prf, key)?;
}
let default_key_type = prf_key_type(self.prf)?;
let (mut obj, keysize) = ike_derive_setup(
&mut self.finalized,
self.prf,
key,
template,
objfactories,
self.prf_len,
Some(default_key_type),
)?;
let key_bytes = key.get_attr_as_bytes(CKA_VALUE)?;
let mut out = vec![0u8; self.prf_len];
if self.data_as_key {
let mut hmac = HMACOperation::internal(
self.prf,
self.ni_nr.clone(),
self.prf_len,
)?;
prf(&mut hmac, &[key_bytes], &mut out)?;
} else {
let mut hmac = HMACOperation::internal(
self.prf,
key_bytes.to_vec(),
self.prf_len,
)?;
if self.new_key_handle != CK_INVALID_HANDLE {
let new_key =
self.new_key.as_deref().ok_or(CKR_GENERAL_ERROR)?;
prf(&mut hmac, &[new_key, &self.ni_nr], &mut out)?;
} else {
prf(&mut hmac, &[self.ni_nr.as_slice()], &mut out)?;
}
}
if keysize != out.len() {
return Err(CKR_TEMPLATE_INCONSISTENT)?;
}
obj.set_attr(Attribute::from_bytes(CKA_VALUE, out))?;
Ok(vec![obj])
}
}
#[derive(Debug)]
struct Ike1PrfOperation {
finalized: bool,
prf: CK_MECHANISM_TYPE,
prf_len: usize,
handles: [CK_OBJECT_HANDLE; 2],
keygxy: Option<Vec<u8>>,
prev_key: Option<Vec<u8>>,
cky: Vec<u8>, key_number: u8,
}
impl Ike1PrfOperation {
fn new(mech: &CK_MECHANISM) -> Result<Ike1PrfOperation> {
let params = mech.get_parameters::<CK_IKE1_PRF_DERIVE_PARAMS>()?;
if params.hKeygxy == CK_INVALID_HANDLE {
return Err(CKR_MECHANISM_PARAM_INVALID)?;
}
let has_prev_key = params.bHasPrevKey != CK_FALSE;
let prev_handle = if has_prev_key {
if params.hPrevKey == CK_INVALID_HANDLE {
return Err(CKR_MECHANISM_PARAM_INVALID)?;
}
params.hPrevKey
} else {
CK_INVALID_HANDLE
};
Ok(Ike1PrfOperation {
finalized: false,
prf: params.prfMechanism,
prf_len: prf_len(params.prfMechanism)?,
handles: [params.hKeygxy, prev_handle],
keygxy: None,
prev_key: None,
cky: check_ni_nr(
params.pCKYi,
params.ulCKYiLen,
params.pCKYr,
params.ulCKYrLen,
8,
)?,
key_number: params.keyNumber,
})
}
}
impl Drop for Ike1PrfOperation {
fn drop(&mut self) {
if let Some(ref mut v) = self.keygxy {
zeromem(v);
}
if let Some(ref mut v) = self.prev_key {
zeromem(v);
}
}
}
impl MechOperation for Ike1PrfOperation {
fn mechanism(&self) -> Result<CK_MECHANISM_TYPE> {
Ok(CKM_IKE1_PRF_DERIVE)
}
fn finalized(&self) -> bool {
self.finalized
}
fn requires_objects(&self) -> Result<&[CK_OBJECT_HANDLE]> {
if self.handles[1] != CK_INVALID_HANDLE {
Ok(&self.handles)
} else {
Ok(&self.handles[..1])
}
}
fn receives_objects(&mut self, objs: &[&Object]) -> Result<()> {
let expected = if self.handles[1] != CK_INVALID_HANDLE {
2
} else {
1
};
if objs.len() != expected {
return Err(CKR_GENERAL_ERROR)?;
}
if objs[0].get_attr_as_ulong(CKA_KEY_TYPE)? != CKK_GENERIC_SECRET {
return Err(CKR_KEY_TYPE_INCONSISTENT)?;
}
self.keygxy = Some(objs[0].get_attr_as_bytes(CKA_VALUE)?.clone());
if self.handles[1] != CK_INVALID_HANDLE {
self.prev_key = Some(objs[1].get_attr_as_bytes(CKA_VALUE)?.clone());
}
Ok(())
}
}
impl Derive for Ike1PrfOperation {
fn derive(
&mut self,
key: &Object,
template: &[CK_ATTRIBUTE],
_: &Mechanisms,
objfactories: &ObjectFactories,
) -> Result<Vec<Object>> {
require_prf_base_key_type(self.prf, key)?;
if !template.iter().any(|a| a.type_ == CKA_KEY_TYPE) {
return Err(CKR_TEMPLATE_INCOMPLETE)?;
}
let (mut obj, keysize) = ike_derive_setup(
&mut self.finalized,
self.prf,
key,
template,
objfactories,
self.prf_len,
None,
)?;
let gxy = match &self.keygxy {
Some(v) => v.as_slice(),
None => return Err(CKR_GENERAL_ERROR)?,
};
let key_number = [self.key_number];
let mut parts: Vec<&[u8]> = Vec::with_capacity(4);
if let Some(pk) = &self.prev_key {
parts.push(pk);
}
parts.push(gxy);
parts.push(&self.cky);
parts.push(&key_number);
if keysize > self.prf_len {
return Err(CKR_KEY_SIZE_RANGE)?;
}
let key_bytes = key.get_attr_as_bytes(CKA_VALUE)?;
let mut hmac = HMACOperation::internal(
self.prf,
key_bytes.to_vec(),
self.prf_len,
)?;
let mut out = vec![0u8; self.prf_len];
prf(&mut hmac, &parts, &mut out)?;
obj.set_attr(Attribute::from_bytes(
CKA_VALUE,
out[..keysize].to_vec(),
))?;
Ok(vec![obj])
}
}
#[derive(Debug)]
struct Ike1ExtendedOperation {
finalized: bool,
prf: CK_MECHANISM_TYPE,
prf_len: usize,
keygxy_handle: CK_OBJECT_HANDLE,
keygxy: Option<Vec<u8>>,
extra_data: Option<Vec<u8>>,
}
impl Ike1ExtendedOperation {
fn new(mech: &CK_MECHANISM) -> Result<Ike1ExtendedOperation> {
let params = mech.get_parameters::<CK_IKE1_EXTENDED_DERIVE_PARAMS>()?;
let keygxy_handle = if params.bHasKeygxy != CK_FALSE {
if params.hKeygxy == CK_INVALID_HANDLE {
return Err(CKR_MECHANISM_PARAM_INVALID)?;
}
params.hKeygxy
} else {
CK_INVALID_HANDLE
};
Ok(Ike1ExtendedOperation {
finalized: false,
prf: params.prfMechanism,
prf_len: prf_len(params.prfMechanism)?,
keygxy_handle,
keygxy: None,
extra_data: opt_bytes(params.pExtraData, params.ulExtraDataLen)?,
})
}
}
impl Drop for Ike1ExtendedOperation {
fn drop(&mut self) {
if let Some(ref mut v) = self.keygxy {
zeromem(v);
}
if let Some(ref mut v) = self.extra_data {
zeromem(v);
}
}
}
impl MechOperation for Ike1ExtendedOperation {
fn mechanism(&self) -> Result<CK_MECHANISM_TYPE> {
Ok(CKM_IKE1_EXTENDED_DERIVE)
}
fn finalized(&self) -> bool {
self.finalized
}
fn requires_objects(&self) -> Result<&[CK_OBJECT_HANDLE]> {
if self.keygxy_handle != CK_INVALID_HANDLE {
Ok(std::slice::from_ref(&self.keygxy_handle))
} else {
Err(CKR_OK)?
}
}
fn receives_objects(&mut self, objs: &[&Object]) -> Result<()> {
if objs.len() != 1 {
return Err(CKR_GENERAL_ERROR)?;
}
if objs[0].get_attr_as_ulong(CKA_KEY_TYPE)? != CKK_GENERIC_SECRET {
return Err(CKR_KEY_TYPE_INCONSISTENT)?;
}
self.keygxy = Some(objs[0].get_attr_as_bytes(CKA_VALUE)?.clone());
Ok(())
}
}
impl Derive for Ike1ExtendedOperation {
fn derive(
&mut self,
key: &Object,
template: &[CK_ATTRIBUTE],
_: &Mechanisms,
objfactories: &ObjectFactories,
) -> Result<Vec<Object>> {
require_prf_base_key_type(self.prf, key)?;
let (mut obj, keysize) = ike_derive_setup(
&mut self.finalized,
self.prf,
key,
template,
objfactories,
0,
Some(CKK_GENERIC_SECRET),
)?;
if keysize == 0 {
return Err(CKR_TEMPLATE_INCOMPLETE)?;
}
if keysize > 255 * self.prf_len {
return Err(CKR_KEY_SIZE_RANGE)?;
}
let key_bytes = key.get_attr_as_bytes(CKA_VALUE)?;
let gxy: Option<&[u8]> = self.keygxy.as_deref();
let extra: Option<&[u8]> = self.extra_data.as_deref();
let zero = [0u8];
let mut hmac = HMACOperation::internal(
self.prf,
key_bytes.to_vec(),
self.prf_len,
)?;
let mut block = vec![0u8; self.prf_len];
{
let mut parts: Vec<&[u8]> = Vec::with_capacity(2);
if let Some(g) = gxy {
parts.push(g);
}
if let Some(e) = extra {
parts.push(e);
}
if parts.is_empty() {
parts.push(&zero);
}
prf(&mut hmac, &parts, &mut block)?;
}
let mut dkm = Vec::with_capacity(keysize);
dkm.extend_from_slice(&block);
let mut kn = block.clone();
while dkm.len() < keysize {
let mut parts: Vec<&[u8]> = Vec::with_capacity(3);
parts.push(&kn);
if let Some(g) = gxy {
parts.push(g);
}
if let Some(e) = extra {
parts.push(e);
}
prf(&mut hmac, &parts, &mut block)?;
dkm.extend_from_slice(&block);
kn.copy_from_slice(&block);
}
dkm.truncate(keysize);
obj.set_attr(Attribute::from_bytes(CKA_VALUE, dkm))?;
Ok(vec![obj])
}
}
#[derive(Debug)]
struct Ike2PrfPlusOperation {
finalized: bool,
prf: CK_MECHANISM_TYPE,
prf_len: usize,
seed_key_handle: CK_OBJECT_HANDLE,
seed_key: Option<Vec<u8>>,
seed_data: Option<Vec<u8>>,
}
impl Ike2PrfPlusOperation {
fn new(mech: &CK_MECHANISM) -> Result<Ike2PrfPlusOperation> {
let params = mech.get_parameters::<CK_IKE2_PRF_PLUS_DERIVE_PARAMS>()?;
let seed_key_handle = if params.bHasSeedKey != CK_FALSE {
if params.hSeedKey == CK_INVALID_HANDLE {
return Err(CKR_MECHANISM_PARAM_INVALID)?;
}
params.hSeedKey
} else {
CK_INVALID_HANDLE
};
let seed_data = opt_bytes(params.pSeedData, params.ulSeedDataLen)?;
if seed_key_handle == CK_INVALID_HANDLE && seed_data.is_none() {
return Err(CKR_MECHANISM_PARAM_INVALID)?;
}
Ok(Ike2PrfPlusOperation {
finalized: false,
prf: params.prfMechanism,
prf_len: prf_len(params.prfMechanism)?,
seed_key_handle,
seed_key: None,
seed_data,
})
}
}
impl Drop for Ike2PrfPlusOperation {
fn drop(&mut self) {
if let Some(ref mut v) = self.seed_key {
zeromem(v);
}
if let Some(ref mut v) = self.seed_data {
zeromem(v);
}
}
}
impl MechOperation for Ike2PrfPlusOperation {
fn mechanism(&self) -> Result<CK_MECHANISM_TYPE> {
Ok(CKM_IKE2_PRF_PLUS_DERIVE)
}
fn finalized(&self) -> bool {
self.finalized
}
fn requires_objects(&self) -> Result<&[CK_OBJECT_HANDLE]> {
if self.seed_key_handle != CK_INVALID_HANDLE {
Ok(std::slice::from_ref(&self.seed_key_handle))
} else {
Err(CKR_OK)?
}
}
fn receives_objects(&mut self, objs: &[&Object]) -> Result<()> {
if objs.len() != 1 {
return Err(CKR_GENERAL_ERROR)?;
}
self.seed_key = Some(objs[0].get_attr_as_bytes(CKA_VALUE)?.clone());
Ok(())
}
}
impl Derive for Ike2PrfPlusOperation {
fn derive(
&mut self,
key: &Object,
template: &[CK_ATTRIBUTE],
_: &Mechanisms,
objfactories: &ObjectFactories,
) -> Result<Vec<Object>> {
require_prf_base_key_type(self.prf, key)?;
let (mut obj, keysize) = ike_derive_setup(
&mut self.finalized,
self.prf,
key,
template,
objfactories,
0,
Some(CKK_GENERIC_SECRET),
)?;
if keysize == 0 {
return Err(CKR_TEMPLATE_INCOMPLETE)?;
}
if keysize > 255 * self.prf_len {
return Err(CKR_KEY_SIZE_RANGE)?;
}
let key_bytes = key.get_attr_as_bytes(CKA_VALUE)?;
let seed_key: Option<&[u8]> = self.seed_key.as_deref();
let seed_data: Option<&[u8]> = self.seed_data.as_deref();
let mut hmac = HMACOperation::internal(
self.prf,
key_bytes.to_vec(),
self.prf_len,
)?;
let mut block = vec![0u8; self.prf_len];
{
let counter_byte = [1u8];
let mut parts: Vec<&[u8]> = Vec::with_capacity(3);
if let Some(s) = seed_key {
parts.push(s);
}
if let Some(d) = seed_data {
parts.push(d);
}
parts.push(&counter_byte);
prf(&mut hmac, &parts, &mut block)?;
}
let mut dkm = Vec::with_capacity(keysize);
dkm.extend_from_slice(&block);
let mut tn = block.clone();
let mut counter: u8 = 1;
while dkm.len() < keysize {
if counter == 255 {
return Err(CKR_KEY_SIZE_RANGE)?;
}
counter += 1;
let counter_byte = [counter];
let mut parts: Vec<&[u8]> = Vec::with_capacity(4);
parts.push(&tn);
if let Some(s) = seed_key {
parts.push(s);
}
if let Some(d) = seed_data {
parts.push(d);
}
parts.push(&counter_byte);
prf(&mut hmac, &parts, &mut block)?;
dkm.extend_from_slice(&block);
tn.copy_from_slice(&block);
}
dkm.truncate(keysize);
obj.set_attr(Attribute::from_bytes(CKA_VALUE, dkm))?;
Ok(vec![obj])
}
}