From ac74eed192698b57b1f2143101bb9162b1f3c54e Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Tue, 25 Mar 2025 19:06:12 +0100 Subject: [PATCH 01/13] Added wrappers for multi-part digesting functions Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/session/digesting.rs | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/cryptoki/src/session/digesting.rs b/cryptoki/src/session/digesting.rs index ba5e7617..bdbe14f2 100644 --- a/cryptoki/src/session/digesting.rs +++ b/cryptoki/src/session/digesting.rs @@ -5,6 +5,7 @@ use crate::context::Function; use crate::error::{Result, Rv}; use crate::mechanism::Mechanism; +use crate::object::ObjectHandle; use crate::session::Session; use cryptoki_sys::*; use std::convert::TryInto; @@ -52,4 +53,76 @@ impl Session { Ok(digest) } + + /// Starts new multi-part digesting operation + pub fn digest_initialize(&self, m: &Mechanism) -> Result<()> { + let mut mechanism: CK_MECHANISM = m.into(); + + unsafe { + Rv::from(get_pkcs11!(self.client(), C_DigestInit)( + self.handle(), + &mut mechanism as CK_MECHANISM_PTR, + )) + .into_result(Function::DigestInit)?; + } + + Ok(()) + } + + /// Continues an ongoing multi-part digesting operation + pub fn digest_update(&self, data: &[u8]) -> Result<()> { + unsafe { + Rv::from(get_pkcs11!(self.client(), C_DigestUpdate)( + self.handle(), + data.as_ptr() as *mut u8, + data.len().try_into()?, + )) + .into_result(Function::DigestUpdate)?; + } + + Ok(()) + } + + /// Continues an ongoing multi-part digesting operation, using the value of a secret key as input + pub fn digest_key(&self, key: ObjectHandle) -> Result<()> { + unsafe { + Rv::from(get_pkcs11!(self.client(), C_DigestKey)( + self.handle(), + key.handle(), + )) + .into_result(Function::DigestKey)?; + } + + Ok(()) + } + + /// Finalizes ongoing multi-part digest operation + pub fn digest_finalize(&self) -> Result> { + let mut digest_len = 0; + + // Get the output buffer length + unsafe { + Rv::from(get_pkcs11!(self.client(), C_DigestFinal)( + self.handle(), + std::ptr::null_mut(), + &mut digest_len, + )) + .into_result(Function::DigestFinal)?; + } + + let mut digest = vec![0; digest_len.try_into()?]; + + unsafe { + Rv::from(get_pkcs11!(self.client(), C_DigestFinal)( + self.handle(), + digest.as_mut_ptr(), + &mut digest_len, + )) + .into_result(Function::DigestFinal)?; + } + + digest.resize(digest_len.try_into()?, 0); + + Ok(digest) + } } From 50f84a5029af5a0aceeba713814ae7b8b85a4ed4 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Wed, 26 Mar 2025 17:09:51 +0100 Subject: [PATCH 02/13] Added happy-path and failure test cases for multi-part digesting Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/tests/basic.rs | 137 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 6aa7b31a..1064590b 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -1304,6 +1304,143 @@ fn sha256_digest() -> TestResult { Ok(()) } +#[test] +#[serial] +fn sha256_digest_multipart() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // Open a session + let session = pkcs11.open_ro_session(slot)?; + + // Log into the session + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Data to digest + let data1 = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]; + let data2 = vec![0x66, 0x55, 0x44, 0x33, 0x22, 0x11]; + + // Digest data in parts + session.digest_initialize(&Mechanism::Sha256)?; + session.digest_update(&data1)?; + session.digest_update(&data2)?; + + let have = session.digest_finalize()?; + let want = vec![ + 0x8c, 0x18, 0xb1, 0x5f, 0x01, 0x47, 0x13, 0x2a, 0x03, 0xc2, 0xe3, 0xfd, 0x4f, 0x29, 0xb7, + 0x75, 0x80, 0x19, 0xb5, 0x58, 0x5e, 0xfc, 0xeb, 0x45, 0x18, 0x33, 0x2b, 0x2f, 0xa7, 0xa4, + 0x1f, 0x6e, + ]; + + assert_eq!(have, want); + + Ok(()) +} + +#[test] +#[serial] +fn sha256_digest_multipart_with_key() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // Open a session + let session = pkcs11.open_rw_session(slot)?; + + // Log into the session + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Create a key to add to the digest + let key_template = vec![ + Attribute::Token(true), + Attribute::ValueLen((256 / 8).into()), + Attribute::Sensitive(false), + Attribute::Extractable(true), + ]; + let key = session.generate_key(&Mechanism::AesKeyGen, &key_template)?; + + // Data and key bytes to digest + let mut data = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]; + + let attributes = session.get_attributes(key, &[AttributeType::Value])?; + let key_data = attributes.first().unwrap(); + let mut key_data = match key_data { + Attribute::Value(key_data) => key_data.to_owned(), + _ => unreachable!(), + }; + + // Digest data in parts + session.digest_initialize(&Mechanism::Sha256)?; + session.digest_update(&data)?; + session.digest_key(key)?; + + // Create digests to compare + let have = session.digest_finalize()?; + + data.append(&mut key_data); + let want = session.digest(&Mechanism::Sha256, &data)?; + + assert_eq!(have, want); + + Ok(()) +} + +#[test] +#[serial] +fn sha256_digest_multipart_not_initialized() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // Open a session + let session = pkcs11.open_ro_session(slot)?; + + // Log into the session + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Data to digest + let data = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]; + + // Attempt to update digest without an operation having been initialized + let result = session.digest_update(&data); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationNotInitialized, Function::DigestUpdate) + )); + + // Attempt to finalize digest without an operation having been initialized + let result = session.digest_finalize(); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationNotInitialized, Function::DigestFinal) + )); + + Ok(()) +} + +#[test] +#[serial] +fn sha256_digest_multipart_already_initialized() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // Open a session + let session = pkcs11.open_ro_session(slot)?; + + // Log into the session + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Initialize digesting operation twice in a row + session.digest_initialize(&Mechanism::Sha256)?; + let result = session.digest_initialize(&Mechanism::Sha256); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationActive, Function::DigestInit) + )); + + Ok(()) +} + #[test] #[serial] fn gcm_param_graceful_failure() -> TestResult { From 69632a64a1ab0d041022218e2a989d0fdf56c805 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Wed, 26 Mar 2025 17:33:03 +0100 Subject: [PATCH 03/13] Added informative comment to test Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/tests/basic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 1064590b..74e3f81f 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -1351,6 +1351,7 @@ fn sha256_digest_multipart_with_key() -> TestResult { let key_template = vec![ Attribute::Token(true), Attribute::ValueLen((256 / 8).into()), + // Key must be non-sensitive and extractable to get its bytes and digest them directly, for comparison Attribute::Sensitive(false), Attribute::Extractable(true), ]; From 334bc5ec6807f1f6ebac6ed6cadfeedd0d0abfb6 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Thu, 27 Mar 2025 14:23:08 +0100 Subject: [PATCH 04/13] Cleaned up tests a bit Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/tests/basic.rs | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 74e3f81f..b55c812a 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -1309,20 +1309,18 @@ fn sha256_digest() -> TestResult { fn sha256_digest_multipart() -> TestResult { let (pkcs11, slot) = init_pins(); - // Open a session + // Open a session and log in let session = pkcs11.open_ro_session(slot)?; - - // Log into the session session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // Data to digest - let data1 = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]; - let data2 = vec![0x66, 0x55, 0x44, 0x33, 0x22, 0x11]; + let data = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11]; // Digest data in parts session.digest_initialize(&Mechanism::Sha256)?; - session.digest_update(&data1)?; - session.digest_update(&data2)?; + for part in data.chunks(3) { + session.digest_update(part)?; + } let have = session.digest_finalize()?; let want = vec![ @@ -1341,10 +1339,8 @@ fn sha256_digest_multipart() -> TestResult { fn sha256_digest_multipart_with_key() -> TestResult { let (pkcs11, slot) = init_pins(); - // Open a session + // Open a session and log in let session = pkcs11.open_rw_session(slot)?; - - // Log into the session session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // Create a key to add to the digest @@ -1380,6 +1376,9 @@ fn sha256_digest_multipart_with_key() -> TestResult { assert_eq!(have, want); + // Delete key + session.destroy_object(key)?; + Ok(()) } @@ -1388,10 +1387,8 @@ fn sha256_digest_multipart_with_key() -> TestResult { fn sha256_digest_multipart_not_initialized() -> TestResult { let (pkcs11, slot) = init_pins(); - // Open a session + // Open a session and log in let session = pkcs11.open_ro_session(slot)?; - - // Log into the session session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // Data to digest @@ -1423,10 +1420,8 @@ fn sha256_digest_multipart_not_initialized() -> TestResult { fn sha256_digest_multipart_already_initialized() -> TestResult { let (pkcs11, slot) = init_pins(); - // Open a session + // Open a session and log in let session = pkcs11.open_ro_session(slot)?; - - // Log into the session session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // Initialize digesting operation twice in a row From 58eec0aec99a56830baca455fbede154eb9f3fa4 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Thu, 27 Mar 2025 14:24:44 +0100 Subject: [PATCH 05/13] Added multi-part decryption/encryption bindings Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/session/decryption.rs | 78 ++++++++++++++++++++++++++++++ cryptoki/src/session/encryption.rs | 78 ++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) diff --git a/cryptoki/src/session/decryption.rs b/cryptoki/src/session/decryption.rs index 59745fd8..2cd47955 100644 --- a/cryptoki/src/session/decryption.rs +++ b/cryptoki/src/session/decryption.rs @@ -60,4 +60,82 @@ impl Session { Ok(data) } + + /// Starts new multi-part decryption operation + pub fn decrypt_initialize(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { + let mut mechanism: CK_MECHANISM = mechanism.into(); + + unsafe { + Rv::from(get_pkcs11!(self.client(), C_DecryptInit)( + self.handle(), + &mut mechanism as CK_MECHANISM_PTR, + key.handle(), + )) + .into_result(Function::DecryptInit)?; + } + + Ok(()) + } + + /// Continues an ongoing multi-part decryption operation + pub fn decrypt_update(&self, encrypted_data: &[u8]) -> Result> { + let mut data_len = 0; + + // Get the output buffer length + unsafe { + Rv::from(get_pkcs11!(self.client(), C_DecryptUpdate)( + self.handle(), + encrypted_data.as_ptr() as *mut u8, + encrypted_data.len().try_into()?, + std::ptr::null_mut(), + &mut data_len, + )) + .into_result(Function::DecryptUpdate)?; + } + + let mut data = vec![0; data_len.try_into()?]; + + unsafe { + Rv::from(get_pkcs11!(self.client(), C_DecryptUpdate)( + self.handle(), + encrypted_data.as_ptr() as *mut u8, + encrypted_data.len().try_into()?, + data.as_mut_ptr(), + &mut data_len, + )) + .into_result(Function::DecryptUpdate)?; + } + + Ok(data) + } + + /// Finalizes ongoing multi-part decryption operation + pub fn decrypt_finalize(&self) -> Result> { + let mut data_len = 0; + + // Get the output buffer length + unsafe { + Rv::from(get_pkcs11!(self.client(), C_DecryptFinal)( + self.handle(), + std::ptr::null_mut(), + &mut data_len, + )) + .into_result(Function::DecryptFinal)?; + } + + let mut data = vec![0; data_len.try_into()?]; + + unsafe { + Rv::from(get_pkcs11!(self.client(), C_DecryptFinal)( + self.handle(), + data.as_mut_ptr(), + &mut data_len, + )) + .into_result(Function::DecryptFinal)?; + } + + data.resize(data_len.try_into()?, 0); + + Ok(data) + } } diff --git a/cryptoki/src/session/encryption.rs b/cryptoki/src/session/encryption.rs index 24e56ed4..b6c4d007 100644 --- a/cryptoki/src/session/encryption.rs +++ b/cryptoki/src/session/encryption.rs @@ -59,4 +59,82 @@ impl Session { Ok(encrypted_data) } + + /// Starts new multi-part encryption operation + pub fn encrypt_initialize(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { + let mut mechanism: CK_MECHANISM = mechanism.into(); + + unsafe { + Rv::from(get_pkcs11!(self.client(), C_EncryptInit)( + self.handle(), + &mut mechanism as CK_MECHANISM_PTR, + key.handle(), + )) + .into_result(Function::EncryptInit)?; + } + + Ok(()) + } + + /// Continues an ongoing multi-part encryption operation + pub fn encrypt_update(&self, data: &[u8]) -> Result> { + let mut encrypted_data_len = 0; + + // Get the output buffer length + unsafe { + Rv::from(get_pkcs11!(self.client(), C_EncryptUpdate)( + self.handle(), + data.as_ptr() as *mut u8, + data.len().try_into()?, + std::ptr::null_mut(), + &mut encrypted_data_len, + )) + .into_result(Function::EncryptUpdate)?; + } + + let mut encrypted_data = vec![0; encrypted_data_len.try_into()?]; + + unsafe { + Rv::from(get_pkcs11!(self.client(), C_EncryptUpdate)( + self.handle(), + data.as_ptr() as *mut u8, + data.len().try_into()?, + encrypted_data.as_mut_ptr(), + &mut encrypted_data_len, + )) + .into_result(Function::EncryptUpdate)?; + } + + Ok(encrypted_data) + } + + /// Finalizes ongoing multi-part encryption operation + pub fn encrypt_finalize(&self) -> Result> { + let mut encrypted_data_len = 0; + + // Get the output buffer length + unsafe { + Rv::from(get_pkcs11!(self.client(), C_EncryptFinal)( + self.handle(), + std::ptr::null_mut(), + &mut encrypted_data_len, + )) + .into_result(Function::EncryptFinal)?; + } + + let mut encrypted_data = vec![0; encrypted_data_len.try_into()?]; + + unsafe { + Rv::from(get_pkcs11!(self.client(), C_EncryptFinal)( + self.handle(), + encrypted_data.as_mut_ptr(), + &mut encrypted_data_len, + )) + .into_result(Function::EncryptFinal)?; + } + + encrypted_data.resize(encrypted_data_len.try_into()?, 0); + + Ok(encrypted_data) + } } From 189f88ef0788f49d079a7986ec47bf4813b4d618 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Thu, 27 Mar 2025 14:25:15 +0100 Subject: [PATCH 06/13] Added tests for multi-part decryption/encryption Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/tests/basic.rs | 166 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index b55c812a..d0b4ea2f 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -265,6 +265,172 @@ fn encrypt_decrypt() -> TestResult { Ok(()) } +#[test] +#[serial] +// Currently SoftHSM doesn't support EncryptUpdate/DecryptUpdate +#[ignore] +fn encrypt_decrypt_multipart() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Define parameters for keypair + let public_exponent = vec![0x01, 0x00, 0x01]; + let modulus_bits = 1024; + + let pub_key_template = vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::PublicExponent(public_exponent), + Attribute::ModulusBits(modulus_bits.into()), + Attribute::Encrypt(true), + ]; + let priv_key_template = vec![Attribute::Token(true), Attribute::Decrypt(true)]; + + // Generate keypair + let (pub_key, priv_key) = + session.generate_key_pair(&Mechanism::RsaPkcsKeyPairGen, &pub_key_template, &priv_key_template)?; + + // Data to encrypt + let data = vec![0xFF, 0x55, 0xDD, 0x11, 0xBB, 0x33]; + + // Encrypt data in parts + session.encrypt_initialize(&Mechanism::RsaPkcs, pub_key)?; + + let mut encrypted_data = vec![]; + for part in data.chunks(3) { + encrypted_data.extend(session.encrypt_update(part)?); + } + encrypted_data.extend(session.encrypt_finalize()?); + + // Decrypt data in parts + session.decrypt_initialize(&Mechanism::RsaPkcs, priv_key)?; + + let mut decrypted_data = vec![]; + for part in encrypted_data.chunks(3) { + decrypted_data.extend(session.decrypt_update(part)?); + } + decrypted_data.extend(session.decrypt_finalize()?); + + assert_eq!(data, decrypted_data); + + // Delete keys + session.destroy_object(pub_key)?; + session.destroy_object(priv_key)?; + + Ok(()) +} + +#[test] +#[serial] +// Currently SoftHSM doesn't support EncryptUpdate/DecryptUpdate +#[ignore] +fn encrypt_decrypt_multipart_not_initialized() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Data to encrypt/decrypt + let data = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]; + + // Attempt to update encryption without an operation having been initialized + let result = session.encrypt_update(&data); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationNotInitialized, Function::EncryptUpdate) + )); + + // Attempt to finalize encryption without an operation having been initialized + let result = session.encrypt_finalize(); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationNotInitialized, Function::EncryptFinal) + )); + + // Attempt to update decryption without an operation having been initialized + let result = session.decrypt_update(&data); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationNotInitialized, Function::DecryptUpdate) + )); + + // Attempt to finalize decryption without an operation having been initialized + let result = session.decrypt_finalize(); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationNotInitialized, Function::DecryptFinal) + )); + + Ok(()) +} + +#[test] +#[serial] +// Currently SoftHSM doesn't support EncryptUpdate/DecryptUpdate +#[ignore] +fn encrypt_decrypt_multipart_already_initialized() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Define parameters for keypair + let public_exponent = vec![0x01, 0x00, 0x01]; + let modulus_bits = 1024; + + let pub_key_template = vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::PublicExponent(public_exponent), + Attribute::ModulusBits(modulus_bits.into()), + Attribute::Encrypt(true), + ]; + let priv_key_template = vec![Attribute::Token(true), Attribute::Decrypt(true)]; + + // Generate keypair + let (pub_key, priv_key) = + session.generate_key_pair(&Mechanism::RsaPkcsKeyPairGen, &pub_key_template, &priv_key_template)?; + + // Initialize encryption operation twice in a row + session.encrypt_initialize(&Mechanism::RsaPkcs, pub_key)?; + let result = session.encrypt_initialize(&Mechanism::RsaPkcs, pub_key); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationActive, Function::EncryptInit) + )); + + // Initialize encryption operation twice in a row + session.decrypt_initialize(&Mechanism::RsaPkcs, priv_key)?; + let result = session.decrypt_initialize(&Mechanism::RsaPkcs, priv_key); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationActive, Function::DecryptInit) + )); + + // Delete keys + session.destroy_object(pub_key)?; + session.destroy_object(priv_key)?; + + Ok(()) +} + #[test] #[serial] fn derive_key() -> TestResult { From 7e2b18f43415f213a672c6d74c90d980acf2c249 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Thu, 27 Mar 2025 14:47:09 +0100 Subject: [PATCH 07/13] Added multi-part signing/verification bindings Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/session/signing_macing.rs | 104 +++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/cryptoki/src/session/signing_macing.rs b/cryptoki/src/session/signing_macing.rs index a3fd6f6d..faca3b42 100644 --- a/cryptoki/src/session/signing_macing.rs +++ b/cryptoki/src/session/signing_macing.rs @@ -56,6 +56,66 @@ impl Session { Ok(signature) } + /// Starts new multi-part signing operation + pub fn sign_initialize(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { + let mut mechanism: CK_MECHANISM = mechanism.into(); + + unsafe { + Rv::from(get_pkcs11!(self.client(), C_SignInit)( + self.handle(), + &mut mechanism as CK_MECHANISM_PTR, + key.handle(), + )) + .into_result(Function::SignInit)?; + } + + Ok(()) + } + + /// Continues an ongoing multi-part signing operation + pub fn sign_update(&self, data: &[u8]) -> Result<()> { + unsafe { + Rv::from(get_pkcs11!(self.client(), C_SignUpdate)( + self.handle(), + data.as_ptr() as *mut u8, + data.len().try_into()?, + )) + .into_result(Function::SignUpdate)?; + } + + Ok(()) + } + + /// Finalizes ongoing multi-part signing operation + pub fn sign_finalize(&self) -> Result> { + let mut signature_len = 0; + + // Get the output buffer length + unsafe { + Rv::from(get_pkcs11!(self.client(), C_SignFinal)( + self.handle(), + std::ptr::null_mut(), + &mut signature_len, + )) + .into_result(Function::SignFinal)?; + } + + let mut signature = vec![0; signature_len.try_into()?]; + + unsafe { + Rv::from(get_pkcs11!(self.client(), C_SignFinal)( + self.handle(), + signature.as_mut_ptr(), + &mut signature_len, + )) + .into_result(Function::SignFinal)?; + } + + signature.resize(signature_len.try_into()?, 0); + + Ok(signature) + } + /// Verify data in single-part pub fn verify( &self, @@ -86,4 +146,48 @@ impl Session { .into_result(Function::Verify) } } + + /// Starts new multi-part verifying operation + pub fn verify_initialize(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { + let mut mechanism: CK_MECHANISM = mechanism.into(); + + unsafe { + Rv::from(get_pkcs11!(self.client(), C_VerifyInit)( + self.handle(), + &mut mechanism as CK_MECHANISM_PTR, + key.handle(), + )) + .into_result(Function::VerifyInit)?; + } + + Ok(()) + } + + /// Continues an ongoing multi-part verifying operation + pub fn verify_update(&self, data: &[u8]) -> Result<()> { + unsafe { + Rv::from(get_pkcs11!(self.client(), C_VerifyUpdate)( + self.handle(), + data.as_ptr() as *mut u8, + data.len().try_into()?, + )) + .into_result(Function::VerifyUpdate)?; + } + + Ok(()) + } + + /// Finalizes ongoing multi-part verifying operation + pub fn verify_finalize(&self, signature: &[u8]) -> Result<()> { + unsafe { + Rv::from(get_pkcs11!(self.client(), C_VerifyFinal)( + self.handle(), + signature.as_ptr() as *mut u8, + signature.len().try_into()?, + )) + .into_result(Function::VerifyFinal)?; + } + + Ok(()) + } } From feb07eddabb901a10eafbceec9cde7f2a101bcd9 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Thu, 27 Mar 2025 16:22:37 +0100 Subject: [PATCH 08/13] Added tests for multi-part signing/verification Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/tests/basic.rs | 164 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index d0b4ea2f..5729472d 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -213,6 +213,170 @@ fn sign_verify_eddsa_with_ed448_schemes() -> TestResult { Ok(()) } +#[test] +#[serial] +fn sign_verify_multipart() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Define parameters for keypair + let public_exponent = vec![0x01, 0x00, 0x01]; + let modulus_bits = 1024; + + let pub_key_template = vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::PublicExponent(public_exponent), + Attribute::ModulusBits(modulus_bits.into()), + Attribute::Verify(true), + ]; + let priv_key_template = vec![Attribute::Token(true), Attribute::Sign(true)]; + + // Generate keypair + let (pub_key, priv_key) = session.generate_key_pair( + &Mechanism::RsaPkcsKeyPairGen, + &pub_key_template, + &priv_key_template, + )?; + + // Data to sign + let data = vec![0xFF, 0x55, 0xDD, 0x11, 0xBB, 0x33]; + + // Sign data in parts (standard RsaPkcs doesn't support this) + session.sign_initialize(&Mechanism::Sha256RsaPkcs, priv_key)?; + for part in data.chunks(3) { + session.sign_update(part)?; + } + let signature = session.sign_finalize()?; + + // Verify signature in parts (standard RsaPkcs doesn't support this) + session.verify_initialize(&Mechanism::Sha256RsaPkcs, pub_key)?; + for part in data.chunks(3) { + session.verify_update(part)?; + } + session.verify_finalize(&signature)?; + + // Delete keys + session.destroy_object(pub_key)?; + session.destroy_object(priv_key)?; + + Ok(()) +} + +#[test] +#[serial] +fn sign_verify_multipart_not_initialized() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_ro_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Data to sign/verify + let data = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]; + let signature = vec![0x66, 0x55, 0x44, 0x33, 0x22, 0x11]; + + // Attempt to update signing without an operation having been initialized + let result = session.sign_update(&data); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationNotInitialized, Function::SignUpdate) + )); + + // Attempt to finalize signing without an operation having been initialized + let result = session.sign_finalize(); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationNotInitialized, Function::SignFinal) + )); + + // Attempt to update verification without an operation having been initialized + let result = session.verify_update(&data); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationNotInitialized, Function::VerifyUpdate) + )); + + // Attempt to finalize verification without an operation having been initialized + let result = session.verify_finalize(&signature); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationNotInitialized, Function::VerifyFinal) + )); + + Ok(()) +} + +#[test] +#[serial] +fn sign_verify_multipart_already_initialized() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // Open a session and log in + let session = pkcs11.open_rw_session(slot)?; + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // Define parameters for keypair + let public_exponent = vec![0x01, 0x00, 0x01]; + let modulus_bits = 1024; + + let pub_key_template = vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::PublicExponent(public_exponent), + Attribute::ModulusBits(modulus_bits.into()), + Attribute::Verify(true), + ]; + let priv_key_template = vec![Attribute::Token(true), Attribute::Sign(true)]; + + // Generate keypair + let (pub_key, priv_key) = session.generate_key_pair( + &Mechanism::RsaPkcsKeyPairGen, + &pub_key_template, + &priv_key_template, + )?; + + // Initialize signing operation twice in a row + session.sign_initialize(&Mechanism::Sha256RsaPkcs, priv_key)?; + let result = session.sign_initialize(&Mechanism::Sha256RsaPkcs, priv_key); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationActive, Function::SignInit) + )); + + // Make sure signing operation is over before trying same with verification + session.sign_finalize()?; + + // Initialize verification operation twice in a row + session.verify_initialize(&Mechanism::Sha256RsaPkcs, pub_key)?; + let result = session.verify_initialize(&Mechanism::Sha256RsaPkcs, pub_key); + + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + Error::Pkcs11(RvError::OperationActive, Function::VerifyInit) + )); + + // Delete keys + session.destroy_object(pub_key)?; + session.destroy_object(priv_key)?; + + Ok(()) +} + #[test] #[serial] fn encrypt_decrypt() -> TestResult { From 498c5ee4a9ca76cf02d56fe07701a7c6a60759e5 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Thu, 27 Mar 2025 16:25:26 +0100 Subject: [PATCH 09/13] Re-enabled prior tests for multi-part decryption/encryption I found out it was not that multi-part encryption/decryption weren't supported *at all*, it's that they're just supported for symmetric schemes Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/tests/basic.rs | 81 ++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 46 deletions(-) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 5729472d..39d55338 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -431,8 +431,6 @@ fn encrypt_decrypt() -> TestResult { #[test] #[serial] -// Currently SoftHSM doesn't support EncryptUpdate/DecryptUpdate -#[ignore] fn encrypt_decrypt_multipart() -> TestResult { let (pkcs11, slot) = init_pins(); @@ -440,28 +438,24 @@ fn encrypt_decrypt_multipart() -> TestResult { let session = pkcs11.open_rw_session(slot)?; session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; - // Define parameters for keypair - let public_exponent = vec![0x01, 0x00, 0x01]; - let modulus_bits = 1024; - - let pub_key_template = vec![ + // Generate key (currently SoftHSM only supports multi-part encrypt/decrypt for symmetric crypto) + let template = vec![ Attribute::Token(true), Attribute::Private(false), - Attribute::PublicExponent(public_exponent), - Attribute::ModulusBits(modulus_bits.into()), + Attribute::ValueLen((128 / 8).into()), Attribute::Encrypt(true), + Attribute::Decrypt(true), ]; - let priv_key_template = vec![Attribute::Token(true), Attribute::Decrypt(true)]; - - // Generate keypair - let (pub_key, priv_key) = - session.generate_key_pair(&Mechanism::RsaPkcsKeyPairGen, &pub_key_template, &priv_key_template)?; + let key = session.generate_key(&Mechanism::AesKeyGen, &template)?; // Data to encrypt - let data = vec![0xFF, 0x55, 0xDD, 0x11, 0xBB, 0x33]; + let data = vec![ + 0xFF, 0x55, 0xDD, 0x11, 0xBB, 0x33, 0x99, 0x77, 0xFF, 0x55, 0xDD, 0x11, 0xBB, 0x33, 0x99, + 0x77, + ]; // Encrypt data in parts - session.encrypt_initialize(&Mechanism::RsaPkcs, pub_key)?; + session.encrypt_initialize(&Mechanism::AesEcb, key)?; let mut encrypted_data = vec![]; for part in data.chunks(3) { @@ -470,7 +464,7 @@ fn encrypt_decrypt_multipart() -> TestResult { encrypted_data.extend(session.encrypt_finalize()?); // Decrypt data in parts - session.decrypt_initialize(&Mechanism::RsaPkcs, priv_key)?; + session.decrypt_initialize(&Mechanism::AesEcb, key)?; let mut decrypted_data = vec![]; for part in encrypted_data.chunks(3) { @@ -480,26 +474,26 @@ fn encrypt_decrypt_multipart() -> TestResult { assert_eq!(data, decrypted_data); - // Delete keys - session.destroy_object(pub_key)?; - session.destroy_object(priv_key)?; + // Delete key + session.destroy_object(key)?; Ok(()) } #[test] #[serial] -// Currently SoftHSM doesn't support EncryptUpdate/DecryptUpdate -#[ignore] fn encrypt_decrypt_multipart_not_initialized() -> TestResult { let (pkcs11, slot) = init_pins(); // Open a session and log in - let session = pkcs11.open_rw_session(slot)?; + let session = pkcs11.open_ro_session(slot)?; session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // Data to encrypt/decrypt - let data = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]; + let data = vec![ + 0xFF, 0x55, 0xDD, 0x11, 0xBB, 0x33, 0x99, 0x77, 0xFF, 0x55, 0xDD, 0x11, 0xBB, 0x33, 0x99, + 0x77, + ]; // Attempt to update encryption without an operation having been initialized let result = session.encrypt_update(&data); @@ -542,8 +536,6 @@ fn encrypt_decrypt_multipart_not_initialized() -> TestResult { #[test] #[serial] -// Currently SoftHSM doesn't support EncryptUpdate/DecryptUpdate -#[ignore] fn encrypt_decrypt_multipart_already_initialized() -> TestResult { let (pkcs11, slot) = init_pins(); @@ -551,26 +543,19 @@ fn encrypt_decrypt_multipart_already_initialized() -> TestResult { let session = pkcs11.open_rw_session(slot)?; session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; - // Define parameters for keypair - let public_exponent = vec![0x01, 0x00, 0x01]; - let modulus_bits = 1024; - - let pub_key_template = vec![ + // Generate key (currently SoftHSM only supports multi-part encrypt/decrypt for symmetric crypto) + let template = vec![ Attribute::Token(true), Attribute::Private(false), - Attribute::PublicExponent(public_exponent), - Attribute::ModulusBits(modulus_bits.into()), + Attribute::ValueLen((128 / 8).into()), Attribute::Encrypt(true), + Attribute::Decrypt(true), ]; - let priv_key_template = vec![Attribute::Token(true), Attribute::Decrypt(true)]; - - // Generate keypair - let (pub_key, priv_key) = - session.generate_key_pair(&Mechanism::RsaPkcsKeyPairGen, &pub_key_template, &priv_key_template)?; + let key = session.generate_key(&Mechanism::AesKeyGen, &template)?; // Initialize encryption operation twice in a row - session.encrypt_initialize(&Mechanism::RsaPkcs, pub_key)?; - let result = session.encrypt_initialize(&Mechanism::RsaPkcs, pub_key); + session.encrypt_initialize(&Mechanism::AesEcb, key)?; + let result = session.encrypt_initialize(&Mechanism::AesEcb, key); assert!(result.is_err()); assert!(matches!( @@ -578,9 +563,12 @@ fn encrypt_decrypt_multipart_already_initialized() -> TestResult { Error::Pkcs11(RvError::OperationActive, Function::EncryptInit) )); + // Make sure encryption operation is over before trying same with decryption + session.encrypt_finalize()?; + // Initialize encryption operation twice in a row - session.decrypt_initialize(&Mechanism::RsaPkcs, priv_key)?; - let result = session.decrypt_initialize(&Mechanism::RsaPkcs, priv_key); + session.decrypt_initialize(&Mechanism::AesEcb, key)?; + let result = session.decrypt_initialize(&Mechanism::AesEcb, key); assert!(result.is_err()); assert!(matches!( @@ -588,9 +576,8 @@ fn encrypt_decrypt_multipart_already_initialized() -> TestResult { Error::Pkcs11(RvError::OperationActive, Function::DecryptInit) )); - // Delete keys - session.destroy_object(pub_key)?; - session.destroy_object(priv_key)?; + // Delete key + session.destroy_object(key)?; Ok(()) } @@ -1644,7 +1631,9 @@ fn sha256_digest_multipart() -> TestResult { session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // Data to digest - let data = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11]; + let data = vec![ + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, + ]; // Digest data in parts session.digest_initialize(&Mechanism::Sha256)?; From 63fc6ebb2d91c62b970b2d9164d5bbcd4548dfc0 Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Thu, 27 Mar 2025 16:30:58 +0100 Subject: [PATCH 10/13] Slimmed down templates for my tests to the bare minimum Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/tests/basic.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 39d55338..8441394e 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -228,12 +228,10 @@ fn sign_verify_multipart() -> TestResult { let pub_key_template = vec![ Attribute::Token(true), - Attribute::Private(false), Attribute::PublicExponent(public_exponent), Attribute::ModulusBits(modulus_bits.into()), - Attribute::Verify(true), ]; - let priv_key_template = vec![Attribute::Token(true), Attribute::Sign(true)]; + let priv_key_template = vec![Attribute::Token(true)]; // Generate keypair let (pub_key, priv_key) = session.generate_key_pair( @@ -333,12 +331,10 @@ fn sign_verify_multipart_already_initialized() -> TestResult { let pub_key_template = vec![ Attribute::Token(true), - Attribute::Private(false), Attribute::PublicExponent(public_exponent), Attribute::ModulusBits(modulus_bits.into()), - Attribute::Verify(true), ]; - let priv_key_template = vec![Attribute::Token(true), Attribute::Sign(true)]; + let priv_key_template = vec![Attribute::Token(true)]; // Generate keypair let (pub_key, priv_key) = session.generate_key_pair( @@ -441,10 +437,7 @@ fn encrypt_decrypt_multipart() -> TestResult { // Generate key (currently SoftHSM only supports multi-part encrypt/decrypt for symmetric crypto) let template = vec![ Attribute::Token(true), - Attribute::Private(false), Attribute::ValueLen((128 / 8).into()), - Attribute::Encrypt(true), - Attribute::Decrypt(true), ]; let key = session.generate_key(&Mechanism::AesKeyGen, &template)?; @@ -546,10 +539,7 @@ fn encrypt_decrypt_multipart_already_initialized() -> TestResult { // Generate key (currently SoftHSM only supports multi-part encrypt/decrypt for symmetric crypto) let template = vec![ Attribute::Token(true), - Attribute::Private(false), Attribute::ValueLen((128 / 8).into()), - Attribute::Encrypt(true), - Attribute::Decrypt(true), ]; let key = session.generate_key(&Mechanism::AesKeyGen, &template)?; From e6e7da4400637b3e4d67a3ca5f4441f70fee899d Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Fri, 28 Mar 2025 12:01:20 +0100 Subject: [PATCH 11/13] Updated naming of multi-part functions to match the spec Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/session/decryption.rs | 10 +++-- cryptoki/src/session/digesting.rs | 13 +++--- cryptoki/src/session/encryption.rs | 10 +++-- cryptoki/src/session/signing_macing.rs | 20 +++++---- cryptoki/tests/basic.rs | 58 +++++++++++++------------- 5 files changed, 61 insertions(+), 50 deletions(-) diff --git a/cryptoki/src/session/decryption.rs b/cryptoki/src/session/decryption.rs index 2cd47955..6d4358df 100644 --- a/cryptoki/src/session/decryption.rs +++ b/cryptoki/src/session/decryption.rs @@ -62,7 +62,7 @@ impl Session { } /// Starts new multi-part decryption operation - pub fn decrypt_initialize(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { + pub fn decrypt_init(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { let mut mechanism: CK_MECHANISM = mechanism.into(); unsafe { @@ -77,7 +77,8 @@ impl Session { Ok(()) } - /// Continues an ongoing multi-part decryption operation + /// Continues an ongoing multi-part decryption operation, + /// taking in the next part of the encrypted data and returning its decryption pub fn decrypt_update(&self, encrypted_data: &[u8]) -> Result> { let mut data_len = 0; @@ -109,8 +110,9 @@ impl Session { Ok(data) } - /// Finalizes ongoing multi-part decryption operation - pub fn decrypt_finalize(&self) -> Result> { + /// Finalizes ongoing multi-part decryption operation, + /// returning any remaining bytes in the decrypted data + pub fn decrypt_final(&self) -> Result> { let mut data_len = 0; // Get the output buffer length diff --git a/cryptoki/src/session/digesting.rs b/cryptoki/src/session/digesting.rs index bdbe14f2..220bbfa8 100644 --- a/cryptoki/src/session/digesting.rs +++ b/cryptoki/src/session/digesting.rs @@ -55,7 +55,7 @@ impl Session { } /// Starts new multi-part digesting operation - pub fn digest_initialize(&self, m: &Mechanism) -> Result<()> { + pub fn digest_init(&self, m: &Mechanism) -> Result<()> { let mut mechanism: CK_MECHANISM = m.into(); unsafe { @@ -69,7 +69,8 @@ impl Session { Ok(()) } - /// Continues an ongoing multi-part digesting operation + /// Continues an ongoing multi-part digesting operation, + /// taking in the next part of the data to digest pub fn digest_update(&self, data: &[u8]) -> Result<()> { unsafe { Rv::from(get_pkcs11!(self.client(), C_DigestUpdate)( @@ -83,7 +84,8 @@ impl Session { Ok(()) } - /// Continues an ongoing multi-part digesting operation, using the value of a secret key as input + /// Continues an ongoing multi-part digesting operation, + /// using the value of a secret key as input pub fn digest_key(&self, key: ObjectHandle) -> Result<()> { unsafe { Rv::from(get_pkcs11!(self.client(), C_DigestKey)( @@ -96,8 +98,9 @@ impl Session { Ok(()) } - /// Finalizes ongoing multi-part digest operation - pub fn digest_finalize(&self) -> Result> { + /// Finalizes ongoing multi-part digest operation, + /// returning the digest + pub fn digest_final(&self) -> Result> { let mut digest_len = 0; // Get the output buffer length diff --git a/cryptoki/src/session/encryption.rs b/cryptoki/src/session/encryption.rs index b6c4d007..e47cfefd 100644 --- a/cryptoki/src/session/encryption.rs +++ b/cryptoki/src/session/encryption.rs @@ -61,7 +61,7 @@ impl Session { } /// Starts new multi-part encryption operation - pub fn encrypt_initialize(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { + pub fn encrypt_init(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { let mut mechanism: CK_MECHANISM = mechanism.into(); unsafe { @@ -76,7 +76,8 @@ impl Session { Ok(()) } - /// Continues an ongoing multi-part encryption operation + /// Continues an ongoing multi-part encryption operation, + /// taking in the next part of the data and returning its encryption pub fn encrypt_update(&self, data: &[u8]) -> Result> { let mut encrypted_data_len = 0; @@ -108,8 +109,9 @@ impl Session { Ok(encrypted_data) } - /// Finalizes ongoing multi-part encryption operation - pub fn encrypt_finalize(&self) -> Result> { + /// Finalizes ongoing multi-part encryption operation, + /// returning any remaining bytes in the encrypted data + pub fn encrypt_final(&self) -> Result> { let mut encrypted_data_len = 0; // Get the output buffer length diff --git a/cryptoki/src/session/signing_macing.rs b/cryptoki/src/session/signing_macing.rs index faca3b42..9deed03d 100644 --- a/cryptoki/src/session/signing_macing.rs +++ b/cryptoki/src/session/signing_macing.rs @@ -57,7 +57,7 @@ impl Session { } /// Starts new multi-part signing operation - pub fn sign_initialize(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { + pub fn sign_init(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { let mut mechanism: CK_MECHANISM = mechanism.into(); unsafe { @@ -72,7 +72,8 @@ impl Session { Ok(()) } - /// Continues an ongoing multi-part signing operation + /// Continues an ongoing multi-part signing operation, + /// taking in the next part of the data to sign pub fn sign_update(&self, data: &[u8]) -> Result<()> { unsafe { Rv::from(get_pkcs11!(self.client(), C_SignUpdate)( @@ -86,8 +87,9 @@ impl Session { Ok(()) } - /// Finalizes ongoing multi-part signing operation - pub fn sign_finalize(&self) -> Result> { + /// Finalizes ongoing multi-part signing operation, + /// returning the signature + pub fn sign_final(&self) -> Result> { let mut signature_len = 0; // Get the output buffer length @@ -148,7 +150,7 @@ impl Session { } /// Starts new multi-part verifying operation - pub fn verify_initialize(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { + pub fn verify_init(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { let mut mechanism: CK_MECHANISM = mechanism.into(); unsafe { @@ -163,7 +165,8 @@ impl Session { Ok(()) } - /// Continues an ongoing multi-part verifying operation + /// Continues an ongoing multi-part verifying operation, + /// taking in the next part of the data to verify pub fn verify_update(&self, data: &[u8]) -> Result<()> { unsafe { Rv::from(get_pkcs11!(self.client(), C_VerifyUpdate)( @@ -177,8 +180,9 @@ impl Session { Ok(()) } - /// Finalizes ongoing multi-part verifying operation - pub fn verify_finalize(&self, signature: &[u8]) -> Result<()> { + /// Finalizes ongoing multi-part verifying operation, + /// returning Ok only if the signature verifies + pub fn verify_final(&self, signature: &[u8]) -> Result<()> { unsafe { Rv::from(get_pkcs11!(self.client(), C_VerifyFinal)( self.handle(), diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 8441394e..98c431fa 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -244,18 +244,18 @@ fn sign_verify_multipart() -> TestResult { let data = vec![0xFF, 0x55, 0xDD, 0x11, 0xBB, 0x33]; // Sign data in parts (standard RsaPkcs doesn't support this) - session.sign_initialize(&Mechanism::Sha256RsaPkcs, priv_key)?; + session.sign_init(&Mechanism::Sha256RsaPkcs, priv_key)?; for part in data.chunks(3) { session.sign_update(part)?; } - let signature = session.sign_finalize()?; + let signature = session.sign_final()?; // Verify signature in parts (standard RsaPkcs doesn't support this) - session.verify_initialize(&Mechanism::Sha256RsaPkcs, pub_key)?; + session.verify_init(&Mechanism::Sha256RsaPkcs, pub_key)?; for part in data.chunks(3) { session.verify_update(part)?; } - session.verify_finalize(&signature)?; + session.verify_final(&signature)?; // Delete keys session.destroy_object(pub_key)?; @@ -287,7 +287,7 @@ fn sign_verify_multipart_not_initialized() -> TestResult { )); // Attempt to finalize signing without an operation having been initialized - let result = session.sign_finalize(); + let result = session.sign_final(); assert!(result.is_err()); assert!(matches!( @@ -305,7 +305,7 @@ fn sign_verify_multipart_not_initialized() -> TestResult { )); // Attempt to finalize verification without an operation having been initialized - let result = session.verify_finalize(&signature); + let result = session.verify_final(&signature); assert!(result.is_err()); assert!(matches!( @@ -344,8 +344,8 @@ fn sign_verify_multipart_already_initialized() -> TestResult { )?; // Initialize signing operation twice in a row - session.sign_initialize(&Mechanism::Sha256RsaPkcs, priv_key)?; - let result = session.sign_initialize(&Mechanism::Sha256RsaPkcs, priv_key); + session.sign_init(&Mechanism::Sha256RsaPkcs, priv_key)?; + let result = session.sign_init(&Mechanism::Sha256RsaPkcs, priv_key); assert!(result.is_err()); assert!(matches!( @@ -354,11 +354,11 @@ fn sign_verify_multipart_already_initialized() -> TestResult { )); // Make sure signing operation is over before trying same with verification - session.sign_finalize()?; + session.sign_final()?; // Initialize verification operation twice in a row - session.verify_initialize(&Mechanism::Sha256RsaPkcs, pub_key)?; - let result = session.verify_initialize(&Mechanism::Sha256RsaPkcs, pub_key); + session.verify_init(&Mechanism::Sha256RsaPkcs, pub_key)?; + let result = session.verify_init(&Mechanism::Sha256RsaPkcs, pub_key); assert!(result.is_err()); assert!(matches!( @@ -448,22 +448,22 @@ fn encrypt_decrypt_multipart() -> TestResult { ]; // Encrypt data in parts - session.encrypt_initialize(&Mechanism::AesEcb, key)?; + session.encrypt_init(&Mechanism::AesEcb, key)?; let mut encrypted_data = vec![]; for part in data.chunks(3) { encrypted_data.extend(session.encrypt_update(part)?); } - encrypted_data.extend(session.encrypt_finalize()?); + encrypted_data.extend(session.encrypt_final()?); // Decrypt data in parts - session.decrypt_initialize(&Mechanism::AesEcb, key)?; + session.decrypt_init(&Mechanism::AesEcb, key)?; let mut decrypted_data = vec![]; for part in encrypted_data.chunks(3) { decrypted_data.extend(session.decrypt_update(part)?); } - decrypted_data.extend(session.decrypt_finalize()?); + decrypted_data.extend(session.decrypt_final()?); assert_eq!(data, decrypted_data); @@ -498,7 +498,7 @@ fn encrypt_decrypt_multipart_not_initialized() -> TestResult { )); // Attempt to finalize encryption without an operation having been initialized - let result = session.encrypt_finalize(); + let result = session.encrypt_final(); assert!(result.is_err()); assert!(matches!( @@ -516,7 +516,7 @@ fn encrypt_decrypt_multipart_not_initialized() -> TestResult { )); // Attempt to finalize decryption without an operation having been initialized - let result = session.decrypt_finalize(); + let result = session.decrypt_final(); assert!(result.is_err()); assert!(matches!( @@ -544,8 +544,8 @@ fn encrypt_decrypt_multipart_already_initialized() -> TestResult { let key = session.generate_key(&Mechanism::AesKeyGen, &template)?; // Initialize encryption operation twice in a row - session.encrypt_initialize(&Mechanism::AesEcb, key)?; - let result = session.encrypt_initialize(&Mechanism::AesEcb, key); + session.encrypt_init(&Mechanism::AesEcb, key)?; + let result = session.encrypt_init(&Mechanism::AesEcb, key); assert!(result.is_err()); assert!(matches!( @@ -554,11 +554,11 @@ fn encrypt_decrypt_multipart_already_initialized() -> TestResult { )); // Make sure encryption operation is over before trying same with decryption - session.encrypt_finalize()?; + session.encrypt_final()?; // Initialize encryption operation twice in a row - session.decrypt_initialize(&Mechanism::AesEcb, key)?; - let result = session.decrypt_initialize(&Mechanism::AesEcb, key); + session.decrypt_init(&Mechanism::AesEcb, key)?; + let result = session.decrypt_init(&Mechanism::AesEcb, key); assert!(result.is_err()); assert!(matches!( @@ -1626,12 +1626,12 @@ fn sha256_digest_multipart() -> TestResult { ]; // Digest data in parts - session.digest_initialize(&Mechanism::Sha256)?; + session.digest_init(&Mechanism::Sha256)?; for part in data.chunks(3) { session.digest_update(part)?; } - let have = session.digest_finalize()?; + let have = session.digest_final()?; let want = vec![ 0x8c, 0x18, 0xb1, 0x5f, 0x01, 0x47, 0x13, 0x2a, 0x03, 0xc2, 0xe3, 0xfd, 0x4f, 0x29, 0xb7, 0x75, 0x80, 0x19, 0xb5, 0x58, 0x5e, 0xfc, 0xeb, 0x45, 0x18, 0x33, 0x2b, 0x2f, 0xa7, 0xa4, @@ -1673,12 +1673,12 @@ fn sha256_digest_multipart_with_key() -> TestResult { }; // Digest data in parts - session.digest_initialize(&Mechanism::Sha256)?; + session.digest_init(&Mechanism::Sha256)?; session.digest_update(&data)?; session.digest_key(key)?; // Create digests to compare - let have = session.digest_finalize()?; + let have = session.digest_final()?; data.append(&mut key_data); let want = session.digest(&Mechanism::Sha256, &data)?; @@ -1713,7 +1713,7 @@ fn sha256_digest_multipart_not_initialized() -> TestResult { )); // Attempt to finalize digest without an operation having been initialized - let result = session.digest_finalize(); + let result = session.digest_final(); assert!(result.is_err()); assert!(matches!( @@ -1734,8 +1734,8 @@ fn sha256_digest_multipart_already_initialized() -> TestResult { session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // Initialize digesting operation twice in a row - session.digest_initialize(&Mechanism::Sha256)?; - let result = session.digest_initialize(&Mechanism::Sha256); + session.digest_init(&Mechanism::Sha256)?; + let result = session.digest_init(&Mechanism::Sha256); assert!(result.is_err()); assert!(matches!( From c96400c7fbc6c27fb876034fe721c59ae9bba2ac Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Fri, 28 Mar 2025 12:03:55 +0100 Subject: [PATCH 12/13] Fixed CI errors Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/tests/basic.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 98c431fa..82b6dd57 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -241,7 +241,7 @@ fn sign_verify_multipart() -> TestResult { )?; // Data to sign - let data = vec![0xFF, 0x55, 0xDD, 0x11, 0xBB, 0x33]; + let data = [0xFF, 0x55, 0xDD, 0x11, 0xBB, 0x33]; // Sign data in parts (standard RsaPkcs doesn't support this) session.sign_init(&Mechanism::Sha256RsaPkcs, priv_key)?; @@ -1621,7 +1621,7 @@ fn sha256_digest_multipart() -> TestResult { session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // Data to digest - let data = vec![ + let data = [ 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, ]; From 2639ed429d85681db4a5af915f6b0582e23ced0a Mon Sep 17 00:00:00 2001 From: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> Date: Fri, 28 Mar 2025 13:15:03 +0100 Subject: [PATCH 13/13] Fixed CI errors (again) Signed-off-by: Jacob Prud'homme <2160185+jacobprudhomme@users.noreply.github.com> --- cryptoki/src/session/digesting.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptoki/src/session/digesting.rs b/cryptoki/src/session/digesting.rs index 220bbfa8..fc0974d5 100644 --- a/cryptoki/src/session/digesting.rs +++ b/cryptoki/src/session/digesting.rs @@ -99,7 +99,7 @@ impl Session { } /// Finalizes ongoing multi-part digest operation, - /// returning the digest + /// returning the digest pub fn digest_final(&self) -> Result> { let mut digest_len = 0;