tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pkcs11.rs (37112B)


      1 /* -*- Mode: rust; rust-indent-offset: 4 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #![allow(non_snake_case)]
      7 
      8 use pkcs11_bindings::*;
      9 use std::slice;
     10 
     11 use std::collections::btree_map::Entry;
     12 use std::collections::{BTreeMap, BTreeSet};
     13 use std::sync::atomic::{AtomicU32, Ordering};
     14 use std::sync::{Mutex, MutexGuard};
     15 
     16 use crate::internal::{get_attribute, search};
     17 use crate::internal::{ObjectHandle, Query, SearchResult};
     18 
     19 use crate::version::*;
     20 
     21 const BUILTINS_VERSION: CK_VERSION = CK_VERSION {
     22    major: NSS_BUILTINS_LIBRARY_VERSION_MAJOR,
     23    minor: NSS_BUILTINS_LIBRARY_VERSION_MINOR,
     24 };
     25 
     26 const FIRMWARE_VERSION: CK_VERSION = CK_VERSION {
     27    major: NSS_BUILTINS_FIRMWARE_VERSION_MAJOR,
     28    minor: NSS_BUILTINS_FIRMWARE_VERSION_MINOR,
     29 };
     30 
     31 const CRYPTOKI_VERSION: CK_VERSION = CK_VERSION {
     32    major: NSS_BUILTINS_CRYPTOKI_VERSION_MAJOR,
     33    minor: NSS_BUILTINS_CRYPTOKI_VERSION_MINOR,
     34 };
     35 const HARDWARE_VERSION: CK_VERSION = CK_VERSION {
     36    major: NSS_BUILTINS_HARDWARE_VERSION_MAJOR,
     37    minor: NSS_BUILTINS_HARDWARE_VERSION_MINOR,
     38 };
     39 
     40 const MANUFACTURER_ID_BYTES: &[u8; 32] = b"Mozilla Foundation              ";
     41 const LIBRARY_DESCRIPTION_BYTES: &[u8; 32] = b"NSS Builtin Object Cryptoki Modu";
     42 
     43 const SLOT_COUNT: CK_ULONG = 1;
     44 const SLOT_ID_ROOTS: CK_SLOT_ID = 1;
     45 const SLOT_DESCRIPTION_ROOTS_BYTES: &[u8; 64] =
     46    b"NSS Builtin Objects                                             ";
     47 
     48 const TOKEN_LABEL_ROOTS_BYTES: &[u8; 32] = b"Builtin Object Token            ";
     49 const TOKEN_MODEL_BYTES: &[u8; 16] = b"1               ";
     50 const TOKEN_SERIAL_NUMBER_BYTES: &[u8; 16] = b"1               ";
     51 const TOKEN_UTC_TIME: &[u8; 16] = b"                ";
     52 
     53 #[derive(Debug)]
     54 struct PK11Error(CK_RV);
     55 
     56 // The token assigns session handles using a counter. It would make sense to use a 64 bit counter,
     57 // as there would then be no risk of exhausting the session handle space. However,
     58 // CK_SESSION_HANDLE is defined as a C unsigned long, which is a u32 on some platforms.
     59 //
     60 // We start the counter at 1 since PKCS#11 reserves 0 to signal an invalid handle
     61 //
     62 type SessionHandle = u32;
     63 static NEXT_HANDLE: AtomicU32 = AtomicU32::new(1);
     64 
     65 // The token needs to keep track of which sessions are open.
     66 //
     67 type SessionSet = BTreeSet<SessionHandle>;
     68 static OPEN_SESSIONS: Mutex<Option<SessionSet>> = Mutex::new(None);
     69 
     70 // Helper functions for accessing OPEN_SESSIONS
     71 //
     72 type SessionSetGuard = MutexGuard<'static, Option<SessionSet>>;
     73 
     74 fn get_open_sessions_guard() -> Result<SessionSetGuard, PK11Error> {
     75    OPEN_SESSIONS
     76        .lock()
     77        .map_err(|_| PK11Error(CKR_DEVICE_ERROR))
     78 }
     79 
     80 fn get_open_sessions(guard: &mut SessionSetGuard) -> Result<&mut SessionSet, PK11Error> {
     81    let sessions = guard
     82        .as_mut()
     83        .ok_or(PK11Error(CKR_CRYPTOKI_NOT_INITIALIZED))?;
     84    Ok(sessions)
     85 }
     86 
     87 // The token needs to cache search results until the client reads them or closes the session.
     88 //
     89 type SearchCache = BTreeMap<SessionHandle, SearchResult>;
     90 static SEARCHES: Mutex<Option<SearchCache>> = Mutex::new(None);
     91 
     92 // Helper functions for accessing SEARCHES
     93 //
     94 type SearchCacheGuard = MutexGuard<'static, Option<SearchCache>>;
     95 
     96 fn get_search_cache_guard() -> Result<SearchCacheGuard, PK11Error> {
     97    SEARCHES.lock().map_err(|_| PK11Error(CKR_DEVICE_ERROR))
     98 }
     99 
    100 fn get_search_cache(guard: &mut SearchCacheGuard) -> Result<&mut SearchCache, PK11Error> {
    101    let searches = guard
    102        .as_mut()
    103        .ok_or(PK11Error(CKR_CRYPTOKI_NOT_INITIALIZED))?;
    104    Ok(searches)
    105 }
    106 
    107 fn validate_session(handle: SessionHandle) -> Result<(), PK11Error> {
    108    let mut guard = get_open_sessions_guard()?;
    109    let sessions = get_open_sessions(&mut guard)?;
    110    if sessions.contains(&handle) {
    111        return Ok(());
    112    }
    113    if handle < NEXT_HANDLE.load(Ordering::SeqCst) {
    114        Err(PK11Error(CKR_SESSION_CLOSED))
    115    } else {
    116        // Possible that NEXT_HANDLE wrapped and we should return CKR_SESSION_CLOSED.
    117        // But this is best-effort.
    118        Err(PK11Error(CKR_SESSION_HANDLE_INVALID))
    119    }
    120 }
    121 
    122 // The internal implementation of C_Initialize
    123 fn initialize() -> Result<(), PK11Error> {
    124    {
    125        let mut search_cache_guard = get_search_cache_guard()?;
    126        if (*search_cache_guard).is_some() {
    127            return Err(PK11Error(CKR_CRYPTOKI_ALREADY_INITIALIZED));
    128        }
    129        *search_cache_guard = Some(SearchCache::default());
    130    }
    131 
    132    {
    133        let mut session_guard = get_open_sessions_guard()?;
    134        if (*session_guard).is_some() {
    135            return Err(PK11Error(CKR_CRYPTOKI_ALREADY_INITIALIZED));
    136        }
    137        *session_guard = Some(SessionSet::default());
    138    }
    139 
    140    Ok(())
    141 }
    142 
    143 // The internal implementation of C_Finalize
    144 fn finalize() -> Result<(), PK11Error> {
    145    {
    146        let mut guard = get_search_cache_guard()?;
    147        // Try to access the search cache to ensure we're initialized.
    148        // Returns CKR_CRYPTOKI_NOT_INITIALIZED if we're not.
    149        let _ = get_search_cache(&mut guard)?;
    150        *guard = None;
    151    }
    152 
    153    let mut guard = get_open_sessions_guard()?;
    154    let _ = get_open_sessions(&mut guard)?;
    155    *guard = None;
    156 
    157    Ok(())
    158 }
    159 
    160 // Internal implementation of C_OpenSession
    161 fn open_session() -> Result<SessionHandle, PK11Error> {
    162    let mut handle = NEXT_HANDLE.fetch_add(1, Ordering::SeqCst);
    163    if handle == 0 {
    164        // skip handle 0 if the addition wraps
    165        handle = NEXT_HANDLE.fetch_add(1, Ordering::SeqCst);
    166    }
    167 
    168    let mut guard = get_open_sessions_guard()?;
    169    let sessions = get_open_sessions(&mut guard)?;
    170    while !sessions.insert(handle) {
    171        // this only executes if NEXT_HANDLE wraps while sessions with
    172        // small handles are still open.
    173        handle = NEXT_HANDLE.fetch_add(1, Ordering::SeqCst);
    174    }
    175 
    176    Ok(handle)
    177 }
    178 
    179 // Internal implementation of C_CloseSession
    180 fn close_session(session: SessionHandle) -> Result<(), PK11Error> {
    181    {
    182        let mut guard = get_search_cache_guard()?;
    183        let searches = get_search_cache(&mut guard)?;
    184        searches.remove(&session);
    185    }
    186 
    187    {
    188        let mut guard = get_open_sessions_guard()?;
    189        let sessions = get_open_sessions(&mut guard)?;
    190        if sessions.remove(&session) {
    191            Ok(())
    192        } else if session < NEXT_HANDLE.load(Ordering::SeqCst) {
    193            Err(PK11Error(CKR_SESSION_CLOSED))
    194        } else {
    195            Err(PK11Error(CKR_SESSION_HANDLE_INVALID))
    196        }
    197    }
    198 }
    199 
    200 // Internal implementation of C_CloseAllSessions
    201 fn close_all_sessions() -> Result<(), PK11Error> {
    202    {
    203        let mut guard = get_search_cache_guard()?;
    204        let searches = get_search_cache(&mut guard)?;
    205        searches.clear();
    206    }
    207 
    208    {
    209        let mut guard = get_open_sessions_guard()?;
    210        let sessions = get_open_sessions(&mut guard)?;
    211        sessions.clear();
    212    }
    213 
    214    Ok(())
    215 }
    216 
    217 // Internal implementation of C_FindObjectsInit
    218 fn find_objects_init(session: SessionHandle, query: &Query) -> Result<usize, PK11Error> {
    219    validate_session(session)?;
    220 
    221    let results = search(query);
    222    let count = results.len();
    223 
    224    let mut guard = get_search_cache_guard()?;
    225    let searches = get_search_cache(&mut guard)?;
    226    match searches.entry(session) {
    227        Entry::Occupied(_) => Err(PK11Error(CKR_OPERATION_ACTIVE)),
    228        Entry::Vacant(v) => {
    229            v.insert(results);
    230            Ok(count)
    231        }
    232    }
    233 }
    234 
    235 // Internal implementation of C_FindObjects
    236 fn find_objects(session: SessionHandle, out: &mut [CK_OBJECT_HANDLE]) -> Result<usize, PK11Error> {
    237    validate_session(session)?;
    238 
    239    let mut guard = get_search_cache_guard()?;
    240    let searches = get_search_cache(&mut guard)?;
    241    if let Some(objects) = searches.get_mut(&session) {
    242        for (i, out_i) in out.iter_mut().enumerate() {
    243            match objects.pop() {
    244                Some(object) => *out_i = object.into(),
    245                None => return Ok(i),
    246            }
    247        }
    248        Ok(out.len())
    249    } else {
    250        Ok(0)
    251    }
    252 }
    253 
    254 // Internal implementation of C_FindObjectsFinal
    255 fn find_objects_final(session: SessionHandle) -> Result<(), PK11Error> {
    256    validate_session(session)?;
    257 
    258    let mut guard = get_search_cache_guard()?;
    259    let searches = get_search_cache(&mut guard)?;
    260    searches.remove(&session);
    261    Ok(())
    262 }
    263 
    264 extern "C" fn C_Initialize(_pInitArgs: CK_VOID_PTR) -> CK_RV {
    265    match initialize() {
    266        Ok(_) => CKR_OK,
    267        Err(PK11Error(e)) => e,
    268    }
    269 }
    270 
    271 extern "C" fn C_Finalize(pReserved: CK_VOID_PTR) -> CK_RV {
    272    if !pReserved.is_null() {
    273        return CKR_ARGUMENTS_BAD;
    274    }
    275    match finalize() {
    276        Ok(_) => CKR_OK,
    277        Err(PK11Error(e)) => e,
    278    }
    279 }
    280 
    281 extern "C" fn C_GetInfo(pInfo: CK_INFO_PTR) -> CK_RV {
    282    if pInfo.is_null() {
    283        return CKR_ARGUMENTS_BAD;
    284    }
    285    unsafe {
    286        *pInfo = CK_INFO {
    287            cryptokiVersion: CRYPTOKI_VERSION,
    288            manufacturerID: *MANUFACTURER_ID_BYTES,
    289            flags: 0,
    290            libraryDescription: *LIBRARY_DESCRIPTION_BYTES,
    291            libraryVersion: BUILTINS_VERSION,
    292        };
    293    }
    294    CKR_OK
    295 }
    296 
    297 extern "C" fn C_GetSlotList(
    298    _tokenPresent: CK_BBOOL,
    299    pSlotList: CK_SLOT_ID_PTR,
    300    pulCount: CK_ULONG_PTR,
    301 ) -> CK_RV {
    302    if pulCount.is_null() {
    303        return CKR_ARGUMENTS_BAD;
    304    }
    305    if !pSlotList.is_null() {
    306        if unsafe { *pulCount } < SLOT_COUNT {
    307            return CKR_BUFFER_TOO_SMALL;
    308        }
    309        unsafe {
    310            *pSlotList = SLOT_ID_ROOTS;
    311        }
    312    }
    313    unsafe {
    314        *pulCount = SLOT_COUNT;
    315    }
    316    CKR_OK
    317 }
    318 
    319 extern "C" fn C_GetSlotInfo(slotID: CK_SLOT_ID, pInfo: CK_SLOT_INFO_PTR) -> CK_RV {
    320    if (slotID != SLOT_ID_ROOTS) || pInfo.is_null() {
    321        return CKR_ARGUMENTS_BAD;
    322    }
    323    unsafe {
    324        *pInfo = CK_SLOT_INFO {
    325            slotDescription: *SLOT_DESCRIPTION_ROOTS_BYTES,
    326            manufacturerID: *MANUFACTURER_ID_BYTES,
    327            flags: CKF_TOKEN_PRESENT,
    328            hardwareVersion: HARDWARE_VERSION,
    329            firmwareVersion: FIRMWARE_VERSION,
    330        };
    331    }
    332    CKR_OK
    333 }
    334 
    335 extern "C" fn C_GetTokenInfo(slotID: CK_SLOT_ID, pInfo: CK_TOKEN_INFO_PTR) -> CK_RV {
    336    if (slotID != SLOT_ID_ROOTS) || pInfo.is_null() {
    337        return CKR_ARGUMENTS_BAD;
    338    }
    339    unsafe {
    340        *pInfo = CK_TOKEN_INFO {
    341            label: *TOKEN_LABEL_ROOTS_BYTES,
    342            manufacturerID: *MANUFACTURER_ID_BYTES,
    343            model: *TOKEN_MODEL_BYTES,
    344            serialNumber: *TOKEN_SERIAL_NUMBER_BYTES,
    345            flags: CKF_WRITE_PROTECTED,
    346            ulMaxSessionCount: CK_UNAVAILABLE_INFORMATION,
    347            ulSessionCount: 0,
    348            ulMaxRwSessionCount: CK_UNAVAILABLE_INFORMATION,
    349            ulRwSessionCount: 0,
    350            ulMaxPinLen: CK_UNAVAILABLE_INFORMATION,
    351            ulMinPinLen: CK_UNAVAILABLE_INFORMATION,
    352            ulTotalPublicMemory: CK_UNAVAILABLE_INFORMATION,
    353            ulFreePublicMemory: CK_UNAVAILABLE_INFORMATION,
    354            ulTotalPrivateMemory: CK_UNAVAILABLE_INFORMATION,
    355            ulFreePrivateMemory: CK_UNAVAILABLE_INFORMATION,
    356            hardwareVersion: HARDWARE_VERSION,
    357            firmwareVersion: FIRMWARE_VERSION,
    358            utcTime: *TOKEN_UTC_TIME,
    359        };
    360    }
    361    CKR_OK
    362 }
    363 
    364 extern "C" fn C_GetMechanismList(
    365    slotID: CK_SLOT_ID,
    366    _pMechanismList: CK_MECHANISM_TYPE_PTR,
    367    pulCount: CK_ULONG_PTR,
    368 ) -> CK_RV {
    369    if slotID != SLOT_ID_ROOTS || pulCount.is_null() {
    370        return CKR_ARGUMENTS_BAD;
    371    }
    372    unsafe {
    373        *pulCount = 0;
    374    }
    375    CKR_OK
    376 }
    377 
    378 extern "C" fn C_GetMechanismInfo(
    379    _slotID: CK_SLOT_ID,
    380    _type: CK_MECHANISM_TYPE,
    381    _pInfo: CK_MECHANISM_INFO_PTR,
    382 ) -> CK_RV {
    383    CKR_FUNCTION_NOT_SUPPORTED
    384 }
    385 
    386 extern "C" fn C_InitToken(
    387    _slotID: CK_SLOT_ID,
    388    _pPin: CK_UTF8CHAR_PTR,
    389    _ulPinLen: CK_ULONG,
    390    _pLabel: CK_UTF8CHAR_PTR,
    391 ) -> CK_RV {
    392    CKR_FUNCTION_NOT_SUPPORTED
    393 }
    394 
    395 extern "C" fn C_InitPIN(
    396    _hSession: CK_SESSION_HANDLE,
    397    _pPin: CK_UTF8CHAR_PTR,
    398    _ulPinLen: CK_ULONG,
    399 ) -> CK_RV {
    400    CKR_FUNCTION_NOT_SUPPORTED
    401 }
    402 
    403 extern "C" fn C_SetPIN(
    404    _hSession: CK_SESSION_HANDLE,
    405    _pOldPin: CK_UTF8CHAR_PTR,
    406    _ulOldLen: CK_ULONG,
    407    _pNewPin: CK_UTF8CHAR_PTR,
    408    _ulNewLen: CK_ULONG,
    409 ) -> CK_RV {
    410    CKR_FUNCTION_NOT_SUPPORTED
    411 }
    412 
    413 extern "C" fn C_OpenSession(
    414    slotID: CK_SLOT_ID,
    415    flags: CK_FLAGS,
    416    _pApplication: CK_VOID_PTR,
    417    _Notify: CK_NOTIFY,
    418    phSession: CK_SESSION_HANDLE_PTR,
    419 ) -> CK_RV {
    420    if slotID != SLOT_ID_ROOTS || phSession.is_null() {
    421        return CKR_ARGUMENTS_BAD;
    422    }
    423    // [pkcs11-base-v3.0, Section 5.6.1]
    424    // For legacy reasons, the CKF_SERIAL_SESSION bit MUST always be set; if a call to
    425    // C_OpenSession does not have this bit set, the call should return unsuccessfully with the
    426    // error code CKR_SESSION_PARALLEL_NOT_SUPPORTED.
    427    if flags & CKF_SERIAL_SESSION == 0 {
    428        return CKR_SESSION_PARALLEL_NOT_SUPPORTED;
    429    }
    430    let session_id = match open_session() {
    431        Ok(session_id) => session_id as CK_SESSION_HANDLE,
    432        Err(PK11Error(e)) => return e,
    433    };
    434    unsafe { *phSession = session_id };
    435    CKR_OK
    436 }
    437 
    438 extern "C" fn C_CloseSession(hSession: CK_SESSION_HANDLE) -> CK_RV {
    439    let session: SessionHandle = match hSession.try_into() {
    440        Ok(session) => session,
    441        Err(_) => return CKR_SESSION_HANDLE_INVALID,
    442    };
    443    match close_session(session) {
    444        Ok(_) => CKR_OK,
    445        Err(PK11Error(e)) => e,
    446    }
    447 }
    448 
    449 extern "C" fn C_CloseAllSessions(slotID: CK_SLOT_ID) -> CK_RV {
    450    if slotID != SLOT_ID_ROOTS {
    451        return CKR_ARGUMENTS_BAD;
    452    }
    453    match close_all_sessions() {
    454        Ok(_) => CKR_OK,
    455        Err(PK11Error(e)) => e,
    456    }
    457 }
    458 
    459 extern "C" fn C_GetSessionInfo(_hSession: CK_SESSION_HANDLE, _pInfo: CK_SESSION_INFO_PTR) -> CK_RV {
    460    CKR_FUNCTION_NOT_SUPPORTED
    461 }
    462 
    463 extern "C" fn C_GetOperationState(
    464    _hSession: CK_SESSION_HANDLE,
    465    _pOperationState: CK_BYTE_PTR,
    466    _pulOperationStateLen: CK_ULONG_PTR,
    467 ) -> CK_RV {
    468    CKR_FUNCTION_NOT_SUPPORTED
    469 }
    470 
    471 extern "C" fn C_SetOperationState(
    472    _hSession: CK_SESSION_HANDLE,
    473    _pOperationState: CK_BYTE_PTR,
    474    _ulOperationStateLen: CK_ULONG,
    475    _hEncryptionKey: CK_OBJECT_HANDLE,
    476    _hAuthenticationKey: CK_OBJECT_HANDLE,
    477 ) -> CK_RV {
    478    CKR_FUNCTION_NOT_SUPPORTED
    479 }
    480 
    481 extern "C" fn C_Login(
    482    _hSession: CK_SESSION_HANDLE,
    483    _userType: CK_USER_TYPE,
    484    _pPin: CK_UTF8CHAR_PTR,
    485    _ulPinLen: CK_ULONG,
    486 ) -> CK_RV {
    487    CKR_FUNCTION_NOT_SUPPORTED
    488 }
    489 
    490 extern "C" fn C_Logout(_hSession: CK_SESSION_HANDLE) -> CK_RV {
    491    CKR_OK
    492 }
    493 
    494 extern "C" fn C_CreateObject(
    495    _hSession: CK_SESSION_HANDLE,
    496    _pTemplate: CK_ATTRIBUTE_PTR,
    497    _ulCount: CK_ULONG,
    498    _phObject: CK_OBJECT_HANDLE_PTR,
    499 ) -> CK_RV {
    500    CKR_FUNCTION_NOT_SUPPORTED
    501 }
    502 
    503 extern "C" fn C_CopyObject(
    504    _hSession: CK_SESSION_HANDLE,
    505    _hObject: CK_OBJECT_HANDLE,
    506    _pTemplate: CK_ATTRIBUTE_PTR,
    507    _ulCount: CK_ULONG,
    508    _phNewObject: CK_OBJECT_HANDLE_PTR,
    509 ) -> CK_RV {
    510    CKR_FUNCTION_NOT_SUPPORTED
    511 }
    512 
    513 extern "C" fn C_DestroyObject(_hSession: CK_SESSION_HANDLE, _hObject: CK_OBJECT_HANDLE) -> CK_RV {
    514    CKR_FUNCTION_NOT_SUPPORTED
    515 }
    516 
    517 extern "C" fn C_GetObjectSize(
    518    _hSession: CK_SESSION_HANDLE,
    519    _hObject: CK_OBJECT_HANDLE,
    520    _pulSize: CK_ULONG_PTR,
    521 ) -> CK_RV {
    522    CKR_FUNCTION_NOT_SUPPORTED
    523 }
    524 
    525 extern "C" fn C_GetAttributeValue(
    526    _hSession: CK_SESSION_HANDLE,
    527    hObject: CK_OBJECT_HANDLE,
    528    pTemplate: CK_ATTRIBUTE_PTR,
    529    ulCount: CK_ULONG,
    530 ) -> CK_RV {
    531    if pTemplate.is_null() {
    532        return CKR_ARGUMENTS_BAD;
    533    }
    534 
    535    let count: usize = match ulCount.try_into() {
    536        Ok(count) => count,
    537        Err(_) => return CKR_ARGUMENTS_BAD,
    538    };
    539 
    540    // C_GetAttributeValue has a session handle parameter because PKCS#11 objects can have
    541    // session-bound lifetimes and access controls. We don't have any session objects, and all of
    542    // our token objects are public. So there's no good reason to validate the session handle.
    543    //
    544    //let session: SessionHandle = match hSession.try_into() {
    545    //    Ok(session) => session,
    546    //    Err(_) => return CKR_SESSION_HANDLE_INVALID,
    547    //};
    548    //
    549    //if let Err(PK11Error(e)) = validate_session(session) {
    550    //    return e;
    551    //}
    552 
    553    let handle: ObjectHandle = match hObject.try_into() {
    554        Ok(handle) => handle,
    555        Err(_) => return CKR_OBJECT_HANDLE_INVALID,
    556    };
    557 
    558    let attrs: &mut [CK_ATTRIBUTE] = unsafe { slice::from_raw_parts_mut(pTemplate, count) };
    559 
    560    let mut rv = CKR_OK;
    561 
    562    // Handle requests with null pValue fields
    563    for attr in attrs.iter_mut().filter(|x| x.pValue.is_null()) {
    564        attr.ulValueLen = match get_attribute(attr.type_, &handle) {
    565            None => {
    566                // [pkcs11-base-v3.0, Section 5.7.5]
    567                // 2. [...] if the specified value for the object is invalid (the object does not possess
    568                //    such an attribute), then the ulValueLen field in that triple is modified to hold the
    569                //    value CK_UNAVAILABLE_INFORMATION.
    570                rv = CKR_ATTRIBUTE_TYPE_INVALID;
    571                CK_UNAVAILABLE_INFORMATION
    572            }
    573            Some(attr) => {
    574                // [pkcs11-base-v3.0, Section 5.7.5]
    575                // 3. [...] if the pValue field has the value NULL_PTR, then the ulValueLen field is modified
    576                //    to hold the exact length of the specified attribute for the object.
    577                attr.len() as CK_ULONG
    578            }
    579        }
    580    }
    581 
    582    // Handle requests with non-null pValue fields
    583    for attr in attrs.iter_mut().filter(|x| !x.pValue.is_null()) {
    584        let dst_len: usize = match attr.ulValueLen.try_into() {
    585            Ok(dst_len) => dst_len,
    586            Err(_) => return CKR_ARGUMENTS_BAD,
    587        };
    588        attr.ulValueLen = match get_attribute(attr.type_, &handle) {
    589            None => {
    590                // [pkcs11-base-v3.0, Section 5.7.5]
    591                // 2. [...] if the specified value for the object is invalid (the object does not possess
    592                //    such an attribute), then the ulValueLen field in that triple is modified to hold the
    593                //    value CK_UNAVAILABLE_INFORMATION.
    594                rv = CKR_ATTRIBUTE_TYPE_INVALID;
    595                CK_UNAVAILABLE_INFORMATION
    596            }
    597            Some(src) if dst_len >= src.len() => {
    598                // [pkcs11-base-v3.0, Section 5.7.5]
    599                // 4. [...] if the length specified in ulValueLen is large enough to hold the value
    600                //    of the specified attribute for the object, then that attribute is copied into
    601                //    the buffer located at pValue, and the ulValueLen field is modified to hold
    602                //    the exact length of the attribute.
    603                let dst: &mut [u8] =
    604                    unsafe { slice::from_raw_parts_mut(attr.pValue as *mut u8, dst_len) };
    605                dst[..src.len()].copy_from_slice(src);
    606                src.len() as CK_ULONG
    607            }
    608            _ => {
    609                // [pkcs11-base-v3.0, Section 5.7.5]
    610                // 5. Otherwise, the ulValueLen field is modified to hold the value
    611                //    CK_UNAVAILABLE_INFORMATION.
    612                rv = CKR_BUFFER_TOO_SMALL;
    613                CK_UNAVAILABLE_INFORMATION
    614            }
    615        };
    616    }
    617 
    618    // [pkcs11-base-v3.0, Section 5.7.5]
    619    // If case 2 applies to any of the requested attributes, then the call should return the value
    620    // CKR_ATTRIBUTE_TYPE_INVALID.  If case 5 applies to any of the requested attributes, then the
    621    // call should return the value CKR_BUFFER_TOO_SMALL.  As usual, if more than one of these
    622    // error codes is applicable, Cryptoki may return any of them.  Only if none of them applies to
    623    // any of the requested attributes will CKR_OK be returned.
    624    rv
    625 }
    626 
    627 extern "C" fn C_SetAttributeValue(
    628    _hSession: CK_SESSION_HANDLE,
    629    _hObject: CK_OBJECT_HANDLE,
    630    _pTemplate: CK_ATTRIBUTE_PTR,
    631    _ulCount: CK_ULONG,
    632 ) -> CK_RV {
    633    CKR_FUNCTION_NOT_SUPPORTED
    634 }
    635 
    636 extern "C" fn C_FindObjectsInit(
    637    hSession: CK_SESSION_HANDLE,
    638    pTemplate: CK_ATTRIBUTE_PTR,
    639    ulCount: CK_ULONG,
    640 ) -> CK_RV {
    641    if pTemplate.is_null() {
    642        return CKR_ARGUMENTS_BAD;
    643    }
    644    let count: usize = match ulCount.try_into() {
    645        Ok(count) => count,
    646        Err(_) => return CKR_ARGUMENTS_BAD,
    647    };
    648    let session: SessionHandle = match hSession.try_into() {
    649        Ok(session) => session,
    650        Err(_) => return CKR_SESSION_HANDLE_INVALID,
    651    };
    652 
    653    let raw_attrs: &[CK_ATTRIBUTE] = unsafe { slice::from_raw_parts_mut(pTemplate, count) };
    654 
    655    let mut query: Vec<(CK_ATTRIBUTE_TYPE, &[u8])> = Vec::with_capacity(raw_attrs.len());
    656    for attr in raw_attrs {
    657        match usize::try_from(attr.ulValueLen) {
    658            Ok(len) => query.push((attr.type_, unsafe {
    659                slice::from_raw_parts_mut(attr.pValue as *mut u8, len)
    660            })),
    661            Err(_) => return CKR_ARGUMENTS_BAD,
    662        }
    663    }
    664 
    665    match find_objects_init(session, &query) {
    666        Ok(_) => CKR_OK,
    667        Err(PK11Error(e)) => e,
    668    }
    669 }
    670 
    671 extern "C" fn C_FindObjects(
    672    hSession: CK_SESSION_HANDLE,
    673    phObject: CK_OBJECT_HANDLE_PTR,
    674    ulMaxObjectCount: CK_ULONG,
    675    pulObjectCount: CK_ULONG_PTR,
    676 ) -> CK_RV {
    677    if phObject.is_null() || pulObjectCount.is_null() {
    678        return CKR_ARGUMENTS_BAD;
    679    }
    680    let max_object_count: usize = match ulMaxObjectCount.try_into() {
    681        Ok(max_object_count) => max_object_count,
    682        Err(_) => return CKR_ARGUMENTS_BAD,
    683    };
    684    let session: SessionHandle = match hSession.try_into() {
    685        Ok(session) => session,
    686        Err(_) => return CKR_SESSION_HANDLE_INVALID,
    687    };
    688    let out: &mut [CK_OBJECT_HANDLE] =
    689        unsafe { slice::from_raw_parts_mut(phObject, max_object_count) };
    690    match find_objects(session, out) {
    691        Ok(num_found) => {
    692            unsafe { *pulObjectCount = num_found as CK_ULONG };
    693            CKR_OK
    694        }
    695        Err(PK11Error(e)) => e,
    696    }
    697 }
    698 
    699 extern "C" fn C_FindObjectsFinal(hSession: CK_SESSION_HANDLE) -> CK_RV {
    700    let session: SessionHandle = match hSession.try_into() {
    701        Ok(session) => session,
    702        Err(_) => return CKR_SESSION_HANDLE_INVALID,
    703    };
    704    match find_objects_final(session) {
    705        Ok(()) => CKR_OK,
    706        Err(PK11Error(e)) => e,
    707    }
    708 }
    709 
    710 extern "C" fn C_EncryptInit(
    711    _hSession: CK_SESSION_HANDLE,
    712    _pMechanism: CK_MECHANISM_PTR,
    713    _hKey: CK_OBJECT_HANDLE,
    714 ) -> CK_RV {
    715    CKR_FUNCTION_NOT_SUPPORTED
    716 }
    717 
    718 extern "C" fn C_Encrypt(
    719    _hSession: CK_SESSION_HANDLE,
    720    _pData: CK_BYTE_PTR,
    721    _ulDataLen: CK_ULONG,
    722    _pEncryptedData: CK_BYTE_PTR,
    723    _pulEncryptedDataLen: CK_ULONG_PTR,
    724 ) -> CK_RV {
    725    CKR_FUNCTION_NOT_SUPPORTED
    726 }
    727 
    728 extern "C" fn C_EncryptUpdate(
    729    _hSession: CK_SESSION_HANDLE,
    730    _pPart: CK_BYTE_PTR,
    731    _ulPartLen: CK_ULONG,
    732    _pEncryptedPart: CK_BYTE_PTR,
    733    _pulEncryptedPartLen: CK_ULONG_PTR,
    734 ) -> CK_RV {
    735    CKR_FUNCTION_NOT_SUPPORTED
    736 }
    737 
    738 extern "C" fn C_EncryptFinal(
    739    _hSession: CK_SESSION_HANDLE,
    740    _pLastEncryptedPart: CK_BYTE_PTR,
    741    _pulLastEncryptedPartLen: CK_ULONG_PTR,
    742 ) -> CK_RV {
    743    CKR_FUNCTION_NOT_SUPPORTED
    744 }
    745 
    746 extern "C" fn C_DecryptInit(
    747    _hSession: CK_SESSION_HANDLE,
    748    _pMechanism: CK_MECHANISM_PTR,
    749    _hKey: CK_OBJECT_HANDLE,
    750 ) -> CK_RV {
    751    CKR_FUNCTION_NOT_SUPPORTED
    752 }
    753 
    754 extern "C" fn C_Decrypt(
    755    _hSession: CK_SESSION_HANDLE,
    756    _pEncryptedData: CK_BYTE_PTR,
    757    _ulEncryptedDataLen: CK_ULONG,
    758    _pData: CK_BYTE_PTR,
    759    _pulDataLen: CK_ULONG_PTR,
    760 ) -> CK_RV {
    761    CKR_FUNCTION_NOT_SUPPORTED
    762 }
    763 
    764 extern "C" fn C_DecryptUpdate(
    765    _hSession: CK_SESSION_HANDLE,
    766    _pEncryptedPart: CK_BYTE_PTR,
    767    _ulEncryptedPartLen: CK_ULONG,
    768    _pPart: CK_BYTE_PTR,
    769    _pulPartLen: CK_ULONG_PTR,
    770 ) -> CK_RV {
    771    CKR_FUNCTION_NOT_SUPPORTED
    772 }
    773 
    774 extern "C" fn C_DecryptFinal(
    775    _hSession: CK_SESSION_HANDLE,
    776    _pLastPart: CK_BYTE_PTR,
    777    _pulLastPartLen: CK_ULONG_PTR,
    778 ) -> CK_RV {
    779    CKR_FUNCTION_NOT_SUPPORTED
    780 }
    781 
    782 extern "C" fn C_DigestInit(_hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR) -> CK_RV {
    783    CKR_FUNCTION_NOT_SUPPORTED
    784 }
    785 
    786 extern "C" fn C_Digest(
    787    _hSession: CK_SESSION_HANDLE,
    788    _pData: CK_BYTE_PTR,
    789    _ulDataLen: CK_ULONG,
    790    _pDigest: CK_BYTE_PTR,
    791    _pulDigestLen: CK_ULONG_PTR,
    792 ) -> CK_RV {
    793    CKR_FUNCTION_NOT_SUPPORTED
    794 }
    795 
    796 extern "C" fn C_DigestUpdate(
    797    _hSession: CK_SESSION_HANDLE,
    798    _pPart: CK_BYTE_PTR,
    799    _ulPartLen: CK_ULONG,
    800 ) -> CK_RV {
    801    CKR_FUNCTION_NOT_SUPPORTED
    802 }
    803 
    804 extern "C" fn C_DigestKey(_hSession: CK_SESSION_HANDLE, _hKey: CK_OBJECT_HANDLE) -> CK_RV {
    805    CKR_FUNCTION_NOT_SUPPORTED
    806 }
    807 
    808 extern "C" fn C_DigestFinal(
    809    _hSession: CK_SESSION_HANDLE,
    810    _pDigest: CK_BYTE_PTR,
    811    _pulDigestLen: CK_ULONG_PTR,
    812 ) -> CK_RV {
    813    CKR_FUNCTION_NOT_SUPPORTED
    814 }
    815 
    816 extern "C" fn C_SignInit(
    817    _hSession: CK_SESSION_HANDLE,
    818    _pMechanism: CK_MECHANISM_PTR,
    819    _hKey: CK_OBJECT_HANDLE,
    820 ) -> CK_RV {
    821    CKR_FUNCTION_NOT_SUPPORTED
    822 }
    823 
    824 extern "C" fn C_Sign(
    825    _hSession: CK_SESSION_HANDLE,
    826    _pData: CK_BYTE_PTR,
    827    _ulDataLen: CK_ULONG,
    828    _pSignature: CK_BYTE_PTR,
    829    _pulSignatureLen: CK_ULONG_PTR,
    830 ) -> CK_RV {
    831    CKR_FUNCTION_NOT_SUPPORTED
    832 }
    833 
    834 extern "C" fn C_SignUpdate(
    835    _hSession: CK_SESSION_HANDLE,
    836    _pPart: CK_BYTE_PTR,
    837    _ulPartLen: CK_ULONG,
    838 ) -> CK_RV {
    839    CKR_FUNCTION_NOT_SUPPORTED
    840 }
    841 
    842 extern "C" fn C_SignFinal(
    843    _hSession: CK_SESSION_HANDLE,
    844    _pSignature: CK_BYTE_PTR,
    845    _pulSignatureLen: CK_ULONG_PTR,
    846 ) -> CK_RV {
    847    CKR_FUNCTION_NOT_SUPPORTED
    848 }
    849 
    850 extern "C" fn C_SignRecoverInit(
    851    _hSession: CK_SESSION_HANDLE,
    852    _pMechanism: CK_MECHANISM_PTR,
    853    _hKey: CK_OBJECT_HANDLE,
    854 ) -> CK_RV {
    855    CKR_FUNCTION_NOT_SUPPORTED
    856 }
    857 
    858 extern "C" fn C_SignRecover(
    859    _hSession: CK_SESSION_HANDLE,
    860    _pData: CK_BYTE_PTR,
    861    _ulDataLen: CK_ULONG,
    862    _pSignature: CK_BYTE_PTR,
    863    _pulSignatureLen: CK_ULONG_PTR,
    864 ) -> CK_RV {
    865    CKR_FUNCTION_NOT_SUPPORTED
    866 }
    867 
    868 extern "C" fn C_VerifyInit(
    869    _hSession: CK_SESSION_HANDLE,
    870    _pMechanism: CK_MECHANISM_PTR,
    871    _hKey: CK_OBJECT_HANDLE,
    872 ) -> CK_RV {
    873    CKR_FUNCTION_NOT_SUPPORTED
    874 }
    875 
    876 extern "C" fn C_Verify(
    877    _hSession: CK_SESSION_HANDLE,
    878    _pData: CK_BYTE_PTR,
    879    _ulDataLen: CK_ULONG,
    880    _pSignature: CK_BYTE_PTR,
    881    _ulSignatureLen: CK_ULONG,
    882 ) -> CK_RV {
    883    CKR_FUNCTION_NOT_SUPPORTED
    884 }
    885 
    886 extern "C" fn C_VerifyUpdate(
    887    _hSession: CK_SESSION_HANDLE,
    888    _pPart: CK_BYTE_PTR,
    889    _ulPartLen: CK_ULONG,
    890 ) -> CK_RV {
    891    CKR_FUNCTION_NOT_SUPPORTED
    892 }
    893 
    894 extern "C" fn C_VerifyFinal(
    895    _hSession: CK_SESSION_HANDLE,
    896    _pSignature: CK_BYTE_PTR,
    897    _ulSignatureLen: CK_ULONG,
    898 ) -> CK_RV {
    899    CKR_FUNCTION_NOT_SUPPORTED
    900 }
    901 
    902 extern "C" fn C_VerifyRecoverInit(
    903    _hSession: CK_SESSION_HANDLE,
    904    _pMechanism: CK_MECHANISM_PTR,
    905    _hKey: CK_OBJECT_HANDLE,
    906 ) -> CK_RV {
    907    CKR_FUNCTION_NOT_SUPPORTED
    908 }
    909 
    910 extern "C" fn C_VerifyRecover(
    911    _hSession: CK_SESSION_HANDLE,
    912    _pSignature: CK_BYTE_PTR,
    913    _ulSignatureLen: CK_ULONG,
    914    _pData: CK_BYTE_PTR,
    915    _pulDataLen: CK_ULONG_PTR,
    916 ) -> CK_RV {
    917    CKR_FUNCTION_NOT_SUPPORTED
    918 }
    919 
    920 extern "C" fn C_DigestEncryptUpdate(
    921    _hSession: CK_SESSION_HANDLE,
    922    _pPart: CK_BYTE_PTR,
    923    _ulPartLen: CK_ULONG,
    924    _pEncryptedPart: CK_BYTE_PTR,
    925    _pulEncryptedPartLen: CK_ULONG_PTR,
    926 ) -> CK_RV {
    927    CKR_FUNCTION_NOT_SUPPORTED
    928 }
    929 
    930 extern "C" fn C_DecryptDigestUpdate(
    931    _hSession: CK_SESSION_HANDLE,
    932    _pEncryptedPart: CK_BYTE_PTR,
    933    _ulEncryptedPartLen: CK_ULONG,
    934    _pPart: CK_BYTE_PTR,
    935    _pulPartLen: CK_ULONG_PTR,
    936 ) -> CK_RV {
    937    CKR_FUNCTION_NOT_SUPPORTED
    938 }
    939 
    940 extern "C" fn C_SignEncryptUpdate(
    941    _hSession: CK_SESSION_HANDLE,
    942    _pPart: CK_BYTE_PTR,
    943    _ulPartLen: CK_ULONG,
    944    _pEncryptedPart: CK_BYTE_PTR,
    945    _pulEncryptedPartLen: CK_ULONG_PTR,
    946 ) -> CK_RV {
    947    CKR_FUNCTION_NOT_SUPPORTED
    948 }
    949 
    950 extern "C" fn C_DecryptVerifyUpdate(
    951    _hSession: CK_SESSION_HANDLE,
    952    _pEncryptedPart: CK_BYTE_PTR,
    953    _ulEncryptedPartLen: CK_ULONG,
    954    _pPart: CK_BYTE_PTR,
    955    _pulPartLen: CK_ULONG_PTR,
    956 ) -> CK_RV {
    957    CKR_FUNCTION_NOT_SUPPORTED
    958 }
    959 
    960 extern "C" fn C_GenerateKey(
    961    _hSession: CK_SESSION_HANDLE,
    962    _pMechanism: CK_MECHANISM_PTR,
    963    _pTemplate: CK_ATTRIBUTE_PTR,
    964    _ulCount: CK_ULONG,
    965    _phKey: CK_OBJECT_HANDLE_PTR,
    966 ) -> CK_RV {
    967    CKR_FUNCTION_NOT_SUPPORTED
    968 }
    969 
    970 extern "C" fn C_GenerateKeyPair(
    971    _hSession: CK_SESSION_HANDLE,
    972    _pMechanism: CK_MECHANISM_PTR,
    973    _pPublicKeyTemplate: CK_ATTRIBUTE_PTR,
    974    _ulPublicKeyAttributeCount: CK_ULONG,
    975    _pPrivateKeyTemplate: CK_ATTRIBUTE_PTR,
    976    _ulPrivateKeyAttributeCount: CK_ULONG,
    977    _phPublicKey: CK_OBJECT_HANDLE_PTR,
    978    _phPrivateKey: CK_OBJECT_HANDLE_PTR,
    979 ) -> CK_RV {
    980    CKR_FUNCTION_NOT_SUPPORTED
    981 }
    982 
    983 extern "C" fn C_WrapKey(
    984    _hSession: CK_SESSION_HANDLE,
    985    _pMechanism: CK_MECHANISM_PTR,
    986    _hWrappingKey: CK_OBJECT_HANDLE,
    987    _hKey: CK_OBJECT_HANDLE,
    988    _pWrappedKey: CK_BYTE_PTR,
    989    _pulWrappedKeyLen: CK_ULONG_PTR,
    990 ) -> CK_RV {
    991    CKR_FUNCTION_NOT_SUPPORTED
    992 }
    993 
    994 extern "C" fn C_UnwrapKey(
    995    _hSession: CK_SESSION_HANDLE,
    996    _pMechanism: CK_MECHANISM_PTR,
    997    _hUnwrappingKey: CK_OBJECT_HANDLE,
    998    _pWrappedKey: CK_BYTE_PTR,
    999    _ulWrappedKeyLen: CK_ULONG,
   1000    _pTemplate: CK_ATTRIBUTE_PTR,
   1001    _ulAttributeCount: CK_ULONG,
   1002    _phKey: CK_OBJECT_HANDLE_PTR,
   1003 ) -> CK_RV {
   1004    CKR_FUNCTION_NOT_SUPPORTED
   1005 }
   1006 
   1007 extern "C" fn C_DeriveKey(
   1008    _hSession: CK_SESSION_HANDLE,
   1009    _pMechanism: CK_MECHANISM_PTR,
   1010    _hBaseKey: CK_OBJECT_HANDLE,
   1011    _pTemplate: CK_ATTRIBUTE_PTR,
   1012    _ulAttributeCount: CK_ULONG,
   1013    _phKey: CK_OBJECT_HANDLE_PTR,
   1014 ) -> CK_RV {
   1015    CKR_FUNCTION_NOT_SUPPORTED
   1016 }
   1017 
   1018 extern "C" fn C_SeedRandom(
   1019    _hSession: CK_SESSION_HANDLE,
   1020    _pSeed: CK_BYTE_PTR,
   1021    _ulSeedLen: CK_ULONG,
   1022 ) -> CK_RV {
   1023    CKR_FUNCTION_NOT_SUPPORTED
   1024 }
   1025 
   1026 extern "C" fn C_GenerateRandom(
   1027    _hSession: CK_SESSION_HANDLE,
   1028    _RandomData: CK_BYTE_PTR,
   1029    _ulRandomLen: CK_ULONG,
   1030 ) -> CK_RV {
   1031    CKR_FUNCTION_NOT_SUPPORTED
   1032 }
   1033 
   1034 extern "C" fn C_GetFunctionStatus(_hSession: CK_SESSION_HANDLE) -> CK_RV {
   1035    CKR_FUNCTION_NOT_SUPPORTED
   1036 }
   1037 
   1038 extern "C" fn C_CancelFunction(_hSession: CK_SESSION_HANDLE) -> CK_RV {
   1039    CKR_FUNCTION_NOT_SUPPORTED
   1040 }
   1041 
   1042 extern "C" fn C_WaitForSlotEvent(
   1043    _flags: CK_FLAGS,
   1044    _pSlot: CK_SLOT_ID_PTR,
   1045    _pRserved: CK_VOID_PTR,
   1046 ) -> CK_RV {
   1047    CKR_FUNCTION_NOT_SUPPORTED
   1048 }
   1049 
   1050 pub static FUNCTION_LIST: CK_FUNCTION_LIST = CK_FUNCTION_LIST {
   1051    version: CRYPTOKI_VERSION,
   1052    C_Initialize: Some(C_Initialize),
   1053    C_Finalize: Some(C_Finalize),
   1054    C_GetInfo: Some(C_GetInfo),
   1055    C_GetFunctionList: None,
   1056    C_GetSlotList: Some(C_GetSlotList),
   1057    C_GetSlotInfo: Some(C_GetSlotInfo),
   1058    C_GetTokenInfo: Some(C_GetTokenInfo),
   1059    C_GetMechanismList: Some(C_GetMechanismList),
   1060    C_GetMechanismInfo: Some(C_GetMechanismInfo),
   1061    C_InitToken: Some(C_InitToken),
   1062    C_InitPIN: Some(C_InitPIN),
   1063    C_SetPIN: Some(C_SetPIN),
   1064    C_OpenSession: Some(C_OpenSession),
   1065    C_CloseSession: Some(C_CloseSession),
   1066    C_CloseAllSessions: Some(C_CloseAllSessions),
   1067    C_GetSessionInfo: Some(C_GetSessionInfo),
   1068    C_GetOperationState: Some(C_GetOperationState),
   1069    C_SetOperationState: Some(C_SetOperationState),
   1070    C_Login: Some(C_Login),
   1071    C_Logout: Some(C_Logout),
   1072    C_CreateObject: Some(C_CreateObject),
   1073    C_CopyObject: Some(C_CopyObject),
   1074    C_DestroyObject: Some(C_DestroyObject),
   1075    C_GetObjectSize: Some(C_GetObjectSize),
   1076    C_GetAttributeValue: Some(C_GetAttributeValue),
   1077    C_SetAttributeValue: Some(C_SetAttributeValue),
   1078    C_FindObjectsInit: Some(C_FindObjectsInit),
   1079    C_FindObjects: Some(C_FindObjects),
   1080    C_FindObjectsFinal: Some(C_FindObjectsFinal),
   1081    C_EncryptInit: Some(C_EncryptInit),
   1082    C_Encrypt: Some(C_Encrypt),
   1083    C_EncryptUpdate: Some(C_EncryptUpdate),
   1084    C_EncryptFinal: Some(C_EncryptFinal),
   1085    C_DecryptInit: Some(C_DecryptInit),
   1086    C_Decrypt: Some(C_Decrypt),
   1087    C_DecryptUpdate: Some(C_DecryptUpdate),
   1088    C_DecryptFinal: Some(C_DecryptFinal),
   1089    C_DigestInit: Some(C_DigestInit),
   1090    C_Digest: Some(C_Digest),
   1091    C_DigestUpdate: Some(C_DigestUpdate),
   1092    C_DigestKey: Some(C_DigestKey),
   1093    C_DigestFinal: Some(C_DigestFinal),
   1094    C_SignInit: Some(C_SignInit),
   1095    C_Sign: Some(C_Sign),
   1096    C_SignUpdate: Some(C_SignUpdate),
   1097    C_SignFinal: Some(C_SignFinal),
   1098    C_SignRecoverInit: Some(C_SignRecoverInit),
   1099    C_SignRecover: Some(C_SignRecover),
   1100    C_VerifyInit: Some(C_VerifyInit),
   1101    C_Verify: Some(C_Verify),
   1102    C_VerifyUpdate: Some(C_VerifyUpdate),
   1103    C_VerifyFinal: Some(C_VerifyFinal),
   1104    C_VerifyRecoverInit: Some(C_VerifyRecoverInit),
   1105    C_VerifyRecover: Some(C_VerifyRecover),
   1106    C_DigestEncryptUpdate: Some(C_DigestEncryptUpdate),
   1107    C_DecryptDigestUpdate: Some(C_DecryptDigestUpdate),
   1108    C_SignEncryptUpdate: Some(C_SignEncryptUpdate),
   1109    C_DecryptVerifyUpdate: Some(C_DecryptVerifyUpdate),
   1110    C_GenerateKey: Some(C_GenerateKey),
   1111    C_GenerateKeyPair: Some(C_GenerateKeyPair),
   1112    C_WrapKey: Some(C_WrapKey),
   1113    C_UnwrapKey: Some(C_UnwrapKey),
   1114    C_DeriveKey: Some(C_DeriveKey),
   1115    C_SeedRandom: Some(C_SeedRandom),
   1116    C_GenerateRandom: Some(C_GenerateRandom),
   1117    C_GetFunctionStatus: Some(C_GetFunctionStatus),
   1118    C_CancelFunction: Some(C_CancelFunction),
   1119    C_WaitForSlotEvent: Some(C_WaitForSlotEvent),
   1120 };
   1121 
   1122 #[no_mangle]
   1123 pub unsafe fn TRUST_ANCHORS_GetFunctionList(ppFunctionList: CK_FUNCTION_LIST_PTR_PTR) -> CK_RV {
   1124    if ppFunctionList.is_null() {
   1125        return CKR_ARGUMENTS_BAD;
   1126    }
   1127    // CK_FUNCTION_LIST_PTR is a *mut CK_FUNCTION_LIST, but as per the
   1128    // specification, the caller must treat it as *const CK_FUNCTION_LIST.
   1129    *ppFunctionList = std::ptr::addr_of!(FUNCTION_LIST) as CK_FUNCTION_LIST_PTR;
   1130    CKR_OK
   1131 }
   1132 
   1133 #[cfg(test)]
   1134 mod pkcs11_tests {
   1135    use crate::certdata::*;
   1136    use crate::internal::*;
   1137    use crate::pkcs11::*;
   1138 
   1139    #[test]
   1140    fn test_main() {
   1141        // We need to run tests serially because of C_Initialize / C_Finalize calls.
   1142        test_simple();
   1143        test_c_get_function_list();
   1144        test_c_get_attribute();
   1145    }
   1146 
   1147    fn test_simple() {
   1148        let query = &[(CKA_CLASS, CKO_CERTIFICATE_BYTES)];
   1149        initialize().expect("initialize should not fail.");
   1150        let hSession = open_session().expect("open_session should not fail.");
   1151        let count = find_objects_init(hSession, query).expect("find_objects_init should not fail.");
   1152        assert_eq!(count, BUILTINS.len());
   1153        let mut results: [CK_OBJECT_HANDLE; 10] = [0; 10];
   1154        let n_read =
   1155            find_objects(hSession, &mut results).expect("find_objects_init should not fail.");
   1156        assert_eq!(n_read, 10);
   1157        finalize().expect("finalize should not fail.");
   1158    }
   1159 
   1160    fn test_c_get_function_list() {
   1161        let c_null = 0 as *mut std::ffi::c_void;
   1162        let mut pFunctionList: CK_FUNCTION_LIST_PTR = c_null as CK_FUNCTION_LIST_PTR;
   1163        let rv = unsafe { crate::pkcs11::TRUST_ANCHORS_GetFunctionList(&mut pFunctionList) };
   1164        assert_eq!(CKR_OK, rv);
   1165        if let Some(pC_Initialize) = unsafe { (*pFunctionList).C_Initialize } {
   1166            let rv = unsafe { pC_Initialize(c_null) };
   1167            assert_eq!(CKR_OK, rv);
   1168        } else {
   1169            assert!(false);
   1170        }
   1171 
   1172        if let Some(pC_Finalize) = unsafe { (*pFunctionList).C_Finalize } {
   1173            let rv = unsafe { pC_Finalize(c_null) };
   1174            assert_eq!(CKR_OK, rv);
   1175        } else {
   1176            assert!(false);
   1177        }
   1178    }
   1179 
   1180    fn test_c_get_attribute() {
   1181        let c_null = 0 as *mut std::ffi::c_void;
   1182        let template: &mut [CK_ATTRIBUTE] = &mut [CK_ATTRIBUTE {
   1183            type_: CKA_SUBJECT,
   1184            pValue: c_null,
   1185            ulValueLen: 0,
   1186        }];
   1187        let template_ptr = &mut template[0] as CK_ATTRIBUTE_PTR;
   1188        let object: CK_OBJECT_HANDLE = 2;
   1189        let mut session: CK_SESSION_HANDLE = 0;
   1190        assert_eq!(CKR_OK, C_Initialize(c_null));
   1191        assert_eq!(
   1192            CKR_OK,
   1193            C_OpenSession(
   1194                SLOT_ID_ROOTS,
   1195                CKF_SERIAL_SESSION,
   1196                c_null,
   1197                None,
   1198                &mut session as *mut CK_SESSION_HANDLE
   1199            )
   1200        );
   1201        assert_eq!(
   1202            CKR_OK,
   1203            C_GetAttributeValue(session, object, template_ptr, 1)
   1204        );
   1205        let len = template[0].ulValueLen as usize;
   1206        assert_eq!(len, BUILTINS[0].der_name.len());
   1207 
   1208        let value: &mut [u8] = &mut vec![0; 1];
   1209        let value_ptr: *mut u8 = &mut value[0] as *mut u8;
   1210        template[0].pValue = value_ptr as *mut std::ffi::c_void;
   1211        template[0].ulValueLen = 1;
   1212        assert_eq!(
   1213            CKR_BUFFER_TOO_SMALL,
   1214            C_GetAttributeValue(session, object, template_ptr, 1)
   1215        );
   1216        assert_eq!(template[0].ulValueLen, CK_UNAVAILABLE_INFORMATION);
   1217 
   1218        let value: &mut [u8] = &mut vec![0; len];
   1219        let value_ptr: *mut u8 = &mut value[0] as *mut u8;
   1220        template[0].pValue = value_ptr as *mut std::ffi::c_void;
   1221        template[0].ulValueLen = len as CK_ULONG;
   1222        assert_eq!(
   1223            CKR_OK,
   1224            C_GetAttributeValue(session, object, template_ptr, 1)
   1225        );
   1226        assert_eq!(value, BUILTINS[0].der_name);
   1227        assert_eq!(CKR_OK, C_Finalize(c_null));
   1228    }
   1229 }