diff --git a/cryptoki/src/session/object_management.rs b/cryptoki/src/session/object_management.rs index 8009c63..6dcf84f 100644 --- a/cryptoki/src/session/object_management.rs +++ b/cryptoki/src/session/object_management.rs @@ -94,6 +94,42 @@ impl Session { } } + /// Copy an object + /// + /// A template can be provided to change some attributes of the new object, when allowed. + /// + /// # Arguments + /// + /// * `object` - The [ObjectHandle] used to reference the object to copy + /// * `template` - new values for any attributes of the object that can ordinarily be modified + /// check out [PKCS#11 documentation](https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/cs01/pkcs11-spec-v3.1-cs01.html#_Toc111203284) for details + /// + /// # Returns + /// + /// This function will return a new [ObjectHandle] that references the newly created object. + /// + pub fn copy_object( + &self, + object: ObjectHandle, + template: &[Attribute], + ) -> Result { + let mut template: Vec = template.iter().map(|attr| attr.into()).collect(); + let mut object_handle = 0; + + unsafe { + Rv::from(get_pkcs11!(self.client(), C_CopyObject)( + self.handle(), + object.handle(), + template.as_mut_ptr(), + template.len().try_into()?, + &mut object_handle as CK_OBJECT_HANDLE_PTR, + )) + .into_result(Function::CopyObject)?; + } + + Ok(ObjectHandle::new(object_handle)) + } + /// Get the attribute info of an object: if the attribute is present and its size. /// /// # Arguments diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 8bf2a58..02a83a6 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -893,6 +893,56 @@ fn ro_rw_session_test() -> TestResult { Ok(()) } +#[test] +#[serial] +fn session_copy_object() -> TestResult { + let aes128_template = [ + Attribute::Class(ObjectClass::SECRET_KEY), + Attribute::KeyType(KeyType::AES), + Attribute::Encrypt(true), + Attribute::Token(false), + Attribute::Private(true), + Attribute::Sensitive(true), + Attribute::Extractable(false), + Attribute::ValueLen(16.into()), + Attribute::Label("original".as_bytes().to_vec()), + ]; + + let copy_template = vec![Attribute::Label("copy".as_bytes().to_vec())]; + + let insecure_copy_template = vec![Attribute::Extractable(true)]; + + let (pkcs11, slot) = init_pins(); + + // open a session + let rw_session = pkcs11.open_rw_session(slot)?; + + // log in the session + rw_session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + // create a key object + let object = rw_session.generate_key(&Mechanism::AesKeyGen, &aes128_template)?; + + // copy the object without a template + let copy = rw_session.copy_object(object, &[])?; + rw_session.destroy_object(copy)?; + + // copy the object with a template + let copy = rw_session.copy_object(object, ©_template)?; + rw_session.destroy_object(copy)?; + + // try the copy with the insecure template. It should fail. Returning CKR_OK is considered a failure. + rw_session + .copy_object(object, &insecure_copy_template) + .unwrap_err(); + + // delete keys + rw_session.destroy_object(object)?; + rw_session.logout()?; + + Ok(()) +} + #[test] #[serial] fn aes_cbc_encrypt() -> TestResult {