cryptoki-0.6.1/.cargo_vcs_info.json0000644000000001460000000000100127050ustar { "git": { "sha1": "c7a6dbb9f0b86ff6a61d1527e7c217b830fb759c" }, "path_in_vcs": "cryptoki" }cryptoki-0.6.1/Cargo.toml0000644000000031620000000000100107040ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.66.0" name = "cryptoki" version = "0.6.1" authors = ["Contributors to the Parsec project"] description = "Rust-native wrapper around the PKCS #11 API" documentation = "https://docs.rs/crate/cryptoki" readme = "README.md" keywords = [ "pkcs11", "cryptoki", "hsm", ] categories = [ "api-bindings", "external-ffi-bindings", "cryptography", "hardware-support", ] license = "Apache-2.0" repository = "https://github.com/parallaxsecond/rust-cryptoki" [dependencies.bitflags] version = "1.3" [dependencies.cryptoki-sys] version = "0.1.7" [dependencies.libloading] version = "0.7.0" [dependencies.log] version = "0.4.14" [dependencies.paste] version = "1.0.6" [dependencies.psa-crypto] version = "0.12.0" optional = true default-features = false [dependencies.secrecy] version = "0.8.0" [dev-dependencies.hex] version = "0.4.3" [dev-dependencies.num-traits] version = "0.2.14" [dev-dependencies.serial_test] version = "0.5.1" [dev-dependencies.testresult] version = "0.2.0" [features] generate-bindings = ["cryptoki-sys/generate-bindings"] psa-crypto-conversions = ["psa-crypto"] serde = ["secrecy/serde"] cryptoki-0.6.1/Cargo.toml.orig000064400000000000000000000017011046102023000143620ustar 00000000000000[package] name = "cryptoki" version = "0.6.1" authors = ["Contributors to the Parsec project"] edition = '2018' description = "Rust-native wrapper around the PKCS #11 API" readme = "README.md" keywords = ["pkcs11", "cryptoki", "hsm"] categories = ["api-bindings", "external-ffi-bindings", "cryptography", "hardware-support"] license = "Apache-2.0" repository = "https://github.com/parallaxsecond/rust-cryptoki" documentation = "https://docs.rs/crate/cryptoki" rust-version = "1.66.0" [dependencies] bitflags = "1.3" libloading = "0.7.0" log = "0.4.14" psa-crypto = { version = "0.12.0", default-features = false, optional = true } cryptoki-sys = { path = "../cryptoki-sys", version = "0.1.7" } paste = "1.0.6" secrecy = "0.8.0" [dev-dependencies] num-traits = "0.2.14" hex = "0.4.3" serial_test = "0.5.1" testresult = "0.2.0" [features] psa-crypto-conversions = ["psa-crypto"] generate-bindings = ["cryptoki-sys/generate-bindings"] serde = ["secrecy/serde"] cryptoki-0.6.1/LICENSE000064400000000000000000000261361046102023000125110ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. cryptoki-0.6.1/README.md000064400000000000000000000006241046102023000127550ustar 00000000000000# Cryptoki Rust Wrapper

Crates.io Code documentation

This is the high-level, Rust idiomatic wrapper crate for PKCS #11. *Copyright 2021 Contributors to the Parsec project.* cryptoki-0.6.1/src/context/general_purpose.rs000064400000000000000000000157201046102023000175140ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! General-purpose functions use crate::context::{CInitializeArgs, Info, Pkcs11}; use crate::error::{Result, Rv}; use cryptoki_sys::{CK_C_INITIALIZE_ARGS, CK_INFO}; use paste::paste; use std::convert::TryFrom; // See public docs on stub in parent mod.rs #[inline(always)] pub(super) fn initialize(ctx: &Pkcs11, init_args: CInitializeArgs) -> Result<()> { // if no args are specified, library expects NULL let mut init_args = CK_C_INITIALIZE_ARGS::from(init_args); let init_args_ptr = &mut init_args; unsafe { Rv::from(get_pkcs11!(ctx, C_Initialize)( init_args_ptr as *mut CK_C_INITIALIZE_ARGS as *mut ::std::ffi::c_void, )) .into_result() } } // See public docs on stub in parent mod.rs #[inline(always)] pub(super) fn get_library_info(ctx: &Pkcs11) -> Result { let mut info = CK_INFO::default(); unsafe { Rv::from(get_pkcs11!(ctx, C_GetInfo)(&mut info)).into_result()?; Info::try_from(info) } } macro_rules! check_fn { ($pkcs11:expr, $func_name:ident) => {{ let func = paste! { $pkcs11 .impl_ .function_list .[] }; func.is_some() }}; } #[allow(missing_docs)] #[derive(Debug, Copy, Clone)] /// Enumeration of all functions defined by the PKCS11 spec pub enum Function { Initialize, Finalize, GetInfo, GetFunctionList, GetSlotList, GetSlotInfo, GetTokenInfo, GetMechanismList, GetMechanismInfo, InitToken, InitPIN, SetPIN, OpenSession, CloseSession, CloseAllSessions, GetSessionInfo, GetOperationState, SetOperationState, Login, Logout, CreateObject, CopyObject, DestroyObject, GetObjectSize, GetAttributeValue, SetAttributeValue, FindObjectsInit, FindObjects, FindObjectsFinal, EncryptInit, Encrypt, EncryptUpdate, EncryptFinal, DecryptInit, Decrypt, DecryptUpdate, DecryptFinal, DigestInit, Digest, DigestUpdate, DigestKey, DigestFinal, SignInit, Sign, SignUpdate, SignFinal, SignRecoverInit, SignRecover, VerifyInit, Verify, VerifyUpdate, VerifyFinal, VerifyRecoverInit, VerifyRecover, DigestEncryptUpdate, DecryptDigestUpdate, SignEncryptUpdate, DecryptVerifyUpdate, GenerateKey, GenerateKeyPair, WrapKey, UnwrapKey, DeriveKey, SeedRandom, GenerateRandom, GetFunctionStatus, CancelFunction, WaitForSlotEvent, } #[inline(always)] pub(super) fn is_fn_supported(ctx: &Pkcs11, function: Function) -> bool { match function { Function::Initialize => check_fn!(ctx, Initialize), Function::Finalize => check_fn!(ctx, Finalize), Function::GetInfo => check_fn!(ctx, GetInfo), Function::GetFunctionList => check_fn!(ctx, GetFunctionList), Function::GetSlotList => check_fn!(ctx, GetSlotList), Function::GetSlotInfo => check_fn!(ctx, GetSlotInfo), Function::GetTokenInfo => check_fn!(ctx, GetTokenInfo), Function::GetMechanismList => check_fn!(ctx, GetMechanismList), Function::GetMechanismInfo => check_fn!(ctx, GetMechanismInfo), Function::InitToken => check_fn!(ctx, InitToken), Function::InitPIN => check_fn!(ctx, InitPIN), Function::SetPIN => check_fn!(ctx, SetPIN), Function::OpenSession => check_fn!(ctx, OpenSession), Function::CloseSession => check_fn!(ctx, CloseSession), Function::CloseAllSessions => check_fn!(ctx, CloseAllSessions), Function::GetSessionInfo => check_fn!(ctx, GetSessionInfo), Function::GetOperationState => check_fn!(ctx, GetOperationState), Function::SetOperationState => check_fn!(ctx, SetOperationState), Function::Login => check_fn!(ctx, Login), Function::Logout => check_fn!(ctx, Logout), Function::CreateObject => check_fn!(ctx, CreateObject), Function::CopyObject => check_fn!(ctx, CopyObject), Function::DestroyObject => check_fn!(ctx, DestroyObject), Function::GetObjectSize => check_fn!(ctx, GetObjectSize), Function::GetAttributeValue => check_fn!(ctx, GetAttributeValue), Function::SetAttributeValue => check_fn!(ctx, SetAttributeValue), Function::FindObjectsInit => check_fn!(ctx, FindObjectsInit), Function::FindObjects => check_fn!(ctx, FindObjects), Function::FindObjectsFinal => check_fn!(ctx, FindObjectsFinal), Function::EncryptInit => check_fn!(ctx, EncryptInit), Function::Encrypt => check_fn!(ctx, Encrypt), Function::EncryptUpdate => check_fn!(ctx, EncryptUpdate), Function::EncryptFinal => check_fn!(ctx, EncryptFinal), Function::DecryptInit => check_fn!(ctx, DecryptInit), Function::Decrypt => check_fn!(ctx, Decrypt), Function::DecryptUpdate => check_fn!(ctx, DecryptUpdate), Function::DecryptFinal => check_fn!(ctx, DecryptFinal), Function::DigestInit => check_fn!(ctx, DigestInit), Function::Digest => check_fn!(ctx, Digest), Function::DigestUpdate => check_fn!(ctx, DigestUpdate), Function::DigestKey => check_fn!(ctx, DigestKey), Function::DigestFinal => check_fn!(ctx, DigestFinal), Function::SignInit => check_fn!(ctx, SignInit), Function::Sign => check_fn!(ctx, Sign), Function::SignUpdate => check_fn!(ctx, SignUpdate), Function::SignFinal => check_fn!(ctx, SignFinal), Function::SignRecoverInit => check_fn!(ctx, SignRecoverInit), Function::SignRecover => check_fn!(ctx, SignRecover), Function::VerifyInit => check_fn!(ctx, VerifyInit), Function::Verify => check_fn!(ctx, Verify), Function::VerifyUpdate => check_fn!(ctx, VerifyUpdate), Function::VerifyFinal => check_fn!(ctx, VerifyFinal), Function::VerifyRecoverInit => check_fn!(ctx, VerifyRecoverInit), Function::VerifyRecover => check_fn!(ctx, VerifyRecover), Function::DigestEncryptUpdate => check_fn!(ctx, DigestEncryptUpdate), Function::DecryptDigestUpdate => check_fn!(ctx, DecryptDigestUpdate), Function::SignEncryptUpdate => check_fn!(ctx, SignEncryptUpdate), Function::DecryptVerifyUpdate => check_fn!(ctx, DecryptVerifyUpdate), Function::GenerateKey => check_fn!(ctx, GenerateKey), Function::GenerateKeyPair => check_fn!(ctx, GenerateKeyPair), Function::WrapKey => check_fn!(ctx, WrapKey), Function::UnwrapKey => check_fn!(ctx, UnwrapKey), Function::DeriveKey => check_fn!(ctx, DeriveKey), Function::SeedRandom => check_fn!(ctx, SeedRandom), Function::GenerateRandom => check_fn!(ctx, GenerateRandom), Function::GetFunctionStatus => check_fn!(ctx, GetFunctionStatus), Function::CancelFunction => check_fn!(ctx, CancelFunction), Function::WaitForSlotEvent => check_fn!(ctx, WaitForSlotEvent), } } cryptoki-0.6.1/src/context/info.rs000064400000000000000000000034741046102023000152600ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! PKCS11 library information use crate::error::{Error, Result}; use crate::string_from_blank_padded; use crate::types::Version; use cryptoki_sys::*; use std::convert::TryFrom; #[derive(Debug, Clone)] /// General information about the Cryptoki (PKCS#11 library) pub struct Info { cryptoki_version: Version, manufacturer_id: String, // flags library_description: String, library_version: Version, } impl Info { /// Returns the version of Cryptoki interface for compatibility with future /// revisions pub fn cryptoki_version(&self) -> Version { self.cryptoki_version } /// ID of the Cryptoki library manufacturer /// /// **[Conformance](crate#conformance-notes):** /// This string is maximally 32 bytes (*not* chars) as UTF-8 pub fn manufacturer_id(&self) -> &str { &self.manufacturer_id } /// Description of the library /// /// **[Conformance](crate#conformance-notes):** /// This string is maximally 32 bytes (*not* chars) as UTF-8 pub fn library_description(&self) -> &str { &self.library_description } /// Cryptoki library version number pub fn library_version(&self) -> Version { self.library_version } } #[doc(hidden)] impl TryFrom for Info { type Error = Error; fn try_from(val: CK_INFO) -> Result { if val.flags != 0 { return Err(Error::InvalidValue); } Ok(Self { cryptoki_version: val.cryptokiVersion.into(), manufacturer_id: string_from_blank_padded(&val.manufacturerID), library_description: string_from_blank_padded(&val.libraryDescription), library_version: val.libraryVersion.into(), }) } } cryptoki-0.6.1/src/context/locking.rs000064400000000000000000000020541046102023000157440ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Locking related type use cryptoki_sys::{CKF_OS_LOCKING_OK, CK_FLAGS}; use std::ptr; /// Argument for the initialize function #[derive(Copy, Clone, Debug)] pub enum CInitializeArgs { /// The library can use the native OS library for locking OsThreads, // TODO: add variants for custom mutexes here and no multithreading, safety implications for // that. } impl From for cryptoki_sys::CK_C_INITIALIZE_ARGS { fn from(c_initialize_args: CInitializeArgs) -> Self { let mut flags = CK_FLAGS::default(); match c_initialize_args { CInitializeArgs::OsThreads => { flags |= CKF_OS_LOCKING_OK; Self { flags, CreateMutex: None, DestroyMutex: None, LockMutex: None, UnlockMutex: None, pReserved: ptr::null_mut(), } } } } } cryptoki-0.6.1/src/context/mod.rs000064400000000000000000000076471046102023000151120ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Pkcs11 context and initialization types /// Directly get the PKCS #11 operation from the context structure and check for null pointers. macro_rules! get_pkcs11 { ($pkcs11:expr, $func_name:ident) => { ($pkcs11 .impl_ .function_list .$func_name .ok_or(crate::error::Error::NullFunctionPointer)?) }; } mod general_purpose; mod info; mod locking; mod session_management; mod slot_token_management; pub use general_purpose::*; pub use info::*; pub use locking::*; use crate::error::{Error, Result, Rv}; use log::error; use std::fmt; use std::mem; use std::path::Path; use std::ptr; use std::sync::Arc; use std::sync::RwLock; // Implementation of Pkcs11 class that can be enclosed in a single Arc pub(crate) struct Pkcs11Impl { // Even if this field is never read, it is needed for the pointers in function_list to remain // valid. _pkcs11_lib: cryptoki_sys::Pkcs11, pub(crate) function_list: cryptoki_sys::_CK_FUNCTION_LIST, } impl fmt::Debug for Pkcs11Impl { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Pkcs11Impl") .field("function_list", &self.function_list) .finish() } } impl Pkcs11Impl { // Private finalize call #[inline(always)] fn finalize(&self) -> Result<()> { unsafe { Rv::from(self .function_list .C_Finalize .ok_or(Error::NullFunctionPointer)?( ptr::null_mut() )) .into_result() } } } impl Drop for Pkcs11Impl { fn drop(&mut self) { if let Err(e) = self.finalize() { error!("Failed to finalize: {}", e); } } } /// Main PKCS11 context. Should usually be unique per application. #[derive(Clone, Debug)] pub struct Pkcs11 { pub(crate) impl_: Arc, initialized: Arc>, } impl Pkcs11 { /// Instantiate a new context from the path of a PKCS11 dynamic library implementation. pub fn new

(filename: P) -> Result where P: AsRef, { unsafe { let pkcs11_lib = cryptoki_sys::Pkcs11::new(filename.as_ref()).map_err(Error::LibraryLoading)?; let mut list = mem::MaybeUninit::uninit(); Rv::from(pkcs11_lib.C_GetFunctionList(list.as_mut_ptr())).into_result()?; let list_ptr = *list.as_ptr(); Ok(Pkcs11 { impl_: Arc::new(Pkcs11Impl { _pkcs11_lib: pkcs11_lib, function_list: *list_ptr, }), initialized: Arc::new(RwLock::new(false)), }) } } /// Initialize the PKCS11 library pub fn initialize(&self, init_args: CInitializeArgs) -> Result<()> { let mut init_lock = self .initialized .as_ref() .write() .expect("lock not to be poisoned"); if *init_lock { Err(Error::AlreadyInitialized)? } initialize(self, init_args).map(|_| *init_lock = true) } /// Check whether the PKCS11 library has been initialized pub fn is_initialized(&self) -> bool { *self .initialized .as_ref() .read() .expect("lock not to be poisoned") } /// Finalize the PKCS11 library. Indicates that the application no longer needs to use PKCS11. /// The library is also automatically finalized on drop. pub fn finalize(self) {} /// Returns the information about the library pub fn get_library_info(&self) -> Result { get_library_info(self) } /// Check whether a given PKCS11 spec-defined function is supported by this implementation pub fn is_fn_supported(&self, function: Function) -> bool { is_fn_supported(self, function) } } cryptoki-0.6.1/src/context/session_management.rs000064400000000000000000000030321046102023000201720ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Session management functions use cryptoki_sys::{CKF_RW_SESSION, CKF_SERIAL_SESSION}; use crate::context::Pkcs11; use crate::error::{Result, Rv}; use crate::session::Session; use crate::slot::Slot; use std::convert::TryInto; impl Pkcs11 { #[inline(always)] fn open_session(&self, slot_id: Slot, read_write: bool) -> Result { let mut session_handle = 0; let flags = if read_write { CKF_SERIAL_SESSION | CKF_RW_SESSION } else { CKF_SERIAL_SESSION }; unsafe { Rv::from(get_pkcs11!(self, C_OpenSession)( slot_id.try_into()?, flags, // TODO: abstract those types or create new functions for callbacks std::ptr::null_mut(), None, &mut session_handle, )) .into_result()?; } Ok(Session::new(session_handle, self.clone())) } /// Open a new Read-Only session /// /// For a Read-Write session, use `open_rw_session` /// /// Note: No callback is set when opening the session. pub fn open_ro_session(&self, slot_id: Slot) -> Result { self.open_session(slot_id, false) } /// Open a new Read/Write session /// /// Note: No callback is set when opening the session. pub fn open_rw_session(&self, slot_id: Slot) -> Result { self.open_session(slot_id, true) } } cryptoki-0.6.1/src/context/slot_token_management.rs000064400000000000000000000146041046102023000206770ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Slot and token management functions use crate::error::{Result, Rv}; use crate::label_from_str; use crate::mechanism::{MechanismInfo, MechanismType}; use crate::slot::{Slot, SlotInfo, TokenInfo}; use crate::types::AuthPin; use crate::{ context::Pkcs11, error::{Error, RvError}, }; use cryptoki_sys::{ CKF_DONT_BLOCK, CK_BBOOL, CK_FALSE, CK_FLAGS, CK_MECHANISM_INFO, CK_SLOT_ID, CK_SLOT_INFO, CK_TOKEN_INFO, CK_TRUE, }; use secrecy::ExposeSecret; use std::convert::{TryFrom, TryInto}; use crate::error::RvError::BufferTooSmall; impl Pkcs11 { #[inline(always)] fn get_slots(&self, with_token: CK_BBOOL) -> Result> { let mut slot_count = 0; let rval = unsafe { get_pkcs11!(self, C_GetSlotList)(with_token, std::ptr::null_mut(), &mut slot_count) }; Rv::from(rval).into_result()?; let mut slots; loop { slots = vec![0; slot_count as usize]; let rval = unsafe { get_pkcs11!(self, C_GetSlotList)(with_token, slots.as_mut_ptr(), &mut slot_count) }; // Account for a race condition between the call to get the // slot_count and the last call in which the number of slots grew. // In this case, slot_count will have been updated to the larger amount // and we want to loop again with a resized buffer. if !matches!(Rv::from(rval), Rv::Error(BufferTooSmall)) { // Account for other possible error types Rv::from(rval).into_result()?; // Otherwise, we have a valid list to process break; } } // Account for the same race condition, but with a shrinking slot_count slots.truncate(slot_count as usize); Ok(slots.into_iter().map(Slot::new).collect()) } /// Get all slots available with a token pub fn get_slots_with_token(&self) -> Result> { self.get_slots(CK_TRUE) } /// Get all slots pub fn get_all_slots(&self) -> Result> { self.get_slots(CK_FALSE) } /// Get all slots available with a token pub fn get_slots_with_initialized_token(&self) -> Result> { let slots = self.get_slots_with_token()?; slots .into_iter() .filter_map(|slot| match self.get_token_info(slot) { Ok(token_info) => { if token_info.token_initialized() { Some(Ok(slot)) } else { None } } Err(e) => Some(Err(e)), }) .collect() } /// Initialize a token /// /// Currently will use an empty label for all tokens. pub fn init_token(&self, slot: Slot, pin: &AuthPin, label: &str) -> Result<()> { let label = label_from_str(label); unsafe { Rv::from(get_pkcs11!(self, C_InitToken)( slot.try_into()?, pin.expose_secret().as_ptr() as *mut u8, pin.expose_secret().len().try_into()?, label.as_ptr() as *mut u8, )) .into_result() } } /// Returns the slot info pub fn get_slot_info(&self, slot: Slot) -> Result { unsafe { let mut slot_info = CK_SLOT_INFO::default(); Rv::from(get_pkcs11!(self, C_GetSlotInfo)( slot.try_into()?, &mut slot_info, )) .into_result()?; Ok(SlotInfo::from(slot_info)) } } /// Returns information about a specific token pub fn get_token_info(&self, slot: Slot) -> Result { unsafe { let mut token_info = CK_TOKEN_INFO::default(); Rv::from(get_pkcs11!(self, C_GetTokenInfo)( slot.try_into()?, &mut token_info, )) .into_result()?; TokenInfo::try_from(token_info) } } /// Get all mechanisms support by a slot pub fn get_mechanism_list(&self, slot: Slot) -> Result> { let mut mechanism_count = 0; unsafe { Rv::from(get_pkcs11!(self, C_GetMechanismList)( slot.try_into()?, std::ptr::null_mut(), &mut mechanism_count, )) .into_result()?; } let mut mechanisms = vec![0; mechanism_count.try_into()?]; unsafe { Rv::from(get_pkcs11!(self, C_GetMechanismList)( slot.try_into()?, mechanisms.as_mut_ptr(), &mut mechanism_count, )) .into_result()?; } // Truncate mechanisms if count decreased. mechanisms.truncate(mechanism_count.try_into()?); Ok(mechanisms .into_iter() .filter_map(|type_| type_.try_into().ok()) .collect()) } /// Get detailed information about a mechanism for a slot pub fn get_mechanism_info(&self, slot: Slot, type_: MechanismType) -> Result { unsafe { let mut mechanism_info = CK_MECHANISM_INFO::default(); Rv::from(get_pkcs11!(self, C_GetMechanismInfo)( slot.try_into()?, type_.into(), &mut mechanism_info, )) .into_result()?; Ok(MechanismInfo::from(mechanism_info)) } } fn wait_for_slot_event_impl(&self, flags: CK_FLAGS) -> Result { unsafe { let mut slot: CK_SLOT_ID = 0; let wait_for_slot_event = get_pkcs11!(self, C_WaitForSlotEvent); let rv = wait_for_slot_event(flags, &mut slot, std::ptr::null_mut()); Rv::from(rv).into_result()?; Ok(Slot::new(slot)) } } /// Wait for slot events (insertion or removal of a token) pub fn wait_for_slot_event(&self) -> Result { self.wait_for_slot_event_impl(0) } /// Get the latest slot event (insertion or removal of a token) pub fn get_slot_event(&self) -> Result> { match self.wait_for_slot_event_impl(CKF_DONT_BLOCK) { Err(Error::Pkcs11(RvError::NoEvent)) => Ok(None), Ok(slot) => Ok(Some(slot)), Err(x) => Err(x), } } } cryptoki-0.6.1/src/error/mod.rs000064400000000000000000000104531046102023000145440ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Pkcs11 return codes and crate Result/Error types mod rv; mod rv_error; pub use rv::*; pub use rv_error::*; use std::fmt; #[derive(Debug)] /// Main error type pub enum Error { /// Any error that happens during library loading of the PKCS#11 module is encompassed under /// this error. It is a direct forward of the underlying error from libloading. LibraryLoading(libloading::Error), /// All PKCS#11 functions that return non-zero translate to this error. Pkcs11(RvError), /// This error marks a feature that is not yet supported by the PKCS11 Rust abstraction layer. NotSupported, /// Error happening while converting types TryFromInt(std::num::TryFromIntError), /// Error when converting a slice to an array TryFromSlice(std::array::TryFromSliceError), /// Error when converting a numerical str to an integral value ParseInt(core::num::ParseIntError), /// Error converting into a type assuming valid UTF-8 Utf8(std::str::Utf8Error), /// Error with nul characters in Strings NulError(std::ffi::NulError), /// Calling a PKCS11 function that is a NULL function pointer. NullFunctionPointer, /// The value is not one of those expected. InvalidValue, /// The PIN was not set before logging in. PinNotSet, /// The PKCS11 library has already been initialized AlreadyInitialized, } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::LibraryLoading(e) => write!(f, "libloading error ({e})"), Error::Pkcs11(e) => write!(f, "PKCS11 error: {e}"), Error::NotSupported => write!(f, "Feature not supported"), Error::TryFromInt(e) => write!(f, "Conversion between integers failed ({e})"), Error::TryFromSlice(e) => write!(f, "Error converting slice to array ({e})"), Error::ParseInt(e) => write!(f, "Error parsing string as integer ({e})"), Error::Utf8(e) => write!(f, "Invalid UTF-8 ({e})"), Error::NulError(e) => write!(f, "An interior nul byte was found ({e})"), Error::NullFunctionPointer => write!(f, "Calling a NULL function pointer"), Error::InvalidValue => write!(f, "The value is not one of the expected options"), Error::PinNotSet => write!(f, "Pin has not been set before trying to log in"), Error::AlreadyInitialized => write!(f, "PKCS11 library has already been initialized"), } } } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Error::LibraryLoading(e) => Some(e), Error::TryFromInt(e) => Some(e), Error::TryFromSlice(e) => Some(e), Error::ParseInt(e) => Some(e), Error::Utf8(e) => Some(e), Error::NulError(e) => Some(e), Error::Pkcs11(_) | Error::NotSupported | Error::NullFunctionPointer | Error::PinNotSet | Error::InvalidValue | Error::AlreadyInitialized => None, } } } impl From for Error { fn from(err: libloading::Error) -> Error { Error::LibraryLoading(err) } } impl From for Error { fn from(err: std::num::TryFromIntError) -> Error { Error::TryFromInt(err) } } impl From for Error { fn from(err: std::array::TryFromSliceError) -> Error { Error::TryFromSlice(err) } } impl From for Error { fn from(err: core::num::ParseIntError) -> Error { Error::ParseInt(err) } } impl From for Error { fn from(err: std::str::Utf8Error) -> Error { Error::Utf8(err) } } impl From for Error { fn from(err: std::ffi::NulError) -> Error { Error::NulError(err) } } impl From for Error { fn from(_err: std::convert::Infallible) -> Error { unreachable!() } } impl From for Error { fn from(rv_error: RvError) -> Self { Error::Pkcs11(rv_error) } } /// Main Result type pub type Result = core::result::Result; cryptoki-0.6.1/src/error/rv.rs000064400000000000000000000200431046102023000144100ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Function types use super::{Error, Result, RvError}; use cryptoki_sys::*; use log::error; #[derive(Copy, Clone, Debug)] /// Return value of a PKCS11 function pub enum Rv { /// The function exited successfully Ok, /// There was an error Error(RvError), } impl From for Rv { fn from(ck_rv: CK_RV) -> Self { match ck_rv { CKR_OK => Rv::Ok, CKR_CANCEL => Rv::Error(RvError::Cancel), CKR_HOST_MEMORY => Rv::Error(RvError::HostMemory), CKR_SLOT_ID_INVALID => Rv::Error(RvError::SlotIdInvalid), CKR_GENERAL_ERROR => Rv::Error(RvError::GeneralError), CKR_FUNCTION_FAILED => Rv::Error(RvError::FunctionFailed), CKR_ARGUMENTS_BAD => Rv::Error(RvError::ArgumentsBad), CKR_NO_EVENT => Rv::Error(RvError::NoEvent), CKR_NEED_TO_CREATE_THREADS => Rv::Error(RvError::NeedToCreateThreads), CKR_CANT_LOCK => Rv::Error(RvError::CantLock), CKR_ATTRIBUTE_READ_ONLY => Rv::Error(RvError::AttributeReadOnly), CKR_ATTRIBUTE_SENSITIVE => Rv::Error(RvError::AttributeSensitive), CKR_ATTRIBUTE_TYPE_INVALID => Rv::Error(RvError::AttributeTypeInvalid), CKR_ATTRIBUTE_VALUE_INVALID => Rv::Error(RvError::AttributeValueInvalid), CKR_ACTION_PROHIBITED => Rv::Error(RvError::ActionProhibited), CKR_DATA_INVALID => Rv::Error(RvError::DataInvalid), CKR_DATA_LEN_RANGE => Rv::Error(RvError::DataLenRange), CKR_DEVICE_ERROR => Rv::Error(RvError::DeviceError), CKR_DEVICE_MEMORY => Rv::Error(RvError::DeviceMemory), CKR_DEVICE_REMOVED => Rv::Error(RvError::DeviceRemoved), CKR_ENCRYPTED_DATA_INVALID => Rv::Error(RvError::EncryptedDataInvalid), CKR_ENCRYPTED_DATA_LEN_RANGE => Rv::Error(RvError::EncryptedDataLenRange), CKR_FUNCTION_CANCELED => Rv::Error(RvError::FunctionCanceled), CKR_FUNCTION_NOT_PARALLEL => Rv::Error(RvError::FunctionNotParallel), CKR_FUNCTION_NOT_SUPPORTED => Rv::Error(RvError::FunctionNotSupported), CKR_CURVE_NOT_SUPPORTED => Rv::Error(RvError::CurveNotSupported), CKR_KEY_HANDLE_INVALID => Rv::Error(RvError::KeyHandleInvalid), CKR_KEY_SIZE_RANGE => Rv::Error(RvError::KeySizeRange), CKR_KEY_TYPE_INCONSISTENT => Rv::Error(RvError::KeyTypeInconsistent), CKR_KEY_NOT_NEEDED => Rv::Error(RvError::KeyNotNeeded), CKR_KEY_CHANGED => Rv::Error(RvError::KeyChanged), CKR_KEY_NEEDED => Rv::Error(RvError::KeyNeeded), CKR_KEY_INDIGESTIBLE => Rv::Error(RvError::KeyIndigestible), CKR_KEY_FUNCTION_NOT_PERMITTED => Rv::Error(RvError::KeyFunctionNotPermitted), CKR_KEY_NOT_WRAPPABLE => Rv::Error(RvError::KeyNotWrappable), CKR_KEY_UNEXTRACTABLE => Rv::Error(RvError::KeyUnextractable), CKR_MECHANISM_INVALID => Rv::Error(RvError::MechanismInvalid), CKR_MECHANISM_PARAM_INVALID => Rv::Error(RvError::MechanismParamInvalid), CKR_OBJECT_HANDLE_INVALID => Rv::Error(RvError::ObjectHandleInvalid), CKR_OPERATION_ACTIVE => Rv::Error(RvError::OperationActive), CKR_OPERATION_NOT_INITIALIZED => Rv::Error(RvError::OperationNotInitialized), CKR_PIN_INCORRECT => Rv::Error(RvError::PinIncorrect), CKR_PIN_INVALID => Rv::Error(RvError::PinInvalid), CKR_PIN_LEN_RANGE => Rv::Error(RvError::PinLenRange), CKR_PIN_EXPIRED => Rv::Error(RvError::PinExpired), CKR_PIN_LOCKED => Rv::Error(RvError::PinLocked), CKR_SESSION_CLOSED => Rv::Error(RvError::SessionClosed), CKR_SESSION_COUNT => Rv::Error(RvError::SessionCount), CKR_SESSION_HANDLE_INVALID => Rv::Error(RvError::SessionHandleInvalid), CKR_SESSION_PARALLEL_NOT_SUPPORTED => Rv::Error(RvError::SessionParallelNotSupported), CKR_SESSION_READ_ONLY => Rv::Error(RvError::SessionReadOnly), CKR_SESSION_EXISTS => Rv::Error(RvError::SessionExists), CKR_SESSION_READ_ONLY_EXISTS => Rv::Error(RvError::SessionReadOnlyExists), CKR_SESSION_READ_WRITE_SO_EXISTS => Rv::Error(RvError::SessionReadWriteSoExists), CKR_SIGNATURE_INVALID => Rv::Error(RvError::SignatureInvalid), CKR_SIGNATURE_LEN_RANGE => Rv::Error(RvError::SignatureLenRange), CKR_TEMPLATE_INCOMPLETE => Rv::Error(RvError::TemplateIncomplete), CKR_TEMPLATE_INCONSISTENT => Rv::Error(RvError::TemplateInconsistent), CKR_TOKEN_NOT_PRESENT => Rv::Error(RvError::TokenNotPresent), CKR_TOKEN_NOT_RECOGNIZED => Rv::Error(RvError::TokenNotRecognized), CKR_TOKEN_WRITE_PROTECTED => Rv::Error(RvError::TokenWriteProtected), CKR_UNWRAPPING_KEY_HANDLE_INVALID => Rv::Error(RvError::UnwrappingKeyHandleInvalid), CKR_UNWRAPPING_KEY_SIZE_RANGE => Rv::Error(RvError::UnwrappingKeySizeRange), CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT => { Rv::Error(RvError::UnwrappingKeyTypeInconsistent) } CKR_USER_ALREADY_LOGGED_IN => Rv::Error(RvError::UserAlreadyLoggedIn), CKR_USER_NOT_LOGGED_IN => Rv::Error(RvError::UserNotLoggedIn), CKR_USER_PIN_NOT_INITIALIZED => Rv::Error(RvError::UserPinNotInitialized), CKR_USER_TYPE_INVALID => Rv::Error(RvError::UserTypeInvalid), CKR_USER_ANOTHER_ALREADY_LOGGED_IN => Rv::Error(RvError::UserAnotherAlreadyLoggedIn), CKR_USER_TOO_MANY_TYPES => Rv::Error(RvError::UserTooManyTypes), CKR_WRAPPED_KEY_INVALID => Rv::Error(RvError::WrappedKeyInvalid), CKR_WRAPPED_KEY_LEN_RANGE => Rv::Error(RvError::WrappedKeyLenRange), CKR_WRAPPING_KEY_HANDLE_INVALID => Rv::Error(RvError::WrappingKeyHandleInvalid), CKR_WRAPPING_KEY_SIZE_RANGE => Rv::Error(RvError::WrappingKeySizeRange), CKR_WRAPPING_KEY_TYPE_INCONSISTENT => Rv::Error(RvError::WrappingKeyTypeInconsistent), CKR_RANDOM_SEED_NOT_SUPPORTED => Rv::Error(RvError::RandomSeedNotSupported), CKR_RANDOM_NO_RNG => Rv::Error(RvError::RandomNoRng), CKR_DOMAIN_PARAMS_INVALID => Rv::Error(RvError::DomainParamsInvalid), CKR_BUFFER_TOO_SMALL => Rv::Error(RvError::BufferTooSmall), CKR_SAVED_STATE_INVALID => Rv::Error(RvError::SavedStateInvalid), CKR_INFORMATION_SENSITIVE => Rv::Error(RvError::InformationSensitive), CKR_STATE_UNSAVEABLE => Rv::Error(RvError::StateUnsaveable), CKR_CRYPTOKI_NOT_INITIALIZED => Rv::Error(RvError::CryptokiNotInitialized), CKR_CRYPTOKI_ALREADY_INITIALIZED => Rv::Error(RvError::CryptokiAlreadyInitialized), CKR_MUTEX_BAD => Rv::Error(RvError::MutexBad), CKR_MUTEX_NOT_LOCKED => Rv::Error(RvError::MutexNotLocked), CKR_NEW_PIN_MODE => Rv::Error(RvError::NewPinMode), CKR_NEXT_OTP => Rv::Error(RvError::NextOtp), CKR_EXCEEDED_MAX_ITERATIONS => Rv::Error(RvError::ExceededMaxIterations), CKR_FIPS_SELF_TEST_FAILED => Rv::Error(RvError::FipsSelfTestFailed), CKR_LIBRARY_LOAD_FAILED => Rv::Error(RvError::LibraryLoadFailed), CKR_PIN_TOO_WEAK => Rv::Error(RvError::PinTooWeak), CKR_PUBLIC_KEY_INVALID => Rv::Error(RvError::PublicKeyInvalid), CKR_FUNCTION_REJECTED => Rv::Error(RvError::FunctionRejected), CKR_VENDOR_DEFINED => Rv::Error(RvError::VendorDefined), other => { error!( "Can not find a corresponding error for {}, converting to GeneralError.", other ); Rv::Error(RvError::GeneralError) } } } } impl Rv { /// Convert the return value into a standard Result type pub fn into_result(self) -> Result<()> { match self { Rv::Ok => Ok(()), Rv::Error(rv_error) => Err(Error::Pkcs11(rv_error)), } } } cryptoki-0.6.1/src/error/rv_error.rs000064400000000000000000001373031046102023000156310ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Function types use std::fmt; #[derive(Debug, Copy, Clone, PartialEq, Eq)] /// Description of a return value error pub enum RvError { /// When a function executing in serial with an application decides to give the application a chance to do some work, it calls an application-supplied function with a CKN_SURRENDER callback (see Section 5.16). If the callback returns the value CKR_CANCEL, then the function aborts and returns CKR_FUNCTION_CANCELED. Cancel, /// The computer that the Cryptoki library is running on has insufficient memory to perform the requested function. HostMemory, /// The specified slot ID is not valid. SlotIdInvalid, /// Some horrible, unrecoverable error has occurred. In the worst case, it is possible that the function only partially succeeded, and that the computer and/or token is in an inconsistent state. GeneralError, /// The requested function could not be performed, but detailed information about why not is not available in this error return. If the failed function uses a session, it is possible that the CK_SESSION_INFO structure that can be obtained by calling C_GetSessionInfo will hold useful information about what happened in its ulDeviceError field. In any event, although the function call failed, the situation is not necessarily totally hopeless, as it is likely to be when CKR_GENERAL_ERROR is returned. Depending on what the root cause of the error actually was, it is possible that an attempt to make the exact same function call again would succeed. FunctionFailed, /// This is a rather generic error code which indicates that the arguments supplied to the Cryptoki function were in some way not appropriate. ArgumentsBad, /// This value can only be returned by C_GetSlotEvent. It is returned when C_GetSlotEvent is called in non-blocking mode and there are no new slot events to return. NoEvent, /// This value can only be returned by C_Initialize. It is returned when two conditions hold: 1. The application called C_Initialize in a way which tells the Cryptoki library that application threads executing calls to the library cannot use native operating system methods to spawn new threads. 2. The library cannot function properly without being able to spawn new threads in the above fashion. NeedToCreateThreads, /// This value can only be returned by C_Initialize. It means that the type of locking requested by the application for thread-safety is not available in this library, and so the application cannot make use of this library in the specified fashion. CantLock, /// An attempt was made to set a value for an attribute which may not be set by the application, or which may not be modified by the application. See Section 4.1 for more information. AttributeReadOnly, /// An attempt was made to obtain the value of an attribute of an object which cannot be satisfied because the object is either sensitive or un-extractable. AttributeSensitive, /// An invalid attribute type was specified in a template. See Section 4.1 for more information. AttributeTypeInvalid, /// An invalid value was specified for a particular attribute in a template. See Section 4.1 for more information. AttributeValueInvalid, /// This value can only be returned by C_CopyObject, C_SetAttributeValue and C_DestroyObject. It denotes that the action may not be taken, either because of underlying policy restrictions on the token, or because the object has the the relevant CKA_COPYABLE, CKA_MODIFIABLE or CKA_DESTROYABLE policy attribute set to CK_FALSE. ActionProhibited, /// The plaintext input data to a cryptographic operation is invalid. This return value has lower priority than CKR_DATA_LEN_RANGE. DataInvalid, /// The plaintext input data to a cryptographic operation has a bad length. Depending on the operation’s mechanism, this could mean that the plaintext data is too short, too long, or is not a multiple of some particular block size. This return value has higher priority than CKR_DATA_INVALID. DataLenRange, /// Some problem has occurred with the token and/or slot. This error code can be returned by more than just the functions mentioned above; in particular, it is possible for C_GetSlotInfo to return CKR_DEVICE_ERROR. DeviceError, /// The token does not have sufficient memory to perform the requested function. DeviceMemory, /// The token was removed from its slot during the execution of the function. DeviceRemoved, /// The encrypted input to a decryption operation has been determined to be invalid ciphertext. This return value has lower priority than CKR_ENCRYPTED_DATA_LEN_RANGE. EncryptedDataInvalid, /// The ciphertext input to a decryption operation has been determined to be invalid ciphertext solely on the basis of its length. Depending on the operation’s mechanism, this could mean that the ciphertext is too short, too long, or is not a multiple of some particular block size. This return value has higher priority than CKR_ENCRYPTED_DATA_INVALID. EncryptedDataLenRange, /// The function was canceled in mid-execution. This happens to a cryptographic function if the function makes a CKN_SURRENDER application callback which returns CKR_CANCEL (see CKR_CANCEL). It also happens to a function that performs PIN entry through a protected path. The method used to cancel a protected path PIN entry operation is device dependent. FunctionCanceled, /// There is currently no function executing in parallel in the specified session. This is a legacy error code which is only returned by the legacy functions C_GetFunctionStatus and C_CancelFunction. FunctionNotParallel, /// The requested function is not supported by this Cryptoki library. Even unsupported functions in the Cryptoki API should have a “stub” in the library; this stub should simply return the value CKR_FUNCTION_NOT_SUPPORTED. FunctionNotSupported, /// This curve is not supported by this token. Used with Elliptic Curve mechanisms. CurveNotSupported, /// The specified key handle is not valid. It may be the case that the specified handle is a valid handle for an object which is not a key. We reiterate here that 0 is never a valid key handle. KeyHandleInvalid, /// Although the requested keyed cryptographic operation could in principle be carried out, this Cryptoki library (or the token) is unable to actually do it because the supplied key‘s size is outside the range of key sizes that it can handle. KeySizeRange, /// The specified key is not the correct type of key to use with the specified mechanism. This return value has a higher priority than CKR_KEY_FUNCTION_NOT_PERMITTED. KeyTypeInconsistent, /// An extraneous key was supplied to C_SetOperationState. For example, an attempt was made to restore a session that had been performing a message digesting operation, and an encryption key was supplied. KeyNotNeeded, /// This value is only returned by C_SetOperationState. It indicates that one of the keys specified is not the same key that was being used in the original saved session. KeyChanged, /// This value is only returned by C_SetOperationState. It indicates that the session state cannot be restored because C_SetOperationState needs to be supplied with one or more keys that were being used in the original saved session. KeyNeeded, /// This error code can only be returned by C_DigestKey. It indicates that the value of the specified key cannot be digested for some reason (perhaps the key isn’t a secret key, or perhaps the token simply can’t digest this kind of key). KeyIndigestible, /// An attempt has been made to use a key for a cryptographic purpose that the key’s attributes are not set to allow it to do. For example, to use a key for performing encryption, that key MUST have its CKA_ENCRYPT attribute set to CK_TRUE (the fact that the key MUST have a CKA_ENCRYPT attribute implies that the key cannot be a private key). This return value has lower priority than CKR_KEY_TYPE_INCONSISTENT. KeyFunctionNotPermitted, /// Although the specified private or secret key does not have its CKA_EXTRACTABLE attribute set to CK_FALSE, Cryptoki (or the token) is unable to wrap the key as requested (possibly the token can only wrap a given key with certain types of keys, and the wrapping key specified is not one of these types). Compare with CKR_KEY_UNEXTRACTABLE. KeyNotWrappable, /// The specified private or secret key can’t be wrapped because its CKA_EXTRACTABLE attribute is set to CK_FALSE. Compare with CKR_KEY_NOT_WRAPPABLE. KeyUnextractable, /// An invalid mechanism was specified to the cryptographic operation. This error code is an appropriate return value if an unknown mechanism was specified or if the mechanism specified cannot be used in the selected token with the selected function. MechanismInvalid, /// Invalid parameters were supplied to the mechanism specified to the cryptographic operation. Which parameter values are supported by a given mechanism can vary from token to token. MechanismParamInvalid, /// The specified object handle is not valid. We reiterate here that 0 is never a valid object handle. ObjectHandleInvalid, /// There is already an active operation (or combination of active operations) which prevents Cryptoki from activating the specified operation. For example, an active object-searching operation would prevent Cryptoki from activating an encryption operation with C_EncryptInit. Or, an active digesting operation and an active encryption operation would prevent Cryptoki from activating a signature operation. Or, on a token which doesn’t support simultaneous dual cryptographic operations in a session (see the description of the CKF_DUAL_CRYPTO_OPERATIONS flag in the CK_TOKEN_INFO structure), an active signature operation would prevent Cryptoki from activating an encryption operation. OperationActive, /// There is no active operation of an appropriate type in the specified session. For example, an application cannot call C_Encrypt in a session without having called C_EncryptInit first to activate an encryption operation. OperationNotInitialized, /// The specified PIN is incorrect, i.e., does not match the PIN stored on the token. More generally-- when authentication to the token involves something other than a PIN-- the attempt to authenticate the user has failed. PinIncorrect, /// The specified PIN has invalid characters in it. This return code only applies to functions which attempt to set a PIN. PinInvalid, /// The specified PIN is too long or too short. This return code only applies to functions which attempt to set a PIN. PinLenRange, /// The specified PIN has expired, and the requested operation cannot be carried out unless C_SetPIN is called to change the PIN value. Whether or not the normal user’s PIN on a token ever expires varies from token to token. PinExpired, /// The specified PIN is “locked”, and cannot be used. That is, because some particular number of failed authentication attempts has been reached, the token is unwilling to permit further attempts at authentication. Depending on the token, the specified PIN may or may not remain locked indefinitely. PinLocked, /// The session was closed during the execution of the function. Note that, as stated in [PKCS11-UG], the behavior of Cryptoki is undefined if multiple threads of an application attempt to access a common Cryptoki session simultaneously. Therefore, there is actually no guarantee that a function invocation could ever return the value CKR_SESSION_CLOSED. An example of multiple threads accessing a common session simultaneously is where one thread is using a session when another thread closes that same session. SessionClosed, /// This value can only be returned by C_OpenSession. It indicates that the attempt to open a session failed, either because the token has too many sessions already open, or because the token has too many read/write sessions already open. SessionCount, /// The specified session handle was invalid at the time that the function was invoked. Note that this can happen if the session’s token is removed before the function invocation, since removing a token closes all sessions with it. SessionHandleInvalid, /// The specified token does not support parallel sessions. This is a legacy error code—in Cryptoki Version 2.01 and up, no token supports parallel sessions. CKR_SESSION_PARALLEL_NOT_SUPPORTED can only be returned by C_OpenSession, and it is only returned when C_OpenSession is called in a particular `deprecated` way. SessionParallelNotSupported, /// The specified session was unable to accomplish the desired action because it is a read-only session. This return value has lower priority than CKR_TOKEN_WRITE_PROTECTED. SessionReadOnly, /// This value can only be returned by C_InitToken. It indicates that a session with the token is already open, and so the token cannot be initialized. SessionExists, /// A read-only session already exists, and so the SO cannot be logged in. SessionReadOnlyExists, /// A read/write SO session already exists, and so a read-only session cannot be opened. SessionReadWriteSoExists, /// The provided signature/MAC is invalid. This return value has lower priority than CKR_SIGNATURE_LEN_RANGE. SignatureInvalid, /// The provided signature/MAC can be seen to be invalid solely on the basis of its length. This return value has higher priority than CKR_SIGNATURE_INVALID. SignatureLenRange, /// The template specified for creating an object is incomplete, and lacks some necessary attributes. See Section 4.1 for more information. TemplateIncomplete, /// The template specified for creating an object has conflicting attributes. See Section 4.1 for more information. TemplateInconsistent, /// The token was not present in its slot at the time that the function was invoked. TokenNotPresent, /// The Cryptoki library and/or slot does not recognize the token in the slot. TokenNotRecognized, /// The requested action could not be performed because the token is write-protected. This return value has higher priority than CKR_SESSION_READ_ONLY. TokenWriteProtected, /// This value can only be returned by C_UnwrapKey. It indicates that the key handle specified to be used to unwrap another key is not valid. UnwrappingKeyHandleInvalid, /// This value can only be returned by C_UnwrapKey. It indicates that although the requested unwrapping operation could in principle be carried out, this Cryptoki library (or the token) is unable to actually do it because the supplied key’s size is outside the range of key sizes that it can handle. UnwrappingKeySizeRange, /// This value can only be returned by C_UnwrapKey. It indicates that the type of the key specified to unwrap another key is not consistent with the mechanism specified for unwrapping. UnwrappingKeyTypeInconsistent, /// This value can only be returned by C_Login. It indicates that the specified user cannot be logged into the session, because it is already logged into the session. For example, if an application has an open SO session, and it attempts to log the SO into it, it will receive this error code. UserAlreadyLoggedIn, /// The desired action cannot be performed because the appropriate user (or an appropriate user) is not logged in. One example is that a session cannot be logged out unless it is logged in. Another example is that a private object cannot be created on a token unless the session attempting to create it is logged in as the normal user. A final example is that cryptographic operations on certain tokens cannot be performed unless the normal user is logged in. UserNotLoggedIn, /// This value can only be returned by C_Login. It indicates that the normal user’s PIN has not yet been initialized with C_InitPIN. UserPinNotInitialized, /// An invalid value was specified as a CK_USER_TYPE. Valid types are CKU_SO, CKU_USER, and CKU_CONTEXT_SPECIFIC. UserTypeInvalid, /// This value can only be returned by C_Login. It indicates that the specified user cannot be logged into the session, because another user is already logged into the session. For example, if an application has an open SO session, and it attempts to log the normal user into it, it will receive this error code. UserAnotherAlreadyLoggedIn, /// An attempt was made to have more distinct users simultaneously logged into the token than the token and/or library permits. For example, if some application has an open SO session, and another application attempts to log the normal user into a session, the attempt may return this error. It is not required to, however. Only if the simultaneous distinct users cannot be supported does C_Login have to return this value. Note that this error code generalizes to true multi-user tokens. UserTooManyTypes, /// This value can only be returned by C_UnwrapKey. It indicates that the provided wrapped key is not valid. If a call is made to C_UnwrapKey to unwrap a particular type of key (i.e., some particular key type is specified in the template provided to C_UnwrapKey), and the wrapped key provided to C_UnwrapKey is recognizably not a wrapped key of the proper type, then C_UnwrapKey should return CKR_WRAPPED_KEY_INVALID. This return value has lower priority than CKR_WRAPPED_KEY_LEN_RANGE. WrappedKeyInvalid, /// This value can only be returned by C_UnwrapKey. It indicates that the provided wrapped key can be seen to be invalid solely on the basis of its length. This return value has higher priority than CKR_WRAPPED_KEY_INVALID. WrappedKeyLenRange, /// This value can only be returned by C_WrapKey. It indicates that the key handle specified to be used to wrap another key is not valid. WrappingKeyHandleInvalid, /// This value can only be returned by C_WrapKey. It indicates that although the requested wrapping operation could in principle be carried out, this Cryptoki library (or the token) is unable to actually do it because the supplied wrapping key’s size is outside the range of key sizes that it can handle. WrappingKeySizeRange, /// This value can only be returned by C_WrapKey. It indicates that the type of the key specified to wrap another key is not consistent with the mechanism specified for wrapping. WrappingKeyTypeInconsistent, /// This value can only be returned by C_SeedRandom. It indicates that the token’s random number generator does not accept seeding from an application. This return value has lower priority than CKR_RANDOM_NO_RNG. RandomSeedNotSupported, /// This value can be returned by C_SeedRandom and C_GenerateRandom. It indicates that the specified token doesn’t have a random number generator. This return value has higher priority than CKR_RANDOM_SEED_NOT_SUPPORTED. RandomNoRng, /// Invalid or unsupported domain parameters were supplied to the function. Which representation methods of domain parameters are supported by a given mechanism can vary from token to token. DomainParamsInvalid, /// The output of the function is too large to fit in the supplied buffer. BufferTooSmall, /// This value can only be returned by C_SetOperationState. It indicates that the supplied saved cryptographic operations state is invalid, and so it cannot be restored to the specified session. SavedStateInvalid, /// The information requested could not be obtained because the token considers it sensitive, and is not able or willing to reveal it. InformationSensitive, /// The cryptographic operations state of the specified session cannot be saved for some reason (possibly the token is simply unable to save the current state). This return value has lower priority than CKR_OPERATION_NOT_INITIALIZED. StateUnsaveable, /// This value can be returned by any function other than C_Initialize and C_GetFunctionList. It indicates that the function cannot be executed because the Cryptoki library has not yet been initialized by a call to C_Initialize. CryptokiNotInitialized, /// This value can only be returned by C_Initialize. It means that the Cryptoki library has already been initialized (by a previous call to C_Initialize which did not have a matching C_Finalize call). CryptokiAlreadyInitialized, /// This error code can be returned by mutex-handling functions that are passed a bad mutex object as an argument. Unfortunately, it is possible for such a function not to recognize a bad mutex object. There is therefore no guarantee that such a function will successfully detect bad mutex objects and return this value. MutexBad, /// This error code can be returned by mutex-unlocking functions. It indicates that the mutex supplied to the mutex-unlocking function was not locked. MutexNotLocked, /// CKR_NEW_PIN_MODE NewPinMode, /// CKR_NEXT_OTP NextOtp, /// An iterative algorithm (for key pair generation, domain parameter generation etc.) failed because we have exceeded the maximum number of iterations. This error code has precedence over CKR_FUNCTION_FAILED. Examples of iterative algorithms include DSA signature generation (retry if either r = 0 or s = 0) and generation of DSA primes p and q specified in FIPS 186-4. ExceededMaxIterations, /// A FIPS 140-2 power-up self-test or conditional self-test failed. The token entered an error state. Future calls to cryptographic functions on the token will return CKR_GENERAL_ERROR. CKR_FIPS_SELF_TEST_FAILED has a higher precedence over CKR_GENERAL_ERROR. This error may be returned by C_Initialize, if a power-up self-test failed, by C_GenerateRandom or C_SeedRandom, if the continuous random number generator test failed, or by C_GenerateKeyPair, if the pair-wise consistency test failed. FipsSelfTestFailed, /// The Cryptoki library could not load a dependent shared library. LibraryLoadFailed, /// The specified PIN is too weak so that it could be easy to guess. If the PIN is too short, CKR_PIN_LEN_RANGE should be returned instead. This return code only applies to functions which attempt to set a PIN. PinTooWeak, /// The public key fails a public key validation. For example, an EC public key fails the public key validation specified in Section 5.2.2 of ANSI X9.62. This error code may be returned by C_CreateObject, when the public key is created, or by C_VerifyInit or C_VerifyRecoverInit, when the public key is used. It may also be returned by C_DeriveKey, in preference to CKR_MECHANISM_PARAM_INVALID, if the other party's public key specified in the mechanism's parameters is invalid. PublicKeyInvalid, /// The signature request is rejected by the user. FunctionRejected, /// CKR_VENDOR_DEFINED VendorDefined, } impl fmt::Display for RvError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { RvError::Cancel => write!(f, "When a function executing in serial with an application decides to give the application a chance to do some work, it calls an application-supplied function with a CKN_SURRENDER callback (see Section 5.16). If the callback returns the value CKR_CANCEL, then the function aborts and returns CKR_FUNCTION_CANCELED."), RvError::HostMemory => write!(f, "The computer that the Cryptoki library is running on has insufficient memory to perform the requested function."), RvError::SlotIdInvalid => write!(f, "The specified slot ID is not valid."), RvError::GeneralError => write!(f, "Some horrible, unrecoverable error has occurred. In the worst case, it is possible that the function only partially succeeded, and that the computer and/or token is in an inconsistent state."), RvError::FunctionFailed => write!(f, "The requested function could not be performed, but detailed information about why not is not available in this error return. If the failed function uses a session, it is possible that the CK_SESSION_INFO structure that can be obtained by calling C_GetSessionInfo will hold useful information about what happened in its ulDeviceError field. In any event, although the function call failed, the situation is not necessarily totally hopeless, as it is likely to be when CKR_GENERAL_ERROR is returned. Depending on what the root cause of the error actually was, it is possible that an attempt to make the exact same function call again would succeed."), RvError::ArgumentsBad => write!(f, "This is a rather generic error code which indicates that the arguments supplied to the Cryptoki function were in some way not appropriate."), RvError::NoEvent => write!(f, "This value can only be returned by C_GetSlotEvent. It is returned when C_GetSlotEvent is called in non-blocking mode and there are no new slot events to return."), RvError::NeedToCreateThreads => write!(f, "This value can only be returned by C_Initialize. It is returned when two conditions hold: 1. The application called C_Initialize in a way which tells the Cryptoki library that application threads executing calls to the library cannot use native operating system methods to spawn new threads. 2. The library cannot function properly without being able to spawn new threads in the above fashion."), RvError::CantLock => write!(f, "This value can only be returned by C_Initialize. It means that the type of locking requested by the application for thread-safety is not available in this library, and so the application cannot make use of this library in the specified fashion."), RvError::AttributeReadOnly => write!(f, "An attempt was made to set a value for an attribute which may not be set by the application, or which may not be modified by the application. See Section 4.1 for more information."), RvError::AttributeSensitive => write!(f, "An attempt was made to obtain the value of an attribute of an object which cannot be satisfied because the object is either sensitive or un-extractable."), RvError::AttributeTypeInvalid => write!(f, "An invalid attribute type was specified in a template. See Section 4.1 for more information."), RvError::AttributeValueInvalid => write!(f, "An invalid value was specified for a particular attribute in a template. See Section 4.1 for more information."), RvError::ActionProhibited => write!(f, " This value can only be returned by C_CopyObject, C_SetAttributeValue and C_DestroyObject. It denotes that the action may not be taken, either because of underlying policy restrictions on the token, or because the object has the the relevant CKA_COPYABLE, CKA_MODIFIABLE or CKA_DESTROYABLE policy attribute set to CK_FALSE."), RvError::DataInvalid => write!(f, "The plaintext input data to a cryptographic operation is invalid. This return value has lower priority than CKR_DATA_LEN_RANGE."), RvError::DataLenRange => write!(f, "The plaintext input data to a cryptographic operation has a bad length. Depending on the operation’s mechanism, this could mean that the plaintext data is too short, too long, or is not a multiple of some particular block size. This return value has higher priority than CKR_DATA_INVALID."), RvError::DeviceError => write!(f, "Some problem has occurred with the token and/or slot. This error code can be returned by more than just the functions mentioned above; in particular, it is possible for C_GetSlotInfo to return CKR_DEVICE_ERROR."), RvError::DeviceMemory => write!(f, "The token does not have sufficient memory to perform the requested function."), RvError::DeviceRemoved => write!(f, "The token was removed from its slot during the execution of the function."), RvError::EncryptedDataInvalid => write!(f, "The encrypted input to a decryption operation has been determined to be invalid ciphertext. This return value has lower priority than CKR_ENCRYPTED_DATA_LEN_RANGE."), RvError::EncryptedDataLenRange => write!(f, "The ciphertext input to a decryption operation has been determined to be invalid ciphertext solely on the basis of its length. Depending on the operation’s mechanism, this could mean that the ciphertext is too short, too long, or is not a multiple of some particular block size. This return value has higher priority than CKR_ENCRYPTED_DATA_INVALID."), RvError::FunctionCanceled => write!(f, "The function was canceled in mid-execution. This happens to a cryptographic function if the function makes a CKN_SURRENDER application callback which returns CKR_CANCEL (see CKR_CANCEL). It also happens to a function that performs PIN entry through a protected path. The method used to cancel a protected path PIN entry operation is device dependent."), RvError::FunctionNotParallel => write!(f, "There is currently no function executing in parallel in the specified session. This is a legacy error code which is only returned by the legacy functions C_GetFunctionStatus and C_CancelFunction."), RvError::FunctionNotSupported => write!(f, "The requested function is not supported by this Cryptoki library. Even unsupported functions in the Cryptoki API should have a “stub” in the library; this stub should simply return the value CKR_FUNCTION_NOT_SUPPORTED."), RvError::CurveNotSupported => write!(f, " This curve is not supported by this token. Used with Elliptic Curve mechanisms."), RvError::KeyHandleInvalid => write!(f, "The specified key handle is not valid. It may be the case that the specified handle is a valid handle for an object which is not a key. We reiterate here that 0 is never a valid key handle."), RvError::KeySizeRange => write!(f, "Although the requested keyed cryptographic operation could in principle be carried out, this Cryptoki library (or the token) is unable to actually do it because the supplied key‘s size is outside the range of key sizes that it can handle."), RvError::KeyTypeInconsistent => write!(f, "The specified key is not the correct type of key to use with the specified mechanism. This return value has a higher priority than CKR_KEY_FUNCTION_NOT_PERMITTED."), RvError::KeyNotNeeded => write!(f, "An extraneous key was supplied to C_SetOperationState. For example, an attempt was made to restore a session that had been performing a message digesting operation, and an encryption key was supplied."), RvError::KeyChanged => write!(f, "This value is only returned by C_SetOperationState. It indicates that one of the keys specified is not the same key that was being used in the original saved session."), RvError::KeyNeeded => write!(f, "This value is only returned by C_SetOperationState. It indicates that the session state cannot be restored because C_SetOperationState needs to be supplied with one or more keys that were being used in the original saved session."), RvError::KeyIndigestible => write!(f, "This error code can only be returned by C_DigestKey. It indicates that the value of the specified key cannot be digested for some reason (perhaps the key isn’t a secret key, or perhaps the token simply can’t digest this kind of key)."), RvError::KeyFunctionNotPermitted => write!(f, "An attempt has been made to use a key for a cryptographic purpose that the key’s attributes are not set to allow it to do. For example, to use a key for performing encryption, that key MUST have its CKA_ENCRYPT attribute set to CK_TRUE (the fact that the key MUST have a CKA_ENCRYPT attribute implies that the key cannot be a private key). This return value has lower priority than CKR_KEY_TYPE_INCONSISTENT."), RvError::KeyNotWrappable => write!(f, "Although the specified private or secret key does not have its CKA_EXTRACTABLE attribute set to CK_FALSE, Cryptoki (or the token) is unable to wrap the key as requested (possibly the token can only wrap a given key with certain types of keys, and the wrapping key specified is not one of these types). Compare with CKR_KEY_UNEXTRACTABLE."), RvError::KeyUnextractable => write!(f, "The specified private or secret key can’t be wrapped because its CKA_EXTRACTABLE attribute is set to CK_FALSE. Compare with CKR_KEY_NOT_WRAPPABLE."), RvError::MechanismInvalid => write!(f, "An invalid mechanism was specified to the cryptographic operation. This error code is an appropriate return value if an unknown mechanism was specified or if the mechanism specified cannot be used in the selected token with the selected function."), RvError::MechanismParamInvalid => write!(f, "Invalid parameters were supplied to the mechanism specified to the cryptographic operation. Which parameter values are supported by a given mechanism can vary from token to token."), RvError::ObjectHandleInvalid => write!(f, "The specified object handle is not valid. We reiterate here that 0 is never a valid object handle."), RvError::OperationActive => write!(f, "There is already an active operation (or combination of active operations) which prevents Cryptoki from activating the specified operation. For example, an active object-searching operation would prevent Cryptoki from activating an encryption operation with C_EncryptInit. Or, an active digesting operation and an active encryption operation would prevent Cryptoki from activating a signature operation. Or, on a token which doesn’t support simultaneous dual cryptographic operations in a session (see the description of the CKF_DUAL_CRYPTO_OPERATIONS flag in the CK_TOKEN_INFO structure), an active signature operation would prevent Cryptoki from activating an encryption operation."), RvError::OperationNotInitialized => write!(f, "There is no active operation of an appropriate type in the specified session. For example, an application cannot call C_Encrypt in a session without having called C_EncryptInit first to activate an encryption operation."), RvError::PinIncorrect => write!(f, "The specified PIN is incorrect, i.e., does not match the PIN stored on the token. More generally-- when authentication to the token involves something other than a PIN-- the attempt to authenticate the user has failed."), RvError::PinInvalid => write!(f, "The specified PIN has invalid characters in it. This return code only applies to functions which attempt to set a PIN."), RvError::PinLenRange => write!(f, "The specified PIN is too long or too short. This return code only applies to functions which attempt to set a PIN."), RvError::PinExpired => write!(f, "The specified PIN has expired, and the requested operation cannot be carried out unless C_SetPIN is called to change the PIN value. Whether or not the normal user’s PIN on a token ever expires varies from token to token."), RvError::PinLocked => write!(f, "The specified PIN is “locked”, and cannot be used. That is, because some particular number of failed authentication attempts has been reached, the token is unwilling to permit further attempts at authentication. Depending on the token, the specified PIN may or may not remain locked indefinitely."), RvError::SessionClosed => write!(f, "The session was closed during the execution of the function. Note that, as stated in [PKCS11-UG], the behavior of Cryptoki is undefined if multiple threads of an application attempt to access a common Cryptoki session simultaneously. Therefore, there is actually no guarantee that a function invocation could ever return the value CKR_SESSION_CLOSED. An example of multiple threads accessing a common session simultaneously is where one thread is using a session when another thread closes that same session."), RvError::SessionCount => write!(f, "This value can only be returned by C_OpenSession. It indicates that the attempt to open a session failed, either because the token has too many sessions already open, or because the token has too many read/write sessions already open."), RvError::SessionHandleInvalid => write!(f, "The specified session handle was invalid at the time that the function was invoked. Note that this can happen if the session’s token is removed before the function invocation, since removing a token closes all sessions with it."), RvError::SessionParallelNotSupported => write!(f, "The specified token does not support parallel sessions. This is a legacy error code—in Cryptoki Version 2.01 and up, no token supports parallel sessions. CKR_SESSION_PARALLEL_NOT_SUPPORTED can only be returned by C_OpenSession, and it is only returned when C_OpenSession is called in a particular [deprecated] way."), RvError::SessionReadOnly => write!(f, "The specified session was unable to accomplish the desired action because it is a read-only session. This return value has lower priority than CKR_TOKEN_WRITE_PROTECTED."), RvError::SessionExists => write!(f, "This value can only be returned by C_InitToken. It indicates that a session with the token is already open, and so the token cannot be initialized."), RvError::SessionReadOnlyExists => write!(f, "A read-only session already exists, and so the SO cannot be logged in."), RvError::SessionReadWriteSoExists => write!(f, "A read/write SO session already exists, and so a read-only session cannot be opened."), RvError::SignatureInvalid => write!(f, "The provided signature/MAC is invalid. This return value has lower priority than CKR_SIGNATURE_LEN_RANGE."), RvError::SignatureLenRange => write!(f, "The provided signature/MAC can be seen to be invalid solely on the basis of its length. This return value has higher priority than CKR_SIGNATURE_INVALID."), RvError::TemplateIncomplete => write!(f, "The template specified for creating an object is incomplete, and lacks some necessary attributes. See Section 4.1 for more information."), RvError::TemplateInconsistent => write!(f, "The template specified for creating an object has conflicting attributes. See Section 4.1 for more information."), RvError::TokenNotPresent => write!(f, "The token was not present in its slot at the time that the function was invoked."), RvError::TokenNotRecognized => write!(f, "The Cryptoki library and/or slot does not recognize the token in the slot."), RvError::TokenWriteProtected => write!(f, "The requested action could not be performed because the token is write-protected. This return value has higher priority than CKR_SESSION_READ_ONLY."), RvError::UnwrappingKeyHandleInvalid => write!(f, "This value can only be returned by C_UnwrapKey. It indicates that the key handle specified to be used to unwrap another key is not valid."), RvError::UnwrappingKeySizeRange => write!(f, "This value can only be returned by C_UnwrapKey. It indicates that although the requested unwrapping operation could in principle be carried out, this Cryptoki library (or the token) is unable to actually do it because the supplied key’s size is outside the range of key sizes that it can handle."), RvError::UnwrappingKeyTypeInconsistent => write!(f, "This value can only be returned by C_UnwrapKey. It indicates that the type of the key specified to unwrap another key is not consistent with the mechanism specified for unwrapping."), RvError::UserAlreadyLoggedIn => write!(f, "This value can only be returned by C_Login. It indicates that the specified user cannot be logged into the session, because it is already logged into the session. For example, if an application has an open SO session, and it attempts to log the SO into it, it will receive this error code."), RvError::UserNotLoggedIn => write!(f, "The desired action cannot be performed because the appropriate user (or an appropriate user) is not logged in. One example is that a session cannot be logged out unless it is logged in. Another example is that a private object cannot be created on a token unless the session attempting to create it is logged in as the normal user. A final example is that cryptographic operations on certain tokens cannot be performed unless the normal user is logged in."), RvError::UserPinNotInitialized => write!(f, "This value can only be returned by C_Login. It indicates that the normal user’s PIN has not yet been initialized with C_InitPIN."), RvError::UserTypeInvalid => write!(f, "An invalid value was specified as a CK_USER_TYPE. Valid types are CKU_SO, CKU_USER, and CKU_CONTEXT_SPECIFIC."), RvError::UserAnotherAlreadyLoggedIn => write!(f, "This value can only be returned by C_Login. It indicates that the specified user cannot be logged into the session, because another user is already logged into the session. For example, if an application has an open SO session, and it attempts to log the normal user into it, it will receive this error code."), RvError::UserTooManyTypes => write!(f, "An attempt was made to have more distinct users simultaneously logged into the token than the token and/or library permits. For example, if some application has an open SO session, and another application attempts to log the normal user into a session, the attempt may return this error. It is not required to, however. Only if the simultaneous distinct users cannot be supported does C_Login have to return this value. Note that this error code generalizes to true multi-user tokens."), RvError::WrappedKeyInvalid => write!(f, "This value can only be returned by C_UnwrapKey. It indicates that the provided wrapped key is not valid. If a call is made to C_UnwrapKey to unwrap a particular type of key (i.e., some particular key type is specified in the template provided to C_UnwrapKey), and the wrapped key provided to C_UnwrapKey is recognizably not a wrapped key of the proper type, then C_UnwrapKey should return CKR_WRAPPED_KEY_INVALID. This return value has lower priority than CKR_WRAPPED_KEY_LEN_RANGE."), RvError::WrappedKeyLenRange => write!(f, "This value can only be returned by C_UnwrapKey. It indicates that the provided wrapped key can be seen to be invalid solely on the basis of its length. This return value has higher priority than CKR_WRAPPED_KEY_INVALID."), RvError::WrappingKeyHandleInvalid => write!(f, "This value can only be returned by C_WrapKey. It indicates that the key handle specified to be used to wrap another key is not valid."), RvError::WrappingKeySizeRange => write!(f, "This value can only be returned by C_WrapKey. It indicates that although the requested wrapping operation could in principle be carried out, this Cryptoki library (or the token) is unable to actually do it because the supplied wrapping key’s size is outside the range of key sizes that it can handle."), RvError::WrappingKeyTypeInconsistent => write!(f, "This value can only be returned by C_WrapKey. It indicates that the type of the key specified to wrap another key is not consistent with the mechanism specified for wrapping."), RvError::RandomSeedNotSupported => write!(f, "This value can only be returned by C_SeedRandom. It indicates that the token’s random number generator does not accept seeding from an application. This return value has lower priority than CKR_RANDOM_NO_RNG."), RvError::RandomNoRng => write!(f, "This value can be returned by C_SeedRandom and C_GenerateRandom. It indicates that the specified token doesn’t have a random number generator. This return value has higher priority than CKR_RANDOM_SEED_NOT_SUPPORTED."), RvError::DomainParamsInvalid => write!(f, "Invalid or unsupported domain parameters were supplied to the function. Which representation methods of domain parameters are supported by a given mechanism can vary from token to token."), RvError::BufferTooSmall => write!(f, "The output of the function is too large to fit in the supplied buffer."), RvError::SavedStateInvalid => write!(f, "This value can only be returned by C_SetOperationState. It indicates that the supplied saved cryptographic operations state is invalid, and so it cannot be restored to the specified session."), RvError::InformationSensitive => write!(f, "The information requested could not be obtained because the token considers it sensitive, and is not able or willing to reveal it."), RvError::StateUnsaveable => write!(f, "The cryptographic operations state of the specified session cannot be saved for some reason (possibly the token is simply unable to save the current state). This return value has lower priority than CKR_OPERATION_NOT_INITIALIZED."), RvError::CryptokiNotInitialized => write!(f, "This value can be returned by any function other than C_Initialize and C_GetFunctionList. It indicates that the function cannot be executed because the Cryptoki library has not yet been initialized by a call to C_Initialize."), RvError::CryptokiAlreadyInitialized => write!(f, "This value can only be returned by C_Initialize. It means that the Cryptoki library has already been initialized (by a previous call to C_Initialize which did not have a matching C_Finalize call)."), RvError::MutexBad => write!(f, "This error code can be returned by mutex-handling functions that are passed a bad mutex object as an argument. Unfortunately, it is possible for such a function not to recognize a bad mutex object. There is therefore no guarantee that such a function will successfully detect bad mutex objects and return this value."), RvError::MutexNotLocked => write!(f, "This error code can be returned by mutex-unlocking functions. It indicates that the mutex supplied to the mutex-unlocking function was not locked."), RvError::NewPinMode => write!(f, "CKR_NEW_PIN_MODE"), RvError::NextOtp => write!(f, "CKR_NEXT_OTP"), RvError::ExceededMaxIterations => write!(f, "An iterative algorithm (for key pair generation, domain parameter generation etc.) failed because we have exceeded the maximum number of iterations. This error code has precedence over CKR_FUNCTION_FAILED. Examples of iterative algorithms include DSA signature generation (retry if either r = 0 or s = 0) and generation of DSA primes p and q specified in FIPS 186-4."), RvError::FipsSelfTestFailed => write!(f, "A FIPS 140-2 power-up self-test or conditional self-test failed. The token entered an error state. Future calls to cryptographic functions on the token will return CKR_GENERAL_ERROR. CKR_FIPS_SELF_TEST_FAILED has a higher precedence over CKR_GENERAL_ERROR. This error may be returned by C_Initialize, if a power-up self-test failed, by C_GenerateRandom or C_SeedRandom, if the continuous random number generator test failed, or by C_GenerateKeyPair, if the pair-wise consistency test failed."), RvError::LibraryLoadFailed => write!(f, "The Cryptoki library could not load a dependent shared library."), RvError::PinTooWeak => write!(f, "The specified PIN is too weak so that it could be easy to guess. If the PIN is too short, CKR_PIN_LEN_RANGE should be returned instead. This return code only applies to functions which attempt to set a PIN."), RvError::PublicKeyInvalid => write!(f, "The public key fails a public key validation. For example, an EC public key fails the public key validation specified in Section 5.2.2 of ANSI X9.62. This error code may be returned by C_CreateObject, when the public key is created, or by C_VerifyInit or C_VerifyRecoverInit, when the public key is used. It may also be returned by C_DeriveKey, in preference to CKR_MECHANISM_PARAM_INVALID, if the other party's public key specified in the mechanism's parameters is invalid."), RvError::FunctionRejected => write!(f, "The signature request is rejected by the user."), RvError::VendorDefined => write!(f, "CKR_VENDOR_DEFINED"), } } } cryptoki-0.6.1/src/lib.rs000064400000000000000000000056031046102023000134030ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Rust PKCS11 new abstraction //! //! The items in the new module only expose idiomatic and safe Rust types and functions to //! interface with the PKCS11 API. All the PKCS11 items might not be implemented but everything //! that is implemented is safe. //! //! The modules under `new` follow the structure of the PKCS11 document version 2.40 available [here](http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html). //! //! # Conformance Notes //! //! Throughout this crate, many functions and other items include additional //! "**Conformance**" notes. These notes may provide guarantees about behavior or //! additional, contextual information. In all cases, such items pertain //! to information from the PKCS#11 standard and are contingent on the provider //! being accessed through this crate conforming to that standard. That is, this //! crate is permitted to *assume* these guarantees, and is does not necessarily //! check for or enforce them itself. // This list comes from // https://github.com/rust-unofficial/patterns/blob/master/anti_patterns/deny-warnings.md #![allow(renamed_and_removed_lints, unknown_lints)] #![deny(bad_style, dead_code, improper_ctypes, non_shorthand_field_patterns, no_mangle_generic_items, overflowing_literals, path_statements , patterns_in_fns_without_body, private_bounds, private_in_public, private_interfaces, renamed_and_removed_lints, unconditional_recursion, unnameable_types, unused, unused_allocation, unused_comparisons, unused_parens, while_true, missing_debug_implementations, missing_copy_implementations, missing_docs, // Useful to cast to raw pointers //trivial_casts, trivial_numeric_casts, unused_extern_crates, unused_import_braces, unused_qualifications, unused_results)] // Warning: The context module defines the // get_pkcs11() macro, which must be defined before // any modules that use it are declared. #[macro_use] pub mod context; pub mod error; pub mod mechanism; pub mod object; pub mod session; pub mod slot; pub mod types; use cryptoki_sys::CK_UTF8CHAR; fn string_from_blank_padded(field: &[CK_UTF8CHAR]) -> String { let decoded_str = String::from_utf8_lossy(field); decoded_str.trim_end_matches(' ').to_string() } fn label_from_str(label: &str) -> [CK_UTF8CHAR; 32] { let mut lab: [CK_UTF8CHAR; 32] = [32; 32]; let mut i = 0; for c in label.chars() { if i + c.len_utf8() <= 32 { let mut buf = [0; 4]; let bytes = c.encode_utf8(&mut buf).as_bytes(); for b in bytes { lab[i] = *b; i += 1; } } else { break; } } lab } cryptoki-0.6.1/src/mechanism/aead.rs000064400000000000000000000063551046102023000155000ustar 00000000000000// Copyright 2023 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! AEAD block cipher mechanism types use crate::types::Ulong; use cryptoki_sys::*; use std::convert::TryInto; use std::marker::PhantomData; use std::slice; /// Parameters for AES-GCM. #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct GcmParams<'a> { inner: CK_GCM_PARAMS, _marker: PhantomData<&'a [u8]>, } impl<'a> GcmParams<'a> { /// Construct GCM parameters. /// /// # Arguments /// /// `iv` - The initialization vector. This must be non-empty. In PKCS#11 /// 2.40, the maximum length of the IV is 256 bytes. A 12-byte IV may be /// processed more efficiently than other lengths. /// /// `aad` - The additional authenticated data. This data is authenticated /// but not encrypted. This may be between 0 and 2^32-1 bytes. /// /// `tag_bits` - The length, in **bits**, of the authentication tag. Must /// be between 0 and 128. The tag is appended to the end of the /// ciphertext. /// /// # Panics /// /// This function panics if the length of `iv` or `aad` does not /// fit into an [Ulong]. pub fn new(iv: &'a [u8], aad: &'a [u8], tag_bits: Ulong) -> Self { // The ulIvBits parameter seems to be missing from the 2.40 spec, // although it is included in the header file. In [1], OASIS clarified // that the header file is normative. In 3.0, they added the parameter // to the spec, but it seems to be unused: // // > Do not use ulIvBits to specify the length of the initialization // > vector, but ulIvLen instead. // // Further, in v3.0, the IV is permitted to be up to 2^32-1 bytes, // which would cause ulIvBits to overflow on platforms where // sizeof(CK_ULONG) = 4. // // In light of all this, we include ulIvBits in the struct, but always // set it to zero. // // [1]: https://www.oasis-open.org/committees/document.php?document_id=58032&wg_abbrev=pkcs11 GcmParams { inner: CK_GCM_PARAMS { pIv: iv.as_ptr() as *mut _, ulIvLen: iv .len() .try_into() .expect("iv length does not fit in CK_ULONG"), ulIvBits: 0, pAAD: aad.as_ptr() as *mut _, ulAADLen: aad .len() .try_into() .expect("aad length does not fit in CK_ULONG"), ulTagBits: tag_bits.into(), }, _marker: PhantomData, } } /// The initialization vector. pub fn iv(&self) -> &'a [u8] { // SAFETY: In the constructor, the IV always comes from a &'a [u8] unsafe { slice::from_raw_parts(self.inner.pIv, self.inner.ulIvLen as _) } } /// The additional authenticated data. pub fn aad(&self) -> &'a [u8] { // SAEFTY: In the constructor, the AAD always comes from a &'a [u8] unsafe { slice::from_raw_parts(self.inner.pAAD, self.inner.ulAADLen as _) } } /// The length, in bits, of the authentication tag. pub fn tag_bits(&self) -> Ulong { self.inner.ulTagBits.into() } } cryptoki-0.6.1/src/mechanism/elliptic_curve.rs000064400000000000000000000070631046102023000176140ustar 00000000000000//! ECDH mechanism types use crate::types::Ulong; use cryptoki_sys::*; use std::convert::TryInto; use std::marker::PhantomData; use std::ptr; /// ECDH derivation parameters. /// /// The elliptic curve Diffie-Hellman (ECDH) key derivation mechanism /// is a mechanism for key derivation based on the Diffie-Hellman /// version of the elliptic curve key agreement scheme, as defined in /// ANSI X9.63, where each party contributes one key pair all using /// the same EC domain parameters. /// /// This structure wraps a `CK_ECDH1_DERIVE_PARAMS` structure. #[derive(Copy, Debug, Clone)] #[repr(C)] pub struct Ecdh1DeriveParams<'a> { /// Key derivation function kdf: CK_EC_KDF_TYPE, /// Length of the optional shared data used by some of the key /// derivation functions shared_data_len: Ulong, /// Address of the optional data or `std::ptr::null()` of there is /// no shared data shared_data: *const u8, /// Length of the other party's public key public_data_len: Ulong, /// Pointer to the other party public key public_data: *const u8, /// Marker type to ensure we don't outlive shared and public data _marker: PhantomData<&'a [u8]>, } impl<'a> Ecdh1DeriveParams<'a> { /// Construct ECDH derivation parameters. /// /// # Arguments /// /// * `kdf` - The key derivation function to use. /// /// * `public_data` - The other party's public key. A token MUST be able /// to accept this value encoded as a raw octet string (as per section /// A.5.2 of ANSI X9.62). A token MAY, in addition, support accepting /// this value as a DER-encoded `ECPoint` (as per section E.6 of ANSI /// X9.62) i.e. the same as a `CKA_EC_POINT` encoding. The calling /// application is responsible for converting the offered public key to the /// compressed or uncompressed forms of these encodings if the token does /// not support the offered form. pub fn new(kdf: EcKdf<'a>, public_data: &'a [u8]) -> Self { Self { kdf: kdf.kdf_type, shared_data_len: kdf .shared_data .map_or(0, <[u8]>::len) .try_into() .expect("usize can not fit in CK_ULONG"), shared_data: kdf.shared_data.map_or(ptr::null(), <[u8]>::as_ptr), public_data_len: public_data .len() .try_into() .expect("usize can not fit in CK_ULONG"), public_data: public_data.as_ptr(), _marker: PhantomData, } } } /// Key Derivation Function applied to derive keying data from a shared secret. /// /// The key derivation function will be used by the EC key agreement schemes. /// /// The lifetime parameter represents the lifetime of the shared data used by /// the KDF. In the current version of this crate, only the null KDF is /// supported, which takes no shared data. Therefore `'a` can always be inferred /// `'static`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct EcKdf<'a> { kdf_type: CK_EC_KDF_TYPE, shared_data: Option<&'a [u8]>, } impl<'a> EcKdf<'a> { /// The null transformation. The derived key value is produced by /// taking bytes from the left of the agreed value. The new key /// size is limited to the size of the agreed value. pub fn null() -> Self { Self { kdf_type: CKD_NULL, shared_data: None, } } // The intention here is to be able to support other methods with // shared data, without it being a breaking change, by just adding // additional constructors here. } cryptoki-0.6.1/src/mechanism/mechanism_info.rs000064400000000000000000000220601046102023000175540ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Mechanism info and associated flags use bitflags::bitflags; use cryptoki_sys::*; use std::fmt::Debug; bitflags! { struct MechanismInfoFlags: CK_FLAGS { const HW = CKF_HW; const ENCRYPT = CKF_ENCRYPT; const DECRYPT = CKF_DECRYPT; const DIGEST = CKF_DIGEST; const SIGN = CKF_SIGN; const SIGN_RECOVER = CKF_SIGN_RECOVER; const VERIFY = CKF_VERIFY; const VERIFY_RECOVER = CKF_VERIFY_RECOVER; const GENERATE = CKF_GENERATE; const GENERATE_KEY_PAIR = CKF_GENERATE_KEY_PAIR; const WRAP = CKF_WRAP; const UNWRAP = CKF_UNWRAP; const DERIVE = CKF_DERIVE; const EXTENSION = CKF_EXTENSION; const EC_F_P = CKF_EC_F_P; const EC_F_2M = CKF_EC_F_2M; const EC_ECPARAMETERS = CKF_EC_ECPARAMETERS; const EC_NAMEDCURVE = CKF_EC_NAMEDCURVE; const EC_UNCOMPRESS = CKF_EC_UNCOMPRESS; const EC_COMPRESS = CKF_EC_COMPRESS; } } /// Information about a particular mechanism #[derive(Debug, Clone, Copy)] pub struct MechanismInfo { min_key_size: usize, max_key_size: usize, flags: MechanismInfoFlags, } impl MechanismInfo { /// The minimum size of the key for the mechanism /// /// **[Conformance](crate#conformance-notes):** /// Whether this is measured in bits or in bytes is mechanism-dependent. /// For some mechanisms, this field may be meaningless and take any value. pub fn min_key_size(&self) -> usize { self.min_key_size } /// The maximum size of the key for the mechanism /// /// **[Conformance](crate#conformance-notes):** /// Whether this is measured in bits or in bytes is mechanism-dependent /// For some mechanisms, this field may be meaningless and take any value. pub fn max_key_size(&self) -> usize { self.max_key_size } /// True if the mechanism is performed by the device; false if the /// mechanism is performed in software pub fn hardware(&self) -> bool { self.flags.contains(MechanismInfoFlags::HW) } /// True if the mechanism can be used to encrypt data /// /// See [`Session::encrypt`](crate::session::Session::encrypt) pub fn encrypt(&self) -> bool { self.flags.contains(MechanismInfoFlags::ENCRYPT) } /// True if the mechanism can be used to decrypt encrypted data /// /// See [`Session::decrypt`](crate::session::Session::decrypt) pub fn decrypt(&self) -> bool { self.flags.contains(MechanismInfoFlags::DECRYPT) } /// True if the mechanism can be used to digest a message /// // TODO See [`Session::digest`](crate::session::Session::digest) pub fn digest(&self) -> bool { self.flags.contains(MechanismInfoFlags::DIGEST) } /// True if the mechanism can be used to digitally sign data /// /// See [`Session::sign`](crate::session::Session::sign) pub fn sign(&self) -> bool { self.flags.contains(MechanismInfoFlags::SIGN) } /// True if the mechanism can be used to digitally data which can be /// recovered from the signature /// // TODO See [`Session::sign_recover`](crate::session::Session::sign_recover) pub fn sign_recover(&self) -> bool { self.flags.contains(MechanismInfoFlags::SIGN_RECOVER) } /// True if the mechanism can be used to verify a digital signature /// /// See [`Session::verify`](crate::session::Session::verify) pub fn verify(&self) -> bool { self.flags.contains(MechanismInfoFlags::VERIFY) } /// True if the mechanism can be used to verify a digital signature and /// recover the signed data /// // TODO See [`Session::verify_recover`](crate::session::Session::verify_recover) pub fn verify_recover(&self) -> bool { self.flags.contains(MechanismInfoFlags::VERIFY_RECOVER) } /// True if the mechanism can be used to generate a secret key /// // TODO See [`Session::generate`](crate::session::Session::generate) pub fn generate(&self) -> bool { self.flags.contains(MechanismInfoFlags::GENERATE) } /// True if the mechanism can be used to generate a public/private key pair /// /// See [`Session::generate_key_pair`](crate::session::Session::generate_key_pair)) pub fn generate_key_pair(&self) -> bool { self.flags.contains(MechanismInfoFlags::GENERATE_KEY_PAIR) } /// True if the mechanism can be used to wrap (encrypt) a key /// // TODO See [`Session::wrap`](crate::session::Session::wrap)) pub fn wrap(&self) -> bool { self.flags.contains(MechanismInfoFlags::WRAP) } /// True if the mechanism can be used to unwrap (decrypt) a key /// // TODO See [`Session::unwrap`](crate::session::Session::unwrap)) pub fn unwrap(&self) -> bool { self.flags.contains(MechanismInfoFlags::UNWRAP) } /// True if the mechanism can be used to derive a key from a base key /// // TODO See [`Session::derive`](crate::session::Session::derive)) pub fn derive(&self) -> bool { self.flags.contains(MechanismInfoFlags::DERIVE) } /// True if there is an extension to the flags; false if no extensions /// /// **[Conformance](crate#conformance-notes):** /// This *must* be false for PKCS#11 v2.40 pub fn extension(&self) -> bool { self.flags.contains(MechanismInfoFlags::EXTENSION) } /// True if the mechanism can be used to with elliptic curve domain /// parameters over ***Fp*** /// /// **[Conformance](crate#conformance-notes):** /// *At least* one of [`ec_f_p`](Self::ec_f_p) and /// [`ec_f_2m`](Self::ec_f_2m) must be `true` pub fn ec_f_p(&self) -> bool { self.flags.contains(MechanismInfoFlags::EC_F_P) } /// True if the mechanism can be used with elliptic curve domain parameters /// over ***F2m*** /// /// **[Conformance](crate#conformance-notes):** /// *At least* one of [`ec_f_p`](Self::ec_f_p) and /// [`ec_f_2m`](Self::ec_f_2m) must be `true` pub fn ec_f_2m(&self) -> bool { self.flags.contains(MechanismInfoFlags::EC_F_2M) } /// True if the mechanism supports specifying elliptic curve domain /// parameters explicitly /// /// **[Conformance](crate#conformance-notes):** /// *At least* one of [`ec_from_parameters`](Self::ec_from_parameters) and /// [`ec_from_named_curve`](Self::ec_from_named_curve) must be `true` pub fn ec_from_parameters(&self) -> bool { self.flags.contains(MechanismInfoFlags::EC_ECPARAMETERS) } /// True if the mechanism supports specifying elliptic curve domain /// parameters with a named curve /// /// **[Conformance](crate#conformance-notes):** /// *At least* one of [`ec_from_parameters`](Self::ec_from_parameters) and /// [`ec_from_named_curve`](Self::ec_from_named_curve) must be `true` pub fn ec_from_named_curve(&self) -> bool { self.flags.contains(MechanismInfoFlags::EC_NAMEDCURVE) } /// True if the mechanism can be used with elliptic curve points in /// uncompressed form /// /// **[Conformance](crate#conformance-notes):** /// *At least* one of [`ec_uncompressed`](Self::ec_uncompressed) and /// [`ec_compressed`](Self::ec_compressed) must be `true` pub fn ec_uncompressed(&self) -> bool { self.flags.contains(MechanismInfoFlags::EC_UNCOMPRESS) } /// True if the mechanism can be used with elliptic curve points in /// compressed form /// /// **[Conformance](crate#conformance-notes):** /// *At least* one of [`ec_uncompressed`](Self::ec_uncompressed) and /// [`ec_compressed`](Self::ec_compressed) must be `true` pub fn ec_compressed(&self) -> bool { self.flags.contains(MechanismInfoFlags::EC_COMPRESS) } } #[doc(hidden)] impl From for MechanismInfo { fn from(val: CK_MECHANISM_INFO) -> Self { Self { min_key_size: val.ulMinKeySize as usize, max_key_size: val.ulMaxKeySize as usize, flags: MechanismInfoFlags::from_bits_truncate(val.flags), } } } #[cfg(test)] mod test { use super::{MechanismInfo, MechanismInfoFlags}; #[test] fn debug_flags_all() { let expected = "\ HW | ENCRYPT | DECRYPT | DIGEST | SIGN | SIGN_RECOVER | VERIFY | \ VERIFY_RECOVER | GENERATE | GENERATE_KEY_PAIR | WRAP | UNWRAP | DERIVE | \ EXTENSION | EC_F_P | EC_F_2M | EC_ECPARAMETERS | EC_NAMEDCURVE | \ EC_UNCOMPRESS | EC_COMPRESS"; let all = MechanismInfoFlags::all(); let observed = format!("{all:#?}"); println!("{observed}"); assert_eq!(observed, expected); } #[test] fn debug_info() { let info = MechanismInfo { min_key_size: 16, max_key_size: 4096, flags: MechanismInfoFlags::empty(), }; let expected = r#"MechanismInfo { min_key_size: 16, max_key_size: 4096, flags: (empty), }"#; let observed = format!("{info:#?}"); assert_eq!(observed, expected); } } cryptoki-0.6.1/src/mechanism/mod.rs000064400000000000000000001472541046102023000153710ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Data types for mechanisms pub mod aead; pub mod elliptic_curve; mod mechanism_info; pub mod rsa; use crate::error::Error; use cryptoki_sys::*; use log::error; use std::convert::{TryFrom, TryInto}; use std::ffi::c_void; use std::fmt::Formatter; use std::ops::Deref; use std::ptr::null_mut; pub use mechanism_info::MechanismInfo; #[derive(Copy, Debug, Clone, PartialEq, Eq)] // transparent so that a vector of MechanismType should have the same layout than a vector of // CK_MECHANISM_TYPE. /// Type of a mechanism #[repr(transparent)] pub struct MechanismType { val: CK_MECHANISM_TYPE, } impl MechanismType { // AES /// AES key generation mechanism pub const AES_KEY_GEN: MechanismType = MechanismType { val: CKM_AES_KEY_GEN, }; /// AES-CBC mechanism /// /// For encryption, the message length must be a multiple of the block /// size. For wrapping, the mechanism encrypts the value of the key, /// padded on the trailing end with up to block size minus one null bytes. /// For unwrapping, the result is truncated according to the key type and /// the length provided by the template. pub const AES_CBC: MechanismType = MechanismType { val: CKM_AES_CBC }; /// AES-CBC with PKCS#7 padding mechanism /// /// The plaintext may be any size. The PKCS#7 padding allows the length of /// the plaintext to be recovered from the ciphertext. Therefore no length /// should be provided when unwrapping keys with this mechanism. pub const AES_CBC_PAD: MechanismType = MechanismType { val: CKM_AES_CBC_PAD, }; /// AES-ECB mechanism pub const AES_ECB: MechanismType = MechanismType { val: CKM_AES_ECB }; /// AES key wrap mechanism. This mechanism can only wrap a key or encrypt a block of data /// whose length is a multiple of the AES Key Wrap algorithm block size. pub const AES_KEY_WRAP: MechanismType = MechanismType { val: CKM_AES_KEY_WRAP, }; /// AES key wrap mechanism. This mechanism can wrap a key or encrypt a block of data of any /// length. It does the padding detailed in PKCS#7 of inputs. pub const AES_KEY_WRAP_PAD: MechanismType = MechanismType { val: CKM_AES_KEY_WRAP_PAD, }; /// AES-GCM mechanism pub const AES_GCM: MechanismType = MechanismType { val: CKM_AES_GCM }; // RSA /// PKCS #1 RSA key pair generation mechanism pub const RSA_PKCS_KEY_PAIR_GEN: MechanismType = MechanismType { val: CKM_RSA_PKCS_KEY_PAIR_GEN, }; /// Multi-purpose mechanism based on the RSA public-key cryptosystem and the block formats /// initially defined in PKCS #1 v1.5 pub const RSA_PKCS: MechanismType = MechanismType { val: CKM_RSA_PKCS }; /// Mechanism based on the RSA public-key cryptosystem and the PSS block format defined in PKCS /// #1 pub const RSA_PKCS_PSS: MechanismType = MechanismType { val: CKM_RSA_PKCS_PSS, }; /// Multi-purpose mechanism based on the RSA public-key cryptosystem and the OAEP block format /// defined in PKCS #1 pub const RSA_PKCS_OAEP: MechanismType = MechanismType { val: CKM_RSA_PKCS_OAEP, }; /// Multi-purpose mechanism based on the RSA public-key cryptosystem. This is so-called "raw" /// RSA, as assumed in X.509. pub const RSA_X_509: MechanismType = MechanismType { val: CKM_RSA_X_509 }; // DES /// DES /// Note that DES is deprecated. See section 2, p. 6. pub const DES_KEY_GEN: MechanismType = MechanismType { val: CKM_DES_KEY_GEN, }; /// DES2 /// Note that DES2 is deprecated. See section 2, p. 6. pub const DES2_KEY_GEN: MechanismType = MechanismType { val: CKM_DES2_KEY_GEN, }; /// DES3 /// Note that DES3 is deprecated. See section 2, p. 6. pub const DES3_KEY_GEN: MechanismType = MechanismType { val: CKM_DES3_KEY_GEN, }; /// DES-CBC mechanism. /// /// For encryption, the message length must be a multiple of the block /// size. For wrapping, the mechanism encrypts the value of the key, /// padded on the trailing end with up to block size minus one null bytes. /// For unwrapping, the result is truncated according to the key type and /// the length provided by the template. pub const DES_CBC: MechanismType = MechanismType { val: CKM_DES_CBC }; /// DES3-CBC mechanism. /// /// For encryption, the message length must be a multiple of the block /// size. For wrapping, the mechanism encrypts the value of the key, /// padded on the trailing end with up to block size minus one null bytes. /// For unwrapping, the result is truncated according to the key type and /// the length provided by the template. pub const DES3_CBC: MechanismType = MechanismType { val: CKM_DES3_CBC }; /// DES-CBC with PKCS#7 padding mechanism /// /// The plaintext may be any size. The PKCS#7 padding allows the length of /// the plaintext to be recovered from the ciphertext. Therefore no length /// should be provided when unwrapping keys with this mechanism. pub const DES_CBC_PAD: MechanismType = MechanismType { val: CKM_DES_CBC_PAD, }; /// DES3-CBC with PKCS#7 padding mechanism /// /// The plaintext may be any size. The PKCS#7 padding allows the length of /// the plaintext to be recovered from the ciphertext. Therefore no length /// should be provided when unwrapping keys with this mechanism. pub const DES3_CBC_PAD: MechanismType = MechanismType { val: CKM_DES3_CBC_PAD, }; /// DES ECB /// Note that DES is deprecated. See section 2, p. 6. pub const DES_ECB: MechanismType = MechanismType { val: CKM_DES_ECB }; /// DES3 ECB /// Note that DES3 is deprecated. See 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 { val: CKM_EC_KEY_PAIR_GEN, }; /// EC edwards key pair generation mechanism pub const ECC_EDWARDS_KEY_PAIR_GEN: MechanismType = MechanismType { val: CKM_EC_EDWARDS_KEY_PAIR_GEN, }; /// EC montgomery key pair generation mechanism pub const ECC_MONTGOMERY_KEY_PAIR_GEN: MechanismType = MechanismType { val: CKM_EC_MONTGOMERY_KEY_PAIR_GEN, }; /// EDDSA mechanism /// /// Note: EdDSA is not part of the PKCS#11 v2.40 standard and as /// such may not be understood by the backend. It is included here /// because some vendor implementations support it through the /// v2.40 interface. pub const EDDSA: MechanismType = MechanismType { val: CKM_EDDSA }; /// ECDH key derivation mechanism pub const ECDH1_DERIVE: MechanismType = MechanismType { val: CKM_ECDH1_DERIVE, }; /// ECDSA mechanism pub const ECDSA: MechanismType = MechanismType { val: CKM_ECDSA }; /// ECDSA with SHA-1 mechanism pub const ECDSA_SHA1: MechanismType = MechanismType { val: CKM_ECDSA_SHA1, }; /// ECDSA with SHA-224 mechanism pub const ECDSA_SHA224: MechanismType = MechanismType { val: CKM_ECDSA_SHA224, }; /// ECDSA with SHA-256 mechanism pub const ECDSA_SHA256: MechanismType = MechanismType { val: CKM_ECDSA_SHA256, }; /// ECDSA with SHA-384 mechanism pub const ECDSA_SHA384: MechanismType = MechanismType { val: CKM_ECDSA_SHA384, }; /// ECDSA with SHA-512 mechanism pub const ECDSA_SHA512: MechanismType = MechanismType { val: CKM_ECDSA_SHA512, }; // SHA-n /// SHA-1 mechanism pub const SHA1: MechanismType = MechanismType { val: CKM_SHA_1 }; /// SHA-224 mechanism pub const SHA224: MechanismType = MechanismType { val: CKM_SHA224 }; /// SHA-256 mechanism pub const SHA256: MechanismType = MechanismType { val: CKM_SHA256 }; /// SHA-384 mechanism pub const SHA384: MechanismType = MechanismType { val: CKM_SHA384 }; /// SHA-512 mechanism pub const SHA512: MechanismType = MechanismType { val: CKM_SHA512 }; // SHAn-RSA-PKCS /// SHA1-RSA-PKCS mechanism pub const SHA1_RSA_PKCS: MechanismType = MechanismType { val: CKM_SHA1_RSA_PKCS, }; /// SHA224-RSA-PKCS mechanism pub const SHA224_RSA_PKCS: MechanismType = MechanismType { val: CKM_SHA224_RSA_PKCS, }; /// SHA256-RSA-PKCS mechanism pub const SHA256_RSA_PKCS: MechanismType = MechanismType { val: CKM_SHA256_RSA_PKCS, }; /// SHA384-RSA-PKCS mechanism pub const SHA384_RSA_PKCS: MechanismType = MechanismType { val: CKM_SHA384_RSA_PKCS, }; /// SHA512-RSA-PKCS mechanism pub const SHA512_RSA_PKCS: MechanismType = MechanismType { val: CKM_SHA512_RSA_PKCS, }; // SHAn-RSA-PKCS-PSS /// SHA1-RSA-PKCS-PSS mechanism pub const SHA1_RSA_PKCS_PSS: MechanismType = MechanismType { val: CKM_SHA1_RSA_PKCS_PSS, }; /// SHA256-RSA-PKCS-PSS mechanism pub const SHA256_RSA_PKCS_PSS: MechanismType = MechanismType { val: CKM_SHA256_RSA_PKCS_PSS, }; /// SHA384-RSA-PKCS-PSS mechanism pub const SHA384_RSA_PKCS_PSS: MechanismType = MechanismType { val: CKM_SHA384_RSA_PKCS_PSS, }; /// SHA512-RSA-PKCS-PSS mechanism pub const SHA512_RSA_PKCS_PSS: MechanismType = MechanismType { val: CKM_SHA512_RSA_PKCS_PSS, }; pub(crate) fn stringify(mech: CK_MECHANISM_TYPE) -> String { match mech { CKM_RSA_PKCS_KEY_PAIR_GEN => String::from(stringify!(CKM_RSA_PKCS_KEY_PAIR_GEN)), CKM_RSA_PKCS => String::from(stringify!(CKM_RSA_PKCS)), CKM_RSA_9796 => String::from(stringify!(CKM_RSA_9796)), CKM_RSA_X_509 => String::from(stringify!(CKM_RSA_X_509)), CKM_MD2_RSA_PKCS => String::from(stringify!(CKM_MD2_RSA_PKCS)), CKM_MD5_RSA_PKCS => String::from(stringify!(CKM_MD5_RSA_PKCS)), CKM_SHA1_RSA_PKCS => String::from(stringify!(CKM_SHA1_RSA_PKCS)), CKM_RIPEMD128_RSA_PKCS => String::from(stringify!(CKM_RIPEMD128_RSA_PKCS)), CKM_RIPEMD160_RSA_PKCS => String::from(stringify!(CKM_RIPEMD160_RSA_PKCS)), CKM_RSA_PKCS_OAEP => String::from(stringify!(CKM_RSA_PKCS_OAEP)), CKM_RSA_X9_31_KEY_PAIR_GEN => String::from(stringify!(CKM_RSA_X9_31_KEY_PAIR_GEN)), CKM_RSA_X9_31 => String::from(stringify!(CKM_RSA_X9_31)), CKM_SHA1_RSA_X9_31 => String::from(stringify!(CKM_SHA1_RSA_X9_31)), CKM_RSA_PKCS_PSS => String::from(stringify!(CKM_RSA_PKCS_PSS)), CKM_SHA1_RSA_PKCS_PSS => String::from(stringify!(CKM_SHA1_RSA_PKCS_PSS)), CKM_DSA_KEY_PAIR_GEN => String::from(stringify!(CKM_DSA_KEY_PAIR_GEN)), CKM_DSA => String::from(stringify!(CKM_DSA)), CKM_DSA_SHA1 => String::from(stringify!(CKM_DSA_SHA1)), CKM_DSA_SHA224 => String::from(stringify!(CKM_DSA_SHA224)), CKM_DSA_SHA256 => String::from(stringify!(CKM_DSA_SHA256)), CKM_DSA_SHA384 => String::from(stringify!(CKM_DSA_SHA384)), CKM_DSA_SHA512 => String::from(stringify!(CKM_DSA_SHA512)), CKM_DH_PKCS_KEY_PAIR_GEN => String::from(stringify!(CKM_DH_PKCS_KEY_PAIR_GEN)), CKM_DH_PKCS_DERIVE => String::from(stringify!(CKM_DH_PKCS_DERIVE)), CKM_X9_42_DH_KEY_PAIR_GEN => String::from(stringify!(CKM_X9_42_DH_KEY_PAIR_GEN)), CKM_X9_42_DH_DERIVE => String::from(stringify!(CKM_X9_42_DH_DERIVE)), CKM_X9_42_DH_HYBRID_DERIVE => String::from(stringify!(CKM_X9_42_DH_HYBRID_DERIVE)), CKM_X9_42_MQV_DERIVE => String::from(stringify!(CKM_X9_42_MQV_DERIVE)), CKM_SHA256_RSA_PKCS => String::from(stringify!(CKM_SHA256_RSA_PKCS)), CKM_SHA384_RSA_PKCS => String::from(stringify!(CKM_SHA384_RSA_PKCS)), CKM_SHA512_RSA_PKCS => String::from(stringify!(CKM_SHA512_RSA_PKCS)), CKM_SHA256_RSA_PKCS_PSS => String::from(stringify!(CKM_SHA256_RSA_PKCS_PSS)), CKM_SHA384_RSA_PKCS_PSS => String::from(stringify!(CKM_SHA384_RSA_PKCS_PSS)), CKM_SHA512_RSA_PKCS_PSS => String::from(stringify!(CKM_SHA512_RSA_PKCS_PSS)), CKM_SHA512_224 => String::from(stringify!(CKM_SHA512_224)), CKM_SHA512_224_HMAC => String::from(stringify!(CKM_SHA512_224_HMAC)), CKM_SHA512_224_HMAC_GENERAL => String::from(stringify!(CKM_SHA512_224_HMAC_GENERAL)), CKM_SHA512_224_KEY_DERIVATION => { String::from(stringify!(CKM_SHA512_224_KEY_DERIVATION)) } CKM_SHA512_256 => String::from(stringify!(CKM_SHA512_256)), CKM_SHA512_256_HMAC => String::from(stringify!(CKM_SHA512_256_HMAC)), CKM_SHA512_256_HMAC_GENERAL => String::from(stringify!(CKM_SHA512_256_HMAC_GENERAL)), CKM_SHA512_256_KEY_DERIVATION => { String::from(stringify!(CKM_SHA512_256_KEY_DERIVATION)) } CKM_SHA512_T => String::from(stringify!(CKM_SHA512_T)), CKM_SHA512_T_HMAC => String::from(stringify!(CKM_SHA512_T_HMAC)), CKM_SHA512_T_HMAC_GENERAL => String::from(stringify!(CKM_SHA512_T_HMAC_GENERAL)), CKM_SHA512_T_KEY_DERIVATION => String::from(stringify!(CKM_SHA512_T_KEY_DERIVATION)), CKM_RC2_KEY_GEN => String::from(stringify!(CKM_RC2_KEY_GEN)), CKM_RC2_ECB => String::from(stringify!(CKM_RC2_ECB)), CKM_RC2_CBC => String::from(stringify!(CKM_RC2_CBC)), CKM_RC2_MAC => String::from(stringify!(CKM_RC2_MAC)), CKM_RC2_MAC_GENERAL => String::from(stringify!(CKM_RC2_MAC_GENERAL)), CKM_RC2_CBC_PAD => String::from(stringify!(CKM_RC2_CBC_PAD)), CKM_RC4_KEY_GEN => String::from(stringify!(CKM_RC4_KEY_GEN)), CKM_RC4 => String::from(stringify!(CKM_RC4)), CKM_DES_KEY_GEN => String::from(stringify!(CKM_DES_KEY_GEN)), CKM_DES_ECB => String::from(stringify!(CKM_DES_ECB)), CKM_DES_CBC => String::from(stringify!(CKM_DES_CBC)), CKM_DES_MAC => String::from(stringify!(CKM_DES_MAC)), CKM_DES_MAC_GENERAL => String::from(stringify!(CKM_DES_MAC_GENERAL)), CKM_DES_CBC_PAD => String::from(stringify!(CKM_DES_CBC_PAD)), CKM_DES2_KEY_GEN => String::from(stringify!(CKM_DES2_KEY_GEN)), CKM_DES3_KEY_GEN => String::from(stringify!(CKM_DES3_KEY_GEN)), CKM_DES3_ECB => String::from(stringify!(CKM_DES3_ECB)), CKM_DES3_CBC => String::from(stringify!(CKM_DES3_CBC)), CKM_DES3_MAC => String::from(stringify!(CKM_DES3_MAC)), CKM_DES3_MAC_GENERAL => String::from(stringify!(CKM_DES3_MAC_GENERAL)), CKM_DES3_CBC_PAD => String::from(stringify!(CKM_DES3_CBC_PAD)), CKM_DES3_CMAC_GENERAL => String::from(stringify!(CKM_DES3_CMAC_GENERAL)), CKM_DES3_CMAC => String::from(stringify!(CKM_DES3_CMAC)), CKM_CDMF_KEY_GEN => String::from(stringify!(CKM_CDMF_KEY_GEN)), CKM_CDMF_ECB => String::from(stringify!(CKM_CDMF_ECB)), CKM_CDMF_CBC => String::from(stringify!(CKM_CDMF_CBC)), CKM_CDMF_MAC => String::from(stringify!(CKM_CDMF_MAC)), CKM_CDMF_MAC_GENERAL => String::from(stringify!(CKM_CDMF_MAC_GENERAL)), CKM_CDMF_CBC_PAD => String::from(stringify!(CKM_CDMF_CBC_PAD)), CKM_DES_OFB64 => String::from(stringify!(CKM_DES_OFB64)), CKM_DES_OFB8 => String::from(stringify!(CKM_DES_OFB8)), CKM_DES_CFB64 => String::from(stringify!(CKM_DES_CFB64)), CKM_DES_CFB8 => String::from(stringify!(CKM_DES_CFB8)), CKM_MD2 => String::from(stringify!(CKM_MD2)), CKM_MD2_HMAC => String::from(stringify!(CKM_MD2_HMAC)), CKM_MD2_HMAC_GENERAL => String::from(stringify!(CKM_MD2_HMAC_GENERAL)), CKM_MD5 => String::from(stringify!(CKM_MD5)), CKM_MD5_HMAC => String::from(stringify!(CKM_MD5_HMAC)), CKM_MD5_HMAC_GENERAL => String::from(stringify!(CKM_MD5_HMAC_GENERAL)), CKM_SHA_1 => String::from(stringify!(CKM_SHA_1)), CKM_SHA_1_HMAC => String::from(stringify!(CKM_SHA_1_HMAC)), CKM_SHA_1_HMAC_GENERAL => String::from(stringify!(CKM_SHA_1_HMAC_GENERAL)), CKM_RIPEMD128 => String::from(stringify!(CKM_RIPEMD128)), CKM_RIPEMD128_HMAC => String::from(stringify!(CKM_RIPEMD128_HMAC)), CKM_RIPEMD128_HMAC_GENERAL => String::from(stringify!(CKM_RIPEMD128_HMAC_GENERAL)), CKM_RIPEMD160 => String::from(stringify!(CKM_RIPEMD160)), CKM_RIPEMD160_HMAC => String::from(stringify!(CKM_RIPEMD160_HMAC)), CKM_RIPEMD160_HMAC_GENERAL => String::from(stringify!(CKM_RIPEMD160_HMAC_GENERAL)), CKM_SHA256 => String::from(stringify!(CKM_SHA256)), CKM_SHA256_HMAC => String::from(stringify!(CKM_SHA256_HMAC)), CKM_SHA256_HMAC_GENERAL => String::from(stringify!(CKM_SHA256_HMAC_GENERAL)), CKM_SHA384 => String::from(stringify!(CKM_SHA384)), CKM_SHA384_HMAC => String::from(stringify!(CKM_SHA384_HMAC)), CKM_SHA384_HMAC_GENERAL => String::from(stringify!(CKM_SHA384_HMAC_GENERAL)), CKM_SHA512 => String::from(stringify!(CKM_SHA512)), CKM_SHA512_HMAC => String::from(stringify!(CKM_SHA512_HMAC)), CKM_SHA512_HMAC_GENERAL => String::from(stringify!(CKM_SHA512_HMAC_GENERAL)), CKM_SECURID_KEY_GEN => String::from(stringify!(CKM_SECURID_KEY_GEN)), CKM_SECURID => String::from(stringify!(CKM_SECURID)), CKM_HOTP_KEY_GEN => String::from(stringify!(CKM_HOTP_KEY_GEN)), CKM_HOTP => String::from(stringify!(CKM_HOTP)), CKM_ACTI => String::from(stringify!(CKM_ACTI)), CKM_ACTI_KEY_GEN => String::from(stringify!(CKM_ACTI_KEY_GEN)), CKM_CAST_KEY_GEN => String::from(stringify!(CKM_CAST_KEY_GEN)), CKM_CAST_ECB => String::from(stringify!(CKM_CAST_ECB)), CKM_CAST_CBC => String::from(stringify!(CKM_CAST_CBC)), CKM_CAST_MAC => String::from(stringify!(CKM_CAST_MAC)), CKM_CAST_MAC_GENERAL => String::from(stringify!(CKM_CAST_MAC_GENERAL)), CKM_CAST_CBC_PAD => String::from(stringify!(CKM_CAST_CBC_PAD)), CKM_CAST3_KEY_GEN => String::from(stringify!(CKM_CAST3_KEY_GEN)), CKM_CAST3_ECB => String::from(stringify!(CKM_CAST3_ECB)), CKM_CAST3_CBC => String::from(stringify!(CKM_CAST3_CBC)), CKM_CAST3_MAC => String::from(stringify!(CKM_CAST3_MAC)), CKM_CAST3_MAC_GENERAL => String::from(stringify!(CKM_CAST3_MAC_GENERAL)), CKM_CAST3_CBC_PAD => String::from(stringify!(CKM_CAST3_CBC_PAD)), CKM_CAST128_KEY_GEN => String::from(stringify!(CKM_CAST128_KEY_GEN)), CKM_CAST128_ECB => String::from(stringify!(CKM_CAST128_ECB)), CKM_CAST128_CBC => String::from(stringify!(CKM_CAST128_CBC)), CKM_CAST128_MAC => String::from(stringify!(CKM_CAST128_MAC)), CKM_CAST128_MAC_GENERAL => String::from(stringify!(CKM_CAST128_MAC_GENERAL)), CKM_CAST128_CBC_PAD => String::from(stringify!(CKM_CAST128_CBC_PAD)), CKM_RC5_KEY_GEN => String::from(stringify!(CKM_RC5_KEY_GEN)), CKM_RC5_ECB => String::from(stringify!(CKM_RC5_ECB)), CKM_RC5_CBC => String::from(stringify!(CKM_RC5_CBC)), CKM_RC5_MAC => String::from(stringify!(CKM_RC5_MAC)), CKM_RC5_MAC_GENERAL => String::from(stringify!(CKM_RC5_MAC_GENERAL)), CKM_RC5_CBC_PAD => String::from(stringify!(CKM_RC5_CBC_PAD)), CKM_IDEA_KEY_GEN => String::from(stringify!(CKM_IDEA_KEY_GEN)), CKM_IDEA_ECB => String::from(stringify!(CKM_IDEA_ECB)), CKM_IDEA_CBC => String::from(stringify!(CKM_IDEA_CBC)), CKM_IDEA_MAC => String::from(stringify!(CKM_IDEA_MAC)), CKM_IDEA_MAC_GENERAL => String::from(stringify!(CKM_IDEA_MAC_GENERAL)), CKM_IDEA_CBC_PAD => String::from(stringify!(CKM_IDEA_CBC_PAD)), CKM_GENERIC_SECRET_KEY_GEN => String::from(stringify!(CKM_GENERIC_SECRET_KEY_GEN)), CKM_CONCATENATE_BASE_AND_KEY => String::from(stringify!(CKM_CONCATENATE_BASE_AND_KEY)), CKM_CONCATENATE_BASE_AND_DATA => { String::from(stringify!(CKM_CONCATENATE_BASE_AND_DATA)) } CKM_CONCATENATE_DATA_AND_BASE => { String::from(stringify!(CKM_CONCATENATE_DATA_AND_BASE)) } CKM_XOR_BASE_AND_DATA => String::from(stringify!(CKM_XOR_BASE_AND_DATA)), CKM_EXTRACT_KEY_FROM_KEY => String::from(stringify!(CKM_EXTRACT_KEY_FROM_KEY)), CKM_SSL3_PRE_MASTER_KEY_GEN => String::from(stringify!(CKM_SSL3_PRE_MASTER_KEY_GEN)), CKM_SSL3_MASTER_KEY_DERIVE => String::from(stringify!(CKM_SSL3_MASTER_KEY_DERIVE)), CKM_SSL3_KEY_AND_MAC_DERIVE => String::from(stringify!(CKM_SSL3_KEY_AND_MAC_DERIVE)), CKM_SSL3_MASTER_KEY_DERIVE_DH => { String::from(stringify!(CKM_SSL3_MASTER_KEY_DERIVE_DH)) } CKM_TLS_PRE_MASTER_KEY_GEN => String::from(stringify!(CKM_TLS_PRE_MASTER_KEY_GEN)), CKM_TLS_MASTER_KEY_DERIVE => String::from(stringify!(CKM_TLS_MASTER_KEY_DERIVE)), CKM_TLS_KEY_AND_MAC_DERIVE => String::from(stringify!(CKM_TLS_KEY_AND_MAC_DERIVE)), CKM_TLS_MASTER_KEY_DERIVE_DH => String::from(stringify!(CKM_TLS_MASTER_KEY_DERIVE_DH)), CKM_TLS_PRF => String::from(stringify!(CKM_TLS_PRF)), CKM_SSL3_MD5_MAC => String::from(stringify!(CKM_SSL3_MD5_MAC)), CKM_SSL3_SHA1_MAC => String::from(stringify!(CKM_SSL3_SHA1_MAC)), CKM_MD5_KEY_DERIVATION => String::from(stringify!(CKM_MD5_KEY_DERIVATION)), CKM_MD2_KEY_DERIVATION => String::from(stringify!(CKM_MD2_KEY_DERIVATION)), CKM_SHA1_KEY_DERIVATION => String::from(stringify!(CKM_SHA1_KEY_DERIVATION)), CKM_SHA256_KEY_DERIVATION => String::from(stringify!(CKM_SHA256_KEY_DERIVATION)), CKM_SHA384_KEY_DERIVATION => String::from(stringify!(CKM_SHA384_KEY_DERIVATION)), CKM_SHA512_KEY_DERIVATION => String::from(stringify!(CKM_SHA512_KEY_DERIVATION)), CKM_PBE_MD2_DES_CBC => String::from(stringify!(CKM_PBE_MD2_DES_CBC)), CKM_PBE_MD5_DES_CBC => String::from(stringify!(CKM_PBE_MD5_DES_CBC)), CKM_PBE_MD5_CAST_CBC => String::from(stringify!(CKM_PBE_MD5_CAST_CBC)), CKM_PBE_MD5_CAST3_CBC => String::from(stringify!(CKM_PBE_MD5_CAST3_CBC)), CKM_PBE_MD5_CAST128_CBC => String::from(stringify!(CKM_PBE_MD5_CAST128_CBC)), CKM_PBE_SHA1_CAST128_CBC => String::from(stringify!(CKM_PBE_SHA1_CAST128_CBC)), CKM_PBE_SHA1_RC4_128 => String::from(stringify!(CKM_PBE_SHA1_RC4_128)), CKM_PBE_SHA1_RC4_40 => String::from(stringify!(CKM_PBE_SHA1_RC4_40)), CKM_PBE_SHA1_DES3_EDE_CBC => String::from(stringify!(CKM_PBE_SHA1_DES3_EDE_CBC)), CKM_PBE_SHA1_DES2_EDE_CBC => String::from(stringify!(CKM_PBE_SHA1_DES2_EDE_CBC)), CKM_PBE_SHA1_RC2_128_CBC => String::from(stringify!(CKM_PBE_SHA1_RC2_128_CBC)), CKM_PBE_SHA1_RC2_40_CBC => String::from(stringify!(CKM_PBE_SHA1_RC2_40_CBC)), CKM_PKCS5_PBKD2 => String::from(stringify!(CKM_PKCS5_PBKD2)), CKM_PBA_SHA1_WITH_SHA1_HMAC => String::from(stringify!(CKM_PBA_SHA1_WITH_SHA1_HMAC)), CKM_WTLS_PRE_MASTER_KEY_GEN => String::from(stringify!(CKM_WTLS_PRE_MASTER_KEY_GEN)), CKM_WTLS_MASTER_KEY_DERIVE => String::from(stringify!(CKM_WTLS_MASTER_KEY_DERIVE)), CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC => { String::from(stringify!(CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC)) } CKM_WTLS_PRF => String::from(stringify!(CKM_WTLS_PRF)), CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE => { String::from(stringify!(CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE)) } CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE => { String::from(stringify!(CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE)) } CKM_TLS10_MAC_SERVER => String::from(stringify!(CKM_TLS10_MAC_SERVER)), CKM_TLS10_MAC_CLIENT => String::from(stringify!(CKM_TLS10_MAC_CLIENT)), CKM_TLS12_MAC => String::from(stringify!(CKM_TLS12_MAC)), CKM_TLS12_KDF => String::from(stringify!(CKM_TLS12_KDF)), CKM_TLS12_MASTER_KEY_DERIVE => String::from(stringify!(CKM_TLS12_MASTER_KEY_DERIVE)), CKM_TLS12_KEY_AND_MAC_DERIVE => String::from(stringify!(CKM_TLS12_KEY_AND_MAC_DERIVE)), CKM_TLS12_MASTER_KEY_DERIVE_DH => { String::from(stringify!(CKM_TLS12_MASTER_KEY_DERIVE_DH)) } CKM_TLS12_KEY_SAFE_DERIVE => String::from(stringify!(CKM_TLS12_KEY_SAFE_DERIVE)), CKM_TLS_MAC => String::from(stringify!(CKM_TLS_MAC)), CKM_TLS_KDF => String::from(stringify!(CKM_TLS_KDF)), CKM_KEY_WRAP_LYNKS => String::from(stringify!(CKM_KEY_WRAP_LYNKS)), CKM_KEY_WRAP_SET_OAEP => String::from(stringify!(CKM_KEY_WRAP_SET_OAEP)), CKM_CMS_SIG => String::from(stringify!(CKM_CMS_SIG)), CKM_KIP_DERIVE => String::from(stringify!(CKM_KIP_DERIVE)), CKM_KIP_WRAP => String::from(stringify!(CKM_KIP_WRAP)), CKM_KIP_MAC => String::from(stringify!(CKM_KIP_MAC)), CKM_CAMELLIA_KEY_GEN => String::from(stringify!(CKM_CAMELLIA_KEY_GEN)), CKM_CAMELLIA_CTR => String::from(stringify!(CKM_CAMELLIA_CTR)), CKM_ARIA_KEY_GEN => String::from(stringify!(CKM_ARIA_KEY_GEN)), CKM_ARIA_ECB => String::from(stringify!(CKM_ARIA_ECB)), CKM_ARIA_CBC => String::from(stringify!(CKM_ARIA_CBC)), CKM_ARIA_MAC => String::from(stringify!(CKM_ARIA_MAC)), CKM_ARIA_MAC_GENERAL => String::from(stringify!(CKM_ARIA_MAC_GENERAL)), CKM_ARIA_CBC_PAD => String::from(stringify!(CKM_ARIA_CBC_PAD)), CKM_ARIA_ECB_ENCRYPT_DATA => String::from(stringify!(CKM_ARIA_ECB_ENCRYPT_DATA)), CKM_ARIA_CBC_ENCRYPT_DATA => String::from(stringify!(CKM_ARIA_CBC_ENCRYPT_DATA)), CKM_SEED_KEY_GEN => String::from(stringify!(CKM_SEED_KEY_GEN)), CKM_SEED_ECB => String::from(stringify!(CKM_SEED_ECB)), CKM_SEED_CBC => String::from(stringify!(CKM_SEED_CBC)), CKM_SEED_MAC => String::from(stringify!(CKM_SEED_MAC)), CKM_SEED_MAC_GENERAL => String::from(stringify!(CKM_SEED_MAC_GENERAL)), CKM_SEED_CBC_PAD => String::from(stringify!(CKM_SEED_CBC_PAD)), CKM_SEED_ECB_ENCRYPT_DATA => String::from(stringify!(CKM_SEED_ECB_ENCRYPT_DATA)), CKM_SEED_CBC_ENCRYPT_DATA => String::from(stringify!(CKM_SEED_CBC_ENCRYPT_DATA)), CKM_SKIPJACK_KEY_GEN => String::from(stringify!(CKM_SKIPJACK_KEY_GEN)), CKM_SKIPJACK_ECB64 => String::from(stringify!(CKM_SKIPJACK_ECB64)), CKM_SKIPJACK_CBC64 => String::from(stringify!(CKM_SKIPJACK_CBC64)), CKM_SKIPJACK_OFB64 => String::from(stringify!(CKM_SKIPJACK_OFB64)), CKM_SKIPJACK_CFB64 => String::from(stringify!(CKM_SKIPJACK_CFB64)), CKM_SKIPJACK_CFB32 => String::from(stringify!(CKM_SKIPJACK_CFB32)), CKM_SKIPJACK_CFB16 => String::from(stringify!(CKM_SKIPJACK_CFB16)), CKM_SKIPJACK_CFB8 => String::from(stringify!(CKM_SKIPJACK_CFB8)), CKM_SKIPJACK_WRAP => String::from(stringify!(CKM_SKIPJACK_WRAP)), CKM_SKIPJACK_PRIVATE_WRAP => String::from(stringify!(CKM_SKIPJACK_PRIVATE_WRAP)), CKM_SKIPJACK_RELAYX => String::from(stringify!(CKM_SKIPJACK_RELAYX)), CKM_KEA_KEY_PAIR_GEN => String::from(stringify!(CKM_KEA_KEY_PAIR_GEN)), CKM_KEA_KEY_DERIVE => String::from(stringify!(CKM_KEA_KEY_DERIVE)), CKM_FORTEZZA_TIMESTAMP => String::from(stringify!(CKM_FORTEZZA_TIMESTAMP)), CKM_BATON_KEY_GEN => String::from(stringify!(CKM_BATON_KEY_GEN)), CKM_BATON_ECB128 => String::from(stringify!(CKM_BATON_ECB128)), CKM_BATON_ECB96 => String::from(stringify!(CKM_BATON_ECB96)), CKM_BATON_CBC128 => String::from(stringify!(CKM_BATON_CBC128)), CKM_BATON_COUNTER => String::from(stringify!(CKM_BATON_COUNTER)), CKM_BATON_SHUFFLE => String::from(stringify!(CKM_BATON_SHUFFLE)), CKM_BATON_WRAP => String::from(stringify!(CKM_BATON_WRAP)), CKM_EC_KEY_PAIR_GEN => String::from(stringify!(CKM_EC_KEY_PAIR_GEN)), CKM_ECDSA => String::from(stringify!(CKM_ECDSA)), CKM_ECDSA_SHA1 => String::from(stringify!(CKM_ECDSA_SHA1)), CKM_ECDSA_SHA224 => String::from(stringify!(CKM_ECDSA_SHA224)), CKM_ECDSA_SHA256 => String::from(stringify!(CKM_ECDSA_SHA256)), CKM_ECDSA_SHA384 => String::from(stringify!(CKM_ECDSA_SHA384)), CKM_ECDSA_SHA512 => String::from(stringify!(CKM_ECDSA_SHA512)), CKM_ECDH1_DERIVE => String::from(stringify!(CKM_ECDH1_DERIVE)), CKM_ECDH1_COFACTOR_DERIVE => String::from(stringify!(CKM_ECDH1_COFACTOR_DERIVE)), CKM_ECMQV_DERIVE => String::from(stringify!(CKM_ECMQV_DERIVE)), CKM_ECDH_AES_KEY_WRAP => String::from(stringify!(CKM_ECDH_AES_KEY_WRAP)), CKM_RSA_AES_KEY_WRAP => String::from(stringify!(CKM_RSA_AES_KEY_WRAP)), CKM_JUNIPER_KEY_GEN => String::from(stringify!(CKM_JUNIPER_KEY_GEN)), CKM_JUNIPER_ECB128 => String::from(stringify!(CKM_JUNIPER_ECB128)), CKM_JUNIPER_CBC128 => String::from(stringify!(CKM_JUNIPER_CBC128)), CKM_JUNIPER_COUNTER => String::from(stringify!(CKM_JUNIPER_COUNTER)), CKM_JUNIPER_SHUFFLE => String::from(stringify!(CKM_JUNIPER_SHUFFLE)), CKM_JUNIPER_WRAP => String::from(stringify!(CKM_JUNIPER_WRAP)), CKM_FASTHASH => String::from(stringify!(CKM_FASTHASH)), CKM_AES_KEY_GEN => String::from(stringify!(CKM_AES_KEY_GEN)), CKM_AES_ECB => String::from(stringify!(CKM_AES_ECB)), CKM_AES_CBC => String::from(stringify!(CKM_AES_CBC)), CKM_AES_MAC => String::from(stringify!(CKM_AES_MAC)), CKM_AES_MAC_GENERAL => String::from(stringify!(CKM_AES_MAC_GENERAL)), CKM_AES_CBC_PAD => String::from(stringify!(CKM_AES_CBC_PAD)), CKM_AES_CTR => String::from(stringify!(CKM_AES_CTR)), CKM_AES_GCM => String::from(stringify!(CKM_AES_GCM)), CKM_AES_CCM => String::from(stringify!(CKM_AES_CCM)), CKM_AES_CTS => String::from(stringify!(CKM_AES_CTS)), CKM_AES_CMAC => String::from(stringify!(CKM_AES_CMAC)), CKM_AES_CMAC_GENERAL => String::from(stringify!(CKM_AES_CMAC_GENERAL)), CKM_AES_XCBC_MAC => String::from(stringify!(CKM_AES_XCBC_MAC)), CKM_AES_XCBC_MAC_96 => String::from(stringify!(CKM_AES_XCBC_MAC_96)), CKM_AES_GMAC => String::from(stringify!(CKM_AES_GMAC)), CKM_BLOWFISH_KEY_GEN => String::from(stringify!(CKM_BLOWFISH_KEY_GEN)), CKM_BLOWFISH_CBC => String::from(stringify!(CKM_BLOWFISH_CBC)), CKM_TWOFISH_KEY_GEN => String::from(stringify!(CKM_TWOFISH_KEY_GEN)), CKM_TWOFISH_CBC => String::from(stringify!(CKM_TWOFISH_CBC)), CKM_BLOWFISH_CBC_PAD => String::from(stringify!(CKM_BLOWFISH_CBC_PAD)), CKM_TWOFISH_CBC_PAD => String::from(stringify!(CKM_TWOFISH_CBC_PAD)), CKM_DES_ECB_ENCRYPT_DATA => String::from(stringify!(CKM_DES_ECB_ENCRYPT_DATA)), CKM_DES_CBC_ENCRYPT_DATA => String::from(stringify!(CKM_DES_CBC_ENCRYPT_DATA)), CKM_DES3_ECB_ENCRYPT_DATA => String::from(stringify!(CKM_DES3_ECB_ENCRYPT_DATA)), CKM_DES3_CBC_ENCRYPT_DATA => String::from(stringify!(CKM_DES3_CBC_ENCRYPT_DATA)), CKM_AES_ECB_ENCRYPT_DATA => String::from(stringify!(CKM_AES_ECB_ENCRYPT_DATA)), CKM_AES_CBC_ENCRYPT_DATA => String::from(stringify!(CKM_AES_CBC_ENCRYPT_DATA)), CKM_GOSTR3410_KEY_PAIR_GEN => String::from(stringify!(CKM_GOSTR3410_KEY_PAIR_GEN)), CKM_GOSTR3410 => String::from(stringify!(CKM_GOSTR3410)), CKM_GOSTR3410_WITH_GOSTR3411 => String::from(stringify!(CKM_GOSTR3410_WITH_GOSTR3411)), CKM_GOSTR3410_KEY_WRAP => String::from(stringify!(CKM_GOSTR3410_KEY_WRAP)), CKM_GOSTR3410_DERIVE => String::from(stringify!(CKM_GOSTR3410_DERIVE)), CKM_GOSTR3411 => String::from(stringify!(CKM_GOSTR3411)), CKM_GOSTR3411_HMAC => String::from(stringify!(CKM_GOSTR3411_HMAC)), CKM_GOST28147_KEY_GEN => String::from(stringify!(CKM_GOST28147_KEY_GEN)), CKM_GOST28147_ECB => String::from(stringify!(CKM_GOST28147_ECB)), CKM_GOST28147 => String::from(stringify!(CKM_GOST28147)), CKM_GOST28147_MAC => String::from(stringify!(CKM_GOST28147_MAC)), CKM_GOST28147_KEY_WRAP => String::from(stringify!(CKM_GOST28147_KEY_WRAP)), CKM_DSA_PARAMETER_GEN => String::from(stringify!(CKM_DSA_PARAMETER_GEN)), CKM_DH_PKCS_PARAMETER_GEN => String::from(stringify!(CKM_DH_PKCS_PARAMETER_GEN)), CKM_X9_42_DH_PARAMETER_GEN => String::from(stringify!(CKM_X9_42_DH_PARAMETER_GEN)), CKM_DSA_PROBABLISTIC_PARAMETER_GEN => { String::from(stringify!(CKM_DSA_PROBABLISTIC_PARAMETER_GEN)) } CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN => { String::from(stringify!(CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN)) } CKM_AES_OFB => String::from(stringify!(CKM_AES_OFB)), CKM_AES_CFB64 => String::from(stringify!(CKM_AES_CFB64)), CKM_AES_CFB8 => String::from(stringify!(CKM_AES_CFB8)), CKM_AES_CFB128 => String::from(stringify!(CKM_AES_CFB128)), CKM_AES_CFB1 => String::from(stringify!(CKM_AES_CFB1)), CKM_VENDOR_DEFINED => String::from(stringify!(CKM_VENDOR_DEFINED)), CKM_SHA224 => String::from(stringify!(CKM_SHA224)), CKM_SHA224_HMAC => String::from(stringify!(CKM_SHA224_HMAC)), CKM_SHA224_HMAC_GENERAL => String::from(stringify!(CKM_SHA224_HMAC_GENERAL)), CKM_SHA224_RSA_PKCS => String::from(stringify!(CKM_SHA224_RSA_PKCS)), CKM_SHA224_RSA_PKCS_PSS => String::from(stringify!(CKM_SHA224_RSA_PKCS_PSS)), CKM_SHA224_KEY_DERIVATION => String::from(stringify!(CKM_SHA224_KEY_DERIVATION)), CKM_CAMELLIA_ECB => String::from(stringify!(CKM_CAMELLIA_ECB)), CKM_CAMELLIA_CBC => String::from(stringify!(CKM_CAMELLIA_CBC)), CKM_CAMELLIA_MAC => String::from(stringify!(CKM_CAMELLIA_MAC)), CKM_CAMELLIA_MAC_GENERAL => String::from(stringify!(CKM_CAMELLIA_MAC_GENERAL)), CKM_CAMELLIA_CBC_PAD => String::from(stringify!(CKM_CAMELLIA_CBC_PAD)), CKM_CAMELLIA_ECB_ENCRYPT_DATA => { String::from(stringify!(CKM_CAMELLIA_ECB_ENCRYPT_DATA)) } CKM_CAMELLIA_CBC_ENCRYPT_DATA => { String::from(stringify!(CKM_CAMELLIA_CBC_ENCRYPT_DATA)) } CKM_AES_KEY_WRAP => String::from(stringify!(CKM_AES_KEY_WRAP)), CKM_AES_KEY_WRAP_PAD => String::from(stringify!(CKM_AES_KEY_WRAP_PAD)), CKM_RSA_PKCS_TPM_1_1 => String::from(stringify!(CKM_RSA_PKCS_TPM_1_1)), CKM_RSA_PKCS_OAEP_TPM_1_1 => String::from(stringify!(CKM_RSA_PKCS_OAEP_TPM_1_1)), CKM_EC_EDWARDS_KEY_PAIR_GEN => String::from(stringify!(CKM_EC_EDWARDS_KEY_PAIR_GEN)), CKM_EC_MONTGOMERY_KEY_PAIR_GEN => { String::from(stringify!(CKM_EC_MONTGOMERY_KEY_PAIR_GEN)) } CKM_EDDSA => String::from(stringify!(CKM_EDDSA)), _ => format!("unknown {mech:08x}"), } } } impl std::fmt::Display for MechanismType { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", MechanismType::stringify(self.val)) } } impl Deref for MechanismType { type Target = CK_MECHANISM_TYPE; fn deref(&self) -> &Self::Target { &self.val } } impl From for CK_MECHANISM_TYPE { fn from(mechanism_type: MechanismType) -> Self { *mechanism_type } } impl TryFrom for MechanismType { type Error = Error; fn try_from(mechanism_type: CK_MECHANISM_TYPE) -> Result { match mechanism_type { CKM_AES_KEY_GEN => Ok(MechanismType::AES_KEY_GEN), CKM_RSA_PKCS_KEY_PAIR_GEN => Ok(MechanismType::RSA_PKCS_KEY_PAIR_GEN), CKM_RSA_PKCS => Ok(MechanismType::RSA_PKCS), CKM_RSA_PKCS_PSS => Ok(MechanismType::RSA_PKCS_PSS), CKM_RSA_PKCS_OAEP => Ok(MechanismType::RSA_PKCS_OAEP), CKM_SHA_1 => Ok(MechanismType::SHA1), 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), CKM_EDDSA => Ok(MechanismType::EDDSA), CKM_ECDH1_DERIVE => Ok(MechanismType::ECDH1_DERIVE), CKM_ECDSA => Ok(MechanismType::ECDSA), CKM_SHA256_RSA_PKCS => Ok(MechanismType::SHA256_RSA_PKCS), CKM_SHA384_RSA_PKCS => Ok(MechanismType::SHA384_RSA_PKCS), CKM_SHA512_RSA_PKCS => Ok(MechanismType::SHA512_RSA_PKCS), other => { error!("Mechanism type {} is not supported.", other); Err(Error::NotSupported) } } } } #[derive(Copy, Debug, Clone)] #[non_exhaustive] /// Type defining a specific mechanism and its parameters pub enum Mechanism<'a> { // AES /// AES key gen mechanism AesKeyGen, /// AES-CBC mechanism /// /// The parameter to this mechanism is the initialization vector. /// /// For encryption, the message length must be a multiple of the block /// size. For wrapping, the mechanism encrypts the value of the key, /// padded on the trailing end with up to block size minus one null bytes. /// For unwrapping, the result is truncated according to the key type and /// the length provided by the template. AesCbc([u8; 16]), /// AES-CBC with PKCS#7 padding mechanism /// /// The parameter to this mechanism is the initialization vector. /// /// The plaintext may be any size. The PKCS#7 padding allows the length of /// the plaintext to be recovered from the ciphertext. Therefore no length /// should be provided when unwrapping keys with this mechanism. AesCbcPad([u8; 16]), /// AES in ECB mode AesEcb, /// AES key wrap AesKeyWrap, /// AES key wrap with padding block AesKeyWrapPad, /// AES-GCM mechanism AesGcm(aead::GcmParams<'a>), // RSA /// PKCS #1 RSA key pair generation mechanism RsaPkcsKeyPairGen, /// Multi-purpose mechanism based on the RSA public-key cryptosystem and the block formats /// initially defined in PKCS #1 v1.5 RsaPkcs, /// Mechanism based on the RSA public-key cryptosystem and the PSS block format defined in PKCS /// #1 RsaPkcsPss(rsa::PkcsPssParams), /// Multi-purpose mechanism based on the RSA public-key cryptosystem and the OAEP block format /// defined in PKCS #1 RsaPkcsOaep(rsa::PkcsOaepParams<'a>), /// Multi-purpose mechanism based on the RSA public-key cryptosystem. This is so-called "raw" /// RSA, as assumed in X.509. RsaX509, // DES /// DES DesKeyGen, /// DES2 Des2KeyGen, /// DES3 Des3KeyGen, /// DES-CBC mechanism /// /// The parameter to this mechanism is the initialization vector. /// /// For encryption, the message length must be a multiple of the block /// size. For wrapping, the mechanism encrypts the value of the key, /// padded on the trailing end with up to block size minus one null bytes. /// For unwrapping, the result is truncated according to the key type and /// the length provided by the template. DesCbc([u8; 8]), /// DES3-CBC mechanism /// /// The parameter to this mechanism is the initialization vector. /// /// For encryption, the message length must be a multiple of the block /// size. For wrapping, the mechanism encrypts the value of the key, /// padded on the trailing end with up to block size minus one null bytes. /// For unwrapping, the result is truncated according to the key type and /// the length provided by the template. Des3Cbc([u8; 8]), /// DES-CBC with PKCS#7 padding mechanism /// /// The parameter to this mechanism is the initialization vector. /// /// The plaintext may be any size. The PKCS#7 padding allows the length of /// the plaintext to be recovered from the ciphertext. Therefore no length /// should be provided when unwrapping keys with this mechanism. DesCbcPad([u8; 8]), /// DES3-CBC with PKCS#7 padding mechanism /// /// The parameter to this mechanism is the initialization vector. /// /// The plaintext may be any size. The PKCS#7 padding allows the length of /// the plaintext to be recovered from the ciphertext. Therefore no length /// should be provided when unwrapping keys with this mechanism. Des3CbcPad([u8; 8]), /// DES ECB DesEcb, /// DES3 ECB Des3Ecb, // ECC /// EC key pair generation EccKeyPairGen, /// EC edwards key pair generation EccEdwardsKeyPairGen, /// EC montgomery key pair generation EccMontgomeryKeyPairGen, /// ECDH Ecdh1Derive(elliptic_curve::Ecdh1DeriveParams<'a>), /// ECDSA mechanism Ecdsa, /// ECDSA with SHA-1 mechanism EcdsaSha1, /// ECDSA with SHA-224 mechanism EcdsaSha224, /// ECDSA with SHA-256 mechanism EcdsaSha256, /// ECDSA with SHA-384 mechanism EcdsaSha384, /// ECDSA with SHA-512 mechanism EcdsaSha512, /// EDDSA mechanism /// /// Note: EdDSA is not part of the PKCS#11 v2.40 standard and as /// such may not be understood by the backend. It is included here /// because some vendor implementations support it through the /// v2.40 interface. Eddsa, // SHA-n /// SHA-1 mechanism Sha1, /// SHA-224 mechanism Sha224, /// SHA-256 mechanism Sha256, /// SHA-384 mechanism Sha384, /// SHA-512 mechanism Sha512, // SHAn-RSA-PKCS /// SHA1-RSA-PKCS mechanism Sha1RsaPkcs, /// SHA224-RSA-PKCS mechanism Sha224RsaPkcs, /// SHA256-RSA-PKCS mechanism Sha256RsaPkcs, /// SHA384-RSA-PKCS mechanism Sha384RsaPkcs, /// SHA512-RSA-PKCS mechanism Sha512RsaPkcs, // SHAn-RSA-PKCS-PSS /// SHA1-RSA-PKCS-PSS mechanism Sha1RsaPkcsPss(rsa::PkcsPssParams), /// SHA256-RSA-PKCS-PSS mechanism Sha256RsaPkcsPss(rsa::PkcsPssParams), /// SHA256-RSA-PKCS-PSS mechanism Sha384RsaPkcsPss(rsa::PkcsPssParams), /// SHA256-RSA-PKCS-PSS mechanism Sha512RsaPkcsPss(rsa::PkcsPssParams), } impl Mechanism<'_> { /// Get the type of a mechanism pub fn mechanism_type(&self) -> MechanismType { match self { Mechanism::AesKeyGen => MechanismType::AES_KEY_GEN, Mechanism::AesEcb => MechanismType::AES_ECB, Mechanism::AesCbc(_) => MechanismType::AES_CBC, Mechanism::AesCbcPad(_) => MechanismType::AES_CBC_PAD, Mechanism::AesKeyWrap => MechanismType::AES_KEY_WRAP, Mechanism::AesKeyWrapPad => MechanismType::AES_KEY_WRAP_PAD, Mechanism::AesGcm(_) => MechanismType::AES_GCM, Mechanism::RsaPkcsKeyPairGen => MechanismType::RSA_PKCS_KEY_PAIR_GEN, Mechanism::RsaPkcs => MechanismType::RSA_PKCS, Mechanism::RsaPkcsPss(_) => MechanismType::RSA_PKCS_PSS, Mechanism::RsaPkcsOaep(_) => MechanismType::RSA_PKCS_OAEP, Mechanism::RsaX509 => MechanismType::RSA_X_509, Mechanism::DesKeyGen => MechanismType::DES_KEY_GEN, Mechanism::Des2KeyGen => MechanismType::DES2_KEY_GEN, Mechanism::Des3KeyGen => MechanismType::DES3_KEY_GEN, Mechanism::DesCbc(_) => MechanismType::DES_CBC, Mechanism::Des3Cbc(_) => MechanismType::DES3_CBC, Mechanism::DesCbcPad(_) => MechanismType::DES_CBC_PAD, Mechanism::Des3CbcPad(_) => MechanismType::DES3_CBC_PAD, Mechanism::DesEcb => MechanismType::DES_ECB, 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, Mechanism::Eddsa => MechanismType::EDDSA, Mechanism::Ecdh1Derive(_) => MechanismType::ECDH1_DERIVE, Mechanism::Ecdsa => MechanismType::ECDSA, Mechanism::EcdsaSha1 => MechanismType::ECDSA_SHA1, Mechanism::EcdsaSha224 => MechanismType::ECDSA_SHA224, Mechanism::EcdsaSha256 => MechanismType::ECDSA_SHA256, Mechanism::EcdsaSha384 => MechanismType::ECDSA_SHA384, Mechanism::EcdsaSha512 => MechanismType::ECDSA_SHA512, Mechanism::Sha1 => MechanismType::SHA1, Mechanism::Sha224 => MechanismType::SHA224, Mechanism::Sha256 => MechanismType::SHA256, Mechanism::Sha384 => MechanismType::SHA384, Mechanism::Sha512 => MechanismType::SHA512, Mechanism::Sha1RsaPkcs => MechanismType::SHA1_RSA_PKCS, Mechanism::Sha224RsaPkcs => MechanismType::SHA224_RSA_PKCS, Mechanism::Sha256RsaPkcs => MechanismType::SHA256_RSA_PKCS, Mechanism::Sha384RsaPkcs => MechanismType::SHA384_RSA_PKCS, Mechanism::Sha512RsaPkcs => MechanismType::SHA512_RSA_PKCS, Mechanism::Sha1RsaPkcsPss(_) => MechanismType::SHA1_RSA_PKCS_PSS, Mechanism::Sha256RsaPkcsPss(_) => MechanismType::SHA256_RSA_PKCS_PSS, Mechanism::Sha384RsaPkcsPss(_) => MechanismType::SHA384_RSA_PKCS_PSS, Mechanism::Sha512RsaPkcsPss(_) => MechanismType::SHA512_RSA_PKCS_PSS, } } } impl From<&Mechanism<'_>> for CK_MECHANISM { fn from(mech: &Mechanism) -> Self { let mechanism = mech.mechanism_type().into(); match mech { // Mechanisms with parameters Mechanism::AesCbc(params) | Mechanism::AesCbcPad(params) => { make_mechanism(mechanism, params) } Mechanism::DesCbc(params) | Mechanism::Des3Cbc(params) | Mechanism::DesCbcPad(params) | Mechanism::Des3CbcPad(params) => make_mechanism(mechanism, params), Mechanism::AesGcm(params) => CK_MECHANISM { mechanism, pParameter: params as *const _ as *mut c_void, ulParameterLen: std::mem::size_of::() .try_into() .expect("usize can not fit in CK_ULONG"), }, Mechanism::RsaPkcsPss(params) | Mechanism::Sha1RsaPkcsPss(params) | Mechanism::Sha256RsaPkcsPss(params) | Mechanism::Sha384RsaPkcsPss(params) | Mechanism::Sha512RsaPkcsPss(params) => make_mechanism(mechanism, params), Mechanism::RsaPkcsOaep(params) => make_mechanism(mechanism, params), Mechanism::Ecdh1Derive(params) => make_mechanism(mechanism, params), // Mechanisms without parameters Mechanism::AesKeyGen | Mechanism::AesEcb | Mechanism::AesKeyWrap | Mechanism::AesKeyWrapPad | Mechanism::RsaPkcsKeyPairGen | Mechanism::RsaPkcs | Mechanism::RsaX509 | Mechanism::Sha1 | Mechanism::Sha224 | Mechanism::Sha256 | Mechanism::Sha384 | Mechanism::Sha512 | Mechanism::DesKeyGen | Mechanism::Des2KeyGen | Mechanism::Des3KeyGen | Mechanism::DesEcb | Mechanism::Des3Ecb | Mechanism::EccKeyPairGen | Mechanism::EccEdwardsKeyPairGen | Mechanism::EccMontgomeryKeyPairGen | Mechanism::Eddsa | Mechanism::Ecdsa | Mechanism::EcdsaSha1 | Mechanism::EcdsaSha224 | Mechanism::EcdsaSha256 | Mechanism::EcdsaSha384 | Mechanism::EcdsaSha512 | Mechanism::Sha1RsaPkcs | Mechanism::Sha224RsaPkcs | Mechanism::Sha256RsaPkcs | Mechanism::Sha384RsaPkcs | Mechanism::Sha512RsaPkcs => CK_MECHANISM { mechanism, pParameter: null_mut(), ulParameterLen: 0, }, } } } // Make a CK_MECHANISM from mechanism type and parameter fn make_mechanism(mechanism: CK_MECHANISM_TYPE, param: &T) -> CK_MECHANISM { CK_MECHANISM { mechanism, // SAFETY: Although the type signature says *mut, none of the // mechanisms we support involve mutating the parameter, so // this cast is OK. pParameter: param as *const T as *mut c_void, ulParameterLen: std::mem::size_of::() .try_into() .expect("usize can not fit in CK_ULONG"), } } #[cfg(feature = "psa-crypto-conversions")] #[allow(deprecated)] impl TryFrom for Mechanism { type Error = Error; fn try_from(alg: psa_crypto::types::algorithm::Algorithm) -> Result { use psa_crypto::types::algorithm::{ Algorithm, AsymmetricEncryption, AsymmetricSignature, Hash, SignHash, }; match alg { Algorithm::Hash(Hash::Sha1) => Ok(Mechanism::Sha1), Algorithm::Hash(Hash::Sha256) => Ok(Mechanism::Sha256), Algorithm::Hash(Hash::Sha384) => Ok(Mechanism::Sha384), Algorithm::Hash(Hash::Sha512) => Ok(Mechanism::Sha512), Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign { .. }) | Algorithm::AsymmetricEncryption(AsymmetricEncryption::RsaPkcs1v15Crypt { .. }) => { Ok(Mechanism::RsaPkcs) } Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPss { hash_alg: SignHash::Specific(hash_alg), }) => Ok(Mechanism::RsaPkcsPss(rsa::PkcsPssParams { hash_alg: Mechanism::try_from(Algorithm::from(hash_alg))?.mechanism_type(), mgf: rsa::PkcsMgfType::from_psa_crypto_hash(hash_alg)?, s_len: hash_alg.hash_length().try_into()?, })), Algorithm::AsymmetricSignature(AsymmetricSignature::Ecdsa { .. }) => { Ok(Mechanism::Ecdsa) } Algorithm::AsymmetricEncryption(AsymmetricEncryption::RsaOaep { hash_alg }) => { Ok(Mechanism::RsaPkcsOaep(rsa::PkcsOaepParams { hash_alg: Mechanism::try_from(Algorithm::from(hash_alg))?.mechanism_type(), mgf: rsa::PkcsMgfType::from_psa_crypto_hash(hash_alg)?, source: rsa::PkcsOaepSourceType::DATA_SPECIFIED, source_data: std::ptr::null(), source_data_len: 0.into(), })) } alg => { error!("{:?} is not a supported algorithm", alg); Err(Error::NotSupported) } } } } cryptoki-0.6.1/src/mechanism/rsa.rs000064400000000000000000000144771046102023000153770ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! RSA mechanism types use super::{Mechanism, MechanismType}; use crate::error::{Error, Result}; use crate::types::Ulong; use cryptoki_sys::*; use log::error; use std::convert::{TryFrom, TryInto}; use std::ffi::c_void; use std::marker::PhantomData; use std::ops::Deref; #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(transparent)] /// Message Generation Function (MGF) applied to a message block when formatting a message block /// for the PKCS #1 OAEP encryption scheme or the PKCS #1 PSS signature scheme. pub struct PkcsMgfType { val: CK_RSA_PKCS_MGF_TYPE, } impl PkcsMgfType { /// MGF1 SHA-1 pub const MGF1_SHA1: PkcsMgfType = PkcsMgfType { val: CKG_MGF1_SHA1 }; /// MGF1 SHA-224 pub const MGF1_SHA224: PkcsMgfType = PkcsMgfType { val: CKG_MGF1_SHA224, }; /// MGF1 SHA-256 pub const MGF1_SHA256: PkcsMgfType = PkcsMgfType { val: CKG_MGF1_SHA256, }; /// MGF1 SHA-384 pub const MGF1_SHA384: PkcsMgfType = PkcsMgfType { val: CKG_MGF1_SHA384, }; /// MGF1 SHA-512 pub const MGF1_SHA512: PkcsMgfType = PkcsMgfType { val: CKG_MGF1_SHA512, }; } impl Deref for PkcsMgfType { type Target = CK_RSA_PKCS_MGF_TYPE; fn deref(&self) -> &Self::Target { &self.val } } impl From for CK_RSA_PKCS_MGF_TYPE { fn from(mgf_type: PkcsMgfType) -> Self { *mgf_type } } impl TryFrom for PkcsMgfType { type Error = Error; fn try_from(mgf_type: CK_RSA_PKCS_MGF_TYPE) -> Result { match mgf_type { CKG_MGF1_SHA1 => Ok(PkcsMgfType::MGF1_SHA1), CKG_MGF1_SHA224 => Ok(PkcsMgfType::MGF1_SHA224), CKG_MGF1_SHA256 => Ok(PkcsMgfType::MGF1_SHA256), CKG_MGF1_SHA384 => Ok(PkcsMgfType::MGF1_SHA384), CKG_MGF1_SHA512 => Ok(PkcsMgfType::MGF1_SHA512), other => { error!( "Mask Generation Function type {} is not one of the valid values.", other ); Err(Error::InvalidValue) } } } } #[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>(Option<&'a [u8]>); impl<'a> PkcsOaepSource<'a> { /// Construct an empty encoding parameter. /// /// This is equivalent to `data_specified(&[])`. pub fn empty() -> Self { Self(None) } /// Construct an encoding parameter from an array of bytes. pub fn data_specified(source_data: &'a [u8]) -> Self { Self(Some(source_data)) } pub(crate) fn source_ptr(&self) -> *const c_void { 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") } pub(crate) fn source_type(&self) -> CK_RSA_PKCS_OAEP_SOURCE_TYPE { CKZ_DATA_SPECIFIED } } /// Parameters of the RsaPkcsPss mechanism #[derive(Copy, Debug, Clone)] #[repr(C)] pub struct PkcsPssParams { /// hash algorithm used in the PSS encoding; if the signature mechanism does not include /// message hashing, then this value must be the mechanism used by the application to generate /// the message hash; if the signature mechanism includes hashing, then this value must match /// the hash algorithm indicated by the signature mechanism pub hash_alg: MechanismType, /// mask generation function to use on the encoded block pub mgf: PkcsMgfType, /// length, in bytes, of the salt value used in the PSS encoding; typical values are the length /// of the message hash and zero pub s_len: Ulong, } /// Parameters of the RsaPkcsOaep mechanism #[derive(Copy, Debug, Clone)] #[repr(C)] pub struct PkcsOaepParams<'a> { /// mechanism ID of the message digest algorithm used to calculate the digest of the encoding /// parameter hash_alg: MechanismType, /// mask generation function to use on the encoded block mgf: PkcsMgfType, /// source of the encoding parameter source: CK_RSA_PKCS_OAEP_SOURCE_TYPE, /// data used as the input for the encoding parameter source source_data: *const c_void, /// length of the encoding parameter source input source_data_len: Ulong, /// marker type to ensure we don't outlive the source_data _marker: PhantomData<&'a [u8]>, } impl<'a> PkcsOaepParams<'a> { /// Construct a new `PkcsOaepParams`. /// /// # Arguments /// /// * `hash_alg` - The message digest algorithm used to calculate /// a digest of the encoding parameter. /// * `mgf` - The mask generation function to use on the encoded block. /// * `encoding_parameter` - The encoding parameter, also known as the label. pub fn new( hash_alg: MechanismType, mgf: PkcsMgfType, encoding_parameter: PkcsOaepSource<'a>, ) -> Self { PkcsOaepParams { hash_alg, mgf, source: encoding_parameter.source_type(), source_data: encoding_parameter.source_ptr(), source_data_len: encoding_parameter.source_len(), _marker: PhantomData, } } } impl<'a> From> for Mechanism<'a> { fn from(pkcs_oaep_params: PkcsOaepParams<'a>) -> Self { Mechanism::RsaPkcsOaep(pkcs_oaep_params) } } #[cfg(feature = "psa-crypto-conversions")] #[allow(deprecated)] impl PkcsMgfType { /// Convert a PSA Crypto Hash algorithm to a MGF type pub fn from_psa_crypto_hash(alg: psa_crypto::types::algorithm::Hash) -> Result { use psa_crypto::types::algorithm::Hash; match alg { Hash::Sha1 => Ok(PkcsMgfType::MGF1_SHA1), Hash::Sha224 => Ok(PkcsMgfType::MGF1_SHA224), Hash::Sha256 => Ok(PkcsMgfType::MGF1_SHA256), Hash::Sha384 => Ok(PkcsMgfType::MGF1_SHA384), Hash::Sha512 => Ok(PkcsMgfType::MGF1_SHA512), alg => { error!("{:?} is not a supported MGF1 algorithm", alg); Err(Error::NotSupported) } } } } cryptoki-0.6.1/src/object.rs000064400000000000000000001701451046102023000141070ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Object types (including Attributes) use crate::error::{Error, Result}; use crate::mechanism::MechanismType; use crate::types::{Date, Ulong}; use cryptoki_sys::*; use log::error; use std::convert::TryFrom; use std::convert::TryInto; use std::ffi::c_void; use std::fmt::Formatter; use std::ops::Deref; #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] #[non_exhaustive] /// Type of an attribute pub enum AttributeType { /// DER-encoding of the attribute certificate's issuer AcIssuer, /// List of mechanisms allowed to be used with the key AllowedMechanisms, /// Indicates that the user has to supply the PIN for each use with the key AlwaysAuthenticate, /// Indicates if the key has always had the Sensitive attribute set to true AlwaysSensitive, /// Description of the application that manages the object Application, /// BER-encoding of a sequence of object identifier values AttrTypes, /// Base number value of a key Base, /// Type of certificate CertificateType, /// Checksum CheckValue, /// Type of an object Class, /// The CRT coefficient `iqmp` of an RSA private key Coefficient, /// Determines if an object can be copied Copyable, /// Determines if a key supports decryption Decrypt, /// Determines if it is possible to derive other keys from the key Derive, /// Determines if it is possible to destroy an object Destroyable, /// Parameters defining an elliptic curve EcParams, /// DER-encoded Elliptic Curve point EcPoint, /// Determines if a key supports encryption Encrypt, /// The end date for the object EndDate, /// The private exponent `dmp1` of an RSA private key Exponent1, /// The private exponent `dmq1` of an RSA private key Exponent2, /// Determines if a key is extractable and can be wrapped Extractable, /// Hash of issuer public key HashOfIssuerPublicKey, /// Hash of subject public key HashOfSubjectPublicKey, /// Key identifier for key Id, /// DER-encoding of the certificate issuer name Issuer, /// Identifier of the mechanism used to generate the key material KeyGenMechanism, /// Type of a key KeyType, /// Description of the object Label, /// Indicates if the key was generated locally or copied from a locally created object Local, /// Determines if the object can be modified Modifiable, /// Modulus value of a key Modulus, /// Length in bits of the modulus of a key ModulusBits, /// Indicates if the key has never had the Extractable attribute set to true NeverExtractable, /// Object ID ObjectId, /// DER encoding of the attribute certificate's subject field Owner, /// Prime number value of a key Prime, /// The prime `p` of an RSA private key Prime1, /// The prime `q` of an RSA private key Prime2, /// Determines if the object is private Private, /// Private exponent `d` PrivateExponent, /// Public exponent value of a key PublicExponent, /// DER-encoding of the SubjectPublicKeyInfo PublicKeyInfo, /// Determines if the key is sensitive Sensitive, /// DER encoding of the certificate serial number SerialNumber, /// Determines if a key supports signing Sign, /// Determines if a key supports signing where the data can be recovered from the signature SignRecover, /// The start date of the object StartDate, /// DER-encoding of certificate subject name Subject, /// Determines if the object is a token object Token, /// Determines if the object is trusted Trusted, /// Determines if a key supports unwrapping Unwrap, /// Gives the URL where the complete certificate can be obtained Url, /// Value of the object Value, /// Length in bytes of the value ValueLen, /// Determines if a key supports verifying Verify, /// Determines if a key supports verifying where the data can be recovered from the signature VerifyRecover, /// Determines if a key supports wrapping Wrap, /// Indicates that the key can only be wrapped with a wrapping key that has the Trusted attribute WrapWithTrusted, } impl AttributeType { pub(crate) fn stringify(val: CK_ATTRIBUTE_TYPE) -> String { match val { CKA_CLASS => String::from(stringify!(CKA_CLASS)), CKA_TOKEN => String::from(stringify!(CKA_TOKEN)), CKA_PRIVATE => String::from(stringify!(CKA_PRIVATE)), CKA_LABEL => String::from(stringify!(CKA_LABEL)), CKA_APPLICATION => String::from(stringify!(CKA_APPLICATION)), CKA_VALUE => String::from(stringify!(CKA_VALUE)), CKA_OBJECT_ID => String::from(stringify!(CKA_OBJECT_ID)), CKA_CERTIFICATE_TYPE => String::from(stringify!(CKA_CERTIFICATE_TYPE)), CKA_ISSUER => String::from(stringify!(CKA_ISSUER)), CKA_SERIAL_NUMBER => String::from(stringify!(CKA_SERIAL_NUMBER)), CKA_AC_ISSUER => String::from(stringify!(CKA_AC_ISSUER)), CKA_OWNER => String::from(stringify!(CKA_OWNER)), CKA_ATTR_TYPES => String::from(stringify!(CKA_ATTR_TYPES)), CKA_TRUSTED => String::from(stringify!(CKA_TRUSTED)), CKA_CERTIFICATE_CATEGORY => String::from(stringify!(CKA_CERTIFICATE_CATEGORY)), CKA_JAVA_MIDP_SECURITY_DOMAIN => { String::from(stringify!(CKA_JAVA_MIDP_SECURITY_DOMAIN)) } CKA_URL => String::from(stringify!(CKA_URL)), CKA_HASH_OF_SUBJECT_PUBLIC_KEY => { String::from(stringify!(CKA_HASH_OF_SUBJECT_PUBLIC_KEY)) } CKA_HASH_OF_ISSUER_PUBLIC_KEY => { String::from(stringify!(CKA_HASH_OF_ISSUER_PUBLIC_KEY)) } CKA_NAME_HASH_ALGORITHM => String::from(stringify!(CKA_NAME_HASH_ALGORITHM)), CKA_CHECK_VALUE => String::from(stringify!(CKA_CHECK_VALUE)), CKA_KEY_TYPE => String::from(stringify!(CKA_KEY_TYPE)), CKA_SUBJECT => String::from(stringify!(CKA_SUBJECT)), CKA_ID => String::from(stringify!(CKA_ID)), CKA_SENSITIVE => String::from(stringify!(CKA_SENSITIVE)), CKA_ENCRYPT => String::from(stringify!(CKA_ENCRYPT)), CKA_DECRYPT => String::from(stringify!(CKA_DECRYPT)), CKA_WRAP => String::from(stringify!(CKA_WRAP)), CKA_UNWRAP => String::from(stringify!(CKA_UNWRAP)), CKA_SIGN => String::from(stringify!(CKA_SIGN)), CKA_SIGN_RECOVER => String::from(stringify!(CKA_SIGN_RECOVER)), CKA_VERIFY => String::from(stringify!(CKA_VERIFY)), CKA_VERIFY_RECOVER => String::from(stringify!(CKA_VERIFY_RECOVER)), CKA_DERIVE => String::from(stringify!(CKA_DERIVE)), CKA_START_DATE => String::from(stringify!(CKA_START_DATE)), CKA_END_DATE => String::from(stringify!(CKA_END_DATE)), CKA_MODULUS => String::from(stringify!(CKA_MODULUS)), CKA_MODULUS_BITS => String::from(stringify!(CKA_MODULUS_BITS)), CKA_PUBLIC_EXPONENT => String::from(stringify!(CKA_PUBLIC_EXPONENT)), CKA_PRIVATE_EXPONENT => String::from(stringify!(CKA_PRIVATE_EXPONENT)), CKA_PRIME_1 => String::from(stringify!(CKA_PRIME_1)), CKA_PRIME_2 => String::from(stringify!(CKA_PRIME_2)), CKA_EXPONENT_1 => String::from(stringify!(CKA_EXPONENT_1)), CKA_EXPONENT_2 => String::from(stringify!(CKA_EXPONENT_2)), CKA_COEFFICIENT => String::from(stringify!(CKA_COEFFICIENT)), CKA_PUBLIC_KEY_INFO => String::from(stringify!(CKA_PUBLIC_KEY_INFO)), CKA_PRIME => String::from(stringify!(CKA_PRIME)), CKA_SUBPRIME => String::from(stringify!(CKA_SUBPRIME)), CKA_BASE => String::from(stringify!(CKA_BASE)), CKA_PRIME_BITS => String::from(stringify!(CKA_PRIME_BITS)), CKA_SUB_PRIME_BITS => String::from(stringify!(CKA_SUB_PRIME_BITS)), CKA_VALUE_BITS => String::from(stringify!(CKA_VALUE_BITS)), CKA_VALUE_LEN => String::from(stringify!(CKA_VALUE_LEN)), CKA_EXTRACTABLE => String::from(stringify!(CKA_EXTRACTABLE)), CKA_LOCAL => String::from(stringify!(CKA_LOCAL)), CKA_NEVER_EXTRACTABLE => String::from(stringify!(CKA_NEVER_EXTRACTABLE)), CKA_ALWAYS_SENSITIVE => String::from(stringify!(CKA_ALWAYS_SENSITIVE)), CKA_KEY_GEN_MECHANISM => String::from(stringify!(CKA_KEY_GEN_MECHANISM)), CKA_MODIFIABLE => String::from(stringify!(CKA_MODIFIABLE)), CKA_COPYABLE => String::from(stringify!(CKA_COPYABLE)), CKA_DESTROYABLE => String::from(stringify!(CKA_DESTROYABLE)), CKA_EC_PARAMS => String::from(stringify!(CKA_EC_PARAMS)), CKA_EC_POINT => String::from(stringify!(CKA_EC_POINT)), CKA_SECONDARY_AUTH => String::from(stringify!(CKA_SECONDARY_AUTH)), CKA_AUTH_PIN_FLAGS => String::from(stringify!(CKA_AUTH_PIN_FLAGS)), CKA_ALWAYS_AUTHENTICATE => String::from(stringify!(CKA_ALWAYS_AUTHENTICATE)), CKA_WRAP_WITH_TRUSTED => String::from(stringify!(CKA_WRAP_WITH_TRUSTED)), CKA_OTP_FORMAT => String::from(stringify!(CKA_OTP_FORMAT)), CKA_OTP_LENGTH => String::from(stringify!(CKA_OTP_LENGTH)), CKA_OTP_TIME_INTERVAL => String::from(stringify!(CKA_OTP_TIME_INTERVAL)), CKA_OTP_USER_FRIENDLY_MODE => String::from(stringify!(CKA_OTP_USER_FRIENDLY_MODE)), CKA_OTP_CHALLENGE_REQUIREMENT => { String::from(stringify!(CKA_OTP_CHALLENGE_REQUIREMENT)) } CKA_OTP_TIME_REQUIREMENT => String::from(stringify!(CKA_OTP_TIME_REQUIREMENT)), CKA_OTP_COUNTER_REQUIREMENT => String::from(stringify!(CKA_OTP_COUNTER_REQUIREMENT)), CKA_OTP_PIN_REQUIREMENT => String::from(stringify!(CKA_OTP_PIN_REQUIREMENT)), CKA_OTP_USER_IDENTIFIER => String::from(stringify!(CKA_OTP_USER_IDENTIFIER)), CKA_OTP_SERVICE_IDENTIFIER => String::from(stringify!(CKA_OTP_SERVICE_IDENTIFIER)), CKA_OTP_SERVICE_LOGO => String::from(stringify!(CKA_OTP_SERVICE_LOGO)), CKA_OTP_SERVICE_LOGO_TYPE => String::from(stringify!(CKA_OTP_SERVICE_LOGO_TYPE)), CKA_OTP_COUNTER => String::from(stringify!(CKA_OTP_COUNTER)), CKA_OTP_TIME => String::from(stringify!(CKA_OTP_TIME)), CKA_GOSTR3410_PARAMS => String::from(stringify!(CKA_GOSTR3410_PARAMS)), CKA_GOSTR3411_PARAMS => String::from(stringify!(CKA_GOSTR3411_PARAMS)), CKA_GOST28147_PARAMS => String::from(stringify!(CKA_GOST28147_PARAMS)), CKA_HW_FEATURE_TYPE => String::from(stringify!(CKA_HW_FEATURE_TYPE)), CKA_RESET_ON_INIT => String::from(stringify!(CKA_RESET_ON_INIT)), CKA_HAS_RESET => String::from(stringify!(CKA_HAS_RESET)), CKA_PIXEL_X => String::from(stringify!(CKA_PIXEL_X)), CKA_PIXEL_Y => String::from(stringify!(CKA_PIXEL_Y)), CKA_RESOLUTION => String::from(stringify!(CKA_RESOLUTION)), CKA_CHAR_ROWS => String::from(stringify!(CKA_CHAR_ROWS)), CKA_CHAR_COLUMNS => String::from(stringify!(CKA_CHAR_COLUMNS)), CKA_COLOR => String::from(stringify!(CKA_COLOR)), CKA_BITS_PER_PIXEL => String::from(stringify!(CKA_BITS_PER_PIXEL)), CKA_CHAR_SETS => String::from(stringify!(CKA_CHAR_SETS)), CKA_ENCODING_METHODS => String::from(stringify!(CKA_ENCODING_METHODS)), CKA_MIME_TYPES => String::from(stringify!(CKA_MIME_TYPES)), CKA_MECHANISM_TYPE => String::from(stringify!(CKA_MECHANISM_TYPE)), CKA_REQUIRED_CMS_ATTRIBUTES => String::from(stringify!(CKA_REQUIRED_CMS_ATTRIBUTES)), CKA_DEFAULT_CMS_ATTRIBUTES => String::from(stringify!(CKA_DEFAULT_CMS_ATTRIBUTES)), CKA_SUPPORTED_CMS_ATTRIBUTES => String::from(stringify!(CKA_SUPPORTED_CMS_ATTRIBUTES)), CKA_WRAP_TEMPLATE => String::from(stringify!(CKA_WRAP_TEMPLATE)), CKA_UNWRAP_TEMPLATE => String::from(stringify!(CKA_UNWRAP_TEMPLATE)), CKA_DERIVE_TEMPLATE => String::from(stringify!(CKA_DERIVE_TEMPLATE)), CKA_ALLOWED_MECHANISMS => String::from(stringify!(CKA_ALLOWED_MECHANISMS)), _ => format!("unknown ({val:08x})"), } } } impl std::fmt::Display for AttributeType { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let attrib: CK_ATTRIBUTE_TYPE = (*self).into(); write!(f, "{}", AttributeType::stringify(attrib)) } } impl From for CK_ATTRIBUTE_TYPE { fn from(attribute_type: AttributeType) -> Self { match attribute_type { AttributeType::AcIssuer => CKA_AC_ISSUER, AttributeType::AllowedMechanisms => CKA_ALLOWED_MECHANISMS, AttributeType::AlwaysAuthenticate => CKA_ALWAYS_AUTHENTICATE, AttributeType::AlwaysSensitive => CKA_ALWAYS_SENSITIVE, AttributeType::Application => CKA_APPLICATION, AttributeType::AttrTypes => CKA_ATTR_TYPES, AttributeType::Base => CKA_BASE, AttributeType::CertificateType => CKA_CERTIFICATE_TYPE, AttributeType::CheckValue => CKA_CHECK_VALUE, AttributeType::Class => CKA_CLASS, AttributeType::Coefficient => CKA_COEFFICIENT, AttributeType::Copyable => CKA_COPYABLE, AttributeType::Decrypt => CKA_DECRYPT, AttributeType::Derive => CKA_DERIVE, AttributeType::Destroyable => CKA_DESTROYABLE, AttributeType::EcParams => CKA_EC_PARAMS, AttributeType::EcPoint => CKA_EC_POINT, AttributeType::Encrypt => CKA_ENCRYPT, AttributeType::EndDate => CKA_END_DATE, AttributeType::Exponent1 => CKA_EXPONENT_1, AttributeType::Exponent2 => CKA_EXPONENT_2, AttributeType::Extractable => CKA_EXTRACTABLE, AttributeType::HashOfIssuerPublicKey => CKA_HASH_OF_ISSUER_PUBLIC_KEY, AttributeType::HashOfSubjectPublicKey => CKA_HASH_OF_SUBJECT_PUBLIC_KEY, AttributeType::Id => CKA_ID, AttributeType::Issuer => CKA_ISSUER, AttributeType::KeyGenMechanism => CKA_KEY_GEN_MECHANISM, AttributeType::KeyType => CKA_KEY_TYPE, AttributeType::Label => CKA_LABEL, AttributeType::Local => CKA_LOCAL, AttributeType::Modifiable => CKA_MODIFIABLE, AttributeType::Modulus => CKA_MODULUS, AttributeType::ModulusBits => CKA_MODULUS_BITS, AttributeType::NeverExtractable => CKA_NEVER_EXTRACTABLE, AttributeType::ObjectId => CKA_OBJECT_ID, AttributeType::Owner => CKA_OWNER, AttributeType::Prime => CKA_PRIME, AttributeType::Prime1 => CKA_PRIME_1, AttributeType::Prime2 => CKA_PRIME_2, AttributeType::Private => CKA_PRIVATE, AttributeType::PrivateExponent => CKA_PRIVATE_EXPONENT, AttributeType::PublicExponent => CKA_PUBLIC_EXPONENT, AttributeType::PublicKeyInfo => CKA_PUBLIC_KEY_INFO, AttributeType::Sensitive => CKA_SENSITIVE, AttributeType::SerialNumber => CKA_SERIAL_NUMBER, AttributeType::Sign => CKA_SIGN, AttributeType::SignRecover => CKA_SIGN_RECOVER, AttributeType::StartDate => CKA_START_DATE, AttributeType::Subject => CKA_SUBJECT, AttributeType::Token => CKA_TOKEN, AttributeType::Trusted => CKA_TRUSTED, AttributeType::Unwrap => CKA_UNWRAP, AttributeType::Url => CKA_URL, AttributeType::Value => CKA_VALUE, AttributeType::ValueLen => CKA_VALUE_LEN, AttributeType::Verify => CKA_VERIFY, AttributeType::VerifyRecover => CKA_VERIFY_RECOVER, AttributeType::Wrap => CKA_WRAP, AttributeType::WrapWithTrusted => CKA_WRAP_WITH_TRUSTED, } } } impl TryFrom for AttributeType { type Error = Error; fn try_from(attribute_type: CK_ATTRIBUTE_TYPE) -> Result { match attribute_type { CKA_AC_ISSUER => Ok(AttributeType::AcIssuer), CKA_ALLOWED_MECHANISMS => Ok(AttributeType::AllowedMechanisms), CKA_ALWAYS_AUTHENTICATE => Ok(AttributeType::AlwaysAuthenticate), CKA_ALWAYS_SENSITIVE => Ok(AttributeType::AlwaysSensitive), CKA_APPLICATION => Ok(AttributeType::Application), CKA_ATTR_TYPES => Ok(AttributeType::AttrTypes), CKA_BASE => Ok(AttributeType::Base), CKA_CERTIFICATE_TYPE => Ok(AttributeType::CertificateType), CKA_CHECK_VALUE => Ok(AttributeType::CheckValue), CKA_CLASS => Ok(AttributeType::Class), CKA_COEFFICIENT => Ok(AttributeType::Coefficient), CKA_COPYABLE => Ok(AttributeType::Copyable), CKA_DECRYPT => Ok(AttributeType::Decrypt), CKA_DERIVE => Ok(AttributeType::Derive), CKA_DESTROYABLE => Ok(AttributeType::Destroyable), CKA_EC_PARAMS => Ok(AttributeType::EcParams), CKA_EC_POINT => Ok(AttributeType::EcPoint), CKA_ENCRYPT => Ok(AttributeType::Encrypt), CKA_END_DATE => Ok(AttributeType::EndDate), CKA_EXPONENT_1 => Ok(AttributeType::Exponent1), CKA_EXPONENT_2 => Ok(AttributeType::Exponent2), CKA_EXTRACTABLE => Ok(AttributeType::Extractable), CKA_HASH_OF_ISSUER_PUBLIC_KEY => Ok(AttributeType::HashOfIssuerPublicKey), CKA_HASH_OF_SUBJECT_PUBLIC_KEY => Ok(AttributeType::HashOfSubjectPublicKey), CKA_ID => Ok(AttributeType::Id), CKA_ISSUER => Ok(AttributeType::Issuer), CKA_KEY_GEN_MECHANISM => Ok(AttributeType::KeyGenMechanism), CKA_KEY_TYPE => Ok(AttributeType::KeyType), CKA_LABEL => Ok(AttributeType::Label), CKA_LOCAL => Ok(AttributeType::Local), CKA_MODIFIABLE => Ok(AttributeType::Modifiable), CKA_MODULUS => Ok(AttributeType::Modulus), CKA_MODULUS_BITS => Ok(AttributeType::ModulusBits), CKA_NEVER_EXTRACTABLE => Ok(AttributeType::NeverExtractable), CKA_OBJECT_ID => Ok(AttributeType::ObjectId), CKA_OWNER => Ok(AttributeType::Owner), CKA_PRIME => Ok(AttributeType::Prime), CKA_PRIME_1 => Ok(AttributeType::Prime1), CKA_PRIME_2 => Ok(AttributeType::Prime2), CKA_PRIVATE => Ok(AttributeType::Private), CKA_PRIVATE_EXPONENT => Ok(AttributeType::PrivateExponent), CKA_PUBLIC_EXPONENT => Ok(AttributeType::PublicExponent), CKA_PUBLIC_KEY_INFO => Ok(AttributeType::PublicKeyInfo), CKA_SENSITIVE => Ok(AttributeType::Sensitive), CKA_SERIAL_NUMBER => Ok(AttributeType::SerialNumber), CKA_SIGN => Ok(AttributeType::Sign), CKA_SIGN_RECOVER => Ok(AttributeType::SignRecover), CKA_START_DATE => Ok(AttributeType::StartDate), CKA_SUBJECT => Ok(AttributeType::Subject), CKA_TOKEN => Ok(AttributeType::Token), CKA_TRUSTED => Ok(AttributeType::Trusted), CKA_UNWRAP => Ok(AttributeType::Unwrap), CKA_URL => Ok(AttributeType::Url), CKA_VALUE => Ok(AttributeType::Value), CKA_VALUE_LEN => Ok(AttributeType::ValueLen), CKA_VERIFY => Ok(AttributeType::Verify), CKA_VERIFY_RECOVER => Ok(AttributeType::VerifyRecover), CKA_WRAP => Ok(AttributeType::Wrap), CKA_WRAP_WITH_TRUSTED => Ok(AttributeType::WrapWithTrusted), attr_type => { error!("Attribute type {} not supported.", attr_type); Err(Error::NotSupported) } } } } #[derive(Debug, Clone, PartialEq, Eq)] #[non_exhaustive] /// Attribute value pub enum Attribute { /// DER-encoding of the attribute certificate's issuer AcIssuer(Vec), /// List of mechanisms allowed to be used with the key AllowedMechanisms(Vec), /// Indicates that the user has to supply the PIN for each use with the key AlwaysAuthenticate(bool), /// Indicates if the key has always had the Sensitive attribute set to true AlwaysSensitive(bool), /// Description of the application that manages the object Application(Vec), /// BER-encoding of a sequence of object identifier values AttrTypes(Vec), /// Base number value of a key Base(Vec), /// Type of certificate CertificateType(CertificateType), /// Checksum CheckValue(Vec), /// Type of an object Class(ObjectClass), /// The CRT coefficient `iqmp` of an RSA private key Coefficient(Vec), /// Determines if an object can be copied Copyable(bool), /// Determines if a key supports decryption Decrypt(bool), /// Determines if it is possible to derive other keys from the key Derive(bool), /// Determines if it is possible to destroy an object Destroyable(bool), /// Parameters describing an elliptic curve EcParams(Vec), /// Elliptic Curve point EcPoint(Vec), /// Determines if a key supports encryption Encrypt(bool), /// The end date of the object EndDate(Date), /// The private exponent `dmp1` of an RSA private key Exponent1(Vec), /// The private exponent `dmq1` of an RSA private key Exponent2(Vec), /// Determines if a key is extractable and can be wrapped Extractable(bool), /// Hash of issuer public key HashOfIssuerPublicKey(Vec), /// Hash of subject public key HashOfSubjectPublicKey(Vec), /// Key identifier for key Id(Vec), /// DER-encoding of the certificate issuer name Issuer(Vec), /// Identifier of the mechanism used to generate the key material KeyGenMechanism(MechanismType), /// Type of a key KeyType(KeyType), /// Description of the object Label(Vec), /// Indicates if the key was generated locally or copied from a locally created object Local(bool), /// Determines if the object can be modified Modifiable(bool), /// Modulus value of a key Modulus(Vec), /// Length in bits of the modulus of a key ModulusBits(Ulong), /// Indicates if the key has never had the Extractable attribute set to true NeverExtractable(bool), /// Object ID ObjectId(Vec), /// DER encoding of the attribute certificate's subject field Owner(Vec), /// Prime number value of a key Prime(Vec), /// The prime `p` of an RSA private key Prime1(Vec), /// The prime `q` of an RSA private key Prime2(Vec), /// Determines if the object is private Private(bool), /// The private exponent `d` PrivateExponent(Vec), /// Public exponent value of a key PublicExponent(Vec), /// DER-encoding of the SubjectPublicKeyInfo PublicKeyInfo(Vec), /// Determines if the key is sensitive Sensitive(bool), /// DER encoding of the certificate serial number SerialNumber(Vec), /// Determines if a key supports signing Sign(bool), /// Determines if a key supports signing where the data can be recovered from the signature SignRecover(bool), /// The start date of the object StartDate(Date), /// DER-encoding of certificate subject name Subject(Vec), /// Determines if the object is a token object Token(bool), /// Determines if an object is trusted Trusted(bool), /// Determines if a key supports unwrapping Unwrap(bool), /// Gives the URL where the complete certificate can ber obtained Url(Vec), /// Value of the object Value(Vec), /// Length in bytes of the value ValueLen(Ulong), /// Determines if a key supports verifying Verify(bool), /// Determines if a key supports verifying where the data can be recovered from the signature VerifyRecover(bool), /// Determines if a key supports wrapping Wrap(bool), /// Indicates that the key can only be wrapped with a wrapping key that has the Trusted attribute WrapWithTrusted(bool), } impl Attribute { /// Get the type of an attribute pub fn attribute_type(&self) -> AttributeType { match self { Attribute::AcIssuer(_) => AttributeType::AcIssuer, Attribute::AllowedMechanisms(_) => AttributeType::AllowedMechanisms, Attribute::AlwaysAuthenticate(_) => AttributeType::AlwaysAuthenticate, Attribute::AlwaysSensitive(_) => AttributeType::AlwaysSensitive, Attribute::Application(_) => AttributeType::Application, Attribute::AttrTypes(_) => AttributeType::AttrTypes, Attribute::Base(_) => AttributeType::Base, Attribute::CertificateType(_) => AttributeType::CertificateType, Attribute::CheckValue(_) => AttributeType::CheckValue, Attribute::Class(_) => AttributeType::Class, Attribute::Coefficient(_) => AttributeType::Coefficient, Attribute::Copyable(_) => AttributeType::Copyable, Attribute::Decrypt(_) => AttributeType::Decrypt, Attribute::Derive(_) => AttributeType::Derive, Attribute::Destroyable(_) => AttributeType::Destroyable, Attribute::EcParams(_) => AttributeType::EcParams, Attribute::EcPoint(_) => AttributeType::EcPoint, Attribute::Encrypt(_) => AttributeType::Encrypt, Attribute::EndDate(_) => AttributeType::EndDate, Attribute::Exponent1(_) => AttributeType::Exponent1, Attribute::Exponent2(_) => AttributeType::Exponent2, Attribute::Extractable(_) => AttributeType::Extractable, Attribute::HashOfIssuerPublicKey(_) => AttributeType::HashOfIssuerPublicKey, Attribute::HashOfSubjectPublicKey(_) => AttributeType::HashOfSubjectPublicKey, Attribute::Id(_) => AttributeType::Id, Attribute::Issuer(_) => AttributeType::Issuer, Attribute::KeyGenMechanism(_) => AttributeType::KeyGenMechanism, Attribute::KeyType(_) => AttributeType::KeyType, Attribute::Label(_) => AttributeType::Label, Attribute::Local(_) => AttributeType::Local, Attribute::Modifiable(_) => AttributeType::Modifiable, Attribute::Modulus(_) => AttributeType::Modulus, Attribute::ModulusBits(_) => AttributeType::ModulusBits, Attribute::NeverExtractable(_) => AttributeType::NeverExtractable, Attribute::ObjectId(_) => AttributeType::ObjectId, Attribute::Owner(_) => AttributeType::Owner, Attribute::Prime(_) => AttributeType::Prime, Attribute::Prime1(_) => AttributeType::Prime1, Attribute::Prime2(_) => AttributeType::Prime2, Attribute::Private(_) => AttributeType::Private, Attribute::PrivateExponent(_) => AttributeType::PrivateExponent, Attribute::PublicExponent(_) => AttributeType::PublicExponent, Attribute::PublicKeyInfo(_) => AttributeType::PublicKeyInfo, Attribute::Sensitive(_) => AttributeType::Sensitive, Attribute::SerialNumber(_) => AttributeType::SerialNumber, Attribute::Sign(_) => AttributeType::Sign, Attribute::SignRecover(_) => AttributeType::SignRecover, Attribute::StartDate(_) => AttributeType::StartDate, Attribute::Subject(_) => AttributeType::Subject, Attribute::Token(_) => AttributeType::Token, Attribute::Trusted(_) => AttributeType::Trusted, Attribute::Unwrap(_) => AttributeType::Unwrap, Attribute::Url(_) => AttributeType::Url, Attribute::Value(_) => AttributeType::Value, Attribute::ValueLen(_) => AttributeType::ValueLen, Attribute::Verify(_) => AttributeType::Verify, Attribute::VerifyRecover(_) => AttributeType::VerifyRecover, Attribute::Wrap(_) => AttributeType::Wrap, Attribute::WrapWithTrusted(_) => AttributeType::WrapWithTrusted, } } /// Returns the length in bytes of the objects contained by this CkAttribute. fn len(&self) -> usize { match self { Attribute::AlwaysAuthenticate(_) | Attribute::AlwaysSensitive(_) | Attribute::Copyable(_) | Attribute::Decrypt(_) | Attribute::Derive(_) | Attribute::Destroyable(_) | Attribute::Encrypt(_) | Attribute::Extractable(_) | Attribute::Local(_) | Attribute::Modifiable(_) | Attribute::NeverExtractable(_) | Attribute::Private(_) | Attribute::Sensitive(_) | Attribute::Sign(_) | Attribute::SignRecover(_) | Attribute::Token(_) | Attribute::Trusted(_) | Attribute::Unwrap(_) | Attribute::Verify(_) | Attribute::VerifyRecover(_) | Attribute::Wrap(_) | Attribute::WrapWithTrusted(_) => std::mem::size_of::(), Attribute::Base(_) => 1, Attribute::Application(bytes) | Attribute::Label(bytes) | Attribute::Url(bytes) => { std::mem::size_of::() * bytes.len() } Attribute::AcIssuer(bytes) => bytes.len(), Attribute::AttrTypes(bytes) => bytes.len(), Attribute::CertificateType(_) => std::mem::size_of::(), Attribute::CheckValue(bytes) => bytes.len(), Attribute::Class(_) => std::mem::size_of::(), Attribute::Coefficient(bytes) => bytes.len(), Attribute::EcParams(bytes) => bytes.len(), Attribute::EcPoint(bytes) => bytes.len(), Attribute::Exponent1(bytes) => bytes.len(), Attribute::Exponent2(bytes) => bytes.len(), Attribute::HashOfIssuerPublicKey(bytes) => bytes.len(), Attribute::HashOfSubjectPublicKey(bytes) => bytes.len(), Attribute::Id(bytes) => bytes.len(), Attribute::Issuer(bytes) => bytes.len(), Attribute::KeyGenMechanism(_) => std::mem::size_of::(), Attribute::KeyType(_) => std::mem::size_of::(), Attribute::Modulus(bytes) => bytes.len(), Attribute::ModulusBits(_) => std::mem::size_of::(), Attribute::ObjectId(bytes) => bytes.len(), Attribute::Owner(bytes) => bytes.len(), Attribute::Prime(bytes) => bytes.len(), Attribute::Prime1(bytes) => bytes.len(), Attribute::Prime2(bytes) => bytes.len(), Attribute::PrivateExponent(bytes) => bytes.len(), Attribute::PublicExponent(bytes) => bytes.len(), Attribute::PublicKeyInfo(bytes) => bytes.len(), Attribute::SerialNumber(bytes) => bytes.len(), Attribute::Subject(bytes) => bytes.len(), Attribute::Value(bytes) => bytes.len(), Attribute::ValueLen(_) => std::mem::size_of::(), Attribute::EndDate(_) | Attribute::StartDate(_) => std::mem::size_of::(), Attribute::AllowedMechanisms(mechanisms) => { std::mem::size_of::() * mechanisms.len() } } } /// Returns a CK_VOID_PTR pointing to the object contained by this CkAttribute. /// /// Casting from an immutable reference to a mutable pointer is kind of unsafe but the /// Attribute structure will only be used with PKCS11 functions that do not modify the template /// given. /// The C_GetAttributeValue function, which is the only one that modifies the template given, /// will not use Attribute parameters but return them /// directly to the caller. fn ptr(&self) -> *mut c_void { // Note: bools in Rust are guaranteed to occupy a byte, so // &mut bool as a raw pointer will provide the same space // needed for CK_BBOOL types. See also: // https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout match self { // CK_BBOOL Attribute::AlwaysAuthenticate(b) | Attribute::AlwaysSensitive(b) | Attribute::Copyable(b) | Attribute::Decrypt(b) | Attribute::Derive(b) | Attribute::Destroyable(b) | Attribute::Encrypt(b) | Attribute::Extractable(b) | Attribute::Local(b) | Attribute::Modifiable(b) | Attribute::NeverExtractable(b) | Attribute::Private(b) | Attribute::Sensitive(b) | Attribute::Sign(b) | Attribute::SignRecover(b) | Attribute::Token(b) | Attribute::Trusted(b) | Attribute::Unwrap(b) | Attribute::Verify(b) | Attribute::VerifyRecover(b) | Attribute::Wrap(b) | Attribute::WrapWithTrusted(b) => b as *const _ as *mut c_void, // CK_ULONG Attribute::ModulusBits(val) | Attribute::ValueLen(val) => { val as *const _ as *mut c_void } // Vec Attribute::AcIssuer(bytes) | Attribute::Application(bytes) | Attribute::AttrTypes(bytes) | Attribute::Base(bytes) | Attribute::CheckValue(bytes) | Attribute::Coefficient(bytes) | Attribute::EcParams(bytes) | Attribute::EcPoint(bytes) | Attribute::Exponent1(bytes) | Attribute::Exponent2(bytes) | Attribute::HashOfIssuerPublicKey(bytes) | Attribute::HashOfSubjectPublicKey(bytes) | Attribute::Issuer(bytes) | Attribute::Label(bytes) | Attribute::ObjectId(bytes) | Attribute::Prime(bytes) | Attribute::Prime1(bytes) | Attribute::Prime2(bytes) | Attribute::PrivateExponent(bytes) | Attribute::PublicExponent(bytes) | Attribute::PublicKeyInfo(bytes) | Attribute::Modulus(bytes) | Attribute::Owner(bytes) | Attribute::SerialNumber(bytes) | Attribute::Subject(bytes) | Attribute::Url(bytes) | Attribute::Value(bytes) | Attribute::Id(bytes) => bytes.as_ptr() as *mut c_void, // Unique types Attribute::CertificateType(certificate_type) => { certificate_type as *const _ as *mut c_void } Attribute::Class(object_class) => object_class as *const _ as *mut c_void, Attribute::KeyGenMechanism(mech) => mech as *const _ as *mut c_void, Attribute::KeyType(key_type) => key_type as *const _ as *mut c_void, Attribute::AllowedMechanisms(mechanisms) => mechanisms.as_ptr() as *mut c_void, Attribute::EndDate(date) | Attribute::StartDate(date) => { date as *const _ as *mut c_void } } } } impl From<&Attribute> for CK_ATTRIBUTE { fn from(attribute: &Attribute) -> Self { Self { type_: attribute.attribute_type().into(), pValue: attribute.ptr(), // The panic should only happen if there is a bug. ulValueLen: attribute .len() .try_into() .expect("Can not convert the attribute length value (usize) to a CK_ULONG."), } } } /// Private function standing in for `TryInto` for `&[u8]` /// which can't be implemented through the actual trait because /// it and both types are external to this crate. /// NB from the specification: "In Cryptoki, the CK_BBOOL data type /// is a Boolean type that can be true or false. A zero value means /// false, and a nonzero value means true." so there is no invalid /// byte value. fn try_u8_into_bool(slice: &[u8]) -> Result { let as_array: [u8; std::mem::size_of::()] = slice.try_into()?; let as_byte = CK_BBOOL::from_ne_bytes(as_array); Ok(!matches!(as_byte, 0u8)) } impl TryFrom for Attribute { type Error = Error; fn try_from(attribute: CK_ATTRIBUTE) -> Result { let attr_type = AttributeType::try_from(attribute.type_)?; // Cast from c_void to u8 let val = unsafe { std::slice::from_raw_parts( attribute.pValue as *const u8, attribute.ulValueLen.try_into()?, ) }; match attr_type { // CK_BBOOL AttributeType::AlwaysAuthenticate => { Ok(Attribute::AlwaysAuthenticate(try_u8_into_bool(val)?)) } AttributeType::AlwaysSensitive => { Ok(Attribute::AlwaysSensitive(try_u8_into_bool(val)?)) } AttributeType::Copyable => Ok(Attribute::Copyable(try_u8_into_bool(val)?)), AttributeType::Decrypt => Ok(Attribute::Decrypt(try_u8_into_bool(val)?)), AttributeType::Derive => Ok(Attribute::Derive(try_u8_into_bool(val)?)), AttributeType::Destroyable => Ok(Attribute::Destroyable(try_u8_into_bool(val)?)), AttributeType::Encrypt => Ok(Attribute::Encrypt(try_u8_into_bool(val)?)), AttributeType::Extractable => Ok(Attribute::Extractable(try_u8_into_bool(val)?)), AttributeType::Local => Ok(Attribute::Local(try_u8_into_bool(val)?)), AttributeType::Modifiable => Ok(Attribute::Modifiable(try_u8_into_bool(val)?)), AttributeType::NeverExtractable => { Ok(Attribute::NeverExtractable(try_u8_into_bool(val)?)) } AttributeType::Private => Ok(Attribute::Private(try_u8_into_bool(val)?)), AttributeType::Sensitive => Ok(Attribute::Sensitive(try_u8_into_bool(val)?)), AttributeType::Sign => Ok(Attribute::Sign(try_u8_into_bool(val)?)), AttributeType::SignRecover => Ok(Attribute::SignRecover(try_u8_into_bool(val)?)), AttributeType::Token => Ok(Attribute::Token(try_u8_into_bool(val)?)), AttributeType::Trusted => Ok(Attribute::Trusted(try_u8_into_bool(val)?)), AttributeType::Unwrap => Ok(Attribute::Unwrap(try_u8_into_bool(val)?)), AttributeType::Verify => Ok(Attribute::Verify(try_u8_into_bool(val)?)), AttributeType::VerifyRecover => Ok(Attribute::VerifyRecover(try_u8_into_bool(val)?)), AttributeType::Wrap => Ok(Attribute::Wrap(try_u8_into_bool(val)?)), AttributeType::WrapWithTrusted => { Ok(Attribute::WrapWithTrusted(try_u8_into_bool(val)?)) } // CK_ULONG AttributeType::ModulusBits => Ok(Attribute::ModulusBits( CK_ULONG::from_ne_bytes(val.try_into()?).try_into()?, )), AttributeType::ValueLen => Ok(Attribute::ValueLen( CK_ULONG::from_ne_bytes(val.try_into()?).try_into()?, )), // Vec AttributeType::AcIssuer => Ok(Attribute::AcIssuer(val.to_vec())), AttributeType::Application => Ok(Attribute::Application(val.to_vec())), AttributeType::AttrTypes => Ok(Attribute::AttrTypes(val.to_vec())), AttributeType::Base => Ok(Attribute::Base(val.to_vec())), AttributeType::CheckValue => Ok(Attribute::CheckValue(val.to_vec())), AttributeType::Coefficient => Ok(Attribute::Coefficient(val.to_vec())), AttributeType::EcParams => Ok(Attribute::EcParams(val.to_vec())), AttributeType::EcPoint => Ok(Attribute::EcPoint(val.to_vec())), AttributeType::Exponent1 => Ok(Attribute::Exponent1(val.to_vec())), AttributeType::Exponent2 => Ok(Attribute::Exponent2(val.to_vec())), AttributeType::HashOfIssuerPublicKey => { Ok(Attribute::HashOfIssuerPublicKey(val.to_vec())) } AttributeType::HashOfSubjectPublicKey => { Ok(Attribute::HashOfSubjectPublicKey(val.to_vec())) } AttributeType::Issuer => Ok(Attribute::Issuer(val.to_vec())), AttributeType::Label => Ok(Attribute::Label(val.to_vec())), AttributeType::Prime => Ok(Attribute::Prime(val.to_vec())), AttributeType::Prime1 => Ok(Attribute::Prime1(val.to_vec())), AttributeType::Prime2 => Ok(Attribute::Prime2(val.to_vec())), AttributeType::PrivateExponent => Ok(Attribute::PrivateExponent(val.to_vec())), AttributeType::PublicExponent => Ok(Attribute::PublicExponent(val.to_vec())), AttributeType::PublicKeyInfo => Ok(Attribute::PublicKeyInfo(val.to_vec())), AttributeType::Modulus => Ok(Attribute::Modulus(val.to_vec())), AttributeType::ObjectId => Ok(Attribute::ObjectId(val.to_vec())), AttributeType::Owner => Ok(Attribute::Owner(val.to_vec())), AttributeType::SerialNumber => Ok(Attribute::SerialNumber(val.to_vec())), AttributeType::Subject => Ok(Attribute::Subject(val.to_vec())), AttributeType::Url => Ok(Attribute::Url(val.to_vec())), AttributeType::Value => Ok(Attribute::Value(val.to_vec())), AttributeType::Id => Ok(Attribute::Id(val.to_vec())), // Unique types AttributeType::CertificateType => Ok(Attribute::CertificateType( CK_CERTIFICATE_TYPE::from_ne_bytes(val.try_into()?).try_into()?, )), AttributeType::Class => Ok(Attribute::Class( CK_OBJECT_CLASS::from_ne_bytes(val.try_into()?).try_into()?, )), AttributeType::KeyGenMechanism => Ok(Attribute::KeyGenMechanism( CK_MECHANISM_TYPE::from_ne_bytes(val.try_into()?).try_into()?, )), AttributeType::KeyType => Ok(Attribute::KeyType( CK_KEY_TYPE::from_ne_bytes(val.try_into()?).try_into()?, )), AttributeType::AllowedMechanisms => { let val = unsafe { std::slice::from_raw_parts( attribute.pValue as *const CK_MECHANISM_TYPE, attribute.ulValueLen.try_into()?, ) }; let types: Vec = val .iter() .copied() .map(|t| t.try_into()) .collect::>>()?; Ok(Attribute::AllowedMechanisms(types)) } AttributeType::EndDate => { if val.is_empty() { Ok(Attribute::EndDate(Date::new_empty())) } else { let date = val.as_ptr() as *const CK_DATE; unsafe { let year = String::from_utf8_lossy(Vec::from((*date).year).as_slice()) .trim_end() .to_string(); let month = String::from_utf8_lossy(Vec::from((*date).month).as_slice()) .trim_end() .to_string(); let day = String::from_utf8_lossy(Vec::from((*date).day).as_slice()) .trim_end() .to_string(); Ok(Attribute::EndDate(Date::new_from_str_slice( year.as_str(), month.as_str(), day.as_str(), )?)) } } } AttributeType::StartDate => { if val.is_empty() { Ok(Attribute::StartDate(Date::new_empty())) } else { let date = val.as_ptr() as *const CK_DATE; unsafe { let year = String::from_utf8_lossy(Vec::from((*date).year).as_slice()) .trim_end() .to_string(); let month = String::from_utf8_lossy(Vec::from((*date).month).as_slice()) .trim_end() .to_string(); let day = String::from_utf8_lossy(Vec::from((*date).day).as_slice()) .trim_end() .to_string(); Ok(Attribute::StartDate(Date::new_from_str_slice( year.as_str(), month.as_str(), day.as_str(), )?)) } } } } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] /// Token specific identifier for an object pub struct ObjectHandle { handle: CK_OBJECT_HANDLE, } impl ObjectHandle { pub(crate) fn new(handle: CK_OBJECT_HANDLE) -> Self { ObjectHandle { handle } } pub(crate) fn handle(&self) -> CK_OBJECT_HANDLE { self.handle } } impl std::fmt::Display for ObjectHandle { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.handle) } } impl std::fmt::LowerHex for ObjectHandle { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{:08x}", self.handle) } } impl std::fmt::UpperHex for ObjectHandle { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{:08X}", self.handle) } } #[derive(Copy, Debug, Clone, PartialEq, Eq)] #[repr(transparent)] /// Identifier of the class of an object pub struct ObjectClass { val: CK_OBJECT_CLASS, } impl ObjectClass { /// Data objects pub const DATA: ObjectClass = ObjectClass { val: CKO_DATA }; /// Certificate objects pub const CERTIFICATE: ObjectClass = ObjectClass { val: CKO_CERTIFICATE, }; /// Public key object pub const PUBLIC_KEY: ObjectClass = ObjectClass { val: CKO_PUBLIC_KEY, }; /// Private key object pub const PRIVATE_KEY: ObjectClass = ObjectClass { val: CKO_PRIVATE_KEY, }; /// Secret key object pub const SECRET_KEY: ObjectClass = ObjectClass { val: CKO_SECRET_KEY, }; /// A hardware feature object pub const HARDWARE_FEATURE: ObjectClass = ObjectClass { val: CKO_HW_FEATURE, }; /// A domain parameters object pub const DOMAIN_PARAMETERS: ObjectClass = ObjectClass { val: CKO_DOMAIN_PARAMETERS, }; /// A mechanism object pub const MECHANISM: ObjectClass = ObjectClass { val: CKO_MECHANISM }; /// An OTP key object pub const OTP_KEY: ObjectClass = ObjectClass { val: CKO_OTP_KEY }; pub(crate) fn stringify(class: CK_OBJECT_CLASS) -> String { match class { CKO_DATA => String::from(stringify!(CKO_DATA)), CKO_CERTIFICATE => String::from(stringify!(CKO_CERTIFICATE)), CKO_PUBLIC_KEY => String::from(stringify!(CKO_PUBLIC_KEY)), CKO_PRIVATE_KEY => String::from(stringify!(CKO_PRIVATE_KEY)), CKO_SECRET_KEY => String::from(stringify!(CKO_SECRET_KEY)), CKO_HW_FEATURE => String::from(stringify!(CKO_HW_FEATURE)), CKO_DOMAIN_PARAMETERS => String::from(stringify!(CKO_DOMAIN_PARAMETERS)), CKO_MECHANISM => String::from(stringify!(CKO_MECHANISM)), CKO_OTP_KEY => String::from(stringify!(CKO_OTP_KEY)), _ => format!("unknown ({class:08x})"), } } } impl std::fmt::Display for ObjectClass { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", ObjectClass::stringify(self.val)) } } impl Deref for ObjectClass { type Target = CK_OBJECT_CLASS; fn deref(&self) -> &Self::Target { &self.val } } impl From for CK_OBJECT_CLASS { fn from(object_class: ObjectClass) -> Self { *object_class } } impl TryFrom for ObjectClass { type Error = Error; fn try_from(object_class: CK_OBJECT_CLASS) -> Result { match object_class { CKO_DATA => Ok(ObjectClass::DATA), CKO_CERTIFICATE => Ok(ObjectClass::CERTIFICATE), CKO_PUBLIC_KEY => Ok(ObjectClass::PUBLIC_KEY), CKO_PRIVATE_KEY => Ok(ObjectClass::PRIVATE_KEY), CKO_SECRET_KEY => Ok(ObjectClass::SECRET_KEY), CKO_HW_FEATURE => Ok(ObjectClass::HARDWARE_FEATURE), CKO_DOMAIN_PARAMETERS => Ok(ObjectClass::DOMAIN_PARAMETERS), CKO_MECHANISM => Ok(ObjectClass::MECHANISM), CKO_OTP_KEY => Ok(ObjectClass::OTP_KEY), _ => { error!("Object class {} is not supported.", object_class); Err(Error::NotSupported) } } } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(transparent)] /// Key type pub struct KeyType { val: CK_KEY_TYPE, } impl KeyType { /// RSA key pub const RSA: KeyType = KeyType { val: CKK_RSA }; /// DSA key pub const DSA: KeyType = KeyType { val: CKK_DSA }; /// DH key pub const DH: KeyType = KeyType { val: CKK_DH }; /// EC key pub const EC: KeyType = KeyType { val: CKK_EC }; /// X9_42_DH key pub const X9_42_DH: KeyType = KeyType { val: CKK_X9_42_DH }; /// KEA key pub const KEA: KeyType = KeyType { val: CKK_KEA }; /// Generic Secret (hmac) key pub const GENERIC_SECRET: KeyType = KeyType { val: CKK_GENERIC_SECRET, }; /// RC2 key pub const RC2: KeyType = KeyType { val: CKK_RC2 }; /// RC4 key pub const RC4: KeyType = KeyType { val: CKK_RC4 }; /// DES key pub const DES: KeyType = KeyType { val: CKK_DES }; /// DES2 key pub const DES2: KeyType = KeyType { val: CKK_DES2 }; /// DES3 secret /// Note that DES3 is deprecated. See section 2, p. 6. pub const DES3: KeyType = KeyType { val: CKK_DES3 }; /// CAST key pub const CAST: KeyType = KeyType { val: CKK_CAST }; /// CAST3 key pub const CAST3: KeyType = KeyType { val: CKK_CAST3 }; /// CAST128 key pub const CAST128: KeyType = KeyType { val: CKK_CAST128 }; /// RC5 key pub const RC5: KeyType = KeyType { val: CKK_RC5 }; /// IDEA key pub const IDEA: KeyType = KeyType { val: CKK_IDEA }; /// SKIPJACK key pub const SKIPJACK: KeyType = KeyType { val: CKK_SKIPJACK }; /// BATON key pub const BATON: KeyType = KeyType { val: CKK_BATON }; /// JUNIPER key pub const JUNIPER: KeyType = KeyType { val: CKK_JUNIPER }; /// CDMF key pub const CDMF: KeyType = KeyType { val: CKK_CDMF }; /// AES key pub const AES: KeyType = KeyType { val: CKK_AES }; /// BLOWFISH key pub const BLOWFISH: KeyType = KeyType { val: CKK_BLOWFISH }; /// TWOFISH key pub const TWOFISH: KeyType = KeyType { val: CKK_TWOFISH }; /// SECURID key pub const SECURID: KeyType = KeyType { val: CKK_SECURID }; /// HOTP key pub const HOTP: KeyType = KeyType { val: CKK_HOTP }; /// ACTI key pub const ACTI: KeyType = KeyType { val: CKK_ACTI }; /// CAMELLIA key pub const CAMELLIA: KeyType = KeyType { val: CKK_CAMELLIA }; /// ARIA key pub const ARIA: KeyType = KeyType { val: CKK_ARIA }; /// MD5 HMAC key pub const MD5_HMAC: KeyType = KeyType { val: CKK_MD5_HMAC }; /// SHA1 HMAC key pub const SHA_1_HMAC: KeyType = KeyType { val: CKK_SHA_1_HMAC, }; /// RIPEMD128 HMAC key pub const RIPEMD128_HMAC: KeyType = KeyType { val: CKK_RIPEMD128_HMAC, }; /// RIPEMD160 HMAC key pub const RIPEMD160_HMAC: KeyType = KeyType { val: CKK_RIPEMD160_HMAC, }; /// SHA256 HMAC key pub const SHA256_HMAC: KeyType = KeyType { val: CKK_SHA256_HMAC, }; /// SHA384 HMAC key pub const SHA384_HMAC: KeyType = KeyType { val: CKK_SHA256_HMAC, }; /// SHA512 HMAC key pub const SHA512_HMAC: KeyType = KeyType { val: CKK_SHA256_HMAC, }; /// SHA224 HMAC key pub const SHA224_HMAC: KeyType = KeyType { val: CKK_SHA256_HMAC, }; /// SEED key pub const SEED: KeyType = KeyType { val: CKK_SEED }; /// GOSTR3410 key pub const GOSTR3410: KeyType = KeyType { val: CKK_GOSTR3410 }; /// GOSTR3411 key pub const GOSTR3411: KeyType = KeyType { val: CKK_GOSTR3411 }; /// GOST28147 key pub const GOST28147: KeyType = KeyType { val: CKK_GOST28147 }; /// EC edwards key pub const EC_EDWARDS: KeyType = KeyType { val: CKK_EC_EDWARDS, }; /// EC montgomery key pub const EC_MONTGOMERY: KeyType = KeyType { val: CKK_EC_MONTGOMERY, }; fn stringify(key_type: CK_KEY_TYPE) -> String { match key_type { CKK_RSA => String::from(stringify!(CKK_RSA)), CKK_DSA => String::from(stringify!(CKK_DSA)), CKK_DH => String::from(stringify!(CKK_DH)), CKK_EC => String::from(stringify!(CKK_EC)), CKK_X9_42_DH => String::from(stringify!(CKK_X9_42_DH)), CKK_KEA => String::from(stringify!(CKK_KEA)), CKK_GENERIC_SECRET => String::from(stringify!(CKK_GENERIC_SECRET)), CKK_RC2 => String::from(stringify!(CKK_RC2)), CKK_RC4 => String::from(stringify!(CKK_RC4)), CKK_DES => String::from(stringify!(CKK_DES)), CKK_DES2 => String::from(stringify!(CKK_DES2)), CKK_DES3 => String::from(stringify!(CKK_DES3)), CKK_CAST => String::from(stringify!(CKK_CAST)), CKK_CAST3 => String::from(stringify!(CKK_CAST3)), CKK_CAST128 => String::from(stringify!(CKK_CAST128)), CKK_RC5 => String::from(stringify!(CKK_RC5)), CKK_IDEA => String::from(stringify!(CKK_IDEA)), CKK_SKIPJACK => String::from(stringify!(CKK_SKIPJACK)), CKK_BATON => String::from(stringify!(CKK_BATON)), CKK_JUNIPER => String::from(stringify!(CKK_JUNIPER)), CKK_CDMF => String::from(stringify!(CKK_CDMF)), CKK_AES => String::from(stringify!(CKK_AES)), CKK_BLOWFISH => String::from(stringify!(CKK_BLOWFISH)), CKK_TWOFISH => String::from(stringify!(CKK_TWOFISH)), CKK_SECURID => String::from(stringify!(CKK_SECURID)), CKK_HOTP => String::from(stringify!(CKK_HOTP)), CKK_ACTI => String::from(stringify!(CKK_ACTI)), CKK_CAMELLIA => String::from(stringify!(CKK_CAMELLIA)), CKK_ARIA => String::from(stringify!(CKK_ARIA)), CKK_MD5_HMAC => String::from(stringify!(CKK_MD5_HMAC)), CKK_SHA_1_HMAC => String::from(stringify!(CKK_SHA_1_HMAC)), CKK_RIPEMD128_HMAC => String::from(stringify!(CKK_RIPEMD128_HMAC)), CKK_RIPEMD160_HMAC => String::from(stringify!(CKK_RIPEMD160_HMAC)), CKK_SHA256_HMAC => String::from(stringify!(CKK_SHA256_HMAC)), CKK_SHA384_HMAC => String::from(stringify!(CKK_SHA384_HMAC)), CKK_SHA512_HMAC => String::from(stringify!(CKK_SHA512_HMAC)), CKK_SHA224_HMAC => String::from(stringify!(CKK_SHA224_HMAC)), CKK_SEED => String::from(stringify!(CKK_SEED)), CKK_GOSTR3410 => String::from(stringify!(CKK_GOSTR3410)), CKK_GOSTR3411 => String::from(stringify!(CKK_GOSTR3411)), CKK_GOST28147 => String::from(stringify!(CKK_GOST28147)), CKK_EC_EDWARDS => String::from(stringify!(CKK_EC_EDWARDS)), _ => format!("unknown ({key_type:08x})"), } } } impl std::fmt::Display for KeyType { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", KeyType::stringify(self.val)) } } impl Deref for KeyType { type Target = CK_KEY_TYPE; fn deref(&self) -> &Self::Target { &self.val } } impl From for CK_KEY_TYPE { fn from(key_type: KeyType) -> Self { *key_type } } impl TryFrom for KeyType { type Error = Error; fn try_from(key_type: CK_KEY_TYPE) -> Result { match key_type { CKK_RSA => Ok(KeyType::RSA), CKK_DSA => Ok(KeyType::DSA), CKK_DH => Ok(KeyType::DH), CKK_EC => Ok(KeyType::EC), CKK_X9_42_DH => Ok(KeyType::X9_42_DH), CKK_KEA => Ok(KeyType::KEA), CKK_GENERIC_SECRET => Ok(KeyType::GENERIC_SECRET), CKK_RC2 => Ok(KeyType::RC2), CKK_RC4 => Ok(KeyType::RC4), CKK_DES => Ok(KeyType::DES), CKK_DES2 => Ok(KeyType::DES2), CKK_DES3 => Ok(KeyType::DES3), CKK_CAST => Ok(KeyType::CAST), CKK_CAST3 => Ok(KeyType::CAST3), CKK_CAST128 => Ok(KeyType::CAST128), CKK_RC5 => Ok(KeyType::RC5), CKK_IDEA => Ok(KeyType::IDEA), CKK_SKIPJACK => Ok(KeyType::SKIPJACK), CKK_BATON => Ok(KeyType::BATON), CKK_JUNIPER => Ok(KeyType::JUNIPER), CKK_CDMF => Ok(KeyType::CDMF), CKK_AES => Ok(KeyType::AES), CKK_BLOWFISH => Ok(KeyType::BLOWFISH), CKK_TWOFISH => Ok(KeyType::TWOFISH), CKK_SECURID => Ok(KeyType::SECURID), CKK_HOTP => Ok(KeyType::HOTP), CKK_ACTI => Ok(KeyType::ACTI), CKK_CAMELLIA => Ok(KeyType::CAMELLIA), CKK_ARIA => Ok(KeyType::ARIA), CKK_MD5_HMAC => Ok(KeyType::MD5_HMAC), CKK_SHA_1_HMAC => Ok(KeyType::SHA_1_HMAC), CKK_RIPEMD128_HMAC => Ok(KeyType::RIPEMD128_HMAC), CKK_RIPEMD160_HMAC => Ok(KeyType::RIPEMD160_HMAC), CKK_SHA256_HMAC => Ok(KeyType::SHA256_HMAC), CKK_SHA384_HMAC => Ok(KeyType::SHA384_HMAC), CKK_SHA512_HMAC => Ok(KeyType::SHA512_HMAC), CKK_SHA224_HMAC => Ok(KeyType::SHA224_HMAC), CKK_SEED => Ok(KeyType::SEED), CKK_GOSTR3410 => Ok(KeyType::GOSTR3410), CKK_GOSTR3411 => Ok(KeyType::GOSTR3411), CKK_GOST28147 => Ok(KeyType::GOST28147), CKK_EC_EDWARDS => Ok(KeyType::EC_EDWARDS), CKK_EC_MONTGOMERY => Ok(KeyType::EC_MONTGOMERY), _ => { error!("Key type {} is not supported.", key_type); Err(Error::NotSupported) } } } } #[derive(Debug, Copy, Clone)] /// Information about the attribute of an object pub enum AttributeInfo { /// The requested attribute is not a valid attribute for the object TypeInvalid, /// The value of the attribute is sensitive and will not be returned Sensitive, /// The attribute is available to get from the object and has the specified size in bytes. Available(usize), } #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(transparent)] /// The certificate type pub struct CertificateType { val: CK_CERTIFICATE_TYPE, } impl CertificateType { /// An X.509 certificate pub const X_509: CertificateType = CertificateType { val: CKC_X_509 }; /// An X.509 attribute certificate pub const X_509_ATTR: CertificateType = CertificateType { val: CKC_X_509_ATTR_CERT, }; /// A WTLS certificate pub const WTLS: CertificateType = CertificateType { val: CKC_WTLS }; pub(crate) fn stringify(cert_type: CK_CERTIFICATE_TYPE) -> String { match cert_type { CKC_X_509 => String::from(stringify!(CKC_X_509)), CKC_X_509_ATTR_CERT => String::from(stringify!(CKC_X_509_ATTR_CERT)), CKC_WTLS => String::from(stringify!(CKC_WTLS)), _ => format!("unknown ({cert_type:08x})"), } } } impl std::fmt::Display for CertificateType { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", CertificateType::stringify(self.val)) } } impl Deref for CertificateType { type Target = CK_CERTIFICATE_TYPE; fn deref(&self) -> &Self::Target { &self.val } } impl From for CK_CERTIFICATE_TYPE { fn from(certificate_type: CertificateType) -> Self { *certificate_type } } impl TryFrom for CertificateType { type Error = Error; fn try_from(certificate_type: CK_CERTIFICATE_TYPE) -> Result { match certificate_type { CKC_X_509 => Ok(CertificateType::X_509), CKC_X_509_ATTR_CERT => Ok(CertificateType::X_509_ATTR), CKC_WTLS => Ok(CertificateType::WTLS), _ => { error!("Certificate type {} is not supported.", certificate_type); Err(Error::NotSupported) } } } } cryptoki-0.6.1/src/session/decryption.rs000064400000000000000000000033001046102023000164700ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Decrypting data use crate::error::{Result, Rv}; use crate::mechanism::Mechanism; use crate::object::ObjectHandle; use crate::session::Session; use cryptoki_sys::*; use std::convert::TryInto; impl Session { /// Single-part decryption operation pub fn decrypt( &self, mechanism: &Mechanism, key: ObjectHandle, encrypted_data: &[u8], ) -> Result> { let mut mechanism: CK_MECHANISM = mechanism.into(); let mut data_len = 0; unsafe { Rv::from(get_pkcs11!(self.client(), C_DecryptInit)( self.handle(), &mut mechanism as CK_MECHANISM_PTR, key.handle(), )) .into_result()?; } // Get the output buffer length unsafe { Rv::from(get_pkcs11!(self.client(), C_Decrypt)( self.handle(), // C_Decrypt should not modify this buffer encrypted_data.as_ptr() as *mut u8, encrypted_data.len().try_into()?, std::ptr::null_mut(), &mut data_len, )) .into_result()?; } let mut data = vec![0; data_len.try_into()?]; unsafe { Rv::from(get_pkcs11!(self.client(), C_Decrypt)( self.handle(), encrypted_data.as_ptr() as *mut u8, encrypted_data.len().try_into()?, data.as_mut_ptr(), &mut data_len, )) .into_result()?; } data.resize(data_len.try_into()?, 0); Ok(data) } } cryptoki-0.6.1/src/session/digesting.rs000064400000000000000000000027331046102023000162760ustar 00000000000000// Copyright 2023 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Digesting functions use crate::error::{Result, Rv}; use crate::mechanism::Mechanism; use crate::session::Session; use cryptoki_sys::*; use std::convert::TryInto; impl Session { /// Single-part digesting operation pub fn digest(&self, m: &Mechanism, data: &[u8]) -> Result> { let mut mechanism: CK_MECHANISM = m.into(); let mut digest_len = 0; unsafe { Rv::from(get_pkcs11!(self.client(), C_DigestInit)( self.handle(), &mut mechanism as CK_MECHANISM_PTR, )) .into_result()?; } // Get the output buffer length unsafe { Rv::from(get_pkcs11!(self.client(), C_Digest)( self.handle(), data.as_ptr() as *mut u8, data.len().try_into()?, std::ptr::null_mut(), &mut digest_len, )) .into_result()?; } let mut digest = vec![0; digest_len.try_into()?]; unsafe { Rv::from(get_pkcs11!(self.client(), C_Digest)( self.handle(), data.as_ptr() as *mut u8, data.len().try_into()?, digest.as_mut_ptr(), &mut digest_len, )) .into_result()?; } digest.resize(digest_len.try_into()?, 0); Ok(digest) } } cryptoki-0.6.1/src/session/encryption.rs000064400000000000000000000032551046102023000165130ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Encrypting data use crate::error::{Result, Rv}; use crate::mechanism::Mechanism; use crate::object::ObjectHandle; use crate::session::Session; use cryptoki_sys::*; use std::convert::TryInto; impl Session { /// Single-part encryption operation pub fn encrypt( &self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8], ) -> Result> { let mut mechanism: CK_MECHANISM = mechanism.into(); let mut encrypted_data_len = 0; unsafe { Rv::from(get_pkcs11!(self.client(), C_EncryptInit)( self.handle(), &mut mechanism as CK_MECHANISM_PTR, key.handle(), )) .into_result()?; } // Get the output buffer length unsafe { Rv::from(get_pkcs11!(self.client(), C_Encrypt)( self.handle(), data.as_ptr() as *mut u8, data.len().try_into()?, std::ptr::null_mut(), &mut encrypted_data_len, )) .into_result()?; } let mut encrypted_data = vec![0; encrypted_data_len.try_into()?]; unsafe { Rv::from(get_pkcs11!(self.client(), C_Encrypt)( self.handle(), data.as_ptr() as *mut u8, data.len().try_into()?, encrypted_data.as_mut_ptr(), &mut encrypted_data_len, )) .into_result()?; } encrypted_data.resize(encrypted_data_len.try_into()?, 0); Ok(encrypted_data) } } cryptoki-0.6.1/src/session/key_management.rs000064400000000000000000000120271046102023000173020ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Key management functions use crate::error::{Result, Rv}; use crate::mechanism::Mechanism; use crate::object::{Attribute, ObjectHandle}; use crate::session::Session; use cryptoki_sys::{CK_ATTRIBUTE, CK_MECHANISM, CK_MECHANISM_PTR}; use std::convert::TryInto; impl Session { /// 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, mechanism: &Mechanism, pub_key_template: &[Attribute], priv_key_template: &[Attribute], ) -> Result<(ObjectHandle, ObjectHandle)> { let mut mechanism: CK_MECHANISM = mechanism.into(); let mut pub_key_template: Vec = pub_key_template.iter().map(|attr| attr.into()).collect(); let mut priv_key_template: Vec = priv_key_template.iter().map(|attr| attr.into()).collect(); let mut pub_handle = 0; let mut priv_handle = 0; unsafe { Rv::from(get_pkcs11!(self.client(), C_GenerateKeyPair)( self.handle(), &mut mechanism as CK_MECHANISM_PTR, pub_key_template.as_mut_ptr(), pub_key_template.len().try_into()?, priv_key_template.as_mut_ptr(), priv_key_template.len().try_into()?, &mut pub_handle, &mut priv_handle, )) .into_result()?; } Ok(( ObjectHandle::new(pub_handle), ObjectHandle::new(priv_handle), )) } /// Derives a key from a base key pub fn derive_key( &self, mechanism: &Mechanism, base_key: ObjectHandle, 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_DeriveKey)( self.handle(), &mut mechanism as CK_MECHANISM_PTR, base_key.handle(), template.as_mut_ptr(), template.len().try_into()?, &mut handle, )) .into_result()?; } 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)) } } cryptoki-0.6.1/src/session/mod.rs000064400000000000000000000047021046102023000150760ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Session types use crate::context::Pkcs11; use cryptoki_sys::*; use std::fmt::Formatter; use std::marker::PhantomData; mod decryption; mod digesting; mod encryption; mod key_management; mod object_management; mod random; mod session_info; mod session_management; mod signing_macing; mod slot_token_management; pub use session_info::{SessionInfo, SessionState}; /// Type that identifies a session /// /// It will automatically get closed (and logout) on drop. /// Session does not implement Sync to prevent the same Session instance to be used from multiple /// threads. A Session needs to be created in its own thread or to be passed by ownership to /// another thread. #[derive(Debug)] pub struct Session { handle: CK_SESSION_HANDLE, client: Pkcs11, // This is not used but to prevent Session to automatically implement Send and Sync _guard: PhantomData<*mut u32>, } impl std::fmt::Display for Session { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.handle) } } impl std::fmt::LowerHex for Session { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{:08x}", self.handle) } } impl std::fmt::UpperHex for Session { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{:08X}", self.handle) } } // Session does not implement Sync to prevent the same Session instance to be used from multiple // threads. unsafe impl Send for Session {} impl Session { pub(crate) fn new(handle: CK_SESSION_HANDLE, client: Pkcs11) -> Self { Session { handle, client, _guard: PhantomData, } } } impl Session { /// Close a session /// This will be called on drop as well. pub fn close(self) {} pub(crate) fn handle(&self) -> CK_SESSION_HANDLE { self.handle } pub(crate) fn client(&self) -> &Pkcs11 { &self.client } } /// Types of PKCS11 users #[derive(Copy, Clone, Debug)] pub enum UserType { /// Security Officer So, /// User User, /// Context Specific ContextSpecific, } impl From for CK_USER_TYPE { fn from(user_type: UserType) -> CK_USER_TYPE { match user_type { UserType::So => CKU_SO, UserType::User => CKU_USER, UserType::ContextSpecific => CKU_CONTEXT_SPECIFIC, } } } cryptoki-0.6.1/src/session/object_management.rs000064400000000000000000000235341046102023000177650ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Object management functions use crate::error::{Result, Rv, RvError}; use crate::object::{Attribute, AttributeInfo, AttributeType, ObjectHandle}; use crate::session::Session; use cryptoki_sys::*; use std::collections::HashMap; use std::convert::TryInto; // Search 10 elements at a time const MAX_OBJECT_COUNT: usize = 10; impl Session { /// Search for session objects matching a template pub fn find_objects(&self, template: &[Attribute]) -> Result> { let mut template: Vec = template.iter().map(|attr| attr.into()).collect(); unsafe { Rv::from(get_pkcs11!(self.client(), C_FindObjectsInit)( self.handle(), template.as_mut_ptr(), template.len().try_into()?, )) .into_result()?; } let mut object_handles = [0; MAX_OBJECT_COUNT]; let mut object_count = 0; let mut objects = Vec::new(); unsafe { Rv::from(get_pkcs11!(self.client(), C_FindObjects)( self.handle(), object_handles.as_mut_ptr() as CK_OBJECT_HANDLE_PTR, MAX_OBJECT_COUNT.try_into()?, &mut object_count, )) .into_result()?; } while object_count > 0 { objects.extend_from_slice(&object_handles[..object_count.try_into()?]); unsafe { Rv::from(get_pkcs11!(self.client(), C_FindObjects)( self.handle(), object_handles.as_mut_ptr() as CK_OBJECT_HANDLE_PTR, MAX_OBJECT_COUNT.try_into()?, &mut object_count, )) .into_result()?; } } unsafe { Rv::from(get_pkcs11!(self.client(), C_FindObjectsFinal)( self.handle(), )) .into_result()?; } let objects = objects.into_iter().map(ObjectHandle::new).collect(); Ok(objects) } /// Create a new object pub fn create_object(&self, 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_CreateObject)( self.handle(), template.as_mut_ptr(), template.len().try_into()?, &mut object_handle as CK_OBJECT_HANDLE_PTR, )) .into_result()?; } Ok(ObjectHandle::new(object_handle)) } /// Destroy an object pub fn destroy_object(&self, object: ObjectHandle) -> Result<()> { unsafe { Rv::from(get_pkcs11!(self.client(), C_DestroyObject)( self.handle(), object.handle(), )) .into_result() } } /// Get the attribute info of an object: if the attribute is present and its size. /// /// # Arguments /// /// * `object` - The [ObjectHandle] used to reference the object /// * `attributes` - The list of attributes to get the information of /// /// # Returns /// /// This function will return a Vector of [AttributeInfo] enums that will either contain /// the size of the requested attribute, [AttributeInfo::TypeInvalid] if the attribute is not a /// valid type for the object, or [AttributeInfo::Sensitive] if the requested attribute is /// sensitive and will not be returned to the user. /// /// The list of returned attributes is 1-to-1 matched with the provided vector of attribute /// types. If you wish, you may create a hash table simply by: /// /// ```no_run /// use cryptoki::context::Pkcs11; /// use cryptoki::context::CInitializeArgs; /// use cryptoki::object::AttributeType; /// use cryptoki::session::UserType; /// use cryptoki::types::AuthPin; /// use std::collections::HashMap; /// use std::env; /// /// let mut pkcs11 = Pkcs11::new( /// env::var("PKCS11_SOFTHSM2_MODULE") /// .unwrap_or_else(|_| "/usr/local/lib/softhsm/libsofthsm2.so".to_string()), /// ) /// .unwrap(); /// /// pkcs11.initialize(CInitializeArgs::OsThreads).unwrap(); /// let slot = pkcs11.get_slots_with_token().unwrap().remove(0); /// /// let session = pkcs11.open_ro_session(slot).unwrap(); /// session.login(UserType::User, Some(&AuthPin::new("fedcba".into()))); /// /// let empty_attrib= vec![]; /// if let Some(object) = session.find_objects(&empty_attrib).unwrap().get(0) { /// let attribute_types = vec![ /// AttributeType::Token, /// AttributeType::Private, /// AttributeType::Modulus, /// AttributeType::KeyType, /// AttributeType::Verify,]; /// /// let attribute_info = session.get_attribute_info(*object, &attribute_types).unwrap(); /// /// let hash = attribute_types /// .iter() /// .zip(attribute_info.iter()) /// .collect::>(); /// } /// ``` /// /// Alternatively, you can call [Session::get_attribute_info_map], found below. pub fn get_attribute_info( &self, object: ObjectHandle, attributes: &[AttributeType], ) -> Result> { let mut results = Vec::new(); for attrib in attributes.iter() { let mut template: Vec = vec![CK_ATTRIBUTE { type_: (*attrib).into(), pValue: std::ptr::null_mut(), ulValueLen: 0, }]; match unsafe { Rv::from(get_pkcs11!(self.client(), C_GetAttributeValue)( self.handle(), object.handle(), template.as_mut_ptr(), template.len().try_into()?, )) } { Rv::Ok => { results.push(AttributeInfo::Available(template[0].ulValueLen.try_into()?)) } Rv::Error(RvError::AttributeSensitive) => results.push(AttributeInfo::Sensitive), Rv::Error(RvError::AttributeTypeInvalid) => { results.push(AttributeInfo::TypeInvalid) } rv => rv.into_result()?, } } Ok(results) } /// Get the attribute info of an object: if the attribute is present and its size. /// /// # Arguments /// /// * `object` - The [ObjectHandle] used to reference the object /// * `attributes` - The list of attributes to get the information of /// /// # Returns /// /// This function will return a HashMap of [AttributeType] and [AttributeInfo] enums that will /// either contain the size of the requested attribute, [AttributeInfo::TypeInvalid] if the /// attribute is not a valid type for the object, or [AttributeInfo::Sensitive] if the requested /// attribute is sensitive and will not be returned to the user. pub fn get_attribute_info_map( &self, object: ObjectHandle, attributes: Vec, ) -> Result> { let attrib_info = self.get_attribute_info(object, attributes.as_slice())?; Ok(attributes .iter() .cloned() .zip(attrib_info.iter().cloned()) .collect::>()) } /// Get the attributes values of an object. /// Ignore the unavailable one. One has to call the get_attribute_info method to check which /// ones are unavailable. pub fn get_attributes( &self, object: ObjectHandle, attributes: &[AttributeType], ) -> Result> { let attrs_info = self.get_attribute_info(object, attributes)?; // Allocating a chunk of memory where to put the attributes value. let attrs_memory: Vec<(AttributeType, Vec)> = attrs_info .iter() .zip(attributes.iter()) .filter_map(|(attr_info, attr_type)| { if let AttributeInfo::Available(size) = attr_info { Some((*attr_type, vec![0; *size])) } else { None } }) .collect(); let mut template: Vec = attrs_memory .iter() .map(|(attr_type, memory)| { Ok(CK_ATTRIBUTE { type_: (*attr_type).into(), pValue: memory.as_ptr() as *mut std::ffi::c_void, ulValueLen: memory.len().try_into()?, }) }) .collect::>>()?; // This should only return OK as all attributes asked should be // available. Concurrency problem? unsafe { Rv::from(get_pkcs11!(self.client(), C_GetAttributeValue)( self.handle(), object.handle(), template.as_mut_ptr(), template.len().try_into()?, )) .into_result()?; } // Convert from CK_ATTRIBUTE to Attribute template.into_iter().map(|attr| attr.try_into()).collect() } /// Sets the attributes of an object pub fn update_attributes(&self, object: ObjectHandle, template: &[Attribute]) -> Result<()> { let mut template: Vec = template.iter().map(|attr| attr.into()).collect(); unsafe { Rv::from(get_pkcs11!(self.client(), C_SetAttributeValue)( self.handle(), object.handle(), template.as_mut_ptr(), template.len().try_into()?, )) .into_result()?; } Ok(()) } } cryptoki-0.6.1/src/session/random.rs000064400000000000000000000033771046102023000156060ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Functions used to generate random numbers use crate::error::{Result, Rv}; use crate::session::Session; use std::convert::TryInto; impl Session { /// Generates a random number and sticks it in a slice /// /// # Arguments /// /// * `random_slice` - The slice to stick the random data into. The length of the slice represents /// the number of bytes to obtain from the RBG pub fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()> { unsafe { Rv::from(get_pkcs11!(self.client(), C_GenerateRandom)( self.handle(), random_data.as_ptr() as *mut u8, random_data.len().try_into()?, )) .into_result()?; } Ok(()) } /// Generates random data and returns it as a `Vec`. The length of the returned Vector will /// be the amount of random requested, which is `random_len`. pub fn generate_random_vec(&self, random_len: u32) -> Result> { let mut result: Vec = vec![0; random_len as usize]; unsafe { Rv::from(get_pkcs11!(self.client(), C_GenerateRandom)( self.handle(), result.as_mut_ptr(), random_len.try_into()?, )) .into_result()?; } Ok(result) } /// Seeds the RNG pub fn seed_random(&self, seed: &[u8]) -> Result<()> { unsafe { Rv::from(get_pkcs11!(self.client(), C_SeedRandom)( self.handle(), seed.as_ptr() as *mut u8, seed.len().try_into()?, )) .into_result()?; } Ok(()) } } cryptoki-0.6.1/src/session/session_info.rs000064400000000000000000000077521046102023000170250ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Session info use crate::error::{Error, Result}; use crate::slot::Slot; use bitflags::bitflags; use cryptoki_sys::*; use std::convert::{TryFrom, TryInto}; use std::fmt::Debug; bitflags! { /// Collection of flags defined for [`CK_SESSION_INFO`] struct SessionInfoFlags: CK_FLAGS { const RW_SESSION = CKF_RW_SESSION; const SERIAL_SESSION = CKF_SERIAL_SESSION; } } /// Provides information about a session #[derive(Copy, Clone, Debug)] pub struct SessionInfo { slot_id: Slot, state: SessionState, flags: SessionInfoFlags, device_error: u64, } impl SessionInfo { /// ID of the slot that interfaces the token pub fn slot_id(&self) -> Slot { self.slot_id } /// The state of the session pub fn session_state(&self) -> SessionState { self.state } /// True if the session has R/W access to token objects, and false if access /// is read-only pub fn read_write(&self) -> bool { self.flags.contains(SessionInfoFlags::RW_SESSION) } /// An error code defined by the cryptographic device (used for errors not /// covered by PKCS#11) pub fn device_error(&self) -> u64 { self.device_error } } #[doc(hidden)] impl TryFrom for SessionInfo { type Error = Error; fn try_from(val: CK_SESSION_INFO) -> Result { #[allow(clippy::useless_conversion)] let device_error = val.ulDeviceError.into(); Ok(Self { slot_id: Slot::new(val.slotID), state: val.state.try_into()?, flags: SessionInfoFlags::from_bits_truncate(val.flags), device_error, }) } } /// The current state of the session which describes access to token and session /// objects based on user type and login status #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum SessionState { /// The session has read-only access to public token objects and R/W access /// to to public session objects RoPublic, /// A normal user has been authenticated to the token. /// The session has read-only access to all public and private token objects /// The session has R/W access to all public and private session objects RoUser, /// The session has read/write access to all public objects RwPublic, /// A normal user has been authenticated to the token. /// The session has read/write access to all objects RwUser, /// A security officer (SO) user has been authenticated to the token. /// The session has R/W access only to public token objects. The SO /// can set the normal user's PIN. RwSecurityOfficer, } #[doc(hidden)] impl TryFrom for SessionState { type Error = Error; fn try_from(value: CK_STATE) -> Result { match value { CKS_RO_PUBLIC_SESSION => Ok(Self::RoPublic), CKS_RO_USER_FUNCTIONS => Ok(Self::RoUser), CKS_RW_PUBLIC_SESSION => Ok(Self::RwPublic), CKS_RW_USER_FUNCTIONS => Ok(Self::RwUser), CKS_RW_SO_FUNCTIONS => Ok(Self::RwSecurityOfficer), _ => Err(Error::InvalidValue), } } } #[cfg(test)] mod test { use super::{SessionInfo, SessionInfoFlags, SessionState}; use crate::slot::Slot; #[test] fn debug_flags_all() { let expected = "RW_SESSION | SERIAL_SESSION"; let all = SessionInfoFlags::all(); let observed = format!("{all:#?}"); assert_eq!(observed, expected); } #[test] fn debug_info() { let info = SessionInfo { slot_id: Slot::new(100), state: SessionState::RoPublic, flags: SessionInfoFlags::empty(), device_error: 0, }; let expected = r#"SessionInfo { slot_id: Slot { slot_id: 100, }, state: RoPublic, flags: (empty), device_error: 0, }"#; let observed = format!("{info:#?}"); assert_eq!(observed, expected); } } cryptoki-0.6.1/src/session/session_management.rs000064400000000000000000000065751046102023000202100ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Session management functions use crate::error::{Result, Rv}; use crate::session::{Session, SessionInfo, UserType}; use crate::types::{AuthPin, RawAuthPin}; #[cfg(doc)] use cryptoki_sys::CKF_PROTECTED_AUTHENTICATION_PATH; use cryptoki_sys::CK_SESSION_INFO; use log::error; use secrecy::ExposeSecret; use std::convert::{TryFrom, TryInto}; impl Drop for Session { fn drop(&mut self) { #[inline(always)] fn close(session: &Session) -> Result<()> { unsafe { Rv::from(get_pkcs11!(session.client(), C_CloseSession)( session.handle(), )) .into_result() } } if let Err(e) = close(self) { error!("Failed to close session: {}", e); } } } impl Session { /// Log a session in. /// /// # Arguments /// /// * `user_type` - The type of user to log in as /// * `pin` - The PIN to use, or `None` if you wish to use the protected authentication path /// /// _NOTE: By passing `None` into `login`, you must ensure that the /// [CKF_PROTECTED_AUTHENTICATION_PATH] flag is set in the `TokenFlags`._ pub fn login(&self, user_type: UserType, pin: Option<&AuthPin>) -> Result<()> { let (pin, pin_len) = match pin { Some(pin) => ( pin.expose_secret().as_ptr() as *mut u8, pin.expose_secret().len(), ), None => (std::ptr::null_mut(), 0), }; unsafe { Rv::from(get_pkcs11!(self.client(), C_Login)( self.handle(), user_type.into(), pin, pin_len.try_into()?, )) .into_result() } } /// Logs a session in using a slice of raw bytes as a PIN. Some dongle drivers allow /// non UTF-8 characters in the PIN and as a result, we aren't guaranteed that we can /// pass in a UTF-8 string to login. Therefore, it's useful to be able to pass in raw bytes /// rather than convert a UTF-8 string to bytes. /// /// # Arguments /// /// * `user_type` - The type of user to log in as /// * `pin` - The PIN to use /// /// _NOTE: By passing `None` into `login`, you must ensure that the /// [CKF_PROTECTED_AUTHENTICATION_PATH] flag is set in the `TokenFlags`._ pub fn login_with_raw(&self, user_type: UserType, pin: &RawAuthPin) -> Result<()> { unsafe { Rv::from(get_pkcs11!(self.client(), C_Login)( self.handle(), user_type.into(), pin.expose_secret().as_ptr() as *mut u8, pin.expose_secret().len().try_into()?, )) .into_result() } } /// Log a session out pub fn logout(&self) -> Result<()> { unsafe { Rv::from(get_pkcs11!(self.client(), C_Logout)(self.handle())).into_result() } } /// Returns the information about a session pub fn get_session_info(&self) -> Result { let mut session_info = CK_SESSION_INFO::default(); unsafe { Rv::from(get_pkcs11!(self.client(), C_GetSessionInfo)( self.handle(), &mut session_info, )) .into_result()?; SessionInfo::try_from(session_info) } } } cryptoki-0.6.1/src/session/signing_macing.rs000064400000000000000000000047521046102023000173000ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Signing and authentication functions use crate::error::{Result, Rv}; use crate::mechanism::Mechanism; use crate::object::ObjectHandle; use crate::session::Session; use cryptoki_sys::*; use std::convert::TryInto; impl Session { /// Sign data in single-part pub fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result> { let mut mechanism: CK_MECHANISM = mechanism.into(); let mut signature_len = 0; unsafe { Rv::from(get_pkcs11!(self.client(), C_SignInit)( self.handle(), &mut mechanism as CK_MECHANISM_PTR, key.handle(), )) .into_result()?; } // Get the output buffer length unsafe { Rv::from(get_pkcs11!(self.client(), C_Sign)( self.handle(), data.as_ptr() as *mut u8, data.len().try_into()?, std::ptr::null_mut(), &mut signature_len, )) .into_result()?; } let mut signature = vec![0; signature_len.try_into()?]; //TODO: we should add a new error instead of those unwrap! unsafe { Rv::from(get_pkcs11!(self.client(), C_Sign)( self.handle(), data.as_ptr() as *mut u8, data.len().try_into()?, signature.as_mut_ptr(), &mut signature_len, )) .into_result()?; } signature.resize(signature_len.try_into()?, 0); Ok(signature) } /// Verify data in single-part pub fn verify( &self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8], signature: &[u8], ) -> 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()?; } unsafe { Rv::from(get_pkcs11!(self.client(), C_Verify)( self.handle(), data.as_ptr() as *mut u8, data.len().try_into()?, signature.as_ptr() as *mut u8, signature.len().try_into()?, )) .into_result() } } } cryptoki-0.6.1/src/session/slot_token_management.rs000064400000000000000000000024061046102023000206730ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! Slot and token management functions use crate::error::{Result, Rv}; use crate::session::Session; use crate::types::AuthPin; use secrecy::ExposeSecret; use std::convert::TryInto; impl Session { /// Initialize the normal user's pin for a token pub fn init_pin(&self, pin: &AuthPin) -> Result<()> { unsafe { Rv::from(get_pkcs11!(self.client(), C_InitPIN)( self.handle(), pin.expose_secret().as_ptr() as *mut u8, pin.expose_secret().len().try_into()?, )) .into_result() } } /// Changes the PIN of either the currently logged in user or of the `CKU_USER` if no user is /// logged in. pub fn set_pin(&self, old_pin: &AuthPin, new_pin: &AuthPin) -> Result<()> { unsafe { Rv::from(get_pkcs11!(self.client(), C_SetPIN)( self.handle(), old_pin.expose_secret().as_ptr() as *mut u8, old_pin.expose_secret().len().try_into()?, new_pin.expose_secret().as_ptr() as *mut u8, new_pin.expose_secret().len().try_into()?, )) .into_result() } } } cryptoki-0.6.1/src/slot/mod.rs000064400000000000000000000034511046102023000143740ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 // Depending on the target, CK_SLOT_ID is not u64 #![allow(clippy::useless_conversion)] //! Slot and token types mod slot_info; mod token_info; pub use slot_info::SlotInfo; pub use token_info::{Limit, TokenInfo}; use crate::error::{Error, Result}; use cryptoki_sys::CK_SLOT_ID; use std::convert::{TryFrom, TryInto}; use std::fmt::Formatter; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] /// Type identifying a slot pub struct Slot { slot_id: CK_SLOT_ID, } impl std::fmt::LowerHex for Slot { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let val = self.slot_id; std::fmt::LowerHex::fmt(&val, f) } } impl std::fmt::UpperHex for Slot { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let val = self.slot_id; std::fmt::UpperHex::fmt(&val, f) } } impl Slot { pub(crate) fn new(slot_id: CK_SLOT_ID) -> Slot { Slot { slot_id } } /// Underlying ID used for a slot pub fn id(&self) -> u64 { self.slot_id.into() } } impl TryFrom for Slot { type Error = Error; fn try_from(slot_id: u64) -> Result { Ok(Self { slot_id: slot_id.try_into()?, }) } } impl TryFrom for Slot { type Error = Error; fn try_from(slot_id: u32) -> Result { Ok(Self { slot_id: slot_id.try_into()?, }) } } impl From for usize { fn from(slot: Slot) -> Self { slot.slot_id as usize } } impl From for CK_SLOT_ID { fn from(slot: Slot) -> Self { slot.slot_id } } impl std::fmt::Display for Slot { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.slot_id) } } cryptoki-0.6.1/src/slot/slot_info.rs000064400000000000000000000076171046102023000156210ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! PKCS11 Slot info and associated flags use crate::{string_from_blank_padded, types::Version}; use bitflags::bitflags; use cryptoki_sys::*; use std::fmt::Debug; bitflags! { /// Collection of flags defined for [`CK_SLOT_INFO`] struct SlotInfoFlags: CK_FLAGS { const TOKEN_PRESENT=CKF_TOKEN_PRESENT; const REMOVABLE_DEVICE=CKF_REMOVABLE_DEVICE; const HW_SLOT = CKF_HW_SLOT; } } /// Information about a slot #[derive(Debug, Clone)] pub struct SlotInfo { slot_description: String, manufacturer_id: String, flags: SlotInfoFlags, hardware_version: Version, firmware_version: Version, } impl SlotInfo { /// String description of the slot /// /// **[Conformance](crate#conformance-notes):** /// This string is maximally 64 bytes (*not* chars) as UTF-8 pub fn slot_description(&self) -> &str { &self.slot_description } /// ID of the slot manufacturer /// /// **[Conformance](crate#conformance-notes):** /// This string is maximally 32 bytes (*not* chars) as UTF-8 pub fn manufacturer_id(&self) -> &str { &self.manufacturer_id } /// True if a token is in the slot (e.g., a device is in the reader). /// /// **[Conformance](crate#conformance-notes):** /// If this slot does not represent a removable device, a token is *always* /// considered to be present. That is, `slot.removable_device() == false` /// implies `slot.token_present() == true`. pub fn token_present(&self) -> bool { self.flags.contains(SlotInfoFlags::TOKEN_PRESENT) } /// True if the reader supports removable devices. /// /// **[Conformance](crate#conformance-notes):** /// For a given slot, this flag *never* changes pub fn removable_device(&self) -> bool { self.flags.contains(SlotInfoFlags::REMOVABLE_DEVICE) } /// True if the slot is a hardware slot, as opposed to a software slot /// implementing a "soft token" pub fn hardware_slot(&self) -> bool { self.flags.contains(SlotInfoFlags::HW_SLOT) } /// Version number of the slot's hardware pub fn hardware_version(&self) -> Version { self.hardware_version } /// Version number of the slot's firmware pub fn firmware_version(&self) -> Version { self.firmware_version } } #[doc(hidden)] impl From for SlotInfo { fn from(val: CK_SLOT_INFO) -> Self { Self { slot_description: string_from_blank_padded(&val.slotDescription), manufacturer_id: string_from_blank_padded(&val.manufacturerID), flags: SlotInfoFlags::from_bits_truncate(val.flags), hardware_version: val.hardwareVersion.into(), firmware_version: val.firmwareVersion.into(), } } } #[cfg(test)] mod test { use super::{SlotInfo, SlotInfoFlags}; use crate::types::Version; #[test] fn debug_flags_all() { let expected = "TOKEN_PRESENT | REMOVABLE_DEVICE | HW_SLOT"; let all = SlotInfoFlags::all(); let observed = format!("{all:#?}"); assert_eq!(observed, expected); } #[test] fn debug_info() { let info = SlotInfo { slot_description: String::from("Slot Description"), manufacturer_id: String::from("Manufacturer ID"), flags: SlotInfoFlags::empty(), hardware_version: Version::new(0, 255), firmware_version: Version::new(255, 0), }; let expected = r#"SlotInfo { slot_description: "Slot Description", manufacturer_id: "Manufacturer ID", flags: (empty), hardware_version: Version { major: 0, minor: 255, }, firmware_version: Version { major: 255, minor: 0, }, }"#; let observed = format!("{info:#?}"); assert_eq!(observed, expected); } } cryptoki-0.6.1/src/slot/token_info.rs000064400000000000000000000503041046102023000157470ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! PKCS11 Token info and associated flags use crate::error::{Error, Result}; use crate::string_from_blank_padded; use crate::types::convert_utc_time; use crate::types::{UtcTime, Version}; use bitflags::bitflags; use cryptoki_sys::*; use std::convert::TryFrom; use std::fmt::Debug; bitflags! { /// Collection of flags defined for [`CK_TOKEN_INFO`] struct TokenInfoFlags: CK_FLAGS { const RNG = CKF_RNG; const WRITE_PROTECTED = CKF_WRITE_PROTECTED; const LOGIN_REQUIRED = CKF_LOGIN_REQUIRED; const USER_PIN_INITIALIZED = CKF_USER_PIN_INITIALIZED; const RESTORE_KEY_NOT_NEEDED = CKF_RESTORE_KEY_NOT_NEEDED; const CLOCK_ON_TOKEN = CKF_CLOCK_ON_TOKEN; const PROTECTED_AUTHENTICATION_PATH = CKF_PROTECTED_AUTHENTICATION_PATH; const DUAL_CRYPTO_OPERATIONS = CKF_DUAL_CRYPTO_OPERATIONS; const TOKEN_INITIALIZED = CKF_TOKEN_INITIALIZED; const SECONDARY_AUTHENTICATION = CKF_SECONDARY_AUTHENTICATION; const USER_PIN_COUNT_LOW = CKF_USER_PIN_COUNT_LOW; const USER_PIN_FINAL_TRY = CKF_USER_PIN_FINAL_TRY; const USER_PIN_LOCKED = CKF_USER_PIN_LOCKED; const USER_PIN_TO_BE_CHANGED = CKF_USER_PIN_TO_BE_CHANGED; const SO_PIN_COUNT_LOW = CKF_SO_PIN_COUNT_LOW; const SO_PIN_FINAL_TRY = CKF_SO_PIN_FINAL_TRY; const SO_PIN_LOCKED = CKF_SO_PIN_LOCKED; const SO_PIN_TO_BE_CHANGED = CKF_SO_PIN_TO_BE_CHANGED; const ERROR_STATE = CKF_ERROR_STATE; } } #[derive(Debug, Clone, Copy)] /// A limiting value for the token that may or may not take an explicit value pub enum Limit { /// There is an explicit value for this limit Max(u64), /// The token does not provide information about this limit Unavailable, /// The limit is "effectively infinite" and may be treated as such Infinite, } /// Information about a token #[derive(Debug, Clone)] pub struct TokenInfo { // The following four strings are limited in size based on // the orignating struct definition. Sizes are in *bytes* // but UTF-8 data may represent fewer characters. // Original buffers were space (0x20) padded. label: String, // len <= 32 bytes manufacturer_id: String, // len <= 32 bytes model: String, // len <= 16 bytes serial_number: String, // len <= 16 bytes flags: TokenInfoFlags, max_session_count: Limit, session_count: Option, max_rw_session_count: Limit, rw_session_count: Option, max_pin_len: usize, min_pin_len: usize, total_public_memory: Option, free_public_memory: Option, total_private_memory: Option, free_private_memory: Option, hardware_version: Version, firmware_version: Version, utc_time: Option, } trait MaybeUnavailable: Sized { fn maybe_unavailable(value: CK_ULONG) -> Option; } impl MaybeUnavailable for usize { fn maybe_unavailable(value: CK_ULONG) -> Option { if value == CK_UNAVAILABLE_INFORMATION { None } else { Some(value as usize) } } } impl MaybeUnavailable for u64 { fn maybe_unavailable(value: CK_ULONG) -> Option { if value == CK_UNAVAILABLE_INFORMATION { None } else { // Must have cast for when ulong is 32 bits Some(value.into()) } } } /// Flattens both `Infinite` and `Unavailable` to `None`, impl From for Option { fn from(limit: Limit) -> Self { match limit { Limit::Unavailable | Limit::Infinite => None, Limit::Max(n) => Some(n), } } } fn maybe_unlimited(value: CK_ULONG) -> Limit { match value { CK_UNAVAILABLE_INFORMATION => Limit::Unavailable, CK_EFFECTIVELY_INFINITE => Limit::Infinite, // Must have cast for when ulong is 32 bits _ => Limit::Max(value.into()), } } impl TokenInfo { /// An application-defined label, assigned during token initialization /// /// **[Conformance](crate#conformance-notes):** /// This string is maximally 32 bytes (*not* chars) as UTF-8 pub fn label(&self) -> &str { &self.label } /// The ID of the device manufacturer /// /// **[Conformance](crate#conformance-notes):** /// This string is maximally 32 bytes (*not* chars) as UTF-8 pub fn manufacturer_id(&self) -> &str { &self.manufacturer_id } /// The model of the device /// /// **[Conformance](crate#conformance-notes):** /// This string is maximally 16 bytes (*not* chars) as UTF-8 pub fn model(&self) -> &str { &self.model } /// The character-string serial number of the device /// /// **[Conformance](crate#conformance-notes):** /// This string is maximally 16 bytes (*not* chars) as UTF-8 pub fn serial_number(&self) -> &str { &self.serial_number } /// True if the token has its own random number generator pub fn rng(&self) -> bool { self.flags.contains(TokenInfoFlags::RNG) } /// True if the token is write-protected /// /// **[Conformance](crate#conformance-notes):** /// Exactly what this value means is determined by the application. An /// application may be unable to perform certain actions on a write- /// protected token. These actions can include any of the following (non- /// exhaustive): /// * Creating/modifying/deleting any object on the token /// * Creating/modifying/deleting a token object on the token /// * Changing the Security Officer's PIN /// * Changing the normal user's PIN /// /// The token may change its write-protected status depending on the /// session state to implement its object management policy. For instance, /// the token may report write-protection unless the session state is R/W /// SO or R/W User to implement a policy that does not allow any objects, /// public or private, to be created, modified, or deleted unless the user /// has successfully called [`Session::login`](crate::session::Session::login). pub fn write_protected(&self) -> bool { self.flags.contains(TokenInfoFlags::WRITE_PROTECTED) } /// True if there are some cryptographic functions that a user *must* be /// logged in to perform pub fn login_required(&self) -> bool { self.flags.contains(TokenInfoFlags::LOGIN_REQUIRED) } /// True of the normal user's PIN has been initialized pub fn user_pin_initialized(&self) -> bool { self.flags.contains(TokenInfoFlags::USER_PIN_INITIALIZED) } /// True if a successful save of a session's cryptographic operations state /// *always* contains all keys needed to restore the state of the session. pub fn restore_key_not_needed(&self) -> bool { self.flags.contains(TokenInfoFlags::RESTORE_KEY_NOT_NEEDED) } /// True if the token has its own hardware clock pub fn clock_on_token(&self) -> bool { self.flags.contains(TokenInfoFlags::CLOCK_ON_TOKEN) } /// True if the token has a "protected authentication path" whereby a user /// can log into the token without passing a PIN pub fn protected_authentication_path(&self) -> bool { self.flags .contains(TokenInfoFlags::PROTECTED_AUTHENTICATION_PATH) } /// True if a single session with the token can perform dual cryptographic /// operations // TODO: Requires Session callbacks to access // * digest_encrypt_update // * decrypt_digest_update // * sign_encrypt_update // * decrypt_verify_update pub fn dual_crypto_operations(&self) -> bool { self.flags.contains(TokenInfoFlags::DUAL_CRYPTO_OPERATIONS) } /// True if the token has been initialized with /// [`Pkcs11::init_token](crate::context::Pkcs11::init_token) or an /// equivalent mechanism outside the scope of the PKCS#11 standard /// /// **[Conformance](crate#conformance-notes):** /// Calling [`Pkcs11::init_token`](crate::context::Pkcs11::init_token) when /// this flag is set will cause the token to be reinitialized. pub fn token_initialized(&self) -> bool { self.flags.contains(TokenInfoFlags::TOKEN_INITIALIZED) } /// True if the token supports secondary authentication for private key /// objects /// **[Conformance](crate#conformance-notes):** /// This field is deprecated and new providers *must not* set it. I.e., this function must always return `false`. pub fn secondary_authentication(&self) -> bool { self.flags .contains(TokenInfoFlags::SECONDARY_AUTHENTICATION) } /// True if an incorrect user login PIN has been entered at least once /// since the last successful authentication /// /// **[Conformance](crate#conformance-notes):** /// This value may be set to always be false if the token either does not /// support the functionality or will not reveal the information because of /// its security policy. pub fn user_pin_count_low(&self) -> bool { self.flags.contains(TokenInfoFlags::USER_PIN_COUNT_LOW) } /// True if supplying an incorrect user PIN will cause it to become locked /// /// **[Conformance](crate#conformance-notes):** /// This value may be set to always be false if the token either does not /// support the functionality or will not reveal the information because of /// its security policy. pub fn user_pin_final_try(&self) -> bool { self.flags.contains(TokenInfoFlags::USER_PIN_FINAL_TRY) } /// True if the user PIN has been locked; user login to the token is not /// possible pub fn user_pin_locked(&self) -> bool { self.flags.contains(TokenInfoFlags::USER_PIN_LOCKED) } /// True if the user PIN value is the default value set by the token /// initialization or manufacturing, or the PIN has been expired by the /// card /// /// **[Conformance](crate#conformance-notes):** /// This may be always false if the token either does not support the /// functionality or will not reveal the information because of its /// security policy. /// /// If a PIN is set to the default value or has expired, this function /// returns `true`. When true, logging in with a PIN will succeed, but only /// the [`Session::set_pin`][crate::session::Session::set_pin] function can /// be called. Calling any other function that required the user to be /// logged in will cause [`PinExpired`][crate::error::RvError::PinExpired] /// to be returned until /// [`Session::set_pin`][crate::session::Session::set_pin] is called /// successfully. pub fn user_pin_to_be_changed(&self) -> bool { self.flags.contains(TokenInfoFlags::USER_PIN_TO_BE_CHANGED) } /// True if an incorrect Security Officer login PIN has been entered at least once since /// the last successful authentication /// /// **[Conformance](crate#conformance-notes):** /// This value may be set to always be false if the token either does not /// support the functionality or will not reveal the information because of /// its security policy. pub fn so_pin_count_low(&self) -> bool { self.flags.contains(TokenInfoFlags::SO_PIN_COUNT_LOW) } /// True if supplying an incorrect Security Officer PIN will cause it to become locked /// /// **[Conformance](crate#conformance-notes):** /// This value may be set to always be false if the token either does not /// support the functionality or will not reveal the information because of /// its security policy. pub fn so_pin_final_try(&self) -> bool { self.flags.contains(TokenInfoFlags::SO_PIN_FINAL_TRY) } /// True if the Security Officer PIN has been locked; Security Officer login to the token is not /// possible pub fn so_pin_locked(&self) -> bool { self.flags.contains(TokenInfoFlags::SO_PIN_LOCKED) } /// True if the Security Officer PIN value is the default value set by the token /// initialization or manufacturing, or the PIN has been expired by the card /// /// **[Conformance](crate#conformance-notes):** /// This may be always false if the token either does not support the /// functionality or will not reveal the information because of its security /// policy. /// /// If a PIN is set to the default value or has expired, this function /// returns `true`. When true, logging in with a PIN will succeed, but only /// the [`Session::set_pin`][crate::session::Session::set_pin] function can /// be called. Calling any other function that required the user to be /// logged in will cause [`PinExpired`][crate::error::RvError::PinExpired] /// to be returned until /// [`Session::set_pin`][crate::session::Session::set_pin] is called /// successfully. pub fn so_pin_to_be_changed(&self) -> bool { self.flags.contains(TokenInfoFlags::SO_PIN_TO_BE_CHANGED) } /// True if the token failed a FIPS 140-2 self-test and entered an error state pub fn error_state(&self) -> bool { self.flags.contains(TokenInfoFlags::ERROR_STATE) } /// The maximum number of sessions that can be opened with the token at one /// time by a single application. pub fn max_session_count(&self) -> Limit { self.max_session_count } /// The number of sessions this application currently has open with the /// token pub fn session_count(&self) -> Option { self.session_count } /// The maximum number of read/write sessions that can be opened with the /// token at one time by a single application. pub fn max_rw_session_count(&self) -> Limit { self.max_rw_session_count } /// The number of read/write sessions this application currently has open /// with the token pub fn rw_session_count(&self) -> Option { self.rw_session_count } /// The maximum length in bytes of the PIN pub fn max_pin_length(&self) -> usize { self.max_pin_len } /// The minimum length in bytes of the PIN pub fn min_pin_length(&self) -> usize { self.min_pin_len } /// The total amount of memory on the token (in bytes) in which public /// objects may be stored /// Returns `None` if this information is unavailable pub fn total_public_memory(&self) -> Option { self.total_public_memory } /// The amount of free (unused) emmeory on the token (in bytes) for public /// objects /// Returns `None` if this information is unavailable pub fn free_public_memory(&self) -> Option { self.free_public_memory } /// The total amount of memory on the token (in bytes) in which private /// objects may be stored /// Returns `None` if this information is unavailable pub fn total_private_memory(&self) -> Option { self.total_private_memory } /// The amount of free (unused) emmeory on the token (in bytes) for private /// objects /// Returns `None` if this information is unavailable pub fn free_private_memory(&self) -> Option { self.free_private_memory } /// The version number of the hardware pub fn hardware_version(&self) -> Version { self.hardware_version } /// The version number of the firmware pub fn firmware_version(&self) -> Version { self.firmware_version } /// The current UTC datetime reported by the token /// /// Returns `None` if the token is not equipped with a clock (i.e., /// `self.clock_on_token() == false`) /// /// **[Conformance](crate#conformance-notes):** /// The string representation of the datetime from the token is only /// required to be parsable as a string of ASCII digits. No additional /// structure (e.g., months numbered from 0 or from 1) is defined. pub fn utc_time(&self) -> Option { self.utc_time } } #[doc(hidden)] impl TryFrom for TokenInfo { type Error = Error; fn try_from(val: CK_TOKEN_INFO) -> Result { let flags = TokenInfoFlags::from_bits_truncate(val.flags); let utc_time = if flags.contains(TokenInfoFlags::CLOCK_ON_TOKEN) { Some(convert_utc_time(val.utcTime)?) } else { None }; Ok(Self { label: string_from_blank_padded(&val.label), manufacturer_id: string_from_blank_padded(&val.manufacturerID), model: string_from_blank_padded(&val.model), serial_number: string_from_blank_padded(&val.serialNumber), flags, max_session_count: maybe_unlimited(val.ulMaxSessionCount), session_count: u64::maybe_unavailable(val.ulSessionCount), max_rw_session_count: maybe_unlimited(val.ulMaxRwSessionCount), rw_session_count: u64::maybe_unavailable(val.ulRwSessionCount), max_pin_len: val.ulMaxPinLen as usize, min_pin_len: val.ulMinPinLen as usize, total_public_memory: usize::maybe_unavailable(val.ulTotalPublicMemory), free_public_memory: usize::maybe_unavailable(val.ulFreePublicMemory), total_private_memory: usize::maybe_unavailable(val.ulTotalPrivateMemory), free_private_memory: usize::maybe_unavailable(val.ulFreePrivateMemory), hardware_version: val.hardwareVersion.into(), firmware_version: val.firmwareVersion.into(), utc_time, }) } } #[cfg(test)] mod test { use super::{Limit, TokenInfo, TokenInfoFlags}; use crate::types::{UtcTime, Version}; #[test] fn debug_flags_all() { let expected = "\ RNG | WRITE_PROTECTED | LOGIN_REQUIRED | USER_PIN_INITIALIZED | \ RESTORE_KEY_NOT_NEEDED | CLOCK_ON_TOKEN | PROTECTED_AUTHENTICATION_PATH | \ DUAL_CRYPTO_OPERATIONS | TOKEN_INITIALIZED | SECONDARY_AUTHENTICATION | \ USER_PIN_COUNT_LOW | USER_PIN_FINAL_TRY | USER_PIN_LOCKED | \ USER_PIN_TO_BE_CHANGED | SO_PIN_COUNT_LOW | SO_PIN_FINAL_TRY | SO_PIN_LOCKED | \ SO_PIN_TO_BE_CHANGED | ERROR_STATE"; let all = TokenInfoFlags::all(); let observed = format!("{all:#?}"); assert_eq!(observed, expected); } #[test] fn debug_info() { let info = TokenInfo { label: String::from("Token Label"), manufacturer_id: String::from("Manufacturer ID"), model: String::from("Token Model"), serial_number: String::from("Serial Number"), flags: TokenInfoFlags::empty(), max_session_count: Limit::Max(100), // max == 100 session_count: None, // unavailable max_rw_session_count: Limit::Infinite, // max == infinite rw_session_count: Some(1), max_pin_len: 16, min_pin_len: 4, total_public_memory: Some(32 << 30), // 32GiB free_public_memory: Some(1234567890), total_private_memory: None, // unavailable free_private_memory: None, // unavailable hardware_version: Version::new(0, 255), firmware_version: Version::new(255, 0), utc_time: Some(UtcTime { year: 1970, month: 1, day: 1, hour: 0, minute: 0, second: 0, }), }; let expected = r#"TokenInfo { label: "Token Label", manufacturer_id: "Manufacturer ID", model: "Token Model", serial_number: "Serial Number", flags: (empty), max_session_count: Max( 100, ), session_count: None, max_rw_session_count: Infinite, rw_session_count: Some( 1, ), max_pin_len: 16, min_pin_len: 4, total_public_memory: Some( 34359738368, ), free_public_memory: Some( 1234567890, ), total_private_memory: None, free_private_memory: None, hardware_version: Version { major: 0, minor: 255, }, firmware_version: Version { major: 255, minor: 0, }, utc_time: Some( UtcTime { year: 1970, month: 1, day: 1, hour: 0, minute: 0, second: 0, }, ), }"#; let observed = format!("{info:#?}"); assert_eq!(observed, expected); } } cryptoki-0.6.1/src/types.rs000064400000000000000000000223271046102023000140030ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 //! PKCS11 General Data Types use crate::error::{Error, Result}; use cryptoki_sys::*; use secrecy::SecretString; use secrecy::SecretVec; use std::convert::TryFrom; use std::convert::TryInto; use std::fmt::Formatter; use std::ops::Deref; #[derive(Debug, Copy, Clone, Default)] #[repr(transparent)] /// Value that represents a date pub struct Date { date: CK_DATE, } impl Date { /// Creates a new `Date` structure /// /// # Arguments /// /// * `year` - A 4 character length year, e.g. "2021" /// * `month` - A 2 character length mont, e.g. "02" /// * `day` - A 2 character length day, e.g. "15" /// /// # Errors /// /// If the lengths are invalid a `Error::InvalidValue` will be returned pub fn new_from_str_slice(year: &str, month: &str, day: &str) -> Result { if year.len() != 4 || month.len() != 2 || day.len() != 2 { Err(Error::InvalidValue) } else { let mut year_slice: [u8; 4] = Default::default(); let mut month_slice: [u8; 2] = Default::default(); let mut day_slice: [u8; 2] = Default::default(); year_slice.copy_from_slice(year.as_bytes()); month_slice.copy_from_slice(month.as_bytes()); day_slice.copy_from_slice(day.as_bytes()); Ok(Date::new(year_slice, month_slice, day_slice)) } } /// Creates a new `Date` structure from byte slices /// /// # Arguments /// /// * `year` - A 4 character length year, e.g. "2021" /// * `month` - A 2 character length mont, e.g. "02" /// * `day` - A 2 character length day, e.g. "15" pub fn new(year: [u8; 4], month: [u8; 2], day: [u8; 2]) -> Self { let date = CK_DATE { year, month, day }; Self { date } } /// Creates a new, empty `Date` structure /// /// This represents the default value of the attribute (on /// newer implementations of `Cryptoki`). pub fn new_empty() -> Self { Self::default() } /// Check if `Date` is empty /// /// *NOTE*: This function is only representative of newer implementations /// of `Cryptoki`, for which dates are represented as empty object attributes. pub fn is_empty(&self) -> bool { self.date.year == <[u8; 4]>::default() && self.date.month == <[u8; 2]>::default() && self.date.day == <[u8; 2]>::default() } } impl Deref for Date { type Target = CK_DATE; fn deref(&self) -> &Self::Target { &self.date } } impl From for CK_DATE { fn from(date: Date) -> Self { *date } } impl From for Date { fn from(date: CK_DATE) -> Self { Self { date } } } impl std::fmt::Display for Date { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let year = String::from_utf8_lossy(Vec::from(self.year).as_slice()) .trim_end() .to_string(); let month = String::from_utf8_lossy(Vec::from(self.month).as_slice()) .trim_end() .to_string(); let day = String::from_utf8_lossy(Vec::from(self.day).as_slice()) .trim_end() .to_string(); write!(f, "Month: {month}\nDay: {day}\nYear: {year}") } } impl PartialEq for Date { fn eq(&self, other: &Self) -> bool { self.date.year == other.date.year && self.date.month == other.date.month && self.date.day == other.date.day } } impl Eq for Date {} #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(transparent)] /// Unsigned value, at least 32 bits long pub struct Ulong { val: CK_ULONG, } impl Deref for Ulong { type Target = CK_ULONG; fn deref(&self) -> &Self::Target { &self.val } } impl From for CK_ULONG { fn from(ulong: Ulong) -> Self { *ulong } } impl From for Ulong { fn from(ulong: CK_ULONG) -> Self { Ulong { val: ulong } } } impl TryFrom for Ulong { type Error = Error; fn try_from(ulong: usize) -> Result { Ok(Ulong { val: ulong.try_into()?, }) } } impl From for usize { fn from(ulong: Ulong) -> Self { ulong.val as usize } } impl std::fmt::Display for Ulong { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.val) } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] /// Represents a version pub struct Version { major: CK_BYTE, minor: CK_BYTE, } impl std::fmt::Display for Version { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}.{}", self.major, self.minor) } } impl Version { /// Construct a new version #[cfg(test)] pub(crate) fn new(major: u8, minor: u8) -> Self { Self { major, minor } } /// Returns the major version pub fn major(&self) -> CK_BYTE { self.major } /// Returns the minor version pub fn minor(&self) -> CK_BYTE { self.minor } } impl From for CK_VERSION { fn from(version: Version) -> Self { CK_VERSION { major: version.major, minor: version.minor, } } } impl From for Version { fn from(version: CK_VERSION) -> Self { Version { major: version.major, minor: version.minor, } } } /// A UTC datetime returned by a token's clock if present. #[derive(Copy, Clone, Debug)] pub struct UtcTime { /// **[Conformance](crate#conformance-notes):** /// Guaranteed to be in range 0..=9999 pub year: u16, /// **[Conformance](crate#conformance-notes):** /// Guaranteed to be in range 0..=99 pub month: u8, /// **[Conformance](crate#conformance-notes):** /// Guaranteed to be in range 0..=99 pub day: u8, /// **[Conformance](crate#conformance-notes):** /// Guaranteed to be in range 0..=99 pub hour: u8, /// **[Conformance](crate#conformance-notes):** /// Guaranteed to be in range 0..=99 pub minute: u8, /// **[Conformance](crate#conformance-notes):** /// Guaranteed to be in range 0..=99 pub second: u8, } impl UtcTime { /// Stringify the structure in ISO 8601 format. /// /// PKCS#11 and ISO are unrelated standards, and this function is provided /// only for convenience. ISO format is more widely recognized and parsable /// by various date/time utilities, while PKCS#11's internal representation /// of this type is is not used elsewhere. /// Other than formatting, this crate does not guarantee or enforce any part /// of the ISO standard. pub fn as_iso8601_string(&self) -> String { format!( "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}Z", self.year, self.month, self.day, self.hour, self.minute, self.second ) } } // UTC time has the format YYYYMMDDhhmmss00 as ASCII digits pub(crate) fn convert_utc_time(orig: [u8; 16]) -> Result { // Note: No validaiton of these values beyond being ASCII digits // because PKCS#11 doesn't impose any such restrictions. Ok(UtcTime { year: std::str::from_utf8(&orig[0..4])?.parse()?, month: std::str::from_utf8(&orig[4..6])?.parse()?, day: std::str::from_utf8(&orig[6..8])?.parse()?, hour: std::str::from_utf8(&orig[8..10])?.parse()?, minute: std::str::from_utf8(&orig[10..12])?.parse()?, second: std::str::from_utf8(&orig[12..14])?.parse()?, }) } /// Secret wrapper for a Pin /// /// Enable the `serde` feature to add support for Deserialize pub type AuthPin = SecretString; /// Secret wrapper for a raw non UTF-8 Pin /// /// Enable the `serde` feature to add support for Deserialize pub type RawAuthPin = SecretVec; #[cfg(test)] mod test { use super::*; const UTC_TIME: UtcTime = UtcTime { year: 1970, month: 1, day: 1, hour: 0, minute: 0, second: 0, }; #[test] fn utc_time_convert_good() { let valid: [u8; 16] = [ 0x31, 0x39, 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ]; let valid = convert_utc_time(valid).unwrap(); assert_eq!(valid.year, UTC_TIME.year); assert_eq!(valid.month, UTC_TIME.month); assert_eq!(valid.day, UTC_TIME.day); assert_eq!(valid.hour, UTC_TIME.hour); assert_eq!(valid.minute, UTC_TIME.minute); assert_eq!(valid.second, UTC_TIME.second); } #[test] fn utc_time_convert_bad() { // Year starts with a non-numeric value ('A') let invalid: [u8; 16] = [ 0x41, 0x39, 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ]; let invalid = convert_utc_time(invalid); assert!(invalid.is_err()); } #[test] fn utc_time_debug_fmt() { let expected = r#"UtcTime { year: 1970, month: 1, day: 1, hour: 0, minute: 0, second: 0, }"#; let observed = format!("{UTC_TIME:#?}"); assert_eq!(observed, expected); } #[test] fn utc_time_display_fmt() { let iso_format = UTC_TIME.as_iso8601_string(); assert_eq!(&iso_format, "1970-01-01T00:00:00Z"); } } cryptoki-0.6.1/tests/basic.rs000064400000000000000000001015041046102023000142660ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 mod common; 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::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; use serial_test::serial; use std::collections::HashMap; use std::thread; use testresult::TestResult; #[test] #[serial] fn sign_verify() -> TestResult { let (pkcs11, slot) = init_pins(); // open a session let session = pkcs11.open_rw_session(slot)?; // log in the session session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // get mechanism let mechanism = Mechanism::RsaPkcsKeyPairGen; let public_exponent: Vec = vec![0x01, 0x00, 0x01]; let modulus_bits = 1024; // pub key template let pub_key_template = vec![ Attribute::Token(true), Attribute::Private(false), Attribute::PublicExponent(public_exponent), Attribute::ModulusBits(modulus_bits.into()), ]; // priv key template let priv_key_template = vec![Attribute::Token(true)]; // generate a key pair let (public, private) = session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; // data to sign let data = [0xFF, 0x55, 0xDD]; // sign something with it let signature = session.sign(&Mechanism::RsaPkcs, private, &data)?; // verify the signature session.verify(&Mechanism::RsaPkcs, public, &data, &signature)?; // delete keys session.destroy_object(public)?; session.destroy_object(private)?; Ok(()) } #[test] #[serial] fn sign_verify_ed25519() -> TestResult { let (pkcs11, slot) = init_pins(); let session = pkcs11.open_rw_session(slot)?; session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; let mechanism = Mechanism::EccEdwardsKeyPairGen; let pub_key_template = vec![ Attribute::Token(true), Attribute::Private(false), Attribute::Verify(true), // Ed25519 OID // See: https://github.com/opendnssec/SoftHSMv2/blob/ac70dc398b236e4522101930e790008936489e2d/src/lib/test/SignVerifyTests.cpp#L173 Attribute::EcParams(vec![ 0x13, 0x0c, 0x65, 0x64, 0x77, 0x61, 0x72, 0x64, 0x73, 0x32, 0x35, 0x35, 0x31, 0x39, ]), ]; let priv_key_template = vec![Attribute::Token(true)]; let (public, private) = session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; let data = [0xFF, 0x55, 0xDD]; let signature = session.sign(&Mechanism::Eddsa, private, &data)?; session.verify(&Mechanism::Eddsa, public, &data, &signature)?; session.destroy_object(public)?; session.destroy_object(private)?; Ok(()) } #[test] #[serial] fn encrypt_decrypt() -> TestResult { let (pkcs11, slot) = init_pins(); // open a session let session = pkcs11.open_rw_session(slot)?; // log in the session session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // get mechanism let mechanism = Mechanism::RsaPkcsKeyPairGen; let public_exponent: Vec = vec![0x01, 0x00, 0x01]; let modulus_bits = 1024; // pub key template let pub_key_template = vec![ Attribute::Token(true), Attribute::Private(false), Attribute::PublicExponent(public_exponent), Attribute::ModulusBits(modulus_bits.into()), Attribute::Encrypt(true), ]; // priv key template let priv_key_template = vec![Attribute::Token(true), Attribute::Decrypt(true)]; // generate a key pair let (public, private) = session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; // data to encrypt let data = vec![0xFF, 0x55, 0xDD]; // encrypt something with it let encrypted_data = session.encrypt(&Mechanism::RsaPkcs, public, &data)?; // decrypt let decrypted_data = session.decrypt(&Mechanism::RsaPkcs, private, &encrypted_data)?; // The decrypted buffer is bigger than the original one. assert_eq!(data, decrypted_data); // delete keys session.destroy_object(public)?; session.destroy_object(private)?; Ok(()) } #[test] #[serial] fn derive_key() -> TestResult { let (pkcs11, slot) = init_pins(); // open a session let session = pkcs11.open_rw_session(slot)?; // log in the session session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // get mechanism let mechanism = Mechanism::EccKeyPairGen; let secp256r1_oid: Vec = vec![0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07]; // pub key template let pub_key_template = vec![ Attribute::Token(true), Attribute::Private(false), Attribute::Derive(true), Attribute::KeyType(KeyType::EC), Attribute::Verify(true), Attribute::EcParams(secp256r1_oid), ]; // priv key template let priv_key_template = vec![ Attribute::Token(true), Attribute::Private(true), Attribute::Sensitive(true), Attribute::Extractable(false), Attribute::Derive(true), Attribute::Sign(true), ]; // generate a key pair let (public, private) = session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; let ec_point_attribute = session .get_attributes(public, &[AttributeType::EcPoint])? .remove(0); let ec_point = if let Attribute::EcPoint(point) = ec_point_attribute { point } else { panic!("Expected EC point attribute."); }; use cryptoki::mechanism::elliptic_curve::*; let params = Ecdh1DeriveParams::new(EcKdf::null(), &ec_point); let shared_secret = session.derive_key( &Mechanism::Ecdh1Derive(params), private, &[ Attribute::Class(ObjectClass::SECRET_KEY), Attribute::KeyType(KeyType::GENERIC_SECRET), Attribute::Sensitive(false), Attribute::Extractable(true), Attribute::Token(false), ], )?; let value_attribute = session .get_attributes(shared_secret, &[AttributeType::Value])? .remove(0); let value = if let Attribute::Value(value) = value_attribute { value } else { panic!("Expected value attribute."); }; assert_eq!(value.len(), 32); // delete keys session.destroy_object(public)?; session.destroy_object(private)?; Ok(()) } #[test] #[serial] fn import_export() -> TestResult { let (pkcs11, slot) = init_pins(); // open a session let session = pkcs11.open_rw_session(slot)?; // log in the session session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; let public_exponent: Vec = vec![0x01, 0x00, 0x01]; let modulus = vec![0xFF; 1024]; let template = vec![ Attribute::Token(true), Attribute::Private(false), Attribute::PublicExponent(public_exponent), Attribute::Modulus(modulus.clone()), Attribute::Class(ObjectClass::PUBLIC_KEY), Attribute::KeyType(KeyType::RSA), Attribute::Verify(true), ]; { // Intentionally forget the object handle to find it later let _public_key = session.create_object(&template)?; } let is_it_the_public_key = session.find_objects(&template)?.remove(0); let attribute_info = session .get_attribute_info(is_it_the_public_key, &[AttributeType::Modulus])? .remove(0); if let AttributeInfo::Available(size) = attribute_info { assert_eq!(size, 1024); } else { panic!("The Modulus attribute was expected to be present.") }; let attr = session .get_attributes(is_it_the_public_key, &[AttributeType::Modulus])? .remove(0); if let Attribute::Modulus(modulus_cmp) = attr { assert_eq!(modulus[..], modulus_cmp[..]); } else { panic!("Expected the Modulus attribute."); } // delete key session.destroy_object(is_it_the_public_key)?; Ok(()) } #[test] #[serial] fn get_token_info() -> TestResult { let (pkcs11, slot) = init_pins(); let info = pkcs11.get_token_info(slot)?; assert_eq!("SoftHSM project", info.manufacturer_id()); Ok(()) } #[test] #[serial] fn wrap_and_unwrap_key() { let (pkcs11, slot) = init_pins(); // open a session let session = pkcs11.open_rw_session(slot).unwrap(); // log in the session session .login(UserType::User, Some(&AuthPin::new(USER_PIN.into()))) .unwrap(); let key_to_be_wrapped_template = vec![ Attribute::Token(true), // the key needs to be extractable to be suitable for being wrapped Attribute::Extractable(true), Attribute::Encrypt(true), ]; // 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), Attribute::Private(true), Attribute::PublicExponent(vec![0x01, 0x00, 0x01]), Attribute::ModulusBits(1024.into()), // key needs to have "wrap" attribute to wrap other keys Attribute::Wrap(true), ]; // priv key template let priv_key_template = vec![Attribute::Token(true)]; 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), Attribute::Private(true), Attribute::Encrypt(true), 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() { const SESSIONS: usize = 100; let (pkcs11, slot) = init_pins(); let mut threads = Vec::new(); for _ in 0..SESSIONS { let pkcs11 = pkcs11.clone(); threads.push(thread::spawn(move || { let session = pkcs11.open_rw_session(slot).unwrap(); match session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into()))) { Ok(_) | Err(Error::Pkcs11(RvError::UserAlreadyLoggedIn)) => {} Err(e) => panic!("Bad error response: {}", e), } match session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into()))) { Ok(_) | Err(Error::Pkcs11(RvError::UserAlreadyLoggedIn)) => {} Err(e) => panic!("Bad error response: {}", e), } match session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into()))) { Ok(_) | Err(Error::Pkcs11(RvError::UserAlreadyLoggedIn)) => {} Err(e) => panic!("Bad error response: {}", e), } match session.logout() { Ok(_) | Err(Error::Pkcs11(RvError::UserNotLoggedIn)) => {} Err(e) => panic!("Bad error response: {}", e), } match session.logout() { Ok(_) | Err(Error::Pkcs11(RvError::UserNotLoggedIn)) => {} Err(e) => panic!("Bad error response: {}", e), } match session.logout() { Ok(_) | Err(Error::Pkcs11(RvError::UserNotLoggedIn)) => {} Err(e) => panic!("Bad error response: {}", e), } })); } for thread in threads { thread.join().unwrap(); } } #[test] #[serial] fn get_info_test() -> TestResult { let (pkcs11, _) = init_pins(); let info = pkcs11.get_library_info()?; assert_eq!(info.cryptoki_version().major(), 2); assert_eq!(info.cryptoki_version().minor(), 40); assert_eq!(info.manufacturer_id(), String::from("SoftHSM")); Ok(()) } #[test] #[serial] fn get_slot_info_test() -> TestResult { let (pkcs11, slot) = init_pins(); let slot_info = pkcs11.get_slot_info(slot)?; assert!(slot_info.token_present()); assert!(!slot_info.hardware_slot()); assert!(!slot_info.removable_device()); assert_eq!(slot_info.manufacturer_id(), String::from("SoftHSM project")); Ok(()) } #[test] #[serial] fn get_session_info_test() -> TestResult { let (pkcs11, slot) = init_pins(); { let session = pkcs11.open_ro_session(slot)?; let session_info = session.get_session_info()?; assert!(!session_info.read_write()); assert_eq!(session_info.slot_id(), slot); assert!(matches!( session_info.session_state(), SessionState::RoPublic )); session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; let session_info = session.get_session_info()?; assert!(!session_info.read_write()); assert_eq!(session_info.slot_id(), slot); assert!(matches!(session_info.session_state(), SessionState::RoUser)); session.logout()?; if let Err(cryptoki::error::Error::Pkcs11(rv_error)) = session.login(UserType::So, Some(&AuthPin::new(SO_PIN.into()))) { assert_eq!(rv_error, RvError::SessionReadOnlyExists) } else { panic!("Should error when attempting to log in as CKU_SO on a read-only session"); } } let session = pkcs11.open_rw_session(slot)?; let session_info = session.get_session_info()?; assert!(session_info.read_write()); assert_eq!(session_info.slot_id(), slot); assert!(matches!( session_info.session_state(), SessionState::RwPublic )); session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; let session_info = session.get_session_info()?; assert!(session_info.read_write()); assert_eq!(session_info.slot_id(), slot); assert!(matches!(session_info.session_state(), SessionState::RwUser,)); session.logout()?; session.login(UserType::So, Some(&AuthPin::new(SO_PIN.into())))?; let session_info = session.get_session_info()?; assert!(session_info.read_write()); assert_eq!(session_info.slot_id(), slot); assert!(matches!( session_info.session_state(), SessionState::RwSecurityOfficer )); Ok(()) } #[test] #[serial] fn generate_random_test() -> TestResult { let (pkcs11, slot) = init_pins(); let session = pkcs11.open_ro_session(slot)?; let poor_seed: [u8; 32] = [0; 32]; session.seed_random(&poor_seed)?; let mut random_data: [u8; 32] = [0; 32]; session.generate_random_slice(&mut random_data)?; // This of course assumes the RBG in the the SoftHSM is not terrible assert!(!random_data.iter().all(|&x| x == 0)); let random_vec = session.generate_random_vec(32)?; assert_eq!(random_vec.len(), 32); assert!(!random_vec.iter().all(|&x| x == 0)); Ok(()) } #[test] #[serial] fn set_pin_test() -> TestResult { let new_user_pin = "123456"; let (pkcs11, slot) = init_pins(); let session = pkcs11.open_rw_session(slot)?; let user_pin = AuthPin::new(USER_PIN.into()); let new_user_pin = AuthPin::new(new_user_pin.into()); session.login(UserType::User, Some(&user_pin))?; session.set_pin(&user_pin, &new_user_pin)?; session.logout()?; session.login(UserType::User, Some(&new_user_pin))?; Ok(()) } #[test] #[serial] fn get_attribute_info_test() -> TestResult { let (pkcs11, slot) = init_pins(); // open a session let session = pkcs11.open_rw_session(slot)?; // log in the session session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // get mechanism let mechanism = Mechanism::RsaPkcsKeyPairGen; let public_exponent: Vec = vec![0x01, 0x00, 0x01]; let modulus_bits = 2048; // pub key template let pub_key_template = vec![ Attribute::Token(false), Attribute::Private(false), Attribute::PublicExponent(public_exponent), Attribute::ModulusBits(modulus_bits.into()), ]; // priv key template let priv_key_template = vec![ Attribute::Token(false), Attribute::Sensitive(true), Attribute::Extractable(false), ]; // generate a key pair let (public, private) = session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; let pub_attribs = vec![AttributeType::PublicExponent, AttributeType::Modulus]; let mut priv_attribs = pub_attribs.clone(); priv_attribs.push(AttributeType::PrivateExponent); let attrib_info = session.get_attribute_info(public, &pub_attribs)?; let hash = pub_attribs .iter() .zip(attrib_info.iter()) .collect::>(); if let AttributeInfo::Available(size) = hash[&AttributeType::Modulus] { assert_eq!(*size, 2048 / 8); } else { panic!("Modulus should not return Unavailable for an RSA public key"); } match hash[&AttributeType::PublicExponent] { AttributeInfo::Available(_) => {} _ => panic!("Public Exponent should not return Unavailable for an RSA public key"), } let attrib_info = session.get_attribute_info(private, &priv_attribs)?; let hash = priv_attribs .iter() .zip(attrib_info.iter()) .collect::>(); if let AttributeInfo::Available(size) = hash[&AttributeType::Modulus] { assert_eq!(*size, 2048 / 8); } else { panic!("Modulus should not return Unavailable on an RSA private key"); } match hash[&AttributeType::PublicExponent] { AttributeInfo::Available(_) => {} _ => panic!("PublicExponent should not return Unavailable on an RSA private key"), } match hash[&AttributeType::PrivateExponent] { AttributeInfo::Sensitive => {} _ => panic!("Private Exponent of RSA private key should be sensitive"), } let hash = session.get_attribute_info_map(private, priv_attribs)?; if let AttributeInfo::Available(size) = hash[&AttributeType::Modulus] { assert_eq!(size, 2048 / 8); } else { panic!("Modulus should not return Unavailable on an RSA private key"); } match hash[&AttributeType::PublicExponent] { AttributeInfo::Available(_) => {} _ => panic!("Public Exponent should not return Unavailable for an RSA private key"), } match hash[&AttributeType::PrivateExponent] { AttributeInfo::Sensitive => {} _ => panic!("Private Exponent of RSA private key should be sensitive"), } Ok(()) } #[test] #[serial] fn is_fn_supported_test() { use cryptoki::context::Function; let (pkcs11, _) = init_pins(); assert!( pkcs11.is_fn_supported(Function::Initialize), "C_Initialize function reports as not supported" ); assert!( pkcs11.is_fn_supported(Function::Sign), "C_Sign function reports as not supported" ); assert!( pkcs11.is_fn_supported(Function::DigestFinal), "C_DigestFinal function reports as not supported" ); } #[test] #[serial] fn is_initialized_test() { use cryptoki::context::CInitializeArgs; let pkcs11 = get_pkcs11(); assert!( !pkcs11.is_initialized(), "Context created with initialized flag on" ); // initialize the library pkcs11.initialize(CInitializeArgs::OsThreads).unwrap(); assert!( pkcs11.is_initialized(), "Context was not marked as initialized" ); match pkcs11.initialize(CInitializeArgs::OsThreads) { Err(Error::AlreadyInitialized) => (), Err(e) => panic!("Got unexpected error when initializing: {}", e), Ok(()) => panic!("Initializing twice should not have been allowed"), } } #[test] #[serial] #[allow(clippy::redundant_clone)] fn test_clone_initialize() { use cryptoki::context::CInitializeArgs; let pkcs11 = get_pkcs11(); let clone = pkcs11.clone(); assert!( !pkcs11.is_initialized(), "Before initialize() it should not be initialized" ); assert!( !clone.is_initialized(), "Before initialize() the clone should not be initialized" ); pkcs11.initialize(CInitializeArgs::OsThreads).unwrap(); assert!( pkcs11.is_initialized(), "After initialize() it should be initialized" ); assert!( clone.is_initialized(), "After initialize() the clone should be initialized" ); } #[test] #[serial] fn aes_key_attributes_test() -> TestResult { let (pkcs11, slot) = init_pins(); // open a session let session = pkcs11.open_rw_session(slot)?; // log in the session session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // get mechanism let mechanism = Mechanism::AesKeyGen; // pub key template let key_template = vec![ Attribute::Class(ObjectClass::SECRET_KEY), Attribute::Token(true), Attribute::Sensitive(true), Attribute::ValueLen(16.into()), Attribute::KeyType(KeyType::AES), Attribute::Label(b"testAES".to_vec()), Attribute::Private(true), ]; // generate a key pair let key = session.generate_key(&mechanism, &key_template)?; let mut attributes_result = session.get_attributes(key, &[AttributeType::EndDate, AttributeType::StartDate])?; if let Some(Attribute::StartDate(date)) = attributes_result.pop() { assert!(date.is_empty()); } else { panic!("Last attribute was not a start date"); } if let Some(Attribute::EndDate(date)) = attributes_result.pop() { assert!(date.is_empty()); } else { panic!("First attribute was not an end date"); } Ok(()) } #[test] #[serial] fn ro_rw_session_test() -> TestResult { let public_exponent: Vec = vec![0x01, 0x00, 0x01]; let modulus = vec![0xFF; 1024]; let template = vec![ Attribute::Token(true), Attribute::Private(false), Attribute::PublicExponent(public_exponent), Attribute::Modulus(modulus), Attribute::Class(ObjectClass::PUBLIC_KEY), Attribute::KeyType(KeyType::RSA), Attribute::Verify(true), ]; let (pkcs11, slot) = init_pins(); // Try out Read-Only session { // open a session let ro_session = pkcs11.open_ro_session(slot)?; // log in the session ro_session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // generate a key pair // This should NOT work using the Read-Only session let e = ro_session.create_object(&template).unwrap_err(); if let Error::Pkcs11(RvError::SessionReadOnly) = e { // as expected } else { panic!("Got wrong error code (expecting SessionReadOnly): {}", e); } ro_session.logout()?; } // Try out Read/Write session { // 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())))?; // generate a key pair // This should work using the Read/Write session let object = rw_session.create_object(&template)?; // delete keys rw_session.destroy_object(object)?; rw_session.logout()?; } Ok(()) } #[test] #[serial] fn aes_cbc_encrypt() -> TestResult { // Encrypt two blocks of zeros with AES-128-CBC, and zero IV let key = vec![0; 16]; let iv = [0; 16]; let plain = [0; 32]; let expected_cipher = [ 0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b, 0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e, 0xf7, 0x95, 0xbd, 0x4a, 0x52, 0xe2, 0x9e, 0xd7, 0x13, 0xd3, 0x13, 0xfa, 0x20, 0xe9, 0x8d, 0xbc, ]; let (pkcs11, slot) = init_pins(); let session = pkcs11.open_rw_session(slot)?; session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; let template = [ Attribute::Class(ObjectClass::SECRET_KEY), Attribute::KeyType(KeyType::AES), Attribute::Value(key), Attribute::Encrypt(true), ]; let key_handle = session.create_object(&template)?; let mechanism = Mechanism::AesCbc(iv); let cipher = session.encrypt(&mechanism, key_handle, &plain)?; assert_eq!(expected_cipher[..], cipher[..]); Ok(()) } #[test] #[serial] fn aes_cbc_pad_encrypt() -> TestResult { // Encrypt two blocks of zeros with AES-128-CBC and PKCS#7 padding, and zero IV let key = vec![0; 16]; let iv = [0; 16]; let plain = [0; 32]; let expected_cipher = [ 0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b, 0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e, 0xf7, 0x95, 0xbd, 0x4a, 0x52, 0xe2, 0x9e, 0xd7, 0x13, 0xd3, 0x13, 0xfa, 0x20, 0xe9, 0x8d, 0xbc, 0x5c, 0x04, 0x76, 0x16, 0x75, 0x6f, 0xdc, 0x1c, 0x32, 0xe0, 0xdf, 0x6e, 0x8c, 0x59, 0xbb, 0x2a, ]; let (pkcs11, slot) = init_pins(); let session = pkcs11.open_rw_session(slot)?; session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; let template = [ Attribute::Class(ObjectClass::SECRET_KEY), Attribute::KeyType(KeyType::AES), Attribute::Value(key), Attribute::Encrypt(true), ]; let key_handle = session.create_object(&template)?; let mechanism = Mechanism::AesCbcPad(iv); let cipher = session.encrypt(&mechanism, key_handle, &plain)?; assert_eq!(expected_cipher[..], cipher[..]); Ok(()) } #[test] #[serial] fn update_attributes_key() -> TestResult { let (pkcs11, slot) = init_pins(); // open a session let session = pkcs11.open_rw_session(slot)?; // log in the session session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // pub key template let pub_key_template = vec![ Attribute::Token(true), Attribute::Private(true), Attribute::PublicExponent(vec![0x01, 0x00, 0x01]), Attribute::ModulusBits(1024.into()), ]; // priv key template let priv_key_template = vec![Attribute::Token(true), Attribute::Extractable(true)]; let (_public_key, private_key) = session.generate_key_pair( &Mechanism::RsaPkcsKeyPairGen, &pub_key_template, &priv_key_template, )?; let updated_attributes = vec![Attribute::Extractable(false)]; session.update_attributes(private_key, &updated_attributes)?; let mut attributes_result = session.get_attributes(private_key, &[AttributeType::Extractable])?; if let Some(Attribute::Extractable(ext)) = attributes_result.pop() { assert!(!ext); } else { panic!("Last attribute was not extractable"); } Ok(()) } #[test] #[serial] fn sha256_digest() -> TestResult { let (pkcs11, slot) = init_pins(); // open a session let session = pkcs11.open_rw_session(slot)?; // log in the session session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; // data to digest let data = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]; 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, ]; let have = session.digest(&Mechanism::Sha256, &data)?; assert_eq!(want[..], have[..]); Ok(()) } #[test] #[serial] // Currently empty AAD crashes SoftHSM, see: https://github.com/opendnssec/SoftHSMv2/issues/605 #[ignore] fn aes_gcm_no_aad() -> TestResult { // Encrypt two blocks of zeros with AES-128-GCM let key = vec![0; 16]; let iv = [0; 12]; let aad = []; let plain = [0; 32]; let expected_cipher_and_tag = [ 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78, 0xf7, 0x95, 0xaa, 0xab, 0x49, 0x4b, 0x59, 0x23, 0xf7, 0xfd, 0x89, 0xff, 0x94, 0x8b, 0xc1, 0xe0, 0x40, 0x49, 0x0a, 0xf4, 0x80, 0x56, 0x06, 0xb2, 0xa3, 0xa2, 0xe7, 0x93, ]; let (pkcs11, slot) = init_pins(); let session = pkcs11.open_rw_session(slot)?; session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; let template = [ Attribute::Class(ObjectClass::SECRET_KEY), Attribute::KeyType(KeyType::AES), Attribute::Value(key), Attribute::Encrypt(true), ]; let key_handle = session.create_object(&template)?; let mechanism = Mechanism::AesGcm(GcmParams::new(&iv, &aad, 96.into())); let cipher_and_tag = session.encrypt(&mechanism, key_handle, &plain)?; assert_eq!(expected_cipher_and_tag[..], cipher_and_tag[..]); Ok(()) } #[test] #[serial] fn aes_gcm_with_aad() -> TestResult { // Encrypt a block of zeros with AES-128-GCM. // Use another block of zeros for AAD. let key = vec![0; 16]; let iv = [0; 12]; let aad = [0; 16]; let plain = [0; 16]; let expected_cipher_and_tag = [ 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78, 0xd2, 0x4e, 0x50, 0x3a, 0x1b, 0xb0, 0x37, 0x07, 0x1c, 0x71, 0xb3, 0x5d, ]; let (pkcs11, slot) = init_pins(); let session = pkcs11.open_rw_session(slot)?; session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; let template = [ Attribute::Class(ObjectClass::SECRET_KEY), Attribute::KeyType(KeyType::AES), Attribute::Value(key), Attribute::Encrypt(true), ]; let key_handle = session.create_object(&template)?; let mechanism = Mechanism::AesGcm(GcmParams::new(&iv, &aad, 96.into())); let cipher_and_tag = session.encrypt(&mechanism, key_handle, &plain)?; assert_eq!(expected_cipher_and_tag[..], cipher_and_tag[..]); 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 { // Not implemented in SoftHSMv2 // https://github.com/opendnssec/SoftHSMv2/issues/370 let (pkcs11, _slot) = init_pins(); let event = pkcs11.get_slot_event()?; assert_eq!(None, event); Ok(()) } #[test] #[serial] fn wait_for_slot_event() { // Not implemented in SoftHSMv2 // https://github.com/opendnssec/SoftHSMv2/issues/370 let (pkcs11, _slot) = init_pins(); let res = pkcs11.wait_for_slot_event(); assert!( matches!(res, Err(Error::Pkcs11(RvError::FunctionNotSupported))), "res = {:?}", res ); } cryptoki-0.6.1/tests/common.rs000064400000000000000000000023061046102023000144750ustar 00000000000000// Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 use cryptoki::context::{CInitializeArgs, Pkcs11}; use cryptoki::session::UserType; use cryptoki::slot::Slot; use cryptoki::types::AuthPin; use std::env; // The default user pin pub static USER_PIN: &str = "fedcba"; // The default SO pin pub static SO_PIN: &str = "abcdef"; pub fn get_pkcs11() -> Pkcs11 { Pkcs11::new( env::var("PKCS11_SOFTHSM2_MODULE") .unwrap_or_else(|_| "/usr/local/lib/softhsm/libsofthsm2.so".to_string()), ) .unwrap() } pub fn init_pins() -> (Pkcs11, Slot) { let pkcs11 = get_pkcs11(); // initialize the library pkcs11.initialize(CInitializeArgs::OsThreads).unwrap(); // find a slot, get the first one let slot = pkcs11.get_slots_with_token().unwrap().remove(0); let so_pin = AuthPin::new(SO_PIN.into()); pkcs11.init_token(slot, &so_pin, "Test Token").unwrap(); { // open a session let session = pkcs11.open_rw_session(slot).unwrap(); // log in the session session.login(UserType::So, Some(&so_pin)).unwrap(); session.init_pin(&AuthPin::new(USER_PIN.into())).unwrap(); } (pkcs11, slot) }