diff --git a/ossl.h b/ossl.h index d4dcb104..c6c0040b 100644 --- a/ossl.h +++ b/ossl.h @@ -6,3 +6,4 @@ #include "openssl/evp.h" #include "crypto/evp.h" #include "openssl/obj_mac.h" +#include "openssl/kdf.h" diff --git a/src/kdf.rs b/src/kdf.rs new file mode 100644 index 00000000..e78929d8 --- /dev/null +++ b/src/kdf.rs @@ -0,0 +1,339 @@ +// Copyright 2024 Simo Sorce +// See LICENSE.txt file for terms + +use super::attribute; +use super::err_rv; +use super::error; +use super::interface; +use super::object; + +use attribute::from_bytes; +use error::{KError, KResult}; +use interface::*; +use object::{Object, ObjectFactories}; + +use super::mechanism; +use mechanism::*; + +use super::bytes_to_vec; + +use std::fmt::Debug; + +macro_rules! bytes_to_slice { + ($ptr: expr, $len:expr, $typ:ty) => { + if $len > 0 { + unsafe { + std::slice::from_raw_parts($ptr as *const $typ, $len as usize) + } + } else { + &[] + } + }; +} + +#[derive(Debug)] +struct Sp800KDFMechanism { + info: CK_MECHANISM_INFO, +} + +impl Mechanism for Sp800KDFMechanism { + fn info(&self) -> &CK_MECHANISM_INFO { + &self.info + } + + fn derive_operation(&self, mech: &CK_MECHANISM) -> KResult { + if self.info.flags & CKF_DERIVE != CKF_DERIVE { + return err_rv!(CKR_MECHANISM_INVALID); + } + + let kdf = match mech.mechanism { + CKM_SP800_108_COUNTER_KDF => { + if mech.ulParameterLen as usize + != ::std::mem::size_of::() + { + return err_rv!(CKR_ARGUMENTS_BAD); + } + let kdf_params = unsafe { + *(mech.pParameter as *const CK_SP800_108_KDF_PARAMS) + }; + Sp800Operation::counter_kdf_new(kdf_params)? + } + CKM_SP800_108_FEEDBACK_KDF => { + if mech.ulParameterLen as usize + != ::std::mem::size_of::() + { + return err_rv!(CKR_ARGUMENTS_BAD); + } + let kdf_params = unsafe { + *(mech.pParameter + as *const CK_SP800_108_FEEDBACK_KDF_PARAMS) + }; + Sp800Operation::feedback_kdf_new(kdf_params)? + } + CKM_SP800_108_DOUBLE_PIPELINE_KDF => { + return err_rv!(CKR_MECHANISM_INVALID); + } + _ => return err_rv!(CKR_MECHANISM_INVALID), + }; + Ok(Operation::Derive(Box::new(kdf))) + } +} + +pub fn register(mechs: &mut Mechanisms, _: &mut ObjectFactories) { + Sp800Operation::register_mechanisms(mechs); +} + +#[derive(Debug)] +struct Sp800CounterFormat { + defined: bool, + le: bool, + bits: usize, +} + +#[derive(Debug)] +struct Sp800DKMLengthFormat { + method: CK_ULONG, + le: bool, + bits: usize, +} + +#[derive(Debug)] +enum Sp800Params { + Iteration(Sp800CounterFormat), + Counter(Sp800CounterFormat), + ByteArray(Vec), + DKMLength(Sp800DKMLengthFormat), +} + +#[derive(Debug)] +struct Sp800Operation { + mech: CK_MECHANISM_TYPE, + prf: CK_MECHANISM_TYPE, + finalized: bool, + params: Vec, + iv: Vec, + addl_drv_keys: Vec, + addl_objects: Vec, +} + +unsafe impl Send for Sp800Operation {} +unsafe impl Sync for Sp800Operation {} + +impl Sp800Operation { + fn register_mechanisms(mechs: &mut Mechanisms) { + mechs.add_mechanism( + CKM_SP800_108_COUNTER_KDF, + Box::new(Sp800KDFMechanism { + info: CK_MECHANISM_INFO { + ulMinKeySize: 0, + ulMaxKeySize: std::u32::MAX as CK_ULONG, + flags: CKF_DERIVE, + }, + }), + ); + mechs.add_mechanism( + CKM_SP800_108_FEEDBACK_KDF, + Box::new(Sp800KDFMechanism { + info: CK_MECHANISM_INFO { + ulMinKeySize: 0, + ulMaxKeySize: std::u32::MAX as CK_ULONG, + flags: CKF_DERIVE, + }, + }), + ); + } + + fn parse_counter_format( + p: &CK_PRF_DATA_PARAM, + ) -> KResult { + if p.ulValueLen == 0 && p.pValue == std::ptr::null_mut() { + return Ok(Sp800CounterFormat { + defined: false, + le: false, + bits: 16, + }); + } + if p.ulValueLen as usize + != ::std::mem::size_of::() + { + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + let cf = unsafe { *(p.pValue as *const CK_SP800_108_COUNTER_FORMAT) }; + Ok(Sp800CounterFormat { + defined: true, + le: match cf.bLittleEndian { + 0 => false, + 1 => true, + _ => return err_rv!(CKR_MECHANISM_PARAM_INVALID), + }, + bits: match cf.ulWidthInBits { + 8 | 16 | 24 | 32 => cf.ulWidthInBits as usize, + _ => return err_rv!(CKR_MECHANISM_PARAM_INVALID), + }, + }) + } + + fn parse_byte_array(p: &CK_PRF_DATA_PARAM) -> KResult> { + if p.ulValueLen == 0 { + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + Ok(bytes_to_vec!(p.pValue, p.ulValueLen)) + } + + fn parse_dkm_length( + p: &CK_PRF_DATA_PARAM, + ) -> KResult { + if p.ulValueLen as usize + != ::std::mem::size_of::() + { + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + let dkm = + unsafe { *(p.pValue as *const CK_SP800_108_DKM_LENGTH_FORMAT) }; + Ok(Sp800DKMLengthFormat { + method: match dkm.dkmLengthMethod { + CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS + | CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS => { + dkm.dkmLengthMethod + } + _ => return err_rv!(CKR_MECHANISM_PARAM_INVALID), + }, + le: match dkm.bLittleEndian { + 0 => false, + 1 => true, + _ => return err_rv!(CKR_MECHANISM_PARAM_INVALID), + }, + bits: match dkm.ulWidthInBits { + 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 => { + dkm.ulWidthInBits as usize + } + _ => return err_rv!(CKR_MECHANISM_PARAM_INVALID), + }, + }) + } + + fn parse_data_params( + params: &[CK_PRF_DATA_PARAM], + ) -> KResult> { + let mut result = Vec::::with_capacity(params.len()); + + for p in params { + match p.type_ { + CK_SP800_108_ITERATION_VARIABLE => { + let e = Self::parse_counter_format(p)?; + result.push(Sp800Params::Iteration(e)); + } + CK_SP800_108_COUNTER => { + let e = Self::parse_counter_format(p)?; + result.push(Sp800Params::Counter(e)); + } + CK_SP800_108_BYTE_ARRAY => { + let e = Self::parse_byte_array(p)?; + result.push(Sp800Params::ByteArray(e)); + } + CK_SP800_108_DKM_LENGTH => { + let e = Self::parse_dkm_length(p)?; + result.push(Sp800Params::DKMLength(e)); + } + _ => return err_rv!(CKR_MECHANISM_PARAM_INVALID), + } + } + + Ok(result) + } + + fn check_key_op(key: &Object, ktype: CK_KEY_TYPE) -> KResult<()> { + key.check_key_ops(CKO_SECRET_KEY, ktype, CKA_DERIVE) + } + + fn verify_prf_key(mech: CK_MECHANISM_TYPE, key: &Object) -> KResult<()> { + match Self::check_key_op(key, CKK_GENERIC_SECRET) { + Ok(_) => match mech { + CKM_SHA_1_HMAC | CKM_SHA224_HMAC | CKM_SHA256_HMAC + | CKM_SHA384_HMAC | CKM_SHA512_HMAC | CKM_SHA3_224_HMAC + | CKM_SHA3_256_HMAC | CKM_SHA3_384_HMAC | CKM_SHA3_512_HMAC => { + return Ok(()) + } + _ => (), + }, + Err(_) => (), + } + + match mech { + CKM_SHA_1_HMAC => Self::check_key_op(key, CKK_SHA_1_HMAC), + CKM_SHA224_HMAC => Self::check_key_op(key, CKK_SHA224_HMAC), + CKM_SHA256_HMAC => Self::check_key_op(key, CKK_SHA256_HMAC), + CKM_SHA384_HMAC => Self::check_key_op(key, CKK_SHA384_HMAC), + CKM_SHA512_HMAC => Self::check_key_op(key, CKK_SHA512_HMAC), + CKM_SHA3_224_HMAC => Self::check_key_op(key, CKK_SHA3_224_HMAC), + CKM_SHA3_256_HMAC => Self::check_key_op(key, CKK_SHA3_256_HMAC), + CKM_SHA3_384_HMAC => Self::check_key_op(key, CKK_SHA3_384_HMAC), + CKM_SHA3_512_HMAC => Self::check_key_op(key, CKK_SHA3_512_HMAC), + CKM_AES_CMAC => Self::check_key_op(key, CKK_AES), + _ => return err_rv!(CKR_KEY_TYPE_INCONSISTENT), + } + } + + fn counter_kdf_new( + params: CK_SP800_108_KDF_PARAMS, + ) -> KResult { + let data_params = bytes_to_slice!( + params.pDataParams, + params.ulNumberOfDataParams, + CK_PRF_DATA_PARAM + ); + let addl_drv_keys = bytes_to_slice!( + params.pAdditionalDerivedKeys, + params.ulAdditionalDerivedKeys, + CK_DERIVED_KEY + ); + Ok(Sp800Operation { + mech: CKM_SP800_108_COUNTER_KDF, + prf: params.prfType, + finalized: false, + params: Self::parse_data_params(&data_params)?, + iv: Vec::new(), + addl_drv_keys: addl_drv_keys.to_vec(), + addl_objects: Vec::with_capacity(addl_drv_keys.len()), + }) + } + + fn feedback_kdf_new( + params: CK_SP800_108_FEEDBACK_KDF_PARAMS, + ) -> KResult { + let data_params = bytes_to_slice!( + params.pDataParams, + params.ulNumberOfDataParams, + CK_PRF_DATA_PARAM + ); + let addl_drv_keys = bytes_to_slice!( + params.pAdditionalDerivedKeys, + params.ulAdditionalDerivedKeys, + CK_DERIVED_KEY + ); + let iv = if params.pIV != std::ptr::null_mut() && params.ulIVLen != 0 { + bytes_to_vec!(params.pIV, params.ulIVLen) + } else if params.pIV == std::ptr::null_mut() && params.ulIVLen == 0 { + Vec::new() + } else { + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + }; + Ok(Sp800Operation { + mech: CKM_SP800_108_FEEDBACK_KDF, + prf: params.prfType, + finalized: false, + params: Self::parse_data_params(&data_params)?, + iv: iv, + addl_drv_keys: addl_drv_keys.to_vec(), + addl_objects: Vec::with_capacity(addl_drv_keys.len()), + }) + } +} + +impl MechOperation for Sp800Operation { + fn finalized(&self) -> bool { + self.finalized + } +} + +include!("ossl/kdf.rs"); diff --git a/src/lib.rs b/src/lib.rs index 879ccc98..1846ce22 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,6 +48,7 @@ mod drbg; mod ecc; mod hash; mod hmac; +mod kdf; mod rsa; /* Helper code */ @@ -837,7 +838,7 @@ extern "C" fn fn_encrypt_init( let slot_id = session.get_slot_id(); let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); let obj = res_or_ret!(token.get_object_by_handle(key)).clone(); - let mech = res_or_ret!(token.get_mech(data.mechanism)); + let mech = res_or_ret!(token.get_mechanisms().get(data.mechanism)); if mech.info().flags & CKF_ENCRYPT == CKF_ENCRYPT { let operation = res_or_ret!(mech.encryption_new(data, &obj)); session.set_operation(Operation::Encryption(operation)); @@ -951,7 +952,7 @@ extern "C" fn fn_decrypt_init( let slot_id = session.get_slot_id(); let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); let obj = res_or_ret!(token.get_object_by_handle(key)).clone(); - let mech = res_or_ret!(token.get_mech(data.mechanism)); + let mech = res_or_ret!(token.get_mechanisms().get(data.mechanism)); if mech.info().flags & CKF_DECRYPT == CKF_DECRYPT { let operation = res_or_ret!(mech.decryption_new(data, &obj)); session.set_operation(Operation::Decryption(operation)); @@ -1058,7 +1059,7 @@ extern "C" fn fn_digest_init( check_op_empty_or_fail!(session; Digest; mechanism); let data: &CK_MECHANISM = unsafe { &*mechanism }; let token = res_or_ret!(rstate.get_token_from_slot(session.get_slot_id())); - let mech = res_or_ret!(token.get_mech(data.mechanism)); + let mech = res_or_ret!(token.get_mechanisms().get(data.mechanism)); if mech.info().flags & CKF_DIGEST == CKF_DIGEST { let operation = res_or_ret!(mech.digest_new(data)); session.set_operation(Operation::Digest(operation)); @@ -1209,7 +1210,7 @@ extern "C" fn fn_sign_init( let slot_id = session.get_slot_id(); let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); let obj = res_or_ret!(token.get_object_by_handle(key)).clone(); - let mech = res_or_ret!(token.get_mech(data.mechanism)); + let mech = res_or_ret!(token.get_mechanisms().get(data.mechanism)); if mech.info().flags & CKF_SIGN == CKF_SIGN { let operation = res_or_ret!(mech.sign_new(data, &obj)); session.set_operation(Operation::Sign(operation)); @@ -1350,7 +1351,7 @@ extern "C" fn fn_verify_init( let slot_id = session.get_slot_id(); let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); let obj = res_or_ret!(token.get_object_by_handle(key)).clone(); - let mech = res_or_ret!(token.get_mech(data.mechanism)); + let mech = res_or_ret!(token.get_mechanisms().get(data.mechanism)); if mech.info().flags & CKF_VERIFY == CKF_VERIFY { let operation = res_or_ret!(mech.verify_new(data, &obj)); session.set_operation(Operation::Verify(operation)); @@ -1507,7 +1508,7 @@ extern "C" fn fn_generate_key( let slot_id = session.get_slot_id(); let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); - let mech = res_or_ret!(token.get_mech(data.mechanism)); + let mech = res_or_ret!(token.get_mechanisms().get(data.mechanism)); if mech.info().flags & CKF_GENERATE != CKF_GENERATE { return CKR_MECHANISM_INVALID; } @@ -1559,7 +1560,7 @@ extern "C" fn fn_generate_key_pair( let slot_id = session.get_slot_id(); let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); - let mech = res_or_ret!(token.get_mech(data.mechanism)); + let mech = res_or_ret!(token.get_mechanisms().get(data.mechanism)); if mech.info().flags & CKF_GENERATE_KEY_PAIR != CKF_GENERATE_KEY_PAIR { return CKR_MECHANISM_INVALID; } @@ -1602,8 +1603,9 @@ extern "C" fn fn_wrap_key( let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); let kobj = res_or_ret!(token.get_object_by_handle(key)).clone(); let wkobj = res_or_ret!(token.get_object_by_handle(wrapping_key)).clone(); - let factory = res_or_ret!(token.get_obj_factory(&kobj)); - let mech = res_or_ret!(token.get_mech(ck_mech.mechanism)); + let factories = token.get_object_factories(); + let factory = res_or_ret!(factories.get_object_factory(&kobj)); + let mech = res_or_ret!(token.get_mechanisms().get(ck_mech.mechanism)); if mech.info().flags & CKF_WRAP != CKF_WRAP { return CKR_MECHANISM_INVALID; } @@ -1653,11 +1655,13 @@ extern "C" fn fn_unwrap_key( let slot_id = session.get_slot_id(); let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); let kobj = res_or_ret!(token.get_object_by_handle(unwrapping_key)).clone(); - let factory = res_or_ret!(token.get_obj_factory_from_key_template(tmpl)); + let factories = token.get_object_factories(); + let factory = + res_or_ret!(factories.get_obj_factory_from_key_template(tmpl)); let data: &[u8] = unsafe { std::slice::from_raw_parts(wrapped_key, wrapped_key_len as usize) }; - let mech = res_or_ret!(token.get_mech(ck_mech.mechanism)); + let mech = res_or_ret!(token.get_mechanisms().get(ck_mech.mechanism)); if mech.info().flags & CKF_WRAP != CKF_WRAP { return CKR_MECHANISM_INVALID; } @@ -1681,15 +1685,90 @@ extern "C" fn fn_unwrap_key( } extern "C" fn fn_derive_key( - _session: CK_SESSION_HANDLE, - _mechanism: CK_MECHANISM_PTR, - _base_key: CK_OBJECT_HANDLE, - _template: CK_ATTRIBUTE_PTR, - _attribute_count: CK_ULONG, - _ph_key: CK_OBJECT_HANDLE_PTR, + s_handle: CK_SESSION_HANDLE, + mechanism: CK_MECHANISM_PTR, + base_key: CK_OBJECT_HANDLE, + template: CK_ATTRIBUTE_PTR, + attribute_count: CK_ULONG, + key_handle: CK_OBJECT_HANDLE_PTR, ) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED + let rstate = global_rlock!(STATE); + let session = res_or_ret!(rstate.get_session(s_handle)); + + let ck_mech: &CK_MECHANISM = unsafe { &*mechanism }; + let tmpl: &mut [CK_ATTRIBUTE] = unsafe { + std::slice::from_raw_parts_mut(template, attribute_count as usize) + }; + if !session.is_writable() { + fail_if_cka_token_true!(&*tmpl); + } + let slot_id = session.get_slot_id(); + let mut token = res_or_ret!(rstate.get_token_from_slot_mut(slot_id)); + let bkey = res_or_ret!(token.get_object_by_handle(base_key)).clone(); + + /* key checks */ + if !res_or_ret!(bkey.get_attr_as_bool(CKA_DERIVE)) { + return CKR_KEY_FUNCTION_NOT_PERMITTED; + } + + let mech = res_or_ret!(token.get_mechanisms().get(ck_mech.mechanism)); + if mech.info().flags & CKF_DERIVE != CKF_DERIVE { + return CKR_MECHANISM_INVALID; + } + + let mut operation = match res_or_ret!(mech.derive_operation(ck_mech)) { + Operation::Derive(op) => op, + _ => return CKR_MECHANISM_INVALID, + }; + + let result = operation.derive( + &bkey, + tmpl, + token.get_mechanisms(), + token.get_object_factories(), + ); + let (kh, addtl) = match result { + Ok((obj, addtl)) => { + let h = res_or_ret!(token.insert_object(s_handle, obj)); + (h, addtl) + } + Err(e) => return err_to_rv!(e), + }; + + let mut rv = CKR_OK; + if addtl > 0 { + let mut o = Vec::::with_capacity(addtl); + for _ in 0..addtl { + let r = operation.derive_additional_key(); + match r { + Ok((obj, hptr)) => match token.insert_object(s_handle, obj) { + Ok(h) => { + unsafe { core::ptr::write(hptr as *mut _, h) }; + o.push(h); + } + Err(e) => rv = err_to_rv!(e), + }, + Err(_) => rv = CKR_GENERAL_ERROR, + } + if rv != CKR_OK { + break; + } + } + if rv != CKR_OK { + for h in o { + let _ = token.destroy_object(h); + } + let _ = token.destroy_object(kh); + return rv; + } + } + + unsafe { + core::ptr::write(key_handle as *mut _, kh); + } + CKR_OK } + extern "C" fn fn_seed_random( _session: CK_SESSION_HANDLE, _seed: CK_BYTE_PTR, diff --git a/src/mechanism.rs b/src/mechanism.rs index 23a59718..b86b421c 100644 --- a/src/mechanism.rs +++ b/src/mechanism.rs @@ -9,7 +9,7 @@ use super::interface; use super::object; use error::{KError, KResult}; use interface::*; -use object::{Object, ObjectFactory}; +use object::{Object, ObjectFactories, ObjectFactory}; use std::fmt::Debug; @@ -86,6 +86,10 @@ pub trait Mechanism: Debug + Send + Sync { ) -> KResult { err_rv!(CKR_MECHANISM_INVALID) } + + fn derive_operation(&self, _: &CK_MECHANISM) -> KResult { + err_rv!(CKR_MECHANISM_INVALID) + } } #[derive(Debug)] @@ -249,6 +253,23 @@ pub trait Verify: MechOperation { } } +pub trait Derive: MechOperation { + fn derive( + &mut self, + _: &object::Object, + _: &[CK_ATTRIBUTE], + _: &Mechanisms, + _: &ObjectFactories, + ) -> KResult<(Object, usize)> { + err_rv!(CKR_GENERAL_ERROR) + } + fn derive_additional_key( + &mut self, + ) -> KResult<(Object, CK_OBJECT_HANDLE_PTR)> { + err_rv!(CKR_GENERAL_ERROR) + } +} + #[derive(Debug)] pub enum Operation { Empty, @@ -258,6 +279,7 @@ pub enum Operation { Digest(Box), Sign(Box), Verify(Box), + Derive(Box), } impl Operation { @@ -270,6 +292,7 @@ impl Operation { Operation::Digest(op) => op.finalized(), Operation::Sign(op) => op.finalized(), Operation::Verify(op) => op.finalized(), + Operation::Derive(op) => op.finalized(), } } } diff --git a/src/object.rs b/src/object.rs index 714a7a5e..7ea5b10c 100644 --- a/src/object.rs +++ b/src/object.rs @@ -377,6 +377,47 @@ pub trait ObjectFactory: Debug + Send + Sync { ) } + fn default_object_derive( + &self, + template: &[CK_ATTRIBUTE], + origin: &Object, + ) -> KResult { + /* FIXME: handle CKA_DERIVE_TEMPLATE */ + + let mut obj = self.internal_object_create( + template, + OAFlags::SettableOnlyOnCreate, + OAFlags::AlwaysRequired, + )?; + /* overrides */ + obj.set_attr(from_bool(CKA_LOCAL, false))?; + match origin.get_attr_as_bool(CKA_ALWAYS_SENSITIVE) { + Ok(b) => match b { + false => { + obj.set_attr(from_bool(CKA_ALWAYS_SENSITIVE, false))? + } + true => obj.set_attr(from_bool( + CKA_ALWAYS_SENSITIVE, + obj.is_sensitive(), + ))?, + }, + Err(_) => obj.set_attr(from_bool(CKA_ALWAYS_SENSITIVE, false))?, + }; + match origin.get_attr_as_bool(CKA_NEVER_EXTRACTABLE) { + Ok(b) => match b { + false => { + obj.set_attr(from_bool(CKA_NEVER_EXTRACTABLE, false))? + } + true => obj.set_attr(from_bool( + CKA_NEVER_EXTRACTABLE, + !obj.is_extractable(), + ))?, + }, + Err(_) => obj.set_attr(from_bool(CKA_NEVER_EXTRACTABLE, false))?, + }; + Ok(obj) + } + fn internal_object_create( &self, template: &[CK_ATTRIBUTE], @@ -1216,6 +1257,22 @@ impl ObjectFactories { } self.get_object_factory(obj)?.copy(obj, template) } + + pub fn get_obj_factory_from_key_template( + &self, + template: &[CK_ATTRIBUTE], + ) -> KResult<&Box> { + let class = match template.iter().position(|x| x.type_ == CKA_CLASS) { + Some(idx) => template[idx].to_ulong()?, + None => return err_rv!(CKR_TEMPLATE_INCONSISTENT), + }; + let key_type = + match template.iter().position(|x| x.type_ == CKA_KEY_TYPE) { + Some(idx) => template[idx].to_ulong()?, + None => return err_rv!(CKR_TEMPLATE_INCONSISTENT), + }; + self.get_factory(ObjectType::new(class, key_type)) + } } static DATA_OBJECT_FACTORY: Lazy> = diff --git a/src/ossl/common.rs b/src/ossl/common.rs index 6643b223..407a78ae 100644 --- a/src/ossl/common.rs +++ b/src/ossl/common.rs @@ -5,7 +5,8 @@ use super::object; use interface::*; -use std::os::raw::c_uint; +use core::ffi::c_int; +use core::ffi::c_uint; macro_rules! ptr_wrapper { ($name:ident; $ossl:ident; $free:expr) => { @@ -57,6 +58,14 @@ ptr_wrapper!(EvpMdCtx; EVP_MD_CTX; EVP_MD_CTX_free); ptr_wrapper!(BigNum; BIGNUM; BN_free); ptr_wrapper!(EvpCipherCtx; EVP_CIPHER_CTX; EVP_CIPHER_CTX_free); ptr_wrapper!(EvpCipher; EVP_CIPHER; EVP_CIPHER_free); +ptr_wrapper!(EvpKdfCtx; EVP_KDF_CTX; EVP_KDF_CTX_free); +ptr_wrapper!(EvpKdf; EVP_KDF; EVP_KDF_free); + +pub const CIPHER_NAME_AES128: &[u8; 7] = b"AES128\0"; +pub const CIPHER_NAME_AES192: &[u8; 7] = b"AES192\0"; +pub const CIPHER_NAME_AES256: &[u8; 7] = b"AES256\0"; +pub const MAC_NAME_CMAC: &[u8; 5] = b"CMAC\0"; +pub const MAC_NAME_HMAC: &[u8; 5] = b"HMAC\0"; pub fn name_as_char(name: &[u8]) -> *const c_char { name.as_ptr() as *const c_char @@ -224,6 +233,21 @@ impl OsslParam { Ok(self) } + pub fn add_const_c_string( + mut self, + key: *const c_char, + val: *const c_char, + ) -> KResult { + if self.finalized { + return err_rv!(CKR_GENERAL_ERROR); + } + + let param = + unsafe { OSSL_PARAM_construct_utf8_string(key, val as *mut i8, 0) }; + self.p.push(param); + Ok(self) + } + pub fn add_octet_string( mut self, key: *const c_char, @@ -282,6 +306,24 @@ impl OsslParam { Ok(self) } + pub fn add_int( + mut self, + key: *const c_char, + val: c_int, + ) -> KResult { + if self.finalized { + return err_rv!(CKR_GENERAL_ERROR); + } + + let container = val.to_ne_bytes().to_vec(); + let param = unsafe { + OSSL_PARAM_construct_int(key, container.as_ptr() as *mut c_int) + }; + self.v.push(container); + self.p.push(param); + Ok(self) + } + pub fn finalize(mut self) -> OsslParam { if self.finalized { return self; @@ -391,38 +433,47 @@ pub fn mech_type_to_digest_name(mech: CK_MECHANISM_TYPE) -> *const c_char { CKM_SHA1_RSA_PKCS | CKM_ECDSA_SHA1 | CKM_SHA1_RSA_PKCS_PSS + | CKM_SHA_1_HMAC | CKM_SHA_1 => OSSL_DIGEST_NAME_SHA1.as_ptr(), CKM_SHA224_RSA_PKCS | CKM_ECDSA_SHA224 | CKM_SHA224_RSA_PKCS_PSS + | CKM_SHA224_HMAC | CKM_SHA224 => OSSL_DIGEST_NAME_SHA2_224.as_ptr(), CKM_SHA256_RSA_PKCS | CKM_ECDSA_SHA256 | CKM_SHA256_RSA_PKCS_PSS + | CKM_SHA256_HMAC | CKM_SHA256 => OSSL_DIGEST_NAME_SHA2_256.as_ptr(), CKM_SHA384_RSA_PKCS | CKM_ECDSA_SHA384 | CKM_SHA384_RSA_PKCS_PSS + | CKM_SHA384_HMAC | CKM_SHA384 => OSSL_DIGEST_NAME_SHA2_384.as_ptr(), CKM_SHA512_RSA_PKCS | CKM_ECDSA_SHA512 | CKM_SHA512_RSA_PKCS_PSS + | CKM_SHA512_HMAC | CKM_SHA512 => OSSL_DIGEST_NAME_SHA2_512.as_ptr(), CKM_SHA3_224_RSA_PKCS | CKM_ECDSA_SHA3_224 | CKM_SHA3_224_RSA_PKCS_PSS + | CKM_SHA3_224_HMAC | CKM_SHA3_224 => OSSL_DIGEST_NAME_SHA3_224.as_ptr(), CKM_SHA3_256_RSA_PKCS | CKM_ECDSA_SHA3_256 | CKM_SHA3_256_RSA_PKCS_PSS + | CKM_SHA3_256_HMAC | CKM_SHA3_256 => OSSL_DIGEST_NAME_SHA3_256.as_ptr(), CKM_SHA3_384_RSA_PKCS | CKM_ECDSA_SHA3_384 | CKM_SHA3_384_RSA_PKCS_PSS + | CKM_SHA3_384_HMAC | CKM_SHA3_384 => OSSL_DIGEST_NAME_SHA3_384.as_ptr(), CKM_SHA3_512_RSA_PKCS | CKM_ECDSA_SHA3_512 | CKM_SHA3_512_RSA_PKCS_PSS + | CKM_SHA3_512_HMAC | CKM_SHA3_512 => OSSL_DIGEST_NAME_SHA3_512.as_ptr(), _ => std::ptr::null(), }) as *const c_char diff --git a/src/ossl/kdf.rs b/src/ossl/kdf.rs new file mode 100644 index 00000000..94219af6 --- /dev/null +++ b/src/ossl/kdf.rs @@ -0,0 +1,496 @@ +// Copyright 2024 Simo Sorce +// See LICENSE.txt file for terms + +#[cfg(feature = "fips")] +use {super::fips, fips::*}; + +#[cfg(not(feature = "fips"))] +use {super::ossl, ossl::*}; + +use core::ffi::c_int; + +const SP800_MODE_COUNTER: &[u8; 8] = b"counter\0"; +const SP800_MODE_FEEDBACK: &[u8; 9] = b"feedback\0"; + +fn template_to_object( + key: &Object, + template: &[CK_ATTRIBUTE], + objfactories: &ObjectFactories, +) -> KResult { + let objfactory = + objfactories.get_obj_factory_from_key_template(template)?; + objfactory.default_object_derive(template, key) +} + +fn prep_counter_kdf( + sparams: &Vec, + mut params: OsslParam, +) -> KResult { + if sparams.len() < 1 { + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + + /* Key, counter, [Label], [0x00], [Context], [Len] */ + match &sparams[0] { + Sp800Params::Iteration(i) => { + if !i.defined { + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + if i.le { + /* OpenSSL limitations */ + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + params = params.add_int( + name_as_char(OSSL_KDF_PARAM_KBKDF_R), + i.bits as c_int, + )?; + } + _ => return err_rv!(CKR_MECHANISM_PARAM_INVALID), + } + + let mut label = false; + let mut separator = false; + let mut context = false; + let mut dkmlen = false; + + for idx in 1..sparams.len() { + match &sparams[idx] { + Sp800Params::ByteArray(v) => { + if context { + /* already set, bail out */ + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + if separator { + /* separator set, this is a Context */ + params = params.add_octet_string( + name_as_char(OSSL_KDF_PARAM_INFO), + &v, + )?; + context = true; + } else { + /* check if separator */ + if v.len() == 1 && v[0] == 0 { + params = params.add_int( + name_as_char(OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR), + 1, + )?; + separator = true; + } else { + if label { + /* label set and no separator, this is a Context */ + params = params.add_octet_string( + name_as_char(OSSL_KDF_PARAM_INFO), + &v, + )?; + context = true; + } else { + params = params.add_octet_string( + name_as_char(OSSL_KDF_PARAM_SALT), + &v, + )?; + label = true; + } + } + } + } + Sp800Params::DKMLength(v) => { + if dkmlen { + /* already set, bail out */ + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + if v.le + || v.bits != 32 + || v.method != CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS + { + /* OpenSSL limitations */ + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + params = params + .add_int(name_as_char(OSSL_KDF_PARAM_KBKDF_USE_L), 1)?; + dkmlen = true; + + /* DKM Length is always last in OpenSSL, so also mark + * context as true regardless as no more Byte Arrays + * are allowed */ + context = true; + } + _ => return err_rv!(CKR_MECHANISM_PARAM_INVALID), + } + } + if !separator { + params = params + .add_int(name_as_char(OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR), 0)? + } + if !dkmlen { + params = params.add_int(name_as_char(OSSL_KDF_PARAM_KBKDF_USE_L), 0)? + } + Ok(params.finalize()) +} + +fn prep_feedback_kdf( + sparams: &Vec, + mut params: OsslParam, +) -> KResult { + if sparams.len() < 1 { + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + + /* Key, iter, [counter], [Label], [0x00], [Context], [Len] */ + match &sparams[0] { + Sp800Params::Iteration(c) => { + if c.defined { + /* Spec says param must be null for feedback mode */ + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + } + _ => return err_rv!(CKR_MECHANISM_PARAM_INVALID), + } + + let mut counter = false; + let mut label = false; + let mut separator = false; + let mut context = false; + let mut dkmlen = false; + + for idx in 1..sparams.len() { + match &sparams[idx] { + Sp800Params::Counter(c) => { + if counter { + /* already set, bail out */ + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + if c.le { + /* OpenSSL limitations */ + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + params = params.add_int( + name_as_char(OSSL_KDF_PARAM_KBKDF_R), + c.bits as c_int, + )?; + } + Sp800Params::ByteArray(v) => { + /* unconditionally set counter to true as once we get + * a byte array, counter can't be set anymore for + * OpenSSL */ + counter = true; + if context { + /* already set, bail out */ + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + if separator { + /* separator set, this is a Context */ + params = params.add_octet_string( + name_as_char(OSSL_KDF_PARAM_INFO), + &v, + )?; + context = true; + } else { + /* check if separator */ + if v.len() == 1 && v[0] == 0 { + params = params.add_int( + name_as_char(OSSL_KDF_PARAM_KBKDF_USE_L), + 1, + )?; + separator = true; + } else { + if label { + /* label set and no separator, this is a Context */ + params = params.add_octet_string( + name_as_char(OSSL_KDF_PARAM_INFO), + &v, + )?; + context = true; + } else { + params = params.add_octet_string( + name_as_char(OSSL_KDF_PARAM_SALT), + &v, + )?; + label = true; + } + } + } + } + Sp800Params::DKMLength(v) => { + if dkmlen { + /* already set, bail out */ + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + if v.le + || v.bits != 32 + || v.method != CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS + { + /* OpenSSL limitations */ + return err_rv!(CKR_MECHANISM_PARAM_INVALID); + } + params = params + .add_int(name_as_char(OSSL_KDF_PARAM_KBKDF_USE_L), 1)?; + dkmlen = true; + + /* DKM Length is always last in OpenSSL, so also mark + * context and counter as true regardless as no more + * Counter or Byte Arrays are allowed for OpenSSL */ + counter = true; + context = true; + } + _ => return err_rv!(CKR_MECHANISM_PARAM_INVALID), + } + } + if !separator { + params = params + .add_int(name_as_char(OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR), 0)? + } + if !dkmlen { + params = params.add_int(name_as_char(OSSL_KDF_PARAM_KBKDF_USE_L), 0)? + } + Ok(params.finalize()) +} + +fn get_segment_size( + mechanisms: &Mechanisms, + hmac: CK_MECHANISM_TYPE, +) -> KResult { + let mech = CK_MECHANISM { + mechanism: match hmac { + CKM_SHA_1_HMAC => CKM_SHA_1, + CKM_SHA224_HMAC => CKM_SHA224, + CKM_SHA256_HMAC => CKM_SHA256, + CKM_SHA384_HMAC => CKM_SHA384, + CKM_SHA512_HMAC => CKM_SHA512, + CKM_SHA3_224_HMAC => CKM_SHA3_224, + CKM_SHA3_256_HMAC => CKM_SHA3_256, + CKM_SHA3_384_HMAC => CKM_SHA3_384, + CKM_SHA3_512_HMAC => CKM_SHA3_512, + _ => return err_rv!(CKR_MECHANISM_PARAM_INVALID), + }, + pParameter: std::ptr::null_mut(), + ulParameterLen: 0, + }; + + mechanisms + .get(mech.mechanism)? + .digest_new(&mech)? + .digest_len() +} + +fn key_to_segment_size(key: usize, segment: usize) -> usize { + ((key + segment - 1) / segment) * segment +} + +impl Derive for Sp800Operation { + fn derive( + &mut self, + key: &Object, + template: &[CK_ATTRIBUTE], + mechanisms: &Mechanisms, + objfactories: &ObjectFactories, + ) -> KResult<(Object, usize)> { + if self.finalized { + return err_rv!(CKR_OPERATION_NOT_INITIALIZED); + } + self.finalized = true; + + Self::verify_prf_key(self.prf, key)?; + + /* Ok so this stuff in the PKCS#11 spec has an insane level + * of flexibility, fundamentally each parameter correspond to + * data that will be feed to the MAC operation in the order + * it should happen, providing maximum composability and an + * effectively infinite combinatorial matrix. + * While some flexibility may make sense, this is excessive + * and only provide a sharp knife in the hand of users. + * Therefore upon parsing we accept only "well" formed inputs + * that follow the NIST specification of Counter and Feedback + * mode etc.. without flexibility on the ordering for example, + * although we still need to allow for way more options that + * I'd like. + * + * Some of the restrictions here are due to the OpenSSL + * implementation of KBKDF. For example it hardcodes counters + * and other lengths as bigendian, has a fixed size for the L + * variable of 32 bit (or none at all), and supports only + * counters of size 8, 16, 24, 32 ... + * If any of these restrictions breaks a user we'll have to + * reimplement the KBKDF code using raw HAMC/CMAC PRFs */ + + let mac_type_name = if self.prf == CKM_AES_CMAC { + name_as_char(MAC_NAME_CMAC) + } else { + name_as_char(MAC_NAME_HMAC) + }; + let (prf_alg_param, prf_alg_value) = match self.prf { + CKM_SHA_1_HMAC | CKM_SHA224_HMAC | CKM_SHA256_HMAC + | CKM_SHA384_HMAC | CKM_SHA512_HMAC | CKM_SHA3_224_HMAC + | CKM_SHA3_256_HMAC | CKM_SHA3_384_HMAC | CKM_SHA3_512_HMAC => ( + name_as_char(OSSL_KDF_PARAM_DIGEST), + mech_type_to_digest_name(self.prf), + ), + CKM_AES_CMAC => ( + name_as_char(OSSL_KDF_PARAM_CIPHER), + match key.get_attr_as_ulong(CKA_VALUE_LEN)? { + 16 => name_as_char(CIPHER_NAME_AES128), + 24 => name_as_char(CIPHER_NAME_AES192), + 32 => name_as_char(CIPHER_NAME_AES256), + _ => return err_rv!(CKR_KEY_INDIGESTIBLE), + }, + ), + _ => return err_rv!(CKR_MECHANISM_PARAM_INVALID), + }; + + let mut params = OsslParam::with_capacity(10) + .set_zeroize() + .add_const_c_string( + name_as_char(OSSL_KDF_PARAM_MAC), + mac_type_name, + )? + .add_const_c_string(prf_alg_param, prf_alg_value)? + .add_octet_string( + name_as_char(OSSL_KDF_PARAM_KEY), + key.get_attr_as_bytes(CKA_VALUE)?, + )?; + + match self.mech { + CKM_SP800_108_COUNTER_KDF => { + params = params.add_const_c_string( + name_as_char(OSSL_KDF_PARAM_MODE), + name_as_char(SP800_MODE_COUNTER), + )?; + params = prep_counter_kdf(&self.params, params)?; + } + CKM_SP800_108_FEEDBACK_KDF => { + params = params.add_const_c_string( + name_as_char(OSSL_KDF_PARAM_MODE), + name_as_char(SP800_MODE_FEEDBACK), + )?; + if self.iv.len() > 0 { + params = params.add_octet_string( + name_as_char(OSSL_KDF_PARAM_SEED), + &self.iv, + )?; + } + params = prep_feedback_kdf(&self.params, params)?; + } + _ => return err_rv!(CKR_GENERAL_ERROR), + } + + let mut obj = template_to_object(key, template, objfactories)?; + + let keysize = match obj.get_attr_as_ulong(CKA_VALUE_LEN) { + Ok(n) => n as usize, + Err(_) => return err_rv!(CKR_TEMPLATE_INCOMPLETE), + }; + if keysize == 0 || keysize > (u32::MAX as usize) { + return err_rv!(CKR_KEY_SIZE_RANGE); + } + let mut segment = 1; + + if self.addl_drv_keys.len() > 0 { + /* need the mechanism to compute the segment size as + * openssl will just return a linear buffer, that we + * need to split in segments as the spec requires */ + if self.prf == CKM_AES_CMAC { + /* AES CMAC always return 16 bytes signatures */ + segment = 16; + } else { + segment = get_segment_size(mechanisms, self.prf)?; + } + } + + let mut derive_output = key_to_segment_size(keysize, segment); + + /* additional keys */ + for ak in &self.addl_drv_keys { + let tmpl: &[CK_ATTRIBUTE] = unsafe { + std::slice::from_raw_parts_mut( + ak.pTemplate, + ak.ulAttributeCount as usize, + ) + }; + let obj = match template_to_object(key, tmpl, objfactories) { + Ok(o) => o, + Err(e) => { + /* mark the handle as invalid */ + unsafe { + core::ptr::write(ak.phKey, CK_INVALID_HANDLE); + } + return Err(e); + } + }; + let aksize = match obj.get_attr_as_ulong(CKA_VALUE_LEN) { + Ok(n) => n as usize, + Err(_) => return err_rv!(CKR_TEMPLATE_INCOMPLETE), + }; + if aksize == 0 || aksize > (u32::MAX as usize) { + return err_rv!(CKR_KEY_SIZE_RANGE); + } + /* increment size in segment steps */ + derive_output += key_to_segment_size(aksize, segment); + self.addl_objects.push(obj); + } + + let mut kdf = match EvpKdf::from_ptr(unsafe { + EVP_KDF_fetch( + get_libctx(), + name_as_char(OSSL_KDF_NAME_KBKDF), + std::ptr::null(), + ) + }) { + Ok(ek) => ek, + Err(_) => return err_rv!(CKR_DEVICE_ERROR), + }; + let mut kctx = match EvpKdfCtx::from_ptr(unsafe { + EVP_KDF_CTX_new(kdf.as_mut_ptr()) + }) { + Ok(ekc) => ekc, + Err(_) => return err_rv!(CKR_DEVICE_ERROR), + }; + + let mut derived_keys = vec![0u8; derive_output]; + let res = unsafe { + EVP_KDF_derive( + kctx.as_mut_ptr(), + derived_keys.as_mut_ptr(), + derived_keys.len(), + params.as_ptr(), + ) + }; + if res != 1 { + return err_rv!(CKR_DEVICE_ERROR); + } + + obj.set_attr(from_bytes(CKA_VALUE, derived_keys[0..keysize].to_vec()))?; + + let mut cursor = key_to_segment_size(keysize, segment); + for key in &mut self.addl_objects { + let aksize = key.get_attr_as_ulong(CKA_VALUE_LEN)? as usize; + key.set_attr(from_bytes( + CKA_VALUE, + derived_keys[cursor..(cursor + aksize)].to_vec(), + ))?; + cursor += key_to_segment_size(aksize, segment); + } + + Ok((obj, self.addl_objects.len())) + } + + fn derive_additional_key( + &mut self, + ) -> KResult<(Object, CK_OBJECT_HANDLE_PTR)> { + if !self.finalized { + return err_rv!(CKR_OPERATION_NOT_INITIALIZED); + } + /* pops a key at a time from the the vectors, this returns keys + * in reverse order from creation, but that doesn't matter as + * the pointers in the original structure are what give the order + * back to the caller */ + let obj = match self.addl_objects.pop() { + Some(o) => o, + None => return err_rv!(CKR_EXCEEDED_MAX_ITERATIONS), + }; + /* len() here now point to the correct handler container because + * the lenght is always one more than the last object index and + * we just reduced by one the length of the objects array */ + let hp = self.addl_drv_keys[self.addl_objects.len()].phKey; + + Ok((obj, hp)) + } +} diff --git a/src/tests.rs b/src/tests.rs index a205099c..2d6a0503 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -3860,6 +3860,7 @@ fn test_key() { make_attribute!(CKA_VALUE_LEN, &mut len as *mut _, CK_ULONG_SIZE), make_attribute!(CKA_WRAP, &mut truebool as *mut _, CK_BBOOL_SIZE), make_attribute!(CKA_UNWRAP, &mut truebool as *mut _, CK_BBOOL_SIZE), + make_attribute!(CKA_DERIVE, &mut truebool as *mut _, CK_BBOOL_SIZE), make_attribute!( CKA_EXTRACTABLE, &mut truebool as *mut _, @@ -4308,6 +4309,132 @@ fn test_key() { ); assert_eq!(ret, CKR_OK); + /* Test key derivation */ + let mut class = CKO_SECRET_KEY; + let mut ktype = CKK_AES; + let mut len: CK_ULONG = 16; + let mut truebool = CK_TRUE; + let derive_template = [ + make_attribute!(CKA_CLASS, &mut class as *mut _, CK_ULONG_SIZE), + make_attribute!(CKA_KEY_TYPE, &mut ktype as *mut _, CK_ULONG_SIZE), + make_attribute!(CKA_VALUE_LEN, &mut len as *mut _, CK_ULONG_SIZE), + make_attribute!(CKA_ENCRYPT, &mut truebool as *mut _, CK_BBOOL_SIZE), + make_attribute!(CKA_DECRYPT, &mut truebool as *mut _, CK_BBOOL_SIZE), + ]; + + let mut counter_format = CK_SP800_108_COUNTER_FORMAT { + bLittleEndian: 0, + ulWidthInBits: 8, + }; + + let mut data_params = [CK_PRF_DATA_PARAM { + type_: CK_SP800_108_ITERATION_VARIABLE, + pValue: &mut counter_format as *mut _ as CK_VOID_PTR, + ulValueLen: std::mem::size_of::() + as CK_ULONG, + }]; + + let mut params = CK_SP800_108_KDF_PARAMS { + prfType: CKM_SHA3_384_HMAC, + ulNumberOfDataParams: data_params.len() as CK_ULONG, + pDataParams: data_params.as_mut_ptr(), + ulAdditionalDerivedKeys: 0, + pAdditionalDerivedKeys: std::ptr::null_mut(), + }; + + let mut derive_mech = CK_MECHANISM { + mechanism: CKM_SP800_108_COUNTER_KDF, + pParameter: &mut params as *mut _ as CK_VOID_PTR, + ulParameterLen: std::mem::size_of::() + as CK_ULONG, + }; + + let mut handle3 = CK_INVALID_HANDLE; + ret = fn_derive_key( + session, + &mut derive_mech, + handle, + derive_template.as_ptr() as *mut _, + derive_template.len() as CK_ULONG, + &mut handle3, + ); + assert_eq!(ret, CKR_OK); + + /* try again but derive additional keys */ + let mut handle4 = CK_INVALID_HANDLE; + let mut handle5 = CK_UNAVAILABLE_INFORMATION; + let mut handle6 = CK_UNAVAILABLE_INFORMATION; + let mut addl_keys = [ + CK_DERIVED_KEY { + pTemplate: derive_template.as_ptr() as *mut _, + ulAttributeCount: derive_template.len() as CK_ULONG, + phKey: &mut handle5, + }, + CK_DERIVED_KEY { + pTemplate: derive_template.as_ptr() as *mut _, + ulAttributeCount: derive_template.len() as CK_ULONG, + phKey: &mut handle6, + }, + ]; + params.ulAdditionalDerivedKeys = 2; + params.pAdditionalDerivedKeys = addl_keys.as_mut_ptr(); + ret = fn_derive_key( + session, + &mut derive_mech, + handle, + derive_template.as_ptr() as *mut _, + derive_template.len() as CK_ULONG, + &mut handle4, + ); + assert_eq!(ret, CKR_OK); + + /* check each key */ + let mut val: CK_ULONG = 0; + let attrtmpl = [make_attribute!( + CKA_VALUE_LEN, + &mut val as *mut _, + CK_ULONG_SIZE + )]; + + ret = fn_get_attribute_value( + session, + handle3, + attrtmpl.as_ptr() as *mut _, + attrtmpl.len() as CK_ULONG, + ); + assert_eq!(ret, CKR_OK); + assert_eq!(val, 16); + + val = 0; + ret = fn_get_attribute_value( + session, + handle4, + attrtmpl.as_ptr() as *mut _, + attrtmpl.len() as CK_ULONG, + ); + assert_eq!(ret, CKR_OK); + assert_eq!(val, 16); + + val = 0; + ret = fn_get_attribute_value( + session, + handle5, + attrtmpl.as_ptr() as *mut _, + attrtmpl.len() as CK_ULONG, + ); + assert_eq!(ret, CKR_OK); + assert_eq!(val, 16); + + val = 0; + ret = fn_get_attribute_value( + session, + handle6, + attrtmpl.as_ptr() as *mut _, + attrtmpl.len() as CK_ULONG, + ); + assert_eq!(ret, CKR_OK); + assert_eq!(val, 16); + ret = fn_close_session(session); assert_eq!(ret, CKR_OK); diff --git a/src/token.rs b/src/token.rs index 79322307..b74a9be3 100644 --- a/src/token.rs +++ b/src/token.rs @@ -11,6 +11,7 @@ use super::error; use super::hash; use super::hmac; use super::interface; +use super::kdf; use super::mechanism; use super::object; use super::rsa; @@ -201,6 +202,7 @@ impl Token { ecc::register(&mut token.mechanisms, &mut token.object_factories); hash::register(&mut token.mechanisms, &mut token.object_factories); hmac::register(&mut token.mechanisms, &mut token.object_factories); + kdf::register(&mut token.mechanisms, &mut token.object_factories); if token.filename.len() > 0 { match token.storage.open(&token.filename) { @@ -807,34 +809,11 @@ impl Token { Ok(handles) } - pub fn get_mech( - &self, - mech_type: CK_MECHANISM_TYPE, - ) -> KResult<&Box> { - self.mechanisms.get(mech_type) + pub fn get_mechanisms(&self) -> &Mechanisms { + &self.mechanisms } - pub fn get_obj_factory( - &self, - obj: &Object, - ) -> KResult<&Box> { - self.object_factories.get_object_factory(obj) - } - - pub fn get_obj_factory_from_key_template( - &self, - template: &[CK_ATTRIBUTE], - ) -> KResult<&Box> { - let class = match template.iter().position(|x| x.type_ == CKA_CLASS) { - Some(idx) => template[idx].to_ulong()?, - None => return err_rv!(CKR_TEMPLATE_INCONSISTENT), - }; - let key_type = - match template.iter().position(|x| x.type_ == CKA_KEY_TYPE) { - Some(idx) => template[idx].to_ulong()?, - None => return err_rv!(CKR_TEMPLATE_INCONSISTENT), - }; - self.object_factories - .get_factory(object::ObjectType::new(class, key_type)) + pub fn get_object_factories(&self) -> &ObjectFactories { + &self.object_factories } }