Bug 1933630 - Enable the partial history state update collection on GeckoView session...
[gecko.git] / security / manager / ssl / builtins / src / pkcs11.rs
blobfb60aee18711aca90f7f78206ac58e8542fff2f0
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/. */
6 #![allow(non_snake_case)]
8 use pkcs11_bindings::*;
9 use std::slice;
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};
16 use crate::internal::{get_attribute, search};
17 use crate::internal::{ObjectHandle, Query, SearchResult};
19 use crate::version::*;
21 const BUILTINS_VERSION: CK_VERSION = CK_VERSION {
22     major: NSS_BUILTINS_LIBRARY_VERSION_MAJOR,
23     minor: NSS_BUILTINS_LIBRARY_VERSION_MINOR,
26 const FIRMWARE_VERSION: CK_VERSION = CK_VERSION {
27     major: NSS_BUILTINS_FIRMWARE_VERSION_MAJOR,
28     minor: NSS_BUILTINS_FIRMWARE_VERSION_MINOR,
31 const CRYPTOKI_VERSION: CK_VERSION = CK_VERSION {
32     major: NSS_BUILTINS_CRYPTOKI_VERSION_MAJOR,
33     minor: NSS_BUILTINS_CRYPTOKI_VERSION_MINOR,
35 const HARDWARE_VERSION: CK_VERSION = CK_VERSION {
36     major: NSS_BUILTINS_HARDWARE_VERSION_MAJOR,
37     minor: NSS_BUILTINS_HARDWARE_VERSION_MINOR,
40 const MANUFACTURER_ID_BYTES: &[u8; 32] = b"Mozilla Foundation              ";
41 const LIBRARY_DESCRIPTION_BYTES: &[u8; 32] = b"NSS Builtin Object Cryptoki Modu";
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                                             ";
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"                ";
53 #[derive(Debug)]
54 struct PK11Error(CK_RV);
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.
60 // We start the counter at 1 since PKCS#11 reserves 0 to signal an invalid handle
62 type SessionHandle = u32;
63 static NEXT_HANDLE: AtomicU32 = AtomicU32::new(1);
65 // The token needs to keep track of which sessions are open.
67 type SessionSet = BTreeSet<SessionHandle>;
68 static OPEN_SESSIONS: Mutex<Option<SessionSet>> = Mutex::new(None);
70 // Helper functions for accessing OPEN_SESSIONS
72 type SessionSetGuard = MutexGuard<'static, Option<SessionSet>>;
74 fn get_open_sessions_guard() -> Result<SessionSetGuard, PK11Error> {
75     OPEN_SESSIONS
76         .lock()
77         .map_err(|_| PK11Error(CKR_DEVICE_ERROR))
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)
87 // The token needs to cache search results until the client reads them or closes the session.
89 type SearchCache = BTreeMap<SessionHandle, SearchResult>;
90 static SEARCHES: Mutex<Option<SearchCache>> = Mutex::new(None);
92 // Helper functions for accessing SEARCHES
94 type SearchCacheGuard = MutexGuard<'static, Option<SearchCache>>;
96 fn get_search_cache_guard() -> Result<SearchCacheGuard, PK11Error> {
97     SEARCHES.lock().map_err(|_| PK11Error(CKR_DEVICE_ERROR))
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)
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     }
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     }
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     }
140     Ok(())
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     }
153     let mut guard = get_open_sessions_guard()?;
154     let _ = get_open_sessions(&mut guard)?;
155     *guard = None;
157     Ok(())
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     }
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     }
176     Ok(handle)
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     }
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     }
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     }
208     {
209         let mut guard = get_open_sessions_guard()?;
210         let sessions = get_open_sessions(&mut guard)?;
211         sessions.clear();
212     }
214     Ok(())
217 // Internal implementation of C_FindObjectsInit
218 fn find_objects_init(session: SessionHandle, query: &Query) -> Result<usize, PK11Error> {
219     validate_session(session)?;
221     let results = search(query);
222     let count = results.len();
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     }
235 // Internal implementation of C_FindObjects
236 fn find_objects(session: SessionHandle, out: &mut [CK_OBJECT_HANDLE]) -> Result<usize, PK11Error> {
237     validate_session(session)?;
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     }
254 // Internal implementation of C_FindObjectsFinal
255 fn find_objects_final(session: SessionHandle) -> Result<(), PK11Error> {
256     validate_session(session)?;
258     let mut guard = get_search_cache_guard()?;
259     let searches = get_search_cache(&mut guard)?;
260     searches.remove(&session);
261     Ok(())
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     }
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     }
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
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
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
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
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
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
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
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
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
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
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     }
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     }
459 extern "C" fn C_GetSessionInfo(_hSession: CK_SESSION_HANDLE, _pInfo: CK_SESSION_INFO_PTR) -> CK_RV {
460     CKR_FUNCTION_NOT_SUPPORTED
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
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
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
490 extern "C" fn C_Logout(_hSession: CK_SESSION_HANDLE) -> CK_RV {
491     CKR_OK
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
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
513 extern "C" fn C_DestroyObject(_hSession: CK_SESSION_HANDLE, _hObject: CK_OBJECT_HANDLE) -> CK_RV {
514     CKR_FUNCTION_NOT_SUPPORTED
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
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     }
535     let count: usize = match ulCount.try_into() {
536         Ok(count) => count,
537         Err(_) => return CKR_ARGUMENTS_BAD,
538     };
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     //}
553     let handle: ObjectHandle = match hObject.try_into() {
554         Ok(handle) => handle,
555         Err(_) => return CKR_OBJECT_HANDLE_INVALID,
556     };
558     let attrs: &mut [CK_ATTRIBUTE] = unsafe { slice::from_raw_parts_mut(pTemplate, count) };
560     let mut rv = CKR_OK;
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     }
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     }
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
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
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     };
653     let raw_attrs: &[CK_ATTRIBUTE] = unsafe { slice::from_raw_parts_mut(pTemplate, count) };
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     }
665     match find_objects_init(session, &query) {
666         Ok(_) => CKR_OK,
667         Err(PK11Error(e)) => e,
668     }
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     }
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     }
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
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
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
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
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
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
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
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
782 extern "C" fn C_DigestInit(_hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR) -> CK_RV {
783     CKR_FUNCTION_NOT_SUPPORTED
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
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
804 extern "C" fn C_DigestKey(_hSession: CK_SESSION_HANDLE, _hKey: CK_OBJECT_HANDLE) -> CK_RV {
805     CKR_FUNCTION_NOT_SUPPORTED
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1034 extern "C" fn C_GetFunctionStatus(_hSession: CK_SESSION_HANDLE) -> CK_RV {
1035     CKR_FUNCTION_NOT_SUPPORTED
1038 extern "C" fn C_CancelFunction(_hSession: CK_SESSION_HANDLE) -> CK_RV {
1039     CKR_FUNCTION_NOT_SUPPORTED
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
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),
1122 #[no_mangle]
1123 pub unsafe fn BUILTINSC_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
1133 #[cfg(test)]
1134 mod pkcs11_tests {
1135     use crate::certdata::*;
1136     use crate::internal::*;
1137     use crate::pkcs11::*;
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     }
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     }
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::BUILTINSC_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         }
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     }
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());
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);
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     }