The authors of PKCS #11 v2.40 utilize a common pattern when an API returns a variable length list of items. In APIs such as C_GetSlotList
and C_GetMechanismList
, the application is expected to call the APIs twice. In the first invocation, a pointer to a CK_ULONG
is set to the number of items that will be returned on the next invocation. This allows the application to allocate enough memory and invoke the API again to retrieve the results.
The C_FindObjects
call also returns a variable number of items, but it uses a different paradigm. The parameter CK_OBJECT_HANDLE_PTR phObject
is set to the head of the result list. The parameter CK_ULONG_PTR pulObjectCount
is set to the number of items returned, which is ensured to be less than CK_ULONG ulMaxObjectCount
.
The standard does not explicitly say that phObject
must be a valid pointer to a block of memory large enough to hold ulMaxObjectCount
CK_OBJECT_HANDLE
s.
One could interpret the standard as meaning that the application must pessimistically allocate enough memory for ulMaxObjectCount
objects. Alternately, one could interpret the standard as meaning that the PKCS #11 implementation will allocate pulObjectCount
CK_OBJECT_HANDLE
s and it is then the application's responsibility to free that memory. This later interpretation seems suspect however, as no where else in the standard does the implementation of PKCS #11 ever allocate memory.
The passage is:
C_FindObjects continues a search for token and session objects that
match a template, obtaining additional object handles. hSession is
the session’s handle; phObject points to the location that receives
the list (array) of additional object handles; ulMaxObjectCount is
the maximum number of object handles to be returned; pulObjectCount
points to the location that receives the actual number of object
handles returned.
If there are no more objects matching the template, then the location
that pulObjectCount points to receives the value 0.
The search MUST have been initialized with C_FindObjectsInit.
The non-normative example is not very helpful, as it sets ulMaxObjectCount
to 1. It does, however, allocate the memory for that one entry. Which seems to indicate that the application must pessimistically pre-allocate the memory.
CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hObject;
CK_ULONG ulObjectCount;
CK_RV rv;
.
.
rv = C_FindObjectsInit(hSession, NULL_PTR, 0);
assert(rv == CKR_OK);
while (1) {
rv = C_FindObjects(hSession, &hObject, 1, &ulObjectCount);
if (rv != CKR_OK || ulObjectCount == 0)
break;
.
.
}
rv = C_FindObjectsFinal(hSession);
assert(rv == CKR_OK);
Specification Link: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.pdf
Yes, it would appear that the application is responsible for allocating space for the object handles returned by C_FindObjects()
. The example code does this, even though it only requests a single object handle at a time, and so should you.
You could just as well rewrite the example code to request multiple object handles, e.g. like this:
#define MAX_OBJECT_COUNT 100 /* arbitrary value */
K_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hObjects[MAX_OBJECT_COUNT];
CK_ULONG ulObjectCount, i;
CK_RV rv;
rv = C_FindObjectsInit(hSession, NULL_PTR, 0);
assert(rv == CKR_OK);
while (1) {
rv = C_FindObjects(hSession, hObjects, MAX_OBJECT_COUNT, &ulObjectCount);
if (rv != CKR_OK || ulObjectCount == 0) break;
for (i = 0; i < ulObjectCount; i++) {
/* do something with hObjects[i] here */
}
}
rv = C_FindObjectsFinal(hSession);
assert(rv == CKR_OK);
Presumably, the ability to request multiple object handles in a single C_FindObjects()
call is intended as a performance optimization.
FWIW, this is pretty much exactly how many C standard library functions like fread()
work as well. It'd be extremely inefficient to read data from a file one byte at a time with fgetc()
, so the fread()
function lets you allocate an arbitrarily large buffer and read as much data as will fit into it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With