Skip to content

Commit

Permalink
Merge pull request #56 from vkkoskie/module-tree-hygiene
Browse files Browse the repository at this point in the history
Module tree hygiene
  • Loading branch information
mike-boquard authored Nov 4, 2021
2 parents c05e91f + 7919c61 commit abd872a
Show file tree
Hide file tree
Showing 45 changed files with 3,102 additions and 2,773 deletions.
2 changes: 1 addition & 1 deletion cryptoki/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
99 changes: 99 additions & 0 deletions cryptoki/src/context/flags.rs
Original file line number Diff line number Diff line change
@@ -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<InitializeFlags> for CK_FLAGS {
fn from(flags: InitializeFlags) -> Self {
flags.flags
}
}

impl TryFrom<CK_FLAGS> for InitializeFlags {
type Error = Error;

fn try_from(flags: CK_FLAGS) -> Result<Self> {
if flags & !(CKF_OS_LOCKING_OK | CKF_LIBRARY_CANT_CREATE_OS_THREADS) != 0 {
Err(Error::InvalidValue)
} else {
Ok(Self { flags })
}
}
}
39 changes: 39 additions & 0 deletions cryptoki/src/context/general_purpose.rs
Original file line number Diff line number Diff line change
@@ -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<Info> {
let mut info = CK_INFO::default();
unsafe {
Rv::from(get_pkcs11!(ctx, C_GetInfo)(&mut info)).into_result()?;
Ok(Info::new(info))
}
}
59 changes: 59 additions & 0 deletions cryptoki/src/context/info.rs
Original file line number Diff line number Diff line change
@@ -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<Info> for CK_INFO {
fn from(info: Info) -> Self {
*info
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
137 changes: 137 additions & 0 deletions cryptoki/src/context/mod.rs
Original file line number Diff line number Diff line change
@@ -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<P>(filename: P) -> Result<Self>
where
P: AsRef<Path>,
{
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<Info> {
general_purpose::get_library_info(self)
}

/// Get all slots available with a token
pub fn get_slots_with_token(&self) -> Result<Vec<Slot>> {
slot_token_management::get_slots_with_token(self)
}

/// Get all slots available with a token
pub fn get_slots_with_initialized_token(&self) -> Result<Vec<Slot>> {
slot_token_management::get_slots_with_initialized_token(self)
}

/// Get all slots
pub fn get_all_slots(&self) -> Result<Vec<Slot>> {
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<SlotInfo> {
slot_token_management::get_slot_info(self, slot)
}

/// Returns information about a specific token
pub fn get_token_info(&self, slot: Slot) -> Result<TokenInfo> {
slot_token_management::get_token_info(self, slot)
}

/// Get all mechanisms support by a slot
pub fn get_mechanism_list(&self, slot: Slot) -> Result<Vec<MechanismType>> {
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<MechanismInfo> {
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> {
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);
}
}
}
33 changes: 33 additions & 0 deletions cryptoki/src/context/session_management.rs
Original file line number Diff line number Diff line change
@@ -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<Session> {
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))
}
Loading

0 comments on commit abd872a

Please sign in to comment.