Skip to content

Commit

Permalink
Merge pull request #227 from Direktor799/main
Browse files Browse the repository at this point in the history
feat: add HKDF mechanisms
  • Loading branch information
hug-dev authored Oct 23, 2024
2 parents 89235a6 + ed6e72e commit 9e3f1b6
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 1 deletion.
121 changes: 121 additions & 0 deletions cryptoki/src/mechanism/hkdf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright 2024 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! Mechanisms of hash-based key derive function (HKDF)
//! See: <https://docs.oasis-open.org/pkcs11/pkcs11-curr/v3.0/os/pkcs11-curr-v3.0-os.html#_Toc30061597>
use std::{convert::TryInto, marker::PhantomData, ptr::null_mut, slice};

use cryptoki_sys::{CKF_HKDF_SALT_DATA, CKF_HKDF_SALT_KEY, CKF_HKDF_SALT_NULL};

use crate::object::ObjectHandle;

use super::MechanismType;

/// The salt for the extract stage.
#[derive(Debug, Clone, Copy)]
pub enum HkdfSalt<'a> {
/// CKF_HKDF_SALT_NULL no salt is supplied.
Null,
/// CKF_HKDF_SALT_DATA salt is supplied as a data in pSalt with length ulSaltLen.
Data(&'a [u8]),
/// CKF_HKDF_SALT_KEY salt is supplied as a key in hSaltKey
Key(ObjectHandle),
}

/// HKDF parameters.
///
/// This structure wraps a `CK_HKDF_PARAMS` structure.
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct HkdfParams<'a> {
inner: cryptoki_sys::CK_HKDF_PARAMS,
/// Marker type to ensure we don't outlive the data
_marker: PhantomData<&'a [u8]>,
}

impl<'a> HkdfParams<'a> {
/// Construct parameters for hash-based key derive function (HKDF).
///
/// # Arguments
///
/// * `prf_hash_mechanism` - The base hash used for the HMAC in the underlying HKDF operation
///
/// * `salt` - The salt for the extract stage, skip extract if `None`.
///
/// * `info` - The info string for the expand stage, skip expand if `None`.
pub fn new(
prf_hash_mechanism: MechanismType,
salt: Option<HkdfSalt>,
info: Option<&'a [u8]>,
) -> Self {
Self {
inner: cryptoki_sys::CK_HKDF_PARAMS {
bExtract: salt.is_some() as u8,
bExpand: info.is_some() as u8,
prfHashMechanism: *prf_hash_mechanism,
ulSaltType: match salt {
None | Some(HkdfSalt::Null) => CKF_HKDF_SALT_NULL,
Some(HkdfSalt::Data(_)) => CKF_HKDF_SALT_DATA,
Some(HkdfSalt::Key(_)) => CKF_HKDF_SALT_KEY,
},
pSalt: if let Some(HkdfSalt::Data(data)) = salt {
data.as_ptr() as *mut _
} else {
null_mut()
},
ulSaltLen: if let Some(HkdfSalt::Data(data)) = salt {
data.len()
.try_into()
.expect("salt length does not fit in CK_ULONG")
} else {
0
},
hSaltKey: if let Some(HkdfSalt::Key(key)) = salt {
key.handle()
} else {
0
},
pInfo: if let Some(info) = info {
info.as_ptr() as *mut _
} else {
null_mut()
},
ulInfoLen: if let Some(info) = info {
info.len()
.try_into()
.expect("salt length does not fit in CK_ULONG")
} else {
0
},
},
_marker: PhantomData,
}
}

/// Whether to execute the extract portion of HKDF.
pub fn extract(&self) -> bool {
self.inner.bExtract != 0
}

/// Whether to execute the expand portion of HKDF.
pub fn expand(&self) -> bool {
self.inner.bExpand != 0
}

/// The salt for the extract stage.
pub fn salt(&self) -> HkdfSalt<'a> {
match self.inner.ulSaltType {
CKF_HKDF_SALT_NULL => HkdfSalt::Null,
CKF_HKDF_SALT_DATA => HkdfSalt::Data(unsafe {
slice::from_raw_parts(self.inner.pSalt, self.inner.ulSaltLen as _)
}),
CKF_HKDF_SALT_KEY => HkdfSalt::Key(ObjectHandle::new(self.inner.hSaltKey)),
_ => unreachable!(),
}
}

/// The info string for the expand stage.
pub fn info(&self) -> &'a [u8] {
unsafe { slice::from_raw_parts(self.inner.pInfo, self.inner.ulInfoLen as _) }
}
}
37 changes: 36 additions & 1 deletion cryptoki/src/mechanism/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
pub mod aead;
pub mod ekdf;
pub mod elliptic_curve;
pub mod hkdf;
mod mechanism_info;
pub mod rsa;

Expand Down Expand Up @@ -285,6 +286,18 @@ impl MechanismType {
val: CKM_GENERIC_SECRET_KEY_GEN,
};

// HKDF
/// HKDF key generation mechanism
pub const HKDF_KEY_GEN: MechanismType = MechanismType {
val: CKM_HKDF_KEY_GEN,
};
/// HKDF-DERIVE mechanism
pub const HKDF_DERIVE: MechanismType = MechanismType {
val: CKM_HKDF_DERIVE,
};
/// HKDF-DATA mechanism
pub const HKDF_DATA: MechanismType = MechanismType { val: CKM_HKDF_DATA };

pub(crate) fn stringify(mech: CK_MECHANISM_TYPE) -> String {
match mech {
CKM_RSA_PKCS_KEY_PAIR_GEN => String::from(stringify!(CKM_RSA_PKCS_KEY_PAIR_GEN)),
Expand Down Expand Up @@ -641,6 +654,9 @@ impl MechanismType {
String::from(stringify!(CKM_EC_MONTGOMERY_KEY_PAIR_GEN))
}
CKM_EDDSA => String::from(stringify!(CKM_EDDSA)),
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)),
_ => format!("unknown {mech:08x}"),
}
}
Expand Down Expand Up @@ -717,6 +733,9 @@ impl TryFrom<CK_MECHANISM_TYPE> for MechanismType {
CKM_SHA384_HMAC => Ok(MechanismType::SHA384_HMAC),
CKM_SHA512_HMAC => Ok(MechanismType::SHA512_HMAC),
CKM_GENERIC_SECRET_KEY_GEN => Ok(MechanismType::GENERIC_SECRET_KEY_GEN),
CKM_HKDF_KEY_GEN => Ok(MechanismType::HKDF_KEY_GEN),
CKM_HKDF_DERIVE => Ok(MechanismType::HKDF_DERIVE),
CKM_HKDF_DATA => Ok(MechanismType::HKDF_DATA),
other => {
error!("Mechanism type {} is not supported.", other);
Err(Error::NotSupported)
Expand Down Expand Up @@ -910,6 +929,14 @@ pub enum Mechanism<'a> {

/// GENERIC-SECRET-KEY-GEN mechanism
GenericSecretKeyGen,

// HKDF
/// HKDF key gen mechanism
HkdfKeyGen,
/// HKDF-DERIVE mechanism
HkdfDerive(hkdf::HkdfParams<'a>),
/// HKDF-DATA mechanism
HkdfData(hkdf::HkdfParams<'a>),
}

impl Mechanism<'_> {
Expand Down Expand Up @@ -977,6 +1004,10 @@ impl Mechanism<'_> {
Mechanism::Sha512Hmac => MechanismType::SHA512_HMAC,

Mechanism::GenericSecretKeyGen => MechanismType::GENERIC_SECRET_KEY_GEN,

Mechanism::HkdfKeyGen => MechanismType::HKDF_KEY_GEN,
Mechanism::HkdfDerive(_) => MechanismType::HKDF_DERIVE,
Mechanism::HkdfData(_) => MechanismType::HKDF_DATA,
}
}
}
Expand Down Expand Up @@ -1008,6 +1039,9 @@ impl From<&Mechanism<'_>> for CK_MECHANISM {
| Mechanism::Sha512RsaPkcsPss(params) => make_mechanism(mechanism, params),
Mechanism::RsaPkcsOaep(params) => make_mechanism(mechanism, params),
Mechanism::Ecdh1Derive(params) => make_mechanism(mechanism, params),
Mechanism::HkdfDerive(params) | Mechanism::HkdfData(params) => {
make_mechanism(mechanism, params)
}
// Mechanisms without parameters
Mechanism::AesKeyGen
| Mechanism::AesEcb
Expand Down Expand Up @@ -1047,7 +1081,8 @@ impl From<&Mechanism<'_>> for CK_MECHANISM {
| Mechanism::Sha256Hmac
| Mechanism::Sha384Hmac
| Mechanism::Sha512Hmac
| Mechanism::GenericSecretKeyGen => CK_MECHANISM {
| Mechanism::GenericSecretKeyGen
| Mechanism::HkdfKeyGen => CK_MECHANISM {
mechanism,
pParameter: null_mut(),
ulParameterLen: 0,
Expand Down
6 changes: 6 additions & 0 deletions cryptoki/src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,9 @@ impl KeyType {
val: CKK_EC_MONTGOMERY,
};

/// HKDF key
pub const HKDF: KeyType = KeyType { val: CKK_HKDF };

fn stringify(key_type: CK_KEY_TYPE) -> String {
match key_type {
CKK_RSA => String::from(stringify!(CKK_RSA)),
Expand Down Expand Up @@ -1236,6 +1239,8 @@ impl KeyType {
CKK_GOSTR3411 => String::from(stringify!(CKK_GOSTR3411)),
CKK_GOST28147 => String::from(stringify!(CKK_GOST28147)),
CKK_EC_EDWARDS => String::from(stringify!(CKK_EC_EDWARDS)),
CKK_EC_MONTGOMERY => String::from(stringify!(CKK_EC_MONTGOMERY)),
CKK_HKDF => String::from(stringify!(CKK_HKDF)),
_ => format!("unknown ({key_type:08x})"),
}
}
Expand Down Expand Up @@ -1309,6 +1314,7 @@ impl TryFrom<CK_KEY_TYPE> for KeyType {
CKK_GOST28147 => Ok(KeyType::GOST28147),
CKK_EC_EDWARDS => Ok(KeyType::EC_EDWARDS),
CKK_EC_MONTGOMERY => Ok(KeyType::EC_MONTGOMERY),
CKK_HKDF => Ok(KeyType::HKDF),
_ => {
error!("Key type {} is not supported.", key_type);
Err(Error::NotSupported)
Expand Down

0 comments on commit 9e3f1b6

Please sign in to comment.