diff --git a/cryptoki/src/context/general_purpose.rs b/cryptoki/src/context/general_purpose.rs index be7ead9d..6177c3dd 100644 --- a/cryptoki/src/context/general_purpose.rs +++ b/cryptoki/src/context/general_purpose.rs @@ -145,7 +145,7 @@ pub enum Function { impl Display for Function { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Function::{:?}", self) + write!(f, "Function::{self:?}") } } diff --git a/cryptoki/src/context/mod.rs b/cryptoki/src/context/mod.rs index e320ef11..f96537c8 100644 --- a/cryptoki/src/context/mod.rs +++ b/cryptoki/src/context/mod.rs @@ -35,7 +35,6 @@ use std::fmt; use std::mem; use std::path::Path; use std::ptr; -use std::sync::Arc; use std::sync::RwLock; /// Enum for various function lists @@ -52,8 +51,8 @@ enum FunctionList { //V3_2(cryptoki_sys::CK_FUNCTION_LIST_3_2), } -// Implementation of Pkcs11 class that can be enclosed in a single Arc -pub(crate) struct Pkcs11Impl { +/// Implementation of Pkcs11 class that can be enclosed in a single Arc +pub 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, @@ -69,6 +68,55 @@ impl fmt::Debug for Pkcs11Impl { } impl Pkcs11Impl { + /// Initializes Pkcs11 using raw Pkcs11 object. + /// + /// # Safety + /// + /// `pkcs11_lib` must point to a valid Pkcs11 object. + pub unsafe fn new_unchecked(pkcs11_lib: cryptoki_sys::Pkcs11) -> Result { + /* First try the 3.0 API to get default interface. It might have some more functions than + * the 2.4 API */ + let mut interface = mem::MaybeUninit::uninit(); + if pkcs11_lib.C_GetInterface.is_ok() { + Rv::from(pkcs11_lib.C_GetInterface( + ptr::null_mut(), + ptr::null_mut(), + interface.as_mut_ptr(), + 0, + )) + .into_result(Function::GetInterface)?; + if !interface.as_ptr().is_null() { + let ifce_ptr: *mut cryptoki_sys::CK_INTERFACE = *interface.as_ptr(); + let ifce: cryptoki_sys::CK_INTERFACE = *ifce_ptr; + + let list_ptr: *mut cryptoki_sys::CK_FUNCTION_LIST = + ifce.pFunctionList as *mut cryptoki_sys::CK_FUNCTION_LIST; + let list: cryptoki_sys::CK_FUNCTION_LIST = *list_ptr; + if list.version.major >= 3 { + let list30_ptr: *mut cryptoki_sys::CK_FUNCTION_LIST_3_0 = + ifce.pFunctionList as *mut cryptoki_sys::CK_FUNCTION_LIST_3_0; + return Ok(Pkcs11Impl { + _pkcs11_lib: pkcs11_lib, + function_list: FunctionList::V3_0(*list30_ptr), + }); + } + /* fall back to the 2.* API */ + } + } + + let mut list = mem::MaybeUninit::uninit(); + + Rv::from(pkcs11_lib.C_GetFunctionList(list.as_mut_ptr())) + .into_result(Function::GetFunctionList)?; + + let list_ptr = *list.as_ptr(); + + Ok(Pkcs11Impl { + _pkcs11_lib: pkcs11_lib, + function_list: FunctionList::V2(v2tov3(*list_ptr)), + }) + } + #[inline(always)] pub(crate) fn get_function_list(&self) -> cryptoki_sys::CK_FUNCTION_LIST_3_0 { match self.function_list { @@ -76,12 +124,22 @@ impl Pkcs11Impl { FunctionList::V3_0(l) => l, } } +} + +/// Main PKCS11 context. Should usually be unique per application. +#[derive(Debug)] +pub struct Pkcs11 { + pub(crate) impl_: Pkcs11Impl, + initialized: RwLock, +} +impl Pkcs11 { // Private finalize call #[inline(always)] - fn finalize(&self) -> Result<()> { + fn finalize_ref(&self) -> Result<()> { unsafe { Rv::from(self + .impl_ .get_function_list() .C_Finalize .ok_or(Error::NullFunctionPointer)?( @@ -92,21 +150,14 @@ impl Pkcs11Impl { } } -impl Drop for Pkcs11Impl { +impl Drop for Pkcs11 { fn drop(&mut self) { - if let Err(e) = self.finalize() { + if let Err(e) = self.finalize_ref() { 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 @@ -116,7 +167,10 @@ impl Pkcs11 { unsafe { let pkcs11_lib = cryptoki_sys::Pkcs11::new(filename.as_ref()).map_err(Error::LibraryLoading)?; - Self::_new(pkcs11_lib) + Ok(Self { + impl_: Pkcs11Impl::new_unchecked(pkcs11_lib)?, + initialized: RwLock::new(false), + }) } } @@ -128,67 +182,16 @@ impl Pkcs11 { #[cfg(windows)] let this_lib = libloading::os::windows::Library::this()?; let pkcs11_lib = cryptoki_sys::Pkcs11::from_library(this_lib)?; - Self::_new(pkcs11_lib) - } - } - - unsafe fn _new(pkcs11_lib: cryptoki_sys::Pkcs11) -> Result { - /* First try the 3.0 API to get default interface. It might have some more functions than - * the 2.4 API */ - let mut interface = mem::MaybeUninit::uninit(); - if pkcs11_lib.C_GetInterface.is_ok() { - Rv::from(pkcs11_lib.C_GetInterface( - ptr::null_mut(), - ptr::null_mut(), - interface.as_mut_ptr(), - 0, - )) - .into_result(Function::GetInterface)?; - if !interface.as_ptr().is_null() { - let ifce_ptr: *mut cryptoki_sys::CK_INTERFACE = *interface.as_ptr(); - let ifce: cryptoki_sys::CK_INTERFACE = *ifce_ptr; - - let list_ptr: *mut cryptoki_sys::CK_FUNCTION_LIST = - ifce.pFunctionList as *mut cryptoki_sys::CK_FUNCTION_LIST; - let list: cryptoki_sys::CK_FUNCTION_LIST = *list_ptr; - if list.version.major >= 3 { - let list30_ptr: *mut cryptoki_sys::CK_FUNCTION_LIST_3_0 = - ifce.pFunctionList as *mut cryptoki_sys::CK_FUNCTION_LIST_3_0; - return Ok(Pkcs11 { - impl_: Arc::new(Pkcs11Impl { - _pkcs11_lib: pkcs11_lib, - function_list: FunctionList::V3_0(*list30_ptr), - }), - initialized: Arc::new(RwLock::new(false)), - }); - } - /* fall back to the 2.* API */ - } + Ok(Self { + impl_: Pkcs11Impl::new_unchecked(pkcs11_lib)?, + initialized: RwLock::new(false), + }) } - - let mut list = mem::MaybeUninit::uninit(); - - Rv::from(pkcs11_lib.C_GetFunctionList(list.as_mut_ptr())) - .into_result(Function::GetFunctionList)?; - - let list_ptr = *list.as_ptr(); - - Ok(Pkcs11 { - impl_: Arc::new(Pkcs11Impl { - _pkcs11_lib: pkcs11_lib, - function_list: FunctionList::V2(v2tov3(*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"); + let mut init_lock = self.initialized.write().expect("lock not to be poisoned"); if *init_lock { Err(Error::AlreadyInitialized)? } @@ -197,11 +200,7 @@ impl Pkcs11 { /// 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") + *self.initialized.read().expect("lock not to be poisoned") } /// Finalize the PKCS11 library. Indicates that the application no longer needs to use PKCS11. diff --git a/cryptoki/src/context/session_management.rs b/cryptoki/src/context/session_management.rs index 382c45da..3edc85e1 100644 --- a/cryptoki/src/context/session_management.rs +++ b/cryptoki/src/context/session_management.rs @@ -13,7 +13,7 @@ use super::Function; impl Pkcs11 { #[inline(always)] - fn open_session(&self, slot_id: Slot, read_write: bool) -> Result { + fn open_session(&self, slot_id: Slot, read_write: bool) -> Result> { let mut session_handle = 0; let flags = if read_write { @@ -33,7 +33,7 @@ impl Pkcs11 { .into_result(Function::OpenSession)?; } - Ok(Session::new(session_handle, self.clone())) + Ok(Session::new(session_handle, self)) } /// Open a new Read-Only session @@ -60,14 +60,14 @@ impl Pkcs11 { /// let session = client.open_ro_session(slot)?; /// # let _ = session; Ok(()) } /// ``` - pub fn open_ro_session(&self, slot_id: Slot) -> Result { + 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 { + pub fn open_rw_session(&self, slot_id: Slot) -> Result> { self.open_session(slot_id, true) } } diff --git a/cryptoki/src/session/decryption.rs b/cryptoki/src/session/decryption.rs index 6d4358df..45361501 100644 --- a/cryptoki/src/session/decryption.rs +++ b/cryptoki/src/session/decryption.rs @@ -10,7 +10,7 @@ use crate::session::Session; use cryptoki_sys::*; use std::convert::TryInto; -impl Session { +impl Session<'_> { /// Single-part decryption operation pub fn decrypt( &self, diff --git a/cryptoki/src/session/digesting.rs b/cryptoki/src/session/digesting.rs index fc0974d5..ea977cee 100644 --- a/cryptoki/src/session/digesting.rs +++ b/cryptoki/src/session/digesting.rs @@ -10,7 +10,7 @@ use crate::session::Session; use cryptoki_sys::*; use std::convert::TryInto; -impl Session { +impl Session<'_> { /// Single-part digesting operation pub fn digest(&self, m: &Mechanism, data: &[u8]) -> Result> { let mut mechanism: CK_MECHANISM = m.into(); diff --git a/cryptoki/src/session/encryption.rs b/cryptoki/src/session/encryption.rs index e47cfefd..aa5042e8 100644 --- a/cryptoki/src/session/encryption.rs +++ b/cryptoki/src/session/encryption.rs @@ -10,7 +10,7 @@ use crate::session::Session; use cryptoki_sys::*; use std::convert::TryInto; -impl Session { +impl Session<'_> { /// Single-part encryption operation pub fn encrypt( &self, diff --git a/cryptoki/src/session/key_management.rs b/cryptoki/src/session/key_management.rs index 0d5dfd13..689076b4 100644 --- a/cryptoki/src/session/key_management.rs +++ b/cryptoki/src/session/key_management.rs @@ -10,7 +10,7 @@ use crate::session::Session; use cryptoki_sys::{CK_ATTRIBUTE, CK_MECHANISM, CK_MECHANISM_PTR}; use std::convert::TryInto; -impl Session { +impl Session<'_> { /// Generate a secret key pub fn generate_key( &self, diff --git a/cryptoki/src/session/message_decryption.rs b/cryptoki/src/session/message_decryption.rs index 1d9bae8b..c55056fd 100644 --- a/cryptoki/src/session/message_decryption.rs +++ b/cryptoki/src/session/message_decryption.rs @@ -10,7 +10,7 @@ use crate::session::Session; use cryptoki_sys::*; use std::convert::TryInto; -impl Session { +impl Session<'_> { /// Prepare a session for one or more Message-based decryption using the same mechanism and key pub fn message_decrypt_init(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { let mut mechanism: CK_MECHANISM = mechanism.into(); diff --git a/cryptoki/src/session/message_encryption.rs b/cryptoki/src/session/message_encryption.rs index 5288339a..8143b4c4 100644 --- a/cryptoki/src/session/message_encryption.rs +++ b/cryptoki/src/session/message_encryption.rs @@ -10,7 +10,7 @@ use crate::session::Session; use cryptoki_sys::*; use std::convert::TryInto; -impl Session { +impl Session<'_> { /// Prepare a session for one or more Message-based encryption using the same mechanism and key pub fn message_encrypt_init(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { let mut mechanism: CK_MECHANISM = mechanism.into(); diff --git a/cryptoki/src/session/mod.rs b/cryptoki/src/session/mod.rs index bf05fde2..13627f80 100644 --- a/cryptoki/src/session/mod.rs +++ b/cryptoki/src/session/mod.rs @@ -31,37 +31,33 @@ pub use session_info::{SessionInfo, SessionState}; /// 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 { +pub struct Session<'a> { handle: CK_SESSION_HANDLE, - client: Pkcs11, + client: &'a 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 { +impl<'a> std::fmt::Display for Session<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.handle) } } -impl std::fmt::LowerHex for Session { +impl<'a> std::fmt::LowerHex for Session<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{:08x}", self.handle) } } -impl std::fmt::UpperHex for Session { +impl<'a> std::fmt::UpperHex for Session<'a> { 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 { +impl<'a> Session<'a> { + pub(crate) fn new(handle: CK_SESSION_HANDLE, client: &'a Pkcs11) -> Self { Session { handle, client, @@ -70,7 +66,7 @@ impl Session { } } -impl Session { +impl<'a> Session<'a> { /// Close a session /// This will be called on drop as well. pub fn close(self) {} @@ -80,7 +76,7 @@ impl Session { } pub(crate) fn client(&self) -> &Pkcs11 { - &self.client + self.client } } diff --git a/cryptoki/src/session/object_management.rs b/cryptoki/src/session/object_management.rs index 3cec80d3..7e7008c1 100644 --- a/cryptoki/src/session/object_management.rs +++ b/cryptoki/src/session/object_management.rs @@ -78,7 +78,7 @@ const MAX_OBJECT_COUNT: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(10) /// ``` #[derive(Debug)] pub struct ObjectHandleIterator<'a> { - session: &'a Session, + session: &'a Session<'a>, object_count: usize, index: usize, cache: Vec, @@ -207,7 +207,7 @@ impl Drop for ObjectHandleIterator<'_> { } } -impl Session { +impl Session<'_> { /// Iterate over session objects matching a template. /// /// # Arguments @@ -224,7 +224,7 @@ impl Session { /// * [`ObjectHandleIterator`] for more information on how to use the iterator /// * [`Session::iter_objects_with_cache_size`] for a way to specify the cache size #[inline(always)] - pub fn iter_objects(&self, template: &[Attribute]) -> Result { + pub fn iter_objects(&self, template: &[Attribute]) -> Result> { self.iter_objects_with_cache_size(template, MAX_OBJECT_COUNT) } @@ -248,7 +248,7 @@ impl Session { &self, template: &[Attribute], cache_size: NonZeroUsize, - ) -> Result { + ) -> Result> { let template: Vec = template.iter().map(Into::into).collect(); ObjectHandleIterator::new(self, template, cache_size) } diff --git a/cryptoki/src/session/random.rs b/cryptoki/src/session/random.rs index 4926933b..2269fcbb 100644 --- a/cryptoki/src/session/random.rs +++ b/cryptoki/src/session/random.rs @@ -7,7 +7,7 @@ use crate::error::{Result, Rv}; use crate::session::Session; use std::convert::TryInto; -impl Session { +impl Session<'_> { /// Generates a random number and sticks it in a slice /// /// # Arguments diff --git a/cryptoki/src/session/session_management.rs b/cryptoki/src/session/session_management.rs index c5f22b03..ce498217 100644 --- a/cryptoki/src/session/session_management.rs +++ b/cryptoki/src/session/session_management.rs @@ -14,7 +14,7 @@ use log::error; use secrecy::ExposeSecret; use std::convert::{TryFrom, TryInto}; -impl Drop for Session { +impl Drop for Session<'_> { fn drop(&mut self) { #[inline(always)] fn close(session: &Session) -> Result<()> { @@ -32,7 +32,7 @@ impl Drop for Session { } } -impl Session { +impl Session<'_> { /// Log a session in. /// /// # Arguments diff --git a/cryptoki/src/session/signing_macing.rs b/cryptoki/src/session/signing_macing.rs index 9deed03d..6f112e25 100644 --- a/cryptoki/src/session/signing_macing.rs +++ b/cryptoki/src/session/signing_macing.rs @@ -10,7 +10,7 @@ use crate::session::Session; use cryptoki_sys::*; use std::convert::TryInto; -impl Session { +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(); diff --git a/cryptoki/src/session/slot_token_management.rs b/cryptoki/src/session/slot_token_management.rs index 4dde294b..4983fac1 100644 --- a/cryptoki/src/session/slot_token_management.rs +++ b/cryptoki/src/session/slot_token_management.rs @@ -9,7 +9,7 @@ use crate::types::AuthPin; use secrecy::ExposeSecret; use std::convert::TryInto; -impl Session { +impl Session<'_> { /// Initialize the normal user's pin for a token pub fn init_pin(&self, pin: &AuthPin) -> Result<()> { unsafe { diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 6f54db3b..7ecd713c 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -22,6 +22,7 @@ use cryptoki::types::AuthPin; use serial_test::serial; use std::collections::HashMap; use std::num::NonZeroUsize; +use std::sync::Arc; use std::thread; use cryptoki::mechanism::ekdf::AesCbcDeriveParams; @@ -992,6 +993,7 @@ fn login_feast() { const SESSIONS: usize = 100; let (pkcs11, slot) = init_pins(); + let pkcs11 = Arc::new(pkcs11); let mut threads = Vec::new(); for _ in 0..SESSIONS { @@ -1197,7 +1199,7 @@ fn get_attribute_info_test() -> TestResult { session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; let pub_attribs = vec![AttributeType::PublicExponent, AttributeType::Modulus]; - let mut priv_attribs = [ + let priv_attribs = [ AttributeType::PublicExponent, AttributeType::Modulus, AttributeType::PrivateExponent, @@ -1328,7 +1330,7 @@ fn is_initialized_test() { fn test_clone_initialize() { use cryptoki::context::CInitializeArgs; - let pkcs11 = get_pkcs11(); + let pkcs11 = Arc::new(get_pkcs11()); let clone = pkcs11.clone(); assert!(