PKCS #11 C_FindObjects 中的内存所有权,其中 ulMaxObjectCount != 1

Memory ownership in PKCS #11 C_FindObjects where ulMaxObjectCount != 1

PKCS #11 v2.40 的作者在 API returns 可变长度项目列表时使用了一种通用模式。在 C_GetSlotListC_GetMechanismList 等 API 中,应用程序应调用 API 两次。在第一次调用中,指向 CK_ULONG 的指针被设置为将在下一次调用时返回的项目数。这允许应用程序分配足够的内存并再次调用 API 以检索结果。

C_FindObjects 也调用 returns 可变数量的项目,但它使用不同的范例。参数 CK_OBJECT_HANDLE_PTR phObject 设置为结果列表的头部。参数CK_ULONG_PTR pulObjectCount设置为返回的item个数,保证小于CK_ULONG ulMaxObjectCount.

该标准没有明确指出 phObject 必须是一个有效的指针,指向一个足以容纳 ulMaxObjectCount CK_OBJECT_HANDLEs 的内存块。

可以将标准解释为应用程序必须悲观地为 ulMaxObjectCount 对象分配足够的内存。或者,可以将标准解释为 PKCS #11 实现将分配 pulObjectCount CK_OBJECT_HANDLEs,然后由应用程序负责释放该内存。然而,后来的解释似乎令人怀疑,因为标准中没有其他地方执行 PKCS #11 分配内存。

这段话是:

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.

非规范示例不是很有帮助,因为它将 ulMaxObjectCount 设置为 1。但是,它确实为该条目分配了内存。这似乎表明应用程序必须悲观地预分配内存。

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);

规格Link:http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.pdf

是的,应用程序似乎负责为 C_FindObjects() 返回的对象句柄分配 space。示例代码执行此操作,即使它一次只请求一个对象句柄,您也应该这样做。

您也可以重写示例代码以请求多个对象句柄,例如像这样:

#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);

据推测,在单个 C_FindObjects() 调用中请求多个对象句柄的能力旨在优化性能。

FWIW,这几乎就是像 fread() 这样的许多 C 标准库函数的工作原理。使用 fgetc() 从文件中一次读取一个字节的数据效率极低,因此 fread() 函数允许您分配一个任意大的缓冲区并读取尽可能多的数据。