/* -*- Mode: rust; rust-indent-offset: 4 -*- */ /* 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/. */
#![allow(non_snake_case)]
use pkcs11_bindings::*; use std::slice;
use std::collections::btree_map::Entry; use std::collections::{BTreeMap, BTreeSet}; use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::{Mutex, MutexGuard};
// The token assigns session handles using a counter. It would make sense to use a 64 bit counter, // as there would then be no risk of exhausting the session handle space. However, // CK_SESSION_HANDLE is defined as a C unsigned long, which is a u32 on some platforms. // // We start the counter at 1 since PKCS#11 reserves 0 to signal an invalid handle // type SessionHandle = u32; static NEXT_HANDLE: AtomicU32 = AtomicU32::new(1);
// The token needs to keep track of which sessions are open. // type SessionSet = BTreeSet<SessionHandle>; static OPEN_SESSIONS: Mutex<Option<SessionSet>> = Mutex::new(None);
// Helper functions for accessing OPEN_SESSIONS // type SessionSetGuard = MutexGuard<'static, Option<SessionSet>>;
// The token needs to cache search results until the client reads them or closes the session. // type SearchCache = BTreeMap<SessionHandle, SearchResult>; static SEARCHES: Mutex<Option<SearchCache>> = Mutex::new(None);
// Helper functions for accessing SEARCHES // type SearchCacheGuard = MutexGuard<'static, Option<SearchCache>>;
fn validate_session(handle: SessionHandle) -> Result<(), PK11Error> { letmut guard = get_open_sessions_guard()?; let sessions = get_open_sessions(&mut guard)?; if sessions.contains(&handle) { return Ok(());
} if handle < NEXT_HANDLE.load(Ordering::SeqCst) {
Err(PK11Error(CKR_SESSION_CLOSED))
} else { // Possible that NEXT_HANDLE wrapped and we should return CKR_SESSION_CLOSED. // But this is best-effort.
Err(PK11Error(CKR_SESSION_HANDLE_INVALID))
}
}
// The internal implementation of C_Initialize fn initialize() -> Result<(), PK11Error> {
{ letmut search_cache_guard = get_search_cache_guard()?; if (*search_cache_guard).is_some() { return Err(PK11Error(CKR_CRYPTOKI_ALREADY_INITIALIZED));
}
*search_cache_guard = Some(SearchCache::default());
}
// Internal implementation of C_OpenSession fn open_session() -> Result<SessionHandle, PK11Error> { letmut handle = NEXT_HANDLE.fetch_add(1, Ordering::SeqCst); if handle == 0 { // skip handle 0 if the addition wraps
handle = NEXT_HANDLE.fetch_add(1, Ordering::SeqCst);
}
letmut guard = get_open_sessions_guard()?; let sessions = get_open_sessions(&mut guard)?; while !sessions.insert(handle) { // this only executes if NEXT_HANDLE wraps while sessions with // small handles are still open.
handle = NEXT_HANDLE.fetch_add(1, Ordering::SeqCst);
}
extern"C"fn C_OpenSession(
slotID: CK_SLOT_ID,
flags: CK_FLAGS,
_pApplication: CK_VOID_PTR,
_Notify: CK_NOTIFY,
phSession: CK_SESSION_HANDLE_PTR,
) -> CK_RV { if slotID != SLOT_ID_ROOTS || phSession.is_null() { return CKR_ARGUMENTS_BAD;
} // [pkcs11-base-v3.0, Section 5.6.1] // For legacy reasons, the CKF_SERIAL_SESSION bit MUST always be set; if a call to // C_OpenSession does not have this bit set, the call should return unsuccessfully with the // error code CKR_SESSION_PARALLEL_NOT_SUPPORTED. if flags & CKF_SERIAL_SESSION == 0 { return CKR_SESSION_PARALLEL_NOT_SUPPORTED;
} let session_id = match open_session() {
Ok(session_id) => session_id as CK_SESSION_HANDLE,
Err(PK11Error(e)) => return e,
}; unsafe { *phSession = session_id };
CKR_OK
}
extern"C"fn C_CloseSession(hSession: CK_SESSION_HANDLE) -> CK_RV { let session: SessionHandle = match hSession.try_into() {
Ok(session) => session,
Err(_) => return CKR_SESSION_HANDLE_INVALID,
}; match close_session(session) {
Ok(_) => CKR_OK,
Err(PK11Error(e)) => e,
}
}
extern"C"fn C_CloseAllSessions(slotID: CK_SLOT_ID) -> CK_RV { if slotID != SLOT_ID_ROOTS { return CKR_ARGUMENTS_BAD;
} match close_all_sessions() {
Ok(_) => CKR_OK,
Err(PK11Error(e)) => e,
}
}
let count: usize = match ulCount.try_into() {
Ok(count) => count,
Err(_) => return CKR_ARGUMENTS_BAD,
};
// C_GetAttributeValue has a session handle parameter because PKCS#11 objects can have // session-bound lifetimes and access controls. We don't have any session objects, and all of // our token objects are public. So there's no good reason to validate the session handle. // //let session: SessionHandle = match hSession.try_into() { // Ok(session) => session, // Err(_) => return CKR_SESSION_HANDLE_INVALID, //}; // //if let Err(PK11Error(e)) = validate_session(session) { // return e; //}
let handle: ObjectHandle = match hObject.try_into() {
Ok(handle) => handle,
Err(_) => return CKR_OBJECT_HANDLE_INVALID,
};
let attrs: &mut [CK_ATTRIBUTE] = unsafe { slice::from_raw_parts_mut(pTemplate, count) };
letmut rv = CKR_OK;
// Handle requests with null pValue fields for attr in attrs.iter_mut().filter(|x| x.pValue.is_null()) {
attr.ulValueLen = match get_attribute(attr.type_, &handle) {
None => { // [pkcs11-base-v3.0, Section 5.7.5] // 2. [...] if the specified value for the object is invalid (the object does not possess // such an attribute), then the ulValueLen field in that triple is modified to hold the // value CK_UNAVAILABLE_INFORMATION.
rv = CKR_ATTRIBUTE_TYPE_INVALID;
CK_UNAVAILABLE_INFORMATION
}
Some(attr) => { // [pkcs11-base-v3.0, Section 5.7.5] // 3. [...] if the pValue field has the value NULL_PTR, then the ulValueLen field is modified // to hold the exact length of the specified attribute for the object.
attr.len() as CK_ULONG
}
}
}
// Handle requests with non-null pValue fields for attr in attrs.iter_mut().filter(|x| !x.pValue.is_null()) { let dst_len: usize = match attr.ulValueLen.try_into() {
Ok(dst_len) => dst_len,
Err(_) => return CKR_ARGUMENTS_BAD,
};
attr.ulValueLen = match get_attribute(attr.type_, &handle) {
None => { // [pkcs11-base-v3.0, Section 5.7.5] // 2. [...] if the specified value for the object is invalid (the object does not possess // such an attribute), then the ulValueLen field in that triple is modified to hold the // value CK_UNAVAILABLE_INFORMATION.
rv = CKR_ATTRIBUTE_TYPE_INVALID;
CK_UNAVAILABLE_INFORMATION
}
Some(src) if dst_len >= src.len() => { // [pkcs11-base-v3.0, Section 5.7.5] // 4. [...] if the length specified in ulValueLen is large enough to hold the value // of the specified attribute for the object, then that attribute is copied into // the buffer located at pValue, and the ulValueLen field is modified to hold // the exact length of the attribute. let dst: &mut [u8] = unsafe { slice::from_raw_parts_mut(attr.pValue as *mut u8, dst_len) };
dst[..src.len()].copy_from_slice(src);
src.len() as CK_ULONG
}
_ => { // [pkcs11-base-v3.0, Section 5.7.5] // 5. Otherwise, the ulValueLen field is modified to hold the value // CK_UNAVAILABLE_INFORMATION.
rv = CKR_BUFFER_TOO_SMALL;
CK_UNAVAILABLE_INFORMATION
}
};
}
// [pkcs11-base-v3.0, Section 5.7.5] // If case 2 applies to any of the requested attributes, then the call should return the value // CKR_ATTRIBUTE_TYPE_INVALID. If case 5 applies to any of the requested attributes, then the // call should return the value CKR_BUFFER_TOO_SMALL. As usual, if more than one of these // error codes is applicable, Cryptoki may return any of them. Only if none of them applies to // any of the requested attributes will CKR_OK be returned.
rv
}
#[no_mangle] pubunsafefn BUILTINSC_GetFunctionList(ppFunctionList: CK_FUNCTION_LIST_PTR_PTR) -> CK_RV { if ppFunctionList.is_null() { return CKR_ARGUMENTS_BAD;
} // CK_FUNCTION_LIST_PTR is a *mut CK_FUNCTION_LIST, but as per the // specification, the caller must treat it as *const CK_FUNCTION_LIST.
*ppFunctionList = std::ptr::addr_of!(FUNCTION_LIST) as CK_FUNCTION_LIST_PTR;
CKR_OK
}
#[cfg(test)] mod pkcs11_tests { usecrate::certdata::*; usecrate::internal::*; usecrate::pkcs11::*;
#[test] fn test_main() { // We need to run tests serially because of C_Initialize / C_Finalize calls.
test_simple();
test_c_get_function_list();
test_c_get_attribute();
}
fn test_simple() { let query = &[(CKA_CLASS, CKO_CERTIFICATE_BYTES)];
initialize().expect("initialize should not fail."); let hSession = open_session().expect("open_session should not fail."); let count = find_objects_init(hSession, query).expect("find_objects_init should not fail.");
assert_eq!(count, BUILTINS.len()); letmut results: [CK_OBJECT_HANDLE; 10] = [0; 10]; let n_read =
find_objects(hSession, &mut results).expect("find_objects_init should not fail.");
assert_eq!(n_read, 10);
finalize().expect("finalize should not fail.");
}
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.