/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Helper macro to prefix log messages with the current thread ID. #[macro_export]
macro_rules! log_with_thread_id {
($log_level:ident, $($message:expr),*) => {
$log_level!("{:?} {}", std::thread::current().id(), format_args!($($message),*));
};
}
// This module defines a few helper macros that can be used to declare the repetitive, boilerplate // code required to implement a PKCS#11 module. They require the macros `try_to_get_manager_guard` // and `manager_guard_to_manager` to be defined. Generally speaking, these manager macros are used // to get a mutable handle on a `Mutex<Option<Manager<...>>>` that represents the state of the // module.
/// NB: Requires MANUFACTURER_ID_BYTES and LIBRARY_DESCRIPTION_BYTES to be defined. #[macro_export]
macro_rules! declare_pkcs11_informational_functions {
() => { /// This gets called to gather some information about the module. In particular, this /// implementation supports (portions of) cryptoki (PKCS #11) version 2.2. extern"C"fn C_GetInfo(pInfo: CK_INFO_PTR) -> CK_RV { if pInfo.is_null() {
log_with_thread_id!(error, "C_GetInfo: CKR_ARGUMENTS_BAD"); return CKR_ARGUMENTS_BAD;
} let info = CK_INFO {
cryptokiVersion: CK_VERSION { major: 2, minor: 2 },
manufacturerID: *MANUFACTURER_ID_BYTES,
flags: 0,
libraryDescription: *LIBRARY_DESCRIPTION_BYTES,
libraryVersion: CK_VERSION { major: 0, minor: 0 },
}; unsafe {
*pInfo = info;
}
log_with_thread_id!(debug, "C_GetInfo: CKR_OK");
CKR_OK
}
/// This gets called twice: once with a null `pSlotList` to get the number of slots /// (returned via `pulCount`) and a second time to get the ID for each slot. extern"C"fn C_GetSlotList(
tokenPresent: CK_BBOOL,
pSlotList: CK_SLOT_ID_PTR,
pulCount: CK_ULONG_PTR,
) -> CK_RV { if pulCount.is_null() {
log_with_thread_id!(error, "C_GetSlotList: CKR_ARGUMENTS_BAD"); return CKR_ARGUMENTS_BAD;
} letmut manager_guard = try_to_get_manager_guard!(); let manager = manager_guard_to_manager!(manager_guard); let slot_ids = manager.get_slot_ids(if tokenPresent == CK_TRUE { true } else { false }); let slot_count: CK_ULONG = slot_ids.len().try_into().unwrap(); if !pSlotList.is_null() { ifunsafe { *pulCount } < slot_count {
log_with_thread_id!(error, "C_GetSlotList: CKR_BUFFER_TOO_SMALL"); return CKR_BUFFER_TOO_SMALL;
} unsafe {
std::ptr::copy_nonoverlapping(slot_ids.as_ptr(), pSlotList, slot_ids.len());
}
}; unsafe {
*pulCount = slot_count;
}
log_with_thread_id!(debug, "C_GetSlotList: CKR_OK");
CKR_OK
}
/// This gets called to initialize a search for objects matching a given list of attributes. extern"C"fn C_FindObjectsInit(
hSession: CK_SESSION_HANDLE,
pTemplate: CK_ATTRIBUTE_PTR,
ulCount: CK_ULONG,
) -> CK_RV { if pTemplate.is_null() {
log_with_thread_id!(error, "C_FindObjectsInit: CKR_ARGUMENTS_BAD"); return CKR_ARGUMENTS_BAD;
} letmut attrs = Vec::new();
log_with_thread_id!(trace, "C_FindObjectsInit:"); for i in0..ulCount as usize { let attr = unsafe { &*pTemplate.add(i) };
trace_attr(" ", attr); // Copy out the attribute type to avoid making a reference to an unaligned field. let attr_type = attr.type_; if !RELEVANT_ATTRIBUTES.contains(&attr_type) {
log_with_thread_id!(
debug, "C_FindObjectsInit: irrelevant attribute, returning CKR_ATTRIBUTE_TYPE_INVALID"
); return CKR_ATTRIBUTE_TYPE_INVALID;
} let slice = unsafe {
std::slice::from_raw_parts(attr.pValue as *const u8, attr.ulValueLen as usize)
};
attrs.push((attr_type, slice.to_owned()));
} letmut manager_guard = try_to_get_manager_guard!(); let manager = manager_guard_to_manager!(manager_guard); match manager.start_search(hSession, attrs) {
Ok(()) => {}
Err(e) => {
log_with_thread_id!(error, "C_FindObjectsInit: CKR_ARGUMENTS_BAD: {}", e); return CKR_ARGUMENTS_BAD;
}
}
log_with_thread_id!(debug, "C_FindObjectsInit: CKR_OK");
CKR_OK
}
/// This gets called after `C_FindObjectsInit` to get the results of a search. extern"C"fn C_FindObjects(
hSession: CK_SESSION_HANDLE,
phObject: CK_OBJECT_HANDLE_PTR,
ulMaxObjectCount: CK_ULONG,
pulObjectCount: CK_ULONG_PTR,
) -> CK_RV { if phObject.is_null() || pulObjectCount.is_null() || ulMaxObjectCount == 0 {
log_with_thread_id!(error, "C_FindObjects: CKR_ARGUMENTS_BAD"); return CKR_ARGUMENTS_BAD;
} letmut manager_guard = try_to_get_manager_guard!(); let manager = manager_guard_to_manager!(manager_guard); let handles = match manager.search(hSession, ulMaxObjectCount as usize) {
Ok(handles) => handles,
Err(e) => {
log_with_thread_id!(error, "C_FindObjects: CKR_ARGUMENTS_BAD: {}", e); return CKR_ARGUMENTS_BAD;
}
};
log_with_thread_id!(debug, "C_FindObjects: found handles {:?}", handles); if handles.len() > ulMaxObjectCount as usize {
log_with_thread_id!(error, "C_FindObjects: manager returned too many handles"); return CKR_DEVICE_ERROR;
} unsafe {
*pulObjectCount = handles.len() as CK_ULONG;
} for (index, handle) in handles.iter().enumerate() { if index < ulMaxObjectCount as usize { unsafe {
*(phObject.add(index)) = *handle;
}
}
}
log_with_thread_id!(debug, "C_FindObjects: CKR_OK");
CKR_OK
}
/// This gets called after `C_FindObjectsInit` and `C_FindObjects` to finish a search. extern"C"fn C_FindObjectsFinal(hSession: CK_SESSION_HANDLE) -> CK_RV { letmut manager_guard = try_to_get_manager_guard!(); let manager = manager_guard_to_manager!(manager_guard); // It would be an error if there were no search for this session, but we can be permissive here. match manager.clear_search(hSession) {
Ok(()) => {
log_with_thread_id!(debug, "C_FindObjectsFinal: CKR_OK");
CKR_OK
}
Err(e) => {
log_with_thread_id!(error, "C_FindObjectsFinal: clear_search failed: {}", e);
CKR_DEVICE_ERROR
}
}
}
/// This gets called to obtain the values of a number of attributes of an object identified /// by the given handle. If a specified attribute is not defined on the object, the length /// of that attribute is set to CK_UNAVAILABLE_INFORMATION to indicate that it is not /// available. This gets called twice: once to obtain the lengths of the attributes and /// again to get the values. extern"C"fn C_GetAttributeValue(
hSession: CK_SESSION_HANDLE,
hObject: CK_OBJECT_HANDLE,
pTemplate: CK_ATTRIBUTE_PTR,
ulCount: CK_ULONG,
) -> CK_RV { if pTemplate.is_null() {
log_with_thread_id!(error, "C_GetAttributeValue: CKR_ARGUMENTS_BAD"); return CKR_ARGUMENTS_BAD;
} letmut attr_types = Vec::with_capacity(ulCount as usize); for i in0..ulCount as usize { let attr = unsafe { &*pTemplate.add(i) };
attr_types.push(attr.type_);
} letmut manager_guard = try_to_get_manager_guard!(); let manager = manager_guard_to_manager!(manager_guard); let values = match manager.get_attributes(hSession, hObject, attr_types) {
Ok(values) => values,
Err(e) => {
log_with_thread_id!(error, "C_GetAttributeValue: CKR_ARGUMENTS_BAD ({})", e); return CKR_ARGUMENTS_BAD;
}
}; if values.len() != ulCount as usize {
log_with_thread_id!(
error, "C_GetAttributeValue: manager.get_attributes didn't return the right number of values"
); return CKR_DEVICE_ERROR;
} for (i, value) in values.iter().enumerate().take(ulCount as usize) { let attr = unsafe { &mut *pTemplate.add(i) }; iflet Some(attr_value) = value { if attr.pValue.is_null() {
attr.ulValueLen = attr_value.len() as CK_ULONG;
} else { let ptr: *mut u8 = attr.pValue as *mut u8; if attr_value.len() != attr.ulValueLen as usize {
log_with_thread_id!(error, "C_GetAttributeValue: incorrect attr size"); return CKR_ARGUMENTS_BAD;
} unsafe {
std::ptr::copy_nonoverlapping(attr_value.as_ptr(), ptr, attr_value.len());
}
}
} else {
attr.ulValueLen = CK_UNAVAILABLE_INFORMATION;
}
}
log_with_thread_id!(debug, "C_GetAttributeValue: CKR_OK");
CKR_OK
}
};
}
#[macro_export]
macro_rules! declare_pkcs11_sign_functions {
() => { /// This gets called to set up a sign operation. extern"C"fn C_SignInit(
hSession: CK_SESSION_HANDLE,
pMechanism: CK_MECHANISM_PTR,
hKey: CK_OBJECT_HANDLE,
) -> CK_RV { if pMechanism.is_null() {
log_with_thread_id!(error, "C_SignInit: CKR_ARGUMENTS_BAD"); return CKR_ARGUMENTS_BAD;
} // Presumably we should validate the mechanism against hKey, but the specification // doesn't actually seem to require this. let mechanism = unsafe { *pMechanism };
log_with_thread_id!(debug, "C_SignInit: mechanism is {:?}", mechanism); let mechanism_params = if mechanism.mechanism == CKM_RSA_PKCS_PSS { if mechanism.ulParameterLen as usize
!= std::mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>()
{ let len = mechanism.ulParameterLen;
log_with_thread_id!(
error, "C_SignInit: bad ulParameterLen for CKM_RSA_PKCS_PSS: {}",
len
); return CKR_ARGUMENTS_BAD;
}
Some(unsafe { *(mechanism.pParameter as *const CK_RSA_PKCS_PSS_PARAMS) })
} else {
None
}; letmut manager_guard = try_to_get_manager_guard!(); let manager = manager_guard_to_manager!(manager_guard); match manager.start_sign(hSession, hKey, mechanism_params) {
Ok(()) => {}
Err(e) => {
log_with_thread_id!(error, "C_SignInit: CKR_GENERAL_ERROR: {}", e); return CKR_GENERAL_ERROR;
}
};
log_with_thread_id!(debug, "C_SignInit: CKR_OK");
CKR_OK
}
/// NSS calls this after `C_SignInit` (there are more ways in the PKCS #11 specification to /// sign data, but this is the only way supported by these modules). extern"C"fn C_Sign(
hSession: CK_SESSION_HANDLE,
pData: CK_BYTE_PTR,
ulDataLen: CK_ULONG,
pSignature: CK_BYTE_PTR,
pulSignatureLen: CK_ULONG_PTR,
) -> CK_RV { if pData.is_null() || pulSignatureLen.is_null() {
log_with_thread_id!(error, "C_Sign: CKR_ARGUMENTS_BAD"); return CKR_ARGUMENTS_BAD;
} let data = unsafe { std::slice::from_raw_parts(pData, ulDataLen as usize) }; if pSignature.is_null() { letmut manager_guard = try_to_get_manager_guard!(); let manager = manager_guard_to_manager!(manager_guard); match manager.get_signature_length(hSession, data.to_vec()) {
Ok(signature_length) => unsafe {
*pulSignatureLen = signature_length as CK_ULONG;
},
Err(e) => {
log_with_thread_id!(error, "C_Sign: get_signature_length failed: {}", e); return CKR_GENERAL_ERROR;
}
}
} else { letmut manager_guard = try_to_get_manager_guard!(); let manager = manager_guard_to_manager!(manager_guard); match manager.sign(hSession, data.to_vec()) {
Ok(signature) => { let signature_capacity = unsafe { *pulSignatureLen } as usize; if signature_capacity < signature.len() {
log_with_thread_id!(error, "C_Sign: CKR_ARGUMENTS_BAD"); return CKR_ARGUMENTS_BAD;
} let ptr: *mut u8 = pSignature as *mut u8; unsafe {
std::ptr::copy_nonoverlapping(signature.as_ptr(), ptr, signature.len());
*pulSignatureLen = signature.len() as CK_ULONG;
}
}
Err(e) => {
log_with_thread_id!(error, "C_Sign: sign failed: {}", e); return CKR_GENERAL_ERROR;
}
}
}
log_with_thread_id!(debug, "C_Sign: CKR_OK");
CKR_OK
}
};
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.