Skip to content

Commit 7e4946e

Browse files
committed
Fix C_FindObjectsInit to allow NULL template with zero count
Per PKCS#11 spec, C_FindObjectsInit(hSession, NULL_PTR, 0) should match all objects. The implementation unconditionally rejected pTemplate == NULL with CKR_ARGUMENTS_BAD, even when ulCount == 0. Change the check to only reject NULL when ulCount != 0 (a genuine error). Add test that verifies both the match-all case and the NULL-with-nonzero-count error case. F-816
1 parent 550a034 commit 7e4946e

3 files changed

Lines changed: 384 additions & 1 deletion

File tree

src/crypto.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1595,7 +1595,7 @@ CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession,
15951595
WOLFPKCS11_LEAVE("C_FindObjectsInit", rv);
15961596
return rv;
15971597
}
1598-
if (pTemplate == NULL) {
1598+
if (pTemplate == NULL && ulCount != 0) {
15991599
rv = CKR_ARGUMENTS_BAD;
16001600
WOLFPKCS11_LEAVE("C_FindObjectsInit", rv);
16011601
return rv;
Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,376 @@
1+
/* find_objects_null_template_test.c
2+
*
3+
* Copyright (C) 2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfPKCS11.
6+
*
7+
* wolfPKCS11 is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfPKCS11 is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*
21+
* Test for C_FindObjectsInit with NULL template (issue #816).
22+
*
23+
* Per PKCS#11 v3.0 spec, C_FindObjectsInit(hSession, NULL_PTR, 0) should
24+
* match all objects. The current implementation unconditionally rejects
25+
* pTemplate == NULL with CKR_ARGUMENTS_BAD, even when ulCount == 0.
26+
*/
27+
28+
#ifdef HAVE_CONFIG_H
29+
#include <wolfpkcs11/config.h>
30+
#endif
31+
32+
#include <stdio.h>
33+
34+
#ifndef WOLFSSL_USER_SETTINGS
35+
#include <wolfssl/options.h>
36+
#endif
37+
#include <wolfssl/wolfcrypt/settings.h>
38+
#include <wolfssl/wolfcrypt/misc.h>
39+
40+
#ifndef WOLFPKCS11_USER_SETTINGS
41+
#include <wolfpkcs11/options.h>
42+
#endif
43+
#include <wolfpkcs11/pkcs11.h>
44+
45+
#ifndef HAVE_PKCS11_STATIC
46+
#include <dlfcn.h>
47+
#endif
48+
49+
#include "testdata.h"
50+
51+
#define FIND_NULL_TEST_DIR "./store/find_null_test"
52+
#define WOLFPKCS11_TOKEN_FILENAME "wp11_token_0000000000000001"
53+
54+
static int test_passed = 0;
55+
static int test_failed = 0;
56+
57+
#define CHECK_CKR(rv, op, expected) do { \
58+
if (rv != expected) { \
59+
fprintf(stderr, "FAIL: %s: expected %ld, got %ld\n", op, (long)expected, (long)rv); \
60+
test_failed++; \
61+
result = -1; \
62+
goto cleanup; \
63+
} else { \
64+
printf("PASS: %s\n", op); \
65+
test_passed++; \
66+
} \
67+
} while(0)
68+
69+
#ifndef HAVE_PKCS11_STATIC
70+
static void* dlib;
71+
#endif
72+
static CK_FUNCTION_LIST* funcList;
73+
static CK_SLOT_ID slot = 0;
74+
static const char* tokenName = "wolfpkcs11";
75+
static byte* soPin = (byte*)"password123456";
76+
static int soPinLen = 14;
77+
static byte* userPin = (byte*)"someUserPin";
78+
static int userPinLen = 11;
79+
80+
static CK_OBJECT_CLASS secretKeyClass = CKO_SECRET_KEY;
81+
static CK_OBJECT_CLASS dataClass = CKO_DATA;
82+
static CK_BBOOL ckTrue = CK_TRUE;
83+
static CK_BBOOL ckFalse = CK_FALSE;
84+
static CK_KEY_TYPE genericKeyType = CKK_GENERIC_SECRET;
85+
86+
/* Test key data */
87+
static unsigned char testKeyData[32] = {
88+
0x74, 0x9A, 0xBD, 0xAA, 0x2A, 0x52, 0x07, 0x47,
89+
0xD6, 0xA6, 0x36, 0xB2, 0x07, 0x32, 0x8E, 0xD0,
90+
0xBA, 0x69, 0x7B, 0xC6, 0xC3, 0x44, 0x9E, 0xD4,
91+
0x81, 0x48, 0xFD, 0x2D, 0x68, 0xA2, 0x8B, 0x67,
92+
};
93+
94+
static unsigned char keyId[] = {0xDE, 0xAD, 0xBE, 0xEF};
95+
static char keyLabel[] = "find-null-test-key";
96+
97+
/* Test data object content */
98+
static unsigned char testDataValue[] = "test data object for find-null";
99+
static char dataLabel[] = "find-null-test-data";
100+
101+
static CK_RV pkcs11_init(void)
102+
{
103+
CK_RV ret;
104+
CK_C_INITIALIZE_ARGS args;
105+
CK_INFO info;
106+
CK_SLOT_ID slotList[16];
107+
CK_ULONG slotCount = sizeof(slotList) / sizeof(slotList[0]);
108+
109+
#ifndef HAVE_PKCS11_STATIC
110+
CK_C_GetFunctionList func;
111+
112+
dlib = dlopen(WOLFPKCS11_DLL_FILENAME, RTLD_NOW | RTLD_LOCAL);
113+
if (dlib == NULL) {
114+
fprintf(stderr, "dlopen error: %s\n", dlerror());
115+
return -1;
116+
}
117+
118+
func = (CK_C_GetFunctionList)dlsym(dlib, "C_GetFunctionList");
119+
if (func == NULL) {
120+
fprintf(stderr, "Failed to get function list function\n");
121+
dlclose(dlib);
122+
return -1;
123+
}
124+
125+
ret = func(&funcList);
126+
if (ret != CKR_OK) {
127+
fprintf(stderr, "Failed to get function list: 0x%lx\n",
128+
(unsigned long)ret);
129+
dlclose(dlib);
130+
return ret;
131+
}
132+
#else
133+
ret = C_GetFunctionList(&funcList);
134+
if (ret != CKR_OK) {
135+
fprintf(stderr, "Failed to get function list: 0x%lx\n",
136+
(unsigned long)ret);
137+
return ret;
138+
}
139+
#endif
140+
141+
XMEMSET(&args, 0, sizeof(args));
142+
args.flags = CKF_OS_LOCKING_OK;
143+
ret = funcList->C_Initialize(&args);
144+
if (ret != CKR_OK)
145+
return ret;
146+
147+
ret = funcList->C_GetInfo(&info);
148+
if (ret != CKR_OK)
149+
return ret;
150+
151+
ret = funcList->C_GetSlotList(CK_TRUE, slotList, &slotCount);
152+
if (ret != CKR_OK)
153+
return ret;
154+
155+
if (slotCount > 0) {
156+
slot = slotList[0];
157+
} else {
158+
fprintf(stderr, "No slots available\n");
159+
return CKR_GENERAL_ERROR;
160+
}
161+
162+
return ret;
163+
}
164+
165+
static CK_RV pkcs11_final(void)
166+
{
167+
if (funcList != NULL) {
168+
funcList->C_Finalize(NULL);
169+
funcList = NULL;
170+
}
171+
#ifndef HAVE_PKCS11_STATIC
172+
if (dlib) {
173+
dlclose(dlib);
174+
dlib = NULL;
175+
}
176+
#endif
177+
return CKR_OK;
178+
}
179+
180+
static CK_RV pkcs11_init_token(void)
181+
{
182+
unsigned char label[32];
183+
184+
XMEMSET(label, ' ', sizeof(label));
185+
XMEMCPY(label, tokenName, XSTRLEN(tokenName));
186+
187+
return funcList->C_InitToken(slot, soPin, soPinLen, label);
188+
}
189+
190+
static CK_RV pkcs11_open_session(CK_SESSION_HANDLE* session)
191+
{
192+
CK_RV ret;
193+
int sessFlags = CKF_SERIAL_SESSION | CKF_RW_SESSION;
194+
195+
ret = funcList->C_OpenSession(slot, sessFlags, NULL, NULL, session);
196+
if (ret != CKR_OK)
197+
return ret;
198+
199+
ret = funcList->C_Login(*session, CKU_USER, userPin, userPinLen);
200+
if (ret != CKR_OK)
201+
return ret;
202+
203+
return CKR_OK;
204+
}
205+
206+
static CK_RV pkcs11_close_session(CK_SESSION_HANDLE session)
207+
{
208+
funcList->C_Logout(session);
209+
return funcList->C_CloseSession(session);
210+
}
211+
212+
/* Remove token file so C_InitToken sees an uninitialized token. */
213+
static void cleanup_test_files(const char* dir)
214+
{
215+
char filepath[512];
216+
217+
snprintf(filepath, sizeof(filepath), "%s" PATH_SEP "%s", dir,
218+
WOLFPKCS11_TOKEN_FILENAME);
219+
(void)remove(filepath);
220+
}
221+
222+
static CK_RV create_secret_key(CK_SESSION_HANDLE session,
223+
CK_OBJECT_HANDLE* key)
224+
{
225+
CK_ATTRIBUTE tmpl[] = {
226+
{ CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) },
227+
{ CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) },
228+
{ CKA_TOKEN, &ckFalse, sizeof(ckFalse) },
229+
{ CKA_PRIVATE, &ckFalse, sizeof(ckFalse) },
230+
{ CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) },
231+
{ CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) },
232+
{ CKA_SIGN, &ckTrue, sizeof(ckTrue) },
233+
{ CKA_VERIFY, &ckTrue, sizeof(ckTrue) },
234+
{ CKA_VALUE, testKeyData, sizeof(testKeyData) },
235+
{ CKA_ID, keyId, sizeof(keyId) },
236+
{ CKA_LABEL, keyLabel, sizeof(keyLabel)-1 }
237+
};
238+
CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl);
239+
240+
return funcList->C_CreateObject(session, tmpl, tmplCnt, key);
241+
}
242+
243+
static CK_RV create_data_object(CK_SESSION_HANDLE session,
244+
CK_OBJECT_HANDLE* obj)
245+
{
246+
CK_ATTRIBUTE tmpl[] = {
247+
{ CKA_CLASS, &dataClass, sizeof(dataClass) },
248+
{ CKA_TOKEN, &ckFalse, sizeof(ckFalse) },
249+
{ CKA_PRIVATE, &ckFalse, sizeof(ckFalse) },
250+
{ CKA_VALUE, testDataValue, sizeof(testDataValue)-1 },
251+
{ CKA_LABEL, dataLabel, sizeof(dataLabel)-1 }
252+
};
253+
CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl);
254+
255+
return funcList->C_CreateObject(session, tmpl, tmplCnt, obj);
256+
}
257+
258+
static int find_objects_null_template_test(void)
259+
{
260+
CK_RV ret;
261+
CK_SESSION_HANDLE session = 0;
262+
CK_OBJECT_HANDLE key, dataObj;
263+
CK_OBJECT_HANDLE found[10];
264+
CK_ULONG foundCount;
265+
int result = 0;
266+
267+
printf("\n=== Testing C_FindObjectsInit with NULL template ===\n");
268+
269+
cleanup_test_files(FIND_NULL_TEST_DIR);
270+
271+
ret = pkcs11_init();
272+
CHECK_CKR(ret, "C_Initialize", CKR_OK);
273+
274+
ret = pkcs11_init_token();
275+
CHECK_CKR(ret, "C_InitToken", CKR_OK);
276+
277+
/* Set user PIN via SO session */
278+
{
279+
CK_SESSION_HANDLE soSession;
280+
int sessFlags = CKF_SERIAL_SESSION | CKF_RW_SESSION;
281+
282+
ret = funcList->C_OpenSession(slot, sessFlags, NULL, NULL, &soSession);
283+
CHECK_CKR(ret, "C_OpenSession (SO)", CKR_OK);
284+
285+
ret = funcList->C_Login(soSession, CKU_SO, soPin, soPinLen);
286+
CHECK_CKR(ret, "C_Login (SO)", CKR_OK);
287+
288+
ret = funcList->C_InitPIN(soSession, userPin, userPinLen);
289+
CHECK_CKR(ret, "C_InitPIN", CKR_OK);
290+
291+
funcList->C_Logout(soSession);
292+
funcList->C_CloseSession(soSession);
293+
}
294+
295+
ret = pkcs11_open_session(&session);
296+
CHECK_CKR(ret, "C_OpenSession (user)", CKR_OK);
297+
298+
/* Create two different object types */
299+
ret = create_secret_key(session, &key);
300+
CHECK_CKR(ret, "C_CreateObject (secret key)", CKR_OK);
301+
302+
ret = create_data_object(session, &dataObj);
303+
CHECK_CKR(ret, "C_CreateObject (data object)", CKR_OK);
304+
305+
/*
306+
* Test 1: C_FindObjectsInit(session, NULL, 0) should return CKR_OK
307+
* per PKCS#11 spec — NULL template with count 0 means "match all".
308+
*
309+
* BUG: Currently returns CKR_ARGUMENTS_BAD (see src/crypto.c:1598).
310+
*/
311+
ret = funcList->C_FindObjectsInit(session, NULL_PTR, 0);
312+
CHECK_CKR(ret, "C_FindObjectsInit(NULL, 0) [spec: match all]", CKR_OK);
313+
314+
ret = funcList->C_FindObjects(session, found, 10, &foundCount);
315+
CHECK_CKR(ret, "C_FindObjects [expect >= 2 objects]", CKR_OK);
316+
317+
if (foundCount < 2) {
318+
fprintf(stderr, "FAIL: C_FindObjects: expected >= 2 objects, "
319+
"found %lu\n", (unsigned long)foundCount);
320+
test_failed++;
321+
result = -1;
322+
} else {
323+
printf("PASS: C_FindObjects found %lu objects (>= 2)\n",
324+
(unsigned long)foundCount);
325+
test_passed++;
326+
}
327+
328+
ret = funcList->C_FindObjectsFinal(session);
329+
CHECK_CKR(ret, "C_FindObjectsFinal", CKR_OK);
330+
331+
/*
332+
* Test 2: C_FindObjectsInit(session, NULL, non_zero) should still
333+
* return CKR_ARGUMENTS_BAD — a non-zero count with NULL template
334+
* is a genuine error.
335+
*/
336+
ret = funcList->C_FindObjectsInit(session, NULL_PTR, 5);
337+
CHECK_CKR(ret, "C_FindObjectsInit(NULL, 5) [expect ARGUMENTS_BAD]",
338+
CKR_ARGUMENTS_BAD);
339+
340+
cleanup:
341+
if (session != 0)
342+
pkcs11_close_session(session);
343+
pkcs11_final();
344+
return result;
345+
}
346+
347+
static void print_results(void)
348+
{
349+
printf("\n=== Test Results ===\n");
350+
printf("Tests passed: %d\n", test_passed);
351+
printf("Tests failed: %d\n", test_failed);
352+
353+
if (test_failed == 0) {
354+
printf("ALL TESTS PASSED!\n");
355+
} else {
356+
printf("SOME TESTS FAILED!\n");
357+
}
358+
}
359+
360+
int main(int argc, char* argv[])
361+
{
362+
#ifndef WOLFPKCS11_NO_ENV
363+
XSETENV("WOLFPKCS11_TOKEN_PATH", FIND_NULL_TEST_DIR, 1);
364+
#endif
365+
366+
(void)argc;
367+
(void)argv;
368+
369+
printf("=== wolfPKCS11 C_FindObjectsInit NULL Template Test ===\n");
370+
371+
(void)find_objects_null_template_test();
372+
373+
print_results();
374+
375+
return (test_failed == 0) ? 0 : 1;
376+
}

0 commit comments

Comments
 (0)