diff --git a/cryptoki/Cargo.toml b/cryptoki/Cargo.toml index e572dd81..74ed658a 100644 --- a/cryptoki/Cargo.toml +++ b/cryptoki/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cryptoki" -version = "0.2.0" +version = "0.3.0" authors = ["Contributors to the Parsec project"] edition = '2018' description = "Rust-native wrapper around the PKCS #11 API" diff --git a/cryptoki/src/context/flags.rs b/cryptoki/src/context/flags.rs new file mode 100644 index 00000000..e1ed47a8 --- /dev/null +++ b/cryptoki/src/context/flags.rs @@ -0,0 +1,99 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! PKCS11 flags for use with CInitializeArgs + +use crate::error::{Error, Result}; +use crate::types::Flags; +use cryptoki_sys::*; +use std::convert::TryFrom; +use std::fmt::Formatter; + +#[derive(Debug, Default, Clone, Copy)] +/// Collection of flags defined for [`CK_C_INITIALIZE_ARGS`] +pub struct InitializeFlags { + flags: CK_FLAGS, +} + +impl Flags for InitializeFlags { + type FlagType = CK_FLAGS; + + fn flag_value(&self) -> Self::FlagType { + self.flags + } + + fn flag(&self, flag: Self::FlagType) -> bool { + self.flag_value() & flag == flag + } + + fn set_flag(&mut self, flag: Self::FlagType, b: bool) { + if b { + self.flags |= flag; + } else { + self.flags &= !flag; + } + } + + fn stringify_flag(flag: CK_FLAGS) -> &'static str { + match flag { + CKF_LIBRARY_CANT_CREATE_OS_THREADS => { + std::stringify!(CKF_LIBRARY_CANT_CREATE_OS_THREADS) + } + CKF_OS_LOCKING_OK => std::stringify!(CKF_OS_LOCKING_OK), + _ => "Unknown CK_C_INITIALIZE_ARGS flag", + } + } +} + +impl InitializeFlags { + /// Creates a new instance of `InitializeFlags` with no flags set + pub fn new() -> Self { + InitializeFlags::default() + } + + /// Gets value of [`CKF_LIBRARY_CANT_CREATE_OS_THREADS`] + pub fn library_cant_create_os_threads(&self) -> bool { + self.flag(CKF_LIBRARY_CANT_CREATE_OS_THREADS) + } + + /// Sets value of [`CKF_LIBRARY_CANT_CREATE_OS_THREADS`] + pub fn set_library_cant_create_os_threads(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_LIBRARY_CANT_CREATE_OS_THREADS, b); + self + } + + /// Gets value of [`CKF_OS_LOCKING_OK`] + pub fn os_locking_ok(&self) -> bool { + self.flag(CKF_OS_LOCKING_OK) + } + + /// Sets value of [`CKF_OS_LOCKING_OK`] + pub fn set_os_locking_ok(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_OS_LOCKING_OK, b); + self + } +} + +impl std::fmt::Display for InitializeFlags { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let flags = vec![CKF_LIBRARY_CANT_CREATE_OS_THREADS, CKF_OS_LOCKING_OK]; + self.stringify_fmt(f, flags) + } +} + +impl From for CK_FLAGS { + fn from(flags: InitializeFlags) -> Self { + flags.flags + } +} + +impl TryFrom for InitializeFlags { + type Error = Error; + + fn try_from(flags: CK_FLAGS) -> Result { + if flags & !(CKF_OS_LOCKING_OK | CKF_LIBRARY_CANT_CREATE_OS_THREADS) != 0 { + Err(Error::InvalidValue) + } else { + Ok(Self { flags }) + } + } +} diff --git a/cryptoki/src/context/general_purpose.rs b/cryptoki/src/context/general_purpose.rs new file mode 100644 index 00000000..8dca50c1 --- /dev/null +++ b/cryptoki/src/context/general_purpose.rs @@ -0,0 +1,39 @@ +// 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 std::ptr; + +// 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() + } +} + +#[inline(always)] +pub(super) fn finalize_private(ctx: &Pkcs11) -> Result<()> { + // Safe because Session contain a reference to self so that this function can not be called + // while there are live Session instances. + unsafe { Rv::from(get_pkcs11!(ctx, C_Finalize)(ptr::null_mut())).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()?; + Ok(Info::new(info)) + } +} diff --git a/cryptoki/src/context/info.rs b/cryptoki/src/context/info.rs new file mode 100644 index 00000000..e2fed6ba --- /dev/null +++ b/cryptoki/src/context/info.rs @@ -0,0 +1,59 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! PKCS11 library information + +use crate::string_from_blank_padded; +use crate::types::Version; +use cryptoki_sys::*; +use std::ops::Deref; + +#[derive(Debug, Clone, Copy)] +/// Type identifying the PKCS#11 library information +pub struct Info { + val: CK_INFO, +} + +impl Info { + pub(crate) fn new(val: CK_INFO) -> Self { + Self { val } + } + + /// Returns the version of Cryptoki that the library is compatible with + pub fn cryptoki_version(&self) -> Version { + self.val.cryptokiVersion.into() + } + + /// Returns the flags of the library (should be zero!) + pub fn flags(&self) -> CK_FLAGS { + self.val.flags + } + + /// Returns the description of the library + pub fn library_description(&self) -> String { + string_from_blank_padded(&self.val.libraryDescription) + } + + /// Returns the version of the library + pub fn library_version(&self) -> Version { + self.val.libraryVersion.into() + } + + /// Returns the manufacturer of the library + pub fn manufacturer_id(&self) -> String { + string_from_blank_padded(&self.val.manufacturerID) + } +} + +impl Deref for Info { + type Target = CK_INFO; + + fn deref(&self) -> &Self::Target { + &self.val + } +} + +impl From for CK_INFO { + fn from(info: Info) -> Self { + *info + } +} diff --git a/cryptoki/src/types/locking.rs b/cryptoki/src/context/locking.rs similarity index 96% rename from cryptoki/src/types/locking.rs rename to cryptoki/src/context/locking.rs index f17f515b..2c0093ad 100644 --- a/cryptoki/src/types/locking.rs +++ b/cryptoki/src/context/locking.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 //! Locking related type -use crate::types::InitializeFlags; +use super::InitializeFlags; use std::ptr; /// Argument for the initialize function diff --git a/cryptoki/src/context/mod.rs b/cryptoki/src/context/mod.rs new file mode 100644 index 00000000..b54398e3 --- /dev/null +++ b/cryptoki/src/context/mod.rs @@ -0,0 +1,137 @@ +// 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 + .function_list + .$func_name + .ok_or(crate::error::Error::NullFunctionPointer)?) + }; +} + +mod flags; +mod general_purpose; +mod info; +mod locking; +mod session_management; +mod slot_token_management; + +pub use flags::*; +pub use info::*; +pub use locking::*; + +use crate::error::{Error, Result, Rv}; +use crate::mechanism::{MechanismInfo, MechanismType}; +use crate::session::{Session, SessionFlags}; +use crate::slot::{Slot, SlotInfo, TokenInfo}; + +use derivative::Derivative; +use log::error; +use std::mem; +use std::path::Path; + +/// Main PKCS11 context. Should usually be unique per application. +#[derive(Derivative)] +#[derivative(Debug)] +pub struct Pkcs11 { + // Even if this field is never read, it is needed for the pointers in function_list to remain + // valid. + #[derivative(Debug = "ignore")] + _pkcs11_lib: cryptoki_sys::Pkcs11, + pub(crate) function_list: cryptoki_sys::_CK_FUNCTION_LIST, +} + +impl Pkcs11 { + /// Instantiate a new context from the path of a PKCS11 dynamic llibrary 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 { + _pkcs11_lib: pkcs11_lib, + function_list: *list_ptr, + }) + } + } + + /// Initialize the PKCS11 library + pub fn initialize(&self, init_args: CInitializeArgs) -> Result<()> { + general_purpose::initialize(self, init_args) + } + + /// 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 { + general_purpose::get_library_info(self) + } + + /// Get all slots available with a token + pub fn get_slots_with_token(&self) -> Result> { + slot_token_management::get_slots_with_token(self) + } + + /// Get all slots available with a token + pub fn get_slots_with_initialized_token(&self) -> Result> { + slot_token_management::get_slots_with_initialized_token(self) + } + + /// Get all slots + pub fn get_all_slots(&self) -> Result> { + slot_token_management::get_all_slots(self) + } + + /// Initialize a token + /// + /// Currently will use an empty label for all tokens. + pub fn init_token(&self, slot: Slot, pin: &str, label: &str) -> Result<()> { + slot_token_management::init_token(self, slot, pin, label) + } + + /// Returns the slot info + pub fn get_slot_info(&self, slot: Slot) -> Result { + slot_token_management::get_slot_info(self, slot) + } + + /// Returns information about a specific token + pub fn get_token_info(&self, slot: Slot) -> Result { + slot_token_management::get_token_info(self, slot) + } + + /// Get all mechanisms support by a slot + pub fn get_mechanism_list(&self, slot: Slot) -> Result> { + slot_token_management::get_mechanism_list(self, slot) + } + + /// Get detailed information about a mechanism for a slot + pub fn get_mechanism_info(&self, slot: Slot, type_: MechanismType) -> Result { + slot_token_management::get_mechanism_info(self, slot, type_) + } + + /// Open a new session with no callback set + pub fn open_session_no_callback(&self, slot_id: Slot, flags: SessionFlags) -> Result { + session_management::open_session_no_callback(self, slot_id, flags) + } +} + +impl Drop for Pkcs11 { + fn drop(&mut self) { + if let Err(e) = general_purpose::finalize_private(self) { + error!("Failed to finalize: {}", e); + } + } +} diff --git a/cryptoki/src/context/session_management.rs b/cryptoki/src/context/session_management.rs new file mode 100644 index 00000000..7d6644d4 --- /dev/null +++ b/cryptoki/src/context/session_management.rs @@ -0,0 +1,33 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! Session management functions + +use crate::context::Pkcs11; +use crate::error::{Result, Rv}; +use crate::session::{Session, SessionFlags}; +use crate::slot::Slot; +use std::convert::TryInto; + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn open_session_no_callback( + ctx: &Pkcs11, + slot_id: Slot, + flags: SessionFlags, +) -> Result { + let mut session_handle = 0; + + unsafe { + Rv::from(get_pkcs11!(ctx, C_OpenSession)( + slot_id.try_into()?, + flags.into(), + // 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, ctx)) +} diff --git a/cryptoki/src/context/slot_token_management.rs b/cryptoki/src/context/slot_token_management.rs new file mode 100644 index 00000000..7257b0cf --- /dev/null +++ b/cryptoki/src/context/slot_token_management.rs @@ -0,0 +1,193 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! Slot and token management functions + +use crate::context::Pkcs11; +use crate::error::{Result, Rv}; +use crate::label_from_str; +use crate::mechanism::{MechanismInfo, MechanismType}; +use crate::slot::{Slot, SlotInfo, TokenInfo}; +use cryptoki_sys::{CK_MECHANISM_INFO, CK_SLOT_INFO, CK_TOKEN_INFO}; +use std::convert::TryInto; + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn get_slots_with_token(ctx: &Pkcs11) -> Result> { + let mut slot_count = 0; + + unsafe { + Rv::from(get_pkcs11!(ctx, C_GetSlotList)( + cryptoki_sys::CK_TRUE, + std::ptr::null_mut(), + &mut slot_count, + )) + .into_result()?; + } + + let mut slots = vec![0; slot_count.try_into()?]; + + unsafe { + Rv::from(get_pkcs11!(ctx, C_GetSlotList)( + cryptoki_sys::CK_TRUE, + slots.as_mut_ptr(), + &mut slot_count, + )) + .into_result()?; + } + + let mut slots: Vec = slots.into_iter().map(Slot::new).collect(); + + // This should always truncate slots. + slots.resize(slot_count.try_into()?, Slot::new(0)); + + Ok(slots) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn get_slots_with_initialized_token(ctx: &Pkcs11) -> Result> { + let slots = ctx.get_slots_with_token()?; + + slots + .into_iter() + .filter_map(|slot| match ctx.get_token_info(slot) { + Ok(token_info) => { + if token_info.flags().token_initialized() { + Some(Ok(slot)) + } else { + None + } + } + Err(e) => Some(Err(e)), + }) + .collect() +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn get_all_slots(ctx: &Pkcs11) -> Result> { + let mut slot_count = 0; + + unsafe { + Rv::from(get_pkcs11!(ctx, C_GetSlotList)( + cryptoki_sys::CK_FALSE, + std::ptr::null_mut(), + &mut slot_count, + )) + .into_result()?; + } + + let mut slots = vec![0; slot_count.try_into()?]; + + unsafe { + Rv::from(get_pkcs11!(ctx, C_GetSlotList)( + cryptoki_sys::CK_FALSE, + slots.as_mut_ptr(), + &mut slot_count, + )) + .into_result()?; + } + + let mut slots: Vec = slots.into_iter().map(Slot::new).collect(); + + // This should always truncate slots. + slots.resize(slot_count.try_into()?, Slot::new(0)); + + Ok(slots) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn init_token(ctx: &Pkcs11, slot: Slot, pin: &str, label: &str) -> Result<()> { + let label = label_from_str(label); + unsafe { + Rv::from(get_pkcs11!(ctx, C_InitToken)( + slot.try_into()?, + pin.as_ptr() as *mut u8, + pin.len().try_into()?, + label.as_ptr() as *mut u8, + )) + .into_result() + } +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn get_slot_info(ctx: &Pkcs11, slot: Slot) -> Result { + unsafe { + let mut slot_info = CK_SLOT_INFO::default(); + Rv::from(get_pkcs11!(ctx, C_GetSlotInfo)( + slot.try_into()?, + &mut slot_info, + )) + .into_result()?; + Ok(SlotInfo::new(slot_info)) + } +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn get_token_info(ctx: &Pkcs11, slot: Slot) -> Result { + unsafe { + let mut token_info = CK_TOKEN_INFO::default(); + Rv::from(get_pkcs11!(ctx, C_GetTokenInfo)( + slot.try_into()?, + &mut token_info, + )) + .into_result()?; + Ok(TokenInfo::new(token_info)) + } +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn get_mechanism_list(ctx: &Pkcs11, slot: Slot) -> Result> { + let mut mechanism_count = 0; + + unsafe { + Rv::from(get_pkcs11!(ctx, 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!(ctx, 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()) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn get_mechanism_info( + ctx: &Pkcs11, + slot: Slot, + type_: MechanismType, +) -> Result { + unsafe { + let mut mechanism_info = CK_MECHANISM_INFO::default(); + Rv::from(get_pkcs11!(ctx, C_GetMechanismInfo)( + slot.try_into()?, + type_.into(), + &mut mechanism_info, + )) + .into_result()?; + Ok(MechanismInfo::new(mechanism_info)) + } +} diff --git a/cryptoki/src/error/mod.rs b/cryptoki/src/error/mod.rs new file mode 100644 index 00000000..a5f484d6 --- /dev/null +++ b/cryptoki/src/error/mod.rs @@ -0,0 +1,114 @@ +// 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 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, +} + +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::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"), + } + } +} + +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::NulError(e) => Some(e), + Error::Pkcs11(_) + | Error::NotSupported + | Error::NullFunctionPointer + | Error::PinNotSet + | Error::InvalidValue => 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: 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; diff --git a/cryptoki/src/error/rv.rs b/cryptoki/src/error/rv.rs new file mode 100644 index 00000000..660e1d30 --- /dev/null +++ b/cryptoki/src/error/rv.rs @@ -0,0 +1,137 @@ +// 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)), + } + } +} diff --git a/cryptoki/src/types/function.rs b/cryptoki/src/error/rv_error.rs similarity index 85% rename from cryptoki/src/types/function.rs rename to cryptoki/src/error/rv_error.rs index b16a3ba5..20022c71 100644 --- a/cryptoki/src/types/function.rs +++ b/cryptoki/src/error/rv_error.rs @@ -2,131 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 //! Function types -use crate::{Error, Result}; -use cryptoki_sys::*; -use log::error; use std::fmt; -#[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) - } - } - } -} - #[derive(Debug, Copy, Clone, PartialEq)] /// Description of a return value error pub enum RvError { @@ -420,19 +297,3 @@ impl fmt::Display for RvError { } } } - -impl From for Error { - fn from(rv_error: RvError) -> Self { - Error::Pkcs11(rv_error) - } -} - -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)), - } - } -} diff --git a/cryptoki/src/functions/decryption.rs b/cryptoki/src/functions/decryption.rs deleted file mode 100644 index d9fa2c2f..00000000 --- a/cryptoki/src/functions/decryption.rs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! Decrypting data - -use crate::get_pkcs11; -use crate::types::function::Rv; -use crate::types::mechanism::Mechanism; -use crate::types::object::ObjectHandle; -use crate::types::session::Session; -use crate::Result; -use cryptoki_sys::*; -use std::convert::TryInto; - -impl<'a> Session<'a> { - /// 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) - } -} diff --git a/cryptoki/src/functions/encryption.rs b/cryptoki/src/functions/encryption.rs deleted file mode 100644 index 71ce0bbf..00000000 --- a/cryptoki/src/functions/encryption.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! Encrypting data - -use crate::get_pkcs11; -use crate::types::function::Rv; -use crate::types::mechanism::Mechanism; -use crate::types::object::ObjectHandle; -use crate::types::session::Session; -use crate::Result; -use cryptoki_sys::*; -use std::convert::TryInto; - -impl<'a> Session<'a> { - /// 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) - } -} diff --git a/cryptoki/src/functions/general_purpose.rs b/cryptoki/src/functions/general_purpose.rs deleted file mode 100644 index b3f5b9d1..00000000 --- a/cryptoki/src/functions/general_purpose.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! General-purpose functions - -use crate::get_pkcs11; -use crate::types::function::Rv; -use crate::types::locking::CInitializeArgs; -use crate::types::Info; -use crate::Pkcs11; -use crate::Result; -use cryptoki_sys::{CK_C_INITIALIZE_ARGS, CK_INFO}; -use std::ptr; - -impl Pkcs11 { - /// Initialize the PKCS11 library - pub fn initialize(&self, 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!(self, C_Initialize)( - init_args_ptr as *mut CK_C_INITIALIZE_ARGS as *mut ::std::ffi::c_void, - )) - .into_result() - } - } - - pub(crate) fn finalize_private(&self) -> Result<()> { - // Safe because Session contain a reference to self so that this function can not be called - // while there are live Session instances. - unsafe { Rv::from(get_pkcs11!(self, C_Finalize)(ptr::null_mut())).into_result() } - } - - /// 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 { - let mut info = CK_INFO::default(); - unsafe { - Rv::from(get_pkcs11!(self, C_GetInfo)(&mut info)).into_result()?; - Ok(Info::new(info)) - } - } -} diff --git a/cryptoki/src/functions/key_management.rs b/cryptoki/src/functions/key_management.rs deleted file mode 100644 index 38febaf0..00000000 --- a/cryptoki/src/functions/key_management.rs +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! Key management functions - -use crate::get_pkcs11; -use crate::types::function::Rv; -use crate::types::mechanism::Mechanism; -use crate::types::object::{Attribute, ObjectHandle}; -use crate::types::session::Session; -use crate::Result; -use cryptoki_sys::{CK_ATTRIBUTE, CK_MECHANISM, CK_MECHANISM_PTR}; -use std::convert::TryInto; - -impl<'a> Session<'a> { - /// 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)) - } -} diff --git a/cryptoki/src/functions/mod.rs b/cryptoki/src/functions/mod.rs deleted file mode 100644 index 2e7fb287..00000000 --- a/cryptoki/src/functions/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! PKCS11 functions - -pub mod decryption; -pub mod encryption; -pub mod general_purpose; -pub mod key_management; -pub mod object_management; -pub mod random; -pub mod session_management; -pub mod signing_macing; -pub mod slot_token_management; diff --git a/cryptoki/src/functions/object_management.rs b/cryptoki/src/functions/object_management.rs deleted file mode 100644 index a8c5a7b3..00000000 --- a/cryptoki/src/functions/object_management.rs +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! Object management functions - -use crate::get_pkcs11; -use crate::types::function::{Rv, RvError}; -use crate::types::object::{Attribute, AttributeInfo, AttributeType, ObjectHandle}; -use crate::types::session::Session; -use crate::Result; -use cryptoki_sys::*; -use std::collections::HashMap; -use std::convert::TryInto; - -// Search 10 elements at a time -const MAX_OBJECT_COUNT: usize = 10; - -impl<'a> Session<'a> { - /// 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: - /// - /// ```rust - /// use cryptoki::Pkcs11; - /// use cryptoki::types::locking::CInitializeArgs; - /// use cryptoki::types::object::AttributeType; - /// use cryptoki::types::session::UserType; - /// use cryptoki::types::SessionFlags; - /// use std::collections::HashMap; - /// use std::env; - /// - /// let 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 mut flags = SessionFlags::new(); - /// let _ = flags.set_rw_session(true).set_serial_session(true); - /// - /// let session = pkcs11.open_session_no_callback(slot, flags).unwrap(); - /// session.login(UserType::User, Some("fedcba")); - /// - /// 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() - } -} diff --git a/cryptoki/src/functions/random.rs b/cryptoki/src/functions/random.rs deleted file mode 100644 index 219f3f56..00000000 --- a/cryptoki/src/functions/random.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! Functions used to generate random numbers - -use crate::get_pkcs11; -use crate::types::function::Rv; -use crate::types::session::Session; -use crate::Result; -use std::convert::TryInto; - -impl<'a> Session<'a> { - /// 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() as *mut u8, - 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(()) - } -} diff --git a/cryptoki/src/functions/session_management.rs b/cryptoki/src/functions/session_management.rs deleted file mode 100644 index e29a905e..00000000 --- a/cryptoki/src/functions/session_management.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! Session management functions - -use crate::get_pkcs11; -use crate::types::function::Rv; -use crate::types::session::{Session, SessionInfo, UserType}; -use crate::types::slot_token::Slot; -use crate::types::SessionFlags; -use crate::Pkcs11; -use crate::Result; -use cryptoki_sys::CK_SESSION_INFO; -use std::convert::TryInto; - -impl Pkcs11 { - /// Open a new session with no callback set - pub fn open_session_no_callback(&self, slot_id: Slot, flags: SessionFlags) -> Result { - let mut session_handle = 0; - - unsafe { - Rv::from(get_pkcs11!(self, C_OpenSession)( - slot_id.try_into()?, - flags.into(), - // 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)) - } -} - -impl<'a> Session<'a> { - /// Close a session - /// This will be called on drop as well. - pub fn close(&self) {} - - pub(crate) fn close_private(&self) -> Result<()> { - unsafe { Rv::from(get_pkcs11!(self.client(), C_CloseSession)(self.handle())).into_result() } - } - - /// 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<&str>) -> Result<()> { - let (pin, pin_len) = match pin { - Some(pin) => (pin.as_ptr() as *mut u8, pin.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() - } - } - - /// 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()?; - Ok(SessionInfo::new(session_info)) - } - } -} diff --git a/cryptoki/src/functions/signing_macing.rs b/cryptoki/src/functions/signing_macing.rs deleted file mode 100644 index 7b59f014..00000000 --- a/cryptoki/src/functions/signing_macing.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! Signing and authentication functions - -use crate::get_pkcs11; -use crate::types::function::Rv; -use crate::types::mechanism::Mechanism; -use crate::types::object::ObjectHandle; -use crate::types::session::Session; -use crate::Result; -use cryptoki_sys::*; -use std::convert::TryInto; - -impl<'a> Session<'a> { - /// 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() - } - } -} diff --git a/cryptoki/src/functions/slot_token_management.rs b/cryptoki/src/functions/slot_token_management.rs deleted file mode 100644 index 96417119..00000000 --- a/cryptoki/src/functions/slot_token_management.rs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! Slot and token management functions - -use crate::types::function::Rv; -use crate::types::mechanism::{MechanismInfo, MechanismType}; -use crate::types::slot_token::{Slot, SlotInfo, TokenInfo}; -use crate::Pkcs11; -use crate::Result; -use crate::Session; -use crate::{get_pkcs11, label_from_str}; -use cryptoki_sys::{CK_MECHANISM_INFO, CK_SLOT_INFO, CK_TOKEN_INFO}; -use std::convert::TryInto; - -impl Pkcs11 { - /// Get all slots available with a token - pub fn get_slots_with_token(&self) -> Result> { - let mut slot_count = 0; - - unsafe { - Rv::from(get_pkcs11!(self, C_GetSlotList)( - cryptoki_sys::CK_TRUE, - std::ptr::null_mut(), - &mut slot_count, - )) - .into_result()?; - } - - let mut slots = vec![0; slot_count.try_into()?]; - - unsafe { - Rv::from(get_pkcs11!(self, C_GetSlotList)( - cryptoki_sys::CK_TRUE, - slots.as_mut_ptr(), - &mut slot_count, - )) - .into_result()?; - } - - let mut slots: Vec = slots.into_iter().map(Slot::new).collect(); - - // This should always truncate slots. - slots.resize(slot_count.try_into()?, Slot::new(0)); - - Ok(slots) - } - - /// 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.flags().token_initialized() { - Some(Ok(slot)) - } else { - None - } - } - Err(e) => Some(Err(e)), - }) - .collect() - } - - /// Get all slots - pub fn get_all_slots(&self) -> Result> { - let mut slot_count = 0; - - unsafe { - Rv::from(get_pkcs11!(self, C_GetSlotList)( - cryptoki_sys::CK_FALSE, - std::ptr::null_mut(), - &mut slot_count, - )) - .into_result()?; - } - - let mut slots = vec![0; slot_count.try_into()?]; - - unsafe { - Rv::from(get_pkcs11!(self, C_GetSlotList)( - cryptoki_sys::CK_FALSE, - slots.as_mut_ptr(), - &mut slot_count, - )) - .into_result()?; - } - - let mut slots: Vec = slots.into_iter().map(Slot::new).collect(); - - // This should always truncate slots. - slots.resize(slot_count.try_into()?, Slot::new(0)); - - Ok(slots) - } - - /// Initialize a token - /// - /// Currently will use an empty label for all tokens. - pub fn init_token(&self, slot: Slot, pin: &str, label: &str) -> Result<()> { - let label = label_from_str(label); - unsafe { - Rv::from(get_pkcs11!(self, C_InitToken)( - slot.try_into()?, - pin.as_ptr() as *mut u8, - pin.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::new(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()?; - Ok(TokenInfo::new(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::new(mechanism_info)) - } - } -} - -impl<'a> Session<'a> { - /// Initialize the normal user's pin for a token - pub fn init_pin(&self, pin: &str) -> Result<()> { - unsafe { - Rv::from(get_pkcs11!(self.client(), C_InitPIN)( - self.handle(), - pin.as_ptr() as *mut u8, - pin.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: &str, new_pin: &str) -> Result<()> { - unsafe { - Rv::from(get_pkcs11!(self.client(), C_SetPIN)( - self.handle(), - old_pin.as_ptr() as *mut u8, - old_pin.len().try_into()?, - new_pin.as_ptr() as *mut u8, - new_pin.len().try_into()?, - )) - .into_result() - } - } -} diff --git a/cryptoki/src/lib.rs b/cryptoki/src/lib.rs index 72562377..77252f14 100644 --- a/cryptoki/src/lib.rs +++ b/cryptoki/src/lib.rs @@ -37,168 +37,20 @@ unused_qualifications, unused_results)] -pub mod functions; -pub mod objects; +// 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 crate::types::function::{Rv, RvError}; -use crate::types::session::Session; use cryptoki_sys::CK_UTF8CHAR; -use derivative::Derivative; -use log::error; -use std::fmt; -use std::mem; -use std::path::Path; - -/// Directly get the PKCS #11 operation from the context structure and check for null pointers. -#[macro_export] -macro_rules! get_pkcs11 { - ($pkcs11:expr, $func_name:ident) => { - ($pkcs11 - .function_list - .$func_name - .ok_or(crate::Error::NullFunctionPointer)?) - }; -} - -/// Main PKCS11 context. Should usually be unique per application. -#[derive(Derivative)] -#[derivative(Debug)] -pub struct Pkcs11 { - // Even if this field is never read, it is needed for the pointers in function_list to remain - // valid. - #[derivative(Debug = "ignore")] - _pkcs11_lib: cryptoki_sys::Pkcs11, - function_list: cryptoki_sys::_CK_FUNCTION_LIST, -} - -impl Pkcs11 { - /// Instantiate a new context from the path of a PKCS11 dynamic llibrary 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 { - _pkcs11_lib: pkcs11_lib, - function_list: *list_ptr, - }) - } - } -} - -#[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 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, -} - -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::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"), - } - } -} - -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::NulError(e) => Some(e), - Error::Pkcs11(_) - | Error::NotSupported - | Error::NullFunctionPointer - | Error::PinNotSet - | Error::InvalidValue => 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: std::ffi::NulError) -> Error { - Error::NulError(err) - } -} - -impl From for Error { - fn from(_err: std::convert::Infallible) -> Error { - unreachable!() - } -} - -impl Drop for Pkcs11 { - fn drop(&mut self) { - if let Err(e) = self.finalize_private() { - error!("Failed to finalize: {}", e); - } - } -} - -/// Main Result type -pub type Result = core::result::Result; fn string_from_blank_padded(field: &[CK_UTF8CHAR]) -> String { let decoded_str = String::from_utf8_lossy(field); diff --git a/cryptoki/src/types/mechanism/elliptic_curve.rs b/cryptoki/src/mechanism/elliptic_curve.rs similarity index 97% rename from cryptoki/src/types/mechanism/elliptic_curve.rs rename to cryptoki/src/mechanism/elliptic_curve.rs index 115e5944..8b6bc8c8 100644 --- a/cryptoki/src/types/mechanism/elliptic_curve.rs +++ b/cryptoki/src/mechanism/elliptic_curve.rs @@ -1,6 +1,7 @@ //! ECDH mechanism types -use crate::{types::Ulong, Error, Result}; +use crate::error::{Error, Result}; +use crate::types::Ulong; use cryptoki_sys::*; use log::error; use std::convert::TryFrom; diff --git a/cryptoki/src/mechanism/flags.rs b/cryptoki/src/mechanism/flags.rs new file mode 100644 index 00000000..507f90ea --- /dev/null +++ b/cryptoki/src/mechanism/flags.rs @@ -0,0 +1,300 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! PKCS11 General Data Types + +use crate::types::Flags; +use cryptoki_sys::*; +use std::fmt::Formatter; + +#[derive(Debug, Default, Clone, Copy)] +/// Collection of flags defined for [`CK_MECHANISM_INFO`] +pub struct MechanismFlags { + flags: CK_FLAGS, +} + +impl Flags for MechanismFlags { + type FlagType = CK_FLAGS; + + fn flag_value(&self) -> Self::FlagType { + self.flags + } + + fn flag(&self, flag: Self::FlagType) -> bool { + self.flag_value() & flag == flag + } + + fn set_flag(&mut self, flag: Self::FlagType, b: bool) { + if b { + self.flags |= flag; + } else { + self.flags &= !flag; + } + } + + fn stringify_flag(flag: CK_FLAGS) -> &'static str { + match flag { + CKF_HW => std::stringify!(CKF_HW), + CKF_ENCRYPT => std::stringify!(CKF_ENCRYPT), + CKF_DECRYPT => std::stringify!(CKF_DECRYPT), + CKF_DIGEST => std::stringify!(CKF_DIGEST), + CKF_SIGN => std::stringify!(CKF_SIGN), + CKF_SIGN_RECOVER => std::stringify!(CKF_SIGN_RECOVER), + CKF_VERIFY => std::stringify!(CKF_VERIFY), + CKF_VERIFY_RECOVER => std::stringify!(CKF_VERIFY_RECOVER), + CKF_GENERATE => std::stringify!(CKF_GENERATE), + CKF_GENERATE_KEY_PAIR => std::stringify!(CKF_GENERATE_KEY_PAIR), + CKF_WRAP => std::stringify!(CKF_WRAP), + CKF_UNWRAP => std::stringify!(CKF_UNWRAP), + CKF_DERIVE => std::stringify!(CKF_DERIVE), + CKF_EXTENSION => std::stringify!(CKF_EXTENSION), + CKF_EC_F_P => std::stringify!(CKF_EC_F_P), + CKF_EC_NAMEDCURVE => std::stringify!(CKF_EC_NAMEDCURVE), + CKF_EC_UNCOMPRESS => std::stringify!(CKF_EC_UNCOMPRESS), + CKF_EC_COMPRESS => std::stringify!(CKF_EC_COMPRESS), + _ => "Unknown CK_MECHANISM_INFO flag", + } + } +} + +impl MechanismFlags { + /// Creates a new instance of `MechanismFlags` with no flags set + pub fn new() -> Self { + MechanismFlags::default() + } + + /// Gets value of [`CKF_HW`] + pub fn hardware(&self) -> bool { + self.flag(CKF_HW) + } + + /// Sets value of [`CKF_HW`] + pub fn set_hardware(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_HW, b); + self + } + + /// Gets value of [`CKF_ENCRYPT`] + pub fn encrypt(&self) -> bool { + self.flag(CKF_ENCRYPT) + } + + /// Sets value of [`CKF_ENCRYPT`] + pub fn set_encrypt(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_ENCRYPT, b); + self + } + + /// Gets value of [`CKF_DECRYPT`] + pub fn decrypt(&self) -> bool { + self.flag(CKF_DECRYPT) + } + + /// Sets value of [`CKF_DECRYPT`] + pub fn set_decrypt(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_DECRYPT, b); + self + } + + /// Gets value of [`CKF_DIGEST`] + pub fn digest(&self) -> bool { + self.flag(CKF_DIGEST) + } + + /// Sets value of [`CKF_DIGEST`] + pub fn set_digest(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_DIGEST, b); + self + } + + /// Gets value of [`CKF_SIGN`] + pub fn sign(&self) -> bool { + self.flag(CKF_SIGN) + } + + /// Sets value of [`CKF_SIGN`] + pub fn set_sign(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_SIGN, b); + self + } + + /// Gets value of [`CKF_SIGN_RECOVER`] + pub fn sign_recover(&self) -> bool { + self.flag(CKF_SIGN_RECOVER) + } + + /// Sets value of [`CKF_SIGN_RECOVER`] + pub fn set_sign_recover(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_SIGN_RECOVER, b); + self + } + + /// Gets value of [`CKF_VERIFY`] + pub fn verify(&self) -> bool { + self.flag(CKF_VERIFY) + } + + /// Sets value of [`CKF_VERIFY`] + pub fn set_verify(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_VERIFY, b); + self + } + + /// Gets value of [`CKF_VERIFY_RECOVER`] + pub fn verify_recover(&self) -> bool { + self.flag(CKF_VERIFY_RECOVER) + } + + /// Sets value of [`CKF_VERIFY_RECOVER`] + pub fn set_verify_recover(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_VERIFY_RECOVER, b); + self + } + + /// Gets value of [`CKF_GENERATE`] + pub fn generate(&self) -> bool { + self.flag(CKF_GENERATE) + } + + /// Sets value of [`CKF_GENERATE`] + pub fn set_generate(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_GENERATE, b); + self + } + + /// Gets value of [`CKF_GENERATE_KEY_PAIR`] + pub fn generate_key_pair(&self) -> bool { + self.flag(CKF_GENERATE_KEY_PAIR) + } + + /// Sets value of [`CKF_GENERATE_KEY_PAIR`] + pub fn set_generate_key_pair(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_GENERATE_KEY_PAIR, b); + self + } + + /// Gets value of [`CKF_WRAP`] + pub fn wrap(&self) -> bool { + self.flag(CKF_WRAP) + } + + /// Sets value of [`CKF_WRAP`] + pub fn set_wrap(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_WRAP, b); + self + } + + /// Gets value of [`CKF_UNWRAP`] + pub fn unwrap(&self) -> bool { + self.flag(CKF_UNWRAP) + } + + /// Sets value of [`CKF_UNWRAP`] + pub fn set_unwrap(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_UNWRAP, b); + self + } + + /// Gets value of [`CKF_DERIVE`] + pub fn derive(&self) -> bool { + self.flag(CKF_DERIVE) + } + + /// Sets value of [`CKF_DERIVE`] + pub fn set_derive(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_DERIVE, b); + self + } + + /// Gets value of [`CKF_EXTENSION`] + pub fn extension(&self) -> bool { + self.flag(CKF_EXTENSION) + } + + /// Sets value of [`CKF_EXTENSION`] + pub fn set_extension(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_EXTENSION, b); + self + } + + /// Gets value of [`CKF_EC_F_P`] + pub fn ec_f_p(&self) -> bool { + self.flag(CKF_EC_F_P) + } + + /// Sets value of [`CKF_EC_F_P`] + pub fn set_ec_f_p(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_EC_F_P, b); + self + } + + /// Gets value of [`CKF_EC_NAMEDCURVE`] + pub fn ec_namedcurve(&self) -> bool { + self.flag(CKF_EC_NAMEDCURVE) + } + + /// Sets value of [`CKF_EC_NAMEDCURVE`] + pub fn set_ec_namedcurve(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_EC_NAMEDCURVE, b); + self + } + + /// Gets value of [`CKF_EC_UNCOMPRESS`] + pub fn ec_uncompress(&self) -> bool { + self.flag(CKF_EC_UNCOMPRESS) + } + + /// Sets value of [`CKF_EC_UNCOMPRESS`] + pub fn set_ec_uncompress(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_EC_UNCOMPRESS, b); + self + } + + /// Gets value of [`CKF_EC_COMPRESS`] + pub fn ec_compress(&self) -> bool { + self.flag(CKF_EC_COMPRESS) + } + + /// Sets value of [`CKF_EC_COMPRESS`] + pub fn set_ec_compress(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_EC_COMPRESS, b); + self + } +} + +impl std::fmt::Display for MechanismFlags { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let flags = vec![ + CKF_HW, + CKF_ENCRYPT, + CKF_DECRYPT, + CKF_DIGEST, + CKF_SIGN, + CKF_SIGN_RECOVER, + CKF_VERIFY, + CKF_VERIFY_RECOVER, + CKF_GENERATE, + CKF_GENERATE_KEY_PAIR, + CKF_WRAP, + CKF_UNWRAP, + CKF_DERIVE, + CKF_EXTENSION, + CKF_EC_F_P, + CKF_EC_NAMEDCURVE, + CKF_EC_UNCOMPRESS, + CKF_EC_COMPRESS, + ]; + self.stringify_fmt(f, flags) + } +} + +impl From for CK_FLAGS { + fn from(flags: MechanismFlags) -> Self { + flags.flags + } +} + +impl From for MechanismFlags { + fn from(flags: CK_FLAGS) -> Self { + Self { flags } + } +} diff --git a/cryptoki/src/types/mechanism/mod.rs b/cryptoki/src/mechanism/mod.rs similarity index 99% rename from cryptoki/src/types/mechanism/mod.rs rename to cryptoki/src/mechanism/mod.rs index 91a48d12..d7115c0d 100644 --- a/cryptoki/src/types/mechanism/mod.rs +++ b/cryptoki/src/mechanism/mod.rs @@ -3,10 +3,12 @@ //! Data types for mechanisms pub mod elliptic_curve; +mod flags; pub mod rsa; +pub use flags::*; -use crate::types::{MechanismFlags, Ulong}; -use crate::Error; +use crate::error::Error; +use crate::types::Ulong; use cryptoki_sys::*; use log::error; use std::convert::{TryFrom, TryInto}; diff --git a/cryptoki/src/types/mechanism/rsa.rs b/cryptoki/src/mechanism/rsa.rs similarity index 98% rename from cryptoki/src/types/mechanism/rsa.rs rename to cryptoki/src/mechanism/rsa.rs index e3b2b975..f85eb3c4 100644 --- a/cryptoki/src/types/mechanism/rsa.rs +++ b/cryptoki/src/mechanism/rsa.rs @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 //! RSA mechanism types -use crate::types::mechanism::{Mechanism, MechanismType}; +use super::{Mechanism, MechanismType}; +use crate::error::{Error, Result}; use crate::types::Ulong; -use crate::{Error, Result}; use cryptoki_sys::*; use log::error; use std::convert::TryFrom; diff --git a/cryptoki/src/types/object.rs b/cryptoki/src/object.rs similarity index 99% rename from cryptoki/src/types/object.rs rename to cryptoki/src/object.rs index f075ac53..5b40b352 100644 --- a/cryptoki/src/types/object.rs +++ b/cryptoki/src/object.rs @@ -1,10 +1,10 @@ // Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 -//! Object types +//! Object types (including Attributes) -use crate::types::mechanism::MechanismType; +use crate::error::{Error, Result}; +use crate::mechanism::MechanismType; use crate::types::{Bbool, Date, Ulong}; -use crate::{Error, Result}; use cryptoki_sys::*; use log::error; use std::convert::TryFrom; diff --git a/cryptoki/src/objects/mod.rs b/cryptoki/src/objects/mod.rs deleted file mode 100644 index 44ffe467..00000000 --- a/cryptoki/src/objects/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! PKCS11 objects diff --git a/cryptoki/src/session/decryption.rs b/cryptoki/src/session/decryption.rs new file mode 100644 index 00000000..8a5e57e0 --- /dev/null +++ b/cryptoki/src/session/decryption.rs @@ -0,0 +1,61 @@ +// 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; + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn decrypt( + session: &Session<'_>, + 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!(session.client(), C_DecryptInit)( + session.handle(), + &mut mechanism as CK_MECHANISM_PTR, + key.handle(), + )) + .into_result()?; + } + + // Get the output buffer length + unsafe { + Rv::from(get_pkcs11!(session.client(), C_Decrypt)( + session.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!(session.client(), C_Decrypt)( + session.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) +} diff --git a/cryptoki/src/session/encryption.rs b/cryptoki/src/session/encryption.rs new file mode 100644 index 00000000..13fc08f7 --- /dev/null +++ b/cryptoki/src/session/encryption.rs @@ -0,0 +1,60 @@ +// 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; + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub fn encrypt( + session: &Session<'_>, + 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!(session.client(), C_EncryptInit)( + session.handle(), + &mut mechanism as CK_MECHANISM_PTR, + key.handle(), + )) + .into_result()?; + } + + // Get the output buffer length + unsafe { + Rv::from(get_pkcs11!(session.client(), C_Encrypt)( + session.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!(session.client(), C_Encrypt)( + session.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) +} diff --git a/cryptoki/src/session/flags.rs b/cryptoki/src/session/flags.rs new file mode 100644 index 00000000..27f5af9d --- /dev/null +++ b/cryptoki/src/session/flags.rs @@ -0,0 +1,89 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! PKCS11 General Data Types + +use crate::types::Flags; +use cryptoki_sys::*; +use std::fmt::Formatter; + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +/// Collection of flags defined for [`CK_SESSION_INFO`] +pub struct SessionFlags { + flags: CK_FLAGS, +} + +impl Flags for SessionFlags { + type FlagType = CK_FLAGS; + + fn flag_value(&self) -> Self::FlagType { + self.flags + } + + fn flag(&self, flag: Self::FlagType) -> bool { + self.flag_value() & flag == flag + } + + fn set_flag(&mut self, flag: Self::FlagType, b: bool) { + if b { + self.flags |= flag; + } else { + self.flags &= !flag; + } + } + + fn stringify_flag(flag: Self::FlagType) -> &'static str { + match flag { + CKF_RW_SESSION => std::stringify!(CKF_RW_SESSION), + CKF_SERIAL_SESSION => std::stringify!(CKF_SERIAL_SESSION), + _ => "Unknown session flag", + } + } +} + +impl SessionFlags { + /// Creates a new instance of `SessionFlags` with no flags set + pub fn new() -> Self { + SessionFlags::default() + } + + /// Gets value of [`CKF_RW_SESSION`] + pub fn rw_session(&self) -> bool { + self.flag(CKF_RW_SESSION) + } + + /// Sets value of [`CKF_RW_SESSION`] + pub fn set_rw_session(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_RW_SESSION, b); + self + } + + /// Gets value of [`CKF_SERIAL_SESSION`] + pub fn serial_session(&self) -> bool { + self.flag(CKF_SERIAL_SESSION) + } + + /// Sets value of [`CKF_SERIAL_SESSION`] + pub fn set_serial_session(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_SERIAL_SESSION, b); + self + } +} + +impl std::fmt::Display for SessionFlags { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let flags = vec![CKF_RW_SESSION, CKF_SERIAL_SESSION]; + self.stringify_fmt(f, flags) + } +} + +impl From for CK_FLAGS { + fn from(flags: SessionFlags) -> Self { + flags.flags + } +} + +impl From for SessionFlags { + fn from(flags: CK_FLAGS) -> Self { + Self { flags } + } +} diff --git a/cryptoki/src/session/key_management.rs b/cryptoki/src/session/key_management.rs new file mode 100644 index 00000000..085d7bac --- /dev/null +++ b/cryptoki/src/session/key_management.rs @@ -0,0 +1,162 @@ +// 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; + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn generate_key( + session: &Session<'_>, + 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!(session.client(), C_GenerateKey)( + session.handle(), + &mut mechanism as CK_MECHANISM_PTR, + template.as_mut_ptr(), + template.len().try_into()?, + &mut handle, + )) + .into_result()?; + } + + Ok(ObjectHandle::new(handle)) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn generate_key_pair( + session: &Session<'_>, + 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!(session.client(), C_GenerateKeyPair)( + session.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), + )) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn derive_key( + session: &Session<'_>, + 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!(session.client(), C_DeriveKey)( + session.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)) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn wrap_key( + session: &Session<'_>, + 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!(session.client(), C_WrapKey)( + session.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!(session.client(), C_WrapKey)( + session.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) + } +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn unwrap_key( + session: &Session<'_>, + 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!(session.client(), C_UnwrapKey)( + session.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)) +} diff --git a/cryptoki/src/session/mod.rs b/cryptoki/src/session/mod.rs new file mode 100644 index 00000000..c82a42b9 --- /dev/null +++ b/cryptoki/src/session/mod.rs @@ -0,0 +1,478 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! Session types + +use crate::context::Pkcs11; +use crate::error::Result; +use crate::mechanism::Mechanism; +use crate::object::{Attribute, AttributeInfo, AttributeType, ObjectHandle}; +use crate::slot::Slot; +use crate::types::Ulong; + +use cryptoki_sys::*; +use log::error; +use std::collections::HashMap; +use std::convert::TryInto; +use std::fmt::Formatter; +use std::ops::Deref; + +mod decryption; +mod encryption; +mod flags; +mod key_management; +mod object_management; +mod random; +mod session_management; +mod signing_macing; +mod slot_token_management; + +pub use flags::*; + +/// 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<'a> { + handle: CK_SESSION_HANDLE, + client: &'a Pkcs11, + // This is not used but to prevent Session to automatically implement Send and Sync + _guard: *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<'a> Send for Session<'a> {} + +impl<'a> Session<'a> { + pub(crate) fn new(handle: CK_SESSION_HANDLE, client: &'a Pkcs11) -> Self { + Session { + handle, + client, + _guard: std::ptr::null_mut::(), + } + } +} + +impl Session<'_> { + /// Initialize the normal user's pin for a token + pub fn init_pin(&self, pin: &str) -> Result<()> { + slot_token_management::init_pin(self, pin) + } + + /// 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: &str, new_pin: &str) -> Result<()> { + slot_token_management::set_pin(self, old_pin, new_pin) + } + + /// Close a session + /// This will be called on drop as well. + pub fn close(self) {} + + /// 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<&str>) -> Result<()> { + session_management::login(self, user_type, pin) + } + + /// Log a session out + pub fn logout(&self) -> Result<()> { + session_management::logout(self) + } + + /// Returns the information about a session + pub fn get_session_info(&self) -> Result { + session_management::get_session_info(self) + } + + /// Search for session objects matching a template + pub fn find_objects(&self, template: &[Attribute]) -> Result> { + object_management::find_objects(self, template) + } + + /// Create a new object + pub fn create_object(&self, template: &[Attribute]) -> Result { + object_management::create_object(self, template) + } + + /// Destroy an object + pub fn destroy_object(&self, object: ObjectHandle) -> Result<()> { + object_management::destroy_object(self, object) + } + + /// 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::session::SessionFlags; + /// use std::collections::HashMap; + /// use std::env; + /// + /// let 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 mut flags = SessionFlags::new(); + /// let _ = flags.set_rw_session(true).set_serial_session(true); + /// + /// let session = pkcs11.open_session_no_callback(slot, flags).unwrap(); + /// session.login(UserType::User, Some("fedcba")); + /// + /// 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> { + object_management::get_attribute_info(self, object, attributes) + } + + /// 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> { + object_management::get_attribute_info_map(self, object, attributes) + } + + /// 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> { + object_management::get_attributes(self, object, attributes) + } + + /// Single-part encryption operation + pub fn encrypt( + &self, + mechanism: &Mechanism, + key: ObjectHandle, + data: &[u8], + ) -> Result> { + encryption::encrypt(self, mechanism, key, data) + } + + /// Single-part decryption operation + pub fn decrypt( + &self, + mechanism: &Mechanism, + key: ObjectHandle, + encrypted_data: &[u8], + ) -> Result> { + decryption::decrypt(self, mechanism, key, encrypted_data) + } + + /// Sign data in single-part + pub fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result> { + signing_macing::sign(self, mechanism, key, data) + } + + /// Verify data in single-part + pub fn verify( + &self, + mechanism: &Mechanism, + key: ObjectHandle, + data: &[u8], + signature: &[u8], + ) -> Result<()> { + signing_macing::verify(self, mechanism, key, data, signature) + } + + /// Generate a secret key + pub fn generate_key( + &self, + mechanism: &Mechanism, + template: &[Attribute], + ) -> Result { + key_management::generate_key(self, mechanism, template) + } + + /// 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)> { + key_management::generate_key_pair(self, mechanism, pub_key_template, priv_key_template) + } + + /// Derives a key from a base key + pub fn derive_key( + &self, + mechanism: &Mechanism, + base_key: ObjectHandle, + template: &[Attribute], + ) -> Result { + key_management::derive_key(self, mechanism, base_key, template) + } + + /// Wrap key + pub fn wrap_key( + &self, + mechanism: &Mechanism, + wrapping_key: ObjectHandle, + key: ObjectHandle, + ) -> Result> { + key_management::wrap_key(self, mechanism, wrapping_key, key) + } + + /// Unwrap previously wrapped key + pub fn unwrap_key( + &self, + mechanism: &Mechanism, + unwrapping_key: ObjectHandle, + wrapped_key: &[u8], + template: &[Attribute], + ) -> Result { + key_management::unwrap_key(self, mechanism, unwrapping_key, wrapped_key, template) + } + + /// 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<()> { + random::generate_random_slice(self, random_data) + } + + /// 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> { + random::generate_random_vec(self, random_len) + } + + /// Seeds the RNG + pub fn seed_random(&self, seed: &[u8]) -> Result<()> { + random::seed_random(self, seed) + } + + pub(crate) fn handle(&self) -> CK_SESSION_HANDLE { + self.handle + } + + pub(crate) fn client(&self) -> &Pkcs11 { + self.client + } +} + +impl Drop for Session<'_> { + fn drop(&mut self) { + if let Err(e) = session_management::close_private(self) { + error!("Failed to close session: {}", e); + } + } +} + +/// 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, + } + } +} + +/// Represents the state of a session +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct SessionState { + val: CK_STATE, +} + +impl SessionState { + /// Read-only public session + pub const RO_PUBLIC_SESSION: SessionState = SessionState { + val: CKS_RO_PUBLIC_SESSION, + }; + + /// Read-only user access + pub const RO_USER_FUNCTIONS: SessionState = SessionState { + val: CKS_RO_USER_FUNCTIONS, + }; + + /// Read/write public session + pub const RW_PUBLIC_SESSION: SessionState = SessionState { + val: CKS_RW_PUBLIC_SESSION, + }; + + /// Read/write user access + pub const RW_USER_FUNCTIONS: SessionState = SessionState { + val: CKS_RW_USER_FUNCTIONS, + }; + + /// Read/write SO access + pub const RW_SO_FUNCTIONS: SessionState = SessionState { + val: CKS_RW_SO_FUNCTIONS, + }; + + /// Stringifies the value of a [CK_STATE] + pub(crate) fn stringify(state: CK_STATE) -> &'static str { + match state { + CKS_RO_PUBLIC_SESSION => stringify!(CKS_RO_PUBLIC_SESSION), + CKS_RO_USER_FUNCTIONS => stringify!(CKS_RO_USER_FUNCTIONS), + CKS_RW_PUBLIC_SESSION => stringify!(CKS_RW_PUBLIC_SESSION), + CKS_RW_USER_FUNCTIONS => stringify!(CKS_RW_USER_FUNCTIONS), + CKS_RW_SO_FUNCTIONS => stringify!(CKS_RW_SO_FUNCTIONS), + _ => "Unknown state value", + } + } +} + +impl Deref for SessionState { + type Target = CK_STATE; + + fn deref(&self) -> &Self::Target { + &self.val + } +} + +impl From for CK_STATE { + fn from(session_state: SessionState) -> Self { + *session_state + } +} + +impl From for SessionState { + fn from(val: CK_STATE) -> Self { + Self { val } + } +} + +impl std::fmt::Display for SessionState { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", SessionState::stringify(self.val)) + } +} + +/// Type identifying the session information +#[derive(Copy, Clone, Debug)] +pub struct SessionInfo { + val: CK_SESSION_INFO, +} + +impl SessionInfo { + pub(crate) fn new(val: CK_SESSION_INFO) -> Self { + Self { val } + } + + /// Returns an error code defined by the cryptographic device + pub fn device_error(&self) -> Ulong { + self.val.ulDeviceError.into() + } + + /// Returns the flags for this session + pub fn flags(&self) -> SessionFlags { + self.val.flags.into() + } + + /// Returns the state of the session + pub fn session_state(&self) -> SessionState { + self.val.state.into() + } + + /// Returns the slot the session is on + pub fn slot_id(&self) -> Slot { + // The unwrap should not fail as `slotID` is a `CK_SLOT_ID ` which is the same type as + // `slot_id` within the `Slot` structure + self.val.slotID.try_into().unwrap() + } +} diff --git a/cryptoki/src/session/object_management.rs b/cryptoki/src/session/object_management.rs new file mode 100644 index 00000000..493eeda7 --- /dev/null +++ b/cryptoki/src/session/object_management.rs @@ -0,0 +1,199 @@ +// 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; + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn find_objects( + session: &Session<'_>, + template: &[Attribute], +) -> Result> { + let mut template: Vec = template.iter().map(|attr| attr.into()).collect(); + + unsafe { + Rv::from(get_pkcs11!(session.client(), C_FindObjectsInit)( + session.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!(session.client(), C_FindObjects)( + session.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!(session.client(), C_FindObjects)( + session.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!(session.client(), C_FindObjectsFinal)( + session.handle(), + )) + .into_result()?; + } + + let objects = objects.into_iter().map(ObjectHandle::new).collect(); + + Ok(objects) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn create_object(session: &Session<'_>, template: &[Attribute]) -> Result { + let mut template: Vec = template.iter().map(|attr| attr.into()).collect(); + let mut object_handle = 0; + + unsafe { + Rv::from(get_pkcs11!(session.client(), C_CreateObject)( + session.handle(), + template.as_mut_ptr(), + template.len().try_into()?, + &mut object_handle as CK_OBJECT_HANDLE_PTR, + )) + .into_result()?; + } + + Ok(ObjectHandle::new(object_handle)) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn destroy_object(session: &Session<'_>, object: ObjectHandle) -> Result<()> { + unsafe { + Rv::from(get_pkcs11!(session.client(), C_DestroyObject)( + session.handle(), + object.handle(), + )) + .into_result() + } +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn get_attribute_info( + session: &Session<'_>, + 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!(session.client(), C_GetAttributeValue)( + session.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) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn get_attribute_info_map( + session: &Session<'_>, + object: ObjectHandle, + attributes: Vec, +) -> Result> { + let attrib_info = session.get_attribute_info(object, attributes.as_slice())?; + + Ok(attributes + .iter() + .cloned() + .zip(attrib_info.iter().cloned()) + .collect::>()) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn get_attributes( + session: &Session<'_>, + object: ObjectHandle, + attributes: &[AttributeType], +) -> Result> { + let attrs_info = session.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!(session.client(), C_GetAttributeValue)( + session.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() +} diff --git a/cryptoki/src/session/random.rs b/cryptoki/src/session/random.rs new file mode 100644 index 00000000..0ae41f6e --- /dev/null +++ b/cryptoki/src/session/random.rs @@ -0,0 +1,50 @@ +// 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; + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn generate_random_slice(session: &Session<'_>, random_data: &mut [u8]) -> Result<()> { + unsafe { + Rv::from(get_pkcs11!(session.client(), C_GenerateRandom)( + session.handle(), + random_data.as_ptr() as *mut u8, + random_data.len().try_into()?, + )) + .into_result()?; + } + Ok(()) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn generate_random_vec(session: &Session<'_>, random_len: u32) -> Result> { + let mut result: Vec = vec![0; random_len as usize]; + unsafe { + Rv::from(get_pkcs11!(session.client(), C_GenerateRandom)( + session.handle(), + result.as_mut_ptr() as *mut u8, + random_len.try_into()?, + )) + .into_result()?; + } + Ok(result) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn seed_random(session: &Session<'_>, seed: &[u8]) -> Result<()> { + unsafe { + Rv::from(get_pkcs11!(session.client(), C_SeedRandom)( + session.handle(), + seed.as_ptr() as *mut u8, + seed.len().try_into()?, + )) + .into_result()?; + } + Ok(()) +} diff --git a/cryptoki/src/session/session_management.rs b/cryptoki/src/session/session_management.rs new file mode 100644 index 00000000..c9df0463 --- /dev/null +++ b/cryptoki/src/session/session_management.rs @@ -0,0 +1,57 @@ +// 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 cryptoki_sys::CK_SESSION_INFO; +use std::convert::TryInto; + +// See public docs on close() in parent mod.rs +#[inline(always)] +pub(super) fn close_private(session: &Session<'_>) -> Result<()> { + unsafe { + Rv::from(get_pkcs11!(session.client(), C_CloseSession)( + session.handle(), + )) + .into_result() + } +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn login(session: &Session<'_>, user_type: UserType, pin: Option<&str>) -> Result<()> { + let (pin, pin_len) = match pin { + Some(pin) => (pin.as_ptr() as *mut u8, pin.len()), + None => (std::ptr::null_mut(), 0), + }; + unsafe { + Rv::from(get_pkcs11!(session.client(), C_Login)( + session.handle(), + user_type.into(), + pin, + pin_len.try_into()?, + )) + .into_result() + } +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn logout(session: &Session<'_>) -> Result<()> { + unsafe { Rv::from(get_pkcs11!(session.client(), C_Logout)(session.handle())).into_result() } +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn get_session_info(session: &Session<'_>) -> Result { + let mut session_info = CK_SESSION_INFO::default(); + unsafe { + Rv::from(get_pkcs11!(session.client(), C_GetSessionInfo)( + session.handle(), + &mut session_info, + )) + .into_result()?; + Ok(SessionInfo::new(session_info)) + } +} diff --git a/cryptoki/src/session/signing_macing.rs b/cryptoki/src/session/signing_macing.rs new file mode 100644 index 00000000..ad423c3f --- /dev/null +++ b/cryptoki/src/session/signing_macing.rs @@ -0,0 +1,93 @@ +// 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; + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn sign( + session: &Session<'_>, + mechanism: &Mechanism, + key: ObjectHandle, + data: &[u8], +) -> Result> { + let mut mechanism: CK_MECHANISM = mechanism.into(); + let mut signature_len = 0; + + unsafe { + Rv::from(get_pkcs11!(session.client(), C_SignInit)( + session.handle(), + &mut mechanism as CK_MECHANISM_PTR, + key.handle(), + )) + .into_result()?; + } + + // Get the output buffer length + unsafe { + Rv::from(get_pkcs11!(session.client(), C_Sign)( + session.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!(session.client(), C_Sign)( + session.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) +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn verify( + session: &Session<'_>, + mechanism: &Mechanism, + key: ObjectHandle, + data: &[u8], + signature: &[u8], +) -> Result<()> { + let mut mechanism: CK_MECHANISM = mechanism.into(); + + unsafe { + Rv::from(get_pkcs11!(session.client(), C_VerifyInit)( + session.handle(), + &mut mechanism as CK_MECHANISM_PTR, + key.handle(), + )) + .into_result()?; + } + + unsafe { + Rv::from(get_pkcs11!(session.client(), C_Verify)( + session.handle(), + data.as_ptr() as *mut u8, + data.len().try_into()?, + signature.as_ptr() as *mut u8, + signature.len().try_into()?, + )) + .into_result() + } +} diff --git a/cryptoki/src/session/slot_token_management.rs b/cryptoki/src/session/slot_token_management.rs new file mode 100644 index 00000000..911ff05b --- /dev/null +++ b/cryptoki/src/session/slot_token_management.rs @@ -0,0 +1,35 @@ +// 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 std::convert::TryInto; + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn init_pin(session: &Session<'_>, pin: &str) -> Result<()> { + unsafe { + Rv::from(get_pkcs11!(session.client(), C_InitPIN)( + session.handle(), + pin.as_ptr() as *mut u8, + pin.len().try_into()?, + )) + .into_result() + } +} + +// See public docs on stub in parent mod.rs +#[inline(always)] +pub(super) fn set_pin(session: &Session<'_>, old_pin: &str, new_pin: &str) -> Result<()> { + unsafe { + Rv::from(get_pkcs11!(session.client(), C_SetPIN)( + session.handle(), + old_pin.as_ptr() as *mut u8, + old_pin.len().try_into()?, + new_pin.as_ptr() as *mut u8, + new_pin.len().try_into()?, + )) + .into_result() + } +} diff --git a/cryptoki/src/slot/flags.rs b/cryptoki/src/slot/flags.rs new file mode 100644 index 00000000..182c712f --- /dev/null +++ b/cryptoki/src/slot/flags.rs @@ -0,0 +1,394 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! PKCS11 General Data Types + +use crate::types::Flags; +use cryptoki_sys::*; +use std::fmt::Formatter; + +#[derive(Debug, Default, Clone, Copy)] +/// Collection of flags defined for [`CK_SLOT_INFO`] +pub struct SlotFlags { + flags: CK_FLAGS, +} + +impl Flags for SlotFlags { + type FlagType = CK_FLAGS; + + fn flag_value(&self) -> Self::FlagType { + self.flags + } + + fn flag(&self, flag: Self::FlagType) -> bool { + self.flag_value() & flag == flag + } + + fn set_flag(&mut self, flag: Self::FlagType, b: bool) { + if b { + self.flags |= flag; + } else { + self.flags &= !flag; + } + } + + fn stringify_flag(flag: Self::FlagType) -> &'static str { + match flag { + CKF_TOKEN_PRESENT => std::stringify!(CKF_TOKEN_PRESENT), + CKF_REMOVABLE_DEVICE => std::stringify!(CKF_REMOVABLE_DEVICE), + CKF_HW_SLOT => std::stringify!(CKF_HW_SLOT), + _ => "Unknown CK_SLOT_INFO flag", + } + } +} + +impl SlotFlags { + /// Creates a new instance of `SlotFlags` with no flags set + pub fn new() -> Self { + SlotFlags::default() + } + + /// Gets value of [`CKF_TOKEN_PRESENT`] + pub fn token_present(&self) -> bool { + self.flag(CKF_TOKEN_PRESENT) + } + + /// Sets value of [`CKF_TOKEN_PRESENT`] + pub fn set_token_present(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_TOKEN_PRESENT, b); + self + } + + /// Gets value of [`CKF_REMOVABLE_DEVICE`] + pub fn removable_device(&self) -> bool { + self.flag(CKF_REMOVABLE_DEVICE) + } + + /// Sets value of [`CKF_REMOVABLE_DEVICE`] + pub fn set_removable_device(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_REMOVABLE_DEVICE, b); + self + } + + /// Gets value of [`CKF_HW_SLOT`] + pub fn hardware_slot(&self) -> bool { + self.flag(CKF_HW_SLOT) + } + + /// Sets value of [`CKF_HW_SLOT`] + pub fn set_hardware_slot(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_HW_SLOT, b); + self + } +} + +impl std::fmt::Display for SlotFlags { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let flags = vec![CKF_TOKEN_PRESENT, CKF_REMOVABLE_DEVICE, CKF_HW_SLOT]; + self.stringify_fmt(f, flags) + } +} + +impl From for CK_FLAGS { + fn from(flags: SlotFlags) -> Self { + flags.flags + } +} + +impl From for SlotFlags { + fn from(flags: CK_FLAGS) -> Self { + Self { flags } + } +} + +#[derive(Debug, Default, Clone, Copy)] +/// Collection of flags defined for [`CK_TOKEN_INFO`] +pub struct TokenFlags { + flags: CK_FLAGS, +} + +impl Flags for TokenFlags { + type FlagType = CK_FLAGS; + + fn flag_value(&self) -> Self::FlagType { + self.flags + } + + fn flag(&self, flag: Self::FlagType) -> bool { + self.flag_value() & flag == flag + } + + fn set_flag(&mut self, flag: Self::FlagType, b: bool) { + if b { + self.flags |= flag; + } else { + self.flags &= !flag; + } + } + + fn stringify_flag(flag: Self::FlagType) -> &'static str { + match flag { + CKF_RNG => std::stringify!(CKF_RNG), + CKF_WRITE_PROTECTED => std::stringify!(CKF_WRITE_PROTECTED), + CKF_LOGIN_REQUIRED => std::stringify!(CKF_LOGIN_REQUIRED), + CKF_USER_PIN_INITIALIZED => std::stringify!(CKF_USER_PIN_INITIALIZED), + CKF_RESTORE_KEY_NOT_NEEDED => std::stringify!(CKF_RESTORE_KEY_NOT_NEEDED), + CKF_CLOCK_ON_TOKEN => std::stringify!(CKF_CLOCK_ON_TOKEN), + CKF_PROTECTED_AUTHENTICATION_PATH => std::stringify!(CKF_PROTECTED_AUTHENTICATION_PATH), + CKF_DUAL_CRYPTO_OPERATIONS => std::stringify!(CKF_DUAL_CRYPTO_OPERATIONS), + CKF_TOKEN_INITIALIZED => std::stringify!(CKF_TOKEN_INITIALIZED), + CKF_SECONDARY_AUTHENTICATION => std::stringify!(CKF_SECONDARY_AUTHENTICATION), + CKF_USER_PIN_COUNT_LOW => std::stringify!(CKF_USER_PIN_COUNT_LOW), + CKF_USER_PIN_FINAL_TRY => std::stringify!(CKF_USER_PIN_FINAL_TRY), + CKF_USER_PIN_LOCKED => std::stringify!(CKF_USER_PIN_LOCKED), + CKF_USER_PIN_TO_BE_CHANGED => std::stringify!(CKF_USER_PIN_TO_BE_CHANGED), + CKF_SO_PIN_COUNT_LOW => std::stringify!(CKF_SO_PIN_COUNT_LOW), + CKF_SO_PIN_FINAL_TRY => std::stringify!(CKF_SO_PIN_FINAL_TRY), + CKF_SO_PIN_LOCKED => std::stringify!(CKF_SO_PIN_LOCKED), + CKF_SO_PIN_TO_BE_CHANGED => std::stringify!(CKF_SO_PIN_TO_BE_CHANGED), + _ => "Unknown CK_TOKEN_INFO flag", + } + } +} + +impl TokenFlags { + /// Creates a new instance of `TokenFlags` with no flags set + pub fn new() -> Self { + TokenFlags::default() + } + + /// Gets value of [`CKF_RNG`] + pub fn random_number_generator(&self) -> bool { + self.flag(CKF_RNG) + } + + /// Sets value of [`CKF_RNG`] + pub fn set_random_number_generator(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_RNG, b); + self + } + + /// Gets value of [`CKF_WRITE_PROTECTED`] + pub fn write_protected(&self) -> bool { + self.flag(CKF_WRITE_PROTECTED) + } + + /// Sets value of [`CKF_WRITE_PROTECTED`] + pub fn set_write_protected(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_WRITE_PROTECTED, b); + self + } + + /// Gets value of [`CKF_LOGIN_REQUIRED`] + pub fn login_required(&self) -> bool { + self.flag(CKF_LOGIN_REQUIRED) + } + + /// Sets value of [`CKF_LOGIN_REQUIRED`] + pub fn set_login_required(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_LOGIN_REQUIRED, b); + self + } + + /// Gets value of [`CKF_USER_PIN_INITIALIZED`] + pub fn user_pin_initialized(&self) -> bool { + self.flag(CKF_USER_PIN_INITIALIZED) + } + + /// Sets value of [`CKF_USER_PIN_INITIALIZED`] + pub fn set_user_pin_initialized(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_USER_PIN_INITIALIZED, b); + self + } + + /// Gets value of [`CKF_RESTORE_KEY_NOT_NEEDED`] + pub fn restore_key_not_needed(&self) -> bool { + self.flag(CKF_RESTORE_KEY_NOT_NEEDED) + } + + /// Sets value of [`CKF_RESTORE_KEY_NOT_NEEDED`] + pub fn set_restore_key_not_needed(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_RESTORE_KEY_NOT_NEEDED, b); + self + } + + /// Gets value of [`CKF_CLOCK_ON_TOKEN`] + pub fn clock_on_token(&self) -> bool { + self.flag(CKF_CLOCK_ON_TOKEN) + } + + /// Sets value of [`CKF_CLOCK_ON_TOKEN`] + pub fn set_clock_on_token(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_CLOCK_ON_TOKEN, b); + self + } + + /// Gets value of [`CKF_PROTECTED_AUTHENTICATION_PATH`] + pub fn protected_authentication_path(&self) -> bool { + self.flag(CKF_PROTECTED_AUTHENTICATION_PATH) + } + + /// Sets value of [`CKF_PROTECTED_AUTHENTICATION_PATH`] + pub fn set_protected_authentication_path(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_PROTECTED_AUTHENTICATION_PATH, b); + self + } + + /// Gets value of [`CKF_DUAL_CRYPTO_OPERATIONS`] + pub fn dual_crypto_operations(&self) -> bool { + self.flag(CKF_DUAL_CRYPTO_OPERATIONS) + } + + /// Sets value of [`CKF_DUAL_CRYPTO_OPERATIONS`] + pub fn set_dual_crypto_operations(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_DUAL_CRYPTO_OPERATIONS, b); + self + } + + /// Gets value of [`CKF_TOKEN_INITIALIZED`] + pub fn token_initialized(&self) -> bool { + self.flag(CKF_TOKEN_INITIALIZED) + } + + /// Sets value of [`CKF_TOKEN_INITIALIZED`] + pub fn set_token_initialized(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_TOKEN_INITIALIZED, b); + self + } + + /// Gets value of [`CKF_SECONDARY_AUTHENTICATION`] + pub fn secondary_authentication(&self) -> bool { + self.flag(CKF_SECONDARY_AUTHENTICATION) + } + + /// Sets value of [`CKF_SECONDARY_AUTHENTICATION`] + pub fn set_secondary_authentication(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_SECONDARY_AUTHENTICATION, b); + self + } + + /// Gets value of [`CKF_USER_PIN_COUNT_LOW`] + pub fn user_pin_count_low(&self) -> bool { + self.flag(CKF_USER_PIN_COUNT_LOW) + } + + /// Sets value of [`CKF_USER_PIN_COUNT_LOW`] + pub fn set_user_pin_count_low(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_USER_PIN_COUNT_LOW, b); + self + } + + /// Gets value of [`CKF_USER_PIN_FINAL_TRY`] + pub fn user_pin_final_try(&self) -> bool { + self.flag(CKF_USER_PIN_FINAL_TRY) + } + + /// Sets value of [`CKF_USER_PIN_FINAL_TRY`] + pub fn set_user_pin_final_try(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_USER_PIN_FINAL_TRY, b); + self + } + + /// Gets value of [`CKF_USER_PIN_LOCKED`] + pub fn user_pin_locked(&self) -> bool { + self.flag(CKF_USER_PIN_LOCKED) + } + + /// Sets value of [`CKF_USER_PIN_LOCKED`] + pub fn set_user_pin_locked(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_USER_PIN_LOCKED, b); + self + } + + /// Gets value of [`CKF_USER_PIN_TO_BE_CHANGED`] + pub fn user_pin_to_be_changed(&self) -> bool { + self.flag(CKF_USER_PIN_TO_BE_CHANGED) + } + + /// Sets value of [`CKF_USER_PIN_TO_BE_CHANGED`] + pub fn set_user_pin_to_be_changed(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_USER_PIN_TO_BE_CHANGED, b); + self + } + + /// Gets value of [`CKF_SO_PIN_COUNT_LOW`] + pub fn so_pin_count_low(&self) -> bool { + self.flag(CKF_SO_PIN_COUNT_LOW) + } + + /// Sets value of [`CKF_SO_PIN_COUNT_LOW`] + pub fn set_so_pin_count_low(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_SO_PIN_COUNT_LOW, b); + self + } + + /// Gets value of [`CKF_SO_PIN_FINAL_TRY`] + pub fn so_pin_final_try(&self) -> bool { + self.flag(CKF_SO_PIN_FINAL_TRY) + } + + /// Sets value of [`CKF_SO_PIN_FINAL_TRY`] + pub fn set_so_pin_final_try(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_SO_PIN_FINAL_TRY, b); + self + } + + /// Gets value of [`CKF_SO_PIN_LOCKED`] + pub fn so_pin_locked(&self) -> bool { + self.flag(CKF_SO_PIN_LOCKED) + } + + /// Sets value of [`CKF_SO_PIN_LOCKED`] + pub fn set_so_pin_locked(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_SO_PIN_LOCKED, b); + self + } + + /// Gets value of [`CKF_SO_PIN_TO_BE_CHANGED`] + pub fn so_pin_to_be_changed(&self) -> bool { + self.flag(CKF_SO_PIN_TO_BE_CHANGED) + } + + /// Sets value of [`CKF_SO_PIN_TO_BE_CHANGED`] + pub fn set_so_pin_to_be_changed(&mut self, b: bool) -> &mut Self { + self.set_flag(CKF_SO_PIN_TO_BE_CHANGED, b); + self + } +} + +impl std::fmt::Display for TokenFlags { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let flags = vec![ + CKF_RNG, + CKF_WRITE_PROTECTED, + CKF_LOGIN_REQUIRED, + CKF_USER_PIN_INITIALIZED, + CKF_RESTORE_KEY_NOT_NEEDED, + CKF_CLOCK_ON_TOKEN, + CKF_PROTECTED_AUTHENTICATION_PATH, + CKF_DUAL_CRYPTO_OPERATIONS, + CKF_TOKEN_INITIALIZED, + CKF_SECONDARY_AUTHENTICATION, + CKF_USER_PIN_COUNT_LOW, + CKF_USER_PIN_FINAL_TRY, + CKF_USER_PIN_LOCKED, + CKF_USER_PIN_TO_BE_CHANGED, + CKF_SO_PIN_COUNT_LOW, + CKF_SO_PIN_FINAL_TRY, + CKF_SO_PIN_LOCKED, + CKF_SO_PIN_TO_BE_CHANGED, + ]; + self.stringify_fmt(f, flags) + } +} + +impl From for CK_FLAGS { + fn from(flags: TokenFlags) -> Self { + flags.flags + } +} + +impl From for TokenFlags { + fn from(flags: CK_FLAGS) -> Self { + Self { flags } + } +} diff --git a/cryptoki/src/types/slot_token.rs b/cryptoki/src/slot/mod.rs similarity index 97% rename from cryptoki/src/types/slot_token.rs rename to cryptoki/src/slot/mod.rs index 8e5e3264..edc50c87 100644 --- a/cryptoki/src/types/slot_token.rs +++ b/cryptoki/src/slot/mod.rs @@ -6,9 +6,12 @@ //! Slot and token types -use crate::types::{SlotFlags, TokenFlags, Ulong, Version}; -use crate::{string_from_blank_padded, Error, Result}; +mod flags; +use crate::error::{Error, Result}; +use crate::string_from_blank_padded; +use crate::types::{Ulong, Version}; use cryptoki_sys::{CK_SLOT_ID, CK_SLOT_INFO, CK_TOKEN_INFO}; +pub use flags::*; use std::convert::{TryFrom, TryInto}; use std::fmt::Formatter; use std::ops::Deref; diff --git a/cryptoki/src/types.rs b/cryptoki/src/types.rs new file mode 100644 index 00000000..05c50e45 --- /dev/null +++ b/cryptoki/src/types.rs @@ -0,0 +1,269 @@ +// 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 log::error; +use std::convert::TryFrom; +use std::convert::TryInto; +use std::fmt::Formatter; +use std::ops::Deref; + +pub(crate) trait Flags: std::fmt::Display { + type FlagType: Copy; + + fn flag_value(&self) -> Self::FlagType; + + fn flag(&self, flag: Self::FlagType) -> bool; + + fn set_flag(&mut self, flag: Self::FlagType, b: bool); + + fn stringify_flag(flag: Self::FlagType) -> &'static str; + + fn stringify_fmt(&self, f: &mut Formatter<'_>, flags: Vec) -> std::fmt::Result { + let mut first_done = false; + for flag in flags.iter() { + if self.flag(*flag) { + if first_done { + write!(f, ", ")?; + } + write!(f, "{}", Self::stringify_flag(*flag))?; + first_done = true; + } + } + Ok(()) + } +} + +#[repr(u8)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +/// Byte-sized boolean +pub enum Bbool { + /// False value + False = 0, + /// True value + True = 1, +} + +impl TryFrom<&[u8]> for Bbool { + type Error = Error; + + fn try_from(slice: &[u8]) -> Result { + CK_BBOOL::from_ne_bytes(slice.try_into()?).try_into() + } +} + +impl From for CK_BBOOL { + fn from(bbool: Bbool) -> Self { + bbool as CK_BBOOL + } +} + +impl From for Bbool { + fn from(val: bool) -> Self { + if val { + Bbool::True + } else { + Bbool::False + } + } +} + +impl From for bool { + fn from(val: Bbool) -> Self { + match val { + Bbool::False => false, + Bbool::True => true, + } + } +} + +impl TryFrom for Bbool { + type Error = Error; + + fn try_from(bbool: CK_BBOOL) -> Result { + match bbool { + CK_FALSE => Ok(Bbool::False), + CK_TRUE => Ok(Bbool::True), + other => { + error!("Bbool value {} is invalid.", other); + Err(Error::InvalidValue) + } + } + } +} + +#[derive(Debug, Copy, Clone)] +#[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 } + } +} + +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: {}\nDay: {}\nYear: {}", month, day, year) + } +} + +#[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 { + /// 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, + } + } +} diff --git a/cryptoki/src/types/mod.rs b/cryptoki/src/types/mod.rs deleted file mode 100644 index 39ece419..00000000 --- a/cryptoki/src/types/mod.rs +++ /dev/null @@ -1,1179 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! PKCS11 General Data Types - -pub mod function; -pub mod locking; -pub mod mechanism; -pub mod object; -pub mod session; -pub mod slot_token; - -use crate::{string_from_blank_padded, Error, Result}; -use cryptoki_sys::*; -use log::error; -use std::convert::TryFrom; -use std::convert::TryInto; -use std::fmt::Formatter; -use std::ops::Deref; - -trait Flags: std::fmt::Display { - type FlagType: Copy; - - fn flag_value(&self) -> Self::FlagType; - - fn flag(&self, flag: Self::FlagType) -> bool; - - fn set_flag(&mut self, flag: Self::FlagType, b: bool); - - fn stringify_flag(flag: Self::FlagType) -> &'static str; - - fn stringify_fmt(&self, f: &mut Formatter<'_>, flags: Vec) -> std::fmt::Result { - let mut first_done = false; - for flag in flags.iter() { - if self.flag(*flag) { - if first_done { - write!(f, ", ")?; - } - write!(f, "{}", Self::stringify_flag(*flag))?; - first_done = true; - } - } - Ok(()) - } -} - -#[derive(Debug, Default, Clone, Copy)] -/// Collection of flags defined for [`CK_C_INITIALIZE_ARGS`] -pub struct InitializeFlags { - flags: CK_FLAGS, -} - -impl Flags for InitializeFlags { - type FlagType = CK_FLAGS; - - fn flag_value(&self) -> Self::FlagType { - self.flags - } - - fn flag(&self, flag: Self::FlagType) -> bool { - self.flag_value() & flag == flag - } - - fn set_flag(&mut self, flag: Self::FlagType, b: bool) { - if b { - self.flags |= flag; - } else { - self.flags &= !flag; - } - } - - fn stringify_flag(flag: CK_FLAGS) -> &'static str { - match flag { - CKF_LIBRARY_CANT_CREATE_OS_THREADS => { - std::stringify!(CKF_LIBRARY_CANT_CREATE_OS_THREADS) - } - CKF_OS_LOCKING_OK => std::stringify!(CKF_OS_LOCKING_OK), - _ => "Unknown CK_C_INITIALIZE_ARGS flag", - } - } -} - -impl InitializeFlags { - /// Creates a new instance of `InitializeFlags` with no flags set - pub fn new() -> Self { - InitializeFlags::default() - } - - /// Gets value of [`CKF_LIBRARY_CANT_CREATE_OS_THREADS`] - pub fn library_cant_create_os_threads(&self) -> bool { - self.flag(CKF_LIBRARY_CANT_CREATE_OS_THREADS) - } - - /// Sets value of [`CKF_LIBRARY_CANT_CREATE_OS_THREADS`] - pub fn set_library_cant_create_os_threads(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_LIBRARY_CANT_CREATE_OS_THREADS, b); - self - } - - /// Gets value of [`CKF_OS_LOCKING_OK`] - pub fn os_locking_ok(&self) -> bool { - self.flag(CKF_OS_LOCKING_OK) - } - - /// Sets value of [`CKF_OS_LOCKING_OK`] - pub fn set_os_locking_ok(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_OS_LOCKING_OK, b); - self - } -} - -impl std::fmt::Display for InitializeFlags { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let flags = vec![CKF_LIBRARY_CANT_CREATE_OS_THREADS, CKF_OS_LOCKING_OK]; - self.stringify_fmt(f, flags) - } -} - -impl From for CK_FLAGS { - fn from(flags: InitializeFlags) -> Self { - flags.flags - } -} - -impl TryFrom for InitializeFlags { - type Error = Error; - - fn try_from(flags: CK_FLAGS) -> Result { - if flags & !(CKF_OS_LOCKING_OK | CKF_LIBRARY_CANT_CREATE_OS_THREADS) != 0 { - Err(Error::InvalidValue) - } else { - Ok(Self { flags }) - } - } -} - -#[derive(Debug, Default, Clone, Copy)] -/// Collection of flags defined for [`CK_MECHANISM_INFO`] -pub struct MechanismFlags { - flags: CK_FLAGS, -} - -impl Flags for MechanismFlags { - type FlagType = CK_FLAGS; - - fn flag_value(&self) -> Self::FlagType { - self.flags - } - - fn flag(&self, flag: Self::FlagType) -> bool { - self.flag_value() & flag == flag - } - - fn set_flag(&mut self, flag: Self::FlagType, b: bool) { - if b { - self.flags |= flag; - } else { - self.flags &= !flag; - } - } - - fn stringify_flag(flag: CK_FLAGS) -> &'static str { - match flag { - CKF_HW => std::stringify!(CKF_HW), - CKF_ENCRYPT => std::stringify!(CKF_ENCRYPT), - CKF_DECRYPT => std::stringify!(CKF_DECRYPT), - CKF_DIGEST => std::stringify!(CKF_DIGEST), - CKF_SIGN => std::stringify!(CKF_SIGN), - CKF_SIGN_RECOVER => std::stringify!(CKF_SIGN_RECOVER), - CKF_VERIFY => std::stringify!(CKF_VERIFY), - CKF_VERIFY_RECOVER => std::stringify!(CKF_VERIFY_RECOVER), - CKF_GENERATE => std::stringify!(CKF_GENERATE), - CKF_GENERATE_KEY_PAIR => std::stringify!(CKF_GENERATE_KEY_PAIR), - CKF_WRAP => std::stringify!(CKF_WRAP), - CKF_UNWRAP => std::stringify!(CKF_UNWRAP), - CKF_DERIVE => std::stringify!(CKF_DERIVE), - CKF_EXTENSION => std::stringify!(CKF_EXTENSION), - CKF_EC_F_P => std::stringify!(CKF_EC_F_P), - CKF_EC_NAMEDCURVE => std::stringify!(CKF_EC_NAMEDCURVE), - CKF_EC_UNCOMPRESS => std::stringify!(CKF_EC_UNCOMPRESS), - CKF_EC_COMPRESS => std::stringify!(CKF_EC_COMPRESS), - _ => "Unknown CK_MECHANISM_INFO flag", - } - } -} - -impl MechanismFlags { - /// Creates a new instance of `MechanismFlags` with no flags set - pub fn new() -> Self { - MechanismFlags::default() - } - - /// Gets value of [`CKF_HW`] - pub fn hardware(&self) -> bool { - self.flag(CKF_HW) - } - - /// Sets value of [`CKF_HW`] - pub fn set_hardware(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_HW, b); - self - } - - /// Gets value of [`CKF_ENCRYPT`] - pub fn encrypt(&self) -> bool { - self.flag(CKF_ENCRYPT) - } - - /// Sets value of [`CKF_ENCRYPT`] - pub fn set_encrypt(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_ENCRYPT, b); - self - } - - /// Gets value of [`CKF_DECRYPT`] - pub fn decrypt(&self) -> bool { - self.flag(CKF_DECRYPT) - } - - /// Sets value of [`CKF_DECRYPT`] - pub fn set_decrypt(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_DECRYPT, b); - self - } - - /// Gets value of [`CKF_DIGEST`] - pub fn digest(&self) -> bool { - self.flag(CKF_DIGEST) - } - - /// Sets value of [`CKF_DIGEST`] - pub fn set_digest(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_DIGEST, b); - self - } - - /// Gets value of [`CKF_SIGN`] - pub fn sign(&self) -> bool { - self.flag(CKF_SIGN) - } - - /// Sets value of [`CKF_SIGN`] - pub fn set_sign(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_SIGN, b); - self - } - - /// Gets value of [`CKF_SIGN_RECOVER`] - pub fn sign_recover(&self) -> bool { - self.flag(CKF_SIGN_RECOVER) - } - - /// Sets value of [`CKF_SIGN_RECOVER`] - pub fn set_sign_recover(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_SIGN_RECOVER, b); - self - } - - /// Gets value of [`CKF_VERIFY`] - pub fn verify(&self) -> bool { - self.flag(CKF_VERIFY) - } - - /// Sets value of [`CKF_VERIFY`] - pub fn set_verify(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_VERIFY, b); - self - } - - /// Gets value of [`CKF_VERIFY_RECOVER`] - pub fn verify_recover(&self) -> bool { - self.flag(CKF_VERIFY_RECOVER) - } - - /// Sets value of [`CKF_VERIFY_RECOVER`] - pub fn set_verify_recover(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_VERIFY_RECOVER, b); - self - } - - /// Gets value of [`CKF_GENERATE`] - pub fn generate(&self) -> bool { - self.flag(CKF_GENERATE) - } - - /// Sets value of [`CKF_GENERATE`] - pub fn set_generate(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_GENERATE, b); - self - } - - /// Gets value of [`CKF_GENERATE_KEY_PAIR`] - pub fn generate_key_pair(&self) -> bool { - self.flag(CKF_GENERATE_KEY_PAIR) - } - - /// Sets value of [`CKF_GENERATE_KEY_PAIR`] - pub fn set_generate_key_pair(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_GENERATE_KEY_PAIR, b); - self - } - - /// Gets value of [`CKF_WRAP`] - pub fn wrap(&self) -> bool { - self.flag(CKF_WRAP) - } - - /// Sets value of [`CKF_WRAP`] - pub fn set_wrap(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_WRAP, b); - self - } - - /// Gets value of [`CKF_UNWRAP`] - pub fn unwrap(&self) -> bool { - self.flag(CKF_UNWRAP) - } - - /// Sets value of [`CKF_UNWRAP`] - pub fn set_unwrap(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_UNWRAP, b); - self - } - - /// Gets value of [`CKF_DERIVE`] - pub fn derive(&self) -> bool { - self.flag(CKF_DERIVE) - } - - /// Sets value of [`CKF_DERIVE`] - pub fn set_derive(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_DERIVE, b); - self - } - - /// Gets value of [`CKF_EXTENSION`] - pub fn extension(&self) -> bool { - self.flag(CKF_EXTENSION) - } - - /// Sets value of [`CKF_EXTENSION`] - pub fn set_extension(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_EXTENSION, b); - self - } - - /// Gets value of [`CKF_EC_F_P`] - pub fn ec_f_p(&self) -> bool { - self.flag(CKF_EC_F_P) - } - - /// Sets value of [`CKF_EC_F_P`] - pub fn set_ec_f_p(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_EC_F_P, b); - self - } - - /// Gets value of [`CKF_EC_NAMEDCURVE`] - pub fn ec_namedcurve(&self) -> bool { - self.flag(CKF_EC_NAMEDCURVE) - } - - /// Sets value of [`CKF_EC_NAMEDCURVE`] - pub fn set_ec_namedcurve(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_EC_NAMEDCURVE, b); - self - } - - /// Gets value of [`CKF_EC_UNCOMPRESS`] - pub fn ec_uncompress(&self) -> bool { - self.flag(CKF_EC_UNCOMPRESS) - } - - /// Sets value of [`CKF_EC_UNCOMPRESS`] - pub fn set_ec_uncompress(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_EC_UNCOMPRESS, b); - self - } - - /// Gets value of [`CKF_EC_COMPRESS`] - pub fn ec_compress(&self) -> bool { - self.flag(CKF_EC_COMPRESS) - } - - /// Sets value of [`CKF_EC_COMPRESS`] - pub fn set_ec_compress(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_EC_COMPRESS, b); - self - } -} - -impl std::fmt::Display for MechanismFlags { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let flags = vec![ - CKF_HW, - CKF_ENCRYPT, - CKF_DECRYPT, - CKF_DIGEST, - CKF_SIGN, - CKF_SIGN_RECOVER, - CKF_VERIFY, - CKF_VERIFY_RECOVER, - CKF_GENERATE, - CKF_GENERATE_KEY_PAIR, - CKF_WRAP, - CKF_UNWRAP, - CKF_DERIVE, - CKF_EXTENSION, - CKF_EC_F_P, - CKF_EC_NAMEDCURVE, - CKF_EC_UNCOMPRESS, - CKF_EC_COMPRESS, - ]; - self.stringify_fmt(f, flags) - } -} - -impl From for CK_FLAGS { - fn from(flags: MechanismFlags) -> Self { - flags.flags - } -} - -impl From for MechanismFlags { - fn from(flags: CK_FLAGS) -> Self { - Self { flags } - } -} - -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] -/// Collection of flags defined for [`CK_SESSION_INFO`] -pub struct SessionFlags { - flags: CK_FLAGS, -} - -impl Flags for SessionFlags { - type FlagType = CK_FLAGS; - - fn flag_value(&self) -> Self::FlagType { - self.flags - } - - fn flag(&self, flag: Self::FlagType) -> bool { - self.flag_value() & flag == flag - } - - fn set_flag(&mut self, flag: Self::FlagType, b: bool) { - if b { - self.flags |= flag; - } else { - self.flags &= !flag; - } - } - - fn stringify_flag(flag: Self::FlagType) -> &'static str { - match flag { - CKF_RW_SESSION => std::stringify!(CKF_RW_SESSION), - CKF_SERIAL_SESSION => std::stringify!(CKF_SERIAL_SESSION), - _ => "Unknown session flag", - } - } -} - -impl SessionFlags { - /// Creates a new instance of `SessionFlags` with no flags set - pub fn new() -> Self { - SessionFlags::default() - } - - /// Gets value of [`CKF_RW_SESSION`] - pub fn rw_session(&self) -> bool { - self.flag(CKF_RW_SESSION) - } - - /// Sets value of [`CKF_RW_SESSION`] - pub fn set_rw_session(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_RW_SESSION, b); - self - } - - /// Gets value of [`CKF_SERIAL_SESSION`] - pub fn serial_session(&self) -> bool { - self.flag(CKF_SERIAL_SESSION) - } - - /// Sets value of [`CKF_SERIAL_SESSION`] - pub fn set_serial_session(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_SERIAL_SESSION, b); - self - } -} - -impl std::fmt::Display for SessionFlags { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let flags = vec![CKF_RW_SESSION, CKF_SERIAL_SESSION]; - self.stringify_fmt(f, flags) - } -} - -impl From for CK_FLAGS { - fn from(flags: SessionFlags) -> Self { - flags.flags - } -} - -impl From for SessionFlags { - fn from(flags: CK_FLAGS) -> Self { - Self { flags } - } -} - -#[derive(Debug, Default, Clone, Copy)] -/// Collection of flags defined for [`CK_SLOT_INFO`] -pub struct SlotFlags { - flags: CK_FLAGS, -} - -impl Flags for SlotFlags { - type FlagType = CK_FLAGS; - - fn flag_value(&self) -> Self::FlagType { - self.flags - } - - fn flag(&self, flag: Self::FlagType) -> bool { - self.flag_value() & flag == flag - } - - fn set_flag(&mut self, flag: Self::FlagType, b: bool) { - if b { - self.flags |= flag; - } else { - self.flags &= !flag; - } - } - - fn stringify_flag(flag: Self::FlagType) -> &'static str { - match flag { - CKF_TOKEN_PRESENT => std::stringify!(CKF_TOKEN_PRESENT), - CKF_REMOVABLE_DEVICE => std::stringify!(CKF_REMOVABLE_DEVICE), - CKF_HW_SLOT => std::stringify!(CKF_HW_SLOT), - _ => "Unknown CK_SLOT_INFO flag", - } - } -} - -impl SlotFlags { - /// Creates a new instance of `SlotFlags` with no flags set - pub fn new() -> Self { - SlotFlags::default() - } - - /// Gets value of [`CKF_TOKEN_PRESENT`] - pub fn token_present(&self) -> bool { - self.flag(CKF_TOKEN_PRESENT) - } - - /// Sets value of [`CKF_TOKEN_PRESENT`] - pub fn set_token_present(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_TOKEN_PRESENT, b); - self - } - - /// Gets value of [`CKF_REMOVABLE_DEVICE`] - pub fn removable_device(&self) -> bool { - self.flag(CKF_REMOVABLE_DEVICE) - } - - /// Sets value of [`CKF_REMOVABLE_DEVICE`] - pub fn set_removable_device(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_REMOVABLE_DEVICE, b); - self - } - - /// Gets value of [`CKF_HW_SLOT`] - pub fn hardware_slot(&self) -> bool { - self.flag(CKF_HW_SLOT) - } - - /// Sets value of [`CKF_HW_SLOT`] - pub fn set_hardware_slot(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_HW_SLOT, b); - self - } -} - -impl std::fmt::Display for SlotFlags { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let flags = vec![CKF_TOKEN_PRESENT, CKF_REMOVABLE_DEVICE, CKF_HW_SLOT]; - self.stringify_fmt(f, flags) - } -} - -impl From for CK_FLAGS { - fn from(flags: SlotFlags) -> Self { - flags.flags - } -} - -impl From for SlotFlags { - fn from(flags: CK_FLAGS) -> Self { - Self { flags } - } -} - -#[derive(Debug, Default, Clone, Copy)] -/// Collection of flags defined for [`CK_TOKEN_INFO`] -pub struct TokenFlags { - flags: CK_FLAGS, -} - -impl Flags for TokenFlags { - type FlagType = CK_FLAGS; - - fn flag_value(&self) -> Self::FlagType { - self.flags - } - - fn flag(&self, flag: Self::FlagType) -> bool { - self.flag_value() & flag == flag - } - - fn set_flag(&mut self, flag: Self::FlagType, b: bool) { - if b { - self.flags |= flag; - } else { - self.flags &= !flag; - } - } - - fn stringify_flag(flag: Self::FlagType) -> &'static str { - match flag { - CKF_RNG => std::stringify!(CKF_RNG), - CKF_WRITE_PROTECTED => std::stringify!(CKF_WRITE_PROTECTED), - CKF_LOGIN_REQUIRED => std::stringify!(CKF_LOGIN_REQUIRED), - CKF_USER_PIN_INITIALIZED => std::stringify!(CKF_USER_PIN_INITIALIZED), - CKF_RESTORE_KEY_NOT_NEEDED => std::stringify!(CKF_RESTORE_KEY_NOT_NEEDED), - CKF_CLOCK_ON_TOKEN => std::stringify!(CKF_CLOCK_ON_TOKEN), - CKF_PROTECTED_AUTHENTICATION_PATH => std::stringify!(CKF_PROTECTED_AUTHENTICATION_PATH), - CKF_DUAL_CRYPTO_OPERATIONS => std::stringify!(CKF_DUAL_CRYPTO_OPERATIONS), - CKF_TOKEN_INITIALIZED => std::stringify!(CKF_TOKEN_INITIALIZED), - CKF_SECONDARY_AUTHENTICATION => std::stringify!(CKF_SECONDARY_AUTHENTICATION), - CKF_USER_PIN_COUNT_LOW => std::stringify!(CKF_USER_PIN_COUNT_LOW), - CKF_USER_PIN_FINAL_TRY => std::stringify!(CKF_USER_PIN_FINAL_TRY), - CKF_USER_PIN_LOCKED => std::stringify!(CKF_USER_PIN_LOCKED), - CKF_USER_PIN_TO_BE_CHANGED => std::stringify!(CKF_USER_PIN_TO_BE_CHANGED), - CKF_SO_PIN_COUNT_LOW => std::stringify!(CKF_SO_PIN_COUNT_LOW), - CKF_SO_PIN_FINAL_TRY => std::stringify!(CKF_SO_PIN_FINAL_TRY), - CKF_SO_PIN_LOCKED => std::stringify!(CKF_SO_PIN_LOCKED), - CKF_SO_PIN_TO_BE_CHANGED => std::stringify!(CKF_SO_PIN_TO_BE_CHANGED), - _ => "Unknown CK_TOKEN_INFO flag", - } - } -} - -impl TokenFlags { - /// Creates a new instance of `TokenFlags` with no flags set - pub fn new() -> Self { - TokenFlags::default() - } - - /// Gets value of [`CKF_RNG`] - pub fn random_number_generator(&self) -> bool { - self.flag(CKF_RNG) - } - - /// Sets value of [`CKF_RNG`] - pub fn set_random_number_generator(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_RNG, b); - self - } - - /// Gets value of [`CKF_WRITE_PROTECTED`] - pub fn write_protected(&self) -> bool { - self.flag(CKF_WRITE_PROTECTED) - } - - /// Sets value of [`CKF_WRITE_PROTECTED`] - pub fn set_write_protected(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_WRITE_PROTECTED, b); - self - } - - /// Gets value of [`CKF_LOGIN_REQUIRED`] - pub fn login_required(&self) -> bool { - self.flag(CKF_LOGIN_REQUIRED) - } - - /// Sets value of [`CKF_LOGIN_REQUIRED`] - pub fn set_login_required(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_LOGIN_REQUIRED, b); - self - } - - /// Gets value of [`CKF_USER_PIN_INITIALIZED`] - pub fn user_pin_initialized(&self) -> bool { - self.flag(CKF_USER_PIN_INITIALIZED) - } - - /// Sets value of [`CKF_USER_PIN_INITIALIZED`] - pub fn set_user_pin_initialized(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_USER_PIN_INITIALIZED, b); - self - } - - /// Gets value of [`CKF_RESTORE_KEY_NOT_NEEDED`] - pub fn restore_key_not_needed(&self) -> bool { - self.flag(CKF_RESTORE_KEY_NOT_NEEDED) - } - - /// Sets value of [`CKF_RESTORE_KEY_NOT_NEEDED`] - pub fn set_restore_key_not_needed(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_RESTORE_KEY_NOT_NEEDED, b); - self - } - - /// Gets value of [`CKF_CLOCK_ON_TOKEN`] - pub fn clock_on_token(&self) -> bool { - self.flag(CKF_CLOCK_ON_TOKEN) - } - - /// Sets value of [`CKF_CLOCK_ON_TOKEN`] - pub fn set_clock_on_token(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_CLOCK_ON_TOKEN, b); - self - } - - /// Gets value of [`CKF_PROTECTED_AUTHENTICATION_PATH`] - pub fn protected_authentication_path(&self) -> bool { - self.flag(CKF_PROTECTED_AUTHENTICATION_PATH) - } - - /// Sets value of [`CKF_PROTECTED_AUTHENTICATION_PATH`] - pub fn set_protected_authentication_path(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_PROTECTED_AUTHENTICATION_PATH, b); - self - } - - /// Gets value of [`CKF_DUAL_CRYPTO_OPERATIONS`] - pub fn dual_crypto_operations(&self) -> bool { - self.flag(CKF_DUAL_CRYPTO_OPERATIONS) - } - - /// Sets value of [`CKF_DUAL_CRYPTO_OPERATIONS`] - pub fn set_dual_crypto_operations(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_DUAL_CRYPTO_OPERATIONS, b); - self - } - - /// Gets value of [`CKF_TOKEN_INITIALIZED`] - pub fn token_initialized(&self) -> bool { - self.flag(CKF_TOKEN_INITIALIZED) - } - - /// Sets value of [`CKF_TOKEN_INITIALIZED`] - pub fn set_token_initialized(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_TOKEN_INITIALIZED, b); - self - } - - /// Gets value of [`CKF_SECONDARY_AUTHENTICATION`] - pub fn secondary_authentication(&self) -> bool { - self.flag(CKF_SECONDARY_AUTHENTICATION) - } - - /// Sets value of [`CKF_SECONDARY_AUTHENTICATION`] - pub fn set_secondary_authentication(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_SECONDARY_AUTHENTICATION, b); - self - } - - /// Gets value of [`CKF_USER_PIN_COUNT_LOW`] - pub fn user_pin_count_low(&self) -> bool { - self.flag(CKF_USER_PIN_COUNT_LOW) - } - - /// Sets value of [`CKF_USER_PIN_COUNT_LOW`] - pub fn set_user_pin_count_low(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_USER_PIN_COUNT_LOW, b); - self - } - - /// Gets value of [`CKF_USER_PIN_FINAL_TRY`] - pub fn user_pin_final_try(&self) -> bool { - self.flag(CKF_USER_PIN_FINAL_TRY) - } - - /// Sets value of [`CKF_USER_PIN_FINAL_TRY`] - pub fn set_user_pin_final_try(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_USER_PIN_FINAL_TRY, b); - self - } - - /// Gets value of [`CKF_USER_PIN_LOCKED`] - pub fn user_pin_locked(&self) -> bool { - self.flag(CKF_USER_PIN_LOCKED) - } - - /// Sets value of [`CKF_USER_PIN_LOCKED`] - pub fn set_user_pin_locked(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_USER_PIN_LOCKED, b); - self - } - - /// Gets value of [`CKF_USER_PIN_TO_BE_CHANGED`] - pub fn user_pin_to_be_changed(&self) -> bool { - self.flag(CKF_USER_PIN_TO_BE_CHANGED) - } - - /// Sets value of [`CKF_USER_PIN_TO_BE_CHANGED`] - pub fn set_user_pin_to_be_changed(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_USER_PIN_TO_BE_CHANGED, b); - self - } - - /// Gets value of [`CKF_SO_PIN_COUNT_LOW`] - pub fn so_pin_count_low(&self) -> bool { - self.flag(CKF_SO_PIN_COUNT_LOW) - } - - /// Sets value of [`CKF_SO_PIN_COUNT_LOW`] - pub fn set_so_pin_count_low(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_SO_PIN_COUNT_LOW, b); - self - } - - /// Gets value of [`CKF_SO_PIN_FINAL_TRY`] - pub fn so_pin_final_try(&self) -> bool { - self.flag(CKF_SO_PIN_FINAL_TRY) - } - - /// Sets value of [`CKF_SO_PIN_FINAL_TRY`] - pub fn set_so_pin_final_try(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_SO_PIN_FINAL_TRY, b); - self - } - - /// Gets value of [`CKF_SO_PIN_LOCKED`] - pub fn so_pin_locked(&self) -> bool { - self.flag(CKF_SO_PIN_LOCKED) - } - - /// Sets value of [`CKF_SO_PIN_LOCKED`] - pub fn set_so_pin_locked(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_SO_PIN_LOCKED, b); - self - } - - /// Gets value of [`CKF_SO_PIN_TO_BE_CHANGED`] - pub fn so_pin_to_be_changed(&self) -> bool { - self.flag(CKF_SO_PIN_TO_BE_CHANGED) - } - - /// Sets value of [`CKF_SO_PIN_TO_BE_CHANGED`] - pub fn set_so_pin_to_be_changed(&mut self, b: bool) -> &mut Self { - self.set_flag(CKF_SO_PIN_TO_BE_CHANGED, b); - self - } -} - -impl std::fmt::Display for TokenFlags { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let flags = vec![ - CKF_RNG, - CKF_WRITE_PROTECTED, - CKF_LOGIN_REQUIRED, - CKF_USER_PIN_INITIALIZED, - CKF_RESTORE_KEY_NOT_NEEDED, - CKF_CLOCK_ON_TOKEN, - CKF_PROTECTED_AUTHENTICATION_PATH, - CKF_DUAL_CRYPTO_OPERATIONS, - CKF_TOKEN_INITIALIZED, - CKF_SECONDARY_AUTHENTICATION, - CKF_USER_PIN_COUNT_LOW, - CKF_USER_PIN_FINAL_TRY, - CKF_USER_PIN_LOCKED, - CKF_USER_PIN_TO_BE_CHANGED, - CKF_SO_PIN_COUNT_LOW, - CKF_SO_PIN_FINAL_TRY, - CKF_SO_PIN_LOCKED, - CKF_SO_PIN_TO_BE_CHANGED, - ]; - self.stringify_fmt(f, flags) - } -} - -impl From for CK_FLAGS { - fn from(flags: TokenFlags) -> Self { - flags.flags - } -} - -impl From for TokenFlags { - fn from(flags: CK_FLAGS) -> Self { - Self { flags } - } -} - -#[repr(u8)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -/// Byte-sized boolean -pub enum Bbool { - /// False value - False = 0, - /// True value - True = 1, -} - -impl TryFrom<&[u8]> for Bbool { - type Error = Error; - - fn try_from(slice: &[u8]) -> Result { - CK_BBOOL::from_ne_bytes(slice.try_into()?).try_into() - } -} - -impl From for CK_BBOOL { - fn from(bbool: Bbool) -> Self { - bbool as CK_BBOOL - } -} - -impl From for Bbool { - fn from(val: bool) -> Self { - if val { - Bbool::True - } else { - Bbool::False - } - } -} - -impl From for bool { - fn from(val: Bbool) -> Self { - match val { - Bbool::False => false, - Bbool::True => true, - } - } -} - -impl TryFrom for Bbool { - type Error = Error; - - fn try_from(bbool: CK_BBOOL) -> Result { - match bbool { - CK_FALSE => Ok(Bbool::False), - CK_TRUE => Ok(Bbool::True), - other => { - error!("Bbool value {} is invalid.", other); - Err(Error::InvalidValue) - } - } - } -} - -#[derive(Debug, Copy, Clone)] -#[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 } - } -} - -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: {}\nDay: {}\nYear: {}", month, day, year) - } -} - -#[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 { - /// 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, - } - } -} - -#[derive(Debug, Clone, Copy)] -/// Type identifying the PKCS#11 library information -pub struct Info { - val: CK_INFO, -} - -impl Info { - pub(crate) fn new(val: CK_INFO) -> Self { - Self { val } - } - - /// Returns the version of Cryptoki that the library is compatible with - pub fn cryptoki_version(&self) -> Version { - self.val.cryptokiVersion.into() - } - - /// Returns the flags of the library (should be zero!) - pub fn flags(&self) -> CK_FLAGS { - self.val.flags - } - - /// Returns the description of the library - pub fn library_description(&self) -> String { - string_from_blank_padded(&self.val.libraryDescription) - } - - /// Returns the version of the library - pub fn library_version(&self) -> Version { - self.val.libraryVersion.into() - } - - /// Returns the manufacturer of the library - pub fn manufacturer_id(&self) -> String { - string_from_blank_padded(&self.val.manufacturerID) - } -} - -impl Deref for Info { - type Target = CK_INFO; - - fn deref(&self) -> &Self::Target { - &self.val - } -} - -impl From for CK_INFO { - fn from(info: Info) -> Self { - *info - } -} diff --git a/cryptoki/src/types/session.rs b/cryptoki/src/types/session.rs deleted file mode 100644 index 80e818fa..00000000 --- a/cryptoki/src/types/session.rs +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2021 Contributors to the Parsec project. -// SPDX-License-Identifier: Apache-2.0 -//! Session types - -use crate::types::slot_token::Slot; -use crate::types::{SessionFlags, Ulong}; -use crate::Pkcs11; -use cryptoki_sys::*; -use log::error; -use std::convert::TryInto; -use std::fmt::Formatter; -use std::ops::Deref; - -/// 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<'a> { - handle: CK_SESSION_HANDLE, - client: &'a Pkcs11, - // This is not used but to prevent Session to automatically implement Send and Sync - _guard: *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<'a> Send for Session<'a> {} - -impl<'a> Session<'a> { - pub(crate) fn new(handle: CK_SESSION_HANDLE, client: &'a Pkcs11) -> Self { - Session { - handle, - client, - _guard: std::ptr::null_mut::(), - } - } - - pub(crate) fn handle(&self) -> CK_SESSION_HANDLE { - self.handle - } - - pub(crate) fn client(&self) -> &Pkcs11 { - self.client - } -} - -impl Drop for Session<'_> { - fn drop(&mut self) { - if let Err(e) = self.close_private() { - error!("Failed to close session: {}", e); - } - } -} - -/// 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, - } - } -} - -/// Represents the state of a session -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct SessionState { - val: CK_STATE, -} - -impl SessionState { - /// Read-only public session - pub const RO_PUBLIC_SESSION: SessionState = SessionState { - val: CKS_RO_PUBLIC_SESSION, - }; - - /// Read-only user access - pub const RO_USER_FUNCTIONS: SessionState = SessionState { - val: CKS_RO_USER_FUNCTIONS, - }; - - /// Read/write public session - pub const RW_PUBLIC_SESSION: SessionState = SessionState { - val: CKS_RW_PUBLIC_SESSION, - }; - - /// Read/write user access - pub const RW_USER_FUNCTIONS: SessionState = SessionState { - val: CKS_RW_USER_FUNCTIONS, - }; - - /// Read/write SO access - pub const RW_SO_FUNCTIONS: SessionState = SessionState { - val: CKS_RW_SO_FUNCTIONS, - }; - - /// Stringifies the value of a [CK_STATE] - pub(crate) fn stringify(state: CK_STATE) -> &'static str { - match state { - CKS_RO_PUBLIC_SESSION => stringify!(CKS_RO_PUBLIC_SESSION), - CKS_RO_USER_FUNCTIONS => stringify!(CKS_RO_USER_FUNCTIONS), - CKS_RW_PUBLIC_SESSION => stringify!(CKS_RW_PUBLIC_SESSION), - CKS_RW_USER_FUNCTIONS => stringify!(CKS_RW_USER_FUNCTIONS), - CKS_RW_SO_FUNCTIONS => stringify!(CKS_RW_SO_FUNCTIONS), - _ => "Unknown state value", - } - } -} - -impl Deref for SessionState { - type Target = CK_STATE; - - fn deref(&self) -> &Self::Target { - &self.val - } -} - -impl From for CK_STATE { - fn from(session_state: SessionState) -> Self { - *session_state - } -} - -impl From for SessionState { - fn from(val: CK_STATE) -> Self { - Self { val } - } -} - -impl std::fmt::Display for SessionState { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", SessionState::stringify(self.val)) - } -} - -/// Type identifying the session information -#[derive(Copy, Clone, Debug)] -pub struct SessionInfo { - val: CK_SESSION_INFO, -} - -impl SessionInfo { - pub(crate) fn new(val: CK_SESSION_INFO) -> Self { - Self { val } - } - - /// Returns an error code defined by the cryptographic device - pub fn device_error(&self) -> Ulong { - self.val.ulDeviceError.into() - } - - /// Returns the flags for this session - pub fn flags(&self) -> SessionFlags { - self.val.flags.into() - } - - /// Returns the state of the session - pub fn session_state(&self) -> SessionState { - self.val.state.into() - } - - /// Returns the slot the session is on - pub fn slot_id(&self) -> Slot { - // The unwrap should not fail as `slotID` is a `CK_SLOT_ID ` which is the same type as - // `slot_id` within the `Slot` structure - self.val.slotID.try_into().unwrap() - } -} diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 17e50b10..34a65cef 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -4,12 +4,10 @@ mod common; use crate::common::{SO_PIN, USER_PIN}; use common::init_pins; -use cryptoki::types::function::RvError; -use cryptoki::types::mechanism::Mechanism; -use cryptoki::types::object::{Attribute, AttributeInfo, AttributeType, KeyType, ObjectClass}; -use cryptoki::types::session::{SessionState, UserType}; -use cryptoki::types::SessionFlags; -use cryptoki::Error; +use cryptoki::error::{Error, RvError}; +use cryptoki::mechanism::Mechanism; +use cryptoki::object::{Attribute, AttributeInfo, AttributeType, KeyType, ObjectClass}; +use cryptoki::session::{SessionFlags, SessionState, UserType}; use serial_test::serial; use std::collections::HashMap; use std::sync::Arc; @@ -191,7 +189,7 @@ fn derive_key() -> Result<()> { panic!("Expected EC point attribute."); }; - use cryptoki::types::mechanism::elliptic_curve::*; + use cryptoki::mechanism::elliptic_curve::*; use std::convert::TryInto; let params = Ecdh1DeriveParams { @@ -472,7 +470,9 @@ fn get_session_info_test() -> Result<()> { let mut flags = SessionFlags::new(); // Check that OpenSession errors when CKF_SERIAL_SESSION is not set - if let Err(cryptoki::Error::Pkcs11(rv_error)) = pkcs11.open_session_no_callback(slot, flags) { + if let Err(cryptoki::error::Error::Pkcs11(rv_error)) = + pkcs11.open_session_no_callback(slot, flags) + { assert_eq!(rv_error, RvError::SessionParallelNotSupported); } else { panic!("Should error when CKF_SERIAL_SESSION is not set"); @@ -498,7 +498,9 @@ fn get_session_info_test() -> Result<()> { SessionState::RO_USER_FUNCTIONS ); session.logout()?; - if let Err(cryptoki::Error::Pkcs11(rv_error)) = session.login(UserType::So, Some(SO_PIN)) { + if let Err(cryptoki::error::Error::Pkcs11(rv_error)) = + session.login(UserType::So, Some(SO_PIN)) + { assert_eq!(rv_error, RvError::SessionReadOnlyExists) } else { panic!("Should error when attempting to log in as CKU_SO on a read-only session"); diff --git a/cryptoki/tests/common.rs b/cryptoki/tests/common.rs index 7a9e171c..20e83047 100644 --- a/cryptoki/tests/common.rs +++ b/cryptoki/tests/common.rs @@ -1,10 +1,9 @@ // Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 -use cryptoki::types::locking::CInitializeArgs; -use cryptoki::types::session::UserType; -use cryptoki::types::slot_token::Slot; -use cryptoki::types::SessionFlags; -use cryptoki::Pkcs11; +use cryptoki::context::{CInitializeArgs, Pkcs11}; +use cryptoki::session::SessionFlags; +use cryptoki::session::UserType; +use cryptoki::slot::Slot; use std::env; // The default user pin