diff --git a/cryptoki/src/functions/key_management.rs b/cryptoki/src/functions/key_management.rs index 1c3b816b..38febaf0 100644 --- a/cryptoki/src/functions/key_management.rs +++ b/cryptoki/src/functions/key_management.rs @@ -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 { + let mut 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_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, @@ -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> { + 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 { + let mut 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_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)) + } } diff --git a/cryptoki/src/types/mechanism/mod.rs b/cryptoki/src/types/mechanism/mod.rs index c2f481b7..24627d18 100644 --- a/cryptoki/src/types/mechanism/mod.rs +++ b/cryptoki/src/types/mechanism/mod.rs @@ -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 { @@ -117,6 +127,8 @@ impl TryFrom 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), @@ -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, @@ -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, @@ -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 diff --git a/cryptoki/src/types/object.rs b/cryptoki/src/types/object.rs index 21e3602e..15b73ef7 100644 --- a/cryptoki/src/types/object.rs +++ b/cryptoki/src/types/object.rs @@ -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 { @@ -556,6 +559,7 @@ impl TryFrom 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) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index fce0040f..cb62b687 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -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); +} + #[test] #[serial] fn login_feast() {