diff --git a/src/crypto.c b/src/crypto.c index 5b1f533a..7e906bcb 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -704,6 +704,17 @@ static CK_RV SetAttributeValue(WP11_Session* session, WP11_Object* obj, if ((getVar == CK_TRUE) && (*(CK_BBOOL*)attr->pValue == CK_FALSE)) return CKR_ATTRIBUTE_READ_ONLY; } + /* Cannot change extractable from false to true */ + if (!newObject && attr->type == CKA_EXTRACTABLE) { + getVarLen = sizeof(getVar); + rv = WP11_Object_GetAttr(obj, CKA_EXTRACTABLE, &getVar, + &getVarLen); + if (rv != CKR_OK) + return rv; + + if ((getVar == CK_FALSE) && (*(CK_BBOOL*)attr->pValue == CK_TRUE)) + return CKR_ATTRIBUTE_READ_ONLY; + } ret = WP11_Object_SetAttr(obj, attr->type, (byte*)attr->pValue, attr->ulValueLen); if (ret == MEMORY_E) @@ -747,15 +758,21 @@ static CK_RV NewObject(WP11_Session* session, CK_KEY_TYPE keyType, return CKR_FUNCTION_FAILED; ret = WP11_Object_SetClass(obj, keyClass); - if (ret != 0) + if (ret != 0) { + WP11_Object_Free(obj); return CKR_FUNCTION_FAILED; + } /* Now that object class is set, allocate type-specific data */ ret = wp11_Object_AllocateTypeData(obj); - if (ret == MEMORY_E) + if (ret == MEMORY_E) { + WP11_Object_Free(obj); return CKR_DEVICE_MEMORY; - if (ret != 0) + } + if (ret != 0) { + WP11_Object_Free(obj); return CKR_FUNCTION_FAILED; + } rv = SetAttributeValue(session, obj, pTemplate, ulCount, CK_TRUE); if (rv != CKR_OK) { @@ -1206,15 +1223,21 @@ CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, /* Set the object class from the original object */ ret = WP11_Object_SetClass(newObj, WP11_Object_GetClass(obj)); - if (ret != 0) + if (ret != 0) { + WP11_Object_Free(newObj); return CKR_FUNCTION_FAILED; + } /* Now that object class is set, allocate type-specific data */ ret = wp11_Object_AllocateTypeData(newObj); - if (ret == MEMORY_E) + if (ret == MEMORY_E) { + WP11_Object_Free(newObj); return CKR_DEVICE_MEMORY; - if (ret != 0) + } + if (ret != 0) { + WP11_Object_Free(newObj); return CKR_FUNCTION_FAILED; + } /* copy all the attributes from the original object to the new object */ rv = WP11_Object_Copy(obj, newObj); @@ -1573,7 +1596,7 @@ CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, WOLFPKCS11_LEAVE("C_FindObjectsInit", rv); return rv; } - if (pTemplate == NULL) { + if (pTemplate == NULL && ulCount != 0) { rv = CKR_ARGUMENTS_BAD; WOLFPKCS11_LEAVE("C_FindObjectsInit", rv); return rv; @@ -7399,15 +7422,22 @@ static int SetKeyExtract(WP11_Session* session, byte* ptr, CK_ULONG length, secretKeyData[1] = ptr + (length - symmKeyLen); secretKeyLen[1] = symmKeyLen; ret = WP11_Object_SetSecretKey(secret, secretKeyData, secretKeyLen); - if (ret != CKR_OK) + if (ret != CKR_OK) { + WP11_Object_Free(secret); return CKR_FUNCTION_FAILED; + } ret = (int)AddObject(session, secret, pTemplate, ulAttributeCount, handle); if (ret != CKR_OK) { + WP11_Object_Free(secret); return ret; } } - if ((ret == 0) && (isMac)) { + else { + WP11_Object_Free(secret); + return ret; + } + if (isMac) { ret = WP11_Object_SetAttr(secret, CKA_KEY_TYPE, (byte*)&keyType, sizeof(keyType)); if (ret != CKR_OK) @@ -7840,8 +7870,10 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, secretKeyLen[1] = symmKeyLen; ret = WP11_Object_SetSecretKey(obj, secretKeyData, secretKeyLen); - if (ret != 0) + if (ret != 0) { + WP11_Object_Free(obj); rv = CKR_FUNCTION_FAILED; + } if (ret == 0) { rv = AddObject(session, obj, pTemplate, ulAttributeCount, phKey); diff --git a/src/internal.c b/src/internal.c index 9a34e53e..ac7ddc0e 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2831,6 +2831,7 @@ static int wp11_EncryptData(byte* out, byte* data, int len, byte* key, ret = wc_AesGcmEncrypt(&aes, out, data, len, iv, ivSz, out + len, AES_BLOCK_SIZE, NULL, 0); } + wc_AesFree(&aes); return ret; } @@ -2865,6 +2866,7 @@ static int wp11_DecryptData(byte* out, byte* data, int len, byte* key, ret = wc_AesGcmDecrypt(&aes, out, data, len, iv, ivSz, data + len, AES_BLOCK_SIZE, NULL, 0); } + wc_AesFree(&aes); return ret; } @@ -7010,6 +7012,17 @@ WP11_Slot* WP11_Session_GetSlot(WP11_Session* session) return session->slot; } +/** + * Get the slot id associated with the session. + * + * @param session [in] Session object. + * @return Slot id. + */ +CK_SLOT_ID WP11_Session_GetSlotId(WP11_Session* session) +{ + return session->slotId; +} + /** * Get the mechanism associated with the session. * @@ -9133,10 +9146,11 @@ static int GetSha1CheckValue(const byte* dataIn, int inLen, byte* dataOut, } ret = wc_Hash(WC_HASH_TYPE_SHA, dataIn, inLen, hash, WC_SHA_DIGEST_SIZE); - if (ret == 0) { - XMEMCPY(dataOut, hash, PKCS11_CHECK_VALUE_SIZE); - *outLen = PKCS11_CHECK_VALUE_SIZE; + if (ret != 0) { + return CKR_FUNCTION_FAILED; } + XMEMCPY(dataOut, hash, PKCS11_CHECK_VALUE_SIZE); + *outLen = PKCS11_CHECK_VALUE_SIZE; return CKR_OK; } diff --git a/src/slot.c b/src/slot.c index e013d6ce..e16bb65f 100644 --- a/src/slot.c +++ b/src/slot.c @@ -571,7 +571,7 @@ static CK_MECHANISM_INFO rsaOaepMechInfo = { #ifdef WC_RSA_PSS /* Info on RSA PKCS#1 PSS mechanism. */ static CK_MECHANISM_INFO rsaPssMechInfo = { - 256, 521, CKF_SIGN | CKF_VERIFY + 1024, 4096, CKF_SIGN | CKF_VERIFY }; #endif #ifndef NO_SHA256 @@ -1639,6 +1639,7 @@ CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, return rv; } + pInfo->slotID = WP11_Session_GetSlotId(session); pInfo->state = WP11_Session_GetState(session); pInfo->flags = CKF_SERIAL_SESSION; if (WP11_Session_IsRW(session)) diff --git a/tests/find_objects_null_template_test.c b/tests/find_objects_null_template_test.c new file mode 100644 index 00000000..84fb1022 --- /dev/null +++ b/tests/find_objects_null_template_test.c @@ -0,0 +1,378 @@ +/* find_objects_null_template_test.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfPKCS11. + * + * wolfPKCS11 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfPKCS11 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + * Test for C_FindObjectsInit with NULL template (issue #816). + * + * Per PKCS#11 v3.0 spec, C_FindObjectsInit(hSession, NULL_PTR, 0) should + * match all objects. The current implementation unconditionally rejects + * pTemplate == NULL with CKR_ARGUMENTS_BAD, even when ulCount == 0. + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef WOLFSSL_USER_SETTINGS + #include +#endif +#include +#include + +#ifndef WOLFPKCS11_USER_SETTINGS + #include +#endif +#include + +#ifndef HAVE_PKCS11_STATIC +#include +#endif + +#include "testdata.h" + +#define FIND_NULL_TEST_DIR "./store/find_null_test" +#define WOLFPKCS11_TOKEN_FILENAME "wp11_token_0000000000000001" + +static int test_passed = 0; +static int test_failed = 0; + +#define CHECK_CKR(rv, op, expected) do { \ + if (rv != expected) { \ + fprintf(stderr, "FAIL: %s: expected %ld, got %ld\n", op, (long)expected, (long)rv); \ + test_failed++; \ + result = -1; \ + goto cleanup; \ + } else { \ + printf("PASS: %s\n", op); \ + test_passed++; \ + } \ +} while(0) + +#ifndef HAVE_PKCS11_STATIC +static void* dlib; +#endif +static CK_FUNCTION_LIST* funcList; +static CK_SLOT_ID slot = 0; +static const char* tokenName = "wolfpkcs11"; +static byte* soPin = (byte*)"password123456"; +static int soPinLen = 14; +static byte* userPin = (byte*)"someUserPin"; +static int userPinLen = 11; + +static CK_OBJECT_CLASS secretKeyClass = CKO_SECRET_KEY; +static CK_OBJECT_CLASS dataClass = CKO_DATA; +static CK_BBOOL ckTrue = CK_TRUE; +static CK_BBOOL ckFalse = CK_FALSE; +static CK_KEY_TYPE genericKeyType = CKK_GENERIC_SECRET; + +/* Test key data */ +static unsigned char testKeyData[32] = { + 0x74, 0x9A, 0xBD, 0xAA, 0x2A, 0x52, 0x07, 0x47, + 0xD6, 0xA6, 0x36, 0xB2, 0x07, 0x32, 0x8E, 0xD0, + 0xBA, 0x69, 0x7B, 0xC6, 0xC3, 0x44, 0x9E, 0xD4, + 0x81, 0x48, 0xFD, 0x2D, 0x68, 0xA2, 0x8B, 0x67, +}; + +static unsigned char keyId[] = {0xDE, 0xAD, 0xBE, 0xEF}; +static char keyLabel[] = "find-null-test-key"; + +/* Test data object content */ +static unsigned char testDataValue[] = "test data object for find-null"; +static char dataLabel[] = "find-null-test-data"; + +static CK_RV pkcs11_init(void) +{ + CK_RV ret; + CK_C_INITIALIZE_ARGS args; + CK_INFO info; + CK_SLOT_ID slotList[16]; + CK_ULONG slotCount = sizeof(slotList) / sizeof(slotList[0]); + +#ifndef HAVE_PKCS11_STATIC + CK_C_GetFunctionList func; + + dlib = dlopen(WOLFPKCS11_DLL_FILENAME, RTLD_NOW | RTLD_LOCAL); + if (dlib == NULL) { + fprintf(stderr, "dlopen error: %s\n", dlerror()); + return -1; + } + + func = (CK_C_GetFunctionList)dlsym(dlib, "C_GetFunctionList"); + if (func == NULL) { + fprintf(stderr, "Failed to get function list function\n"); + dlclose(dlib); + return -1; + } + + ret = func(&funcList); + if (ret != CKR_OK) { + fprintf(stderr, "Failed to get function list: 0x%lx\n", + (unsigned long)ret); + dlclose(dlib); + return ret; + } +#else + ret = C_GetFunctionList(&funcList); + if (ret != CKR_OK) { + fprintf(stderr, "Failed to get function list: 0x%lx\n", + (unsigned long)ret); + return ret; + } +#endif + + XMEMSET(&args, 0, sizeof(args)); + args.flags = CKF_OS_LOCKING_OK; + ret = funcList->C_Initialize(&args); + if (ret != CKR_OK) + return ret; + + ret = funcList->C_GetInfo(&info); + if (ret != CKR_OK) + return ret; + + ret = funcList->C_GetSlotList(CK_TRUE, slotList, &slotCount); + if (ret != CKR_OK) + return ret; + + if (slotCount > 0) { + slot = slotList[0]; + } else { + fprintf(stderr, "No slots available\n"); + return CKR_GENERAL_ERROR; + } + + return ret; +} + +static CK_RV pkcs11_final(void) +{ + if (funcList != NULL) { + funcList->C_Finalize(NULL); + funcList = NULL; + } +#ifndef HAVE_PKCS11_STATIC + if (dlib) { + dlclose(dlib); + dlib = NULL; + } +#endif + return CKR_OK; +} + +static CK_RV pkcs11_init_token(void) +{ + unsigned char label[32]; + + XMEMSET(label, ' ', sizeof(label)); + XMEMCPY(label, tokenName, XSTRLEN(tokenName)); + + return funcList->C_InitToken(slot, soPin, soPinLen, label); +} + +static CK_RV pkcs11_open_session(CK_SESSION_HANDLE* session) +{ + CK_RV ret; + int sessFlags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + + ret = funcList->C_OpenSession(slot, sessFlags, NULL, NULL, session); + if (ret != CKR_OK) + return ret; + + ret = funcList->C_Login(*session, CKU_USER, userPin, userPinLen); + if (ret != CKR_OK) { + funcList->C_CloseSession(*session); + return ret; + } + + return CKR_OK; +} + +static CK_RV pkcs11_close_session(CK_SESSION_HANDLE session) +{ + funcList->C_Logout(session); + return funcList->C_CloseSession(session); +} + +/* Remove token file so C_InitToken sees an uninitialized token. */ +static void cleanup_test_files(const char* dir) +{ + char filepath[512]; + + snprintf(filepath, sizeof(filepath), "%s" PATH_SEP "%s", dir, + WOLFPKCS11_TOKEN_FILENAME); + (void)remove(filepath); +} + +static CK_RV create_secret_key(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE* key) +{ + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, testKeyData, sizeof(testKeyData) }, + { CKA_ID, keyId, sizeof(keyId) }, + { CKA_LABEL, keyLabel, sizeof(keyLabel)-1 } + }; + CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); + + return funcList->C_CreateObject(session, tmpl, tmplCnt, key); +} + +static CK_RV create_data_object(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE* obj) +{ + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &dataClass, sizeof(dataClass) }, + { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_VALUE, testDataValue, sizeof(testDataValue)-1 }, + { CKA_LABEL, dataLabel, sizeof(dataLabel)-1 } + }; + CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); + + return funcList->C_CreateObject(session, tmpl, tmplCnt, obj); +} + +static int find_objects_null_template_test(void) +{ + CK_RV ret; + CK_SESSION_HANDLE session = 0; + CK_OBJECT_HANDLE key, dataObj; + CK_OBJECT_HANDLE found[10]; + CK_ULONG foundCount; + int result = 0; + + printf("\n=== Testing C_FindObjectsInit with NULL template ===\n"); + + cleanup_test_files(FIND_NULL_TEST_DIR); + + ret = pkcs11_init(); + CHECK_CKR(ret, "C_Initialize", CKR_OK); + + ret = pkcs11_init_token(); + CHECK_CKR(ret, "C_InitToken", CKR_OK); + + /* Set user PIN via SO session */ + { + CK_SESSION_HANDLE soSession; + int sessFlags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + + ret = funcList->C_OpenSession(slot, sessFlags, NULL, NULL, &soSession); + CHECK_CKR(ret, "C_OpenSession (SO)", CKR_OK); + + ret = funcList->C_Login(soSession, CKU_SO, soPin, soPinLen); + CHECK_CKR(ret, "C_Login (SO)", CKR_OK); + + ret = funcList->C_InitPIN(soSession, userPin, userPinLen); + CHECK_CKR(ret, "C_InitPIN", CKR_OK); + + funcList->C_Logout(soSession); + funcList->C_CloseSession(soSession); + } + + ret = pkcs11_open_session(&session); + CHECK_CKR(ret, "C_OpenSession (user)", CKR_OK); + + /* Create two different object types */ + ret = create_secret_key(session, &key); + CHECK_CKR(ret, "C_CreateObject (secret key)", CKR_OK); + + ret = create_data_object(session, &dataObj); + CHECK_CKR(ret, "C_CreateObject (data object)", CKR_OK); + + /* + * Test 1: C_FindObjectsInit(session, NULL, 0) should return CKR_OK + * per PKCS#11 spec — NULL template with count 0 means "match all". + * + * BUG: Currently returns CKR_ARGUMENTS_BAD (see src/crypto.c:1598). + */ + ret = funcList->C_FindObjectsInit(session, NULL_PTR, 0); + CHECK_CKR(ret, "C_FindObjectsInit(NULL, 0) [spec: match all]", CKR_OK); + + ret = funcList->C_FindObjects(session, found, 10, &foundCount); + CHECK_CKR(ret, "C_FindObjects [expect >= 2 objects]", CKR_OK); + + if (foundCount < 2) { + fprintf(stderr, "FAIL: C_FindObjects: expected >= 2 objects, " + "found %lu\n", (unsigned long)foundCount); + test_failed++; + result = -1; + } else { + printf("PASS: C_FindObjects found %lu objects (>= 2)\n", + (unsigned long)foundCount); + test_passed++; + } + + ret = funcList->C_FindObjectsFinal(session); + CHECK_CKR(ret, "C_FindObjectsFinal", CKR_OK); + + /* + * Test 2: C_FindObjectsInit(session, NULL, non_zero) should still + * return CKR_ARGUMENTS_BAD — a non-zero count with NULL template + * is a genuine error. + */ + ret = funcList->C_FindObjectsInit(session, NULL_PTR, 5); + CHECK_CKR(ret, "C_FindObjectsInit(NULL, 5) [expect ARGUMENTS_BAD]", + CKR_ARGUMENTS_BAD); + +cleanup: + if (session != 0) + pkcs11_close_session(session); + pkcs11_final(); + return result; +} + +static void print_results(void) +{ + printf("\n=== Test Results ===\n"); + printf("Tests passed: %d\n", test_passed); + printf("Tests failed: %d\n", test_failed); + + if (test_failed == 0) { + printf("ALL TESTS PASSED!\n"); + } else { + printf("SOME TESTS FAILED!\n"); + } +} + +int main(int argc, char* argv[]) +{ +#ifndef WOLFPKCS11_NO_ENV + XSETENV("WOLFPKCS11_TOKEN_PATH", FIND_NULL_TEST_DIR, 1); +#endif + + (void)argc; + (void)argv; + + printf("=== wolfPKCS11 C_FindObjectsInit NULL Template Test ===\n"); + + (void)find_objects_null_template_test(); + + print_results(); + + return (test_failed == 0) ? 0 : 1; +} diff --git a/tests/include.am b/tests/include.am index a0a0904b..857e4e12 100644 --- a/tests/include.am +++ b/tests/include.am @@ -41,6 +41,11 @@ noinst_PROGRAMS += tests/empty_pin_store_test tests_empty_pin_store_test_SOURCES = tests/empty_pin_store_test.c tests_empty_pin_store_test_LDADD = +check_PROGRAMS += tests/find_objects_null_template_test +noinst_PROGRAMS += tests/find_objects_null_template_test +tests_find_objects_null_template_test_SOURCES = tests/find_objects_null_template_test.c +tests_find_objects_null_template_test_LDADD = + check_PROGRAMS += tests/pkcs11v3test noinst_PROGRAMS += tests/pkcs11v3test tests_pkcs11v3test_SOURCES = tests/pkcs11v3test.c @@ -55,10 +60,12 @@ tests_rsa_session_persistence_test_LDADD += src/libwolfpkcs11.la tests_debug_test_LDADD += src/libwolfpkcs11.la tests_object_id_uniqueness_test_LDADD += src/libwolfpkcs11.la tests_empty_pin_store_test_LDADD += src/libwolfpkcs11.la +tests_find_objects_null_template_test_LDADD += src/libwolfpkcs11.la tests_pkcs11v3test_LDADD += src/libwolfpkcs11.la else tests_object_id_uniqueness_test_LDADD += src/libwolfpkcs11.la tests_empty_pin_store_test_LDADD += src/libwolfpkcs11.la +tests_find_objects_null_template_test_LDADD += src/libwolfpkcs11.la endif EXTRA_DIST += tests/unit.h \ diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index 88af986d..17a3e62f 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -1076,6 +1076,9 @@ static CK_RV test_session(void* args) } if (ret == CKR_OK) CHECK_COND((info.ulDeviceError == 0), ret, "Get Session info error"); + if (ret == CKR_OK) + CHECK_COND((info.slotID == (CK_SLOT_ID)slot), ret, + "Get Session info slotID"); /* Get function status and cancel function are not valid anymore. */ if (ret == CKR_OK) { @@ -3716,6 +3719,109 @@ static CK_RV test_attribute_get(void* args) return ret; } +static CK_RV test_extractable_set_false_to_true(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret = CKR_OK; + CK_OBJECT_HANDLE objFalse = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE objTrue = CK_INVALID_HANDLE; + static byte keyData[] = { 0x01 }; + static byte id[] = { 0x04, 0x05, 0x06 }; + CK_BBOOL val; + /* Object created with CKA_EXTRACTABLE = FALSE */ + CK_ATTRIBUTE createTmplFalse[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_ID, id, sizeof(id) }, + }; + CK_ULONG createTmplFalseCnt = + sizeof(createTmplFalse) / sizeof(*createTmplFalse); + /* Object created with CKA_EXTRACTABLE = TRUE */ + CK_ATTRIBUTE createTmplTrue[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_ID, id, sizeof(id) }, + }; + CK_ULONG createTmplTrueCnt = + sizeof(createTmplTrue) / sizeof(*createTmplTrue); + CK_ATTRIBUTE setExtractTrue[] = { + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + }; + CK_ULONG setExtractTrueCnt = + sizeof(setExtractTrue) / sizeof(*setExtractTrue); + CK_ATTRIBUTE setExtractFalse[] = { + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + }; + CK_ULONG setExtractFalseCnt = + sizeof(setExtractFalse) / sizeof(*setExtractFalse); + CK_ATTRIBUTE getExtract[] = { + { CKA_EXTRACTABLE, &val, sizeof(val) }, + }; + CK_ULONG getExtractCnt = sizeof(getExtract) / sizeof(*getExtract); + + /* Create object with CKA_EXTRACTABLE = FALSE */ + ret = funcList->C_CreateObject(session, createTmplFalse, createTmplFalseCnt, + &objFalse); + CHECK_CKR(ret, "Create Object extractable=false"); + + /* Attempt to change CKA_EXTRACTABLE FALSE -> TRUE (must fail) */ + if (ret == CKR_OK) { + ret = funcList->C_SetAttributeValue(session, objFalse, setExtractTrue, + setExtractTrueCnt); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_READ_ONLY, + "Set extractable false->true"); + } + + /* Verify CKA_EXTRACTABLE is still FALSE */ + if (ret == CKR_OK) { + val = CK_TRUE; + ret = funcList->C_GetAttributeValue(session, objFalse, getExtract, + getExtractCnt); + CHECK_CKR(ret, "Get extractable after failed set"); + } + if (ret == CKR_OK) { + CHECK_COND(val == CK_FALSE, ret, + "Extractable still false after failed set"); + } + + /* Create object with CKA_EXTRACTABLE = TRUE */ + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, createTmplTrue, + createTmplTrueCnt, &objTrue); + CHECK_CKR(ret, "Create Object extractable=true"); + } + + /* Change CKA_EXTRACTABLE TRUE -> FALSE (must succeed) */ + if (ret == CKR_OK) { + ret = funcList->C_SetAttributeValue(session, objTrue, setExtractFalse, + setExtractFalseCnt); + CHECK_CKR(ret, "Set extractable true->false"); + } + + /* Verify CKA_EXTRACTABLE is now FALSE */ + if (ret == CKR_OK) { + val = CK_TRUE; + ret = funcList->C_GetAttributeValue(session, objTrue, getExtract, + getExtractCnt); + CHECK_CKR(ret, "Get extractable after set false"); + } + if (ret == CKR_OK) { + CHECK_COND(val == CK_FALSE, ret, + "Extractable now false after set"); + } + + if (objFalse != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, objFalse); + if (objTrue != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, objTrue); + + return ret; +} + static CK_RV test_data_object(void* args) { CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; @@ -16090,6 +16196,7 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_attribute), PKCS11TEST_FUNC_SESS_DECL(test_attribute_types), PKCS11TEST_FUNC_SESS_DECL(test_attribute_get), + PKCS11TEST_FUNC_SESS_DECL(test_extractable_set_false_to_true), PKCS11TEST_FUNC_SESS_DECL(test_data_object), PKCS11TEST_FUNC_SESS_DECL(test_data_object_null_value), PKCS11TEST_FUNC_SESS_DECL(test_attributes_secret), diff --git a/wolfpkcs11/internal.h b/wolfpkcs11/internal.h index 06b01cc4..443851a0 100644 --- a/wolfpkcs11/internal.h +++ b/wolfpkcs11/internal.h @@ -356,6 +356,7 @@ WP11_LOCAL int WP11_Session_IsHashOpInitialized(WP11_Session* session, int mecha WP11_LOCAL enum wc_HashType WP11_Session_ToHashType(WP11_Session* session); WP11_LOCAL void WP11_Session_SetOpInitialized(WP11_Session* session, int init); WP11_LOCAL WP11_Slot* WP11_Session_GetSlot(WP11_Session* session); +WP11_LOCAL CK_SLOT_ID WP11_Session_GetSlotId(WP11_Session* session); WP11_LOCAL CK_MECHANISM_TYPE WP11_Session_GetMechanism(WP11_Session* session); WP11_LOCAL void WP11_Session_SetMechanism(WP11_Session* session, CK_MECHANISM_TYPE mechanism);