From 266358162ed68545637f46978618a90763fbb117 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Tue, 12 Sep 2023 10:51:30 +0200 Subject: [PATCH 1/3] Fix RSA OKCS OAEP mechanism Handling of empty data specified was broken. As specified in "2.1.7 PKCS #1 RSA OAEP mechanism parameters" the `CKZ_DATA_SPECIFIED` source: > Array of CK_BYTE containing the value of the encoding parameter. > If the parameter is empty, pSourceData must be NULL and ulSourceDataLen > must be zero. Adjusts by returning `std::ptr::null()` when the source data has not been specified (`PkcsOaepSource::empty()` was used) and adds a tests case for this. One more test case that is ignored is added to handle the case when the data specified is non-empty. Unfortunately this test fails for unknown reasons (I haven't been able to find if SoftHSM supports it or not). Fixes: https://github.com/parallaxsecond/rust-cryptoki/issues/163 Fixes: https://github.com/parallaxsecond/rust-cryptoki/pull/164 Signed-off-by: Wiktor Kwapisiewicz Co-authored-by: Nachiketh S Ujjainimath --- cryptoki/src/mechanism/rsa.rs | 13 ++++++--- cryptoki/tests/basic.rs | 54 ++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/cryptoki/src/mechanism/rsa.rs b/cryptoki/src/mechanism/rsa.rs index 905e6b39..7bb09889 100644 --- a/cryptoki/src/mechanism/rsa.rs +++ b/cryptoki/src/mechanism/rsa.rs @@ -79,27 +79,32 @@ impl TryFrom for PkcsMgfType { #[derive(Debug, Clone, Copy)] /// Source of the encoding parameter when formatting a message block for the PKCS #1 OAEP /// encryption scheme -pub struct PkcsOaepSource<'a>(&'a [u8]); +pub struct PkcsOaepSource<'a>(Option<&'a [u8]>); impl<'a> PkcsOaepSource<'a> { /// Construct an empty encoding parameter. /// /// This is equivalent to `data_specified(&[])`. pub fn empty() -> Self { - Self(&[]) + Self(None) } /// Construct an encoding parameter from an array of bytes. pub fn data_specified(source_data: &'a [u8]) -> Self { - Self(source_data) + Self(Some(source_data)) } pub(crate) fn source_ptr(&self) -> *const c_void { - self.0.as_ptr() as _ + if let Some(source_data) = self.0 { + source_data.as_ptr() as _ + } else { + std::ptr::null() + } } pub(crate) fn source_len(&self) -> Ulong { self.0 + .unwrap_or_default() .len() .try_into() .expect("usize can not fit in CK_ULONG") diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index f0b96986..30273654 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -6,7 +6,8 @@ use crate::common::{get_pkcs11, SO_PIN, USER_PIN}; use common::init_pins; use cryptoki::error::{Error, RvError}; use cryptoki::mechanism::aead::GcmParams; -use cryptoki::mechanism::Mechanism; +use cryptoki::mechanism::rsa::{PkcsMgfType, PkcsOaepParams, PkcsOaepSource}; +use cryptoki::mechanism::{Mechanism, MechanismType}; use cryptoki::object::{Attribute, AttributeInfo, AttributeType, KeyType, ObjectClass}; use cryptoki::session::{SessionState, UserType}; use cryptoki::types::AuthPin; @@ -1028,6 +1029,57 @@ fn aes_gcm_with_aad() -> TestResult { Ok(()) } +#[test] +#[serial] +fn rsa_pkcs_oaep_empty() -> TestResult { + let (pkcs11, slot) = init_pins(); + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + let pub_key_template = [Attribute::ModulusBits(2048.into())]; + let (pubkey, privkey) = + session.generate_key_pair(&Mechanism::RsaPkcsKeyPairGen, &pub_key_template, &[])?; + let oaep = PkcsOaepParams::new( + MechanismType::SHA1, + PkcsMgfType::MGF1_SHA1, + PkcsOaepSource::empty(), + ); + let encrypt_mechanism: Mechanism = Mechanism::RsaPkcsOaep(oaep); + let encrypted_data = session.encrypt(&encrypt_mechanism, pubkey, b"Hello")?; + + let decrypted_data = session.decrypt(&encrypt_mechanism, privkey, &encrypted_data)?; + let decrypted = String::from_utf8(decrypted_data)?; + assert_eq!("Hello", decrypted); + + Ok(()) +} + +#[test] +#[serial] +#[ignore] // it's not clear why the test with data specified fails +fn rsa_pkcs_oaep_with_data() -> TestResult { + let (pkcs11, slot) = init_pins(); + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + let pub_key_template = [Attribute::ModulusBits(2048.into())]; + let (pubkey, privkey) = + session.generate_key_pair(&Mechanism::RsaPkcsKeyPairGen, &pub_key_template, &[])?; + let oaep = PkcsOaepParams::new( + MechanismType::SHA1, + PkcsMgfType::MGF1_SHA1, + PkcsOaepSource::data_specified(&[1, 2, 3, 4, 5, 6, 7, 8]), + ); + let encrypt_mechanism: Mechanism = Mechanism::RsaPkcsOaep(oaep); + let encrypted_data = session.encrypt(&encrypt_mechanism, pubkey, b"Hello")?; + + let decrypted_data = session.decrypt(&encrypt_mechanism, privkey, &encrypted_data)?; + let decrypted = String::from_utf8(decrypted_data)?; + assert_eq!("Hello", decrypted); + + Ok(()) +} + #[test] #[serial] fn get_slot_event() -> TestResult { From 68640e6e16d237c30f894b35f030361733575a64 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Tue, 12 Sep 2023 11:02:52 +0200 Subject: [PATCH 2/3] Fix clippy lint: unnecessary-cast Signed-off-by: Wiktor Kwapisiewicz --- cryptoki/src/session/random.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptoki/src/session/random.rs b/cryptoki/src/session/random.rs index 11db44ee..728a5c17 100644 --- a/cryptoki/src/session/random.rs +++ b/cryptoki/src/session/random.rs @@ -32,7 +32,7 @@ impl Session { unsafe { Rv::from(get_pkcs11!(self.client(), C_GenerateRandom)( self.handle(), - result.as_mut_ptr() as *mut u8, + result.as_mut_ptr(), random_len.try_into()?, )) .into_result()?; From ce38f7eff6fa0562fe74ebccb2d457fc1d45d85a Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Tue, 12 Sep 2023 11:08:29 +0200 Subject: [PATCH 3/3] Fix clippy lint: useless-vec Signed-off-by: Wiktor Kwapisiewicz --- cryptoki/tests/basic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 30273654..3c363a75 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -954,7 +954,7 @@ fn sha256_digest() -> TestResult { // data to digest let data = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]; - let want = vec![ + let want = [ 0x17, 0x22, 0x6b, 0x1f, 0x68, 0xae, 0xba, 0xcd, 0xef, 0x07, 0x46, 0x45, 0x0f, 0x64, 0x28, 0x74, 0x63, 0x8b, 0x29, 0x57, 0x07, 0xef, 0x73, 0xfb, 0x2c, 0x6b, 0xb7, 0xf8, 0x8e, 0x89, 0x92, 0x9f,