Skip to content

Commit e42c41c

Browse files
committed
Refactor object handle iterator and find objects function
- documentation enhanced - documentation example adjusted/simplified - tests simplifications - `find_objects()` method is now calling `iter_objects()` Signed-off-by: Eric Devolder <[email protected]>
1 parent 7377844 commit e42c41c

File tree

2 files changed

+87
-120
lines changed

2 files changed

+87
-120
lines changed

cryptoki/src/session/object_management.rs

Lines changed: 56 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ const MAX_OBJECT_COUNT: usize = 10;
1818
/// Used to iterate over the object handles returned by underlying calls to `C_FindObjects`.
1919
/// The iterator is created by calling the `iter_objects` and `iter_objects_with_cache_size` methods on a `Session` object.
2020
///
21+
/// # Note
22+
///
23+
/// The iterator `new()` method will call `C_FindObjectsInit`. It means that until the iterator is dropped,
24+
/// creating another iterator will result in an error (typically `RvError::OperationActive` ).
25+
///
2126
/// # Example
2227
///
2328
/// ```no_run
@@ -30,47 +35,44 @@ const MAX_OBJECT_COUNT: usize = 10;
3035
/// use cryptoki::types::AuthPin;
3136
/// use std::env;
3237
///
33-
/// fn test() -> Result<(), Error> {
34-
/// let pkcs11 = Pkcs11::new(
35-
/// env::var("PKCS11_SOFTHSM2_MODULE")
36-
/// .unwrap_or_else(|_| "/usr/local/lib/libsofthsm2.so".to_string()),
37-
/// )?;
38+
/// # fn main() -> testresult::TestResult {
39+
/// let pkcs11 = Pkcs11::new(
40+
/// env::var("PKCS11_SOFTHSM2_MODULE")
41+
/// .unwrap_or_else(|_| "/usr/local/lib/libsofthsm2.so".to_string()),
42+
/// )?;
3843
///
39-
/// pkcs11.initialize(CInitializeArgs::OsThreads)?;
40-
/// let slot = pkcs11.get_slots_with_token()?.remove(0);
44+
/// pkcs11.initialize(CInitializeArgs::OsThreads)?;
45+
/// let slot = pkcs11.get_slots_with_token()?.remove(0);
4146
///
42-
/// let session = pkcs11.open_ro_session(slot).unwrap();
43-
/// session.login(UserType::User, Some(&AuthPin::new("fedcba".into())))?;
47+
/// let session = pkcs11.open_ro_session(slot).unwrap();
48+
/// session.login(UserType::User, Some(&AuthPin::new("fedcba".into())))?;
4449
///
45-
/// let token_object = vec![Attribute::Token(true)];
46-
/// let wanted_attr = vec![AttributeType::Label];
50+
/// let token_object = vec![Attribute::Token(true)];
51+
/// let wanted_attr = vec![AttributeType::Label];
4752
///
48-
/// for (idx, obj) in session.iter_objects(&token_object)?.enumerate() {
49-
/// let obj = obj?; // handle potential error condition
53+
/// for (idx, obj) in session.iter_objects(&token_object)?.enumerate() {
54+
/// let obj = obj?; // handle potential error condition
5055
///
51-
/// let attributes = session.get_attributes(obj, &wanted_attr)?;
56+
/// let attributes = session.get_attributes(obj, &wanted_attr)?;
5257
///
53-
/// match attributes.get(0) {
54-
/// Some(Attribute::Label(l)) => {
55-
/// println!(
56-
/// "token object #{}: handle {}, label {}",
57-
/// idx,
58-
/// obj,
59-
/// String::from_utf8(l.to_vec())
60-
/// .unwrap_or_else(|_| "*** not valid utf8 ***".to_string())
61-
/// );
62-
/// }
63-
/// _ => {
64-
/// println!("token object #{}: handle {}, label not found", idx, obj);
65-
/// }
58+
/// match attributes.get(0) {
59+
/// Some(Attribute::Label(l)) => {
60+
/// println!(
61+
/// "token object #{}: handle {}, label {}",
62+
/// idx,
63+
/// obj,
64+
/// String::from_utf8(l.to_vec())
65+
/// .unwrap_or_else(|_| "*** not valid utf8 ***".to_string())
66+
/// );
67+
/// }
68+
/// _ => {
69+
/// println!("token object #{}: handle {}, label not found", idx, obj);
6670
/// }
6771
/// }
68-
/// Ok(())
6972
/// }
73+
/// # Ok(())
74+
/// # }
7075
///
71-
/// pub fn main() {
72-
/// test().unwrap();
73-
/// }
7476
/// ```
7577
#[derive(Debug)]
7678
pub struct ObjectHandleIterator<'a> {
@@ -154,8 +156,7 @@ impl<'a> Iterator for ObjectHandleIterator<'a> {
154156
)
155157
},
156158
None => {
157-
// C_FindObjects() is not implemented on this implementation
158-
// sort of unexpected. TODO: Consider panic!() instead?
159+
// C_FindObjects() is not implemented,, bark and return an error
159160
log::error!("C_FindObjects() is not implemented on this library");
160161
return Some(Err(Error::NullFunctionPointer) as Result<ObjectHandle>);
161162
}
@@ -173,9 +174,9 @@ impl<'a> Iterator for ObjectHandleIterator<'a> {
173174

174175
impl Drop for ObjectHandleIterator<'_> {
175176
fn drop(&mut self) {
176-
// silently pass if C_FindObjectsFinal() is not implemented on this implementation
177-
// this is unexpected. TODO: Consider panic!() instead?
177+
// bark but pass if C_FindObjectsFinal() is not implemented
178178
if let Some(f) = get_pkcs11_func!(self.session.client(), C_FindObjectsFinal) {
179+
log::error!("C_FindObjectsFinal() is not implemented on this library");
179180
// swallow the return value, as we can't do anything about it
180181
let _ = unsafe { f(self.session.handle()) };
181182
}
@@ -220,17 +221,31 @@ impl Session {
220221
template: &[Attribute],
221222
cache_size: usize,
222223
) -> Result<ObjectHandleIterator> {
223-
let template: Vec<CK_ATTRIBUTE> = template.iter().map(|attr| attr.into()).collect();
224+
let template: Vec<CK_ATTRIBUTE> = template.iter().map(Into::into).collect();
224225
ObjectHandleIterator::new(self, template, cache_size)
225226
}
226227

227228
/// Search for session objects matching a template
228229
///
229230
/// # Arguments
231+
///
230232
/// * `template` - A [Attribute] of search parameters that will be used
231233
/// to find objects.
232234
///
233-
/// # Examples
235+
/// # Returns
236+
///
237+
/// Upon success, a vector of [ObjectHandle] wrapped in a Result.
238+
/// Upon failure, the first error encountered.
239+
///
240+
/// # Note
241+
///
242+
/// It is a convenience method that will call [`Session::iter_objects`] and collect the results.
243+
///
244+
/// # See also
245+
///
246+
/// * [`Session::iter_objects`] for a way to specify the cache size
247+
248+
/// # Example
234249
///
235250
/// ```rust
236251
/// # fn main() -> testresult::TestResult {
@@ -260,54 +275,11 @@ impl Session {
260275
/// }
261276
/// # Ok(()) }
262277
/// ```
278+
///
279+
#[inline(always)]
263280
pub fn find_objects(&self, template: &[Attribute]) -> Result<Vec<ObjectHandle>> {
264-
let mut template: Vec<CK_ATTRIBUTE> = template.iter().map(|attr| attr.into()).collect();
265-
266-
unsafe {
267-
Rv::from(get_pkcs11!(self.client(), C_FindObjectsInit)(
268-
self.handle(),
269-
template.as_mut_ptr(),
270-
template.len().try_into()?,
271-
))
272-
.into_result(Function::FindObjectsInit)?;
273-
}
274-
275-
let mut object_handles = [0; MAX_OBJECT_COUNT];
276-
let mut object_count = MAX_OBJECT_COUNT as CK_ULONG; // set to MAX_OBJECT_COUNT to enter loop
277-
let mut objects = Vec::new();
278-
279-
// as long as the number of objects returned equals the maximum number
280-
// of objects that can be returned, we keep calling C_FindObjects
281-
while object_count == MAX_OBJECT_COUNT as CK_ULONG {
282-
unsafe {
283-
Rv::from(get_pkcs11!(self.client(), C_FindObjects)(
284-
self.handle(),
285-
object_handles.as_mut_ptr() as CK_OBJECT_HANDLE_PTR,
286-
MAX_OBJECT_COUNT.try_into()?,
287-
&mut object_count,
288-
))
289-
.into_result(Function::FindObjects)?;
290-
}
291-
292-
// exit loop, no more objects to be returned, no need to extend the objects vector
293-
if object_count == 0 {
294-
break;
295-
}
296-
297-
// extend the objects vector with the new objects
298-
objects.extend_from_slice(&object_handles[..object_count.try_into()?]);
299-
}
300-
301-
unsafe {
302-
Rv::from(get_pkcs11!(self.client(), C_FindObjectsFinal)(
303-
self.handle(),
304-
))
305-
.into_result(Function::FindObjectsFinal)?;
306-
}
307-
308-
let objects = objects.into_iter().map(ObjectHandle::new).collect();
309-
310-
Ok(objects)
281+
self.iter_objects(template)?
282+
.collect::<Result<Vec<ObjectHandle>>>()
311283
}
312284

313285
/// Create a new object

cryptoki/tests/basic.rs

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -313,15 +313,13 @@ fn get_token_info() -> TestResult {
313313

314314
#[test]
315315
#[serial]
316-
fn session_find_objects() {
316+
fn session_find_objects() -> testresult::TestResult {
317317
let (pkcs11, slot) = init_pins();
318318
// open a session
319-
let session = pkcs11.open_rw_session(slot).unwrap();
319+
let session = pkcs11.open_rw_session(slot)?;
320320

321321
// log in the session
322-
session
323-
.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))
324-
.unwrap();
322+
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;
325323

326324
// we generate 11 keys with the same CKA_ID
327325
// we will check 3 different use cases, this will cover all cases for Session.find_objects
@@ -351,32 +349,31 @@ fn session_find_objects() {
351349
Attribute::KeyType(KeyType::DES3),
352350
];
353351

354-
let mut found_keys = session.find_objects(&key_search_template).unwrap();
352+
let mut found_keys = session.find_objects(&key_search_template)?;
355353
assert_eq!(found_keys.len(), 11);
356354

357355
// destroy one key
358-
session.destroy_object(found_keys.pop().unwrap()).unwrap();
356+
session.destroy_object(found_keys.pop().unwrap())?;
359357

360-
let mut found_keys = session.find_objects(&key_search_template).unwrap();
358+
let mut found_keys = session.find_objects(&key_search_template)?;
361359
assert_eq!(found_keys.len(), 10);
362360

363361
// destroy another key
364-
session.destroy_object(found_keys.pop().unwrap()).unwrap();
365-
let found_keys = session.find_objects(&key_search_template).unwrap();
362+
session.destroy_object(found_keys.pop().unwrap())?;
363+
let found_keys = session.find_objects(&key_search_template)?;
366364
assert_eq!(found_keys.len(), 9);
365+
Ok(())
367366
}
368367

369368
#[test]
370369
#[serial]
371-
fn session_objecthandle_iterator() {
370+
fn session_objecthandle_iterator() -> testresult::TestResult {
372371
let (pkcs11, slot) = init_pins();
373372
// open a session
374-
let session = pkcs11.open_rw_session(slot).unwrap();
373+
let session = pkcs11.open_rw_session(slot)?;
375374

376375
// log in the session
377-
session
378-
.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))
379-
.unwrap();
376+
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;
380377

381378
// we generate 11 keys with the same CKA_ID
382379

@@ -389,9 +386,7 @@ fn session_objecthandle_iterator() {
389386
];
390387

391388
// generate a secret key
392-
let _key = session
393-
.generate_key(&Mechanism::Des3KeyGen, &key_template)
394-
.unwrap();
389+
let _key = session.generate_key(&Mechanism::Des3KeyGen, &key_template);
395390
});
396391

397392
// retrieve these keys using this template
@@ -404,9 +399,7 @@ fn session_objecthandle_iterator() {
404399

405400
// test iter_objects_with_cache_size()
406401
// count keys with cache size of 20
407-
let found_keys = session
408-
.iter_objects_with_cache_size(&key_search_template, 20)
409-
.unwrap();
402+
let found_keys = session.iter_objects_with_cache_size(&key_search_template, 20)?;
410403
let found_keys = found_keys.map_while(|key| key.ok()).count();
411404
assert_eq!(found_keys, 11);
412405

@@ -415,23 +408,18 @@ fn session_objecthandle_iterator() {
415408
assert!(found_keys.is_err());
416409

417410
// count keys with cache size of 1
418-
let found_keys = session
419-
.iter_objects_with_cache_size(&key_search_template, 1)
420-
.unwrap();
411+
let found_keys = session.iter_objects_with_cache_size(&key_search_template, 1)?;
421412
let found_keys = found_keys.map_while(|key| key.ok()).count();
422413
assert_eq!(found_keys, 11);
423414

424415
// count keys with cache size of 10
425-
let found_keys = session
426-
.iter_objects_with_cache_size(&key_search_template, 10)
427-
.unwrap();
416+
let found_keys = session.iter_objects_with_cache_size(&key_search_template, 10)?;
428417
let found_keys = found_keys.map_while(|key| key.ok()).count();
429418
assert_eq!(found_keys, 11);
430419

431420
// fetch keys into a vector
432421
let found_keys: Vec<ObjectHandle> = session
433-
.iter_objects_with_cache_size(&key_search_template, 10)
434-
.unwrap()
422+
.iter_objects_with_cache_size(&key_search_template, 10)?
435423
.map_while(|key| key.ok())
436424
.collect();
437425
assert_eq!(found_keys.len(), 11);
@@ -440,24 +428,31 @@ fn session_objecthandle_iterator() {
440428
let key1 = found_keys[1];
441429

442430
session.destroy_object(key0).unwrap();
443-
let found_keys = session
444-
.iter_objects_with_cache_size(&key_search_template, 10)
445-
.unwrap();
431+
let found_keys = session.iter_objects_with_cache_size(&key_search_template, 10)?;
446432
let found_keys = found_keys.map_while(|key| key.ok()).count();
447433
assert_eq!(found_keys, 10);
448434

449435
// destroy another key
450436
session.destroy_object(key1).unwrap();
451-
let found_keys = session
452-
.iter_objects_with_cache_size(&key_search_template, 10)
453-
.unwrap();
437+
let found_keys = session.iter_objects_with_cache_size(&key_search_template, 10)?;
454438
let found_keys = found_keys.map_while(|key| key.ok()).count();
455439
assert_eq!(found_keys, 9);
456440

457441
// test iter_objects()
458-
let found_keys = session.iter_objects(&key_search_template).unwrap();
442+
let found_keys = session.iter_objects(&key_search_template)?;
459443
let found_keys = found_keys.map_while(|key| key.ok()).count();
460444
assert_eq!(found_keys, 9);
445+
446+
// test interleaved iterators - the second iterator should fail
447+
let iter = session.iter_objects(&key_search_template);
448+
let iter2 = session.iter_objects(&key_search_template);
449+
450+
assert!(matches!(iter, Ok(_)));
451+
assert!(matches!(
452+
iter2,
453+
Err(Error::Pkcs11(RvError::OperationActive, _))
454+
));
455+
Ok(())
461456
}
462457

463458
#[test]

0 commit comments

Comments
 (0)