Skip to content

Commit 9e3f1b6

Browse files
authored
Merge pull request #227 from Direktor799/main
feat: add HKDF mechanisms
2 parents 89235a6 + ed6e72e commit 9e3f1b6

File tree

3 files changed

+163
-1
lines changed

3 files changed

+163
-1
lines changed

cryptoki/src/mechanism/hkdf.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// Copyright 2024 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
//! Mechanisms of hash-based key derive function (HKDF)
4+
//! See: <https://docs.oasis-open.org/pkcs11/pkcs11-curr/v3.0/os/pkcs11-curr-v3.0-os.html#_Toc30061597>
5+
6+
use std::{convert::TryInto, marker::PhantomData, ptr::null_mut, slice};
7+
8+
use cryptoki_sys::{CKF_HKDF_SALT_DATA, CKF_HKDF_SALT_KEY, CKF_HKDF_SALT_NULL};
9+
10+
use crate::object::ObjectHandle;
11+
12+
use super::MechanismType;
13+
14+
/// The salt for the extract stage.
15+
#[derive(Debug, Clone, Copy)]
16+
pub enum HkdfSalt<'a> {
17+
/// CKF_HKDF_SALT_NULL no salt is supplied.
18+
Null,
19+
/// CKF_HKDF_SALT_DATA salt is supplied as a data in pSalt with length ulSaltLen.
20+
Data(&'a [u8]),
21+
/// CKF_HKDF_SALT_KEY salt is supplied as a key in hSaltKey
22+
Key(ObjectHandle),
23+
}
24+
25+
/// HKDF parameters.
26+
///
27+
/// This structure wraps a `CK_HKDF_PARAMS` structure.
28+
#[derive(Debug, Clone, Copy)]
29+
#[repr(transparent)]
30+
pub struct HkdfParams<'a> {
31+
inner: cryptoki_sys::CK_HKDF_PARAMS,
32+
/// Marker type to ensure we don't outlive the data
33+
_marker: PhantomData<&'a [u8]>,
34+
}
35+
36+
impl<'a> HkdfParams<'a> {
37+
/// Construct parameters for hash-based key derive function (HKDF).
38+
///
39+
/// # Arguments
40+
///
41+
/// * `prf_hash_mechanism` - The base hash used for the HMAC in the underlying HKDF operation
42+
///
43+
/// * `salt` - The salt for the extract stage, skip extract if `None`.
44+
///
45+
/// * `info` - The info string for the expand stage, skip expand if `None`.
46+
pub fn new(
47+
prf_hash_mechanism: MechanismType,
48+
salt: Option<HkdfSalt>,
49+
info: Option<&'a [u8]>,
50+
) -> Self {
51+
Self {
52+
inner: cryptoki_sys::CK_HKDF_PARAMS {
53+
bExtract: salt.is_some() as u8,
54+
bExpand: info.is_some() as u8,
55+
prfHashMechanism: *prf_hash_mechanism,
56+
ulSaltType: match salt {
57+
None | Some(HkdfSalt::Null) => CKF_HKDF_SALT_NULL,
58+
Some(HkdfSalt::Data(_)) => CKF_HKDF_SALT_DATA,
59+
Some(HkdfSalt::Key(_)) => CKF_HKDF_SALT_KEY,
60+
},
61+
pSalt: if let Some(HkdfSalt::Data(data)) = salt {
62+
data.as_ptr() as *mut _
63+
} else {
64+
null_mut()
65+
},
66+
ulSaltLen: if let Some(HkdfSalt::Data(data)) = salt {
67+
data.len()
68+
.try_into()
69+
.expect("salt length does not fit in CK_ULONG")
70+
} else {
71+
0
72+
},
73+
hSaltKey: if let Some(HkdfSalt::Key(key)) = salt {
74+
key.handle()
75+
} else {
76+
0
77+
},
78+
pInfo: if let Some(info) = info {
79+
info.as_ptr() as *mut _
80+
} else {
81+
null_mut()
82+
},
83+
ulInfoLen: if let Some(info) = info {
84+
info.len()
85+
.try_into()
86+
.expect("salt length does not fit in CK_ULONG")
87+
} else {
88+
0
89+
},
90+
},
91+
_marker: PhantomData,
92+
}
93+
}
94+
95+
/// Whether to execute the extract portion of HKDF.
96+
pub fn extract(&self) -> bool {
97+
self.inner.bExtract != 0
98+
}
99+
100+
/// Whether to execute the expand portion of HKDF.
101+
pub fn expand(&self) -> bool {
102+
self.inner.bExpand != 0
103+
}
104+
105+
/// The salt for the extract stage.
106+
pub fn salt(&self) -> HkdfSalt<'a> {
107+
match self.inner.ulSaltType {
108+
CKF_HKDF_SALT_NULL => HkdfSalt::Null,
109+
CKF_HKDF_SALT_DATA => HkdfSalt::Data(unsafe {
110+
slice::from_raw_parts(self.inner.pSalt, self.inner.ulSaltLen as _)
111+
}),
112+
CKF_HKDF_SALT_KEY => HkdfSalt::Key(ObjectHandle::new(self.inner.hSaltKey)),
113+
_ => unreachable!(),
114+
}
115+
}
116+
117+
/// The info string for the expand stage.
118+
pub fn info(&self) -> &'a [u8] {
119+
unsafe { slice::from_raw_parts(self.inner.pInfo, self.inner.ulInfoLen as _) }
120+
}
121+
}

cryptoki/src/mechanism/mod.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
pub mod aead;
66
pub mod ekdf;
77
pub mod elliptic_curve;
8+
pub mod hkdf;
89
mod mechanism_info;
910
pub mod rsa;
1011

@@ -285,6 +286,18 @@ impl MechanismType {
285286
val: CKM_GENERIC_SECRET_KEY_GEN,
286287
};
287288

289+
// HKDF
290+
/// HKDF key generation mechanism
291+
pub const HKDF_KEY_GEN: MechanismType = MechanismType {
292+
val: CKM_HKDF_KEY_GEN,
293+
};
294+
/// HKDF-DERIVE mechanism
295+
pub const HKDF_DERIVE: MechanismType = MechanismType {
296+
val: CKM_HKDF_DERIVE,
297+
};
298+
/// HKDF-DATA mechanism
299+
pub const HKDF_DATA: MechanismType = MechanismType { val: CKM_HKDF_DATA };
300+
288301
pub(crate) fn stringify(mech: CK_MECHANISM_TYPE) -> String {
289302
match mech {
290303
CKM_RSA_PKCS_KEY_PAIR_GEN => String::from(stringify!(CKM_RSA_PKCS_KEY_PAIR_GEN)),
@@ -641,6 +654,9 @@ impl MechanismType {
641654
String::from(stringify!(CKM_EC_MONTGOMERY_KEY_PAIR_GEN))
642655
}
643656
CKM_EDDSA => String::from(stringify!(CKM_EDDSA)),
657+
CKM_HKDF_KEY_GEN => String::from(stringify!(CKM_HKDF_KEY_GEN)),
658+
CKM_HKDF_DERIVE => String::from(stringify!(CKM_HKDF_DERIVE)),
659+
CKM_HKDF_DATA => String::from(stringify!(CKM_HKDF_DATA)),
644660
_ => format!("unknown {mech:08x}"),
645661
}
646662
}
@@ -717,6 +733,9 @@ impl TryFrom<CK_MECHANISM_TYPE> for MechanismType {
717733
CKM_SHA384_HMAC => Ok(MechanismType::SHA384_HMAC),
718734
CKM_SHA512_HMAC => Ok(MechanismType::SHA512_HMAC),
719735
CKM_GENERIC_SECRET_KEY_GEN => Ok(MechanismType::GENERIC_SECRET_KEY_GEN),
736+
CKM_HKDF_KEY_GEN => Ok(MechanismType::HKDF_KEY_GEN),
737+
CKM_HKDF_DERIVE => Ok(MechanismType::HKDF_DERIVE),
738+
CKM_HKDF_DATA => Ok(MechanismType::HKDF_DATA),
720739
other => {
721740
error!("Mechanism type {} is not supported.", other);
722741
Err(Error::NotSupported)
@@ -910,6 +929,14 @@ pub enum Mechanism<'a> {
910929

911930
/// GENERIC-SECRET-KEY-GEN mechanism
912931
GenericSecretKeyGen,
932+
933+
// HKDF
934+
/// HKDF key gen mechanism
935+
HkdfKeyGen,
936+
/// HKDF-DERIVE mechanism
937+
HkdfDerive(hkdf::HkdfParams<'a>),
938+
/// HKDF-DATA mechanism
939+
HkdfData(hkdf::HkdfParams<'a>),
913940
}
914941

915942
impl Mechanism<'_> {
@@ -977,6 +1004,10 @@ impl Mechanism<'_> {
9771004
Mechanism::Sha512Hmac => MechanismType::SHA512_HMAC,
9781005

9791006
Mechanism::GenericSecretKeyGen => MechanismType::GENERIC_SECRET_KEY_GEN,
1007+
1008+
Mechanism::HkdfKeyGen => MechanismType::HKDF_KEY_GEN,
1009+
Mechanism::HkdfDerive(_) => MechanismType::HKDF_DERIVE,
1010+
Mechanism::HkdfData(_) => MechanismType::HKDF_DATA,
9801011
}
9811012
}
9821013
}
@@ -1008,6 +1039,9 @@ impl From<&Mechanism<'_>> for CK_MECHANISM {
10081039
| Mechanism::Sha512RsaPkcsPss(params) => make_mechanism(mechanism, params),
10091040
Mechanism::RsaPkcsOaep(params) => make_mechanism(mechanism, params),
10101041
Mechanism::Ecdh1Derive(params) => make_mechanism(mechanism, params),
1042+
Mechanism::HkdfDerive(params) | Mechanism::HkdfData(params) => {
1043+
make_mechanism(mechanism, params)
1044+
}
10111045
// Mechanisms without parameters
10121046
Mechanism::AesKeyGen
10131047
| Mechanism::AesEcb
@@ -1047,7 +1081,8 @@ impl From<&Mechanism<'_>> for CK_MECHANISM {
10471081
| Mechanism::Sha256Hmac
10481082
| Mechanism::Sha384Hmac
10491083
| Mechanism::Sha512Hmac
1050-
| Mechanism::GenericSecretKeyGen => CK_MECHANISM {
1084+
| Mechanism::GenericSecretKeyGen
1085+
| Mechanism::HkdfKeyGen => CK_MECHANISM {
10511086
mechanism,
10521087
pParameter: null_mut(),
10531088
ulParameterLen: 0,

cryptoki/src/object.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,9 @@ impl KeyType {
11921192
val: CKK_EC_MONTGOMERY,
11931193
};
11941194

1195+
/// HKDF key
1196+
pub const HKDF: KeyType = KeyType { val: CKK_HKDF };
1197+
11951198
fn stringify(key_type: CK_KEY_TYPE) -> String {
11961199
match key_type {
11971200
CKK_RSA => String::from(stringify!(CKK_RSA)),
@@ -1236,6 +1239,8 @@ impl KeyType {
12361239
CKK_GOSTR3411 => String::from(stringify!(CKK_GOSTR3411)),
12371240
CKK_GOST28147 => String::from(stringify!(CKK_GOST28147)),
12381241
CKK_EC_EDWARDS => String::from(stringify!(CKK_EC_EDWARDS)),
1242+
CKK_EC_MONTGOMERY => String::from(stringify!(CKK_EC_MONTGOMERY)),
1243+
CKK_HKDF => String::from(stringify!(CKK_HKDF)),
12391244
_ => format!("unknown ({key_type:08x})"),
12401245
}
12411246
}
@@ -1309,6 +1314,7 @@ impl TryFrom<CK_KEY_TYPE> for KeyType {
13091314
CKK_GOST28147 => Ok(KeyType::GOST28147),
13101315
CKK_EC_EDWARDS => Ok(KeyType::EC_EDWARDS),
13111316
CKK_EC_MONTGOMERY => Ok(KeyType::EC_MONTGOMERY),
1317+
CKK_HKDF => Ok(KeyType::HKDF),
13121318
_ => {
13131319
error!("Key type {} is not supported.", key_type);
13141320
Err(Error::NotSupported)

0 commit comments

Comments
 (0)