From f0a29747a0439ce865f94a10daa62ec00a098a48 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Fri, 4 Apr 2025 15:23:07 +0200 Subject: [PATCH 01/22] Added mechanisms for NIST SP 800-108 KDF and their parameters Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 376 ++++++++++++++++++++++++++++++++ cryptoki/src/mechanism/mod.rs | 38 ++++ 2 files changed, 414 insertions(+) create mode 100644 cryptoki/src/mechanism/kbkdf.rs diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs new file mode 100644 index 00000000..239c16bb --- /dev/null +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -0,0 +1,376 @@ +// Copyright 2025 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! Mechanisms of NIST key-based key derive functions (SP 800-108, informally KBKDF) +//! See: + +use std::{convert::TryInto, marker::PhantomData, ptr}; + +use cryptoki_sys::{ + CK_ATTRIBUTE, CK_ATTRIBUTE_PTR, CK_DERIVED_KEY, CK_DERIVED_KEY_PTR, CK_OBJECT_HANDLE, + CK_PRF_DATA_PARAM, CK_PRF_DATA_PARAM_PTR, CK_SP800_108_BYTE_ARRAY, CK_SP800_108_COUNTER, + CK_SP800_108_COUNTER_FORMAT, CK_SP800_108_DKM_LENGTH, CK_SP800_108_DKM_LENGTH_FORMAT, + CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS, + CK_SP800_108_ITERATION_VARIABLE, CK_ULONG, +}; + +use crate::object::Attribute; + +use super::MechanismType; + +/// Endianness of byte representation of data. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Endianness { + /// Little endian. + Little, + /// Big endian. + Big, +} + +/// Defines encoding format for a counter value. +/// +/// Corresponds to CK_SP800_108_COUNTER_FORMAT. +#[derive(Debug, Clone, Copy)] +pub struct KbkdfCounterFormat { + endianness: Endianness, + width_in_bits: usize, +} + +impl From for CK_SP800_108_COUNTER_FORMAT { + fn from(value: KbkdfCounterFormat) -> Self { + Self { + bLittleEndian: (value.endianness == Endianness::Little).into(), + ulWidthInBits: value + .width_in_bits + .try_into() + .expect("bit width of KBKDF internal counter does not fit in CK_ULONG"), + } + } +} + +/// Method for calculating length of DKM (derived key material). +/// +/// Corresponds to CK_SP800_108_DKM_LENGTH_METHOD. +#[derive(Debug, Clone, Copy)] +pub enum DkmLengthMethod { + /// Sum of length of all keys derived by given invocation of KDF. + SumOfKeys, + /// Sum of length of all segments of output produced by PRF in given invocation of KDF. + SumOfSegments, +} + +/// Defines encoding format for DKM (derived key material). +/// +/// Corresponds to CK_SP800_108_DKM_LENGTH_FORMAT. +#[derive(Debug, Clone, Copy)] +pub struct KbkdfDkmLengthFormat { + dkm_length_method: DkmLengthMethod, + endianness: Endianness, + width_in_bits: usize, +} + +impl From for CK_SP800_108_DKM_LENGTH_FORMAT { + fn from(value: KbkdfDkmLengthFormat) -> Self { + Self { + dkmLengthMethod: match value.dkm_length_method { + DkmLengthMethod::SumOfKeys => CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, + DkmLengthMethod::SumOfSegments => CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS, + }, + bLittleEndian: (value.endianness == Endianness::Little).into(), + ulWidthInBits: value + .width_in_bits + .try_into() + .expect("bit width of KBKDF derived key material does not fit in CK_ULONG"), + } + } +} + +/// A segment of input data for the PRF, to be used to construct a sequence of input. +/// +/// Corresponds to CK_PRF_DATA_PARAM in the specific cases of the KDF operating in feedback- or double pipeline-mode. +#[derive(Debug, Clone, Copy)] +pub enum PrfDataParam<'a> { + /// Identifies location of predefined iteration variable in constructed PRF input data. + IterationVariable, + /// Identifies location of counter in constructed PRF input data. + Counter(KbkdfCounterFormat), + /// Identifies location of DKM (derived key material) length in constructed PRF input data. + DkmLength(KbkdfDkmLengthFormat), + /// Identifies location and value of byte array of data in constructed PRF input data. + ByteArray(&'a [u8]), +} + +/// A segment of input data for the PRF, to be used to construct a sequence of input. +/// +/// Corresponds to CK_PRF_DATA_PARAM in the specific case of the KDF operating in counter-mode. +#[derive(Debug, Clone, Copy)] +pub enum PrfCounterDataParam<'a> { + /// Identifies location of iteration variable (a counter in this case) in constructed PRF input data. + IterationVariable(KbkdfCounterFormat), + /// Identifies location of DKM (derived key material) length in constructed PRF input data. + DkmLength(KbkdfDkmLengthFormat), + /// Identifies location and value of byte array of data in constructed PRF input data. + ByteArray(&'a [u8]), +} + +/// Parameters for additional key to be derived from base key. +#[derive(Debug, Clone, Copy)] +pub struct DerivedKey<'a> { + template: &'a [Attribute], + object_handle: CK_OBJECT_HANDLE, +} + +impl<'a> DerivedKey<'a> { + /// Construct template for additional key to be derived by KDF. + /// + /// # Arguments + /// + /// * `template` - The template for the key to be derived. + pub fn new(template: &'a [Attribute]) -> Self { + Self { + template, + object_handle: 0, + } + } +} + +/// NIST SP 800-108 (aka KBKDF) counter-mode parameters. +/// +/// This structure wraps a `CK_SP800_108_KDF_PARAMS` structure. +#[derive(Debug, Clone, Copy)] +#[repr(transparent)] +pub struct KbkdfCounterParams<'a> { + inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS, + /// Marker type to ensure we don't outlive the data + _marker: PhantomData<&'a [u8]>, +} + +impl<'a> KbkdfCounterParams<'a> { + /// Construct parameters for NIST SP 800-108 KDF (aka KBKDF) pseuderandom function-based key + /// derivation function, in counter-mode. + /// + /// # Arguments + /// + /// * `prf_mechanism` - The pseudorandom function that underlies the KBKDF operation. + /// + /// * `prf_data_params` - The sequence of data segments used as input data for the PRF. Requires at least [`PrfCounterDataParam::IterationVariable`]. + /// + /// * `additional_derived_keys` - Any additional keys to be generated by the KDF from the base key. + pub fn new( + prf_mechanism: MechanismType, + prf_data_params: Vec>, + additional_derived_keys: Vec>, + ) -> Self { + let prf_data_params: Vec = + prf_data_params.into_iter().map(Into::into).collect(); + let additional_derived_keys: Vec = additional_derived_keys + .into_iter() + .map(Into::into) + .collect(); + + Self { + inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS { + prfType: prf_mechanism.into(), + ulNumberOfDataParams: prf_data_params + .len() + .try_into() + .expect("number of data parameters does not fit in CK_ULONG"), + pDataParams: prf_data_params.as_ptr() as CK_PRF_DATA_PARAM_PTR, + ulAdditionalDerivedKeys: additional_derived_keys + .len() + .try_into() + .expect("number of additional derived keys does not fit in CK_ULONG"), + pAdditionalDerivedKeys: additional_derived_keys.as_ptr() as CK_DERIVED_KEY_PTR, + }, + _marker: PhantomData, + } + } +} + +/// NIST SP 800-108 (aka KBKDF) feedback-mode parameters. +/// +/// This structure wraps a `CK_SP800_108_FEEDBACK_KDF_PARAMS` structure. +#[derive(Debug, Clone, Copy)] +#[repr(transparent)] +pub struct KbkdfFeedbackParams<'a> { + inner: cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS, + /// Marker type to ensure we don't outlive the data + _marker: PhantomData<&'a [u8]>, +} + +impl<'a> KbkdfFeedbackParams<'a> { + /// Construct parameters for NIST SP 800-108 KDF (aka KBKDF) pseuderandom function-based key + /// derivation function, in feedback-mode. + /// + /// # Arguments + /// + /// * `prf_mechanism` - The pseudorandom function that underlies the KBKDF operation. + /// + /// * `prf_data_params` - The sequence of data segments used as input data for the PRF. Requires at least [`PrfCounterDataParam::IterationVariable`]. + /// + /// * `iv` - The IV to be used for the feedback-mode KDF. + /// + /// * `additional_derived_keys` - Any additional keys to be generated by the KDF from the base key. + pub fn new( + prf_mechanism: MechanismType, + prf_data_params: Vec>, + iv: Option<&'a [u8]>, + additional_derived_keys: Vec>, + ) -> Self { + let prf_data_params: Vec = + prf_data_params.into_iter().map(Into::into).collect(); + let additional_derived_keys: Vec = additional_derived_keys + .into_iter() + .map(Into::into) + .collect(); + + Self { + inner: cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS { + prfType: prf_mechanism.into(), + ulNumberOfDataParams: prf_data_params + .len() + .try_into() + .expect("number of data parameters does not fit in CK_ULONG"), + pDataParams: prf_data_params.as_ptr() as CK_PRF_DATA_PARAM_PTR, + ulIVLen: iv.map_or(0, |iv| { + iv.len() + .try_into() + .expect("IV length does not fit in CK_ULONG") + }), + pIV: iv.map_or(ptr::null_mut(), |iv| iv.as_ptr() as *mut _), + ulAdditionalDerivedKeys: additional_derived_keys + .len() + .try_into() + .expect("number of additional derived keys does not fit in CK_ULONG"), + pAdditionalDerivedKeys: additional_derived_keys.as_ptr() as CK_DERIVED_KEY_PTR, + }, + _marker: PhantomData, + } + } +} + +/// NIST SP 800-108 (aka KBKDF) double pipeline-mode parameters. +/// +/// This structure wraps a `CK_SP800_108_KDF_PARAMS` structure. +#[derive(Debug, Clone, Copy)] +#[repr(transparent)] +pub struct KbkdfDoublePipelineParams<'a> { + inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS, + /// Marker type to ensure we don't outlive the data + _marker: PhantomData<&'a [u8]>, +} + +impl<'a> KbkdfDoublePipelineParams<'a> { + /// Construct parameters for NIST SP 800-108 KDF (aka KBKDF) pseuderandom function-based key + /// derivation function, in double pipeline-mode. + /// + /// # Arguments + /// + /// * `prf_mechanism` - The pseudorandom function that underlies the KBKDF operation. + /// + /// * `prf_data_params` - The sequence of data segments used as input data for the PRF. Requires at least [`PrfCounterDataParam::IterationVariable`]. + /// + /// * `additional_derived_keys` - Any additional keys to be generated by the KDF from the base key. + pub fn new( + prf_mechanism: MechanismType, + prf_data_params: Vec>, + additional_derived_keys: Vec>, + ) -> Self { + let prf_data_params: Vec = + prf_data_params.into_iter().map(Into::into).collect(); + let additional_derived_keys: Vec = additional_derived_keys + .into_iter() + .map(Into::into) + .collect(); + + Self { + inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS { + prfType: prf_mechanism.into(), + ulNumberOfDataParams: prf_data_params + .len() + .try_into() + .expect("number of data parameters does not fit in CK_ULONG"), + pDataParams: prf_data_params.as_ptr() as CK_PRF_DATA_PARAM_PTR, + ulAdditionalDerivedKeys: additional_derived_keys + .len() + .try_into() + .expect("number of additional derived keys does not fit in CK_ULONG"), + pAdditionalDerivedKeys: additional_derived_keys.as_ptr() as CK_DERIVED_KEY_PTR, + }, + _marker: PhantomData, + } + } +} + +impl<'a> From> for CK_PRF_DATA_PARAM { + fn from(value: PrfDataParam<'a>) -> Self { + Self { + type_: match value { + PrfDataParam::IterationVariable => CK_SP800_108_ITERATION_VARIABLE, + PrfDataParam::Counter(_) => CK_SP800_108_COUNTER, + PrfDataParam::DkmLength(_) => CK_SP800_108_DKM_LENGTH, + PrfDataParam::ByteArray(_) => CK_SP800_108_BYTE_ARRAY, + }, + pValue: match value { + PrfDataParam::IterationVariable => ptr::null_mut(), + PrfDataParam::Counter(inner) => &inner as *const _ as *mut _, + PrfDataParam::DkmLength(inner) => &inner as *const _ as *mut _, + PrfDataParam::ByteArray(data) => data.as_ptr() as *mut _, + }, + ulValueLen: match value { + PrfDataParam::IterationVariable => 0, + PrfDataParam::Counter(_) => size_of::() as CK_ULONG, + PrfDataParam::DkmLength(_) => { + size_of::() as CK_ULONG + } + PrfDataParam::ByteArray(data) => data + .len() + .try_into() + .expect("length of data parameter does not fit in CK_ULONG"), + }, + } + } +} + +impl<'a> From> for CK_PRF_DATA_PARAM { + fn from(value: PrfCounterDataParam<'a>) -> Self { + Self { + type_: match value { + PrfCounterDataParam::IterationVariable(_) => CK_SP800_108_ITERATION_VARIABLE, + PrfCounterDataParam::DkmLength(_) => CK_SP800_108_DKM_LENGTH, + PrfCounterDataParam::ByteArray(_) => CK_SP800_108_BYTE_ARRAY, + }, + pValue: match value { + PrfCounterDataParam::IterationVariable(inner) => &inner as *const _ as *mut _, + PrfCounterDataParam::DkmLength(inner) => &inner as *const _ as *mut _, + PrfCounterDataParam::ByteArray(data) => data.as_ptr() as *mut _, + }, + ulValueLen: match value { + PrfCounterDataParam::IterationVariable(_) => { + size_of::() as CK_ULONG + } + PrfCounterDataParam::DkmLength(_) => { + size_of::() as CK_ULONG + } + PrfCounterDataParam::ByteArray(data) => data + .len() + .try_into() + .expect("length of data parameter does not fit in CK_ULONG"), + }, + } + } +} + +impl<'a> From> for CK_DERIVED_KEY { + fn from(mut value: DerivedKey<'a>) -> Self { + let template: Vec = value.template.iter().map(|attr| attr.into()).collect(); + + Self { + pTemplate: template.as_ptr() as CK_ATTRIBUTE_PTR, + ulAttributeCount: template + .len() + .try_into() + .expect("number of attributes in template does not fit in CK_ULONG"), + phKey: &mut value.object_handle, + } + } +} diff --git a/cryptoki/src/mechanism/mod.rs b/cryptoki/src/mechanism/mod.rs index b5ca489d..096691c5 100644 --- a/cryptoki/src/mechanism/mod.rs +++ b/cryptoki/src/mechanism/mod.rs @@ -7,6 +7,7 @@ pub mod eddsa; pub mod ekdf; pub mod elliptic_curve; pub mod hkdf; +pub mod kbkdf; mod mechanism_info; pub mod rsa; pub mod vendor_defined; @@ -326,6 +327,20 @@ impl MechanismType { /// HKDF-DATA mechanism pub const HKDF_DATA: MechanismType = MechanismType { val: CKM_HKDF_DATA }; + // NIST SP 800-108 KDF (aka KBKDF) + /// NIST SP 800-108 KDF (aka KBKDF) mechanism in counter-mode + pub const SP800_108_COUNTER_KDF: MechanismType = MechanismType { + val: CKM_SP800_108_COUNTER_KDF, + }; + /// NIST SP 800-108 KDF (aka KBKDF) mechanism in feedback-mode + pub const SP800_108_FEEDBACK_KDF: MechanismType = MechanismType { + val: CKM_SP800_108_FEEDBACK_KDF, + }; + /// NIST SP 800-108 KDF (aka KBKDF) mechanism in double pipeline-mode + pub const SP800_108_DOUBLE_PIPELINE_KDF: MechanismType = MechanismType { + val: CKM_SP800_108_DOUBLE_PIPELINE_KDF, + }; + /// Create vendor defined mechanism /// /// # Arguments @@ -715,6 +730,11 @@ impl MechanismType { CKM_HKDF_KEY_GEN => String::from(stringify!(CKM_HKDF_KEY_GEN)), CKM_HKDF_DERIVE => String::from(stringify!(CKM_HKDF_DERIVE)), CKM_HKDF_DATA => String::from(stringify!(CKM_HKDF_DATA)), + CKM_SP800_108_COUNTER_KDF => String::from(stringify!(CKM_SP800_108_COUNTER_KDF)), + CKM_SP800_108_FEEDBACK_KDF => String::from(stringify!(CKM_SP800_108_FEEDBACK_KDF)), + CKM_SP800_108_DOUBLE_PIPELINE_KDF => { + String::from(stringify!(CKM_SP800_108_DOUBLE_PIPELINE_KDF)) + } _ => format!("unknown {mech:08x}"), } } @@ -799,6 +819,9 @@ impl TryFrom for MechanismType { CKM_HKDF_KEY_GEN => Ok(MechanismType::HKDF_KEY_GEN), CKM_HKDF_DERIVE => Ok(MechanismType::HKDF_DERIVE), CKM_HKDF_DATA => Ok(MechanismType::HKDF_DATA), + CKM_SP800_108_COUNTER_KDF => Ok(MechanismType::SP800_108_COUNTER_KDF), + CKM_SP800_108_FEEDBACK_KDF => Ok(MechanismType::SP800_108_FEEDBACK_KDF), + CKM_SP800_108_DOUBLE_PIPELINE_KDF => Ok(MechanismType::SP800_108_DOUBLE_PIPELINE_KDF), other => { error!("Mechanism type {} is not supported.", other); Err(Error::NotSupported) @@ -1021,6 +1044,14 @@ pub enum Mechanism<'a> { /// HKDF-DATA mechanism HkdfData(hkdf::HkdfParams<'a>), + // NIST SP 800-108 KDF (aka KBKDF) + /// NIST SP 800-108 KDF (aka KBKDF) mechanism in counter-mode + KbkdfCounter(kbkdf::KbkdfCounterParams<'a>), + /// NIST SP 800-108 KDF (aka KBKDF) mechanism in feedback-mode + KbkdfFeedback(kbkdf::KbkdfFeedbackParams<'a>), + /// NIST SP 800-108 KDF (aka KBKDF) mechanism in double pipeline-mode + KbkdfDoublePipeline(kbkdf::KbkdfDoublePipelineParams<'a>), + /// Vendor defined mechanism VendorDefined(VendorDefinedMechanism<'a>), } @@ -1102,6 +1133,10 @@ impl Mechanism<'_> { Mechanism::HkdfDerive(_) => MechanismType::HKDF_DERIVE, Mechanism::HkdfData(_) => MechanismType::HKDF_DATA, + Mechanism::KbkdfCounter(_) => MechanismType::SP800_108_COUNTER_KDF, + Mechanism::KbkdfFeedback(_) => MechanismType::SP800_108_FEEDBACK_KDF, + Mechanism::KbkdfDoublePipeline(_) => MechanismType::SP800_108_DOUBLE_PIPELINE_KDF, + Mechanism::VendorDefined(vm) => MechanismType { val: vm.inner.mechanism, }, @@ -1154,6 +1189,9 @@ impl From<&Mechanism<'_>> for CK_MECHANISM { Mechanism::HkdfDerive(params) | Mechanism::HkdfData(params) => { make_mechanism(mechanism, params) } + Mechanism::KbkdfCounter(params) => make_mechanism(mechanism, params), + Mechanism::KbkdfFeedback(params) => make_mechanism(mechanism, params), + Mechanism::KbkdfDoublePipeline(params) => make_mechanism(mechanism, params), // Mechanisms without parameters Mechanism::AesKeyGen | Mechanism::AesEcb From 543dd75e94b3193142c2b9ef16742899f38784dc Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Tue, 8 Apr 2025 11:01:12 +0200 Subject: [PATCH 02/22] Added derive_keys function to get additional derived keys from mechanism params Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 105 ++++++++++++++++++------- cryptoki/src/mechanism/mod.rs | 25 +++++- cryptoki/src/session/key_management.rs | 29 ++++++- 3 files changed, 127 insertions(+), 32 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index 239c16bb..1e2ba5b0 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -3,7 +3,7 @@ //! Mechanisms of NIST key-based key derive functions (SP 800-108, informally KBKDF) //! See: -use std::{convert::TryInto, marker::PhantomData, ptr}; +use core::{convert::TryInto, marker::PhantomData, ptr, slice}; use cryptoki_sys::{ CK_ATTRIBUTE, CK_ATTRIBUTE_PTR, CK_DERIVED_KEY, CK_DERIVED_KEY_PTR, CK_OBJECT_HANDLE, @@ -158,14 +158,12 @@ impl<'a> KbkdfCounterParams<'a> { pub fn new( prf_mechanism: MechanismType, prf_data_params: Vec>, - additional_derived_keys: Vec>, + mut additional_derived_keys: Vec>, ) -> Self { let prf_data_params: Vec = - prf_data_params.into_iter().map(Into::into).collect(); - let additional_derived_keys: Vec = additional_derived_keys - .into_iter() - .map(Into::into) - .collect(); + prf_data_params.iter().map(Into::into).collect(); + let additional_derived_keys: Vec = + additional_derived_keys.iter_mut().map(Into::into).collect(); Self { inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS { @@ -184,6 +182,23 @@ impl<'a> KbkdfCounterParams<'a> { _marker: PhantomData, } } + + /// The additional keys derived by the KDF, as per the params + pub fn additional_derived_keys(&self) -> Vec { + let derived_keys = unsafe { + slice::from_raw_parts( + self.inner.pAdditionalDerivedKeys, + self.inner.ulAdditionalDerivedKeys as _, + ) + }; + + unsafe { + derived_keys + .iter() + .map(|derived_key| *derived_key.phKey) + .collect() + } + } } /// NIST SP 800-108 (aka KBKDF) feedback-mode parameters. @@ -214,14 +229,12 @@ impl<'a> KbkdfFeedbackParams<'a> { prf_mechanism: MechanismType, prf_data_params: Vec>, iv: Option<&'a [u8]>, - additional_derived_keys: Vec>, + mut additional_derived_keys: Vec>, ) -> Self { let prf_data_params: Vec = - prf_data_params.into_iter().map(Into::into).collect(); - let additional_derived_keys: Vec = additional_derived_keys - .into_iter() - .map(Into::into) - .collect(); + prf_data_params.iter().map(Into::into).collect(); + let additional_derived_keys: Vec = + additional_derived_keys.iter_mut().map(Into::into).collect(); Self { inner: cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS { @@ -246,6 +259,23 @@ impl<'a> KbkdfFeedbackParams<'a> { _marker: PhantomData, } } + + /// The additional keys derived by the KDF, as per the params + pub fn additional_derived_keys(&self) -> Vec { + let derived_keys = unsafe { + slice::from_raw_parts( + self.inner.pAdditionalDerivedKeys, + self.inner.ulAdditionalDerivedKeys as _, + ) + }; + + unsafe { + derived_keys + .iter() + .map(|derived_key| *derived_key.phKey) + .collect() + } + } } /// NIST SP 800-108 (aka KBKDF) double pipeline-mode parameters. @@ -273,14 +303,12 @@ impl<'a> KbkdfDoublePipelineParams<'a> { pub fn new( prf_mechanism: MechanismType, prf_data_params: Vec>, - additional_derived_keys: Vec>, + mut additional_derived_keys: Vec>, ) -> Self { let prf_data_params: Vec = - prf_data_params.into_iter().map(Into::into).collect(); - let additional_derived_keys: Vec = additional_derived_keys - .into_iter() - .map(Into::into) - .collect(); + prf_data_params.iter().map(Into::into).collect(); + let additional_derived_keys: Vec = + additional_derived_keys.iter_mut().map(Into::into).collect(); Self { inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS { @@ -299,10 +327,27 @@ impl<'a> KbkdfDoublePipelineParams<'a> { _marker: PhantomData, } } + + /// The additional keys derived by the KDF, as per the params + pub fn additional_derived_keys(&self) -> Vec { + let derived_keys = unsafe { + slice::from_raw_parts( + self.inner.pAdditionalDerivedKeys, + self.inner.ulAdditionalDerivedKeys as _, + ) + }; + + unsafe { + derived_keys + .iter() + .map(|derived_key| *derived_key.phKey) + .collect() + } + } } -impl<'a> From> for CK_PRF_DATA_PARAM { - fn from(value: PrfDataParam<'a>) -> Self { +impl<'a> From<&PrfDataParam<'a>> for CK_PRF_DATA_PARAM { + fn from(value: &PrfDataParam<'a>) -> Self { Self { type_: match value { PrfDataParam::IterationVariable => CK_SP800_108_ITERATION_VARIABLE, @@ -312,8 +357,8 @@ impl<'a> From> for CK_PRF_DATA_PARAM { }, pValue: match value { PrfDataParam::IterationVariable => ptr::null_mut(), - PrfDataParam::Counter(inner) => &inner as *const _ as *mut _, - PrfDataParam::DkmLength(inner) => &inner as *const _ as *mut _, + PrfDataParam::Counter(inner) => inner as *const _ as *mut _, + PrfDataParam::DkmLength(inner) => inner as *const _ as *mut _, PrfDataParam::ByteArray(data) => data.as_ptr() as *mut _, }, ulValueLen: match value { @@ -331,8 +376,8 @@ impl<'a> From> for CK_PRF_DATA_PARAM { } } -impl<'a> From> for CK_PRF_DATA_PARAM { - fn from(value: PrfCounterDataParam<'a>) -> Self { +impl<'a> From<&PrfCounterDataParam<'a>> for CK_PRF_DATA_PARAM { + fn from(value: &PrfCounterDataParam<'a>) -> Self { Self { type_: match value { PrfCounterDataParam::IterationVariable(_) => CK_SP800_108_ITERATION_VARIABLE, @@ -340,8 +385,8 @@ impl<'a> From> for CK_PRF_DATA_PARAM { PrfCounterDataParam::ByteArray(_) => CK_SP800_108_BYTE_ARRAY, }, pValue: match value { - PrfCounterDataParam::IterationVariable(inner) => &inner as *const _ as *mut _, - PrfCounterDataParam::DkmLength(inner) => &inner as *const _ as *mut _, + PrfCounterDataParam::IterationVariable(inner) => inner as *const _ as *mut _, + PrfCounterDataParam::DkmLength(inner) => inner as *const _ as *mut _, PrfCounterDataParam::ByteArray(data) => data.as_ptr() as *mut _, }, ulValueLen: match value { @@ -360,9 +405,9 @@ impl<'a> From> for CK_PRF_DATA_PARAM { } } -impl<'a> From> for CK_DERIVED_KEY { - fn from(mut value: DerivedKey<'a>) -> Self { - let template: Vec = value.template.iter().map(|attr| attr.into()).collect(); +impl<'a> From<&mut DerivedKey<'a>> for CK_DERIVED_KEY { + fn from(value: &mut DerivedKey<'a>) -> Self { + let template: Vec = value.template.iter().map(Into::into).collect(); Self { pTemplate: template.as_ptr() as CK_ATTRIBUTE_PTR, diff --git a/cryptoki/src/mechanism/mod.rs b/cryptoki/src/mechanism/mod.rs index 096691c5..87da54fc 100644 --- a/cryptoki/src/mechanism/mod.rs +++ b/cryptoki/src/mechanism/mod.rs @@ -12,7 +12,6 @@ mod mechanism_info; pub mod rsa; pub mod vendor_defined; -use crate::error::Error; use cryptoki_sys::*; use log::error; use std::convert::{TryFrom, TryInto}; @@ -23,7 +22,9 @@ use std::ops::Deref; use std::ptr::null_mut; use vendor_defined::VendorDefinedMechanism; +use crate::error::Error; use crate::mechanism::rsa::PkcsOaepParams; +use crate::object::ObjectHandle; pub use mechanism_info::MechanismInfo; #[derive(Copy, Debug, Clone, PartialEq, Eq)] @@ -1283,3 +1284,25 @@ impl MessageParam<'_> { } } } + +/// Trait for mechanism types that define additional keys to be derived in their parameters +pub trait HasAdditionalDerivedKeys { + /// Get the object handles for the additional keys that were derived + fn additional_derived_keys(&self) -> Vec; +} + +impl HasAdditionalDerivedKeys for &Mechanism<'_> { + fn additional_derived_keys(&self) -> Vec { + let additional_derived_keys = match self { + Mechanism::KbkdfCounter(params) => params.additional_derived_keys(), + Mechanism::KbkdfFeedback(params) => params.additional_derived_keys(), + Mechanism::KbkdfDoublePipeline(params) => params.additional_derived_keys(), + _ => unimplemented!("The given mechanism doesn't define additional keys to derive"), // TODO: this or return an option? + }; + + additional_derived_keys + .into_iter() + .map(ObjectHandle::new) + .collect() + } +} diff --git a/cryptoki/src/session/key_management.rs b/cryptoki/src/session/key_management.rs index 0d5dfd13..f0b43ea8 100644 --- a/cryptoki/src/session/key_management.rs +++ b/cryptoki/src/session/key_management.rs @@ -4,7 +4,7 @@ use crate::context::Function; use crate::error::{Result, Rv}; -use crate::mechanism::Mechanism; +use crate::mechanism::{HasAdditionalDerivedKeys as _, Mechanism}; use crate::object::{Attribute, ObjectHandle}; use crate::session::Session; use cryptoki_sys::{CK_ATTRIBUTE, CK_MECHANISM, CK_MECHANISM_PTR}; @@ -93,6 +93,33 @@ impl Session { Ok(ObjectHandle::new(handle)) } + /// Derives multiple keys from a base key + pub fn derive_keys( + &self, + mechanism: &Mechanism, + base_key: ObjectHandle, + template: &[Attribute], + ) -> Result<(ObjectHandle, Vec)> { + let mut c_mechanism: CK_MECHANISM = mechanism.into(); + let mut template: Vec = template.iter().map(|attr| attr.into()).collect(); + let mut handle = 0; + unsafe { + Rv::from(get_pkcs11!(self.client(), C_DeriveKey)( + self.handle(), + &mut c_mechanism as CK_MECHANISM_PTR, + base_key.handle(), + template.as_mut_ptr(), + template.len().try_into()?, + &mut handle, + )) + .into_result(Function::DeriveKey)?; + } + + let additional_key_handles = mechanism.additional_derived_keys(); + + Ok((ObjectHandle::new(handle), additional_key_handles)) + } + /// Wrap key pub fn wrap_key( &self, From 06418732358769a3ce3cd246226d52339da1083a Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Wed, 9 Apr 2025 12:33:44 +0200 Subject: [PATCH 03/22] Restructured design to actually be able to reference original memory locations in PKCS#11 structs Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 317 ++++++++++++++++++-------------- 1 file changed, 175 insertions(+), 142 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index 1e2ba5b0..b5b690ed 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -6,11 +6,12 @@ use core::{convert::TryInto, marker::PhantomData, ptr, slice}; use cryptoki_sys::{ - CK_ATTRIBUTE, CK_ATTRIBUTE_PTR, CK_DERIVED_KEY, CK_DERIVED_KEY_PTR, CK_OBJECT_HANDLE, + CK_ATTRIBUTE_PTR, CK_DERIVED_KEY, CK_DERIVED_KEY_PTR, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE_PTR, CK_PRF_DATA_PARAM, CK_PRF_DATA_PARAM_PTR, CK_SP800_108_BYTE_ARRAY, CK_SP800_108_COUNTER, CK_SP800_108_COUNTER_FORMAT, CK_SP800_108_DKM_LENGTH, CK_SP800_108_DKM_LENGTH_FORMAT, CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS, - CK_SP800_108_ITERATION_VARIABLE, CK_ULONG, + CK_SP800_108_FEEDBACK_KDF_PARAMS, CK_SP800_108_ITERATION_VARIABLE, CK_SP800_108_KDF_PARAMS, + CK_ULONG, }; use crate::object::Attribute; @@ -28,21 +29,29 @@ pub enum Endianness { /// Defines encoding format for a counter value. /// -/// Corresponds to CK_SP800_108_COUNTER_FORMAT. +/// This structure wraps a `CK_SP800_108_COUNTER_FORMAT` structure. #[derive(Debug, Clone, Copy)] +#[repr(transparent)] pub struct KbkdfCounterFormat { - endianness: Endianness, - width_in_bits: usize, + inner: CK_SP800_108_COUNTER_FORMAT, } -impl From for CK_SP800_108_COUNTER_FORMAT { - fn from(value: KbkdfCounterFormat) -> Self { +impl KbkdfCounterFormat { + /// Construct encoding format for KDF's internal counter variable. + /// + /// # Arguments + /// + /// * `endianness` - The endianness of the counter's bit representation. + /// + /// * `width_in_bits` - The number of bits used to represent the counter value. + pub fn new(endianness: Endianness, width_in_bits: usize) -> Self { Self { - bLittleEndian: (value.endianness == Endianness::Little).into(), - ulWidthInBits: value - .width_in_bits + inner: CK_SP800_108_COUNTER_FORMAT { + bLittleEndian: (endianness == Endianness::Little).into(), + ulWidthInBits: width_in_bits .try_into() .expect("bit width of KBKDF internal counter does not fit in CK_ULONG"), + }, } } } @@ -60,63 +69,167 @@ pub enum DkmLengthMethod { /// Defines encoding format for DKM (derived key material). /// -/// Corresponds to CK_SP800_108_DKM_LENGTH_FORMAT. +/// This structure wraps a `CK_SP800_108_DKM_LENGTH_FORMAT` structure. #[derive(Debug, Clone, Copy)] +#[repr(transparent)] pub struct KbkdfDkmLengthFormat { + inner: CK_SP800_108_DKM_LENGTH_FORMAT, +} + +impl KbkdfDkmLengthFormat { + /// Construct encoding format for length value of DKM (derived key material) from KDF. + /// + /// # Arguments + /// + /// * `dkm_length_method` - The method used to calculate the DKM length value. + /// + /// * `endianness` - The endianness of the DKM length value's bit representation. + /// + /// * `width_in_bits` - The number of bits used to represent the DKM length value. + pub fn new( dkm_length_method: DkmLengthMethod, endianness: Endianness, width_in_bits: usize, -} - -impl From for CK_SP800_108_DKM_LENGTH_FORMAT { - fn from(value: KbkdfDkmLengthFormat) -> Self { + ) -> Self { Self { - dkmLengthMethod: match value.dkm_length_method { + inner: CK_SP800_108_DKM_LENGTH_FORMAT { + dkmLengthMethod: match dkm_length_method { DkmLengthMethod::SumOfKeys => CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, DkmLengthMethod::SumOfSegments => CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS, + }, + bLittleEndian: (endianness == Endianness::Little).into(), + ulWidthInBits: width_in_bits.try_into().expect( + "bit width of KBKDF derived key material length value does not fit in CK_ULONG", + ), }, - bLittleEndian: (value.endianness == Endianness::Little).into(), - ulWidthInBits: value - .width_in_bits - .try_into() - .expect("bit width of KBKDF derived key material does not fit in CK_ULONG"), } } } -/// A segment of input data for the PRF, to be used to construct a sequence of input. -/// -/// Corresponds to CK_PRF_DATA_PARAM in the specific cases of the KDF operating in feedback- or double pipeline-mode. +/// The type of a segment of input data for the PRF, for a KBKDF operating in feedback- or double pipeline-mode. #[derive(Debug, Clone, Copy)] -pub enum PrfDataParam<'a> { +pub enum PrfDataParamType<'a> { /// Identifies location of predefined iteration variable in constructed PRF input data. IterationVariable, /// Identifies location of counter in constructed PRF input data. - Counter(KbkdfCounterFormat), + Counter(&'a KbkdfCounterFormat), /// Identifies location of DKM (derived key material) length in constructed PRF input data. - DkmLength(KbkdfDkmLengthFormat), + DkmLength(&'a KbkdfDkmLengthFormat), /// Identifies location and value of byte array of data in constructed PRF input data. ByteArray(&'a [u8]), } /// A segment of input data for the PRF, to be used to construct a sequence of input. /// -/// Corresponds to CK_PRF_DATA_PARAM in the specific case of the KDF operating in counter-mode. +/// Corresponds to CK_PRF_DATA_PARAM in the specific cases of the KDF operating in feedback- or double pipeline-mode. #[derive(Debug, Clone, Copy)] -pub enum PrfCounterDataParam<'a> { +#[repr(transparent)] +pub struct PrfDataParam<'a> { + inner: CK_PRF_DATA_PARAM, + /// Marker type to ensure we don't outlive the data + _marker: PhantomData<&'a [u8]>, +} + +impl<'a> PrfDataParam<'a> { + /// Construct data parameter for input of the PRF internal to the KBKDF. + /// + /// # Arguments + /// + /// * `type_` - The specific type and parameters for the data parameter. + pub fn new(type_: PrfDataParamType<'a>) -> Self { + Self { + inner: match type_ { + PrfDataParamType::IterationVariable => CK_PRF_DATA_PARAM { + type_: CK_SP800_108_ITERATION_VARIABLE, + pValue: ptr::null_mut(), + ulValueLen: 0, + }, + PrfDataParamType::Counter(counter_format) => CK_PRF_DATA_PARAM { + type_: CK_SP800_108_COUNTER, + pValue: &counter_format.inner as *const _ as *mut _, + ulValueLen: size_of::() as CK_ULONG, + }, + PrfDataParamType::DkmLength(dkm_length_format) => CK_PRF_DATA_PARAM { + type_: CK_SP800_108_DKM_LENGTH, + pValue: &dkm_length_format.inner as *const _ as *mut _, + ulValueLen: size_of::() as CK_ULONG, + }, + PrfDataParamType::ByteArray(data) => CK_PRF_DATA_PARAM { + type_: CK_SP800_108_BYTE_ARRAY, + pValue: data.as_ptr() as *mut _, + ulValueLen: data + .len() + .try_into() + .expect("length of data parameter does not fit in CK_ULONG"), + }, + }, + _marker: PhantomData, + } + } +} + +/// The type of a segment of input data for the PRF, for a KBKDF operating in counter-mode. +#[derive(Debug, Clone, Copy)] +pub enum PrfCounterDataParamType<'a> { /// Identifies location of iteration variable (a counter in this case) in constructed PRF input data. - IterationVariable(KbkdfCounterFormat), + IterationVariable(&'a KbkdfCounterFormat), /// Identifies location of DKM (derived key material) length in constructed PRF input data. - DkmLength(KbkdfDkmLengthFormat), + DkmLength(&'a KbkdfDkmLengthFormat), /// Identifies location and value of byte array of data in constructed PRF input data. ByteArray(&'a [u8]), } +/// A segment of input data for the PRF, to be used to construct a sequence of input. +/// +/// Corresponds to CK_PRF_DATA_PARAM in the specific case of the KDF operating in counter-mode. +#[derive(Debug, Clone, Copy)] +#[repr(transparent)] +pub struct PrfCounterDataParam<'a> { + inner: CK_PRF_DATA_PARAM, + /// Marker type to ensure we don't outlive the data + _marker: PhantomData<&'a [u8]>, +} + +impl<'a> PrfCounterDataParam<'a> { + /// Construct data parameter for input of the PRF internal to the KBKDF. + /// + /// # Arguments + /// + /// * `type_` - The specific type and parameters for the data parameter. + pub fn new(type_: PrfCounterDataParamType<'a>) -> Self { + Self { + inner: match type_ { + PrfCounterDataParamType::IterationVariable(counter_format) => CK_PRF_DATA_PARAM { + type_: CK_SP800_108_ITERATION_VARIABLE, + pValue: &counter_format.inner as *const _ as *mut _, + ulValueLen: size_of::() as CK_ULONG, + }, + PrfCounterDataParamType::DkmLength(dkm_length_format) => CK_PRF_DATA_PARAM { + type_: CK_SP800_108_DKM_LENGTH, + pValue: &dkm_length_format.inner as *const _ as *mut _, + ulValueLen: size_of::() as CK_ULONG, + }, + PrfCounterDataParamType::ByteArray(data) => CK_PRF_DATA_PARAM { + type_: CK_SP800_108_BYTE_ARRAY, + pValue: data.as_ptr() as *mut _, + ulValueLen: data + .len() + .try_into() + .expect("length of data parameter does not fit in CK_ULONG"), + }, + }, + _marker: PhantomData, + } + } +} + /// Parameters for additional key to be derived from base key. #[derive(Debug, Clone, Copy)] +#[repr(transparent)] pub struct DerivedKey<'a> { - template: &'a [Attribute], - object_handle: CK_OBJECT_HANDLE, + inner: CK_DERIVED_KEY, + /// Marker type to ensure we don't outlive the data + _marker: PhantomData<&'a [u8]>, } impl<'a> DerivedKey<'a> { @@ -125,10 +238,19 @@ impl<'a> DerivedKey<'a> { /// # Arguments /// /// * `template` - The template for the key to be derived. - pub fn new(template: &'a [Attribute]) -> Self { + /// + /// * `handle` - The location into which will be written the handle of the new derived key. + pub fn new(template: &'a [Attribute], handle: &'a mut u64) -> Self { Self { - template, - object_handle: 0, + inner: CK_DERIVED_KEY { + pTemplate: template.as_ptr() as CK_ATTRIBUTE_PTR, + ulAttributeCount: template + .len() + .try_into() + .expect("number of attributes in template does not fit in CK_ULONG"), + phKey: handle as CK_OBJECT_HANDLE_PTR, + }, + _marker: PhantomData, } } } @@ -139,7 +261,7 @@ impl<'a> DerivedKey<'a> { #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct KbkdfCounterParams<'a> { - inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS, + inner: CK_SP800_108_KDF_PARAMS, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, } @@ -157,16 +279,11 @@ impl<'a> KbkdfCounterParams<'a> { /// * `additional_derived_keys` - Any additional keys to be generated by the KDF from the base key. pub fn new( prf_mechanism: MechanismType, - prf_data_params: Vec>, - mut additional_derived_keys: Vec>, + prf_data_params: &'a [PrfCounterDataParam<'a>], + additional_derived_keys: &'a mut [DerivedKey<'a>], ) -> Self { - let prf_data_params: Vec = - prf_data_params.iter().map(Into::into).collect(); - let additional_derived_keys: Vec = - additional_derived_keys.iter_mut().map(Into::into).collect(); - Self { - inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS { + inner: CK_SP800_108_KDF_PARAMS { prfType: prf_mechanism.into(), ulNumberOfDataParams: prf_data_params .len() @@ -177,7 +294,7 @@ impl<'a> KbkdfCounterParams<'a> { .len() .try_into() .expect("number of additional derived keys does not fit in CK_ULONG"), - pAdditionalDerivedKeys: additional_derived_keys.as_ptr() as CK_DERIVED_KEY_PTR, + pAdditionalDerivedKeys: additional_derived_keys.as_mut_ptr() as CK_DERIVED_KEY_PTR, }, _marker: PhantomData, } @@ -207,7 +324,7 @@ impl<'a> KbkdfCounterParams<'a> { #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct KbkdfFeedbackParams<'a> { - inner: cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS, + inner: CK_SP800_108_FEEDBACK_KDF_PARAMS, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, } @@ -220,24 +337,19 @@ impl<'a> KbkdfFeedbackParams<'a> { /// /// * `prf_mechanism` - The pseudorandom function that underlies the KBKDF operation. /// - /// * `prf_data_params` - The sequence of data segments used as input data for the PRF. Requires at least [`PrfCounterDataParam::IterationVariable`]. + /// * `prf_data_params` - The sequence of data segments used as input data for the PRF. Requires at least [`PrfDataParam::IterationVariable`]. /// /// * `iv` - The IV to be used for the feedback-mode KDF. /// /// * `additional_derived_keys` - Any additional keys to be generated by the KDF from the base key. pub fn new( prf_mechanism: MechanismType, - prf_data_params: Vec>, + prf_data_params: &'a [PrfDataParam<'a>], iv: Option<&'a [u8]>, - mut additional_derived_keys: Vec>, + additional_derived_keys: &'a mut [DerivedKey<'a>], ) -> Self { - let prf_data_params: Vec = - prf_data_params.iter().map(Into::into).collect(); - let additional_derived_keys: Vec = - additional_derived_keys.iter_mut().map(Into::into).collect(); - Self { - inner: cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS { + inner: CK_SP800_108_FEEDBACK_KDF_PARAMS { prfType: prf_mechanism.into(), ulNumberOfDataParams: prf_data_params .len() @@ -254,7 +366,7 @@ impl<'a> KbkdfFeedbackParams<'a> { .len() .try_into() .expect("number of additional derived keys does not fit in CK_ULONG"), - pAdditionalDerivedKeys: additional_derived_keys.as_ptr() as CK_DERIVED_KEY_PTR, + pAdditionalDerivedKeys: additional_derived_keys.as_mut_ptr() as CK_DERIVED_KEY_PTR, }, _marker: PhantomData, } @@ -284,7 +396,7 @@ impl<'a> KbkdfFeedbackParams<'a> { #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct KbkdfDoublePipelineParams<'a> { - inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS, + inner: CK_SP800_108_KDF_PARAMS, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, } @@ -297,21 +409,16 @@ impl<'a> KbkdfDoublePipelineParams<'a> { /// /// * `prf_mechanism` - The pseudorandom function that underlies the KBKDF operation. /// - /// * `prf_data_params` - The sequence of data segments used as input data for the PRF. Requires at least [`PrfCounterDataParam::IterationVariable`]. + /// * `prf_data_params` - The sequence of data segments used as input data for the PRF. Requires at least [`PrfDataParam::IterationVariable`]. /// /// * `additional_derived_keys` - Any additional keys to be generated by the KDF from the base key. pub fn new( prf_mechanism: MechanismType, - prf_data_params: Vec>, - mut additional_derived_keys: Vec>, + prf_data_params: &'a [PrfDataParam<'a>], + additional_derived_keys: &'a mut [DerivedKey<'a>], ) -> Self { - let prf_data_params: Vec = - prf_data_params.iter().map(Into::into).collect(); - let additional_derived_keys: Vec = - additional_derived_keys.iter_mut().map(Into::into).collect(); - Self { - inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS { + inner: CK_SP800_108_KDF_PARAMS { prfType: prf_mechanism.into(), ulNumberOfDataParams: prf_data_params .len() @@ -322,7 +429,7 @@ impl<'a> KbkdfDoublePipelineParams<'a> { .len() .try_into() .expect("number of additional derived keys does not fit in CK_ULONG"), - pAdditionalDerivedKeys: additional_derived_keys.as_ptr() as CK_DERIVED_KEY_PTR, + pAdditionalDerivedKeys: additional_derived_keys.as_mut_ptr() as CK_DERIVED_KEY_PTR, }, _marker: PhantomData, } @@ -345,77 +452,3 @@ impl<'a> KbkdfDoublePipelineParams<'a> { } } } - -impl<'a> From<&PrfDataParam<'a>> for CK_PRF_DATA_PARAM { - fn from(value: &PrfDataParam<'a>) -> Self { - Self { - type_: match value { - PrfDataParam::IterationVariable => CK_SP800_108_ITERATION_VARIABLE, - PrfDataParam::Counter(_) => CK_SP800_108_COUNTER, - PrfDataParam::DkmLength(_) => CK_SP800_108_DKM_LENGTH, - PrfDataParam::ByteArray(_) => CK_SP800_108_BYTE_ARRAY, - }, - pValue: match value { - PrfDataParam::IterationVariable => ptr::null_mut(), - PrfDataParam::Counter(inner) => inner as *const _ as *mut _, - PrfDataParam::DkmLength(inner) => inner as *const _ as *mut _, - PrfDataParam::ByteArray(data) => data.as_ptr() as *mut _, - }, - ulValueLen: match value { - PrfDataParam::IterationVariable => 0, - PrfDataParam::Counter(_) => size_of::() as CK_ULONG, - PrfDataParam::DkmLength(_) => { - size_of::() as CK_ULONG - } - PrfDataParam::ByteArray(data) => data - .len() - .try_into() - .expect("length of data parameter does not fit in CK_ULONG"), - }, - } - } -} - -impl<'a> From<&PrfCounterDataParam<'a>> for CK_PRF_DATA_PARAM { - fn from(value: &PrfCounterDataParam<'a>) -> Self { - Self { - type_: match value { - PrfCounterDataParam::IterationVariable(_) => CK_SP800_108_ITERATION_VARIABLE, - PrfCounterDataParam::DkmLength(_) => CK_SP800_108_DKM_LENGTH, - PrfCounterDataParam::ByteArray(_) => CK_SP800_108_BYTE_ARRAY, - }, - pValue: match value { - PrfCounterDataParam::IterationVariable(inner) => inner as *const _ as *mut _, - PrfCounterDataParam::DkmLength(inner) => inner as *const _ as *mut _, - PrfCounterDataParam::ByteArray(data) => data.as_ptr() as *mut _, - }, - ulValueLen: match value { - PrfCounterDataParam::IterationVariable(_) => { - size_of::() as CK_ULONG - } - PrfCounterDataParam::DkmLength(_) => { - size_of::() as CK_ULONG - } - PrfCounterDataParam::ByteArray(data) => data - .len() - .try_into() - .expect("length of data parameter does not fit in CK_ULONG"), - }, - } - } -} - -impl<'a> From<&mut DerivedKey<'a>> for CK_DERIVED_KEY { - fn from(value: &mut DerivedKey<'a>) -> Self { - let template: Vec = value.template.iter().map(Into::into).collect(); - - Self { - pTemplate: template.as_ptr() as CK_ATTRIBUTE_PTR, - ulAttributeCount: template - .len() - .try_into() - .expect("number of attributes in template does not fit in CK_ULONG"), - phKey: &mut value.object_handle, - } - } -} From 799469a0b3b8073ef5a3de072201a18258132c8a Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Wed, 9 Apr 2025 13:00:38 +0200 Subject: [PATCH 04/22] Qualified all cryptoki_sys imports as a stylistic choice Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 120 +++++++++++++++++--------------- 1 file changed, 62 insertions(+), 58 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index b5b690ed..80508831 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -5,15 +5,6 @@ use core::{convert::TryInto, marker::PhantomData, ptr, slice}; -use cryptoki_sys::{ - CK_ATTRIBUTE_PTR, CK_DERIVED_KEY, CK_DERIVED_KEY_PTR, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE_PTR, - CK_PRF_DATA_PARAM, CK_PRF_DATA_PARAM_PTR, CK_SP800_108_BYTE_ARRAY, CK_SP800_108_COUNTER, - CK_SP800_108_COUNTER_FORMAT, CK_SP800_108_DKM_LENGTH, CK_SP800_108_DKM_LENGTH_FORMAT, - CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS, - CK_SP800_108_FEEDBACK_KDF_PARAMS, CK_SP800_108_ITERATION_VARIABLE, CK_SP800_108_KDF_PARAMS, - CK_ULONG, -}; - use crate::object::Attribute; use super::MechanismType; @@ -33,7 +24,7 @@ pub enum Endianness { #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct KbkdfCounterFormat { - inner: CK_SP800_108_COUNTER_FORMAT, + inner: cryptoki_sys::CK_SP800_108_COUNTER_FORMAT, } impl KbkdfCounterFormat { @@ -46,7 +37,7 @@ impl KbkdfCounterFormat { /// * `width_in_bits` - The number of bits used to represent the counter value. pub fn new(endianness: Endianness, width_in_bits: usize) -> Self { Self { - inner: CK_SP800_108_COUNTER_FORMAT { + inner: cryptoki_sys::CK_SP800_108_COUNTER_FORMAT { bLittleEndian: (endianness == Endianness::Little).into(), ulWidthInBits: width_in_bits .try_into() @@ -73,7 +64,7 @@ pub enum DkmLengthMethod { #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct KbkdfDkmLengthFormat { - inner: CK_SP800_108_DKM_LENGTH_FORMAT, + inner: cryptoki_sys::CK_SP800_108_DKM_LENGTH_FORMAT, } impl KbkdfDkmLengthFormat { @@ -92,10 +83,12 @@ impl KbkdfDkmLengthFormat { width_in_bits: usize, ) -> Self { Self { - inner: CK_SP800_108_DKM_LENGTH_FORMAT { + inner: cryptoki_sys::CK_SP800_108_DKM_LENGTH_FORMAT { dkmLengthMethod: match dkm_length_method { - DkmLengthMethod::SumOfKeys => CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, - DkmLengthMethod::SumOfSegments => CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS, + DkmLengthMethod::SumOfKeys => cryptoki_sys::CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, + DkmLengthMethod::SumOfSegments => { + cryptoki_sys::CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS + } }, bLittleEndian: (endianness == Endianness::Little).into(), ulWidthInBits: width_in_bits.try_into().expect( @@ -125,7 +118,7 @@ pub enum PrfDataParamType<'a> { #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct PrfDataParam<'a> { - inner: CK_PRF_DATA_PARAM, + inner: cryptoki_sys::CK_PRF_DATA_PARAM, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, } @@ -139,23 +132,25 @@ impl<'a> PrfDataParam<'a> { pub fn new(type_: PrfDataParamType<'a>) -> Self { Self { inner: match type_ { - PrfDataParamType::IterationVariable => CK_PRF_DATA_PARAM { - type_: CK_SP800_108_ITERATION_VARIABLE, + PrfDataParamType::IterationVariable => cryptoki_sys::CK_PRF_DATA_PARAM { + type_: cryptoki_sys::CK_SP800_108_ITERATION_VARIABLE, pValue: ptr::null_mut(), ulValueLen: 0, }, - PrfDataParamType::Counter(counter_format) => CK_PRF_DATA_PARAM { - type_: CK_SP800_108_COUNTER, + PrfDataParamType::Counter(counter_format) => cryptoki_sys::CK_PRF_DATA_PARAM { + type_: cryptoki_sys::CK_SP800_108_COUNTER, pValue: &counter_format.inner as *const _ as *mut _, - ulValueLen: size_of::() as CK_ULONG, + ulValueLen: size_of::() + as cryptoki_sys::CK_ULONG, }, - PrfDataParamType::DkmLength(dkm_length_format) => CK_PRF_DATA_PARAM { - type_: CK_SP800_108_DKM_LENGTH, + PrfDataParamType::DkmLength(dkm_length_format) => cryptoki_sys::CK_PRF_DATA_PARAM { + type_: cryptoki_sys::CK_SP800_108_DKM_LENGTH, pValue: &dkm_length_format.inner as *const _ as *mut _, - ulValueLen: size_of::() as CK_ULONG, + ulValueLen: size_of::() + as cryptoki_sys::CK_ULONG, }, - PrfDataParamType::ByteArray(data) => CK_PRF_DATA_PARAM { - type_: CK_SP800_108_BYTE_ARRAY, + PrfDataParamType::ByteArray(data) => cryptoki_sys::CK_PRF_DATA_PARAM { + type_: cryptoki_sys::CK_SP800_108_BYTE_ARRAY, pValue: data.as_ptr() as *mut _, ulValueLen: data .len() @@ -185,7 +180,7 @@ pub enum PrfCounterDataParamType<'a> { #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct PrfCounterDataParam<'a> { - inner: CK_PRF_DATA_PARAM, + inner: cryptoki_sys::CK_PRF_DATA_PARAM, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, } @@ -199,18 +194,24 @@ impl<'a> PrfCounterDataParam<'a> { pub fn new(type_: PrfCounterDataParamType<'a>) -> Self { Self { inner: match type_ { - PrfCounterDataParamType::IterationVariable(counter_format) => CK_PRF_DATA_PARAM { - type_: CK_SP800_108_ITERATION_VARIABLE, - pValue: &counter_format.inner as *const _ as *mut _, - ulValueLen: size_of::() as CK_ULONG, - }, - PrfCounterDataParamType::DkmLength(dkm_length_format) => CK_PRF_DATA_PARAM { - type_: CK_SP800_108_DKM_LENGTH, - pValue: &dkm_length_format.inner as *const _ as *mut _, - ulValueLen: size_of::() as CK_ULONG, - }, - PrfCounterDataParamType::ByteArray(data) => CK_PRF_DATA_PARAM { - type_: CK_SP800_108_BYTE_ARRAY, + PrfCounterDataParamType::IterationVariable(counter_format) => { + cryptoki_sys::CK_PRF_DATA_PARAM { + type_: cryptoki_sys::CK_SP800_108_ITERATION_VARIABLE, + pValue: &counter_format.inner as *const _ as *mut _, + ulValueLen: size_of::() + as cryptoki_sys::CK_ULONG, + } + } + PrfCounterDataParamType::DkmLength(dkm_length_format) => { + cryptoki_sys::CK_PRF_DATA_PARAM { + type_: cryptoki_sys::CK_SP800_108_DKM_LENGTH, + pValue: &dkm_length_format.inner as *const _ as *mut _, + ulValueLen: size_of::() + as cryptoki_sys::CK_ULONG, + } + } + PrfCounterDataParamType::ByteArray(data) => cryptoki_sys::CK_PRF_DATA_PARAM { + type_: cryptoki_sys::CK_SP800_108_BYTE_ARRAY, pValue: data.as_ptr() as *mut _, ulValueLen: data .len() @@ -227,7 +228,7 @@ impl<'a> PrfCounterDataParam<'a> { #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct DerivedKey<'a> { - inner: CK_DERIVED_KEY, + inner: cryptoki_sys::CK_DERIVED_KEY, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, } @@ -242,13 +243,13 @@ impl<'a> DerivedKey<'a> { /// * `handle` - The location into which will be written the handle of the new derived key. pub fn new(template: &'a [Attribute], handle: &'a mut u64) -> Self { Self { - inner: CK_DERIVED_KEY { - pTemplate: template.as_ptr() as CK_ATTRIBUTE_PTR, + inner: cryptoki_sys::CK_DERIVED_KEY { + pTemplate: template.as_ptr() as cryptoki_sys::CK_ATTRIBUTE_PTR, ulAttributeCount: template .len() .try_into() .expect("number of attributes in template does not fit in CK_ULONG"), - phKey: handle as CK_OBJECT_HANDLE_PTR, + phKey: handle as cryptoki_sys::CK_OBJECT_HANDLE_PTR, }, _marker: PhantomData, } @@ -261,7 +262,7 @@ impl<'a> DerivedKey<'a> { #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct KbkdfCounterParams<'a> { - inner: CK_SP800_108_KDF_PARAMS, + inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, } @@ -283,25 +284,26 @@ impl<'a> KbkdfCounterParams<'a> { additional_derived_keys: &'a mut [DerivedKey<'a>], ) -> Self { Self { - inner: CK_SP800_108_KDF_PARAMS { + inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS { prfType: prf_mechanism.into(), ulNumberOfDataParams: prf_data_params .len() .try_into() .expect("number of data parameters does not fit in CK_ULONG"), - pDataParams: prf_data_params.as_ptr() as CK_PRF_DATA_PARAM_PTR, + pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, ulAdditionalDerivedKeys: additional_derived_keys .len() .try_into() .expect("number of additional derived keys does not fit in CK_ULONG"), - pAdditionalDerivedKeys: additional_derived_keys.as_mut_ptr() as CK_DERIVED_KEY_PTR, + pAdditionalDerivedKeys: additional_derived_keys.as_mut_ptr() + as cryptoki_sys::CK_DERIVED_KEY_PTR, }, _marker: PhantomData, } } /// The additional keys derived by the KDF, as per the params - pub fn additional_derived_keys(&self) -> Vec { + pub fn additional_derived_keys(&self) -> Vec { let derived_keys = unsafe { slice::from_raw_parts( self.inner.pAdditionalDerivedKeys, @@ -324,7 +326,7 @@ impl<'a> KbkdfCounterParams<'a> { #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct KbkdfFeedbackParams<'a> { - inner: CK_SP800_108_FEEDBACK_KDF_PARAMS, + inner: cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, } @@ -349,13 +351,13 @@ impl<'a> KbkdfFeedbackParams<'a> { additional_derived_keys: &'a mut [DerivedKey<'a>], ) -> Self { Self { - inner: CK_SP800_108_FEEDBACK_KDF_PARAMS { + inner: cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS { prfType: prf_mechanism.into(), ulNumberOfDataParams: prf_data_params .len() .try_into() .expect("number of data parameters does not fit in CK_ULONG"), - pDataParams: prf_data_params.as_ptr() as CK_PRF_DATA_PARAM_PTR, + pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, ulIVLen: iv.map_or(0, |iv| { iv.len() .try_into() @@ -366,14 +368,15 @@ impl<'a> KbkdfFeedbackParams<'a> { .len() .try_into() .expect("number of additional derived keys does not fit in CK_ULONG"), - pAdditionalDerivedKeys: additional_derived_keys.as_mut_ptr() as CK_DERIVED_KEY_PTR, + pAdditionalDerivedKeys: additional_derived_keys.as_mut_ptr() + as cryptoki_sys::CK_DERIVED_KEY_PTR, }, _marker: PhantomData, } } /// The additional keys derived by the KDF, as per the params - pub fn additional_derived_keys(&self) -> Vec { + pub fn additional_derived_keys(&self) -> Vec { let derived_keys = unsafe { slice::from_raw_parts( self.inner.pAdditionalDerivedKeys, @@ -396,7 +399,7 @@ impl<'a> KbkdfFeedbackParams<'a> { #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct KbkdfDoublePipelineParams<'a> { - inner: CK_SP800_108_KDF_PARAMS, + inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, } @@ -418,25 +421,26 @@ impl<'a> KbkdfDoublePipelineParams<'a> { additional_derived_keys: &'a mut [DerivedKey<'a>], ) -> Self { Self { - inner: CK_SP800_108_KDF_PARAMS { + inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS { prfType: prf_mechanism.into(), ulNumberOfDataParams: prf_data_params .len() .try_into() .expect("number of data parameters does not fit in CK_ULONG"), - pDataParams: prf_data_params.as_ptr() as CK_PRF_DATA_PARAM_PTR, + pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, ulAdditionalDerivedKeys: additional_derived_keys .len() .try_into() .expect("number of additional derived keys does not fit in CK_ULONG"), - pAdditionalDerivedKeys: additional_derived_keys.as_mut_ptr() as CK_DERIVED_KEY_PTR, + pAdditionalDerivedKeys: additional_derived_keys.as_mut_ptr() + as cryptoki_sys::CK_DERIVED_KEY_PTR, }, _marker: PhantomData, } } /// The additional keys derived by the KDF, as per the params - pub fn additional_derived_keys(&self) -> Vec { + pub fn additional_derived_keys(&self) -> Vec { let derived_keys = unsafe { slice::from_raw_parts( self.inner.pAdditionalDerivedKeys, From 5f7a92263c49a3b7e86010202f82c4930f94e410 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Wed, 9 Apr 2025 13:18:48 +0200 Subject: [PATCH 05/22] Simplified CounterFormat and DkmLengthFormat wrapper structs Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 56 ++++++++++++++------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index 80508831..dbcd31cd 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -23,9 +23,7 @@ pub enum Endianness { /// This structure wraps a `CK_SP800_108_COUNTER_FORMAT` structure. #[derive(Debug, Clone, Copy)] #[repr(transparent)] -pub struct KbkdfCounterFormat { - inner: cryptoki_sys::CK_SP800_108_COUNTER_FORMAT, -} +pub struct KbkdfCounterFormat(cryptoki_sys::CK_SP800_108_COUNTER_FORMAT); impl KbkdfCounterFormat { /// Construct encoding format for KDF's internal counter variable. @@ -36,14 +34,12 @@ impl KbkdfCounterFormat { /// /// * `width_in_bits` - The number of bits used to represent the counter value. pub fn new(endianness: Endianness, width_in_bits: usize) -> Self { - Self { - inner: cryptoki_sys::CK_SP800_108_COUNTER_FORMAT { - bLittleEndian: (endianness == Endianness::Little).into(), - ulWidthInBits: width_in_bits + Self(cryptoki_sys::CK_SP800_108_COUNTER_FORMAT { + bLittleEndian: (endianness == Endianness::Little).into(), + ulWidthInBits: width_in_bits .try_into() .expect("bit width of KBKDF internal counter does not fit in CK_ULONG"), - }, - } + }) } } @@ -63,9 +59,7 @@ pub enum DkmLengthMethod { /// This structure wraps a `CK_SP800_108_DKM_LENGTH_FORMAT` structure. #[derive(Debug, Clone, Copy)] #[repr(transparent)] -pub struct KbkdfDkmLengthFormat { - inner: cryptoki_sys::CK_SP800_108_DKM_LENGTH_FORMAT, -} +pub struct KbkdfDkmLengthFormat(cryptoki_sys::CK_SP800_108_DKM_LENGTH_FORMAT); impl KbkdfDkmLengthFormat { /// Construct encoding format for length value of DKM (derived key material) from KDF. @@ -78,24 +72,22 @@ impl KbkdfDkmLengthFormat { /// /// * `width_in_bits` - The number of bits used to represent the DKM length value. pub fn new( - dkm_length_method: DkmLengthMethod, - endianness: Endianness, - width_in_bits: usize, + dkm_length_method: DkmLengthMethod, + endianness: Endianness, + width_in_bits: usize, ) -> Self { - Self { - inner: cryptoki_sys::CK_SP800_108_DKM_LENGTH_FORMAT { - dkmLengthMethod: match dkm_length_method { - DkmLengthMethod::SumOfKeys => cryptoki_sys::CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, - DkmLengthMethod::SumOfSegments => { - cryptoki_sys::CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS - } - }, - bLittleEndian: (endianness == Endianness::Little).into(), - ulWidthInBits: width_in_bits.try_into().expect( - "bit width of KBKDF derived key material length value does not fit in CK_ULONG", - ), + Self(cryptoki_sys::CK_SP800_108_DKM_LENGTH_FORMAT { + dkmLengthMethod: match dkm_length_method { + DkmLengthMethod::SumOfKeys => cryptoki_sys::CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, + DkmLengthMethod::SumOfSegments => { + cryptoki_sys::CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS + } }, - } + bLittleEndian: (endianness == Endianness::Little).into(), + ulWidthInBits: width_in_bits.try_into().expect( + "bit width of KBKDF derived key material length value does not fit in CK_ULONG", + ), + }) } } @@ -139,13 +131,13 @@ impl<'a> PrfDataParam<'a> { }, PrfDataParamType::Counter(counter_format) => cryptoki_sys::CK_PRF_DATA_PARAM { type_: cryptoki_sys::CK_SP800_108_COUNTER, - pValue: &counter_format.inner as *const _ as *mut _, + pValue: counter_format as *const _ as *mut _, ulValueLen: size_of::() as cryptoki_sys::CK_ULONG, }, PrfDataParamType::DkmLength(dkm_length_format) => cryptoki_sys::CK_PRF_DATA_PARAM { type_: cryptoki_sys::CK_SP800_108_DKM_LENGTH, - pValue: &dkm_length_format.inner as *const _ as *mut _, + pValue: dkm_length_format as *const _ as *mut _, ulValueLen: size_of::() as cryptoki_sys::CK_ULONG, }, @@ -197,7 +189,7 @@ impl<'a> PrfCounterDataParam<'a> { PrfCounterDataParamType::IterationVariable(counter_format) => { cryptoki_sys::CK_PRF_DATA_PARAM { type_: cryptoki_sys::CK_SP800_108_ITERATION_VARIABLE, - pValue: &counter_format.inner as *const _ as *mut _, + pValue: counter_format as *const _ as *mut _, ulValueLen: size_of::() as cryptoki_sys::CK_ULONG, } @@ -205,7 +197,7 @@ impl<'a> PrfCounterDataParam<'a> { PrfCounterDataParamType::DkmLength(dkm_length_format) => { cryptoki_sys::CK_PRF_DATA_PARAM { type_: cryptoki_sys::CK_SP800_108_DKM_LENGTH, - pValue: &dkm_length_format.inner as *const _ as *mut _, + pValue: dkm_length_format as *const _ as *mut _, ulValueLen: size_of::() as cryptoki_sys::CK_ULONG, } From 8258b7bcb4ccf315e388a783837147cb8162e038 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Wed, 9 Apr 2025 14:40:13 +0200 Subject: [PATCH 06/22] Added support for not providing additional keys to derive Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 146 +++++++++++++++++++------------- cryptoki/src/mechanism/mod.rs | 15 ++-- 2 files changed, 93 insertions(+), 68 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index dbcd31cd..8bc6d241 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -5,7 +5,7 @@ use core::{convert::TryInto, marker::PhantomData, ptr, slice}; -use crate::object::Attribute; +use crate::object::{Attribute, ObjectHandle}; use super::MechanismType; @@ -273,7 +273,7 @@ impl<'a> KbkdfCounterParams<'a> { pub fn new( prf_mechanism: MechanismType, prf_data_params: &'a [PrfCounterDataParam<'a>], - additional_derived_keys: &'a mut [DerivedKey<'a>], + additional_derived_keys: Option<&'a mut [DerivedKey<'a>]>, ) -> Self { Self { inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS { @@ -283,31 +283,41 @@ impl<'a> KbkdfCounterParams<'a> { .try_into() .expect("number of data parameters does not fit in CK_ULONG"), pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, - ulAdditionalDerivedKeys: additional_derived_keys - .len() - .try_into() - .expect("number of additional derived keys does not fit in CK_ULONG"), - pAdditionalDerivedKeys: additional_derived_keys.as_mut_ptr() - as cryptoki_sys::CK_DERIVED_KEY_PTR, + ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| { + keys.len() + .try_into() + .expect("number of additional derived keys does not fit in CK_ULONG") + }), + pAdditionalDerivedKeys: additional_derived_keys.map_or(ptr::null_mut(), |keys| { + keys.as_mut_ptr() as cryptoki_sys::CK_DERIVED_KEY_PTR + }), }, _marker: PhantomData, } } /// The additional keys derived by the KDF, as per the params - pub fn additional_derived_keys(&self) -> Vec { - let derived_keys = unsafe { - slice::from_raw_parts( - self.inner.pAdditionalDerivedKeys, - self.inner.ulAdditionalDerivedKeys as _, - ) - }; + pub(crate) fn additional_derived_keys(&self) -> Option> { + if self.inner.ulAdditionalDerivedKeys == 0 { + None + } else { + // SAFETY: if the number of derived keys > 0, then at least one was explicitly provided during construction + let derived_keys = unsafe { + slice::from_raw_parts( + self.inner.pAdditionalDerivedKeys, + self.inner.ulAdditionalDerivedKeys as _, + ) + }; - unsafe { - derived_keys - .iter() - .map(|derived_key| *derived_key.phKey) - .collect() + Some( + derived_keys + .iter() + .map(|derived_key| { + // SAFETY: a value is always provided during construction + ObjectHandle::new(unsafe { *derived_key.phKey }) + }) + .collect(), + ) } } } @@ -340,7 +350,7 @@ impl<'a> KbkdfFeedbackParams<'a> { prf_mechanism: MechanismType, prf_data_params: &'a [PrfDataParam<'a>], iv: Option<&'a [u8]>, - additional_derived_keys: &'a mut [DerivedKey<'a>], + additional_derived_keys: Option<&'a mut [DerivedKey<'a>]>, ) -> Self { Self { inner: cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS { @@ -356,31 +366,41 @@ impl<'a> KbkdfFeedbackParams<'a> { .expect("IV length does not fit in CK_ULONG") }), pIV: iv.map_or(ptr::null_mut(), |iv| iv.as_ptr() as *mut _), - ulAdditionalDerivedKeys: additional_derived_keys - .len() - .try_into() - .expect("number of additional derived keys does not fit in CK_ULONG"), - pAdditionalDerivedKeys: additional_derived_keys.as_mut_ptr() - as cryptoki_sys::CK_DERIVED_KEY_PTR, + ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| { + keys.len() + .try_into() + .expect("number of additional derived keys does not fit in CK_ULONG") + }), + pAdditionalDerivedKeys: additional_derived_keys.map_or(ptr::null_mut(), |keys| { + keys.as_mut_ptr() as cryptoki_sys::CK_DERIVED_KEY_PTR + }), }, _marker: PhantomData, } } /// The additional keys derived by the KDF, as per the params - pub fn additional_derived_keys(&self) -> Vec { - let derived_keys = unsafe { - slice::from_raw_parts( - self.inner.pAdditionalDerivedKeys, - self.inner.ulAdditionalDerivedKeys as _, - ) - }; + pub(crate) fn additional_derived_keys(&self) -> Option> { + if self.inner.ulAdditionalDerivedKeys == 0 { + None + } else { + // SAFETY: if the number of derived keys > 0, then at least one was explicitly provided during construction + let derived_keys = unsafe { + slice::from_raw_parts( + self.inner.pAdditionalDerivedKeys, + self.inner.ulAdditionalDerivedKeys as _, + ) + }; - unsafe { - derived_keys - .iter() - .map(|derived_key| *derived_key.phKey) - .collect() + Some( + derived_keys + .iter() + .map(|derived_key| { + // SAFETY: a value is always provided during construction + ObjectHandle::new(unsafe { *derived_key.phKey }) + }) + .collect(), + ) } } } @@ -410,7 +430,7 @@ impl<'a> KbkdfDoublePipelineParams<'a> { pub fn new( prf_mechanism: MechanismType, prf_data_params: &'a [PrfDataParam<'a>], - additional_derived_keys: &'a mut [DerivedKey<'a>], + additional_derived_keys: Option<&'a mut [DerivedKey<'a>]>, ) -> Self { Self { inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS { @@ -420,31 +440,41 @@ impl<'a> KbkdfDoublePipelineParams<'a> { .try_into() .expect("number of data parameters does not fit in CK_ULONG"), pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, - ulAdditionalDerivedKeys: additional_derived_keys - .len() - .try_into() - .expect("number of additional derived keys does not fit in CK_ULONG"), - pAdditionalDerivedKeys: additional_derived_keys.as_mut_ptr() - as cryptoki_sys::CK_DERIVED_KEY_PTR, + ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| { + keys.len() + .try_into() + .expect("number of additional derived keys does not fit in CK_ULONG") + }), + pAdditionalDerivedKeys: additional_derived_keys.map_or(ptr::null_mut(), |keys| { + keys.as_mut_ptr() as cryptoki_sys::CK_DERIVED_KEY_PTR + }), }, _marker: PhantomData, } } /// The additional keys derived by the KDF, as per the params - pub fn additional_derived_keys(&self) -> Vec { - let derived_keys = unsafe { - slice::from_raw_parts( - self.inner.pAdditionalDerivedKeys, - self.inner.ulAdditionalDerivedKeys as _, - ) - }; + pub(crate) fn additional_derived_keys(&self) -> Option> { + if self.inner.ulAdditionalDerivedKeys == 0 { + None + } else { + // SAFETY: if the number of derived keys > 0, then at least one was explicitly provided during construction + let derived_keys = unsafe { + slice::from_raw_parts( + self.inner.pAdditionalDerivedKeys, + self.inner.ulAdditionalDerivedKeys as _, + ) + }; - unsafe { - derived_keys - .iter() - .map(|derived_key| *derived_key.phKey) - .collect() + Some( + derived_keys + .iter() + .map(|derived_key| { + // SAFETY: a value is always provided during construction + ObjectHandle::new(unsafe { *derived_key.phKey }) + }) + .collect(), + ) } } } diff --git a/cryptoki/src/mechanism/mod.rs b/cryptoki/src/mechanism/mod.rs index 87da54fc..31344545 100644 --- a/cryptoki/src/mechanism/mod.rs +++ b/cryptoki/src/mechanism/mod.rs @@ -1293,16 +1293,11 @@ pub trait HasAdditionalDerivedKeys { impl HasAdditionalDerivedKeys for &Mechanism<'_> { fn additional_derived_keys(&self) -> Vec { - let additional_derived_keys = match self { - Mechanism::KbkdfCounter(params) => params.additional_derived_keys(), - Mechanism::KbkdfFeedback(params) => params.additional_derived_keys(), - Mechanism::KbkdfDoublePipeline(params) => params.additional_derived_keys(), + match self { + Mechanism::KbkdfCounter(params) => params.additional_derived_keys().unwrap_or_default(), + Mechanism::KbkdfFeedback(params) => params.additional_derived_keys().unwrap_or_default(), + Mechanism::KbkdfDoublePipeline(params) => params.additional_derived_keys().unwrap_or_default(), _ => unimplemented!("The given mechanism doesn't define additional keys to derive"), // TODO: this or return an option? - }; - - additional_derived_keys - .into_iter() - .map(ObjectHandle::new) - .collect() + } } } From d2b09c4c4730a9c8c0f67cc1e62f544d5ac8607d Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Thu, 10 Apr 2025 19:08:40 +0200 Subject: [PATCH 07/22] Fixed issue where underlying derived key structs were being formed incorrectly Because I was forgetting that the slice of Attributes within had to be converted to a slice of CK_ATTRIBUTEs! This need to convert internally (otherwise exposing end users to the internal CK_ATTRIBUTE type) meant that we needed to store this converted slice within each DerivedKey, so that the memory stayed valid. This meant playing around with a few changes to the standard "PKCS#11 struct wrapped in a Rust struct marked `transparent`" pattern that had been used for params Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 320 ++++++++++++++++++-------------- cryptoki/src/mechanism/mod.rs | 6 +- 2 files changed, 182 insertions(+), 144 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index 8bc6d241..e11f823b 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -3,7 +3,7 @@ //! Mechanisms of NIST key-based key derive functions (SP 800-108, informally KBKDF) //! See: -use core::{convert::TryInto, marker::PhantomData, ptr, slice}; +use core::{convert::TryInto, marker::PhantomData, pin::Pin, ptr}; use crate::object::{Attribute, ObjectHandle}; @@ -216,34 +216,27 @@ impl<'a> PrfCounterDataParam<'a> { } } -/// Parameters for additional key to be derived from base key. -#[derive(Debug, Clone, Copy)] -#[repr(transparent)] -pub struct DerivedKey<'a> { - inner: cryptoki_sys::CK_DERIVED_KEY, - /// Marker type to ensure we don't outlive the data - _marker: PhantomData<&'a [u8]>, +/// Container for information on an additional key to be derived. +#[derive(Debug)] +pub struct DerivedKey { + template: Pin>, + handle: cryptoki_sys::CK_OBJECT_HANDLE, } -impl<'a> DerivedKey<'a> { +impl DerivedKey { /// Construct template for additional key to be derived by KDF. /// /// # Arguments /// /// * `template` - The template for the key to be derived. - /// - /// * `handle` - The location into which will be written the handle of the new derived key. - pub fn new(template: &'a [Attribute], handle: &'a mut u64) -> Self { + pub fn new(template: &[Attribute]) -> Self { + let template: Box<[cryptoki_sys::CK_ATTRIBUTE]> = + template.iter().map(|attr| attr.into()).collect(); + let template = Pin::new(template); + Self { - inner: cryptoki_sys::CK_DERIVED_KEY { - pTemplate: template.as_ptr() as cryptoki_sys::CK_ATTRIBUTE_PTR, - ulAttributeCount: template - .len() - .try_into() - .expect("number of attributes in template does not fit in CK_ULONG"), - phKey: handle as cryptoki_sys::CK_OBJECT_HANDLE_PTR, - }, - _marker: PhantomData, + template, + handle: 0, } } } @@ -251,9 +244,11 @@ impl<'a> DerivedKey<'a> { /// NIST SP 800-108 (aka KBKDF) counter-mode parameters. /// /// This structure wraps a `CK_SP800_108_KDF_PARAMS` structure. -#[derive(Debug, Clone, Copy)] -#[repr(transparent)] +#[derive(Debug)] pub struct KbkdfCounterParams<'a> { + /// Holds own data so that we have a contiguous memory region to give to backend + additional_derived_keys: Option>>, + inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, @@ -273,61 +268,76 @@ impl<'a> KbkdfCounterParams<'a> { pub fn new( prf_mechanism: MechanismType, prf_data_params: &'a [PrfCounterDataParam<'a>], - additional_derived_keys: Option<&'a mut [DerivedKey<'a>]>, + additional_derived_keys: Option<&'a mut [DerivedKey]>, ) -> Self { - Self { - inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS { - prfType: prf_mechanism.into(), - ulNumberOfDataParams: prf_data_params - .len() + let additional_derived_keys: Option> = + additional_derived_keys.map(|keys| { + keys.iter_mut() + .map(|key| cryptoki_sys::CK_DERIVED_KEY { + pTemplate: key.template.as_ptr() as cryptoki_sys::CK_ATTRIBUTE_PTR, + ulAttributeCount: key + .template + .len() + .try_into() + .expect("number of attributes in template does not fit in CK_ULONG"), + phKey: &mut key.handle as cryptoki_sys::CK_OBJECT_HANDLE_PTR, + }) + .collect() + }); + let mut additional_derived_keys = additional_derived_keys.map(|keys| Pin::new(keys)); + + let inner = cryptoki_sys::CK_SP800_108_KDF_PARAMS { + prfType: prf_mechanism.into(), + ulNumberOfDataParams: prf_data_params + .len() + .try_into() + .expect("number of data parameters does not fit in CK_ULONG"), + pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, + ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| { + keys.len() .try_into() - .expect("number of data parameters does not fit in CK_ULONG"), - pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, - ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| { - keys.len() - .try_into() - .expect("number of additional derived keys does not fit in CK_ULONG") - }), - pAdditionalDerivedKeys: additional_derived_keys.map_or(ptr::null_mut(), |keys| { + .expect("number of additional derived keys does not fit in CK_ULONG") + }), + pAdditionalDerivedKeys: additional_derived_keys + .as_mut() + .map_or(ptr::null_mut(), |keys| { keys.as_mut_ptr() as cryptoki_sys::CK_DERIVED_KEY_PTR }), - }, + }; + + Self { + additional_derived_keys, + + inner, _marker: PhantomData, } } + pub(crate) fn inner(&self) -> &cryptoki_sys::CK_SP800_108_KDF_PARAMS { + &self.inner + } + /// The additional keys derived by the KDF, as per the params pub(crate) fn additional_derived_keys(&self) -> Option> { - if self.inner.ulAdditionalDerivedKeys == 0 { - None - } else { - // SAFETY: if the number of derived keys > 0, then at least one was explicitly provided during construction - let derived_keys = unsafe { - slice::from_raw_parts( - self.inner.pAdditionalDerivedKeys, - self.inner.ulAdditionalDerivedKeys as _, - ) - }; - - Some( - derived_keys - .iter() - .map(|derived_key| { - // SAFETY: a value is always provided during construction - ObjectHandle::new(unsafe { *derived_key.phKey }) - }) - .collect(), - ) - } + self.additional_derived_keys.as_ref().map(|keys| { + keys.iter() + .map(|key| { + // SAFETY: a value is always provided during construction + ObjectHandle::new(unsafe { *key.phKey }) + }) + .collect() + }) } } /// NIST SP 800-108 (aka KBKDF) feedback-mode parameters. /// /// This structure wraps a `CK_SP800_108_FEEDBACK_KDF_PARAMS` structure. -#[derive(Debug, Clone, Copy)] -#[repr(transparent)] +#[derive(Debug)] pub struct KbkdfFeedbackParams<'a> { + /// Holds own data so that we have a contiguous memory region to give to backend + additional_derived_keys: Option>>, + inner: cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, @@ -350,67 +360,82 @@ impl<'a> KbkdfFeedbackParams<'a> { prf_mechanism: MechanismType, prf_data_params: &'a [PrfDataParam<'a>], iv: Option<&'a [u8]>, - additional_derived_keys: Option<&'a mut [DerivedKey<'a>]>, + additional_derived_keys: Option<&'a mut [DerivedKey]>, ) -> Self { - Self { - inner: cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS { - prfType: prf_mechanism.into(), - ulNumberOfDataParams: prf_data_params - .len() + let additional_derived_keys: Option> = + additional_derived_keys.map(|keys| { + keys.iter_mut() + .map(|key| cryptoki_sys::CK_DERIVED_KEY { + pTemplate: key.template.as_ptr() as cryptoki_sys::CK_ATTRIBUTE_PTR, + ulAttributeCount: key + .template + .len() + .try_into() + .expect("number of attributes in template does not fit in CK_ULONG"), + phKey: &mut key.handle as cryptoki_sys::CK_OBJECT_HANDLE_PTR, + }) + .collect() + }); + let mut additional_derived_keys = additional_derived_keys.map(|keys| Pin::new(keys)); + + let inner = cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS { + prfType: prf_mechanism.into(), + ulNumberOfDataParams: prf_data_params + .len() + .try_into() + .expect("number of data parameters does not fit in CK_ULONG"), + pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, + ulIVLen: iv.map_or(0, |iv| { + iv.len() .try_into() - .expect("number of data parameters does not fit in CK_ULONG"), - pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, - ulIVLen: iv.map_or(0, |iv| { - iv.len() - .try_into() - .expect("IV length does not fit in CK_ULONG") - }), - pIV: iv.map_or(ptr::null_mut(), |iv| iv.as_ptr() as *mut _), - ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| { - keys.len() - .try_into() - .expect("number of additional derived keys does not fit in CK_ULONG") - }), - pAdditionalDerivedKeys: additional_derived_keys.map_or(ptr::null_mut(), |keys| { + .expect("IV length does not fit in CK_ULONG") + }), + pIV: iv.map_or(ptr::null_mut(), |iv| iv.as_ptr() as *mut _), + ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| { + keys.len() + .try_into() + .expect("number of additional derived keys does not fit in CK_ULONG") + }), + pAdditionalDerivedKeys: additional_derived_keys + .as_mut() + .map_or(ptr::null_mut(), |keys| { keys.as_mut_ptr() as cryptoki_sys::CK_DERIVED_KEY_PTR }), - }, + }; + + Self { + additional_derived_keys, + + inner, _marker: PhantomData, } } + pub(crate) fn inner(&self) -> &cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS { + &self.inner + } + /// The additional keys derived by the KDF, as per the params pub(crate) fn additional_derived_keys(&self) -> Option> { - if self.inner.ulAdditionalDerivedKeys == 0 { - None - } else { - // SAFETY: if the number of derived keys > 0, then at least one was explicitly provided during construction - let derived_keys = unsafe { - slice::from_raw_parts( - self.inner.pAdditionalDerivedKeys, - self.inner.ulAdditionalDerivedKeys as _, - ) - }; - - Some( - derived_keys - .iter() - .map(|derived_key| { - // SAFETY: a value is always provided during construction - ObjectHandle::new(unsafe { *derived_key.phKey }) - }) - .collect(), - ) - } + self.additional_derived_keys.as_ref().map(|keys| { + keys.iter() + .map(|key| { + // SAFETY: a value is always provided during construction + ObjectHandle::new(unsafe { *key.phKey }) + }) + .collect() + }) } } /// NIST SP 800-108 (aka KBKDF) double pipeline-mode parameters. /// /// This structure wraps a `CK_SP800_108_KDF_PARAMS` structure. -#[derive(Debug, Clone, Copy)] -#[repr(transparent)] +#[derive(Debug)] pub struct KbkdfDoublePipelineParams<'a> { + /// Holds own data so that we have a contiguous memory region to give to backend + additional_derived_keys: Option>>, + inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, @@ -430,51 +455,64 @@ impl<'a> KbkdfDoublePipelineParams<'a> { pub fn new( prf_mechanism: MechanismType, prf_data_params: &'a [PrfDataParam<'a>], - additional_derived_keys: Option<&'a mut [DerivedKey<'a>]>, + additional_derived_keys: Option<&'a mut [DerivedKey]>, ) -> Self { - Self { - inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS { - prfType: prf_mechanism.into(), - ulNumberOfDataParams: prf_data_params - .len() + let additional_derived_keys: Option> = + additional_derived_keys.map(|keys| { + keys.iter_mut() + .map(|key| cryptoki_sys::CK_DERIVED_KEY { + pTemplate: key.template.as_ptr() as cryptoki_sys::CK_ATTRIBUTE_PTR, + ulAttributeCount: key + .template + .len() + .try_into() + .expect("number of attributes in template does not fit in CK_ULONG"), + phKey: &mut key.handle as cryptoki_sys::CK_OBJECT_HANDLE_PTR, + }) + .collect() + }); + let mut additional_derived_keys = additional_derived_keys.map(|keys| Pin::new(keys)); + + let inner = cryptoki_sys::CK_SP800_108_KDF_PARAMS { + prfType: prf_mechanism.into(), + ulNumberOfDataParams: prf_data_params + .len() + .try_into() + .expect("number of data parameters does not fit in CK_ULONG"), + pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, + ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| { + keys.len() .try_into() - .expect("number of data parameters does not fit in CK_ULONG"), - pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, - ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| { - keys.len() - .try_into() - .expect("number of additional derived keys does not fit in CK_ULONG") - }), - pAdditionalDerivedKeys: additional_derived_keys.map_or(ptr::null_mut(), |keys| { + .expect("number of additional derived keys does not fit in CK_ULONG") + }), + pAdditionalDerivedKeys: additional_derived_keys + .as_mut() + .map_or(ptr::null_mut(), |keys| { keys.as_mut_ptr() as cryptoki_sys::CK_DERIVED_KEY_PTR }), - }, + }; + + Self { + additional_derived_keys, + + inner, _marker: PhantomData, } } + pub(crate) fn inner(&self) -> &cryptoki_sys::CK_SP800_108_KDF_PARAMS { + &self.inner + } + /// The additional keys derived by the KDF, as per the params pub(crate) fn additional_derived_keys(&self) -> Option> { - if self.inner.ulAdditionalDerivedKeys == 0 { - None - } else { - // SAFETY: if the number of derived keys > 0, then at least one was explicitly provided during construction - let derived_keys = unsafe { - slice::from_raw_parts( - self.inner.pAdditionalDerivedKeys, - self.inner.ulAdditionalDerivedKeys as _, - ) - }; - - Some( - derived_keys - .iter() - .map(|derived_key| { - // SAFETY: a value is always provided during construction - ObjectHandle::new(unsafe { *derived_key.phKey }) - }) - .collect(), - ) - } + self.additional_derived_keys.as_ref().map(|keys| { + keys.iter() + .map(|key| { + // SAFETY: a value is always provided during construction + ObjectHandle::new(unsafe { *key.phKey }) + }) + .collect() + }) } } diff --git a/cryptoki/src/mechanism/mod.rs b/cryptoki/src/mechanism/mod.rs index 31344545..0bbcb4e5 100644 --- a/cryptoki/src/mechanism/mod.rs +++ b/cryptoki/src/mechanism/mod.rs @@ -1190,9 +1190,9 @@ impl From<&Mechanism<'_>> for CK_MECHANISM { Mechanism::HkdfDerive(params) | Mechanism::HkdfData(params) => { make_mechanism(mechanism, params) } - Mechanism::KbkdfCounter(params) => make_mechanism(mechanism, params), - Mechanism::KbkdfFeedback(params) => make_mechanism(mechanism, params), - Mechanism::KbkdfDoublePipeline(params) => make_mechanism(mechanism, params), + Mechanism::KbkdfCounter(params) => make_mechanism(mechanism, params.inner()), + Mechanism::KbkdfFeedback(params) => make_mechanism(mechanism, params.inner()), + Mechanism::KbkdfDoublePipeline(params) => make_mechanism(mechanism, params.inner()), // Mechanisms without parameters Mechanism::AesKeyGen | Mechanism::AesEcb From 3cb3c347eb8fd7534cd7e82766d080c67f559847 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Fri, 11 Apr 2025 10:58:01 +0200 Subject: [PATCH 08/22] Cleaned up code with implementation of From for DerivedKey Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 77 ++++++++++++++------------------- 1 file changed, 33 insertions(+), 44 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index e11f823b..40f75b15 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -230,8 +230,7 @@ impl DerivedKey { /// /// * `template` - The template for the key to be derived. pub fn new(template: &[Attribute]) -> Self { - let template: Box<[cryptoki_sys::CK_ATTRIBUTE]> = - template.iter().map(|attr| attr.into()).collect(); + let template: Box<[cryptoki_sys::CK_ATTRIBUTE]> = template.iter().map(Into::into).collect(); let template = Pin::new(template); Self { @@ -241,6 +240,20 @@ impl DerivedKey { } } +impl From<&mut DerivedKey> for cryptoki_sys::CK_DERIVED_KEY { + fn from(value: &mut DerivedKey) -> Self { + cryptoki_sys::CK_DERIVED_KEY { + pTemplate: value.template.as_ptr() as cryptoki_sys::CK_ATTRIBUTE_PTR, + ulAttributeCount: value + .template + .len() + .try_into() + .expect("number of attributes in template does not fit in CK_ULONG"), + phKey: &mut value.handle as cryptoki_sys::CK_OBJECT_HANDLE_PTR, + } + } +} + /// NIST SP 800-108 (aka KBKDF) counter-mode parameters. /// /// This structure wraps a `CK_SP800_108_KDF_PARAMS` structure. @@ -270,21 +283,13 @@ impl<'a> KbkdfCounterParams<'a> { prf_data_params: &'a [PrfCounterDataParam<'a>], additional_derived_keys: Option<&'a mut [DerivedKey]>, ) -> Self { - let additional_derived_keys: Option> = - additional_derived_keys.map(|keys| { + let mut additional_derived_keys = additional_derived_keys + .map(|keys| { keys.iter_mut() - .map(|key| cryptoki_sys::CK_DERIVED_KEY { - pTemplate: key.template.as_ptr() as cryptoki_sys::CK_ATTRIBUTE_PTR, - ulAttributeCount: key - .template - .len() - .try_into() - .expect("number of attributes in template does not fit in CK_ULONG"), - phKey: &mut key.handle as cryptoki_sys::CK_OBJECT_HANDLE_PTR, - }) - .collect() - }); - let mut additional_derived_keys = additional_derived_keys.map(|keys| Pin::new(keys)); + .map(Into::into) + .collect::>() + }) + .map(Pin::new); let inner = cryptoki_sys::CK_SP800_108_KDF_PARAMS { prfType: prf_mechanism.into(), @@ -362,21 +367,13 @@ impl<'a> KbkdfFeedbackParams<'a> { iv: Option<&'a [u8]>, additional_derived_keys: Option<&'a mut [DerivedKey]>, ) -> Self { - let additional_derived_keys: Option> = - additional_derived_keys.map(|keys| { + let mut additional_derived_keys = additional_derived_keys + .map(|keys| { keys.iter_mut() - .map(|key| cryptoki_sys::CK_DERIVED_KEY { - pTemplate: key.template.as_ptr() as cryptoki_sys::CK_ATTRIBUTE_PTR, - ulAttributeCount: key - .template - .len() - .try_into() - .expect("number of attributes in template does not fit in CK_ULONG"), - phKey: &mut key.handle as cryptoki_sys::CK_OBJECT_HANDLE_PTR, - }) - .collect() - }); - let mut additional_derived_keys = additional_derived_keys.map(|keys| Pin::new(keys)); + .map(Into::into) + .collect::>() + }) + .map(Pin::new); let inner = cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS { prfType: prf_mechanism.into(), @@ -457,21 +454,13 @@ impl<'a> KbkdfDoublePipelineParams<'a> { prf_data_params: &'a [PrfDataParam<'a>], additional_derived_keys: Option<&'a mut [DerivedKey]>, ) -> Self { - let additional_derived_keys: Option> = - additional_derived_keys.map(|keys| { + let mut additional_derived_keys = additional_derived_keys + .map(|keys| { keys.iter_mut() - .map(|key| cryptoki_sys::CK_DERIVED_KEY { - pTemplate: key.template.as_ptr() as cryptoki_sys::CK_ATTRIBUTE_PTR, - ulAttributeCount: key - .template - .len() - .try_into() - .expect("number of attributes in template does not fit in CK_ULONG"), - phKey: &mut key.handle as cryptoki_sys::CK_OBJECT_HANDLE_PTR, - }) - .collect() - }); - let mut additional_derived_keys = additional_derived_keys.map(|keys| Pin::new(keys)); + .map(Into::into) + .collect::>() + }) + .map(Pin::new); let inner = cryptoki_sys::CK_SP800_108_KDF_PARAMS { prfType: prf_mechanism.into(), From 8ac48ed215e1ce056ae34321fcb0d84bcf677966 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:54:58 +0200 Subject: [PATCH 09/22] Removed additional types to match the PKCS#11 spec 1-to-1 Gave up some type safety on which types of PRF data parameters are allowed for which KDF modes, in exchange for being a 1-to-1 binding with the PKCS#11 spec. Depending on the wants of the project, this can be reversed. Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 160 +++----------------------------- cryptoki/src/mechanism/mod.rs | 9 +- 2 files changed, 18 insertions(+), 151 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index 40f75b15..f7a3bc18 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -95,7 +95,7 @@ impl KbkdfDkmLengthFormat { #[derive(Debug, Clone, Copy)] pub enum PrfDataParamType<'a> { /// Identifies location of predefined iteration variable in constructed PRF input data. - IterationVariable, + IterationVariable(Option<&'a KbkdfCounterFormat>), /// Identifies location of counter in constructed PRF input data. Counter(&'a KbkdfCounterFormat), /// Identifies location of DKM (derived key material) length in constructed PRF input data. @@ -124,11 +124,19 @@ impl<'a> PrfDataParam<'a> { pub fn new(type_: PrfDataParamType<'a>) -> Self { Self { inner: match type_ { - PrfDataParamType::IterationVariable => cryptoki_sys::CK_PRF_DATA_PARAM { + PrfDataParamType::IterationVariable(None) => cryptoki_sys::CK_PRF_DATA_PARAM { type_: cryptoki_sys::CK_SP800_108_ITERATION_VARIABLE, pValue: ptr::null_mut(), ulValueLen: 0, }, + PrfDataParamType::IterationVariable(Some(counter_format)) => { + cryptoki_sys::CK_PRF_DATA_PARAM { + type_: cryptoki_sys::CK_SP800_108_ITERATION_VARIABLE, + pValue: counter_format as *const _ as *mut _, + ulValueLen: size_of::() + as cryptoki_sys::CK_ULONG, + } + } PrfDataParamType::Counter(counter_format) => cryptoki_sys::CK_PRF_DATA_PARAM { type_: cryptoki_sys::CK_SP800_108_COUNTER, pValue: counter_format as *const _ as *mut _, @@ -155,67 +163,6 @@ impl<'a> PrfDataParam<'a> { } } -/// The type of a segment of input data for the PRF, for a KBKDF operating in counter-mode. -#[derive(Debug, Clone, Copy)] -pub enum PrfCounterDataParamType<'a> { - /// Identifies location of iteration variable (a counter in this case) in constructed PRF input data. - IterationVariable(&'a KbkdfCounterFormat), - /// Identifies location of DKM (derived key material) length in constructed PRF input data. - DkmLength(&'a KbkdfDkmLengthFormat), - /// Identifies location and value of byte array of data in constructed PRF input data. - ByteArray(&'a [u8]), -} - -/// A segment of input data for the PRF, to be used to construct a sequence of input. -/// -/// Corresponds to CK_PRF_DATA_PARAM in the specific case of the KDF operating in counter-mode. -#[derive(Debug, Clone, Copy)] -#[repr(transparent)] -pub struct PrfCounterDataParam<'a> { - inner: cryptoki_sys::CK_PRF_DATA_PARAM, - /// Marker type to ensure we don't outlive the data - _marker: PhantomData<&'a [u8]>, -} - -impl<'a> PrfCounterDataParam<'a> { - /// Construct data parameter for input of the PRF internal to the KBKDF. - /// - /// # Arguments - /// - /// * `type_` - The specific type and parameters for the data parameter. - pub fn new(type_: PrfCounterDataParamType<'a>) -> Self { - Self { - inner: match type_ { - PrfCounterDataParamType::IterationVariable(counter_format) => { - cryptoki_sys::CK_PRF_DATA_PARAM { - type_: cryptoki_sys::CK_SP800_108_ITERATION_VARIABLE, - pValue: counter_format as *const _ as *mut _, - ulValueLen: size_of::() - as cryptoki_sys::CK_ULONG, - } - } - PrfCounterDataParamType::DkmLength(dkm_length_format) => { - cryptoki_sys::CK_PRF_DATA_PARAM { - type_: cryptoki_sys::CK_SP800_108_DKM_LENGTH, - pValue: dkm_length_format as *const _ as *mut _, - ulValueLen: size_of::() - as cryptoki_sys::CK_ULONG, - } - } - PrfCounterDataParamType::ByteArray(data) => cryptoki_sys::CK_PRF_DATA_PARAM { - type_: cryptoki_sys::CK_SP800_108_BYTE_ARRAY, - pValue: data.as_ptr() as *mut _, - ulValueLen: data - .len() - .try_into() - .expect("length of data parameter does not fit in CK_ULONG"), - }, - }, - _marker: PhantomData, - } - } -} - /// Container for information on an additional key to be derived. #[derive(Debug)] pub struct DerivedKey { @@ -258,7 +205,7 @@ impl From<&mut DerivedKey> for cryptoki_sys::CK_DERIVED_KEY { /// /// This structure wraps a `CK_SP800_108_KDF_PARAMS` structure. #[derive(Debug)] -pub struct KbkdfCounterParams<'a> { +pub struct KbkdfParams<'a> { /// Holds own data so that we have a contiguous memory region to give to backend additional_derived_keys: Option>>, @@ -267,7 +214,7 @@ pub struct KbkdfCounterParams<'a> { _marker: PhantomData<&'a [u8]>, } -impl<'a> KbkdfCounterParams<'a> { +impl<'a> KbkdfParams<'a> { /// Construct parameters for NIST SP 800-108 KDF (aka KBKDF) pseuderandom function-based key /// derivation function, in counter-mode. /// @@ -280,7 +227,7 @@ impl<'a> KbkdfCounterParams<'a> { /// * `additional_derived_keys` - Any additional keys to be generated by the KDF from the base key. pub fn new( prf_mechanism: MechanismType, - prf_data_params: &'a [PrfCounterDataParam<'a>], + prf_data_params: &'a [PrfDataParam<'a>], additional_derived_keys: Option<&'a mut [DerivedKey]>, ) -> Self { let mut additional_derived_keys = additional_derived_keys @@ -424,84 +371,3 @@ impl<'a> KbkdfFeedbackParams<'a> { }) } } - -/// NIST SP 800-108 (aka KBKDF) double pipeline-mode parameters. -/// -/// This structure wraps a `CK_SP800_108_KDF_PARAMS` structure. -#[derive(Debug)] -pub struct KbkdfDoublePipelineParams<'a> { - /// Holds own data so that we have a contiguous memory region to give to backend - additional_derived_keys: Option>>, - - inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS, - /// Marker type to ensure we don't outlive the data - _marker: PhantomData<&'a [u8]>, -} - -impl<'a> KbkdfDoublePipelineParams<'a> { - /// Construct parameters for NIST SP 800-108 KDF (aka KBKDF) pseuderandom function-based key - /// derivation function, in double pipeline-mode. - /// - /// # Arguments - /// - /// * `prf_mechanism` - The pseudorandom function that underlies the KBKDF operation. - /// - /// * `prf_data_params` - The sequence of data segments used as input data for the PRF. Requires at least [`PrfDataParam::IterationVariable`]. - /// - /// * `additional_derived_keys` - Any additional keys to be generated by the KDF from the base key. - pub fn new( - prf_mechanism: MechanismType, - prf_data_params: &'a [PrfDataParam<'a>], - additional_derived_keys: Option<&'a mut [DerivedKey]>, - ) -> Self { - let mut additional_derived_keys = additional_derived_keys - .map(|keys| { - keys.iter_mut() - .map(Into::into) - .collect::>() - }) - .map(Pin::new); - - let inner = cryptoki_sys::CK_SP800_108_KDF_PARAMS { - prfType: prf_mechanism.into(), - ulNumberOfDataParams: prf_data_params - .len() - .try_into() - .expect("number of data parameters does not fit in CK_ULONG"), - pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, - ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| { - keys.len() - .try_into() - .expect("number of additional derived keys does not fit in CK_ULONG") - }), - pAdditionalDerivedKeys: additional_derived_keys - .as_mut() - .map_or(ptr::null_mut(), |keys| { - keys.as_mut_ptr() as cryptoki_sys::CK_DERIVED_KEY_PTR - }), - }; - - Self { - additional_derived_keys, - - inner, - _marker: PhantomData, - } - } - - pub(crate) fn inner(&self) -> &cryptoki_sys::CK_SP800_108_KDF_PARAMS { - &self.inner - } - - /// The additional keys derived by the KDF, as per the params - pub(crate) fn additional_derived_keys(&self) -> Option> { - self.additional_derived_keys.as_ref().map(|keys| { - keys.iter() - .map(|key| { - // SAFETY: a value is always provided during construction - ObjectHandle::new(unsafe { *key.phKey }) - }) - .collect() - }) - } -} diff --git a/cryptoki/src/mechanism/mod.rs b/cryptoki/src/mechanism/mod.rs index 0bbcb4e5..237192da 100644 --- a/cryptoki/src/mechanism/mod.rs +++ b/cryptoki/src/mechanism/mod.rs @@ -1047,11 +1047,11 @@ pub enum Mechanism<'a> { // NIST SP 800-108 KDF (aka KBKDF) /// NIST SP 800-108 KDF (aka KBKDF) mechanism in counter-mode - KbkdfCounter(kbkdf::KbkdfCounterParams<'a>), + KbkdfCounter(kbkdf::KbkdfParams<'a>), /// NIST SP 800-108 KDF (aka KBKDF) mechanism in feedback-mode KbkdfFeedback(kbkdf::KbkdfFeedbackParams<'a>), /// NIST SP 800-108 KDF (aka KBKDF) mechanism in double pipeline-mode - KbkdfDoublePipeline(kbkdf::KbkdfDoublePipelineParams<'a>), + KbkdfDoublePipeline(kbkdf::KbkdfParams<'a>), /// Vendor defined mechanism VendorDefined(VendorDefinedMechanism<'a>), @@ -1190,9 +1190,10 @@ impl From<&Mechanism<'_>> for CK_MECHANISM { Mechanism::HkdfDerive(params) | Mechanism::HkdfData(params) => { make_mechanism(mechanism, params) } - Mechanism::KbkdfCounter(params) => make_mechanism(mechanism, params.inner()), + Mechanism::KbkdfCounter(params) | Mechanism::KbkdfDoublePipeline(params) => { + make_mechanism(mechanism, params.inner()) + } Mechanism::KbkdfFeedback(params) => make_mechanism(mechanism, params.inner()), - Mechanism::KbkdfDoublePipeline(params) => make_mechanism(mechanism, params.inner()), // Mechanisms without parameters Mechanism::AesKeyGen | Mechanism::AesEcb From f1a15f7f375b1869a2dd1a437c69d3eff791eee2 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:07:45 +0200 Subject: [PATCH 10/22] Changed paradigm for how additional derived keys should be retrieved after KDF operation Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 43 +++++++++----------------- cryptoki/src/mechanism/mod.rs | 18 ----------- cryptoki/src/session/key_management.rs | 29 +---------------- 3 files changed, 15 insertions(+), 75 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index f7a3bc18..42420036 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -182,7 +182,16 @@ impl DerivedKey { Self { template, - handle: 0, + handle: cryptoki_sys::CK_INVALID_HANDLE, + } + } + + /// Return handle for derived key, if it has been created yet + pub fn handle(&self) -> Option { + if self.handle == cryptoki_sys::CK_INVALID_HANDLE { + None + } else { + Some(ObjectHandle::new(self.handle)) } } } @@ -207,7 +216,7 @@ impl From<&mut DerivedKey> for cryptoki_sys::CK_DERIVED_KEY { #[derive(Debug)] pub struct KbkdfParams<'a> { /// Holds own data so that we have a contiguous memory region to give to backend - additional_derived_keys: Option>>, + _additional_derived_keys: Option>>, inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS, /// Marker type to ensure we don't outlive the data @@ -258,7 +267,7 @@ impl<'a> KbkdfParams<'a> { }; Self { - additional_derived_keys, + _additional_derived_keys: additional_derived_keys, inner, _marker: PhantomData, @@ -268,18 +277,6 @@ impl<'a> KbkdfParams<'a> { pub(crate) fn inner(&self) -> &cryptoki_sys::CK_SP800_108_KDF_PARAMS { &self.inner } - - /// The additional keys derived by the KDF, as per the params - pub(crate) fn additional_derived_keys(&self) -> Option> { - self.additional_derived_keys.as_ref().map(|keys| { - keys.iter() - .map(|key| { - // SAFETY: a value is always provided during construction - ObjectHandle::new(unsafe { *key.phKey }) - }) - .collect() - }) - } } /// NIST SP 800-108 (aka KBKDF) feedback-mode parameters. @@ -288,7 +285,7 @@ impl<'a> KbkdfParams<'a> { #[derive(Debug)] pub struct KbkdfFeedbackParams<'a> { /// Holds own data so that we have a contiguous memory region to give to backend - additional_derived_keys: Option>>, + _additional_derived_keys: Option>>, inner: cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS, /// Marker type to ensure we don't outlive the data @@ -348,7 +345,7 @@ impl<'a> KbkdfFeedbackParams<'a> { }; Self { - additional_derived_keys, + _additional_derived_keys: additional_derived_keys, inner, _marker: PhantomData, @@ -358,16 +355,4 @@ impl<'a> KbkdfFeedbackParams<'a> { pub(crate) fn inner(&self) -> &cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS { &self.inner } - - /// The additional keys derived by the KDF, as per the params - pub(crate) fn additional_derived_keys(&self) -> Option> { - self.additional_derived_keys.as_ref().map(|keys| { - keys.iter() - .map(|key| { - // SAFETY: a value is always provided during construction - ObjectHandle::new(unsafe { *key.phKey }) - }) - .collect() - }) - } } diff --git a/cryptoki/src/mechanism/mod.rs b/cryptoki/src/mechanism/mod.rs index 237192da..094a8a7b 100644 --- a/cryptoki/src/mechanism/mod.rs +++ b/cryptoki/src/mechanism/mod.rs @@ -24,7 +24,6 @@ use vendor_defined::VendorDefinedMechanism; use crate::error::Error; use crate::mechanism::rsa::PkcsOaepParams; -use crate::object::ObjectHandle; pub use mechanism_info::MechanismInfo; #[derive(Copy, Debug, Clone, PartialEq, Eq)] @@ -1285,20 +1284,3 @@ impl MessageParam<'_> { } } } - -/// Trait for mechanism types that define additional keys to be derived in their parameters -pub trait HasAdditionalDerivedKeys { - /// Get the object handles for the additional keys that were derived - fn additional_derived_keys(&self) -> Vec; -} - -impl HasAdditionalDerivedKeys for &Mechanism<'_> { - fn additional_derived_keys(&self) -> Vec { - match self { - Mechanism::KbkdfCounter(params) => params.additional_derived_keys().unwrap_or_default(), - Mechanism::KbkdfFeedback(params) => params.additional_derived_keys().unwrap_or_default(), - Mechanism::KbkdfDoublePipeline(params) => params.additional_derived_keys().unwrap_or_default(), - _ => unimplemented!("The given mechanism doesn't define additional keys to derive"), // TODO: this or return an option? - } - } -} diff --git a/cryptoki/src/session/key_management.rs b/cryptoki/src/session/key_management.rs index f0b43ea8..0d5dfd13 100644 --- a/cryptoki/src/session/key_management.rs +++ b/cryptoki/src/session/key_management.rs @@ -4,7 +4,7 @@ use crate::context::Function; use crate::error::{Result, Rv}; -use crate::mechanism::{HasAdditionalDerivedKeys as _, Mechanism}; +use crate::mechanism::Mechanism; use crate::object::{Attribute, ObjectHandle}; use crate::session::Session; use cryptoki_sys::{CK_ATTRIBUTE, CK_MECHANISM, CK_MECHANISM_PTR}; @@ -93,33 +93,6 @@ impl Session { Ok(ObjectHandle::new(handle)) } - /// Derives multiple keys from a base key - pub fn derive_keys( - &self, - mechanism: &Mechanism, - base_key: ObjectHandle, - template: &[Attribute], - ) -> Result<(ObjectHandle, Vec)> { - let mut c_mechanism: CK_MECHANISM = mechanism.into(); - let mut template: Vec = template.iter().map(|attr| attr.into()).collect(); - let mut handle = 0; - unsafe { - Rv::from(get_pkcs11!(self.client(), C_DeriveKey)( - self.handle(), - &mut c_mechanism as CK_MECHANISM_PTR, - base_key.handle(), - template.as_mut_ptr(), - template.len().try_into()?, - &mut handle, - )) - .into_result(Function::DeriveKey)?; - } - - let additional_key_handles = mechanism.additional_derived_keys(); - - Ok((ObjectHandle::new(handle), additional_key_handles)) - } - /// Wrap key pub fn wrap_key( &self, From 6cd230f51014a494adcbe3877f7d9a88f598c346 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:44:28 +0200 Subject: [PATCH 11/22] Improved doc comments Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index 42420036..6d583323 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -98,7 +98,7 @@ pub enum PrfDataParamType<'a> { IterationVariable(Option<&'a KbkdfCounterFormat>), /// Identifies location of counter in constructed PRF input data. Counter(&'a KbkdfCounterFormat), - /// Identifies location of DKM (derived key material) length in constructed PRF input data. + /// Identifies location of DKM (derived key material) length value in constructed PRF input data. DkmLength(&'a KbkdfDkmLengthFormat), /// Identifies location and value of byte array of data in constructed PRF input data. ByteArray(&'a [u8]), @@ -106,7 +106,14 @@ pub enum PrfDataParamType<'a> { /// A segment of input data for the PRF, to be used to construct a sequence of input. /// -/// Corresponds to CK_PRF_DATA_PARAM in the specific cases of the KDF operating in feedback- or double pipeline-mode. +/// This structure wraps a `CK_PRF_DATA_PARAM` structure. +/// +/// * [`PrfDataParamType::IterationVariable`] is required for the KDF in all modes. +/// * In counter-mode, [`PrfDataParamType::IterationVariable`] must contain [`KbkdfCounterFormat`]. +/// In feedback- and double pipeline-mode, it must contain [`None`]. +/// * [`PrfDataParamType::Counter`] must not be present in counter-mode. +/// * [`PrfDataParamType::DkmLength`] can be present at most once, in any mode. +/// * [`PrfDataParamType::ByteArray`] can be present any amount of times, in any mode. #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct PrfDataParam<'a> { @@ -210,7 +217,7 @@ impl From<&mut DerivedKey> for cryptoki_sys::CK_DERIVED_KEY { } } -/// NIST SP 800-108 (aka KBKDF) counter-mode parameters. +/// NIST SP 800-108 (aka KBKDF) counter and double pipeline-mode parameters. /// /// This structure wraps a `CK_SP800_108_KDF_PARAMS` structure. #[derive(Debug)] @@ -225,7 +232,7 @@ pub struct KbkdfParams<'a> { impl<'a> KbkdfParams<'a> { /// Construct parameters for NIST SP 800-108 KDF (aka KBKDF) pseuderandom function-based key - /// derivation function, in counter-mode. + /// derivation function, in counter or double pipeline-mode. /// /// # Arguments /// From 3a6d286590aefa9b1513554d7115755a74807c7f Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:52:48 +0200 Subject: [PATCH 12/22] Improved comments and expect() error messages Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 11 ++++++----- cryptoki/src/mechanism/mod.rs | 8 +++++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index 6d583323..8219488b 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -85,7 +85,7 @@ impl KbkdfDkmLengthFormat { }, bLittleEndian: (endianness == Endianness::Little).into(), ulWidthInBits: width_in_bits.try_into().expect( - "bit width of KBKDF derived key material length value does not fit in CK_ULONG", + "bit width of KBKDF DKM length value does not fit in CK_ULONG", ), }) } @@ -111,7 +111,8 @@ pub enum PrfDataParamType<'a> { /// * [`PrfDataParamType::IterationVariable`] is required for the KDF in all modes. /// * In counter-mode, [`PrfDataParamType::IterationVariable`] must contain [`KbkdfCounterFormat`]. /// In feedback- and double pipeline-mode, it must contain [`None`]. -/// * [`PrfDataParamType::Counter`] must not be present in counter-mode. +/// * [`PrfDataParamType::Counter`] must not be present in counter-mode, and can be present at most +/// once in feedback- and double-pipeline modes. /// * [`PrfDataParamType::DkmLength`] can be present at most once, in any mode. /// * [`PrfDataParamType::ByteArray`] can be present any amount of times, in any mode. #[derive(Debug, Clone, Copy)] @@ -162,7 +163,7 @@ impl<'a> PrfDataParam<'a> { ulValueLen: data .len() .try_into() - .expect("length of data parameter does not fit in CK_ULONG"), + .expect("length of PRF data parameter does not fit in CK_ULONG"), }, }, _marker: PhantomData, @@ -259,7 +260,7 @@ impl<'a> KbkdfParams<'a> { ulNumberOfDataParams: prf_data_params .len() .try_into() - .expect("number of data parameters does not fit in CK_ULONG"), + .expect("number of PRF data parameters does not fit in CK_ULONG"), pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| { keys.len() @@ -331,7 +332,7 @@ impl<'a> KbkdfFeedbackParams<'a> { ulNumberOfDataParams: prf_data_params .len() .try_into() - .expect("number of data parameters does not fit in CK_ULONG"), + .expect("number of PRF data parameters does not fit in CK_ULONG"), pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, ulIVLen: iv.map_or(0, |iv| { iv.len() diff --git a/cryptoki/src/mechanism/mod.rs b/cryptoki/src/mechanism/mod.rs index 094a8a7b..805ff87b 100644 --- a/cryptoki/src/mechanism/mod.rs +++ b/cryptoki/src/mechanism/mod.rs @@ -1252,9 +1252,11 @@ impl From<&Mechanism<'_>> for CK_MECHANISM { fn make_mechanism(mechanism: CK_MECHANISM_TYPE, param: &T) -> CK_MECHANISM { CK_MECHANISM { mechanism, - // SAFETY: Although the type signature says *mut, none of the - // mechanisms we support involve mutating the parameter, so - // this cast is OK. + // SAFETY: Parameters that expect to have some part of themselves + // mutated (such as additional_derived_keys in Kbkdf{*}Params) should + // indicate this to the end user by marking the relevant constructor + // parameters as mut. Otherwise, we should generally not expect the + // backend to mutate the parameters, so this cast is fine. pParameter: param as *const T as *mut c_void, ulParameterLen: size_of::() .try_into() From 8a9a30a45cb7fbf0b7fa3fc6a9cb7453e9473d18 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Fri, 11 Apr 2025 17:30:42 +0200 Subject: [PATCH 13/22] Added tests for NIST SP800-108 KDF (KBKDF) Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/tests/basic.rs | 949 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 949 insertions(+) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index e3f418ec..3a8c1918 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -8,6 +8,10 @@ use cryptoki::context::Function; use cryptoki::error::{Error, RvError}; use cryptoki::mechanism::aead::{GcmMessageParams, GcmParams, GeneratorFunction}; use cryptoki::mechanism::eddsa::{EddsaParams, EddsaSignatureScheme}; +use cryptoki::mechanism::kbkdf::{ + DerivedKey, DkmLengthMethod, Endianness, KbkdfCounterFormat, KbkdfDkmLengthFormat, + KbkdfFeedbackParams, KbkdfParams, PrfDataParam, PrfDataParamType, +}; use cryptoki::mechanism::rsa::{PkcsMgfType, PkcsOaepParams, PkcsOaepSource}; use cryptoki::mechanism::{Mechanism, MechanismType, MessageParam}; use cryptoki::object::{ @@ -24,6 +28,7 @@ use cryptoki::mechanism::ekdf::AesCbcDeriveParams; use testresult::TestResult; const AES128_BLOCK_SIZE: usize = 128 / 8; +const AES256_BLOCK_SIZE: usize = 256 / 8; #[test] #[serial] @@ -2170,6 +2175,950 @@ fn ekdf_aes_cbc_encrypt_data() -> TestResult { Ok(()) } +#[test] +#[serial] +fn kbkdf_all_modes() -> TestResult { + /* SoftHSM does not support NIST SP800-108 KDF yet */ + if is_softhsm() { + return Ok(()); + } + + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Generate base key + let base_template = [ + Attribute::Token(true), + Attribute::Private(false), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Derive(true), + ]; + let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; + + // The template of the key to derive + let derived_key_template = [ + Attribute::Token(false), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + ]; + + // Some variables we will use throughout + let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); + let dkm_length_format = + KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); + + /* COUNTER-MODE */ + + // Instantiate KBKDF in counter-mode without additional keys + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(Some(&counter_format))), + PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), + PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), + PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); + + // Derive key + let derived_key_counter = session.derive_key( + &Mechanism::KbkdfCounter(params), + base_key, + &derived_key_template, + )?; + + /* FEEDBACK-MODE - no IV */ + + // Instantiate KBKDF in feedback-mode without additional keys or an IV + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(None)), + PrfDataParam::new(PrfDataParamType::Counter(&counter_format)), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfFeedbackParams::new(MechanismType::AES_CMAC, &data_params, None, None); + + // Derive key + let derived_key_feedback_no_iv = session.derive_key( + &Mechanism::KbkdfFeedback(params), + base_key, + &derived_key_template, + )?; + + /* FEEDBACK-MODE - with IV */ + + // Instantiate KBKDF in feedback-mode without additional keys but with an IV + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(None)), + PrfDataParam::new(PrfDataParamType::Counter(&counter_format)), + ]; + let params = KbkdfFeedbackParams::new( + MechanismType::AES_CMAC, + &data_params, + Some(b"some_initialization_vector"), + None, + ); + + // Derive key + let derived_key_feedback_iv = session.derive_key( + &Mechanism::KbkdfFeedback(params), + base_key, + &derived_key_template, + )?; + + /* DOUBLE PIPELINE-MODE */ + + /* FIXME: NIST SP800-108 in double-pipeline mode is not yet supported by SoftHSM or Kryoptic */ + if false { + // Instantiate KBKDF in feedback-mode without additional keys + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(None)), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); + + // Derive key + let _derived_key_double_pipeline = session.derive_key( + &Mechanism::KbkdfDoublePipeline(params), + base_key, + &derived_key_template, + )?; + } + + // Verify all derived keys match template + let derived_keys = [ + derived_key_counter, + derived_key_feedback_no_iv, + derived_key_feedback_iv, + /* FIXME: same reason as above */ + // derived_key_double_pipeline, + ]; + + let attributes_to_check = [ + AttributeType::Class, + AttributeType::KeyType, + AttributeType::ValueLen, + AttributeType::Encrypt, + AttributeType::Decrypt, + AttributeType::Sign, + AttributeType::Verify, + AttributeType::Derive, + ]; + let wanted_attributes = [ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + Attribute::Sign(false), + Attribute::Verify(false), + Attribute::Derive(false), + ]; + + for key in derived_keys { + let have_attributes = session.get_attributes(key, &attributes_to_check)?; + + for (value_wanted, value_have) in wanted_attributes.iter().zip(have_attributes.iter()) { + assert_eq!(value_wanted, value_have); + } + } + + // Delete all keys + for key in derived_keys { + session.destroy_object(key)?; + } + session.destroy_object(base_key)?; + + Ok(()) +} + +#[test] +#[serial] +fn kbkdf_additional_keys_all_modes() -> TestResult { + /* SoftHSM does not support NIST SP800-108 KDF yet */ + if is_softhsm() { + return Ok(()); + } + + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Generate base key + let base_template = [ + Attribute::Token(true), + Attribute::Private(false), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Derive(true), + ]; + let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; + + // The templates of the keys to derive. We supply more than one to test deriving additional keys + let derived_key_templates = [ + vec![ + Attribute::Token(false), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + ], + vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES128_BLOCK_SIZE as u64).into()), + Attribute::Sign(true), + Attribute::Verify(true), + ], + vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::GENERIC_SECRET), + Attribute::ValueLen(1.into()), + Attribute::Derive(true), + ], + ]; + + // Some variables we will use throughout + let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); + let dkm_length_format = + KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); + let mut additional_derived_keys = derived_key_templates[1..] + .iter() + .map(|template| DerivedKey::new(template)) + .collect::>(); + + let mut derived_keys = vec![]; + + /* COUNTER-MODE */ + + // Instantiate KBKDF in counter-mode without additional keys + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(Some(&counter_format))), + PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), + PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), + PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfParams::new( + MechanismType::AES_CMAC, + &data_params, + Some(&mut additional_derived_keys), + ); + + // Derive key + let main_derived_key_counter = session.derive_key( + &Mechanism::KbkdfCounter(params), + base_key, + &derived_key_templates[0], + )?; + let additional_derived_keys_counter = additional_derived_keys + .iter() + .filter_map(|key| key.handle()) + .collect::>(); + + derived_keys.push(main_derived_key_counter); + derived_keys.extend(additional_derived_keys_counter); + + /* FEEDBACK-MODE - no IV */ + + // Instantiate KBKDF in feedback-mode without additional keys or an IV + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(None)), + PrfDataParam::new(PrfDataParamType::Counter(&counter_format)), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfFeedbackParams::new( + MechanismType::AES_CMAC, + &data_params, + None, + Some(&mut additional_derived_keys), + ); + + // Derive key + let main_derived_key_feedback_no_iv = session.derive_key( + &Mechanism::KbkdfFeedback(params), + base_key, + &derived_key_templates[0], + )?; + let additional_derived_keys_feedback_no_iv = additional_derived_keys + .iter() + .filter_map(|key| key.handle()) + .collect::>(); + + derived_keys.push(main_derived_key_feedback_no_iv); + derived_keys.extend(additional_derived_keys_feedback_no_iv); + + /* FEEDBACK-MODE - with IV */ + + // Instantiate KBKDF in feedback-mode without additional keys but with an IV + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(None)), + PrfDataParam::new(PrfDataParamType::Counter(&counter_format)), + ]; + let params = KbkdfFeedbackParams::new( + MechanismType::AES_CMAC, + &data_params, + Some(b"some_initialization_vector"), + Some(&mut additional_derived_keys), + ); + + // Derive key + let main_derived_key_feedback_iv = session.derive_key( + &Mechanism::KbkdfFeedback(params), + base_key, + &derived_key_templates[0], + )?; + let additional_derived_keys_feedback_iv = additional_derived_keys + .iter() + .filter_map(|key| key.handle()) + .collect::>(); + + derived_keys.push(main_derived_key_feedback_iv); + derived_keys.extend(additional_derived_keys_feedback_iv); + + /* DOUBLE PIPELINE-MODE */ + + /* FIXME: NIST SP800-108 in double-pipeline mode is not yet supported by SoftHSM or Kryoptic */ + if false { + // Instantiate KBKDF in feedback-mode without additional keys + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(None)), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfParams::new( + MechanismType::AES_CMAC, + &data_params, + Some(&mut additional_derived_keys), + ); + + // Derive key + let main_derived_key_double_pipeline = session.derive_key( + &Mechanism::KbkdfDoublePipeline(params), + base_key, + &derived_key_templates[0], + )?; + let additional_derived_keys_double_pipeline = additional_derived_keys + .iter() + .filter_map(|key| key.handle()) + .collect::>(); + + derived_keys.push(main_derived_key_double_pipeline); + derived_keys.extend(additional_derived_keys_double_pipeline); + } + + // Verify all derived keys match template + let attributes_to_check = [ + AttributeType::Class, + AttributeType::KeyType, + AttributeType::ValueLen, + AttributeType::Encrypt, + AttributeType::Decrypt, + AttributeType::Sign, + AttributeType::Verify, + AttributeType::Derive, + ]; + let wanted_attributes = [ + vec![ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + Attribute::Sign(false), + Attribute::Verify(false), + Attribute::Derive(false), + ], + vec![ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES128_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(false), + Attribute::Decrypt(false), + Attribute::Sign(true), + Attribute::Verify(true), + Attribute::Derive(false), + ], + vec![ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::GENERIC_SECRET), + Attribute::ValueLen(1.into()), + Attribute::Encrypt(false), + Attribute::Decrypt(false), + Attribute::Sign(false), + Attribute::Verify(false), + Attribute::Derive(true), + ], + ]; + + for (key, wanted_attributes) in derived_keys.iter().zip(wanted_attributes.iter().cycle()) { + let have_attributes = session.get_attributes(*key, &attributes_to_check)?; + + for (value_wanted, value_have) in wanted_attributes.iter().zip(have_attributes.iter()) { + assert_eq!(value_wanted, value_have); + } + } + + // Delete all keys + for key in derived_keys { + session.destroy_object(key)?; + } + session.destroy_object(base_key)?; + + Ok(()) +} + +#[test] +#[serial] +fn kbkdf_invalid_data_params_counter_mode() -> TestResult { + /* SoftHSM does not support NIST SP800-108 KDF yet */ + if is_softhsm() { + return Ok(()); + } + + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Generate base key + let base_template = [ + Attribute::Token(true), + Attribute::Private(false), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Derive(true), + ]; + let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; + + // The template of the key to derive + let derived_key_template = [ + Attribute::Token(false), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + ]; + + // Some variables we will use throughout + let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); + let dkm_length_format = + KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); + + /* MISSING ITERATION VARIABLE */ + + // Instantiate KBKDF + let data_params = [ + PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), + PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), + PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); + + // Derive key + let result = session.derive_key( + &Mechanism::KbkdfCounter(params), + base_key, + &derived_key_template, + ); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::MechanismParamInvalid, Function::DeriveKey) + )); + + /* MISSING COUNTER FORMAT IN ITERATION VARIABLE */ + + // Instantiate KBKDF + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(None)), + PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), + PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), + PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); + + // Derive key + let result = session.derive_key( + &Mechanism::KbkdfCounter(params), + base_key, + &derived_key_template, + ); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::MechanismParamInvalid, Function::DeriveKey) + )); + + /* INCLUDING COUNTER */ + + // Instantiate KBKDF + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(Some(&counter_format))), + PrfDataParam::new(PrfDataParamType::Counter(&counter_format)), + PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), + PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), + PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); + + // Derive key + let result = session.derive_key( + &Mechanism::KbkdfCounter(params), + base_key, + &derived_key_template, + ); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::MechanismParamInvalid, Function::DeriveKey) + )); + + /* INCLUDING MORE THAN 1 DKM LENGTH FORMAT */ + + // Instantiate KBKDF + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(Some(&counter_format))), + PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), + PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), + PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); + + // Derive key + let result = session.derive_key( + &Mechanism::KbkdfCounter(params), + base_key, + &derived_key_template, + ); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::MechanismParamInvalid, Function::DeriveKey) + )); + + // Delete base key + session.destroy_object(base_key)?; + + Ok(()) +} + +#[test] +#[serial] +fn kbkdf_invalid_data_params_feedback_mode() -> TestResult { + /* SoftHSM does not support NIST SP800-108 KDF yet */ + if is_softhsm() { + return Ok(()); + } + + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Generate base key + let base_template = [ + Attribute::Token(true), + Attribute::Private(false), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Derive(true), + ]; + let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; + + // The template of the key to derive + let derived_key_template = [ + Attribute::Token(false), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + ]; + + // Some variables we will use throughout + let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); + let dkm_length_format = + KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); + + /* MISSING ITERATION VARIABLE */ + + // Instantiate KBKDF + let data_params = [ + PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), + PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), + PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfFeedbackParams::new(MechanismType::AES_CMAC, &data_params, None, None); + + // Derive key + let result = session.derive_key( + &Mechanism::KbkdfFeedback(params), + base_key, + &derived_key_template, + ); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::MechanismParamInvalid, Function::DeriveKey) + )); + + /* INCLUDING COUNTER FORMAT IN ITERATION VARIABLE */ + + // Instantiate KBKDF + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(Some(&counter_format))), + PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), + PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), + PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfFeedbackParams::new(MechanismType::AES_CMAC, &data_params, None, None); + + // Derive key + let result = session.derive_key( + &Mechanism::KbkdfFeedback(params), + base_key, + &derived_key_template, + ); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::MechanismParamInvalid, Function::DeriveKey) + )); + + /* INCLUDING MORE THAN 1 DKM LENGTH FORMAT */ + + // Instantiate KBKDF + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(Some(&counter_format))), + PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), + PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), + PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfFeedbackParams::new(MechanismType::AES_CMAC, &data_params, None, None); + + // Derive key + let result = session.derive_key( + &Mechanism::KbkdfFeedback(params), + base_key, + &derived_key_template, + ); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::MechanismParamInvalid, Function::DeriveKey) + )); + + // Delete base key + session.destroy_object(base_key)?; + + Ok(()) +} + +#[test] +#[serial] +fn kbkdf_invalid_data_params_double_pipeline_mode() -> TestResult { + /* FIXME: NIST SP800-108 in double-pipeline mode is not yet supported by SoftHSM or Kryoptic */ + if true { + return Ok(()); + } + + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Generate base key + let base_template = [ + Attribute::Token(true), + Attribute::Private(false), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Derive(true), + ]; + let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; + + // The template of the key to derive + let derived_key_template = [ + Attribute::Token(false), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + ]; + + // Some variables we will use throughout + let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); + let dkm_length_format = + KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); + + /* MISSING ITERATION VARIABLE */ + + // Instantiate KBKDF + let data_params = [ + PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), + PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), + PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); + + // Derive key + let result = session.derive_key( + &Mechanism::KbkdfDoublePipeline(params), + base_key, + &derived_key_template, + ); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::MechanismParamInvalid, Function::DeriveKey) + )); + + /* INCLUDING COUNTER FORMAT IN ITERATION VARIABLE */ + + // Instantiate KBKDF + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(Some(&counter_format))), + PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), + PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), + PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); + + // Derive key + let result = session.derive_key( + &Mechanism::KbkdfDoublePipeline(params), + base_key, + &derived_key_template, + ); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::MechanismParamInvalid, Function::DeriveKey) + )); + + /* INCLUDING MORE THAN 1 DKM LENGTH FORMAT */ + + // Instantiate KBKDF + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(Some(&counter_format))), + PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), + PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), + PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); + + // Derive key + let result = session.derive_key( + &Mechanism::KbkdfDoublePipeline(params), + base_key, + &derived_key_template, + ); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::MechanismParamInvalid, Function::DeriveKey) + )); + + // Delete base key + session.destroy_object(base_key)?; + + Ok(()) +} + +// #[test] +// #[serial] +// fn kbkdf_invalid_data_params() -> TestResult { +// /* SoftHSM does not support NIST SP800-108 KDF yet */ +// if is_softhsm() { +// return Ok(()); +// } + +// let (pkcs11, slot) = init_pins(); + +// // Open a session and log in +// let session = pkcs11.open_rw_session(slot)?; +// session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + +// // Generate base key +// let base_template = vec![ +// Attribute::Token(true), +// Attribute::Private(false), +// Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), +// Attribute::Derive(true), +// ]; +// let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; + +// // The template of the key to derive +// let derived_key_template = vec![ +// Attribute::Token(false), +// Attribute::Private(false), +// Attribute::Class(ObjectClass::SECRET_KEY), +// Attribute::KeyType(KeyType::AES), +// Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), +// Attribute::Encrypt(true), +// Attribute::Decrypt(true), +// ]; + +// // Instantiate KBKDF in counter mode without additional keys +// let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); +// let dkm_length_format = +// KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); +// let data_params = vec![ +// PrfDataParam::new(PrfDataParamType::IterationVariable(Some(&counter_format))), +// PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), +// PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), +// PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), +// PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), +// ]; +// let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); + +// // Derive key +// let derived_key = session.derive_key( +// &Mechanism::KbkdfCounter(params), +// base_key, +// &derived_key_template, +// )?; + +// let wanted_attributes = vec![ +// AttributeType::Class, +// AttributeType::KeyType, +// AttributeType::Encrypt, +// AttributeType::Decrypt, +// AttributeType::Sign, +// AttributeType::Verify, +// AttributeType::Derive, +// AttributeType::ValueLen, +// ]; + +// // TODO: remove this! +// println!( +// "Main derived key: {:#?}", +// session.get_attributes(derived_key, &wanted_attributes)? +// ); + +// session.destroy_object(derived_key)?; +// session.destroy_object(base_key)?; + +// Ok(()) +// } + +// #[test] +// #[serial] +// fn kbkdf_missing_data_params() -> TestResult { +// /* SoftHSM does not support NIST SP800-108 KDF yet */ +// if is_softhsm() { +// return Ok(()); +// } + +// let (pkcs11, slot) = init_pins(); + +// // Open a session and log in +// let session = pkcs11.open_rw_session(slot)?; +// session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + +// // Generate base key +// let base_template = vec![ +// Attribute::Token(true), +// Attribute::Private(false), +// Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), +// Attribute::Derive(true), +// ]; +// let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; + +// // The template of the key to derive +// let derived_key_template = vec![ +// Attribute::Token(false), +// Attribute::Private(false), +// Attribute::Class(ObjectClass::SECRET_KEY), +// Attribute::KeyType(KeyType::AES), +// Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), +// Attribute::Encrypt(true), +// Attribute::Decrypt(true), +// ]; + +// // Instantiate KBKDF in counter mode without additional keys +// let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); +// let dkm_length_format = +// KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); +// let data_params = vec![ +// PrfDataParam::new(PrfDataParamType::IterationVariable(Some(&counter_format))), +// PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), +// PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), +// PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), +// PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), +// ]; +// let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); + +// // Derive key +// let derived_key = session.derive_key( +// &Mechanism::KbkdfCounter(params), +// base_key, +// &derived_key_template, +// )?; + +// let wanted_attributes = vec![ +// AttributeType::Class, +// AttributeType::KeyType, +// AttributeType::Encrypt, +// AttributeType::Decrypt, +// AttributeType::Sign, +// AttributeType::Verify, +// AttributeType::Derive, +// AttributeType::ValueLen, +// ]; + +// // TODO: remove this! +// println!( +// "Main derived key: {:#?}", +// session.get_attributes(derived_key, &wanted_attributes)? +// ); + +// session.destroy_object(derived_key)?; +// session.destroy_object(base_key)?; + +// Ok(()) +// } + #[test] #[serial] fn sign_verify_sha1_hmac() -> TestResult { From 91cd39fba2fb0db99338c07d9ea4bd9b201e2961 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Mon, 14 Apr 2025 11:17:42 +0200 Subject: [PATCH 14/22] Removed all cryptoki_sys qualifiers Changed my mind on coding style Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 112 ++++++++++++++++---------------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index 8219488b..7a87c1b3 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -5,6 +5,15 @@ use core::{convert::TryInto, marker::PhantomData, pin::Pin, ptr}; +use cryptoki_sys::{ + CK_ATTRIBUTE, CK_ATTRIBUTE_PTR, CK_DERIVED_KEY, CK_DERIVED_KEY_PTR, CK_INVALID_HANDLE, + CK_OBJECT_HANDLE, CK_OBJECT_HANDLE_PTR, CK_PRF_DATA_PARAM, CK_PRF_DATA_PARAM_PTR, + CK_SP800_108_BYTE_ARRAY, CK_SP800_108_COUNTER, CK_SP800_108_COUNTER_FORMAT, + CK_SP800_108_DKM_LENGTH, CK_SP800_108_DKM_LENGTH_FORMAT, CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, + CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS, CK_SP800_108_FEEDBACK_KDF_PARAMS, + CK_SP800_108_ITERATION_VARIABLE, CK_SP800_108_KDF_PARAMS, CK_ULONG, +}; + use crate::object::{Attribute, ObjectHandle}; use super::MechanismType; @@ -23,7 +32,7 @@ pub enum Endianness { /// This structure wraps a `CK_SP800_108_COUNTER_FORMAT` structure. #[derive(Debug, Clone, Copy)] #[repr(transparent)] -pub struct KbkdfCounterFormat(cryptoki_sys::CK_SP800_108_COUNTER_FORMAT); +pub struct KbkdfCounterFormat(CK_SP800_108_COUNTER_FORMAT); impl KbkdfCounterFormat { /// Construct encoding format for KDF's internal counter variable. @@ -34,7 +43,7 @@ impl KbkdfCounterFormat { /// /// * `width_in_bits` - The number of bits used to represent the counter value. pub fn new(endianness: Endianness, width_in_bits: usize) -> Self { - Self(cryptoki_sys::CK_SP800_108_COUNTER_FORMAT { + Self(CK_SP800_108_COUNTER_FORMAT { bLittleEndian: (endianness == Endianness::Little).into(), ulWidthInBits: width_in_bits .try_into() @@ -59,7 +68,7 @@ pub enum DkmLengthMethod { /// This structure wraps a `CK_SP800_108_DKM_LENGTH_FORMAT` structure. #[derive(Debug, Clone, Copy)] #[repr(transparent)] -pub struct KbkdfDkmLengthFormat(cryptoki_sys::CK_SP800_108_DKM_LENGTH_FORMAT); +pub struct KbkdfDkmLengthFormat(CK_SP800_108_DKM_LENGTH_FORMAT); impl KbkdfDkmLengthFormat { /// Construct encoding format for length value of DKM (derived key material) from KDF. @@ -76,17 +85,15 @@ impl KbkdfDkmLengthFormat { endianness: Endianness, width_in_bits: usize, ) -> Self { - Self(cryptoki_sys::CK_SP800_108_DKM_LENGTH_FORMAT { + Self(CK_SP800_108_DKM_LENGTH_FORMAT { dkmLengthMethod: match dkm_length_method { - DkmLengthMethod::SumOfKeys => cryptoki_sys::CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, - DkmLengthMethod::SumOfSegments => { - cryptoki_sys::CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS - } + DkmLengthMethod::SumOfKeys => CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, + DkmLengthMethod::SumOfSegments => CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS, }, bLittleEndian: (endianness == Endianness::Little).into(), - ulWidthInBits: width_in_bits.try_into().expect( - "bit width of KBKDF DKM length value does not fit in CK_ULONG", - ), + ulWidthInBits: width_in_bits + .try_into() + .expect("bit width of KBKDF DKM length value does not fit in CK_ULONG"), }) } } @@ -118,7 +125,7 @@ pub enum PrfDataParamType<'a> { #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct PrfDataParam<'a> { - inner: cryptoki_sys::CK_PRF_DATA_PARAM, + inner: CK_PRF_DATA_PARAM, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, } @@ -132,33 +139,28 @@ impl<'a> PrfDataParam<'a> { pub fn new(type_: PrfDataParamType<'a>) -> Self { Self { inner: match type_ { - PrfDataParamType::IterationVariable(None) => cryptoki_sys::CK_PRF_DATA_PARAM { - type_: cryptoki_sys::CK_SP800_108_ITERATION_VARIABLE, + PrfDataParamType::IterationVariable(None) => CK_PRF_DATA_PARAM { + type_: CK_SP800_108_ITERATION_VARIABLE, pValue: ptr::null_mut(), ulValueLen: 0, }, - PrfDataParamType::IterationVariable(Some(counter_format)) => { - cryptoki_sys::CK_PRF_DATA_PARAM { - type_: cryptoki_sys::CK_SP800_108_ITERATION_VARIABLE, - pValue: counter_format as *const _ as *mut _, - ulValueLen: size_of::() - as cryptoki_sys::CK_ULONG, - } - } - PrfDataParamType::Counter(counter_format) => cryptoki_sys::CK_PRF_DATA_PARAM { - type_: cryptoki_sys::CK_SP800_108_COUNTER, + PrfDataParamType::IterationVariable(Some(counter_format)) => CK_PRF_DATA_PARAM { + type_: CK_SP800_108_ITERATION_VARIABLE, + pValue: counter_format as *const _ as *mut _, + ulValueLen: size_of::() as CK_ULONG, + }, + PrfDataParamType::Counter(counter_format) => CK_PRF_DATA_PARAM { + type_: CK_SP800_108_COUNTER, pValue: counter_format as *const _ as *mut _, - ulValueLen: size_of::() - as cryptoki_sys::CK_ULONG, + ulValueLen: size_of::() as CK_ULONG, }, - PrfDataParamType::DkmLength(dkm_length_format) => cryptoki_sys::CK_PRF_DATA_PARAM { - type_: cryptoki_sys::CK_SP800_108_DKM_LENGTH, + PrfDataParamType::DkmLength(dkm_length_format) => CK_PRF_DATA_PARAM { + type_: CK_SP800_108_DKM_LENGTH, pValue: dkm_length_format as *const _ as *mut _, - ulValueLen: size_of::() - as cryptoki_sys::CK_ULONG, + ulValueLen: size_of::() as CK_ULONG, }, - PrfDataParamType::ByteArray(data) => cryptoki_sys::CK_PRF_DATA_PARAM { - type_: cryptoki_sys::CK_SP800_108_BYTE_ARRAY, + PrfDataParamType::ByteArray(data) => CK_PRF_DATA_PARAM { + type_: CK_SP800_108_BYTE_ARRAY, pValue: data.as_ptr() as *mut _, ulValueLen: data .len() @@ -174,8 +176,8 @@ impl<'a> PrfDataParam<'a> { /// Container for information on an additional key to be derived. #[derive(Debug)] pub struct DerivedKey { - template: Pin>, - handle: cryptoki_sys::CK_OBJECT_HANDLE, + template: Pin>, + handle: CK_OBJECT_HANDLE, } impl DerivedKey { @@ -185,18 +187,18 @@ impl DerivedKey { /// /// * `template` - The template for the key to be derived. pub fn new(template: &[Attribute]) -> Self { - let template: Box<[cryptoki_sys::CK_ATTRIBUTE]> = template.iter().map(Into::into).collect(); + let template: Box<[CK_ATTRIBUTE]> = template.iter().map(Into::into).collect(); let template = Pin::new(template); Self { template, - handle: cryptoki_sys::CK_INVALID_HANDLE, + handle: CK_INVALID_HANDLE, } } /// Return handle for derived key, if it has been created yet pub fn handle(&self) -> Option { - if self.handle == cryptoki_sys::CK_INVALID_HANDLE { + if self.handle == CK_INVALID_HANDLE { None } else { Some(ObjectHandle::new(self.handle)) @@ -204,16 +206,16 @@ impl DerivedKey { } } -impl From<&mut DerivedKey> for cryptoki_sys::CK_DERIVED_KEY { +impl From<&mut DerivedKey> for CK_DERIVED_KEY { fn from(value: &mut DerivedKey) -> Self { - cryptoki_sys::CK_DERIVED_KEY { - pTemplate: value.template.as_ptr() as cryptoki_sys::CK_ATTRIBUTE_PTR, + CK_DERIVED_KEY { + pTemplate: value.template.as_ptr() as CK_ATTRIBUTE_PTR, ulAttributeCount: value .template .len() .try_into() .expect("number of attributes in template does not fit in CK_ULONG"), - phKey: &mut value.handle as cryptoki_sys::CK_OBJECT_HANDLE_PTR, + phKey: &mut value.handle as CK_OBJECT_HANDLE_PTR, } } } @@ -224,9 +226,9 @@ impl From<&mut DerivedKey> for cryptoki_sys::CK_DERIVED_KEY { #[derive(Debug)] pub struct KbkdfParams<'a> { /// Holds own data so that we have a contiguous memory region to give to backend - _additional_derived_keys: Option>>, + _additional_derived_keys: Option>>, - inner: cryptoki_sys::CK_SP800_108_KDF_PARAMS, + inner: CK_SP800_108_KDF_PARAMS, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, } @@ -251,17 +253,17 @@ impl<'a> KbkdfParams<'a> { .map(|keys| { keys.iter_mut() .map(Into::into) - .collect::>() + .collect::>() }) .map(Pin::new); - let inner = cryptoki_sys::CK_SP800_108_KDF_PARAMS { + let inner = CK_SP800_108_KDF_PARAMS { prfType: prf_mechanism.into(), ulNumberOfDataParams: prf_data_params .len() .try_into() .expect("number of PRF data parameters does not fit in CK_ULONG"), - pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, + pDataParams: prf_data_params.as_ptr() as CK_PRF_DATA_PARAM_PTR, ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| { keys.len() .try_into() @@ -270,7 +272,7 @@ impl<'a> KbkdfParams<'a> { pAdditionalDerivedKeys: additional_derived_keys .as_mut() .map_or(ptr::null_mut(), |keys| { - keys.as_mut_ptr() as cryptoki_sys::CK_DERIVED_KEY_PTR + keys.as_mut_ptr() as CK_DERIVED_KEY_PTR }), }; @@ -282,7 +284,7 @@ impl<'a> KbkdfParams<'a> { } } - pub(crate) fn inner(&self) -> &cryptoki_sys::CK_SP800_108_KDF_PARAMS { + pub(crate) fn inner(&self) -> &CK_SP800_108_KDF_PARAMS { &self.inner } } @@ -293,9 +295,9 @@ impl<'a> KbkdfParams<'a> { #[derive(Debug)] pub struct KbkdfFeedbackParams<'a> { /// Holds own data so that we have a contiguous memory region to give to backend - _additional_derived_keys: Option>>, + _additional_derived_keys: Option>>, - inner: cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS, + inner: CK_SP800_108_FEEDBACK_KDF_PARAMS, /// Marker type to ensure we don't outlive the data _marker: PhantomData<&'a [u8]>, } @@ -323,17 +325,17 @@ impl<'a> KbkdfFeedbackParams<'a> { .map(|keys| { keys.iter_mut() .map(Into::into) - .collect::>() + .collect::>() }) .map(Pin::new); - let inner = cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS { + let inner = CK_SP800_108_FEEDBACK_KDF_PARAMS { prfType: prf_mechanism.into(), ulNumberOfDataParams: prf_data_params .len() .try_into() .expect("number of PRF data parameters does not fit in CK_ULONG"), - pDataParams: prf_data_params.as_ptr() as cryptoki_sys::CK_PRF_DATA_PARAM_PTR, + pDataParams: prf_data_params.as_ptr() as CK_PRF_DATA_PARAM_PTR, ulIVLen: iv.map_or(0, |iv| { iv.len() .try_into() @@ -348,7 +350,7 @@ impl<'a> KbkdfFeedbackParams<'a> { pAdditionalDerivedKeys: additional_derived_keys .as_mut() .map_or(ptr::null_mut(), |keys| { - keys.as_mut_ptr() as cryptoki_sys::CK_DERIVED_KEY_PTR + keys.as_mut_ptr() as CK_DERIVED_KEY_PTR }), }; @@ -360,7 +362,7 @@ impl<'a> KbkdfFeedbackParams<'a> { } } - pub(crate) fn inner(&self) -> &cryptoki_sys::CK_SP800_108_FEEDBACK_KDF_PARAMS { + pub(crate) fn inner(&self) -> &CK_SP800_108_FEEDBACK_KDF_PARAMS { &self.inner } } From 1d2fca8d602db973c196eda45f8b8992940d5921 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Mon, 14 Apr 2025 11:31:30 +0200 Subject: [PATCH 15/22] Renamed `DkmLengthMethod` to `KbkdfDkmLengthMethod` for consistency Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 8 ++++---- cryptoki/tests/basic.rs | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index 7a87c1b3..10b065eb 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -56,7 +56,7 @@ impl KbkdfCounterFormat { /// /// Corresponds to CK_SP800_108_DKM_LENGTH_METHOD. #[derive(Debug, Clone, Copy)] -pub enum DkmLengthMethod { +pub enum KbkdfDkmLengthMethod { /// Sum of length of all keys derived by given invocation of KDF. SumOfKeys, /// Sum of length of all segments of output produced by PRF in given invocation of KDF. @@ -81,14 +81,14 @@ impl KbkdfDkmLengthFormat { /// /// * `width_in_bits` - The number of bits used to represent the DKM length value. pub fn new( - dkm_length_method: DkmLengthMethod, + dkm_length_method: KbkdfDkmLengthMethod, endianness: Endianness, width_in_bits: usize, ) -> Self { Self(CK_SP800_108_DKM_LENGTH_FORMAT { dkmLengthMethod: match dkm_length_method { - DkmLengthMethod::SumOfKeys => CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, - DkmLengthMethod::SumOfSegments => CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS, + KbkdfDkmLengthMethod::SumOfKeys => CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS, + KbkdfDkmLengthMethod::SumOfSegments => CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS, }, bLittleEndian: (endianness == Endianness::Little).into(), ulWidthInBits: width_in_bits diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 3a8c1918..ff5d502d 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -9,7 +9,7 @@ use cryptoki::error::{Error, RvError}; use cryptoki::mechanism::aead::{GcmMessageParams, GcmParams, GeneratorFunction}; use cryptoki::mechanism::eddsa::{EddsaParams, EddsaSignatureScheme}; use cryptoki::mechanism::kbkdf::{ - DerivedKey, DkmLengthMethod, Endianness, KbkdfCounterFormat, KbkdfDkmLengthFormat, + DerivedKey, KbkdfDkmLengthMethod, Endianness, KbkdfCounterFormat, KbkdfDkmLengthFormat, KbkdfFeedbackParams, KbkdfParams, PrfDataParam, PrfDataParamType, }; use cryptoki::mechanism::rsa::{PkcsMgfType, PkcsOaepParams, PkcsOaepSource}; @@ -2212,7 +2212,7 @@ fn kbkdf_all_modes() -> TestResult { // Some variables we will use throughout let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); let dkm_length_format = - KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); + KbkdfDkmLengthFormat::new(KbkdfDkmLengthMethod::SumOfKeys, Endianness::Big, 16); /* COUNTER-MODE */ @@ -2393,7 +2393,7 @@ fn kbkdf_additional_keys_all_modes() -> TestResult { // Some variables we will use throughout let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); let dkm_length_format = - KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); + KbkdfDkmLengthFormat::new(KbkdfDkmLengthMethod::SumOfKeys, Endianness::Big, 16); let mut additional_derived_keys = derived_key_templates[1..] .iter() .map(|template| DerivedKey::new(template)) @@ -2616,7 +2616,7 @@ fn kbkdf_invalid_data_params_counter_mode() -> TestResult { // Some variables we will use throughout let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); let dkm_length_format = - KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); + KbkdfDkmLengthFormat::new(KbkdfDkmLengthMethod::SumOfKeys, Endianness::Big, 16); /* MISSING ITERATION VARIABLE */ @@ -2762,7 +2762,7 @@ fn kbkdf_invalid_data_params_feedback_mode() -> TestResult { // Some variables we will use throughout let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); let dkm_length_format = - KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); + KbkdfDkmLengthFormat::new(KbkdfDkmLengthMethod::SumOfKeys, Endianness::Big, 16); /* MISSING ITERATION VARIABLE */ @@ -2882,7 +2882,7 @@ fn kbkdf_invalid_data_params_double_pipeline_mode() -> TestResult { // Some variables we will use throughout let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); let dkm_length_format = - KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); + KbkdfDkmLengthFormat::new(KbkdfDkmLengthMethod::SumOfKeys, Endianness::Big, 16); /* MISSING ITERATION VARIABLE */ From 4e6be131da319ea228c2f0b9a75942ef9dbd1c5f Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Mon, 14 Apr 2025 11:47:43 +0200 Subject: [PATCH 16/22] Removed unused tests I forgot about Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/tests/basic.rs | 154 ---------------------------------------- 1 file changed, 154 deletions(-) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index ff5d502d..d2f65918 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -2965,160 +2965,6 @@ fn kbkdf_invalid_data_params_double_pipeline_mode() -> TestResult { Ok(()) } -// #[test] -// #[serial] -// fn kbkdf_invalid_data_params() -> TestResult { -// /* SoftHSM does not support NIST SP800-108 KDF yet */ -// if is_softhsm() { -// return Ok(()); -// } - -// let (pkcs11, slot) = init_pins(); - -// // Open a session and log in -// let session = pkcs11.open_rw_session(slot)?; -// session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; - -// // Generate base key -// let base_template = vec![ -// Attribute::Token(true), -// Attribute::Private(false), -// Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), -// Attribute::Derive(true), -// ]; -// let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; - -// // The template of the key to derive -// let derived_key_template = vec![ -// Attribute::Token(false), -// Attribute::Private(false), -// Attribute::Class(ObjectClass::SECRET_KEY), -// Attribute::KeyType(KeyType::AES), -// Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), -// Attribute::Encrypt(true), -// Attribute::Decrypt(true), -// ]; - -// // Instantiate KBKDF in counter mode without additional keys -// let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); -// let dkm_length_format = -// KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); -// let data_params = vec![ -// PrfDataParam::new(PrfDataParamType::IterationVariable(Some(&counter_format))), -// PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), -// PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), -// PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), -// PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), -// ]; -// let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); - -// // Derive key -// let derived_key = session.derive_key( -// &Mechanism::KbkdfCounter(params), -// base_key, -// &derived_key_template, -// )?; - -// let wanted_attributes = vec![ -// AttributeType::Class, -// AttributeType::KeyType, -// AttributeType::Encrypt, -// AttributeType::Decrypt, -// AttributeType::Sign, -// AttributeType::Verify, -// AttributeType::Derive, -// AttributeType::ValueLen, -// ]; - -// // TODO: remove this! -// println!( -// "Main derived key: {:#?}", -// session.get_attributes(derived_key, &wanted_attributes)? -// ); - -// session.destroy_object(derived_key)?; -// session.destroy_object(base_key)?; - -// Ok(()) -// } - -// #[test] -// #[serial] -// fn kbkdf_missing_data_params() -> TestResult { -// /* SoftHSM does not support NIST SP800-108 KDF yet */ -// if is_softhsm() { -// return Ok(()); -// } - -// let (pkcs11, slot) = init_pins(); - -// // Open a session and log in -// let session = pkcs11.open_rw_session(slot)?; -// session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; - -// // Generate base key -// let base_template = vec![ -// Attribute::Token(true), -// Attribute::Private(false), -// Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), -// Attribute::Derive(true), -// ]; -// let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; - -// // The template of the key to derive -// let derived_key_template = vec![ -// Attribute::Token(false), -// Attribute::Private(false), -// Attribute::Class(ObjectClass::SECRET_KEY), -// Attribute::KeyType(KeyType::AES), -// Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), -// Attribute::Encrypt(true), -// Attribute::Decrypt(true), -// ]; - -// // Instantiate KBKDF in counter mode without additional keys -// let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); -// let dkm_length_format = -// KbkdfDkmLengthFormat::new(DkmLengthMethod::SumOfKeys, Endianness::Big, 16); -// let data_params = vec![ -// PrfDataParam::new(PrfDataParamType::IterationVariable(Some(&counter_format))), -// PrfDataParam::new(PrfDataParamType::ByteArray(b"test_label")), -// PrfDataParam::new(PrfDataParamType::ByteArray(&[0])), -// PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), -// PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), -// ]; -// let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); - -// // Derive key -// let derived_key = session.derive_key( -// &Mechanism::KbkdfCounter(params), -// base_key, -// &derived_key_template, -// )?; - -// let wanted_attributes = vec![ -// AttributeType::Class, -// AttributeType::KeyType, -// AttributeType::Encrypt, -// AttributeType::Decrypt, -// AttributeType::Sign, -// AttributeType::Verify, -// AttributeType::Derive, -// AttributeType::ValueLen, -// ]; - -// // TODO: remove this! -// println!( -// "Main derived key: {:#?}", -// session.get_attributes(derived_key, &wanted_attributes)? -// ); - -// session.destroy_object(derived_key)?; -// session.destroy_object(base_key)?; - -// Ok(()) -// } - #[test] #[serial] fn sign_verify_sha1_hmac() -> TestResult { From 56a113dc426132602fa1c7e12fe8ba3962988864 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Mon, 14 Apr 2025 11:55:45 +0200 Subject: [PATCH 17/22] Made lint fixes Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 4 ++-- cryptoki/tests/basic.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index 10b065eb..f0cbe9be 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -241,7 +241,7 @@ impl<'a> KbkdfParams<'a> { /// /// * `prf_mechanism` - The pseudorandom function that underlies the KBKDF operation. /// - /// * `prf_data_params` - The sequence of data segments used as input data for the PRF. Requires at least [`PrfCounterDataParam::IterationVariable`]. + /// * `prf_data_params` - The sequence of data segments used as input data for the PRF. Requires at least [`PrfDataParamType::IterationVariable`]. /// /// * `additional_derived_keys` - Any additional keys to be generated by the KDF from the base key. pub fn new( @@ -310,7 +310,7 @@ impl<'a> KbkdfFeedbackParams<'a> { /// /// * `prf_mechanism` - The pseudorandom function that underlies the KBKDF operation. /// - /// * `prf_data_params` - The sequence of data segments used as input data for the PRF. Requires at least [`PrfDataParam::IterationVariable`]. + /// * `prf_data_params` - The sequence of data segments used as input data for the PRF. Requires at least [`PrfDataParamType::IterationVariable`]. /// /// * `iv` - The IV to be used for the feedback-mode KDF. /// diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index d2f65918..f98a9e38 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -9,7 +9,7 @@ use cryptoki::error::{Error, RvError}; use cryptoki::mechanism::aead::{GcmMessageParams, GcmParams, GeneratorFunction}; use cryptoki::mechanism::eddsa::{EddsaParams, EddsaSignatureScheme}; use cryptoki::mechanism::kbkdf::{ - DerivedKey, KbkdfDkmLengthMethod, Endianness, KbkdfCounterFormat, KbkdfDkmLengthFormat, + DerivedKey, Endianness, KbkdfCounterFormat, KbkdfDkmLengthFormat, KbkdfDkmLengthMethod, KbkdfFeedbackParams, KbkdfParams, PrfDataParam, PrfDataParamType, }; use cryptoki::mechanism::rsa::{PkcsMgfType, PkcsOaepParams, PkcsOaepSource}; From d0a7c87eb3b90ccf3d138e6bc0ce067b580511a3 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Tue, 15 Apr 2025 11:18:37 +0200 Subject: [PATCH 18/22] Improved doc comments Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index f0cbe9be..fbb7b59e 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -102,6 +102,9 @@ impl KbkdfDkmLengthFormat { #[derive(Debug, Clone, Copy)] pub enum PrfDataParamType<'a> { /// Identifies location of predefined iteration variable in constructed PRF input data. + /// + /// For counter-mode, this must contain a [`KbkdfCounterFormat`]. + /// For feedback- and double-pipeline mode, this must contain [`None`]. IterationVariable(Option<&'a KbkdfCounterFormat>), /// Identifies location of counter in constructed PRF input data. Counter(&'a KbkdfCounterFormat), From 53f116f8d4998a0a0087137cac3ad39f0b2390da Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Tue, 22 Apr 2025 16:40:11 +0200 Subject: [PATCH 19/22] Made spelling fix Co-authored-by: Wiktor Kwapisiewicz Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index fbb7b59e..d49cc4da 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -237,7 +237,7 @@ pub struct KbkdfParams<'a> { } impl<'a> KbkdfParams<'a> { - /// Construct parameters for NIST SP 800-108 KDF (aka KBKDF) pseuderandom function-based key + /// Construct parameters for NIST SP 800-108 KDF (aka KBKDF) pseudorandom function-based key /// derivation function, in counter or double pipeline-mode. /// /// # Arguments From 18de27848266b2a6b871b8342fc794a7bee2d49a Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Tue, 22 Apr 2025 17:20:22 +0200 Subject: [PATCH 20/22] Changed to `NonZeroUsize` for defining bit-width of `CounterFormat` and `DkmLengthFormat` Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index d49cc4da..c1c1a9c8 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -4,6 +4,7 @@ //! See: use core::{convert::TryInto, marker::PhantomData, pin::Pin, ptr}; +use std::num::NonZeroUsize; use cryptoki_sys::{ CK_ATTRIBUTE, CK_ATTRIBUTE_PTR, CK_DERIVED_KEY, CK_DERIVED_KEY_PTR, CK_INVALID_HANDLE, @@ -42,10 +43,11 @@ impl KbkdfCounterFormat { /// * `endianness` - The endianness of the counter's bit representation. /// /// * `width_in_bits` - The number of bits used to represent the counter value. - pub fn new(endianness: Endianness, width_in_bits: usize) -> Self { + pub fn new(endianness: Endianness, width_in_bits: NonZeroUsize) -> Self { Self(CK_SP800_108_COUNTER_FORMAT { bLittleEndian: (endianness == Endianness::Little).into(), ulWidthInBits: width_in_bits + .get() .try_into() .expect("bit width of KBKDF internal counter does not fit in CK_ULONG"), }) @@ -83,7 +85,7 @@ impl KbkdfDkmLengthFormat { pub fn new( dkm_length_method: KbkdfDkmLengthMethod, endianness: Endianness, - width_in_bits: usize, + width_in_bits: NonZeroUsize, ) -> Self { Self(CK_SP800_108_DKM_LENGTH_FORMAT { dkmLengthMethod: match dkm_length_method { @@ -92,6 +94,7 @@ impl KbkdfDkmLengthFormat { }, bLittleEndian: (endianness == Endianness::Little).into(), ulWidthInBits: width_in_bits + .get() .try_into() .expect("bit width of KBKDF DKM length value does not fit in CK_ULONG"), }) From e34b4b627604b4e4a3b3180735fc40eb7fc6a010 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Tue, 22 Apr 2025 18:01:02 +0200 Subject: [PATCH 21/22] Split out tests for different modes of the SP800-108 KDF Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/tests/basic.rs | 589 +++++++++++++++++++++++++++++++++------- 1 file changed, 493 insertions(+), 96 deletions(-) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index f98a9e38..b243a892 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -2177,7 +2177,7 @@ fn ekdf_aes_cbc_encrypt_data() -> TestResult { #[test] #[serial] -fn kbkdf_all_modes() -> TestResult { +fn kbkdf_counter_mode() -> TestResult { /* SoftHSM does not support NIST SP800-108 KDF yet */ if is_softhsm() { return Ok(()); @@ -2210,11 +2210,12 @@ fn kbkdf_all_modes() -> TestResult { ]; // Some variables we will use throughout - let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); - let dkm_length_format = - KbkdfDkmLengthFormat::new(KbkdfDkmLengthMethod::SumOfKeys, Endianness::Big, 16); - - /* COUNTER-MODE */ + let counter_format = KbkdfCounterFormat::new(Endianness::Big, NonZeroUsize::new(16).unwrap()); + let dkm_length_format = KbkdfDkmLengthFormat::new( + KbkdfDkmLengthMethod::SumOfKeys, + Endianness::Big, + NonZeroUsize::new(16).unwrap(), + ); // Instantiate KBKDF in counter-mode without additional keys let data_params = [ @@ -2227,12 +2228,88 @@ fn kbkdf_all_modes() -> TestResult { let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); // Derive key - let derived_key_counter = session.derive_key( + let derived_key = session.derive_key( &Mechanism::KbkdfCounter(params), base_key, &derived_key_template, )?; + // Verify derive key matches template + let attributes_to_check = [ + AttributeType::Class, + AttributeType::KeyType, + AttributeType::ValueLen, + AttributeType::Encrypt, + AttributeType::Decrypt, + AttributeType::Sign, + AttributeType::Verify, + AttributeType::Derive, + ]; + let wanted_attributes = [ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + Attribute::Sign(false), + Attribute::Verify(false), + Attribute::Derive(false), + ]; + let have_attributes = session.get_attributes(derived_key, &attributes_to_check)?; + + for (value_wanted, value_have) in wanted_attributes.iter().zip(have_attributes.iter()) { + assert_eq!(value_wanted, value_have); + } + + // Delete keys + session.destroy_object(derived_key)?; + session.destroy_object(base_key)?; + + Ok(()) +} + +#[test] +#[serial] +fn kbkdf_feedback_mode() -> TestResult { + /* SoftHSM does not support NIST SP800-108 KDF yet */ + if is_softhsm() { + return Ok(()); + } + + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Generate base key + let base_template = [ + Attribute::Token(true), + Attribute::Private(false), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Derive(true), + ]; + let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; + + // The template of the key to derive + let derived_key_template = [ + Attribute::Token(false), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + ]; + + // Some variables we will use throughout + let counter_format = KbkdfCounterFormat::new(Endianness::Big, NonZeroUsize::new(16).unwrap()); + let dkm_length_format = KbkdfDkmLengthFormat::new( + KbkdfDkmLengthMethod::SumOfKeys, + Endianness::Big, + NonZeroUsize::new(16).unwrap(), + ); + /* FEEDBACK-MODE - no IV */ // Instantiate KBKDF in feedback-mode without additional keys or an IV @@ -2271,33 +2348,8 @@ fn kbkdf_all_modes() -> TestResult { &derived_key_template, )?; - /* DOUBLE PIPELINE-MODE */ - - /* FIXME: NIST SP800-108 in double-pipeline mode is not yet supported by SoftHSM or Kryoptic */ - if false { - // Instantiate KBKDF in feedback-mode without additional keys - let data_params = [ - PrfDataParam::new(PrfDataParamType::IterationVariable(None)), - PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), - ]; - let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); - - // Derive key - let _derived_key_double_pipeline = session.derive_key( - &Mechanism::KbkdfDoublePipeline(params), - base_key, - &derived_key_template, - )?; - } - - // Verify all derived keys match template - let derived_keys = [ - derived_key_counter, - derived_key_feedback_no_iv, - derived_key_feedback_iv, - /* FIXME: same reason as above */ - // derived_key_double_pipeline, - ]; + // Verify derived keys match template + let derived_keys = [derived_key_feedback_no_iv, derived_key_feedback_iv]; let attributes_to_check = [ AttributeType::Class, @@ -2339,7 +2391,92 @@ fn kbkdf_all_modes() -> TestResult { #[test] #[serial] -fn kbkdf_additional_keys_all_modes() -> TestResult { +#[ignore = "unsupported by both SoftHSM and Kryoptic for the moment"] +fn kbkdf_double_pipeline_mode() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Generate base key + let base_template = [ + Attribute::Token(true), + Attribute::Private(false), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Derive(true), + ]; + let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; + + // The template of the key to derive + let derived_key_template = [ + Attribute::Token(false), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + ]; + + // Some variables we will use throughout + let dkm_length_format = KbkdfDkmLengthFormat::new( + KbkdfDkmLengthMethod::SumOfKeys, + Endianness::Big, + NonZeroUsize::new(16).unwrap(), + ); + + // Instantiate KBKDF in feedback-mode without additional keys + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(None)), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let params = KbkdfParams::new(MechanismType::AES_CMAC, &data_params, None); + + // Derive key + let derived_key = session.derive_key( + &Mechanism::KbkdfDoublePipeline(params), + base_key, + &derived_key_template, + )?; + + // Verify derive key matches template + let attributes_to_check = [ + AttributeType::Class, + AttributeType::KeyType, + AttributeType::ValueLen, + AttributeType::Encrypt, + AttributeType::Decrypt, + AttributeType::Sign, + AttributeType::Verify, + AttributeType::Derive, + ]; + let wanted_attributes = [ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + Attribute::Sign(false), + Attribute::Verify(false), + Attribute::Derive(false), + ]; + let have_attributes = session.get_attributes(derived_key, &attributes_to_check)?; + + for (value_wanted, value_have) in wanted_attributes.iter().zip(have_attributes.iter()) { + assert_eq!(value_wanted, value_have); + } + + // Delete keys + session.destroy_object(derived_key)?; + session.destroy_object(base_key)?; + + Ok(()) +} + +#[test] +#[serial] +fn kbkdf_additional_keys_counter_mode() -> TestResult { /* SoftHSM does not support NIST SP800-108 KDF yet */ if is_softhsm() { return Ok(()); @@ -2391,17 +2528,12 @@ fn kbkdf_additional_keys_all_modes() -> TestResult { ]; // Some variables we will use throughout - let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); - let dkm_length_format = - KbkdfDkmLengthFormat::new(KbkdfDkmLengthMethod::SumOfKeys, Endianness::Big, 16); - let mut additional_derived_keys = derived_key_templates[1..] - .iter() - .map(|template| DerivedKey::new(template)) - .collect::>(); - - let mut derived_keys = vec![]; - - /* COUNTER-MODE */ + let counter_format = KbkdfCounterFormat::new(Endianness::Big, NonZeroUsize::new(16).unwrap()); + let dkm_length_format = KbkdfDkmLengthFormat::new( + KbkdfDkmLengthMethod::SumOfKeys, + Endianness::Big, + NonZeroUsize::new(16).unwrap(), + ); // Instantiate KBKDF in counter-mode without additional keys let data_params = [ @@ -2411,25 +2543,155 @@ fn kbkdf_additional_keys_all_modes() -> TestResult { PrfDataParam::new(PrfDataParamType::ByteArray(b"\xfe\xed\xbe\xef")), PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), ]; + let mut additional_derived_keys = derived_key_templates[1..] + .iter() + .map(|template| DerivedKey::new(template)) + .collect::>(); let params = KbkdfParams::new( MechanismType::AES_CMAC, &data_params, Some(&mut additional_derived_keys), ); - // Derive key - let main_derived_key_counter = session.derive_key( + let mut derived_keys = vec![]; + + // Derive all keys + let main_derived_key = session.derive_key( &Mechanism::KbkdfCounter(params), base_key, &derived_key_templates[0], )?; - let additional_derived_keys_counter = additional_derived_keys + let additional_derived_keys = additional_derived_keys .iter() .filter_map(|key| key.handle()) .collect::>(); - derived_keys.push(main_derived_key_counter); - derived_keys.extend(additional_derived_keys_counter); + derived_keys.push(main_derived_key); + derived_keys.extend(additional_derived_keys); + + // Verify all derived keys match template + let attributes_to_check = [ + AttributeType::Class, + AttributeType::KeyType, + AttributeType::ValueLen, + AttributeType::Encrypt, + AttributeType::Decrypt, + AttributeType::Sign, + AttributeType::Verify, + AttributeType::Derive, + ]; + let wanted_attributes = [ + vec![ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + Attribute::Sign(false), + Attribute::Verify(false), + Attribute::Derive(false), + ], + vec![ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES128_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(false), + Attribute::Decrypt(false), + Attribute::Sign(true), + Attribute::Verify(true), + Attribute::Derive(false), + ], + vec![ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::GENERIC_SECRET), + Attribute::ValueLen(1.into()), + Attribute::Encrypt(false), + Attribute::Decrypt(false), + Attribute::Sign(false), + Attribute::Verify(false), + Attribute::Derive(true), + ], + ]; + + for (key, wanted_attributes) in derived_keys.iter().zip(wanted_attributes.iter().cycle()) { + let have_attributes = session.get_attributes(*key, &attributes_to_check)?; + + for (value_wanted, value_have) in wanted_attributes.iter().zip(have_attributes.iter()) { + assert_eq!(value_wanted, value_have); + } + } + + // Delete all keys + for key in derived_keys { + session.destroy_object(key)?; + } + session.destroy_object(base_key)?; + + Ok(()) +} + +#[test] +#[serial] +fn kbkdf_additional_keys_feedback_mode() -> TestResult { + /* SoftHSM does not support NIST SP800-108 KDF yet */ + if is_softhsm() { + return Ok(()); + } + + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Generate base key + let base_template = [ + Attribute::Token(true), + Attribute::Private(false), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Derive(true), + ]; + let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; + + // The templates of the keys to derive. We supply more than one to test deriving additional keys + let derived_key_templates = [ + vec![ + Attribute::Token(false), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + ], + vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES128_BLOCK_SIZE as u64).into()), + Attribute::Sign(true), + Attribute::Verify(true), + ], + vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::GENERIC_SECRET), + Attribute::ValueLen(1.into()), + Attribute::Derive(true), + ], + ]; + + // Some variables we will use throughout + let counter_format = KbkdfCounterFormat::new(Endianness::Big, NonZeroUsize::new(16).unwrap()); + let dkm_length_format = KbkdfDkmLengthFormat::new( + KbkdfDkmLengthMethod::SumOfKeys, + Endianness::Big, + NonZeroUsize::new(16).unwrap(), + ); + + let mut derived_keys = vec![]; /* FEEDBACK-MODE - no IV */ @@ -2439,6 +2701,10 @@ fn kbkdf_additional_keys_all_modes() -> TestResult { PrfDataParam::new(PrfDataParamType::Counter(&counter_format)), PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), ]; + let mut additional_derived_keys = derived_key_templates[1..] + .iter() + .map(|template| DerivedKey::new(template)) + .collect::>(); let params = KbkdfFeedbackParams::new( MechanismType::AES_CMAC, &data_params, @@ -2446,19 +2712,19 @@ fn kbkdf_additional_keys_all_modes() -> TestResult { Some(&mut additional_derived_keys), ); - // Derive key - let main_derived_key_feedback_no_iv = session.derive_key( + // Derive all keys + let main_derived_key = session.derive_key( &Mechanism::KbkdfFeedback(params), base_key, &derived_key_templates[0], )?; - let additional_derived_keys_feedback_no_iv = additional_derived_keys + let additional_derived_keys = additional_derived_keys .iter() .filter_map(|key| key.handle()) .collect::>(); - derived_keys.push(main_derived_key_feedback_no_iv); - derived_keys.extend(additional_derived_keys_feedback_no_iv); + derived_keys.push(main_derived_key); + derived_keys.extend(additional_derived_keys); /* FEEDBACK-MODE - with IV */ @@ -2467,6 +2733,10 @@ fn kbkdf_additional_keys_all_modes() -> TestResult { PrfDataParam::new(PrfDataParamType::IterationVariable(None)), PrfDataParam::new(PrfDataParamType::Counter(&counter_format)), ]; + let mut additional_derived_keys = derived_key_templates[1..] + .iter() + .map(|template| DerivedKey::new(template)) + .collect::>(); let params = KbkdfFeedbackParams::new( MechanismType::AES_CMAC, &data_params, @@ -2474,49 +2744,167 @@ fn kbkdf_additional_keys_all_modes() -> TestResult { Some(&mut additional_derived_keys), ); - // Derive key - let main_derived_key_feedback_iv = session.derive_key( + // Derive all keys + let main_derived_key = session.derive_key( &Mechanism::KbkdfFeedback(params), base_key, &derived_key_templates[0], )?; - let additional_derived_keys_feedback_iv = additional_derived_keys + let additional_derived_keys = additional_derived_keys .iter() .filter_map(|key| key.handle()) .collect::>(); - derived_keys.push(main_derived_key_feedback_iv); - derived_keys.extend(additional_derived_keys_feedback_iv); + derived_keys.push(main_derived_key); + derived_keys.extend(additional_derived_keys); + + // Verify all derived keys match template + let attributes_to_check = [ + AttributeType::Class, + AttributeType::KeyType, + AttributeType::ValueLen, + AttributeType::Encrypt, + AttributeType::Decrypt, + AttributeType::Sign, + AttributeType::Verify, + AttributeType::Derive, + ]; + let wanted_attributes = [ + vec![ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + Attribute::Sign(false), + Attribute::Verify(false), + Attribute::Derive(false), + ], + vec![ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES128_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(false), + Attribute::Decrypt(false), + Attribute::Sign(true), + Attribute::Verify(true), + Attribute::Derive(false), + ], + vec![ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::GENERIC_SECRET), + Attribute::ValueLen(1.into()), + Attribute::Encrypt(false), + Attribute::Decrypt(false), + Attribute::Sign(false), + Attribute::Verify(false), + Attribute::Derive(true), + ], + ]; - /* DOUBLE PIPELINE-MODE */ + for (key, wanted_attributes) in derived_keys.iter().zip(wanted_attributes.iter().cycle()) { + let have_attributes = session.get_attributes(*key, &attributes_to_check)?; - /* FIXME: NIST SP800-108 in double-pipeline mode is not yet supported by SoftHSM or Kryoptic */ - if false { - // Instantiate KBKDF in feedback-mode without additional keys - let data_params = [ - PrfDataParam::new(PrfDataParamType::IterationVariable(None)), - PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), - ]; - let params = KbkdfParams::new( - MechanismType::AES_CMAC, - &data_params, - Some(&mut additional_derived_keys), - ); + for (value_wanted, value_have) in wanted_attributes.iter().zip(have_attributes.iter()) { + assert_eq!(value_wanted, value_have); + } + } - // Derive key - let main_derived_key_double_pipeline = session.derive_key( - &Mechanism::KbkdfDoublePipeline(params), - base_key, - &derived_key_templates[0], - )?; - let additional_derived_keys_double_pipeline = additional_derived_keys - .iter() - .filter_map(|key| key.handle()) - .collect::>(); - - derived_keys.push(main_derived_key_double_pipeline); - derived_keys.extend(additional_derived_keys_double_pipeline); + // Delete all keys + for key in derived_keys { + session.destroy_object(key)?; } + session.destroy_object(base_key)?; + + Ok(()) +} + +#[test] +#[serial] +#[ignore = "unsupported by both SoftHSM and Kryoptic for the moment"] +fn kbkdf_additional_keys_double_pipeline_mode() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Generate base key + let base_template = [ + Attribute::Token(true), + Attribute::Private(false), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Derive(true), + ]; + let base_key = session.generate_key(&Mechanism::AesKeyGen, &base_template)?; + + // The templates of the keys to derive. We supply more than one to test deriving additional keys + let derived_key_templates = [ + vec![ + Attribute::Token(false), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES256_BLOCK_SIZE as u64).into()), + Attribute::Encrypt(true), + Attribute::Decrypt(true), + ], + vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::ValueLen((AES128_BLOCK_SIZE as u64).into()), + Attribute::Sign(true), + Attribute::Verify(true), + ], + vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::GENERIC_SECRET), + Attribute::ValueLen(1.into()), + Attribute::Derive(true), + ], + ]; + + // Some variables we will use throughout + let dkm_length_format = KbkdfDkmLengthFormat::new( + KbkdfDkmLengthMethod::SumOfKeys, + Endianness::Big, + NonZeroUsize::new(16).unwrap(), + ); + + // Instantiate KBKDF in feedback-mode without additional keys + let data_params = [ + PrfDataParam::new(PrfDataParamType::IterationVariable(None)), + PrfDataParam::new(PrfDataParamType::DkmLength(&dkm_length_format)), + ]; + let mut additional_derived_keys = derived_key_templates[1..] + .iter() + .map(|template| DerivedKey::new(template)) + .collect::>(); + let params = KbkdfParams::new( + MechanismType::AES_CMAC, + &data_params, + Some(&mut additional_derived_keys), + ); + + let mut derived_keys = vec![]; + + // Derive all keys + let main_derived_key = session.derive_key( + &Mechanism::KbkdfDoublePipeline(params), + base_key, + &derived_key_templates[0], + )?; + let additional_derived_keys = additional_derived_keys + .iter() + .filter_map(|key| key.handle()) + .collect::>(); + + derived_keys.push(main_derived_key); + derived_keys.extend(additional_derived_keys); // Verify all derived keys match template let attributes_to_check = [ @@ -2614,9 +3002,12 @@ fn kbkdf_invalid_data_params_counter_mode() -> TestResult { ]; // Some variables we will use throughout - let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); - let dkm_length_format = - KbkdfDkmLengthFormat::new(KbkdfDkmLengthMethod::SumOfKeys, Endianness::Big, 16); + let counter_format = KbkdfCounterFormat::new(Endianness::Big, NonZeroUsize::new(16).unwrap()); + let dkm_length_format = KbkdfDkmLengthFormat::new( + KbkdfDkmLengthMethod::SumOfKeys, + Endianness::Big, + NonZeroUsize::new(16).unwrap(), + ); /* MISSING ITERATION VARIABLE */ @@ -2760,9 +3151,12 @@ fn kbkdf_invalid_data_params_feedback_mode() -> TestResult { ]; // Some variables we will use throughout - let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); - let dkm_length_format = - KbkdfDkmLengthFormat::new(KbkdfDkmLengthMethod::SumOfKeys, Endianness::Big, 16); + let counter_format = KbkdfCounterFormat::new(Endianness::Big, NonZeroUsize::new(16).unwrap()); + let dkm_length_format = KbkdfDkmLengthFormat::new( + KbkdfDkmLengthMethod::SumOfKeys, + Endianness::Big, + NonZeroUsize::new(16).unwrap(), + ); /* MISSING ITERATION VARIABLE */ @@ -2880,9 +3274,12 @@ fn kbkdf_invalid_data_params_double_pipeline_mode() -> TestResult { ]; // Some variables we will use throughout - let counter_format = KbkdfCounterFormat::new(Endianness::Big, 16); - let dkm_length_format = - KbkdfDkmLengthFormat::new(KbkdfDkmLengthMethod::SumOfKeys, Endianness::Big, 16); + let counter_format = KbkdfCounterFormat::new(Endianness::Big, NonZeroUsize::new(16).unwrap()); + let dkm_length_format = KbkdfDkmLengthFormat::new( + KbkdfDkmLengthMethod::SumOfKeys, + Endianness::Big, + NonZeroUsize::new(16).unwrap(), + ); /* MISSING ITERATION VARIABLE */ From bea29ba5bab8e5b70e009b3b004c44c99ec6847d Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Tue, 22 Apr 2025 18:03:55 +0200 Subject: [PATCH 22/22] Added mutability marker to `PhantomData` sitting inside KDF params, to indicate necessity of mutability Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/mechanism/kbkdf.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cryptoki/src/mechanism/kbkdf.rs b/cryptoki/src/mechanism/kbkdf.rs index c1c1a9c8..84c300c3 100644 --- a/cryptoki/src/mechanism/kbkdf.rs +++ b/cryptoki/src/mechanism/kbkdf.rs @@ -236,7 +236,7 @@ pub struct KbkdfParams<'a> { inner: CK_SP800_108_KDF_PARAMS, /// Marker type to ensure we don't outlive the data - _marker: PhantomData<&'a [u8]>, + _marker: PhantomData<&'a mut [u8]>, } impl<'a> KbkdfParams<'a> { @@ -305,7 +305,7 @@ pub struct KbkdfFeedbackParams<'a> { inner: CK_SP800_108_FEEDBACK_KDF_PARAMS, /// Marker type to ensure we don't outlive the data - _marker: PhantomData<&'a [u8]>, + _marker: PhantomData<&'a mut [u8]>, } impl<'a> KbkdfFeedbackParams<'a> {