Files
yubikey-piv-pkcs11/native-pkcs11/src/lib.rs

1605 lines
47 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![allow(non_snake_case)]
#![allow(clippy::missing_safety_doc)]
#![deny(unsafe_op_in_unsafe_fn)]
use std::{
cmp,
slice,
sync::{
atomic::{AtomicBool, Ordering},
Once,
},
};
use tracing::metadata::LevelFilter;
use tracing_error::ErrorLayer;
use tracing_subscriber::{EnvFilter, fmt::format::FmtSpan, prelude::*, Registry};
use native_pkcs11_core::{
attribute::{Attribute, Attributes},
mechanism::{parse_mechanism, SUPPORTED_SIGNATURE_MECHANISMS},
object::{self, Object},
};
pub use native_pkcs11_core::Error;
use native_pkcs11_traits::backend;
use pkcs11_sys::*;
// Export necessary items for registering a custom Backend.
pub use pkcs11_sys::{CK_FUNCTION_LIST, CK_FUNCTION_LIST_PTR_PTR, CK_RV, CKR_OK};
use crate::{
sessions::{FindContext, SignContext},
utils::right_pad_string_to_array,
};
mod object_store;
mod sessions;
mod utils;
const LIBRARY_DESCRIPTION: &[u8; 32] = b" ";
const MANUFACTURER_ID: &[u8; 32] = b"hatter ";
const SLOT_DESCRIPTION: &[u8; 64] =
b"Platform Cryptography Support ";
const SLOT_ID: CK_SLOT_ID = 1;
const TOKEN_MODEL: &[u8; 16] = b"hardware ";
const TOKEN_SERIAL_NUMBER: &[u8; 16] = b"0000000000000000";
static INITIALIZED: AtomicBool = AtomicBool::new(false);
type Result = std::result::Result<(), Error>;
fn result_to_rv<F>(f: F) -> CK_RV
where
F: FnOnce() -> Result,
{
match f() {
Ok(()) => CKR_OK,
Err(e) => {
tracing::error!(%e);
e.into()
}
}
}
macro_rules! cryptoki_fn {
(fn $name:ident ( $($arg:ident : $type:ty),* $(,)?) $body:block) => {
#[tracing::instrument]
#[no_mangle]
pub extern "C" fn $name($($arg: $type),*) -> CK_RV {
// TODO(bweeks): should this be `expr` instead of `block`?
result_to_rv(|| $body)
}
};
(unsafe fn $name:ident ( $($arg:ident : $type:ty),* $(,)?) $body:block) => {
#[tracing::instrument]
#[no_mangle]
pub unsafe extern "C" fn $name($($arg: $type),*) -> CK_RV {
// TODO(bweeks): should this be `expr` instead of `block`?
result_to_rv(|| $body)
}
};
}
macro_rules! cryptoki_fn_not_supported {
($name:ident, $($arg:ident: $type:ty),*) => {
cryptoki_fn!(fn $name($($arg: $type),*) {Err(Error::FunctionNotSupported)});
};
}
macro_rules! not_null {
($ptr:expr) => {
if $ptr.is_null() {
return Err(Error::ArgumentsBad);
}
};
}
macro_rules! initialized {
() => {
if INITIALIZED.load(Ordering::SeqCst) == false {
return Err(Error::CryptokiNotInitialized);
}
};
}
macro_rules! valid_session {
($handle:expr) => {
if !sessions::exists($handle) {
return Err(Error::SessionHandleInvalid($handle));
}
};
}
macro_rules! valid_slot {
($id:expr) => {
if $id != SLOT_ID {
return Err(Error::SlotIdInvalid($id));
}
};
}
pub static mut FUNC_LIST: CK_FUNCTION_LIST = CK_FUNCTION_LIST {
// In this structure version is the cryptoki specification version number. The major and minor
// versions must be set to 0x02 and 0x28 indicating a version 2.40 compatible structure.
version: CK_VERSION { major: 2, minor: 4 },
C_Initialize: Some(C_Initialize),
C_Finalize: Some(C_Finalize),
C_GetInfo: Some(C_GetInfo),
C_GetFunctionList: Some(C_GetFunctionList),
C_GetSlotList: Some(C_GetSlotList),
C_GetSlotInfo: Some(C_GetSlotInfo),
C_GetTokenInfo: Some(C_GetTokenInfo),
C_GetMechanismList: Some(C_GetMechanismList),
C_GetMechanismInfo: Some(C_GetMechanismInfo),
C_InitToken: Some(C_InitToken),
C_InitPIN: Some(C_InitPIN),
C_SetPIN: Some(C_SetPIN),
C_OpenSession: Some(C_OpenSession),
C_CloseSession: Some(C_CloseSession),
C_CloseAllSessions: Some(C_CloseAllSessions),
C_GetSessionInfo: Some(C_GetSessionInfo),
C_GetOperationState: Some(C_GetOperationState),
C_SetOperationState: Some(C_SetOperationState),
C_Login: Some(C_Login),
C_Logout: Some(C_Logout),
C_CreateObject: Some(C_CreateObject),
C_CopyObject: Some(C_CopyObject),
C_DestroyObject: Some(C_DestroyObject),
C_GetObjectSize: Some(C_GetObjectSize),
C_GetAttributeValue: Some(C_GetAttributeValue),
C_SetAttributeValue: Some(C_SetAttributeValue),
C_FindObjectsInit: Some(C_FindObjectsInit),
C_FindObjects: Some(C_FindObjects),
C_FindObjectsFinal: Some(C_FindObjectsFinal),
C_EncryptInit: Some(C_EncryptInit),
C_Encrypt: Some(C_Encrypt),
C_EncryptUpdate: Some(C_EncryptUpdate),
C_EncryptFinal: Some(C_EncryptFinal),
C_DecryptInit: Some(C_DecryptInit),
C_Decrypt: Some(C_Decrypt),
C_DecryptUpdate: Some(C_DecryptUpdate),
C_DecryptFinal: Some(C_DecryptFinal),
C_DigestInit: Some(C_DigestInit),
C_Digest: Some(C_Digest),
C_DigestUpdate: Some(C_DigestUpdate),
C_DigestKey: Some(C_DigestKey),
C_DigestFinal: Some(C_DigestFinal),
C_SignInit: Some(C_SignInit),
C_Sign: Some(C_Sign),
C_SignUpdate: Some(C_SignUpdate),
C_SignFinal: Some(C_SignFinal),
C_SignRecoverInit: Some(C_SignRecoverInit),
C_SignRecover: Some(C_SignRecover),
C_VerifyInit: Some(C_VerifyInit),
C_Verify: Some(C_Verify),
C_VerifyUpdate: Some(C_VerifyUpdate),
C_VerifyFinal: Some(C_VerifyFinal),
C_VerifyRecoverInit: Some(C_VerifyRecoverInit),
C_VerifyRecover: Some(C_VerifyRecover),
C_DigestEncryptUpdate: Some(C_DigestEncryptUpdate),
C_DecryptDigestUpdate: Some(C_DecryptDigestUpdate),
C_SignEncryptUpdate: Some(C_SignEncryptUpdate),
C_DecryptVerifyUpdate: Some(C_DecryptVerifyUpdate),
C_GenerateKey: Some(C_GenerateKey),
C_GenerateKeyPair: Some(C_GenerateKeyPair),
C_WrapKey: Some(C_WrapKey),
C_UnwrapKey: Some(C_UnwrapKey),
C_DeriveKey: Some(C_DeriveKey),
C_SeedRandom: Some(C_SeedRandom),
C_GenerateRandom: Some(C_GenerateRandom),
C_GetFunctionStatus: Some(C_GetFunctionStatus),
C_CancelFunction: Some(C_CancelFunction),
C_WaitForSlotEvent: Some(C_WaitForSlotEvent),
};
static TRACING_INIT: Once = Once::new();
cryptoki_fn!(
fn C_Initialize(pInitArgs: CK_VOID_PTR) {
TRACING_INIT.call_once(|| {
let env_filter = EnvFilter::builder()
.with_default_directive(LevelFilter::WARN.into())
.from_env_lossy();
let force_stderr = std::env::var("NATIVE_PKCS11_LOG_STDERR").is_ok();
if !force_stderr {
if let Ok(journald_layer) = tracing_journald::layer() {
_ = Registry::default()
.with(journald_layer.with_syslog_identifier("native-pkcs11".into()))
.with(env_filter)
.with(ErrorLayer::default())
.try_init();
return;
}
}
_ = Registry::default()
.with(
tracing_subscriber::fmt::layer()
.with_writer(std::io::stderr)
.with_span_events(FmtSpan::ENTER),
)
.with(env_filter)
.with(ErrorLayer::default())
.try_init();
});
if !pInitArgs.is_null() {
let args = unsafe { *(pInitArgs as CK_C_INITIALIZE_ARGS_PTR) };
if !args.pReserved.is_null() {
return Err(Error::ArgumentsBad);
}
}
if INITIALIZED.swap(true, Ordering::SeqCst) {
return Err(Error::CryptokiAlreadyInitialized);
}
Ok(())
}
);
cryptoki_fn!(
fn C_Finalize(pReserved: CK_VOID_PTR) {
initialized!();
if !pReserved.is_null() {
return Err(Error::ArgumentsBad);
}
INITIALIZED.store(false, Ordering::SeqCst);
Ok(())
}
);
cryptoki_fn!(
unsafe fn C_GetInfo(pInfo: CK_INFO_PTR) {
initialized!();
not_null!(pInfo);
let info = CK_INFO {
cryptokiVersion: CK_VERSION {
major: CRYPTOKI_VERSION_MAJOR,
minor: CRYPTOKI_VERSION_MINOR,
},
manufacturerID: *MANUFACTURER_ID,
flags: 0,
libraryDescription: *LIBRARY_DESCRIPTION,
libraryVersion: CK_VERSION { major: 0, minor: 1 },
};
unsafe { *pInfo = info };
Ok(())
}
);
#[cfg(not(feature = "custom-function-list"))]
cryptoki_fn!(
unsafe fn C_GetFunctionList(ppFunctionList: CK_FUNCTION_LIST_PTR_PTR) {
not_null!(ppFunctionList);
unsafe { *ppFunctionList = std::ptr::addr_of_mut!(FUNC_LIST) };
native_pkcs11_traits::register_backend(Box::new(
native_pkcs11_piv::YubikeyPivBackend {},
));
Ok(())
}
);
cryptoki_fn!(
unsafe fn C_GetSlotList(
_tokenPresent: CK_BBOOL,
pSlotList: CK_SLOT_ID_PTR,
pulCount: CK_ULONG_PTR,
) {
initialized!();
not_null!(pulCount);
if !pSlotList.is_null() {
if unsafe { *pulCount } < 1 {
return Err(Error::BufferTooSmall);
}
// TODO: this should be an array.
unsafe { *pSlotList = SLOT_ID };
}
unsafe { *pulCount = 1 };
Ok(())
}
);
cryptoki_fn!(
unsafe fn C_GetSlotInfo(slotID: CK_SLOT_ID, pInfo: CK_SLOT_INFO_PTR) {
initialized!();
valid_slot!(slotID);
not_null!(pInfo);
let info = CK_SLOT_INFO {
slotDescription: *SLOT_DESCRIPTION,
manufacturerID: *MANUFACTURER_ID,
flags: CKF_TOKEN_PRESENT,
// TODO: populate all fields.
..Default::default()
};
unsafe { *pInfo = info };
Ok(())
}
);
cryptoki_fn!(
unsafe fn C_GetTokenInfo(slotID: CK_SLOT_ID, pInfo: CK_TOKEN_INFO_PTR) {
initialized!();
valid_slot!(slotID);
not_null!(pInfo);
let label = right_pad_string_to_array(backend().name());
let info = CK_TOKEN_INFO {
label,
manufacturerID: *MANUFACTURER_ID,
model: *TOKEN_MODEL,
serialNumber: *TOKEN_SERIAL_NUMBER,
flags: CKF_TOKEN_INITIALIZED | CKF_PROTECTED_AUTHENTICATION_PATH | CKF_WRITE_PROTECTED,
ulMaxSessionCount: CK_UNAVAILABLE_INFORMATION,
ulSessionCount: CK_UNAVAILABLE_INFORMATION,
ulMaxRwSessionCount: CK_UNAVAILABLE_INFORMATION,
ulRwSessionCount: CK_UNAVAILABLE_INFORMATION,
ulTotalPublicMemory: CK_UNAVAILABLE_INFORMATION,
ulFreePublicMemory: CK_UNAVAILABLE_INFORMATION,
ulTotalPrivateMemory: CK_UNAVAILABLE_INFORMATION,
ulFreePrivateMemory: CK_UNAVAILABLE_INFORMATION,
// TODO: populate all fields.
..Default::default()
};
unsafe { *pInfo = info };
Ok(())
}
);
cryptoki_fn!(
unsafe fn C_GetMechanismList(
slotID: CK_SLOT_ID,
pMechanismList: CK_MECHANISM_TYPE_PTR,
pulCount: CK_ULONG_PTR,
) {
initialized!();
not_null!(pulCount);
valid_slot!(slotID);
if !pMechanismList.is_null() {
if (unsafe { *pulCount } as usize) < SUPPORTED_SIGNATURE_MECHANISMS.len() {
unsafe { *pulCount = SUPPORTED_SIGNATURE_MECHANISMS.len() as CK_ULONG };
return Err(Error::BufferTooSmall);
}
unsafe {
slice::from_raw_parts_mut(pMechanismList, SUPPORTED_SIGNATURE_MECHANISMS.len())
}
.copy_from_slice(SUPPORTED_SIGNATURE_MECHANISMS);
}
unsafe { *pulCount = SUPPORTED_SIGNATURE_MECHANISMS.len() as CK_ULONG };
Ok(())
}
);
cryptoki_fn!(
unsafe fn C_GetMechanismInfo(
slotID: CK_SLOT_ID,
mechType: CK_MECHANISM_TYPE,
pInfo: CK_MECHANISM_INFO_PTR,
) {
initialized!();
valid_slot!(slotID);
not_null!(pInfo);
if !SUPPORTED_SIGNATURE_MECHANISMS.contains(&mechType) {
return Err(Error::MechanismInvalid(mechType));
}
let info = CK_MECHANISM_INFO {
flags: CKF_SIGN,
..Default::default()
};
unsafe { *pInfo = info };
Ok(())
}
);
cryptoki_fn!(
fn C_InitToken(
slotID: CK_SLOT_ID,
_pPin: CK_UTF8CHAR_PTR,
_ulPinLen: CK_ULONG,
_pLabel: CK_UTF8CHAR_PTR,
) {
initialized!();
valid_slot!(slotID);
Err(Error::TokenWriteProtected)
}
);
cryptoki_fn!(
fn C_InitPIN(hSession: CK_SESSION_HANDLE, _pPin: CK_UTF8CHAR_PTR, _ulPinLen: CK_ULONG) {
initialized!();
valid_session!(hSession);
Err(Error::TokenWriteProtected)
}
);
cryptoki_fn!(
fn C_SetPIN(
hSession: CK_SESSION_HANDLE,
_pOldPin: CK_UTF8CHAR_PTR,
_ulOldLen: CK_ULONG,
_pNewPin: CK_UTF8CHAR_PTR,
_ulNewLen: CK_ULONG,
) {
initialized!();
valid_session!(hSession);
Err(Error::TokenWriteProtected)
}
);
cryptoki_fn!(
unsafe fn C_OpenSession(
slotID: CK_SLOT_ID,
flags: CK_FLAGS,
_pApplication: CK_VOID_PTR,
_Notify: CK_NOTIFY,
phSession: CK_SESSION_HANDLE_PTR,
) {
initialized!();
valid_slot!(slotID);
not_null!(phSession);
if flags & CKF_SERIAL_SESSION == 0 {
return Err(Error::SessionParallelNotSupported);
}
unsafe { *phSession = sessions::create(flags) };
Ok(())
}
);
cryptoki_fn!(
fn C_CloseSession(hSession: CK_SESSION_HANDLE) {
initialized!();
if sessions::close(hSession) {
return Ok(());
}
Err(Error::SessionHandleInvalid(hSession))
}
);
cryptoki_fn!(
fn C_CloseAllSessions(slotID: CK_SLOT_ID) {
initialized!();
valid_slot!(slotID);
sessions::close_all();
Ok(())
}
);
cryptoki_fn!(
unsafe fn C_GetSessionInfo(hSession: CK_SESSION_HANDLE, pInfo: CK_SESSION_INFO_PTR) {
initialized!();
valid_session!(hSession);
not_null!(pInfo);
let flags = sessions::flags(hSession);
let state = if flags & CKF_RW_SESSION == 0 {
CKS_RO_USER_FUNCTIONS
} else {
CKS_RW_USER_FUNCTIONS
};
let info = CK_SESSION_INFO {
slotID: SLOT_ID,
state,
flags,
ulDeviceError: 0,
};
unsafe { *pInfo = info };
Ok(())
}
);
cryptoki_fn_not_supported!(
C_GetOperationState,
hSession: CK_SESSION_HANDLE,
pOperationState: CK_BYTE_PTR,
pulOperationStateLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_SetOperationState,
hSession: CK_SESSION_HANDLE,
pOperationState: CK_BYTE_PTR,
ulOperationStateLen: CK_ULONG,
hEncryptionKey: CK_OBJECT_HANDLE,
hAuthenticationKey: CK_OBJECT_HANDLE
);
cryptoki_fn!(
fn C_Login(
hSession: CK_SESSION_HANDLE,
_userType: CK_USER_TYPE,
_pPin: CK_UTF8CHAR_PTR,
_ulPinLen: CK_ULONG,
) {
initialized!();
valid_session!(hSession);
Ok(())
}
);
cryptoki_fn!(
fn C_Logout(hSession: CK_SESSION_HANDLE) {
initialized!();
valid_session!(hSession);
Ok(())
}
);
cryptoki_fn_not_supported!(
C_CreateObject,
hSession: CK_SESSION_HANDLE,
pTemplate: CK_ATTRIBUTE_PTR,
ulCount: CK_ULONG,
phObject: CK_OBJECT_HANDLE_PTR
);
cryptoki_fn_not_supported!(
C_CopyObject,
hSession: CK_SESSION_HANDLE,
hObject: CK_OBJECT_HANDLE,
pTemplate: CK_ATTRIBUTE_PTR,
ulCount: CK_ULONG,
phNewObject: CK_OBJECT_HANDLE_PTR
);
cryptoki_fn_not_supported!(
C_DestroyObject,
hSession: CK_SESSION_HANDLE,
hObject: CK_OBJECT_HANDLE
);
cryptoki_fn_not_supported!(
C_GetObjectSize,
hSession: CK_SESSION_HANDLE,
hObject: CK_OBJECT_HANDLE,
pulSize: CK_ULONG_PTR
);
cryptoki_fn!(
unsafe fn C_GetAttributeValue(
hSession: CK_SESSION_HANDLE,
hObject: CK_OBJECT_HANDLE,
pTemplate: CK_ATTRIBUTE_PTR,
ulCount: CK_ULONG,
) {
initialized!();
valid_session!(hSession);
not_null!(pTemplate);
sessions::session(hSession, |_session| -> Result {
let object_store = sessions::OBJECT_STORE.lock().unwrap();
let object = match object_store.get(&hObject) {
Some(object) => object,
None => {
return Err(Error::ObjectHandleInvalid(hObject));
}
};
let template = if ulCount > 0 {
if pTemplate.is_null() {
return Err(Error::ArgumentsBad);
}
unsafe { slice::from_raw_parts_mut(pTemplate, ulCount as usize) }
} else {
&mut []
};
let mut result = Ok(());
for attribute in template.iter_mut() {
let type_ = attribute
.type_
.try_into()
.map_err(|_| Error::AttributeTypeInvalid(attribute.type_))?;
if let Some(value) = object.attribute(type_) {
let value = value.as_raw_value();
attribute.ulValueLen = value.len() as CK_ULONG;
if attribute.pValue.is_null() {
continue;
}
if (attribute.ulValueLen as usize) < value.len() {
result = Err(Error::BufferTooSmall);
continue;
}
unsafe { slice::from_raw_parts_mut(attribute.pValue as *mut u8, value.len()) }
.copy_from_slice(&value);
} else {
attribute.ulValueLen = CK_UNAVAILABLE_INFORMATION;
result = Err(Error::AttributeTypeInvalid(attribute.type_));
}
}
result
})
}
);
cryptoki_fn_not_supported!(
C_SetAttributeValue,
hSession: CK_SESSION_HANDLE,
hObject: CK_OBJECT_HANDLE,
pTemplate: CK_ATTRIBUTE_PTR,
ulCount: CK_ULONG
);
cryptoki_fn!(
unsafe fn C_FindObjectsInit(
hSession: CK_SESSION_HANDLE,
pTemplate: CK_ATTRIBUTE_PTR,
ulCount: CK_ULONG,
) {
initialized!();
valid_session!(hSession);
let template: Attributes = unsafe { slice::from_raw_parts(pTemplate, ulCount as usize) }
.iter()
.map(|attr| (*attr).try_into())
.collect::<native_pkcs11_core::Result<Vec<Attribute>>>()?
.into();
sessions::session(hSession, |session| -> Result {
session.find_ctx = Some(FindContext {
objects: sessions::OBJECT_STORE.lock().unwrap().find(template)?,
});
Ok(())
})
}
);
cryptoki_fn!(
unsafe fn C_FindObjects(
hSession: CK_SESSION_HANDLE,
phObject: CK_OBJECT_HANDLE_PTR,
ulMaxObjectCount: CK_ULONG,
pulObjectCount: CK_ULONG_PTR,
) {
initialized!();
valid_session!(hSession);
not_null!(phObject);
not_null!(pulObjectCount);
sessions::session(hSession, |session| -> Result {
let find_ctx = match &mut session.find_ctx {
Some(find_ctx) => find_ctx,
None => {
unsafe { *pulObjectCount = 0 };
return Err(Error::OperationNotInitialized);
}
};
if find_ctx.objects.is_empty() {
unsafe { *pulObjectCount = 0 };
return Ok(());
}
let max_objects = cmp::min(find_ctx.objects.len(), ulMaxObjectCount as usize);
let output = unsafe { slice::from_raw_parts_mut(phObject, max_objects) };
output.copy_from_slice(
&find_ctx
.objects
.drain(0..max_objects)
.collect::<Vec<CK_OBJECT_HANDLE>>(),
);
unsafe { *pulObjectCount = max_objects as CK_ULONG };
Ok(())
})
}
);
cryptoki_fn!(
fn C_FindObjectsFinal(hSession: CK_SESSION_HANDLE) {
initialized!();
valid_session!(hSession);
sessions::session(hSession, |session| -> Result {
if session.find_ctx.is_none() {
return Err(Error::OperationNotInitialized);
}
session.find_ctx = None;
Ok(())
})
}
);
cryptoki_fn_not_supported!(
C_EncryptInit,
hSession: CK_SESSION_HANDLE,
pMechanism: CK_MECHANISM_PTR,
hKey: CK_OBJECT_HANDLE
);
cryptoki_fn_not_supported!(
C_Encrypt,
hSession: CK_SESSION_HANDLE,
pData: CK_BYTE_PTR,
ulDataLen: CK_ULONG,
pEncryptedData: CK_BYTE_PTR,
pulEncryptedDataLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_EncryptUpdate,
hSession: CK_SESSION_HANDLE,
pPart: CK_BYTE_PTR,
ulPartLen: CK_ULONG,
pEncryptedPart: CK_BYTE_PTR,
pulEncryptedPartLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_EncryptFinal,
hSession: CK_SESSION_HANDLE,
pLastEncryptedPart: CK_BYTE_PTR,
pulLastEncryptedPartLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_DecryptInit,
hSession: CK_SESSION_HANDLE,
pMechanism: CK_MECHANISM_PTR,
hKey: CK_OBJECT_HANDLE
);
cryptoki_fn_not_supported!(
C_Decrypt,
hSession: CK_SESSION_HANDLE,
pEncryptedData: CK_BYTE_PTR,
ulEncryptedDataLen: CK_ULONG,
pData: CK_BYTE_PTR,
pulDataLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_DecryptUpdate,
hSession: CK_SESSION_HANDLE,
pEncryptedPart: CK_BYTE_PTR,
ulEncryptedPartLen: CK_ULONG,
pPart: CK_BYTE_PTR,
pulPartLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_DecryptFinal,
hSession: CK_SESSION_HANDLE,
pLastPart: CK_BYTE_PTR,
pulLastPartLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_DigestInit,
hSession: CK_SESSION_HANDLE,
pMechanism: CK_MECHANISM_PTR
);
cryptoki_fn_not_supported!(
C_Digest,
hSession: CK_SESSION_HANDLE,
pData: CK_BYTE_PTR,
ulDataLen: CK_ULONG,
pDigest: CK_BYTE_PTR,
pulDigestLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_DigestUpdate,
hSession: CK_SESSION_HANDLE,
pPart: CK_BYTE_PTR,
ulPartLen: CK_ULONG
);
cryptoki_fn_not_supported!(
C_DigestKey,
hSession: CK_SESSION_HANDLE,
hKey: CK_OBJECT_HANDLE
);
cryptoki_fn_not_supported!(
C_DigestFinal,
hSession: CK_SESSION_HANDLE,
pDigest: CK_BYTE_PTR,
pulDigestLen: CK_ULONG_PTR
);
cryptoki_fn!(
unsafe fn C_SignInit(
hSession: CK_SESSION_HANDLE,
pMechanism: CK_MECHANISM_PTR,
hKey: CK_OBJECT_HANDLE,
) {
initialized!();
valid_session!(hSession);
not_null!(pMechanism);
sessions::session(hSession, |session| -> Result {
let object_store = sessions::OBJECT_STORE.lock().unwrap();
let private_key = match object_store.get(&hKey) {
Some(Object::PrivateKey(private_key)) => private_key,
Some(_) | None => return Err(Error::KeyHandleInvalid(hKey)),
};
let mechanism = unsafe { parse_mechanism(pMechanism.read()) }?;
session.sign_ctx = Some(SignContext {
algorithm: mechanism.into(),
private_key: private_key.clone(),
payload: None,
});
Ok(())
})
}
);
cryptoki_fn!(
unsafe fn C_Sign(
hSession: CK_SESSION_HANDLE,
pData: CK_BYTE_PTR,
ulDataLen: CK_ULONG,
pSignature: CK_BYTE_PTR,
pulSignatureLen: CK_ULONG_PTR,
) {
initialized!();
valid_session!(hSession);
not_null!(pData);
not_null!(pulSignatureLen);
sessions::session(hSession, |session| -> Result {
let data = unsafe { slice::from_raw_parts(pData, ulDataLen as usize) };
unsafe { session.sign(Some(data), pSignature, pulSignatureLen) }?;
Ok(())
})
}
);
cryptoki_fn!(
unsafe fn C_SignUpdate(hSession: CK_SESSION_HANDLE, pPart: CK_BYTE_PTR, ulPartLen: CK_ULONG) {
initialized!();
valid_session!(hSession);
not_null!(pPart);
sessions::session(hSession, |session| -> Result {
let sign_ctx = match session.sign_ctx.as_mut() {
None => return Err(Error::OperationNotInitialized),
Some(sign_ctx) => sign_ctx,
};
sign_ctx
.payload
.get_or_insert(vec![])
.extend_from_slice(unsafe { slice::from_raw_parts(pPart, ulPartLen as usize) });
Ok(())
})
}
);
cryptoki_fn!(
unsafe fn C_SignFinal(
hSession: CK_SESSION_HANDLE,
pSignature: CK_BYTE_PTR,
pulSignatureLen: CK_ULONG_PTR,
) {
initialized!();
valid_session!(hSession);
not_null!(pSignature);
not_null!(pulSignatureLen);
sessions::session(hSession, |session| -> Result {
unsafe { session.sign(None, pSignature, pulSignatureLen) }?;
Ok(())
})
}
);
cryptoki_fn_not_supported!(
C_SignRecoverInit,
hSession: CK_SESSION_HANDLE,
pMechanism: CK_MECHANISM_PTR,
hKey: CK_OBJECT_HANDLE
);
cryptoki_fn_not_supported!(
C_SignRecover,
hSession: CK_SESSION_HANDLE,
pData: CK_BYTE_PTR,
ulDataLen: CK_ULONG,
pSignature: CK_BYTE_PTR,
pulSignatureLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_VerifyInit,
hSession: CK_SESSION_HANDLE,
pMechanism: CK_MECHANISM_PTR,
hKey: CK_OBJECT_HANDLE
);
cryptoki_fn_not_supported!(
C_Verify,
hSession: CK_SESSION_HANDLE,
pData: CK_BYTE_PTR,
ulDataLen: CK_ULONG,
pSignature: CK_BYTE_PTR,
ulSignatureLen: CK_ULONG
);
cryptoki_fn_not_supported!(
C_VerifyUpdate,
hSession: CK_SESSION_HANDLE,
pPart: CK_BYTE_PTR,
ulPartLen: CK_ULONG
);
cryptoki_fn_not_supported!(
C_VerifyFinal,
hSession: CK_SESSION_HANDLE,
pSignature: CK_BYTE_PTR,
ulSignatureLen: CK_ULONG
);
cryptoki_fn_not_supported!(
C_VerifyRecoverInit,
hSession: CK_SESSION_HANDLE,
pMechanism: CK_MECHANISM_PTR,
hKey: CK_OBJECT_HANDLE
);
cryptoki_fn_not_supported!(
C_VerifyRecover,
hSession: CK_SESSION_HANDLE,
pSignature: CK_BYTE_PTR,
ulSignatureLen: CK_ULONG,
pData: CK_BYTE_PTR,
pulDataLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_DigestEncryptUpdate,
hSession: CK_SESSION_HANDLE,
pPart: CK_BYTE_PTR,
ulPartLen: CK_ULONG,
pEncryptedPart: CK_BYTE_PTR,
pulEncryptedPartLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_DecryptDigestUpdate,
hSession: CK_SESSION_HANDLE,
pEncryptedPart: CK_BYTE_PTR,
ulEncryptedPartLen: CK_ULONG,
pPart: CK_BYTE_PTR,
pulPartLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_SignEncryptUpdate,
hSession: CK_SESSION_HANDLE,
pPart: CK_BYTE_PTR,
ulPartLen: CK_ULONG,
pEncryptedPart: CK_BYTE_PTR,
pulEncryptedPartLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_DecryptVerifyUpdate,
hSession: CK_SESSION_HANDLE,
pEncryptedPart: CK_BYTE_PTR,
ulEncryptedPartLen: CK_ULONG,
pPart: CK_BYTE_PTR,
pulPartLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_GenerateKey,
hSession: CK_SESSION_HANDLE,
pMechanism: CK_MECHANISM_PTR,
pTemplate: CK_ATTRIBUTE_PTR,
ulCount: CK_ULONG,
phKey: CK_OBJECT_HANDLE_PTR
);
cryptoki_fn_not_supported!(
C_GenerateKeyPair,
hSession: CK_SESSION_HANDLE,
pMechanism: CK_MECHANISM_PTR,
pPublicKeyTemplate: CK_ATTRIBUTE_PTR,
ulPublicKeyAttributeCount: CK_ULONG,
pPrivateKeyTemplate: CK_ATTRIBUTE_PTR,
ulPrivateKeyAttributeCount: CK_ULONG,
phPublicKey: CK_OBJECT_HANDLE_PTR,
phPrivateKey: CK_OBJECT_HANDLE_PTR
);
cryptoki_fn_not_supported!(
C_WrapKey,
hSession: CK_SESSION_HANDLE,
_pMechanism: CK_MECHANISM_PTR,
_hWrappingKey: CK_OBJECT_HANDLE,
_hKey: CK_OBJECT_HANDLE,
_pWrappedKey: CK_BYTE_PTR,
_pulWrappedKeyLen: CK_ULONG_PTR
);
cryptoki_fn_not_supported!(
C_UnwrapKey,
hSession: CK_SESSION_HANDLE,
pMechanism: CK_MECHANISM_PTR,
hUnwrappingKey: CK_OBJECT_HANDLE,
pWrappedKey: CK_BYTE_PTR,
ulWrappedKeyLen: CK_ULONG,
pTemplate: CK_ATTRIBUTE_PTR,
ulAttributeCount: CK_ULONG,
phKey: CK_OBJECT_HANDLE_PTR
);
cryptoki_fn_not_supported!(
C_DeriveKey,
hSession: CK_SESSION_HANDLE,
pMechanism: CK_MECHANISM_PTR,
hBaseKey: CK_OBJECT_HANDLE,
pTemplate: CK_ATTRIBUTE_PTR,
ulAttributeCount: CK_ULONG,
phKey: CK_OBJECT_HANDLE_PTR
);
cryptoki_fn!(
fn C_SeedRandom(hSession: CK_SESSION_HANDLE, pSeed: CK_BYTE_PTR, _ulSeedLen: CK_ULONG) {
initialized!();
valid_session!(hSession);
not_null!(pSeed);
Err(Error::RandomNoRng)
}
);
cryptoki_fn!(
fn C_GenerateRandom(
hSession: CK_SESSION_HANDLE,
pRandomData: CK_BYTE_PTR,
_ulRandomLen: CK_ULONG,
) {
initialized!();
valid_session!(hSession);
not_null!(pRandomData);
Err(Error::RandomNoRng)
}
);
cryptoki_fn!(
fn C_GetFunctionStatus(hSession: CK_SESSION_HANDLE) {
initialized!();
valid_session!(hSession);
Err(Error::FunctionNotParallel)
}
);
cryptoki_fn!(
fn C_CancelFunction(hSession: CK_SESSION_HANDLE) {
initialized!();
valid_session!(hSession);
Err(Error::FunctionNotParallel)
}
);
cryptoki_fn_not_supported!(
C_WaitForSlotEvent,
flags: CK_FLAGS,
pSlot: CK_SLOT_ID_PTR,
pReserved: CK_VOID_PTR
);
#[cfg(test)]
pub mod tests {
use std::ptr;
use serial_test::serial;
use super::*;
pub fn test_init() {
if !INITIALIZED.load(std::sync::atomic::Ordering::SeqCst) {
let mut func_list: &mut CK_FUNCTION_LIST = &mut CK_FUNCTION_LIST {
..Default::default()
};
unsafe { C_GetFunctionList((&mut func_list) as *mut _ as *mut _) };
}
}
#[test]
#[serial]
fn get_initialize() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
assert_eq!(
C_Initialize(ptr::null_mut()),
CKR_CRYPTOKI_ALREADY_INITIALIZED
);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
let mut args = CK_C_INITIALIZE_ARGS::default();
assert_eq!(
C_Initialize(&mut args as CK_C_INITIALIZE_ARGS_PTR as *mut std::ffi::c_void),
CKR_OK
);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
// Expect CKR_ARGUMENTS_BAD if pReserved is not null.
args.pReserved = 1 as *mut u32 as *mut std::ffi::c_void;
assert_eq!(
C_Initialize(&mut args as CK_C_INITIALIZE_ARGS_PTR as *mut std::ffi::c_void),
CKR_ARGUMENTS_BAD
);
}
#[test]
#[serial]
fn finalize() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
// Expect CKR_ARGUMENTS_BAD if pReserved is not null.
assert_eq!(
C_Finalize(1 as *mut u32 as *mut std::ffi::c_void),
CKR_ARGUMENTS_BAD
);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_CRYPTOKI_NOT_INITIALIZED);
}
#[test]
#[serial]
fn get_info() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut info = CK_INFO::default();
assert_eq!(unsafe { C_GetInfo(&mut info) }, CKR_OK);
// Expect CKR_ARGUMENTS_BAD if pInfo is null.
assert_eq!(unsafe { C_GetInfo(ptr::null_mut()) }, CKR_ARGUMENTS_BAD);
// Expect CKR_CRYPTOKI_NOT_INITIALIZED if token is not initialized.
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
assert_eq!(
unsafe { C_GetInfo(&mut info) },
CKR_CRYPTOKI_NOT_INITIALIZED
);
}
#[test]
#[serial]
fn get_function_list() {
test_init();
let mut function_list = CK_FUNCTION_LIST::default();
let mut function_list_pointer: *mut CK_FUNCTION_LIST = &mut function_list;
assert_eq!(
unsafe { C_GetFunctionList(&mut function_list_pointer) },
CKR_OK
);
// Expect CKR_ARGUMENTS_BAD if ppFunctionList is null.
assert_eq!(
unsafe { C_GetFunctionList(ptr::null_mut()) },
CKR_ARGUMENTS_BAD
);
}
#[test]
#[serial]
fn get_slot_list() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut count = 0;
assert_eq!(
unsafe { C_GetSlotList(CK_FALSE, std::ptr::null_mut(), &mut count) },
CKR_OK
);
assert_eq!(count, 1);
// Expect CKR_ARGUMENTS_BAD if pulCount is null.
assert_eq!(
unsafe { C_GetSlotList(CK_FALSE, ptr::null_mut(), ptr::null_mut()) },
CKR_ARGUMENTS_BAD
);
// Expect CKR_BUFFER_TOO_SMALL if pulCount is less than the number of
// slots.
let mut count = 0;
let mut slot_list = vec![0; 0];
assert_eq!(
unsafe { C_GetSlotList(CK_FALSE, slot_list.as_mut_ptr(), &mut count) },
CKR_BUFFER_TOO_SMALL
);
// Expect CKR_CRYPTOKI_NOT_INITIALIZED if token is not initialized.
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
assert_eq!(
unsafe { C_GetSlotList(CK_FALSE, std::ptr::null_mut(), &mut count) },
CKR_CRYPTOKI_NOT_INITIALIZED
)
}
#[test]
#[serial]
fn get_slot_info() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut slot_info = CK_SLOT_INFO::default();
assert_eq!(unsafe { C_GetSlotInfo(SLOT_ID, &mut slot_info) }, CKR_OK);
// Expect CKR_ARGUMENTS_BAD if pInfo is null.
assert_eq!(
unsafe { C_GetSlotInfo(SLOT_ID, ptr::null_mut()) },
CKR_ARGUMENTS_BAD
);
// Expect CKR_SLOT_ID_INVALID if slotID references a nonexistent slot.
assert_eq!(
unsafe { C_GetSlotInfo(SLOT_ID + 1, ptr::null_mut()) },
CKR_SLOT_ID_INVALID
);
// Expect CKR_CRYPTOKI_NOT_INITIALIZED if token is not initialized.
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
assert_eq!(
unsafe { C_GetSlotInfo(SLOT_ID, &mut slot_info) },
CKR_CRYPTOKI_NOT_INITIALIZED
);
}
#[test]
#[serial]
fn get_token_info() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
assert_eq!(
unsafe { C_GetTokenInfo(SLOT_ID, &mut CK_TOKEN_INFO::default()) },
CKR_OK
);
// Expect CKR_SLOT_ID_INVALID if slotID references a nonexistent slot.
assert_eq!(
unsafe { C_GetTokenInfo(SLOT_ID + 1, ptr::null_mut()) },
CKR_SLOT_ID_INVALID
);
// Expect CKR_ARGUMENTS_BAD if pInfo is null.
assert_eq!(
unsafe { C_GetSlotInfo(SLOT_ID, ptr::null_mut()) },
CKR_ARGUMENTS_BAD
);
// Expect CKR_CRYPTOKI_NOT_INITIALIZED if token is not initialized.
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
assert_eq!(
unsafe { C_GetTokenInfo(SLOT_ID, &mut CK_TOKEN_INFO::default()) },
CKR_CRYPTOKI_NOT_INITIALIZED
);
}
#[test]
#[serial]
fn get_mechanism_list() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut count = 0;
assert_eq!(
unsafe { C_GetMechanismList(SLOT_ID, ptr::null_mut(), &mut count) },
CKR_OK
);
assert_ne!(count, 0);
let mut mechanisms = Vec::<CK_MECHANISM_TYPE>::with_capacity(count as usize);
assert_eq!(
unsafe { C_GetMechanismList(SLOT_ID, mechanisms.as_mut_ptr(), &mut count) },
CKR_OK
);
unsafe {
mechanisms.set_len(count as usize);
}
assert_eq!(mechanisms, *SUPPORTED_SIGNATURE_MECHANISMS);
// Expect CKR_SLOT_ID_INVALID if slotID references a nonexistent slot.
assert_eq!(
unsafe { C_GetMechanismList(SLOT_ID + 1, ptr::null_mut(), &mut count) },
CKR_SLOT_ID_INVALID
);
// Expect CKR_ARGUMENTS_BAD if pulCount is null.
assert_eq!(
unsafe { C_GetMechanismList(SLOT_ID, ptr::null_mut(), ptr::null_mut()) },
CKR_ARGUMENTS_BAD
);
// Expect CKR_BUFFER_TOO_SMALL if pulCount is less than the number of
// mechanisms.
assert_eq!(
unsafe { C_GetMechanismList(SLOT_ID, mechanisms.as_mut_ptr(), &mut (count - 1)) },
CKR_BUFFER_TOO_SMALL
);
// Expect CKR_CRYPTOKI_NOT_INITIALIZED if token is not initialized.
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
assert_eq!(
unsafe { C_GetMechanismList(SLOT_ID, ptr::null_mut(), ptr::null_mut()) },
CKR_CRYPTOKI_NOT_INITIALIZED
);
}
#[test]
#[serial]
fn get_mechanism_info() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut info = CK_MECHANISM_INFO::default();
assert_eq!(
unsafe { C_GetMechanismInfo(SLOT_ID, SUPPORTED_SIGNATURE_MECHANISMS[0], &mut info) },
CKR_OK
);
// Expect CKR_MECHANISM_INVALID if type is an unsupported mechanism.
assert_eq!(
unsafe { C_GetMechanismInfo(SLOT_ID, CKM_DSA, &mut info) },
CKR_MECHANISM_INVALID
);
// Expect CKR_ARGUMENTS_BAD if pInfo is null.
assert_eq!(
unsafe {
C_GetMechanismInfo(SLOT_ID, SUPPORTED_SIGNATURE_MECHANISMS[0], ptr::null_mut())
},
CKR_ARGUMENTS_BAD
);
// Expect CKR_CRYPTOKI_NOT_INITIALIZED if token is not initialized.
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
assert_eq!(
unsafe {
C_GetMechanismInfo(SLOT_ID, SUPPORTED_SIGNATURE_MECHANISMS[0], ptr::null_mut())
},
CKR_CRYPTOKI_NOT_INITIALIZED
);
}
#[test]
#[serial]
fn open_session() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let flags = CKF_SERIAL_SESSION;
let mut handle = CK_INVALID_HANDLE;
assert_eq!(
unsafe { C_OpenSession(SLOT_ID, flags, ptr::null_mut(), None, &mut handle) },
CKR_OK
);
// Expect CKR_SLOT_ID_INVALID if slotID references a nonexistent slot.
assert_eq!(
unsafe { C_OpenSession(SLOT_ID + 1, flags, ptr::null_mut(), None, &mut handle) },
CKR_SLOT_ID_INVALID
);
// Expect CKR_SESSION_PARALLEL_NOT_SUPPORTED if CKF_SERIAL_SESSION flag
// is not set.
assert_eq!(
unsafe { C_OpenSession(SLOT_ID, 0, ptr::null_mut(), None, &mut handle) },
CKR_SESSION_PARALLEL_NOT_SUPPORTED
);
// Expect CKR_ARGUMENTS_BAD if phSession is null.
assert_eq!(
unsafe { C_OpenSession(SLOT_ID, flags, ptr::null_mut(), None, ptr::null_mut()) },
CKR_ARGUMENTS_BAD
);
assert_eq!(C_CloseSession(handle), CKR_OK);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
}
#[test]
#[serial]
fn close_sesson() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut handle = CK_INVALID_HANDLE;
assert_eq!(
unsafe {
C_OpenSession(
SLOT_ID,
CKF_SERIAL_SESSION,
ptr::null_mut(),
None,
&mut handle,
)
},
CKR_OK
);
assert_eq!(C_CloseSession(handle), CKR_OK);
// Expect CKR_SESSION_HANDLE_INVALID if the session has already been closed.
assert_eq!(C_CloseSession(handle), CKR_SESSION_HANDLE_INVALID);
// Expect CKR_SESSION_HANDLE_INVALID if hSession is not a valid handle.
assert_eq!(
C_CloseSession(CK_INVALID_HANDLE),
CKR_SESSION_HANDLE_INVALID
);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
}
#[test]
#[serial]
fn get_session_info() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut handle = CK_INVALID_HANDLE;
assert_eq!(
unsafe {
C_OpenSession(
SLOT_ID,
CKF_SERIAL_SESSION,
ptr::null_mut(),
None,
&mut handle,
)
},
CKR_OK
);
let mut session_info = CK_SESSION_INFO::default();
assert_eq!(
unsafe { C_GetSessionInfo(handle, &mut session_info) },
CKR_OK
);
// Expect CKR_SESSION_HANDLE_INVALID if hSession is not a valid handle.
assert_eq!(
unsafe { C_GetSessionInfo(CK_INVALID_HANDLE, &mut session_info) },
CKR_SESSION_HANDLE_INVALID
);
// Expect CKR_ARGUMENTS_BAD if pInfo is null.
assert_eq!(
unsafe { C_GetSessionInfo(handle, ptr::null_mut()) },
CKR_ARGUMENTS_BAD
);
assert_eq!(C_CloseSession(handle), CKR_OK);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
}
#[test]
#[serial]
fn get_attribute_value() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut session_h = CK_INVALID_HANDLE;
assert_eq!(
unsafe {
C_OpenSession(
SLOT_ID,
CKF_SERIAL_SESSION,
ptr::null_mut(),
None,
&mut session_h,
)
},
CKR_OK
);
let mut template = vec![CK_ATTRIBUTE::default()];
// Expect CKR_OBJECT_HANDLE_INVALID if hObject is not a valid handle.
assert_eq!(
unsafe {
C_GetAttributeValue(
session_h,
CK_INVALID_HANDLE,
template.as_mut_ptr(),
template.len() as CK_ULONG,
)
},
CKR_OBJECT_HANDLE_INVALID
);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
assert_eq!(
unsafe { C_GetAttributeValue(session_h, 0, template.as_mut_ptr(), 0) },
CKR_CRYPTOKI_NOT_INITIALIZED
);
}
#[test]
#[serial]
fn find_objects_init() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut handle = CK_INVALID_HANDLE;
assert_eq!(
unsafe {
C_OpenSession(
SLOT_ID,
CKF_SERIAL_SESSION,
ptr::null_mut(),
None,
&mut handle,
)
},
CKR_OK
);
let mut template = vec![];
assert_eq!(
unsafe { C_FindObjectsInit(handle, template.as_mut_ptr(), template.len() as CK_ULONG) },
CKR_OK
);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
assert_eq!(
unsafe { C_FindObjectsInit(handle, template.as_mut_ptr(), template.len() as CK_ULONG) },
CKR_CRYPTOKI_NOT_INITIALIZED
);
}
#[test]
#[serial]
fn find_objects() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut handle = CK_INVALID_HANDLE;
assert_eq!(
unsafe {
C_OpenSession(
SLOT_ID,
CKF_SERIAL_SESSION,
ptr::null_mut(),
None,
&mut handle,
)
},
CKR_OK
);
let mut template = vec![CK_ATTRIBUTE {
type_: CKA_CLASS,
pValue: CKO_PRIVATE_KEY as CK_VOID_PTR,
ulValueLen: std::mem::size_of_val(&CKO_PRIVATE_KEY) as CK_ULONG,
}];
assert_eq!(
unsafe { C_FindObjectsInit(handle, template.as_mut_ptr(), 0) },
CKR_OK
);
let mut objects = vec![CK_OBJECT_HANDLE::default()];
let mut count = 0;
assert_eq!(
unsafe { C_FindObjects(handle, objects.as_mut_ptr(), 1, &mut count) },
CKR_OK
);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
assert_eq!(
unsafe { C_FindObjects(handle, ptr::null_mut(), 0, ptr::null_mut()) },
CKR_CRYPTOKI_NOT_INITIALIZED
);
}
#[test]
#[serial]
fn find_objects_final() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut handle = CK_INVALID_HANDLE;
assert_eq!(
unsafe {
C_OpenSession(
SLOT_ID,
CKF_SERIAL_SESSION,
ptr::null_mut(),
None,
&mut handle,
)
},
CKR_OK
);
let mut template = vec![];
assert_eq!(
unsafe { C_FindObjectsInit(handle, template.as_mut_ptr(), template.len() as CK_ULONG) },
CKR_OK
);
assert_eq!(C_FindObjectsFinal(handle), CKR_OK);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
assert_eq!(C_FindObjectsFinal(handle), CKR_CRYPTOKI_NOT_INITIALIZED);
}
#[test]
#[serial]
fn get_function_status() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut session_h = CK_INVALID_HANDLE;
assert_eq!(
unsafe {
C_OpenSession(
SLOT_ID,
CKF_SERIAL_SESSION,
ptr::null_mut(),
None,
&mut session_h,
)
},
CKR_OK
);
assert_eq!(C_GetFunctionStatus(session_h), CKR_FUNCTION_NOT_PARALLEL);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
}
#[test]
#[serial]
fn cancel_function() {
test_init();
assert_eq!(C_Initialize(ptr::null_mut()), CKR_OK);
let mut session_h = CK_INVALID_HANDLE;
assert_eq!(
unsafe {
C_OpenSession(
SLOT_ID,
CKF_SERIAL_SESSION,
ptr::null_mut(),
None,
&mut session_h,
)
},
CKR_OK
);
assert_eq!(C_GetFunctionStatus(session_h), CKR_FUNCTION_NOT_PARALLEL);
assert_eq!(C_Finalize(ptr::null_mut()), CKR_OK);
}
}