Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add secret key generation and key wrapping functions #38

Merged
merged 7 commits into from
Sep 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions cryptoki/src/functions/key_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,29 @@ use cryptoki_sys::{CK_ATTRIBUTE, CK_MECHANISM, CK_MECHANISM_PTR};
use std::convert::TryInto;

impl<'a> Session<'a> {
/// Generate a secret key
pub fn generate_key(
&self,
mechanism: &Mechanism,
template: &[Attribute],
) -> Result<ObjectHandle> {
let mut mechanism: CK_MECHANISM = mechanism.into();
let mut template: Vec<CK_ATTRIBUTE> = template.iter().map(|attr| attr.into()).collect();
let mut handle = 0;
unsafe {
Rv::from(get_pkcs11!(self.client(), C_GenerateKey)(
self.handle(),
&mut mechanism as CK_MECHANISM_PTR,
template.as_mut_ptr(),
template.len().try_into()?,
&mut handle,
))
.into_result()?;
}

Ok(ObjectHandle::new(handle))
}

/// Generate a public/private key pair
pub fn generate_key_pair(
&self,
Expand Down Expand Up @@ -70,4 +93,69 @@ impl<'a> Session<'a> {

Ok(ObjectHandle::new(handle))
}

/// Wrap key
pub fn wrap_key(
&self,
mechanism: &Mechanism,
wrapping_key: ObjectHandle,
key: ObjectHandle,
) -> Result<Vec<u8>> {
let mut mechanism: CK_MECHANISM = mechanism.into();
unsafe {
let mut wrapped_key_len = 0;

Rv::from(get_pkcs11!(self.client(), C_WrapKey)(
self.handle(),
&mut mechanism as CK_MECHANISM_PTR,
wrapping_key.handle(),
key.handle(),
std::ptr::null_mut(),
&mut wrapped_key_len,
))
.into_result()?;

let mut wrapped_key = vec![0; wrapped_key_len.try_into()?];

Rv::from(get_pkcs11!(self.client(), C_WrapKey)(
self.handle(),
&mut mechanism as CK_MECHANISM_PTR,
wrapping_key.handle(),
key.handle(),
wrapped_key.as_mut_ptr(),
&mut wrapped_key_len,
))
.into_result()?;

Ok(wrapped_key)
}
}

/// Unwrap previously wrapped key
pub fn unwrap_key(
&self,
mechanism: &Mechanism,
unwrapping_key: ObjectHandle,
wrapped_key: &[u8],
template: &[Attribute],
) -> Result<ObjectHandle> {
let mut mechanism: CK_MECHANISM = mechanism.into();
let mut template: Vec<CK_ATTRIBUTE> = template.iter().map(|attr| attr.into()).collect();
let mut handle = 0;
unsafe {
Rv::from(get_pkcs11!(self.client(), C_UnwrapKey)(
self.handle(),
&mut mechanism as CK_MECHANISM_PTR,
unwrapping_key.handle(),
wrapped_key.as_ptr() as *mut u8,
wrapped_key.len().try_into()?,
template.as_mut_ptr(),
template.len().try_into()?,
&mut handle,
))
.into_result()?;
}

Ok(ObjectHandle::new(handle))
}
}
23 changes: 23 additions & 0 deletions cryptoki/src/types/mechanism/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ impl MechanismType {
val: CKM_RSA_PKCS_OAEP,
};

// DES
/// DES3
/// Note that DES3 is deprecated. See https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf section 2, p. 6.
pub const DES3_KEY_GEN: MechanismType = MechanismType {
val: CKM_DES3_KEY_GEN,
};
/// DES3 ECB
/// Note that DES3 is deprecated. See https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf section 2, p. 6.
pub const DES3_ECB: MechanismType = MechanismType { val: CKM_DES3_ECB };

// ECC
/// EC key pair generation mechanism
pub const ECC_KEY_PAIR_GEN: MechanismType = MechanismType {
Expand Down Expand Up @@ -117,6 +127,8 @@ impl TryFrom<CK_MECHANISM_TYPE> for MechanismType {
CKM_SHA256 => Ok(MechanismType::SHA256),
CKM_SHA384 => Ok(MechanismType::SHA384),
CKM_SHA512 => Ok(MechanismType::SHA512),
CKM_DES3_KEY_GEN => Ok(MechanismType::DES3_KEY_GEN),
CKM_DES3_ECB => Ok(MechanismType::DES3_ECB),
CKM_EC_KEY_PAIR_GEN => Ok(MechanismType::ECC_KEY_PAIR_GEN),
CKM_EC_EDWARDS_KEY_PAIR_GEN => Ok(MechanismType::ECC_EDWARDS_KEY_PAIR_GEN),
CKM_EC_MONTGOMERY_KEY_PAIR_GEN => Ok(MechanismType::ECC_MONTGOMERY_KEY_PAIR_GEN),
Expand Down Expand Up @@ -150,6 +162,12 @@ pub enum Mechanism {
/// defined in PKCS #1
RsaPkcsOaep(rsa::PkcsOaepParams),

// DES
/// DES3
Des3KeyGen,
/// DES3 ECB
Des3Ecb,

// ECC
/// EC key pair generation
EccKeyPairGen,
Expand Down Expand Up @@ -190,6 +208,9 @@ impl Mechanism {
Mechanism::RsaPkcsPss(_) => MechanismType::RSA_PKCS_PSS,
Mechanism::RsaPkcsOaep(_) => MechanismType::RSA_PKCS_OAEP,

Mechanism::Des3KeyGen => MechanismType::DES3_KEY_GEN,
Mechanism::Des3Ecb => MechanismType::DES3_ECB,

Mechanism::EccKeyPairGen => MechanismType::ECC_KEY_PAIR_GEN,
Mechanism::EccEdwardsKeyPairGen => MechanismType::ECC_EDWARDS_KEY_PAIR_GEN,
Mechanism::EccMontgomeryKeyPairGen => MechanismType::ECC_MONTGOMERY_KEY_PAIR_GEN,
Expand Down Expand Up @@ -240,6 +261,8 @@ impl From<&Mechanism> for CK_MECHANISM {
| Mechanism::Sha256
| Mechanism::Sha384
| Mechanism::Sha512
| Mechanism::Des3KeyGen
| Mechanism::Des3Ecb
| Mechanism::EccKeyPairGen
| Mechanism::EccEdwardsKeyPairGen
| Mechanism::EccMontgomeryKeyPairGen
Expand Down
4 changes: 4 additions & 0 deletions cryptoki/src/types/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,9 @@ impl KeyType {
pub const GENERIC_SECRET: KeyType = KeyType {
val: CKK_GENERIC_SECRET,
};
/// DES3 secret
/// Note that DES3 is deprecated. See https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf section 2, p. 6.
pub const DES3: KeyType = KeyType { val: CKK_DES3 };
}

impl Deref for KeyType {
Expand All @@ -556,6 +559,7 @@ impl TryFrom<CK_KEY_TYPE> for KeyType {
CKK_EC_EDWARDS => Ok(KeyType::EC_EDWARDS),
CKK_EC_MONTGOMERY => Ok(KeyType::EC_MONTGOMERY),
CKK_GENERIC_SECRET => Ok(KeyType::GENERIC_SECRET),
CKK_DES3 => Ok(KeyType::DES3),
other => {
error!("Key type {} is not supported.", other);
Err(Error::NotSupported)
Expand Down
87 changes: 87 additions & 0 deletions cryptoki/tests/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,93 @@ fn get_token_info() {
assert_eq!("SoftHSM project", info.get_manufacturer_id());
}

#[test]
#[serial]
fn wrap_and_unwrap_key() {
let (pkcs11, slot) = init_pins();
// set flags
let mut flags = Flags::new();
let _ = flags.set_rw_session(true).set_serial_session(true);

// open a session
let session = pkcs11.open_session_no_callback(slot, flags).unwrap();

// log in the session
session.login(UserType::User).unwrap();

let key_to_be_wrapped_template = vec![
Attribute::Token(true.into()),
// the key needs to be extractable to be suitable for being wrapped
Attribute::Extractable(true.into()),
Attribute::Encrypt(true.into()),
];

// generate a secret key that will be wrapped
let key_to_be_wrapped = session
.generate_key(&Mechanism::Des3KeyGen, &key_to_be_wrapped_template)
.unwrap();

// Des3Ecb input length must be a multiple of 8
// see: PKCS#11 spec Table 10-10, DES-ECB Key And Data Length Constraints
let encrypted_with_original = session
.encrypt(
&Mechanism::Des3Ecb,
key_to_be_wrapped,
&[1, 2, 3, 4, 5, 6, 7, 8],
)
.unwrap();

// pub key template
let pub_key_template = vec![
Attribute::Token(true.into()),
Attribute::Private(true.into()),
Attribute::PublicExponent(vec![0x01, 0x00, 0x01]),
Attribute::ModulusBits(1024.into()),
// key needs to have "wrap" attribute to wrap other keys
Attribute::Wrap(true.into()),
];

// priv key template
let priv_key_template = vec![Attribute::Token(true.into())];

let (wrapping_key, unwrapping_key) = session
.generate_key_pair(
&Mechanism::RsaPkcsKeyPairGen,
&pub_key_template,
&priv_key_template,
)
.unwrap();

let wrapped_key = session
.wrap_key(&Mechanism::RsaPkcs, wrapping_key, key_to_be_wrapped)
.unwrap();
assert_eq!(wrapped_key.len(), 128);

let unwrapped_key = session
.unwrap_key(
&Mechanism::RsaPkcs,
unwrapping_key,
&wrapped_key,
&[
Attribute::Token(true.into()),
Attribute::Private(true.into()),
Attribute::Encrypt(true.into()),
Attribute::Class(ObjectClass::SECRET_KEY),
Attribute::KeyType(KeyType::DES3),
],
)
.unwrap();

let encrypted_with_unwrapped = session
.encrypt(
&Mechanism::Des3Ecb,
unwrapped_key,
&[1, 2, 3, 4, 5, 6, 7, 8],
)
.unwrap();
assert_eq!(encrypted_with_original, encrypted_with_unwrapped);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's cool!

}

#[test]
#[serial]
fn login_feast() {
Expand Down