Skip to content

Allow working with a non-finalizing Pkcs11 #290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cryptoki/src/context/general_purpose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:?}")
}
}

Expand Down
149 changes: 74 additions & 75 deletions cryptoki/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -69,19 +68,78 @@ 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<Self> {
/* 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 {
FunctionList::V2(l) => l,
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<bool>,
}

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)?(
Expand All @@ -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<Pkcs11Impl>,
initialized: Arc<RwLock<bool>>,
}

impl Pkcs11 {
/// Instantiate a new context from the path of a PKCS11 dynamic library implementation.
pub fn new<P>(filename: P) -> Result<Self>
Expand All @@ -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),
})
}
}

Expand All @@ -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<Self> {
/* 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)?
}
Expand All @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions cryptoki/src/context/session_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use super::Function;

impl Pkcs11 {
#[inline(always)]
fn open_session(&self, slot_id: Slot, read_write: bool) -> Result<Session> {
fn open_session(&self, slot_id: Slot, read_write: bool) -> Result<Session<'_>> {
let mut session_handle = 0;

let flags = if read_write {
Expand All @@ -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
Expand All @@ -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<Session> {
pub fn open_ro_session(&self, slot_id: Slot) -> Result<Session<'_>> {
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<Session> {
pub fn open_rw_session(&self, slot_id: Slot) -> Result<Session<'_>> {
self.open_session(slot_id, true)
}
}
2 changes: 1 addition & 1 deletion cryptoki/src/session/decryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion cryptoki/src/session/digesting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<u8>> {
let mut mechanism: CK_MECHANISM = m.into();
Expand Down
2 changes: 1 addition & 1 deletion cryptoki/src/session/encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion cryptoki/src/session/key_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion cryptoki/src/session/message_decryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion cryptoki/src/session/message_encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
22 changes: 9 additions & 13 deletions cryptoki/src/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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) {}
Expand All @@ -80,7 +76,7 @@ impl Session {
}

pub(crate) fn client(&self) -> &Pkcs11 {
&self.client
self.client
}
}

Expand Down
Loading
Loading