diff --git a/src/crypto.c b/src/crypto.c index 99e7492c..b4a14f64 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -3839,7 +3839,10 @@ CK_RV C_DigestInit(CK_SESSION_HANDLE hSession, WP11_Session_SetOpInitialized(session, init); } - rv = ret; + if (ret != 0 && ret != (int)CKR_MECHANISM_INVALID) + rv = CKR_FUNCTION_FAILED; + else + rv = ret; WOLFPKCS11_LEAVE("C_DigestInit", rv); return rv; } @@ -3892,7 +3895,9 @@ CK_RV C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, session); *pulDigestLen = hashLen; - return ret; + if (ret < 0) + return CKR_FUNCTION_FAILED; + return CKR_OK; } /** @@ -3936,7 +3941,9 @@ CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, ret = WP11_Digest_Update(pPart, (word32)ulPartLen, session); - return ret; + if (ret < 0) + return CKR_FUNCTION_FAILED; + return CKR_OK; } /** @@ -3979,7 +3986,9 @@ CK_RV C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) ret = WP11_Digest_Key(obj, session); - return ret; + if (ret < 0) + return CKR_FUNCTION_FAILED; + return CKR_OK; } /** @@ -4027,7 +4036,9 @@ CK_RV C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, ret = WP11_Digest_Final(pDigest, &hashLen, session); *pulDigestLen = hashLen; - return ret; + if (ret < 0) + return CKR_FUNCTION_FAILED; + return CKR_OK; } #ifdef WOLFSSL_HAVE_PRF @@ -6170,7 +6181,7 @@ CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, return CKR_KEY_TYPE_INCONSISTENT; } - ret = CheckOpSupported(obj, CKA_VERIFY); + ret = CheckOpSupported(obj, CKA_VERIFY_RECOVER); if (ret != CKR_OK) return ret; @@ -6748,18 +6759,22 @@ CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, ret = WP11_Object_SetSecretKey(pbkdf2Key, secretKeyData, secretKeyLen); if (ret == 0) { - rv = AddObject(session, pbkdf2Key, pTemplate, ulCount, phKey); - if (rv != CKR_OK) { - WP11_Object_Free(pbkdf2Key); - } + WP11_Object_SetKeyGeneration(pbkdf2Key, pMechanism->mechanism); + rv = SetInitialStates(pbkdf2Key); } else { - WP11_Object_Free(pbkdf2Key); rv = CKR_FUNCTION_FAILED; } + if (rv == CKR_OK) { + rv = AddObject(session, pbkdf2Key, pTemplate, ulCount, phKey); + } + if (rv != CKR_OK) { + WP11_Object_Free(pbkdf2Key); + } } wc_ForceZero(derivedKey, derivedKeyLen); XFREE(derivedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return rv; } #ifdef WOLFPKCS11_NSS @@ -6845,18 +6860,22 @@ CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, ret = WP11_Object_SetSecretKey(pbeKey, secretKeyData, secretKeyLen); if (ret == 0) { - rv = AddObject(session, pbeKey, pTemplate, ulCount, phKey); - if (rv != CKR_OK) { - WP11_Object_Free(pbeKey); - } + WP11_Object_SetKeyGeneration(pbeKey, pMechanism->mechanism); + rv = SetInitialStates(pbeKey); } else { - WP11_Object_Free(pbeKey); rv = CKR_FUNCTION_FAILED; } + if (rv == CKR_OK) { + rv = AddObject(session, pbeKey, pTemplate, ulCount, phKey); + } + if (rv != CKR_OK) { + WP11_Object_Free(pbeKey); + } } wc_ForceZero(derivedKey, derivedKeyLen); XFREE(derivedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return rv; } #endif @@ -6884,7 +6903,8 @@ CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, &key); if (rv == CKR_OK) { int ret = WP11_GenerateRandomKey(key, - WP11_Session_GetSlot(session)); + WP11_Session_GetSlot(session), + pMechanism->mechanism); if (ret != 0) { WP11_Object_Free(key); rv = CKR_FUNCTION_FAILED; @@ -7972,7 +7992,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, if (!lenAttr) { return CKR_MECHANISM_PARAM_INVALID; } - keyLen = *(word32*)lenAttr->pValue; + keyLen = (word32)*(CK_ULONG*)lenAttr->pValue; } else { keyLen = WC_MAX_DIGEST_SIZE; diff --git a/src/internal.c b/src/internal.c index 97b17eb9..1cf1c626 100644 --- a/src/internal.c +++ b/src/internal.c @@ -10627,6 +10627,19 @@ int WP11_Object_SetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, return ret; } +/** + * Mark an object as locally generated and record the mechanism used. + * + * @param object [in] Object to update. + * @param mechanism [in] Generation mechanism. + */ +void WP11_Object_SetKeyGeneration(WP11_Object* object, + CK_MECHANISM_TYPE mechanism) +{ + object->local = 1; + object->keyGenMech = mechanism; +} + /** * Check whether the attribute matches in the object. * @@ -12340,12 +12353,14 @@ int WP11_Mldsa_Verify(unsigned char* sig, word32 sigLen, unsigned char* data, /** * Generate a secret key. * - * @param secret [in] Secret object. - * @param slot [in] Slot operation is performed on. + * @param secret [in] Secret object. + * @param slot [in] Slot operation is performed on. + * @param mechanism [in] Key generation mechanism. * @return -ve on random number generation failure. * 0 on success. */ -int WP11_GenerateRandomKey(WP11_Object* secret, WP11_Slot* slot) +int WP11_GenerateRandomKey(WP11_Object* secret, WP11_Slot* slot, + CK_MECHANISM_TYPE mechanism) { int ret; WP11_Data* key = secret->data.symmKey; @@ -12354,6 +12369,11 @@ int WP11_GenerateRandomKey(WP11_Object* secret, WP11_Slot* slot) ret = wc_RNG_GenerateBlock(&slot->token.rng, key->data, key->len); WP11_Lock_UnlockRW(&slot->token.rngLock); + if (ret == 0) { + secret->local = 1; + secret->keyGenMech = mechanism; + } + return ret; } #endif /* WOLFPKCS11_HKDF || !NO_AES */ diff --git a/src/slot.c b/src/slot.c index 25ea05f5..3bc7c18d 100644 --- a/src/slot.c +++ b/src/slot.c @@ -154,7 +154,7 @@ static CK_RV checkPinLen(CK_ULONG pinLen) #else if (pinLen > WP11_MAX_PIN_LEN) #endif - return CKR_PIN_INCORRECT; + return CKR_PIN_LEN_RANGE; return CKR_OK; } @@ -1255,8 +1255,8 @@ CK_RV C_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, return rv; } - if (checkPinLen(ulPinLen) != CKR_OK) { - rv = CKR_PIN_INCORRECT; + rv = checkPinLen(ulPinLen); + if (rv != CKR_OK) { WOLFPKCS11_LEAVE("C_InitToken", rv); return rv; } @@ -1339,8 +1339,8 @@ CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, return rv; } - if (checkPinLen(ulPinLen) != CKR_OK) { - rv = CKR_PIN_INCORRECT; + rv = checkPinLen(ulPinLen); + if (rv != CKR_OK) { WOLFPKCS11_LEAVE("C_InitPIN", rv); return rv; } @@ -1414,8 +1414,8 @@ CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, WOLFPKCS11_LEAVE("C_SetPIN", rv); return rv; } - if (checkPinLen(ulNewLen) != CKR_OK) { - rv = CKR_PIN_INCORRECT; + rv = checkPinLen(ulNewLen); + if (rv != CKR_OK) { WOLFPKCS11_LEAVE("C_SetPIN", rv); return rv; } diff --git a/tests/aes_keygen_attrs_test.c b/tests/aes_keygen_attrs_test.c new file mode 100644 index 00000000..2e203955 --- /dev/null +++ b/tests/aes_keygen_attrs_test.c @@ -0,0 +1,387 @@ +/* aes_keygen_attrs_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 that C_GenerateKey sets CKA_LOCAL and CKA_KEY_GEN_MECHANISM + * correctly on generated symmetric keys (bugs #2033, #2034). + */ + +#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" + +#ifndef NO_AES + +#define TEST_DIR "./store/aes_keygen_attrs_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_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); +} + +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); +} + +/* + * Test: Generate an AES-256 key via C_GenerateKey and verify that + * CKA_LOCAL is CK_TRUE and CKA_KEY_GEN_MECHANISM is CKM_AES_KEY_GEN. + */ +static int test_aes_keygen_attrs(CK_SESSION_HANDLE session) +{ + CK_RV ret; + CK_OBJECT_HANDLE key; + CK_MECHANISM mech; + CK_KEY_TYPE keyType = CKK_AES; + CK_ULONG keyLen = 32; + CK_BBOOL local = CK_FALSE; + CK_MECHANISM_TYPE genMech = CK_UNAVAILABLE_INFORMATION; + int result = 0; + + CK_ATTRIBUTE genTmpl[] = { + { CKA_VALUE_LEN, &keyLen, sizeof(keyLen) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + }; + CK_ULONG genTmplCnt = sizeof(genTmpl) / sizeof(*genTmpl); + + CK_ATTRIBUTE getTmpl[] = { + { CKA_LOCAL, &local, sizeof(local) }, + { CKA_KEY_GEN_MECHANISM, &genMech, sizeof(genMech) }, + }; + CK_ULONG getTmplCnt = sizeof(getTmpl) / sizeof(*getTmpl); + + mech.mechanism = CKM_AES_KEY_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + ret = funcList->C_GenerateKey(session, &mech, genTmpl, genTmplCnt, &key); + CHECK_CKR(ret, "C_GenerateKey (AES-256)", CKR_OK); + + ret = funcList->C_GetAttributeValue(session, key, getTmpl, getTmplCnt); + CHECK_CKR(ret, "C_GetAttributeValue (CKA_LOCAL, CKA_KEY_GEN_MECHANISM)", + CKR_OK); + + if (local != CK_TRUE) { + fprintf(stderr, + "FAIL: CKA_LOCAL: expected CK_TRUE, got %d\n", (int)local); + test_failed++; + result = -1; + goto cleanup; + } + printf("PASS: CKA_LOCAL is CK_TRUE\n"); + test_passed++; + + if (genMech != CKM_AES_KEY_GEN) { + fprintf(stderr, + "FAIL: CKA_KEY_GEN_MECHANISM: expected 0x%lx (CKM_AES_KEY_GEN)," + " got 0x%lx\n", + (unsigned long)CKM_AES_KEY_GEN, (unsigned long)genMech); + test_failed++; + result = -1; + goto cleanup; + } + printf("PASS: CKA_KEY_GEN_MECHANISM is CKM_AES_KEY_GEN\n"); + test_passed++; + +cleanup: + return result; +} + +static int aes_keygen_attrs_test(void) +{ + CK_RV ret; + CK_SESSION_HANDLE session = 0; + int result = 0; + + printf("\n=== Testing C_GenerateKey CKA_LOCAL and CKA_KEY_GEN_MECHANISM ===\n"); + + cleanup_test_files(TEST_DIR); + + ret = pkcs11_init(); + if (ret != CKR_OK) { + fprintf(stderr, "FAIL: pkcs11_init: 0x%lx\n", (unsigned long)ret); + test_failed++; + return -1; + } + + ret = pkcs11_init_token(); + if (ret != CKR_OK) { + fprintf(stderr, "FAIL: C_InitToken: 0x%lx\n", (unsigned long)ret); + test_failed++; + pkcs11_final(); + return -1; + } + + /* 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); + if (ret != CKR_OK) { + fprintf(stderr, "FAIL: C_OpenSession (SO): 0x%lx\n", + (unsigned long)ret); + test_failed++; + pkcs11_final(); + return -1; + } + + ret = funcList->C_Login(soSession, CKU_SO, soPin, soPinLen); + if (ret != CKR_OK) { + fprintf(stderr, "FAIL: C_Login (SO): 0x%lx\n", + (unsigned long)ret); + test_failed++; + funcList->C_CloseSession(soSession); + pkcs11_final(); + return -1; + } + + ret = funcList->C_InitPIN(soSession, userPin, userPinLen); + if (ret != CKR_OK) { + fprintf(stderr, "FAIL: C_InitPIN: 0x%lx\n", (unsigned long)ret); + test_failed++; + funcList->C_Logout(soSession); + funcList->C_CloseSession(soSession); + pkcs11_final(); + return -1; + } + + funcList->C_Logout(soSession); + funcList->C_CloseSession(soSession); + } + + ret = pkcs11_open_session(&session); + if (ret != CKR_OK) { + fprintf(stderr, "FAIL: pkcs11_open_session: 0x%lx\n", + (unsigned long)ret); + test_failed++; + pkcs11_final(); + return -1; + } + + if (test_aes_keygen_attrs(session) != 0) + result = -1; + + 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", TEST_DIR, 1); +#endif + + (void)argc; + (void)argv; + + printf("=== wolfPKCS11 AES KeyGen Attributes Test ===\n"); + + (void)aes_keygen_attrs_test(); + + print_results(); + + return (test_failed == 0) ? 0 : 1; +} + +#else /* NO_AES */ + +int main(int argc, char* argv[]) +{ + (void)argc; + (void)argv; + + printf("AES not available, skipping keygen attributes test\n"); + return 0; +} + +#endif /* !NO_AES */ diff --git a/tests/include.am b/tests/include.am index 725c474c..87485fc6 100644 --- a/tests/include.am +++ b/tests/include.am @@ -56,6 +56,16 @@ noinst_PROGRAMS += tests/ecb_check_value_error_test tests_ecb_check_value_error_test_SOURCES = tests/ecb_check_value_error_test.c tests_ecb_check_value_error_test_LDADD = +check_PROGRAMS += tests/aes_keygen_attrs_test +noinst_PROGRAMS += tests/aes_keygen_attrs_test +tests_aes_keygen_attrs_test_SOURCES = tests/aes_keygen_attrs_test.c +tests_aes_keygen_attrs_test_LDADD = + +check_PROGRAMS += tests/pbkdf2_keygen_attrs_test +noinst_PROGRAMS += tests/pbkdf2_keygen_attrs_test +tests_pbkdf2_keygen_attrs_test_SOURCES = tests/pbkdf2_keygen_attrs_test.c +tests_pbkdf2_keygen_attrs_test_LDADD = + check_PROGRAMS += tests/pkcs11v3test noinst_PROGRAMS += tests/pkcs11v3test tests_pkcs11v3test_SOURCES = tests/pkcs11v3test.c @@ -73,6 +83,8 @@ tests_empty_pin_store_test_LDADD += src/libwolfpkcs11.la tests_find_objects_null_template_test_LDADD += src/libwolfpkcs11.la tests_aes_cbc_pad_padding_test_LDADD += src/libwolfpkcs11.la tests_ecb_check_value_error_test_LDADD += src/libwolfpkcs11.la +tests_aes_keygen_attrs_test_LDADD += src/libwolfpkcs11.la +tests_pbkdf2_keygen_attrs_test_LDADD += src/libwolfpkcs11.la tests_pkcs11v3test_LDADD += src/libwolfpkcs11.la else tests_object_id_uniqueness_test_LDADD += src/libwolfpkcs11.la @@ -80,6 +92,8 @@ tests_empty_pin_store_test_LDADD += src/libwolfpkcs11.la tests_find_objects_null_template_test_LDADD += src/libwolfpkcs11.la tests_aes_cbc_pad_padding_test_LDADD += src/libwolfpkcs11.la tests_ecb_check_value_error_test_LDADD += src/libwolfpkcs11.la +tests_aes_keygen_attrs_test_LDADD += src/libwolfpkcs11.la +tests_pbkdf2_keygen_attrs_test_LDADD += src/libwolfpkcs11.la endif EXTRA_DIST += tests/unit.h \ diff --git a/tests/pbkdf2_keygen_attrs_test.c b/tests/pbkdf2_keygen_attrs_test.c new file mode 100644 index 00000000..29d10713 --- /dev/null +++ b/tests/pbkdf2_keygen_attrs_test.c @@ -0,0 +1,442 @@ +/* pbkdf2_keygen_attrs_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 that C_GenerateKey sets CKA_LOCAL and CKA_KEY_GEN_MECHANISM + * correctly on PBKDF2-derived keys (bug #2037). + */ + +#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" + +#if !defined(NO_PWDBASED) && !defined(NO_HMAC) + +#define TEST_DIR "./store/pbkdf2_keygen_attrs_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_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); +} + +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); +} + +/* + * Test: Generate a PBKDF2 key via C_GenerateKey and verify that + * CKA_LOCAL is CK_TRUE and CKA_KEY_GEN_MECHANISM is CKM_PKCS5_PBKD2. + */ +static int test_pbkdf2_keygen_attrs(CK_SESSION_HANDLE session) +{ + CK_RV ret; + CK_OBJECT_HANDLE key; + CK_BBOOL local = CK_FALSE; + CK_MECHANISM_TYPE genMech = CK_UNAVAILABLE_INFORMATION; + CK_BBOOL alwaysSensitive = CK_FALSE; + CK_BBOOL neverExtractable = CK_FALSE; + int result = 0; + + CK_BYTE password[] = "TestPassword123"; + CK_ULONG passwordLen = sizeof(password) - 1; + CK_BYTE salt[] = { + 0x8A, 0x2F, 0x3E, 0x91, 0x45, 0x67, 0xBC, 0xDE, + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 + }; + CK_ULONG iterations = 10000; + CK_ULONG keyLength = 32; + + CK_PKCS5_PBKD2_PARAMS pbkdf2Params = { + CKZ_SALT_SPECIFIED, /* saltSource */ + salt, /* pSaltSourceData */ + sizeof(salt), /* ulSaltSourceDataLen */ + iterations, /* iterations */ + CKP_PKCS5_PBKD2_HMAC_SHA256, /* prf */ + NULL, /* pPrfData */ + 0, /* ulPrfDataLen */ + password, /* pPassword */ + &passwordLen /* ulPasswordLen */ + }; + + CK_MECHANISM mech = { + CKM_PKCS5_PBKD2, + &pbkdf2Params, + sizeof(pbkdf2Params) + }; + + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; + CK_BBOOL bTrue = CK_TRUE; + CK_BBOOL bFalse = CK_FALSE; + + CK_ATTRIBUTE genTmpl[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VALUE_LEN, &keyLength, sizeof(keyLength) }, + { CKA_SENSITIVE, &bTrue, sizeof(bTrue) }, + { CKA_EXTRACTABLE, &bFalse, sizeof(bFalse) }, + }; + CK_ULONG genTmplCnt = sizeof(genTmpl) / sizeof(*genTmpl); + + CK_ATTRIBUTE getTmpl[] = { + { CKA_LOCAL, &local, sizeof(local) }, + { CKA_KEY_GEN_MECHANISM, &genMech, sizeof(genMech) }, + { CKA_ALWAYS_SENSITIVE, &alwaysSensitive, sizeof(alwaysSensitive) }, + { CKA_NEVER_EXTRACTABLE, &neverExtractable, sizeof(neverExtractable) }, + }; + CK_ULONG getTmplCnt = sizeof(getTmpl) / sizeof(*getTmpl); + + ret = funcList->C_GenerateKey(session, &mech, genTmpl, genTmplCnt, &key); + CHECK_CKR(ret, "C_GenerateKey (PBKDF2)", CKR_OK); + + ret = funcList->C_GetAttributeValue(session, key, getTmpl, getTmplCnt); + CHECK_CKR(ret, "C_GetAttributeValue (CKA_LOCAL, CKA_KEY_GEN_MECHANISM)", + CKR_OK); + + if (local != CK_TRUE) { + fprintf(stderr, + "FAIL: CKA_LOCAL: expected CK_TRUE, got %d\n", (int)local); + test_failed++; + result = -1; + goto cleanup; + } + printf("PASS: CKA_LOCAL is CK_TRUE\n"); + test_passed++; + + if (genMech != CKM_PKCS5_PBKD2) { + fprintf(stderr, + "FAIL: CKA_KEY_GEN_MECHANISM: expected 0x%lx (CKM_PKCS5_PBKD2)," + " got 0x%lx\n", + (unsigned long)CKM_PKCS5_PBKD2, (unsigned long)genMech); + test_failed++; + result = -1; + goto cleanup; + } + printf("PASS: CKA_KEY_GEN_MECHANISM is CKM_PKCS5_PBKD2\n"); + test_passed++; + + if (alwaysSensitive != CK_TRUE) { + fprintf(stderr, + "FAIL: CKA_ALWAYS_SENSITIVE: expected CK_TRUE, got %d\n", + (int)alwaysSensitive); + test_failed++; + result = -1; + goto cleanup; + } + printf("PASS: CKA_ALWAYS_SENSITIVE is CK_TRUE\n"); + test_passed++; + + if (neverExtractable != CK_TRUE) { + fprintf(stderr, + "FAIL: CKA_NEVER_EXTRACTABLE: expected CK_TRUE, got %d\n", + (int)neverExtractable); + test_failed++; + result = -1; + goto cleanup; + } + printf("PASS: CKA_NEVER_EXTRACTABLE is CK_TRUE\n"); + test_passed++; + +cleanup: + return result; +} + +static int pbkdf2_keygen_attrs_test(void) +{ + CK_RV ret; + CK_SESSION_HANDLE session = 0; + int result = 0; + + printf("\n=== Testing PBKDF2 C_GenerateKey CKA_LOCAL and " + "CKA_KEY_GEN_MECHANISM ===\n"); + + cleanup_test_files(TEST_DIR); + + ret = pkcs11_init(); + if (ret != CKR_OK) { + fprintf(stderr, "FAIL: pkcs11_init: 0x%lx\n", (unsigned long)ret); + test_failed++; + return -1; + } + + ret = pkcs11_init_token(); + if (ret != CKR_OK) { + fprintf(stderr, "FAIL: C_InitToken: 0x%lx\n", (unsigned long)ret); + test_failed++; + pkcs11_final(); + return -1; + } + + /* 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); + if (ret != CKR_OK) { + fprintf(stderr, "FAIL: C_OpenSession (SO): 0x%lx\n", + (unsigned long)ret); + test_failed++; + pkcs11_final(); + return -1; + } + + ret = funcList->C_Login(soSession, CKU_SO, soPin, soPinLen); + if (ret != CKR_OK) { + fprintf(stderr, "FAIL: C_Login (SO): 0x%lx\n", + (unsigned long)ret); + test_failed++; + funcList->C_CloseSession(soSession); + pkcs11_final(); + return -1; + } + + ret = funcList->C_InitPIN(soSession, userPin, userPinLen); + if (ret != CKR_OK) { + fprintf(stderr, "FAIL: C_InitPIN: 0x%lx\n", (unsigned long)ret); + test_failed++; + funcList->C_Logout(soSession); + funcList->C_CloseSession(soSession); + pkcs11_final(); + return -1; + } + + funcList->C_Logout(soSession); + funcList->C_CloseSession(soSession); + } + + ret = pkcs11_open_session(&session); + if (ret != CKR_OK) { + fprintf(stderr, "FAIL: pkcs11_open_session: 0x%lx\n", + (unsigned long)ret); + test_failed++; + pkcs11_final(); + return -1; + } + + if (test_pbkdf2_keygen_attrs(session) != 0) + result = -1; + + 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", TEST_DIR, 1); +#endif + + (void)argc; + (void)argv; + + printf("=== wolfPKCS11 PBKDF2 KeyGen Attributes Test ===\n"); + + (void)pbkdf2_keygen_attrs_test(); + + print_results(); + + return (test_failed == 0) ? 0 : 1; +} + +#else /* NO_PWDBASED || NO_HMAC */ + +int main(int argc, char* argv[]) +{ + (void)argc; + (void)argv; + + printf("PWDBASED/HMAC not available, skipping PBKDF2 keygen attributes test\n"); + return 0; +} + +#endif /* !NO_PWDBASED */ diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index 2606cdb7..73108091 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -697,13 +697,15 @@ static CK_RV test_token(void* args) ret = funcList->C_InitToken(slot, soPin, soPinLen, NULL); CHECK_CKR_FAIL(ret, CKR_ARGUMENTS_BAD, "Init Token no label"); } +#if WP11_MIN_PIN_LEN > 3 if (ret == CKR_OK) { ret = funcList->C_InitToken(slot, soPin, 3, label); - CHECK_CKR_FAIL(ret, CKR_PIN_INCORRECT, "Init Token too short PIN"); + CHECK_CKR_FAIL(ret, CKR_PIN_LEN_RANGE, "Init Token too short PIN"); } +#endif if (ret == CKR_OK) { ret = funcList->C_InitToken(slot, soPin, 33, label); - CHECK_CKR_FAIL(ret, CKR_PIN_INCORRECT, "Init Token too long PIN"); + CHECK_CKR_FAIL(ret, CKR_PIN_LEN_RANGE, "Init Token too long PIN"); } if (ret == CKR_OK) { @@ -833,13 +835,13 @@ static CK_RV test_pin(void* args) #if WP11_MIN_PIN_LEN > 3 if (ret == CKR_OK) { ret = funcList->C_InitPIN(session, userPin, 3); - CHECK_CKR_FAIL(ret, CKR_PIN_INCORRECT, + CHECK_CKR_FAIL(ret, CKR_PIN_LEN_RANGE, "Init PIN too short PIN"); } #endif if (ret == CKR_OK) { ret = funcList->C_InitPIN(session, userPin, 33); - CHECK_CKR_FAIL(ret, CKR_PIN_INCORRECT, + CHECK_CKR_FAIL(ret, CKR_PIN_LEN_RANGE, "Init PIN too long PIN"); } funcList->C_Logout(session); @@ -882,14 +884,14 @@ static CK_RV test_pin(void* args) if (ret == CKR_OK) { ret = funcList->C_SetPIN(session, userPin, userPinLen,userPin, 3); - CHECK_CKR_FAIL(ret, CKR_PIN_INCORRECT, + CHECK_CKR_FAIL(ret, CKR_PIN_LEN_RANGE, "Set PIN too short new pin"); } #endif if (ret == CKR_OK) { ret = funcList->C_SetPIN(session, userPin, userPinLen, userPin, 33); - CHECK_CKR_FAIL(ret, CKR_PIN_INCORRECT, + CHECK_CKR_FAIL(ret, CKR_PIN_LEN_RANGE, "Set PIN too long new pin"); } if (ret == CKR_OK) { diff --git a/wolfpkcs11/internal.h b/wolfpkcs11/internal.h index 66d357fe..f102619a 100644 --- a/wolfpkcs11/internal.h +++ b/wolfpkcs11/internal.h @@ -457,6 +457,8 @@ WP11_LOCAL int WP11_Object_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, CK_ULONG* len); WP11_LOCAL int WP11_Object_SetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, CK_ULONG len); +WP11_LOCAL void WP11_Object_SetKeyGeneration(WP11_Object* object, + CK_MECHANISM_TYPE mechanism); WP11_LOCAL int WP11_Object_MatchAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, CK_ULONG len); WP11_LOCAL int WP11_Generic_SerializeKey(WP11_Object* object, byte* output, word32* poutsz); @@ -534,7 +536,8 @@ WP11_LOCAL int WP11_Dh_GenerateKeyPair(WP11_Object* pub, WP11_Object* priv, WP11_LOCAL int WP11_Dh_Derive(unsigned char* pub, word32 pubLen, unsigned char* key, word32* keyLen, WP11_Object* priv); -WP11_LOCAL int WP11_GenerateRandomKey(WP11_Object* secret, WP11_Slot* slot); +WP11_LOCAL int WP11_GenerateRandomKey(WP11_Object* secret, WP11_Slot* slot, + CK_MECHANISM_TYPE mechanism); WP11_LOCAL int WP11_KDF_Derive(WP11_Session* session, CK_HKDF_PARAMS_PTR params, unsigned char* key, word32* keyLen, WP11_Object* priv);