From 0c18e564218c23fc576d87f76d09a3e8288a6c38 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 25 Jun 2025 21:11:49 +0200 Subject: [PATCH 01/50] Add configdir and other fixes * Declare `CKM_HKDF_KEY_GEN` properly * Increase object cuonts for NSS * Add configdir parameter during `C_Initialize` for NSS --- src/internal.c | 61 +++++++++++++++++++-------- src/slot.c | 6 +++ src/wolfpkcs11.c | 97 +++++++++++++++++++++++++++++++++++++++---- wolfpkcs11/internal.h | 9 ++++ wolfpkcs11/pkcs11.h | 3 ++ 5 files changed, 151 insertions(+), 25 deletions(-) diff --git a/src/internal.c b/src/internal.c index cc161d1e..4990c65d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -491,7 +491,7 @@ struct WP11_Slot { /* Number of slots. */ -static int slotCnt = 1; +static const int slotCnt = 1; /* List of slot objects. */ static WP11_Slot slotList[1]; /* Global random used in random API, cryptographic operations and generating @@ -935,6 +935,7 @@ static word32 wolfPKCS11_Store_Handle(int type, CK_ULONG id1, CK_ULONG id2) static int wolfPKCS11_Store_Name(int type, CK_ULONG id1, CK_ULONG id2, char* name, int nameLen) { + int ret = 0; #ifndef WOLFPKCS11_NO_ENV const char* str = NULL; #endif @@ -1000,54 +1001,58 @@ static int wolfPKCS11_Store_Name(int type, CK_ULONG id1, CK_ULONG id2, char* nam /* Set different filename for each type of data and different ids. */ switch (type) { case WOLFPKCS11_STORE_TOKEN: - XSNPRINTF(name, nameLen, "%s/wp11_token_%016lx", str, id1); + ret = XSNPRINTF(name, nameLen, "%s/wp11_token_%016lx", str, id1); break; case WOLFPKCS11_STORE_OBJECT: - XSNPRINTF(name, nameLen, "%s/wp11_obj_%016lx_%016lx", str, id1, + ret = XSNPRINTF(name, nameLen, "%s/wp11_obj_%016lx_%016lx", str, id1, id2); break; case WOLFPKCS11_STORE_SYMMKEY: - XSNPRINTF(name, nameLen, "%s/wp11_symmkey_%016lx_%016lx", str, + ret = XSNPRINTF(name, nameLen, "%s/wp11_symmkey_%016lx_%016lx", str, id1, id2); break; case WOLFPKCS11_STORE_RSAKEY_PRIV: - XSNPRINTF(name, nameLen, "%s/wp11_rsakey_priv_%016lx_%016lx", + ret = XSNPRINTF(name, nameLen, "%s/wp11_rsakey_priv_%016lx_%016lx", str, id1, id2); break; case WOLFPKCS11_STORE_RSAKEY_PUB: - XSNPRINTF(name, nameLen, "%s/wp11_rsakey_pub_%016lx_%016lx", + ret = XSNPRINTF(name, nameLen, "%s/wp11_rsakey_pub_%016lx_%016lx", str, id1, id2); break; case WOLFPKCS11_STORE_ECCKEY_PRIV: - XSNPRINTF(name, nameLen, "%s/wp11_ecckey_priv_%016lx_%016lx", + ret = XSNPRINTF(name, nameLen, "%s/wp11_ecckey_priv_%016lx_%016lx", str, id1, id2); break; case WOLFPKCS11_STORE_ECCKEY_PUB: - XSNPRINTF(name, nameLen, "%s/wp11_ecckey_pub_%016lx_%016lx", + ret = XSNPRINTF(name, nameLen, "%s/wp11_ecckey_pub_%016lx_%016lx", str, id1, id2); break; case WOLFPKCS11_STORE_DHKEY_PRIV: - XSNPRINTF(name, nameLen, "%s/wp11_dhkey_priv_%016lx_%016lx", + ret = XSNPRINTF(name, nameLen, "%s/wp11_dhkey_priv_%016lx_%016lx", str, id1, id2); break; case WOLFPKCS11_STORE_DHKEY_PUB: - XSNPRINTF(name, nameLen, "%s/wp11_dhkey_pub_%016lx_%016lx", + ret = XSNPRINTF(name, nameLen, "%s/wp11_dhkey_pub_%016lx_%016lx", str, id1, id2); break; case WOLFPKCS11_STORE_CERT: - XSNPRINTF(name, nameLen, "%s/wp11_cert_%016lx_%016lx", + ret = XSNPRINTF(name, nameLen, "%s/wp11_cert_%016lx_%016lx", str, id1, id2); break; case WOLFPKCS11_STORE_TRUST: - XSNPRINTF(name, nameLen, "%s/wp11_trust_%016lx_%016lx", + ret = XSNPRINTF(name, nameLen, "%s/wp11_trust_%016lx_%016lx", str, id1, id2); break; default: - return -1; + ret = -1; break; } - return 0; + if (ret > 0 && ret < (int) sizeof(name)) + ret = 0; + else + ret = -1; + return ret; } #endif @@ -1099,6 +1104,24 @@ int wolfPKCS11_Store_Remove(int type, CK_ULONG id1, CK_ULONG id2) #endif return ret; } +#ifdef WOLFPKCS11_NSS +static char* storeDir = NULL; + +int WP11_SetStoreDir(const char *dir, size_t dirSz) +{ + if (storeDir != NULL) + XFREE(storeDir, NULL, DYNAMIC_TYPE_TMP_BUFFER); + storeDir = NULL; + if (dir != NULL) { + storeDir = (char*) XMALLOC(dirSz + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (storeDir == NULL) + return MEMORY_E; + XMEMCPY(storeDir, dir, dirSz); + storeDir[dirSz] = '\0'; /* Ensure null termination */ + } + return 0; +} +#endif /** * Opens access to location to read/write token data. @@ -4256,7 +4279,7 @@ static int wp11_Object_Unstore(WP11_Object* object, int tokenId, int objId) { int ret; int storeObjType = -1; - + if (objId < 0) { return BAD_FUNC_ARG; } @@ -4936,6 +4959,10 @@ void WP11_Library_Final(void) #endif (void)ret; /* store failure cannot be returned, so log and ignore */ } +#if !defined (WOLFPKCS11_CUSTOM_STORE) && defined(WOLFPKCS11_NSS) + XFREE(storeDir, NULL, DYNAMIC_TYPE_TMP_BUFFER); + storeDir = NULL; +#endif #endif /* Cleanup the slots. */ for (i = 0; i < slotCnt; i++) @@ -6225,9 +6252,7 @@ int WP11_Session_SetPssParams(WP11_Session* session, CK_MECHANISM_TYPE hashAlg, ret = wp11_hash_type(hashAlg, &pss->hashType); if (ret == 0) ret = wp11_mgf(mgf, &pss->mgf); - if (ret == 0 && sLen > RSA_PSS_SALT_MAX_SZ) - ret = BAD_FUNC_ARG; - else + if (ret == 0) pss->saltLen = sLen; return ret; diff --git a/src/slot.c b/src/slot.c index 41e6fae8..553de240 100644 --- a/src/slot.c +++ b/src/slot.c @@ -612,6 +612,9 @@ static CK_MECHANISM_INFO hkdfMechInfo = { static CK_MECHANISM_INFO hkdfDatMechInfo = { 1, 16320, CKF_DERIVE }; +static CK_MECHANISM_INFO hkdfKeyGenMechInfo = { + 20, 64, CKF_GENERATE +}; #endif #ifndef NO_DH /* Info on DH key generation mechanism. */ @@ -926,6 +929,9 @@ CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, case CKM_HKDF_DATA: XMEMCPY(pInfo, &hkdfDatMechInfo, sizeof(CK_MECHANISM_INFO)); break; + case CKM_HKDF_KEY_GEN: + XMEMCPY(pInfo, &hkdfKeyGenMechInfo, sizeof(CK_MECHANISM_INFO)); + break; #endif #ifndef NO_DH case CKM_DH_PKCS_KEY_PAIR_GEN: diff --git a/src/wolfpkcs11.c b/src/wolfpkcs11.c index d9823da9..6493fdd0 100644 --- a/src/wolfpkcs11.c +++ b/src/wolfpkcs11.c @@ -124,6 +124,63 @@ CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) return ret; } +#ifdef WOLFPKCS11_NSS +/* + * Parse a string of NSS configuration parameters. For now only the + * configdir parameter is supported. + */ +static CK_RV ParseNssConfigString(char *nssArgs, + char **configdir, size_t *configdirLen) +{ + while (*nssArgs != '\0') { + char* keyStart; + size_t keyLen; + char* valueStart; + size_t valueLen; + + while (*nssArgs == ' ') + nssArgs++; + if (*nssArgs == '\0') + break; + + keyStart = nssArgs; + while (*nssArgs != '=' && *nssArgs != '\0') + nssArgs++; + if (*nssArgs == '\0') + return CKR_ARGUMENTS_BAD; + + keyLen = nssArgs - keyStart; + nssArgs++; + if (keyLen == 0) + return CKR_ARGUMENTS_BAD; + + if (*nssArgs != '\'') + return CKR_ARGUMENTS_BAD; + nssArgs++; + valueStart = nssArgs; + while (*nssArgs != '\'' && *nssArgs != '\0') + nssArgs++; + if (*nssArgs != '\'') + return CKR_ARGUMENTS_BAD; + valueLen = nssArgs - valueStart; + nssArgs++; + if (valueLen == 0) + return CKR_ARGUMENTS_BAD; + if (*nssArgs != ' ' && *nssArgs != '\0') + return CKR_ARGUMENTS_BAD; + + if (keyLen == XSTR_SIZEOF("configdir") + && XMEMCMP(keyStart, "configdir", keyLen) == 0) { + *configdir = valueStart; + *configdirLen = valueLen; + /* Exit since we only support configdir */ + break; + } + } + return CKR_OK; +} +#endif + /** * Initialize the Crypto-Ki library. * @@ -133,17 +190,43 @@ CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) */ CK_RV C_Initialize(CK_VOID_PTR pInitArgs) { - CK_RV ret; + CK_RV ret = CKR_OK; + CK_C_INITIALIZE_ARGS *args = (CK_C_INITIALIZE_ARGS *)pInitArgs; WOLFPKCS11_ENTER("C_Initialize"); - - if (WP11_Library_Init() != 0) { - ret = CKR_FUNCTION_FAILED; - WOLFPKCS11_LEAVE("C_Initialize", ret); - return ret; + + if (args != NULL) { + WOLFPKCS11_MSG("Warning: C_Initialize called with arguments, but most " + "are ignored."); +#ifdef WOLFPKCS11_NSS + if (args->LibraryParameters != NULL) { + char* configdir = NULL; + size_t configdirLen = 0; + + ret = ParseNssConfigString((char*)args->LibraryParameters, + &configdir, &configdirLen); + if (ret == CKR_OK) { + if (configdir != NULL && configdirLen > 0) { + /* Set the configuration directory for NSS */ + if (WP11_SetStoreDir(configdir, configdirLen) != 0) { + WOLFPKCS11_MSG( + "Failed to set NSS configuration directory."); + ret = CKR_FUNCTION_FAILED; + } else { + WOLFPKCS11_MSG( + "wolfPKCS11 configuration directory set to: %.*s", + (int)configdirLen, configdir); + } + } + } + } +#endif } + if (ret == CKR_OK) + ret = WP11_Library_Init() == 0 ? CKR_OK : CKR_FUNCTION_FAILED; + + (void)pInitArgs; - ret = CKR_OK; WOLFPKCS11_LEAVE("C_Initialize", ret); return ret; } diff --git a/wolfpkcs11/internal.h b/wolfpkcs11/internal.h index f9e3791b..e679dd66 100644 --- a/wolfpkcs11/internal.h +++ b/wolfpkcs11/internal.h @@ -124,8 +124,12 @@ C_EXTRA_FLAGS="-DWOLFSSL_PUBLIC_MP -DWC_RSA_DIRECT" /* Maximum number of objects in a token. */ #ifndef WP11_TOKEN_OBJECT_CNT_MAX +#ifdef WOLFPKCS11_NSS +#define WP11_TOKEN_OBJECT_CNT_MAX 6400 +#else #define WP11_TOKEN_OBJECT_CNT_MAX 64 #endif +#endif /* Session was opened read-only or read/write. */ #define WP11_TOKEN_STATE_UNKNOWN 0 @@ -148,8 +152,12 @@ C_EXTRA_FLAGS="-DWOLFSSL_PUBLIC_MP -DWC_RSA_DIRECT" #define WP11_FIND_STATE_FOUND 2 /* Maximum number of matching objects to hold handles of. */ #ifndef WP11_FIND_MAX +#ifdef WOLFPKCS11_NSS +#define WP11_FIND_MAX 100 +#else #define WP11_FIND_MAX 10 #endif +#endif /* Flags for object. */ #define WP11_FLAG_PRIVATE 0x00000001 @@ -395,6 +403,7 @@ WP11_LOCAL CK_OBJECT_CLASS WP11_Object_GetClass(WP11_Object* object); #ifdef WOLFPKCS11_NSS WP11_LOCAL int WP11_Object_SetTrust(WP11_Object* object, unsigned char** data, CK_ULONG* len); +int WP11_SetStoreDir(const char *dir, size_t dirSz); #endif WP11_LOCAL int WP11_Object_Find(WP11_Session* session, CK_OBJECT_HANDLE objHandle, diff --git a/wolfpkcs11/pkcs11.h b/wolfpkcs11/pkcs11.h index 17e75bdf..b2a66dcc 100644 --- a/wolfpkcs11/pkcs11.h +++ b/wolfpkcs11/pkcs11.h @@ -607,6 +607,9 @@ typedef struct CK_C_INITIALIZE_ARGS { CK_LOCKMUTEX LockMutex; CK_UNLOCKMUTEX UnlockMutex; CK_FLAGS flags; +#ifdef WOLFPKCS11_NSS + CK_CHAR_PTR *LibraryParameters; +#endif CK_VOID_PTR pReserved; } CK_C_INITIALIZE_ARGS; typedef CK_C_INITIALIZE_ARGS* CK_C_INITIALIZE_ARGS_PTR; From 93a1ce3ba53b712da380bd20b51fa4340a2075d9 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 27 Jun 2025 12:43:15 +0200 Subject: [PATCH 02/50] Fix C_CopyObject `C_CopyObject` was not doing a proper copy. This changes the behaviour so that it does. --- src/crypto.c | 15 ++++-- src/internal.c | 118 ++++++++++++++++++++++++++++++++++++++++++ wolfpkcs11/internal.h | 1 + 3 files changed, 129 insertions(+), 5 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index c1352f30..6662b1b6 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -1117,7 +1117,7 @@ CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, WOLFPKCS11_LEAVE("C_CopyObject", rv); return rv; } - if (pTemplate == NULL || phNewObject == NULL) { + if (phNewObject == NULL) { rv = CKR_ARGUMENTS_BAD; WOLFPKCS11_LEAVE("C_CopyObject", rv); return rv; @@ -1166,14 +1166,19 @@ CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, /* Use get and set attribute value to fill in object. */ rv = C_GetAttributeValue(hSession, hObject, pTemplate, ulCount); + /* copy all the attributes from the original object to the new object */ + rv = WP11_Object_Copy(obj, newObj); if (rv != CKR_OK) { WP11_Object_Free(newObj); return rv; } - rv = SetAttributeValue(session, newObj, pTemplate, ulCount, CK_TRUE); - if (rv != CKR_OK) { - WP11_Object_Free(newObj); - return rv; + + if (pTemplate != NULL) { + rv = SetAttributeValue(session, newObj, pTemplate, ulCount, CK_FALSE); + if (rv != CKR_OK) { + WP11_Object_Free(newObj); + return rv; + } } ret = WP11_Session_AddObject(session, onToken, newObj); diff --git a/src/internal.c b/src/internal.c index 4990c65d..413d347e 100644 --- a/src/internal.c +++ b/src/internal.c @@ -214,6 +214,7 @@ typedef struct WP11_DhKey { } WP11_DhKey; #endif +/* When adding/modifying new members, add support in WP11_Object_Copy */ struct WP11_Object { union { #ifndef NO_RSA @@ -2150,6 +2151,123 @@ static long GetRsaExponentValue(unsigned char* eData, word32 eSz) } #endif +#define OBJ_COPY_DATA(src, dest, field) \ + do { \ + if (src->field != NULL) { \ + dest->field = (unsigned char*)XMALLOC(src->field##Len, NULL, \ + DYNAMIC_TYPE_TMP_BUFFER); \ + if (dest->field == NULL) \ + return MEMORY_E; \ + XMEMCPY(dest->field, src->field, src->field##Len); \ + dest->field##Len = src->field##Len; \ + } else { \ + dest->field = NULL; \ + dest->field##Len = 0; \ + } \ + } while (0) + +/** + * Copy an object. Not all fields are supported. + * @param src [in] Source object. + * @param dest [out] Destination object. + * @return 0 on success. + * <0 on failure. + */ +int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) +{ + int ret = 0; + + if (src == NULL || dest == NULL) + return BAD_FUNC_ARG; + + /* We save data copying for the last step */ + + dest->size = src->size; +#ifndef WOLFPKCS11_NO_STORE + OBJ_COPY_DATA(src, dest, keyData); + XMEMCPY(dest->iv, src->iv, sizeof(dest->iv)); + dest->encoded = src->encoded; +#endif + dest->objClass = src->objClass; + dest->keyGenMech = src->keyGenMech; + dest->opFlag = src->opFlag; + XMEMCPY(dest->startDate, src->startDate, sizeof(dest->startDate)); + XMEMCPY(dest->endDate, src->endDate, sizeof(dest->endDate)); + OBJ_COPY_DATA(src, dest, keyId); + OBJ_COPY_DATA(src, dest, label); + OBJ_COPY_DATA(src, dest, issuer); + OBJ_COPY_DATA(src, dest, serial); + OBJ_COPY_DATA(src, dest, subject); + + dest->category = src->category; + + if (src->objClass == CKO_CERTIFICATE) { + return BAD_FUNC_ARG; + } + else if (src->objClass == CKO_NSS_TRUST) { + return BAD_FUNC_ARG; + } + else { + switch (src->type) { +#ifndef NO_RSA + case CKK_RSA: { + byte* derBuf = NULL; + int derSz = 0; + + ret = wc_RsaKeyToDer(&src->data.rsaKey, NULL, 0); + if (ret == 0) /* Should not happen */ + ret = BUFFER_E; + if (ret > 0) { + derSz = ret; + ret = 0; + } + if (ret == 0) { + derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) + ret = MEMORY_E; + } + if (ret == 0) { + ret = wc_RsaKeyToDer(&src->data.rsaKey, derBuf, derSz); + if (ret == 0) /* Should not happen */ + ret = BUFFER_E; + if (ret > 0) + ret = 0; + } + if (ret == 0) { + word32 idx = 0; + ret = wc_RsaPrivateKeyDecode(derBuf, &idx, & + dest->data.rsaKey, (word32)derSz); + } + + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + break; + } +#endif +#ifdef HAVE_ECC + case CKK_EC: + return BAD_FUNC_ARG; +#endif +#ifndef NO_DH + case CKK_DH: + return BAD_FUNC_ARG; +#endif +#ifndef NO_AES + case CKK_AES: +#endif +#ifdef WOLFPKCS11_HKDF + case CKK_HKDF: +#endif + case CKK_GENERIC_SECRET: + XMEMCPY(&dest->data.symmKey, &src->data.symmKey, + sizeof(dest->data.symmKey)); + break; + } + } + + + return ret; +} + #ifndef WOLFPKCS11_NO_STORE /** * Encrypt the data with AES-GCM. diff --git a/wolfpkcs11/internal.h b/wolfpkcs11/internal.h index e679dd66..616300b3 100644 --- a/wolfpkcs11/internal.h +++ b/wolfpkcs11/internal.h @@ -382,6 +382,7 @@ WP11_LOCAL int WP11_Object_New(WP11_Session* session, CK_KEY_TYPE type, WP11_Object** object); WP11_LOCAL int wp11_Object_AllocateTypeData(WP11_Object* object); WP11_LOCAL void WP11_Object_Free(WP11_Object* object); +WP11_LOCAL int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest); WP11_LOCAL CK_OBJECT_HANDLE WP11_Object_GetHandle(WP11_Object* object); WP11_LOCAL CK_KEY_TYPE WP11_Object_GetType(WP11_Object* object); From f317a54cf72e46c5b8f36d6a88de088c3149396f Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Tue, 1 Jul 2025 14:09:09 +0100 Subject: [PATCH 03/50] Fix regression test failures and NSS test failures * `C_CopyObject` template check if there is a `ulCount` * `WP_EC_Derive` would crash when the point isn't DER encoded --- src/crypto.c | 7 +++++++ src/internal.c | 21 ++++++++++++++------- tests/pkcs11mtt.c | 14 -------------- tests/pkcs11test.c | 34 ++++++++++++++++++++-------------- tests/testdata.h | 12 ++++++++++++ 5 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 6662b1b6..637d0472 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -1127,6 +1127,13 @@ CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, WOLFPKCS11_LEAVE("C_CopyObject", rv); return rv; } + if (pTemplate == NULL && ulCount > 0) { + rv = CKR_ARGUMENTS_BAD; + WOLFPKCS11_LEAVE("C_CopyObject", rv); + return rv; + } + + /* Need key type and whether object is to be on the token to create a new * object. Get the object type from original object and where to store diff --git a/src/internal.c b/src/internal.c index 413d347e..4894191b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -10191,14 +10191,22 @@ int WP11_EC_Derive(unsigned char* point, word32 pointLen, unsigned char* key, i++; } else { - ret = ASN_PARSE_E; - goto cleanup; + /* Not valid DER encoding, treat as raw X9.63 data */ + x963Data = point; + x963Len = pointLen; } } - dataLen = point[i++]; - if (dataLen == (int)(pointLen - i)) { - x963Data = point + i; - x963Len = dataLen; + if (i < (int)pointLen) { + dataLen = point[i++]; + if (dataLen == (int)(pointLen - i)) { + x963Data = point + i; + x963Len = dataLen; + } + else { + /* Length mismatch, treat as raw X9.63 data */ + x963Data = point; + x963Len = pointLen; + } } } @@ -10243,7 +10251,6 @@ int WP11_EC_Derive(unsigned char* point, word32 pointLen, unsigned char* key, #endif } -cleanup: wc_ecc_free(&pubKey); return ret; diff --git a/tests/pkcs11mtt.c b/tests/pkcs11mtt.c index b479f882..d3e57215 100644 --- a/tests/pkcs11mtt.c +++ b/tests/pkcs11mtt.c @@ -3251,13 +3251,6 @@ static CK_RV test_rsa_pkcs_pss_sig_fail(void* args) "Sign Init bad mgf algorithm"); params.mgf = CKG_MGF1_SHA256; } - if (ret == CKR_OK) { - params.sLen = 63; - ret = funcList->C_SignInit(session, &mech, priv); - CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, - "Sign Init bad salt length"); - params.sLen = 32; - } if (ret == CKR_OK) { mech.pParameter = NULL; ret = funcList->C_VerifyInit(session, &mech, priv); @@ -3286,13 +3279,6 @@ static CK_RV test_rsa_pkcs_pss_sig_fail(void* args) "Verify Init bad mgf algorithm"); params.mgf = CKG_MGF1_SHA256; } - if (ret == CKR_OK) { - params.sLen = 63; - ret = funcList->C_VerifyInit(session, &mech, priv); - CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, - "Verify Init bad salt length"); - params.sLen = 32; - } funcList->C_DestroyObject(session, pub); funcList->C_DestroyObject(session, priv); diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index 4e8ea51c..8eb150e0 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -5785,13 +5785,6 @@ static CK_RV test_rsa_pkcs_pss_sig_fail(void* args) "Sign Init bad mgf algorithm"); params.mgf = CKG_MGF1_SHA256; } - if (ret == CKR_OK) { - params.sLen = 63; - ret = funcList->C_SignInit(session, &mech, priv); - CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, - "Sign Init bad salt length"); - params.sLen = 32; - } if (ret == CKR_OK) { mech.pParameter = NULL; ret = funcList->C_VerifyInit(session, &mech, priv); @@ -5820,13 +5813,6 @@ static CK_RV test_rsa_pkcs_pss_sig_fail(void* args) "Verify Init bad mgf algorithm"); params.mgf = CKG_MGF1_SHA256; } - if (ret == CKR_OK) { - params.sLen = 63; - ret = funcList->C_VerifyInit(session, &mech, priv); - CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, - "Verify Init bad salt length"); - params.sLen = 32; - } return ret; } @@ -6984,6 +6970,25 @@ static CK_RV test_ecdsa_sig_fail(void* args) return ret; } + +static CK_RV test_ecdh_x963(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE; + + ret = get_ecc_priv_key(session, CK_FALSE, &priv); + if (ret == CKR_OK) + ret = get_ecc_pub_key(session, &pub); + if (ret == CKR_OK) { + /* Test with x963 data */ + ret = ecdh_test(session, priv, ecc_p256_x963_point, + sizeof(ecc_p256_x963_point), 0); + } + + return ret; +} #endif #ifndef NO_DH @@ -13700,6 +13705,7 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_ecc_gen_keys_token), PKCS11TEST_FUNC_SESS_DECL(test_ecc_token_keys_ecdsa), PKCS11TEST_FUNC_SESS_DECL(test_ecdsa_sig_fail), + PKCS11TEST_FUNC_SESS_DECL(test_ecdh_x963), #endif /* HAVE_ECC */ #ifndef NO_DH PKCS11TEST_FUNC_SESS_DECL(test_dh_fixed_keys), diff --git a/tests/testdata.h b/tests/testdata.h index 9ab5a774..d3ded20a 100644 --- a/tests/testdata.h +++ b/tests/testdata.h @@ -256,6 +256,18 @@ static const unsigned char ecc_secret_256[] = { 0x8b, 0x25, 0xe4, 0x6d, 0x5c, 0x9e, 0xdd, 0xf9 }; static const int sizeof_ecc_secret_256 = sizeof(ecc_secret_256); + +static unsigned char ecc_p256_x963_point[] = { + 0x04, 0xe8, 0x0b, 0x9b, 0x25, 0xe3, 0x27, 0x81, + 0xb6, 0xbe, 0x87, 0x29, 0xf5, 0x08, 0x06, 0x74, + 0x04, 0xea, 0xba, 0xd9, 0x92, 0x72, 0x34, 0xca, + 0x56, 0x91, 0x55, 0x90, 0x29, 0xda, 0x4e, 0x7e, + 0x44, 0x09, 0x64, 0xac, 0xfc, 0xb1, 0xb3, 0x06, + 0xb8, 0x38, 0x3c, 0x68, 0x8d, 0x96, 0x75, 0x6b, + 0xee, 0xdd, 0xe1, 0xd5, 0xcb, 0x82, 0x88, 0xd7, + 0x79, 0xa2, 0xe2, 0x7c, 0xd3, 0x60, 0xc6, 0x4c, + 0xc0 +}; #endif #ifndef NO_DH From b8b4ecd714b81bee1be56f6ff0621bc39f2aff56 Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Wed, 2 Jul 2025 15:03:38 +0100 Subject: [PATCH 04/50] Add `CKM_RSA_PKCS` to wrap and unwrap --- src/crypto.c | 74 ++++++++++++++++++++++++++++ tests/pkcs11test.c | 119 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) diff --git a/src/crypto.c b/src/crypto.c index 637d0472..9db2805f 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -6448,6 +6448,9 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; word32 serialSize = 0; byte* serialBuff = NULL; +#ifndef NO_RSA + word32 encDataLen; +#endif WOLFPKCS11_ENTER("C_WrapKey"); #ifdef DEBUG_WOLFPKCS11 @@ -6563,6 +6566,44 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, break; #endif +#ifndef NO_RSA + case CKM_RSA_PKCS: + if (wrapkeyType != CKK_RSA) { + rv = CKR_WRAPPING_KEY_TYPE_INCONSISTENT; + goto err_out; + } + + if (pMechanism->pParameter != NULL || + pMechanism->ulParameterLen != 0) { + rv = CKR_MECHANISM_PARAM_INVALID; + goto err_out; + } + + encDataLen = WP11_Rsa_KeyLen(wrappingKey); + if (pWrappedKey == NULL) { + *pulWrappedKeyLen = encDataLen; + rv = CKR_OK; + goto err_out; + } + if (*pulWrappedKeyLen < encDataLen) { + *pulWrappedKeyLen = encDataLen; + rv = CKR_BUFFER_TOO_SMALL; + goto err_out; + } + + ret = WP11_RsaPkcs15_PublicEncrypt(serialBuff, serialSize, + pWrappedKey, &encDataLen, + wrappingKey, + WP11_Session_GetSlot(session) + ); + if (ret != 0) { + rv = CKR_FUNCTION_FAILED; + goto err_out; + } + *pulWrappedKeyLen = encDataLen; + + break; +#endif default: rv = CKR_MECHANISM_INVALID; break; @@ -6619,6 +6660,9 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE* attr = NULL; byte* workBuffer = NULL; CK_ULONG ulUnwrappedLen = ulWrappedKeyLen; +#ifndef NO_RSA + word32 decryptedLen; +#endif WOLFPKCS11_ENTER("C_UnwrapKey"); #ifdef DEBUG_WOLFPKCS11 @@ -6711,6 +6755,36 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, break; #endif +#ifndef NO_RSA + case CKM_RSA_PKCS: + if (wrapkeyType != CKK_RSA) + return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; + + if (pMechanism->pParameter != NULL || + pMechanism->ulParameterLen != 0) { + rv = CKR_MECHANISM_PARAM_INVALID; + goto err_out; + } + + workBuffer = (byte*)XMALLOC(ulWrappedKeyLen, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (workBuffer == NULL) + return CKR_HOST_MEMORY; + + decryptedLen = (word32)ulUnwrappedLen; + ret = WP11_RsaPkcs15_PrivateDecrypt(pWrappedKey, ulWrappedKeyLen, + workBuffer, &decryptedLen, + unwrappingKey, + WP11_Session_GetSlot(session)); + ulUnwrappedLen = (CK_ULONG)decryptedLen; + + if (ret != 0) { + rv = CKR_FUNCTION_FAILED; + goto err_out; + } + + break; +#endif default: rv = CKR_MECHANISM_INVALID; goto err_out; diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index 8eb150e0..b2c53a78 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -4358,6 +4358,122 @@ static CK_RV find_rsa_priv_key_label(CK_SESSION_HANDLE session, } #endif +static CK_RV test_rsa_wrap_unwrap_key(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_MECHANISM mech = { CKM_RSA_PKCS, NULL, 0 }; + CK_OBJECT_HANDLE wrappingPrivKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE wrappingPubKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE key = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE unwrappedKey = CK_INVALID_HANDLE; + byte wrappedKey[256], keyData[32]; + CK_ULONG wrappedKeyLen; + CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + }; + CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); + + memset(keyData, 7, sizeof(keyData)); + wrappedKeyLen = sizeof(wrappedKey); + + /* Get RSA key pair for wrapping */ + ret = get_rsa_priv_key(session, NULL, 0, CK_FALSE, &wrappingPrivKey); + if (ret == CKR_OK) { + ret = get_rsa_pub_key(session, NULL, 0, &wrappingPubKey); + } + + /* Create a secret key to wrap */ + if (ret == CKR_OK) { + ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, &key); + } + + /* Test wrapping with RSA public key */ + if (ret == CKR_OK) { + ret = funcList->C_WrapKey(session, &mech, wrappingPubKey, key, + wrappedKey, &wrappedKeyLen); + CHECK_CKR(ret, "RSA Wrap Key mechanism"); + } + + /* Destroy original key since unwrap returns new handle */ + funcList->C_DestroyObject(session, key); + key = CK_INVALID_HANDLE; + + /* Test unwrapping with RSA private key */ + if (ret == CKR_OK) { + ret = funcList->C_UnwrapKey(session, &mech, wrappingPrivKey, + wrappedKey, wrappedKeyLen, tmpl, tmplCnt, + &unwrappedKey); + CHECK_CKR(ret, "RSA UnWrap Key mechanism"); + } + + /* Test getting wrapped key length */ + if (ret == CKR_OK) { + ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, &key); + if (ret == CKR_OK) { + CK_ULONG testLen = 0; + ret = funcList->C_WrapKey(session, &mech, wrappingPubKey, key, + NULL, &testLen); + CHECK_CKR(ret, "RSA Wrap Key get length"); + if (ret == CKR_OK && testLen != wrappedKeyLen) { + ret = CKR_GENERAL_ERROR; + printf("ERROR: Expected wrapped key length %lu, got %lu\n", + wrappedKeyLen, testLen); + } + } + } + + /* Test with wrong key type for wrapping */ + if (ret == CKR_OK) { + CK_OBJECT_HANDLE aesKey = CK_INVALID_HANDLE; + ret = get_aes_128_key(session, NULL, 0, &aesKey); + if (ret == CKR_OK) { + CK_RV wrapRet = funcList->C_WrapKey(session, &mech, aesKey, key, + wrappedKey, &wrappedKeyLen); + CHECK_CKR_FAIL(wrapRet, CKR_WRAPPING_KEY_TYPE_INCONSISTENT, + "RSA Wrap Key with AES key"); + funcList->C_DestroyObject(session, aesKey); + } + } + + /* Test with wrong key type for unwrapping */ + if (ret == CKR_OK) { + CK_OBJECT_HANDLE aesKey = CK_INVALID_HANDLE; + ret = get_aes_128_key(session, NULL, 0, &aesKey); + if (ret == CKR_OK) { + CK_RV unwrapRet = funcList->C_UnwrapKey(session, &mech, aesKey, + wrappedKey, wrappedKeyLen, + tmpl, tmplCnt, &key); + CHECK_CKR_FAIL(unwrapRet, CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT, + "RSA UnWrap Key with AES key"); + funcList->C_DestroyObject(session, aesKey); + } + } + + /* Test buffer too small error */ + if (ret == CKR_OK) { + /* Create fresh key for this test since original was destroyed */ + ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, &key); + if (ret == CKR_OK) { + CK_ULONG smallLen = 1; + CK_RV wrapRet = funcList->C_WrapKey(session, &mech, wrappingPubKey, + key, wrappedKey, &smallLen); + CHECK_CKR_FAIL(wrapRet, CKR_BUFFER_TOO_SMALL, + "RSA Wrap Key with buffer too small"); + } + } + + /* Clean up */ + funcList->C_DestroyObject(session, wrappingPrivKey); + funcList->C_DestroyObject(session, wrappingPubKey); + funcList->C_DestroyObject(session, key); + funcList->C_DestroyObject(session, unwrappedKey); + + return ret; +} + static CK_RV test_attributes_rsa(void* args) { CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; @@ -13656,6 +13772,9 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_aes_wrap_unwrap_pad_key), PKCS11TEST_FUNC_SESS_DECL(test_wrap_unwrap_key), #endif /* HAVE_AES_KEYWRAP && !WOLFPKCS11_NO_STORE */ +#ifndef NO_RSA + PKCS11TEST_FUNC_SESS_DECL(test_rsa_wrap_unwrap_key), +#endif #ifndef NO_DH PKCS11TEST_FUNC_SESS_DECL(test_derive_key), #endif From 678a6ed4bee2517be57a345028bcfd662f590a8a Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Wed, 2 Jul 2025 16:14:36 +0100 Subject: [PATCH 05/50] Fix CI failure --- src/internal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/internal.c b/src/internal.c index 4894191b..eba932bc 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2204,9 +2204,11 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) if (src->objClass == CKO_CERTIFICATE) { return BAD_FUNC_ARG; } +#ifdef WOLFPKCS11_NSS else if (src->objClass == CKO_NSS_TRUST) { return BAD_FUNC_ARG; } +#endif else { switch (src->type) { #ifndef NO_RSA From 9a6533f0404a96273b30672558003488a076088f Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Thu, 3 Jul 2025 07:25:49 +0100 Subject: [PATCH 06/50] More NSS fixes * `C_Decrypt` should return `CKR_ENCRYPTED_DATA_INVALID` when decryption fails * Fix Clang compiler error * Fix RSA test for storage disabled * Fix NSS + storage disabled compiling * Declare `CKM_HKDF_KEY_GEN` in mechanism list --- src/crypto.c | 28 ++++++++++++++-------------- src/slot.c | 1 + src/wolfpkcs11.c | 11 +++++------ tests/pkcs11test.c | 13 +++++++++---- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 9db2805f..5573caac 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -2972,7 +2972,7 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, &decDataLen, obj, WP11_Session_GetSlot(session)); if (ret < 0) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_INVALID; *pulDataLen = decDataLen; break; case CKM_RSA_PKCS: @@ -2992,7 +2992,7 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, &decDataLen, obj, WP11_Session_GetSlot(session)); if (ret < 0) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_INVALID; *pulDataLen = decDataLen; break; #ifndef WC_NO_RSA_OAEP @@ -3014,7 +3014,7 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, (int)ulEncryptedDataLen, pData, &decDataLen, obj, session); if (ret < 0) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_INVALID; *pulDataLen = decDataLen; break; #endif @@ -3036,7 +3036,7 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, ret = WP11_AesCbc_Decrypt(pEncryptedData, (int)ulEncryptedDataLen, pData, &decDataLen, session); if (ret < 0) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_INVALID; *pulDataLen = decDataLen; break; case CKM_AES_CBC_PAD: @@ -3055,7 +3055,7 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, (int)ulEncryptedDataLen, pData, &decDataLen, session); if (ret < 0) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_INVALID; *pulDataLen = decDataLen; break; #endif @@ -3075,7 +3075,7 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, ret = WP11_AesCtr_Do(pEncryptedData, (word32)ulEncryptedDataLen, pData, &decDataLen, session); if (ret != 0) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_INVALID; *pulDataLen = decDataLen; break; #endif @@ -3096,7 +3096,7 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, ret = WP11_AesGcm_Decrypt(pEncryptedData, (int)ulEncryptedDataLen, pData, &decDataLen, obj, session); if (ret < 0) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_INVALID; *pulDataLen = decDataLen; break; #endif @@ -3117,7 +3117,7 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, ret = WP11_AesCcm_Decrypt(pEncryptedData, (int)ulEncryptedDataLen, pData, &decDataLen, obj, session); if (ret < 0) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_INVALID; *pulDataLen = decDataLen; break; #endif @@ -3137,7 +3137,7 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, ret = WP11_AesEcb_Decrypt(pEncryptedData, (int)ulEncryptedDataLen, pData, &decDataLen, obj, session); if (ret < 0) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_INVALID; *pulDataLen = decDataLen; break; #endif @@ -3159,7 +3159,7 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, if (ret == BUFFER_E) return CKR_BUFFER_TOO_SMALL; if (ret < 0) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_INVALID; *pulDataLen = decDataLen; break; #endif @@ -3183,15 +3183,15 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, ret = WP11_AesKeyWrap_Decrypt(pEncryptedData, (word32)ulEncryptedDataLen, pData, &decDataLen, session); if (ret != 0) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_INVALID; if (mechanism == CKM_AES_KEY_WRAP_PAD) { int i; byte padValue = pData[decDataLen - 1]; if (padValue > KEYWRAP_BLOCK_SIZE || padValue > decDataLen) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_LEN_RANGE; for (i = 0; i < padValue; i++) { if (pData[decDataLen - 1 - i] != padValue) - return CKR_FUNCTION_FAILED; + return CKR_ENCRYPTED_DATA_INVALID; } decDataLen -= padValue; } @@ -6772,7 +6772,7 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, return CKR_HOST_MEMORY; decryptedLen = (word32)ulUnwrappedLen; - ret = WP11_RsaPkcs15_PrivateDecrypt(pWrappedKey, ulWrappedKeyLen, + ret = WP11_RsaPkcs15_PrivateDecrypt(pWrappedKey, decryptedLen, workBuffer, &decryptedLen, unwrappingKey, WP11_Session_GetSlot(session)); diff --git a/src/slot.c b/src/slot.c index 553de240..39489173 100644 --- a/src/slot.c +++ b/src/slot.c @@ -361,6 +361,7 @@ static CK_MECHANISM_TYPE mechanismList[] = { #ifdef WOLFPKCS11_HKDF CKM_HKDF_DERIVE, CKM_HKDF_DATA, + CKM_HKDF_KEY_GEN, #endif #ifndef NO_DH CKM_DH_PKCS_KEY_PAIR_GEN, diff --git a/src/wolfpkcs11.c b/src/wolfpkcs11.c index 6493fdd0..e2f29305 100644 --- a/src/wolfpkcs11.c +++ b/src/wolfpkcs11.c @@ -111,7 +111,7 @@ CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) { CK_RV ret; WOLFPKCS11_ENTER("C_GetFunctionList"); - + if (ppFunctionList == NULL) { ret = CKR_ARGUMENTS_BAD; WOLFPKCS11_LEAVE("C_GetFunctionList", ret); @@ -124,7 +124,7 @@ CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) return ret; } -#ifdef WOLFPKCS11_NSS +#if (defined(WOLFPKCS11_NSS) && !defined(WOLFPKCS11_NO_STORE)) /* * Parse a string of NSS configuration parameters. For now only the * configdir parameter is supported. @@ -197,7 +197,7 @@ CK_RV C_Initialize(CK_VOID_PTR pInitArgs) if (args != NULL) { WOLFPKCS11_MSG("Warning: C_Initialize called with arguments, but most " "are ignored."); -#ifdef WOLFPKCS11_NSS +#if (defined(WOLFPKCS11_NSS) && !defined(WOLFPKCS11_NO_STORE)) if (args->LibraryParameters != NULL) { char* configdir = NULL; size_t configdirLen = 0; @@ -241,7 +241,7 @@ CK_RV C_Finalize(CK_VOID_PTR pReserved) { CK_RV ret; WOLFPKCS11_ENTER("C_Finalize"); - + WP11_Library_Final(); (void)pReserved; @@ -271,7 +271,7 @@ CK_RV C_GetInfo(CK_INFO_PTR pInfo) { CK_RV ret; WOLFPKCS11_ENTER("C_GetInfo"); - + if (!WP11_Library_IsInitialized()) { ret = CKR_CRYPTOKI_NOT_INITIALIZED; WOLFPKCS11_LEAVE("C_GetInfo", ret); @@ -288,4 +288,3 @@ CK_RV C_GetInfo(CK_INFO_PTR pInfo) WOLFPKCS11_LEAVE("C_GetInfo", ret); return ret; } - diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index b2c53a78..4ca626e5 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -4358,6 +4358,7 @@ static CK_RV find_rsa_priv_key_label(CK_SESSION_HANDLE session, } #endif +#ifndef WOLFPKCS11_NO_STORE static CK_RV test_rsa_wrap_unwrap_key(void* args) { CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; @@ -4387,7 +4388,8 @@ static CK_RV test_rsa_wrap_unwrap_key(void* args) /* Create a secret key to wrap */ if (ret == CKR_OK) { - ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, &key); + ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, + &key); } /* Test wrapping with RSA public key */ @@ -4411,7 +4413,8 @@ static CK_RV test_rsa_wrap_unwrap_key(void* args) /* Test getting wrapped key length */ if (ret == CKR_OK) { - ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, &key); + ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, + &key); if (ret == CKR_OK) { CK_ULONG testLen = 0; ret = funcList->C_WrapKey(session, &mech, wrappingPubKey, key, @@ -4455,7 +4458,8 @@ static CK_RV test_rsa_wrap_unwrap_key(void* args) /* Test buffer too small error */ if (ret == CKR_OK) { /* Create fresh key for this test since original was destroyed */ - ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, &key); + ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, + &key); if (ret == CKR_OK) { CK_ULONG smallLen = 1; CK_RV wrapRet = funcList->C_WrapKey(session, &mech, wrappingPubKey, @@ -4473,6 +4477,7 @@ static CK_RV test_rsa_wrap_unwrap_key(void* args) return ret; } +#endif static CK_RV test_attributes_rsa(void* args) { @@ -13772,7 +13777,7 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_aes_wrap_unwrap_pad_key), PKCS11TEST_FUNC_SESS_DECL(test_wrap_unwrap_key), #endif /* HAVE_AES_KEYWRAP && !WOLFPKCS11_NO_STORE */ -#ifndef NO_RSA +#if (!defined(NO_RSA) && !defined(WOLFPKCS11_NO_STORE)) PKCS11TEST_FUNC_SESS_DECL(test_rsa_wrap_unwrap_key), #endif #ifndef NO_DH From 7eb1d0235853d5a024cd9606fe12bfdf1b90aa7d Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Thu, 3 Jul 2025 12:22:18 +0100 Subject: [PATCH 07/50] Add tests for `C_CopyObject` changes --- tests/pkcs11test.c | 499 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 499 insertions(+) diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index 4ca626e5..40eab0f1 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -1674,6 +1674,501 @@ static CK_RV test_object(void* args) return ret; } +static CK_RV test_copy_object_deep_copy(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret = CKR_OK; + CK_OBJECT_HANDLE originalObj = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE copiedObj = CK_INVALID_HANDLE; + + /* Test data for various attributes */ + static byte keyData[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; + static byte keyId[] = { 0x11, 0x22, 0x33, 0x44 }; + static byte label[] = "test-key-label"; + static byte modifiedKeyData[] = { 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, + 0xF8 }; + static byte modifiedLabel[] = "modified-label"; + + /* Template for creating original object with multiple attributes */ + CK_ATTRIBUTE originalTmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_ID, keyId, sizeof(keyId) }, + { CKA_LABEL, label, sizeof(label)-1 }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + }; + CK_ULONG originalTmplCnt = sizeof(originalTmpl) / sizeof(*originalTmpl); + + /* Template for copying with modifications */ + CK_ATTRIBUTE copyWithModTmpl[] = { + { CKA_LABEL, modifiedLabel, sizeof(modifiedLabel)-1 }, + }; + CK_ULONG copyWithModTmplCnt = sizeof(copyWithModTmpl) / + sizeof(*copyWithModTmpl); + + /* Templates for attribute verification */ + CK_ATTRIBUTE getOriginalAttrs[] = { + { CKA_VALUE, NULL, 0 }, + { CKA_ID, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_EXTRACTABLE, NULL, 0 }, + }; + CK_ULONG getOriginalAttrsCnt = sizeof(getOriginalAttrs) / + sizeof(*getOriginalAttrs); + + CK_ATTRIBUTE getCopiedAttrs[] = { + { CKA_VALUE, NULL, 0 }, + { CKA_ID, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_EXTRACTABLE, NULL, 0 }, + }; + CK_ULONG getCopiedAttrsCnt = sizeof(getCopiedAttrs) / + sizeof(*getCopiedAttrs); + + /* Buffers for retrieved attributes */ + byte origValue[32], copiedValue[32]; + byte origId[32], copiedId[32]; + byte origLabel[64], copiedLabel[64]; + CK_BBOOL origExtractable, copiedExtractable; + + /* Create original object */ + ret = funcList->C_CreateObject(session, originalTmpl, originalTmplCnt, + &originalObj); + CHECK_CKR(ret, "Create original object for copy test"); + + /* Test 1: Copy without modifications (pure copy) */ + if (ret == CKR_OK) { + ret = funcList->C_CopyObject(session, originalObj, NULL, 0, + &copiedObj); + CHECK_CKR(ret, "Copy object without modifications"); + } + + /* Verify that both objects exist and have the same attributes */ + if (ret == CKR_OK) { + /* Set up buffers for original object attributes */ + getOriginalAttrs[0].pValue = origValue; + getOriginalAttrs[0].ulValueLen = sizeof(origValue); + getOriginalAttrs[1].pValue = origId; + getOriginalAttrs[1].ulValueLen = sizeof(origId); + getOriginalAttrs[2].pValue = origLabel; + getOriginalAttrs[2].ulValueLen = sizeof(origLabel); + getOriginalAttrs[3].pValue = &origExtractable; + getOriginalAttrs[3].ulValueLen = sizeof(origExtractable); + + ret = funcList->C_GetAttributeValue(session, originalObj, + getOriginalAttrs, + getOriginalAttrsCnt); + CHECK_CKR(ret, "Get original object attributes"); + } + + if (ret == CKR_OK) { + /* Set up buffers for copied object attributes */ + getCopiedAttrs[0].pValue = copiedValue; + getCopiedAttrs[0].ulValueLen = sizeof(copiedValue); + getCopiedAttrs[1].pValue = copiedId; + getCopiedAttrs[1].ulValueLen = sizeof(copiedId); + getCopiedAttrs[2].pValue = copiedLabel; + getCopiedAttrs[2].ulValueLen = sizeof(copiedLabel); + getCopiedAttrs[3].pValue = &copiedExtractable; + getCopiedAttrs[3].ulValueLen = sizeof(copiedExtractable); + + ret = funcList->C_GetAttributeValue(session, copiedObj, getCopiedAttrs, + getCopiedAttrsCnt); + CHECK_CKR(ret, "Get copied object attributes"); + } + + /* Verify that all attributes match */ + if (ret == CKR_OK) { + if (getOriginalAttrs[0].ulValueLen != getCopiedAttrs[0].ulValueLen || + XMEMCMP(origValue, copiedValue, + getOriginalAttrs[0].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied object VALUE should match original"); + } + } + + if (ret == CKR_OK) { + if (getOriginalAttrs[1].ulValueLen != getCopiedAttrs[1].ulValueLen || + XMEMCMP(origId, copiedId, + getOriginalAttrs[1].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied object ID should match original"); + } + } + + if (ret == CKR_OK) { + if (getOriginalAttrs[2].ulValueLen != getCopiedAttrs[2].ulValueLen || + XMEMCMP(origLabel, copiedLabel, + getOriginalAttrs[2].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied object LABEL should match original"); + } + } + + if (ret == CKR_OK) { + if (origExtractable != copiedExtractable) { + ret = -1; + CHECK_CKR(ret, "Copied object EXTRACTABLE should match original"); + } + } + + /* Clean up first copied object */ + if (ret == CKR_OK) { + ret = funcList->C_DestroyObject(session, copiedObj); + CHECK_CKR(ret, "Destroy first copied object"); + } + + /* Test 2: Copy with modifications */ + if (ret == CKR_OK) { + ret = funcList->C_CopyObject(session, originalObj, copyWithModTmpl, + copyWithModTmplCnt, &copiedObj); + CHECK_CKR(ret, "Copy object with modifications"); + } + + /* Verify that the copied object has the modified label but same other + * attributes */ + if (ret == CKR_OK) { + XMEMSET(copiedLabel, 0, sizeof(copiedLabel)); + getCopiedAttrs[2].pValue = copiedLabel; + getCopiedAttrs[2].ulValueLen = sizeof(copiedLabel); + + ret = funcList->C_GetAttributeValue(session, copiedObj, getCopiedAttrs, + getCopiedAttrsCnt); + CHECK_CKR(ret, "Get modified copied object attributes"); + } + + if (ret == CKR_OK) { + /* Verify VALUE and ID are still the same */ + if (getOriginalAttrs[0].ulValueLen != getCopiedAttrs[0].ulValueLen || + XMEMCMP(origValue, copiedValue, + getOriginalAttrs[0].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, "Modified copied object VALUE should still match " + "original"); + } + } + + if (ret == CKR_OK) { + if (getOriginalAttrs[1].ulValueLen != getCopiedAttrs[1].ulValueLen || + XMEMCMP(origId, copiedId, + getOriginalAttrs[1].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, "Modified copied object ID should still match " + "original"); + } + } + + if (ret == CKR_OK) { + /* Verify LABEL is different (modified) */ + if (getCopiedAttrs[2].ulValueLen != sizeof(modifiedLabel)-1 || + XMEMCMP(copiedLabel, modifiedLabel, + sizeof(modifiedLabel)-1) != 0) { + ret = -1; + CHECK_CKR(ret, "Modified copied object LABEL should be different"); + } + } + + /* Test 3: Verify independence (deep copy) by modifying original object */ + if (ret == CKR_OK) { + CK_ATTRIBUTE modifyOriginalTmpl[] = { + { CKA_VALUE, modifiedKeyData, + sizeof(modifiedKeyData) }, + }; + CK_ULONG modifyOriginalTmplCnt = sizeof(modifyOriginalTmpl) / + sizeof(*modifyOriginalTmpl); + + ret = funcList->C_SetAttributeValue(session, originalObj, + modifyOriginalTmpl, + modifyOriginalTmplCnt); + CHECK_CKR(ret, "Modify original object to test independence"); + } + + if (ret == CKR_OK) { + /* Get the modified original object's value */ + XMEMSET(origValue, 0, sizeof(origValue)); + getOriginalAttrs[0].pValue = origValue; + getOriginalAttrs[0].ulValueLen = sizeof(origValue); + + ret = funcList->C_GetAttributeValue(session, originalObj, + getOriginalAttrs, 1); + CHECK_CKR(ret, "Get modified original object value"); + } + + if (ret == CKR_OK) { + /* Get the copied object's value (should be unchanged) */ + XMEMSET(copiedValue, 0, sizeof(copiedValue)); + getCopiedAttrs[0].pValue = copiedValue; + getCopiedAttrs[0].ulValueLen = sizeof(copiedValue); + + ret = funcList->C_GetAttributeValue(session, copiedObj, getCopiedAttrs, + 1); + CHECK_CKR(ret, "Get copied object value after original " + "modification"); + } + + if (ret == CKR_OK) { + /* Verify original object has modified value */ + if (getOriginalAttrs[0].ulValueLen != sizeof(modifiedKeyData) || + XMEMCMP(origValue, modifiedKeyData, + sizeof(modifiedKeyData)) != 0) { + ret = -1; + CHECK_CKR(ret, "Original object should have modified value"); + } + } + + if (ret == CKR_OK) { + /* Verify copied object still has original value (proving deep copy) */ + if (getCopiedAttrs[0].ulValueLen != sizeof(keyData) || + XMEMCMP(copiedValue, keyData, + sizeof(keyData)) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied object should retain original value " + "(deep copy test)"); + } + } + + /* Clean up */ + if (originalObj != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, originalObj); + } + if (copiedObj != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, copiedObj); + } + + return ret; +} + +#if (!defined(NO_RSA) && !defined(WOLFPKCS11_TPM)) +static CK_RV test_copy_object_rsa_key(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret = CKR_OK; + CK_OBJECT_HANDLE pubKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE privKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE copiedPrivKey = CK_INVALID_HANDLE; + CK_MECHANISM mech; + CK_ULONG bits = 2048; + static byte keyId[] = { 0xAA, 0xBB, 0xCC, 0xDD }; + static byte label[] = "rsa-test-key"; + static byte modifiedLabel[] = "rsa-copied-key"; + + /* RSA key generation template */ + CK_ATTRIBUTE pubKeyTmpl[] = { + { CKA_MODULUS_BITS, &bits, sizeof(bits) }, + { CKA_PUBLIC_EXPONENT, rsa_2048_pub_exp, + sizeof(rsa_2048_pub_exp) }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_WRAP, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, + { CKA_ID, keyId, sizeof(keyId) }, + { CKA_LABEL, label, sizeof(label)-1 }, + }; + CK_ULONG pubKeyTmplCnt = sizeof(pubKeyTmpl) / sizeof(*pubKeyTmpl); + + CK_ATTRIBUTE privKeyTmpl[] = { + { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_UNWRAP, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_ID, keyId, sizeof(keyId) }, + { CKA_LABEL, label, sizeof(label)-1 }, + }; + CK_ULONG privKeyTmplCnt = sizeof(privKeyTmpl) / sizeof(*privKeyTmpl); + + /* Template for copying with modifications */ + CK_ATTRIBUTE copyTmpl[] = { + { CKA_LABEL, modifiedLabel, sizeof(modifiedLabel)-1 }, + }; + CK_ULONG copyTmplCnt = sizeof(copyTmpl) / sizeof(*copyTmpl); + + /* Templates for attribute verification */ + CK_ATTRIBUTE getOriginalAttrs[] = { + { CKA_ID, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_EXTRACTABLE, NULL, 0 }, + { CKA_MODULUS, NULL, 0 }, + }; + CK_ULONG getOriginalAttrsCnt = sizeof(getOriginalAttrs) / + sizeof(*getOriginalAttrs); + + CK_ATTRIBUTE getCopiedAttrs[] = { + { CKA_ID, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_EXTRACTABLE, NULL, 0 }, + { CKA_MODULUS, NULL, 0 }, + }; + CK_ULONG getCopiedAttrsCnt = sizeof(getCopiedAttrs) / + sizeof(*getCopiedAttrs); + + /* Buffers for retrieved attributes */ + byte origId[32], copiedId[32]; + byte origLabel[64], copiedLabel[64]; + byte origModulus[512], copiedModulus[512]; + CK_BBOOL origExtractable, copiedExtractable; + + /* Generate RSA key pair */ + mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + ret = funcList->C_GenerateKeyPair(session, &mech, pubKeyTmpl, + pubKeyTmplCnt, privKeyTmpl, + privKeyTmplCnt, &pubKey, &privKey); + CHECK_CKR(ret, "Generate RSA key pair for copy test"); + + /* Test: Copy RSA private key */ + if (ret == CKR_OK) { + ret = funcList->C_CopyObject(session, privKey, copyTmpl, copyTmplCnt, + &copiedPrivKey); + CHECK_CKR(ret, "Copy RSA private key"); + } + + /* Verify that both keys exist and have expected attributes */ + if (ret == CKR_OK) { + /* Set up buffers for original key attributes */ + getOriginalAttrs[0].pValue = origId; + getOriginalAttrs[0].ulValueLen = sizeof(origId); + getOriginalAttrs[1].pValue = origLabel; + getOriginalAttrs[1].ulValueLen = sizeof(origLabel); + getOriginalAttrs[2].pValue = &origExtractable; + getOriginalAttrs[2].ulValueLen = sizeof(origExtractable); + getOriginalAttrs[3].pValue = origModulus; + getOriginalAttrs[3].ulValueLen = sizeof(origModulus); + + ret = funcList->C_GetAttributeValue(session, privKey, getOriginalAttrs, + getOriginalAttrsCnt); + CHECK_CKR(ret, "Get original RSA key attributes"); + } + + if (ret == CKR_OK) { + /* Set up buffers for copied key attributes */ + getCopiedAttrs[0].pValue = copiedId; + getCopiedAttrs[0].ulValueLen = sizeof(copiedId); + getCopiedAttrs[1].pValue = copiedLabel; + getCopiedAttrs[1].ulValueLen = sizeof(copiedLabel); + getCopiedAttrs[2].pValue = &copiedExtractable; + getCopiedAttrs[2].ulValueLen = sizeof(copiedExtractable); + getCopiedAttrs[3].pValue = copiedModulus; + getCopiedAttrs[3].ulValueLen = sizeof(copiedModulus); + + ret = funcList->C_GetAttributeValue(session, copiedPrivKey, + getCopiedAttrs, getCopiedAttrsCnt); + CHECK_CKR(ret, "Get copied RSA key attributes"); + } + + /* Verify that ID and EXTRACTABLE match, but LABEL is different */ + if (ret == CKR_OK) { + if (getOriginalAttrs[0].ulValueLen != getCopiedAttrs[0].ulValueLen || + XMEMCMP(origId, copiedId, + getOriginalAttrs[0].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied RSA key ID should match original"); + } + } + + if (ret == CKR_OK) { + if (origExtractable != copiedExtractable) { + ret = -1; + CHECK_CKR(ret, "Copied RSA key EXTRACTABLE should match original"); + } + } + + if (ret == CKR_OK) { + /* Verify LABEL is different (modified) */ + if (getCopiedAttrs[1].ulValueLen != sizeof(modifiedLabel)-1 || + XMEMCMP(copiedLabel, modifiedLabel, + sizeof(modifiedLabel)-1) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied RSA key LABEL should be modified"); + } + } + + if (ret == CKR_OK) { + /* Verify MODULUS matches (deep copy of RSA key structure) */ + if (getOriginalAttrs[3].ulValueLen != getCopiedAttrs[3].ulValueLen || + XMEMCMP(origModulus, copiedModulus, + getOriginalAttrs[3].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied RSA key MODULUS should match original"); + } + } + + /* Test that both keys can be used for signing (verifying key structure + * is intact) */ + if (ret == CKR_OK) { + CK_MECHANISM signMech; + CK_BYTE data[] = "test data for signing"; + CK_BYTE signature1[512], signature2[512]; + CK_ULONG sigLen1 = sizeof(signature1); + CK_ULONG sigLen2 = sizeof(signature2); + + signMech.mechanism = CKM_RSA_PKCS; + signMech.pParameter = NULL; + signMech.ulParameterLen = 0; + + /* Sign with original key */ + ret = funcList->C_SignInit(session, &signMech, privKey); + if (ret == CKR_OK) { + ret = funcList->C_Sign(session, data, sizeof(data)-1, signature1, + &sigLen1); + CHECK_CKR(ret, "Sign with original RSA key"); + } + + /* Sign with copied key */ + if (ret == CKR_OK) { + ret = funcList->C_SignInit(session, &signMech, copiedPrivKey); + if (ret == CKR_OK) { + ret = funcList->C_Sign(session, data, sizeof(data)-1, + signature2, &sigLen2); + CHECK_CKR(ret, "Sign with copied RSA key"); + } + } + + /* Both signatures should be valid (though potentially different due + * to PKCS#1 v1.5 padding) */ + if (ret == CKR_OK) { + /* Verify signature1 with public key */ + ret = funcList->C_VerifyInit(session, &signMech, pubKey); + if (ret == CKR_OK) { + ret = funcList->C_Verify(session, data, sizeof(data)-1, + signature1, sigLen1); + CHECK_CKR(ret, "Verify signature from original RSA key"); + } + } + + if (ret == CKR_OK) { + /* Verify signature2 with public key */ + ret = funcList->C_VerifyInit(session, &signMech, pubKey); + if (ret == CKR_OK) { + ret = funcList->C_Verify(session, data, sizeof(data)-1, + signature2, sigLen2); + CHECK_CKR(ret, "Verify signature from copied RSA key"); + } + } + } + + /* Clean up */ + if (pubKey != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, pubKey); + } + if (privKey != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, privKey); + } + if (copiedPrivKey != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, copiedPrivKey); + } + + return ret; +} +#endif /* !NO_RSA */ + #if ((defined(WOLFPKCS11_NSS)) && ((WP11_SESSION_CNT_MAX != 1) || \ (WP11_SESSION_CNT_MIN != 1))) static CK_RV test_cross_session_object(void* args) @@ -13739,6 +14234,10 @@ static TEST_FUNC testFunc[] = { #endif PKCS11TEST_FUNC_SESS_DECL(test_op_state_fail), PKCS11TEST_FUNC_SESS_DECL(test_object), + PKCS11TEST_FUNC_SESS_DECL(test_copy_object_deep_copy), +#if (!defined(NO_RSA) && !defined(WOLFPKCS11_TPM)) + PKCS11TEST_FUNC_SESS_DECL(test_copy_object_rsa_key), +#endif #if ((defined(WOLFPKCS11_NSS)) && ((WP11_SESSION_CNT_MAX != 1) || \ (WP11_SESSION_CNT_MIN != 1))) PKCS11TEST_FUNC_SESS_DECL(test_cross_session_object), From ff676277413b027e863ecf8f1c880b4af2ded12d Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Tue, 8 Jul 2025 15:05:58 +0100 Subject: [PATCH 08/50] Add ECC support to `C_CopyObject` --- src/internal.c | 77 ++++++++++- tests/pkcs11test.c | 334 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 409 insertions(+), 2 deletions(-) diff --git a/src/internal.c b/src/internal.c index eba932bc..26dc59d6 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2246,8 +2246,81 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) } #endif #ifdef HAVE_ECC - case CKK_EC: - return BAD_FUNC_ARG; + case CKK_EC: { + byte* derBuf = NULL; + int derSz = 0; + + /* Initialize destination ECC key */ + ret = wc_ecc_init_ex(&dest->data.ecKey, NULL, + dest->slot->devId); + if (ret != 0) + break; + + /* Determine if this is a private or public key and get DER + * size */ + if (src->objClass == CKO_PRIVATE_KEY) { + ret = wc_EccPrivateKeyToDer(&src->data.ecKey, NULL, 0); + } else { + ret = wc_EccPublicKeyToDer(&src->data.ecKey, NULL, 0, 1); + } + + if (ret == 0) /* Should not happen */ + ret = BUFFER_E; + if (ret > 0) { + derSz = ret; + ret = 0; + } + + if (ret == 0) { + derBuf = (byte*)XMALLOC(derSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) + ret = MEMORY_E; + } + + if (ret == 0) { + /* Encode the source key to DER */ + if (src->objClass == CKO_PRIVATE_KEY) { + ret = wc_EccPrivateKeyToDer(&src->data.ecKey, derBuf, + derSz); + } else { + ret = wc_EccPublicKeyToDer(&src->data.ecKey, derBuf, + derSz, 1); + } + + if (ret == 0) /* Should not happen */ + ret = BUFFER_E; + if (ret > 0) + ret = 0; + } + + if (ret == 0) { + /* Decode the DER data into the destination key */ + word32 idx = 0; + if (src->objClass == CKO_PRIVATE_KEY) { + ret = wc_EccPrivateKeyDecode(derBuf, &idx, + &dest->data.ecKey, + (word32)derSz); + } else { + ret = wc_EccPublicKeyDecode(derBuf, &idx, + &dest->data.ecKey, + (word32)derSz); + } + } + + /* Clean up */ + if (derBuf != NULL) { + XMEMSET(derBuf, 0, derSz); /* Clear sensitive data */ + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + + /* Free destination key on failure */ + if (ret != 0) { + wc_ecc_free(&dest->data.ecKey); + } + + break; + } #endif #ifndef NO_DH case CKK_DH: diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index 40eab0f1..ebb9ef1a 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -2169,6 +2169,337 @@ static CK_RV test_copy_object_rsa_key(void* args) } #endif /* !NO_RSA */ +#ifdef HAVE_ECC +static CK_RV test_copy_object_ecc_key(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret = CKR_OK; + CK_OBJECT_HANDLE pubKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE privKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE copiedPrivKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE copiedPubKey = CK_INVALID_HANDLE; + CK_MECHANISM mech; + static byte keyId[] = { 0xEE, 0xCC, 0xAA, 0xBB }; + static byte label[] = "ecc-test-key"; + static byte modifiedLabel[] = "ecc-copied-key"; + + /* ECC key generation template */ + CK_ATTRIBUTE pubKeyTmpl[] = { + { CKA_EC_PARAMS, ecc_p256_params, + sizeof(ecc_p256_params) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, + { CKA_ID, keyId, sizeof(keyId) }, + { CKA_LABEL, label, sizeof(label)-1 }, + }; + CK_ULONG pubKeyTmplCnt = sizeof(pubKeyTmpl) / sizeof(*pubKeyTmpl); + + CK_ATTRIBUTE privKeyTmpl[] = { + { CKA_EC_PARAMS, ecc_p256_params, + sizeof(ecc_p256_params) }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_ID, keyId, sizeof(keyId) }, + { CKA_LABEL, label, sizeof(label)-1 }, + }; + CK_ULONG privKeyTmplCnt = sizeof(privKeyTmpl) / sizeof(*privKeyTmpl); + + /* Template for copying with modifications */ + CK_ATTRIBUTE copyTmpl[] = { + { CKA_LABEL, modifiedLabel, + sizeof(modifiedLabel)-1 }, + }; + CK_ULONG copyTmplCnt = sizeof(copyTmpl) / sizeof(*copyTmpl); + + /* Templates for attribute verification */ + CK_ATTRIBUTE getOriginalPrivAttrs[] = { + { CKA_ID, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_EXTRACTABLE, NULL, 0 }, + { CKA_EC_PARAMS, NULL, 0 }, + }; + CK_ULONG getOriginalPrivAttrsCnt = sizeof(getOriginalPrivAttrs) / + sizeof(*getOriginalPrivAttrs); + + CK_ATTRIBUTE getCopiedPrivAttrs[] = { + { CKA_ID, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_EXTRACTABLE, NULL, 0 }, + { CKA_EC_PARAMS, NULL, 0 }, + }; + CK_ULONG getCopiedPrivAttrsCnt = sizeof(getCopiedPrivAttrs) / + sizeof(*getCopiedPrivAttrs); + + CK_ATTRIBUTE getOriginalPubAttrs[] = { + { CKA_ID, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_EC_PARAMS, NULL, 0 }, + { CKA_EC_POINT, NULL, 0 }, + }; + CK_ULONG getOriginalPubAttrsCnt = sizeof(getOriginalPubAttrs) / + sizeof(*getOriginalPubAttrs); + + CK_ATTRIBUTE getCopiedPubAttrs[] = { + { CKA_ID, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_EC_PARAMS, NULL, 0 }, + { CKA_EC_POINT, NULL, 0 }, + }; + CK_ULONG getCopiedPubAttrsCnt = sizeof(getCopiedPubAttrs) / + sizeof(*getCopiedPubAttrs); + + /* Buffers for retrieved attributes */ + byte origPrivId[32], copiedPrivId[32]; + byte origPrivLabel[64], copiedPrivLabel[64]; + byte origPrivParams[32], copiedPrivParams[32]; + byte origPubId[32], copiedPubId[32]; + byte origPubLabel[64], copiedPubLabel[64]; + byte origPubParams[32], copiedPubParams[32]; + byte origPubPoint[128], copiedPubPoint[128]; + CK_BBOOL origPrivExtractable, copiedPrivExtractable; + + /* Generate ECC key pair */ + mech.mechanism = CKM_EC_KEY_PAIR_GEN; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + ret = funcList->C_GenerateKeyPair(session, &mech, pubKeyTmpl, + pubKeyTmplCnt, privKeyTmpl, + privKeyTmplCnt, &pubKey, &privKey); + CHECK_CKR(ret, "Generate ECC key pair for copy test"); + + /* Test: Copy ECC private key */ + if (ret == CKR_OK) { + ret = funcList->C_CopyObject(session, privKey, copyTmpl, copyTmplCnt, + &copiedPrivKey); + CHECK_CKR(ret, "Copy ECC private key"); + } + + /* Test: Copy ECC public key */ + if (ret == CKR_OK) { + ret = funcList->C_CopyObject(session, pubKey, copyTmpl, copyTmplCnt, + &copiedPubKey); + CHECK_CKR(ret, "Copy ECC public key"); + } + + /* Verify that both private keys exist and have expected attributes */ + if (ret == CKR_OK) { + /* Set up buffers for original private key attributes */ + getOriginalPrivAttrs[0].pValue = origPrivId; + getOriginalPrivAttrs[0].ulValueLen = sizeof(origPrivId); + getOriginalPrivAttrs[1].pValue = origPrivLabel; + getOriginalPrivAttrs[1].ulValueLen = sizeof(origPrivLabel); + getOriginalPrivAttrs[2].pValue = &origPrivExtractable; + getOriginalPrivAttrs[2].ulValueLen = sizeof(origPrivExtractable); + getOriginalPrivAttrs[3].pValue = origPrivParams; + getOriginalPrivAttrs[3].ulValueLen = sizeof(origPrivParams); + + ret = funcList->C_GetAttributeValue(session, privKey, + getOriginalPrivAttrs, + getOriginalPrivAttrsCnt); + CHECK_CKR(ret, "Get original ECC private key attributes"); + } + + if (ret == CKR_OK) { + /* Set up buffers for copied private key attributes */ + getCopiedPrivAttrs[0].pValue = copiedPrivId; + getCopiedPrivAttrs[0].ulValueLen = sizeof(copiedPrivId); + getCopiedPrivAttrs[1].pValue = copiedPrivLabel; + getCopiedPrivAttrs[1].ulValueLen = sizeof(copiedPrivLabel); + getCopiedPrivAttrs[2].pValue = &copiedPrivExtractable; + getCopiedPrivAttrs[2].ulValueLen = sizeof(copiedPrivExtractable); + getCopiedPrivAttrs[3].pValue = copiedPrivParams; + getCopiedPrivAttrs[3].ulValueLen = sizeof(copiedPrivParams); + + ret = funcList->C_GetAttributeValue(session, copiedPrivKey, + getCopiedPrivAttrs, + getCopiedPrivAttrsCnt); + CHECK_CKR(ret, "Get copied ECC private key attributes"); + } + + /* Verify private key attributes */ + if (ret == CKR_OK) { + if (getOriginalPrivAttrs[0].ulValueLen != + getCopiedPrivAttrs[0].ulValueLen || + XMEMCMP(origPrivId, copiedPrivId, + getOriginalPrivAttrs[0].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied ECC private key ID should match original"); + } + } + + if (ret == CKR_OK) { + if (origPrivExtractable != copiedPrivExtractable) { + ret = -1; + CHECK_CKR(ret, + "Copied ECC private key EXTRACTABLE should match original"); + } + } + + if (ret == CKR_OK) { + /* Verify LABEL is different (modified) */ + if (getCopiedPrivAttrs[1].ulValueLen != sizeof(modifiedLabel)-1 || + XMEMCMP(copiedPrivLabel, modifiedLabel, + sizeof(modifiedLabel)-1) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied ECC private key LABEL should be modified"); + } + } + + if (ret == CKR_OK) { + /* Verify EC_PARAMS matches */ + if (getOriginalPrivAttrs[3].ulValueLen != + getCopiedPrivAttrs[3].ulValueLen || + XMEMCMP(origPrivParams, copiedPrivParams, + getOriginalPrivAttrs[3].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, + "Copied ECC private key EC_PARAMS should match original"); + } + } + + /* Verify that both public keys exist and have expected attributes */ + if (ret == CKR_OK) { + /* Set up buffers for original public key attributes */ + getOriginalPubAttrs[0].pValue = origPubId; + getOriginalPubAttrs[0].ulValueLen = sizeof(origPubId); + getOriginalPubAttrs[1].pValue = origPubLabel; + getOriginalPubAttrs[1].ulValueLen = sizeof(origPubLabel); + getOriginalPubAttrs[2].pValue = origPubParams; + getOriginalPubAttrs[2].ulValueLen = sizeof(origPubParams); + getOriginalPubAttrs[3].pValue = origPubPoint; + getOriginalPubAttrs[3].ulValueLen = sizeof(origPubPoint); + + ret = funcList->C_GetAttributeValue(session, pubKey, + getOriginalPubAttrs, + getOriginalPubAttrsCnt); + CHECK_CKR(ret, "Get original ECC public key attributes"); + } + + if (ret == CKR_OK) { + /* Set up buffers for copied public key attributes */ + getCopiedPubAttrs[0].pValue = copiedPubId; + getCopiedPubAttrs[0].ulValueLen = sizeof(copiedPubId); + getCopiedPubAttrs[1].pValue = copiedPubLabel; + getCopiedPubAttrs[1].ulValueLen = sizeof(copiedPubLabel); + getCopiedPubAttrs[2].pValue = copiedPubParams; + getCopiedPubAttrs[2].ulValueLen = sizeof(copiedPubParams); + getCopiedPubAttrs[3].pValue = copiedPubPoint; + getCopiedPubAttrs[3].ulValueLen = sizeof(copiedPubPoint); + + ret = funcList->C_GetAttributeValue(session, copiedPubKey, + getCopiedPubAttrs, + getCopiedPubAttrsCnt); + CHECK_CKR(ret, "Get copied ECC public key attributes"); + } + + /* Verify public key attributes */ + if (ret == CKR_OK) { + if (getOriginalPubAttrs[0].ulValueLen != + getCopiedPubAttrs[0].ulValueLen || + XMEMCMP(origPubId, copiedPubId, + getOriginalPubAttrs[0].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied ECC public key ID should match original"); + } + } + + if (ret == CKR_OK) { + /* Verify public key LABEL is different (modified) */ + if (getCopiedPubAttrs[1].ulValueLen != sizeof(modifiedLabel)-1 || + XMEMCMP(copiedPubLabel, modifiedLabel, + sizeof(modifiedLabel)-1) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied ECC public key LABEL should be modified"); + } + } + + if (ret == CKR_OK) { + /* Verify EC_POINT matches (deep copy of ECC key structure) */ + if (getOriginalPubAttrs[3].ulValueLen != + getCopiedPubAttrs[3].ulValueLen || + XMEMCMP(origPubPoint, copiedPubPoint, + getOriginalPubAttrs[3].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, + "Copied ECC public key EC_POINT should match original"); + } + } + + /* Test that both private keys can be used for signing (verifying key + * structure is intact) */ + if (ret == CKR_OK) { + CK_MECHANISM signMech; + CK_BYTE data[] = "test data for ECC signing"; + CK_BYTE signature1[128], signature2[128]; + CK_ULONG sigLen1 = sizeof(signature1); + CK_ULONG sigLen2 = sizeof(signature2); + + signMech.mechanism = CKM_ECDSA; + signMech.pParameter = NULL; + signMech.ulParameterLen = 0; + + /* Sign with original private key */ + ret = funcList->C_SignInit(session, &signMech, privKey); + if (ret == CKR_OK) { + ret = funcList->C_Sign(session, data, sizeof(data)-1, + signature1, &sigLen1); + CHECK_CKR(ret, "Sign with original ECC private key"); + } + + /* Sign with copied private key */ + if (ret == CKR_OK) { + ret = funcList->C_SignInit(session, &signMech, copiedPrivKey); + if (ret == CKR_OK) { + ret = funcList->C_Sign(session, data, sizeof(data)-1, + signature2, &sigLen2); + CHECK_CKR(ret, "Sign with copied ECC private key"); + } + } + + /* Both signatures should be valid */ + if (ret == CKR_OK) { + /* Verify signature1 with original public key */ + ret = funcList->C_VerifyInit(session, &signMech, pubKey); + if (ret == CKR_OK) { + ret = funcList->C_Verify(session, data, sizeof(data)-1, + signature1, sigLen1); + CHECK_CKR(ret, "Verify signature from original ECC key"); + } + } + + if (ret == CKR_OK) { + /* Verify signature2 with copied public key */ + ret = funcList->C_VerifyInit(session, &signMech, copiedPubKey); + if (ret == CKR_OK) { + ret = funcList->C_Verify(session, data, sizeof(data)-1, + signature2, sigLen2); + CHECK_CKR(ret, "Verify signature from copied ECC key"); + } + } + } + + /* Clean up */ + if (pubKey != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, pubKey); + } + if (privKey != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, privKey); + } + if (copiedPrivKey != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, copiedPrivKey); + } + if (copiedPubKey != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, copiedPubKey); + } + + return ret; +} +#endif /* HAVE_ECC */ + #if ((defined(WOLFPKCS11_NSS)) && ((WP11_SESSION_CNT_MAX != 1) || \ (WP11_SESSION_CNT_MIN != 1))) static CK_RV test_cross_session_object(void* args) @@ -14238,6 +14569,9 @@ static TEST_FUNC testFunc[] = { #if (!defined(NO_RSA) && !defined(WOLFPKCS11_TPM)) PKCS11TEST_FUNC_SESS_DECL(test_copy_object_rsa_key), #endif +#ifdef HAVE_ECC + PKCS11TEST_FUNC_SESS_DECL(test_copy_object_ecc_key), +#endif #if ((defined(WOLFPKCS11_NSS)) && ((WP11_SESSION_CNT_MAX != 1) || \ (WP11_SESSION_CNT_MIN != 1))) PKCS11TEST_FUNC_SESS_DECL(test_cross_session_object), From 20a36652c2d650a30f851aa35d5b5f38e8347532 Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Tue, 8 Jul 2025 18:20:45 +0100 Subject: [PATCH 09/50] Add support for CKO_DATA --- src/crypto.c | 18 ++- src/internal.c | 144 +++++++++++++++++++++--- tests/pkcs11test.c | 248 +++++++++++++++++++++++++++++++++++++++--- wolfpkcs11/internal.h | 2 + wolfpkcs11/store.h | 1 + 5 files changed, 380 insertions(+), 33 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 5573caac..0395eecc 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -103,9 +103,19 @@ static CK_ATTRIBUTE_TYPE secretKeyParams[] = { CKA_VALUE_LEN, CKA_VALUE, }; + /* Count of secret key data attributes. */ #define SECRET_KEY_PARAMS_CNT (sizeof(secretKeyParams)/sizeof(*secretKeyParams)) +/* Generic data attributes */ +static CK_ATTRIBUTE_TYPE genericDataParams[] = { + CKA_VALUE_LEN, + CKA_VALUE, +}; + +/* Count of generic data attributes */ +#define DATA_PARAMS_CNT (sizeof(genericDataParams)/sizeof(*genericDataParams)) + /* Certificate data attributes */ static CK_ATTRIBUTE_TYPE certParams[] = { CKA_CERTIFICATE_TYPE, @@ -548,6 +558,10 @@ static CK_RV SetAttributeValue(WP11_Session* session, WP11_Object* obj, cnt = TRUST_PARAMS_CNT; } #endif + else if (objClass == CKO_DATA) { + attrs = genericDataParams; + cnt = DATA_PARAMS_CNT; + } else { /* Get the value and length of key specific attribute types. */ switch (type) { @@ -607,6 +621,9 @@ static CK_RV SetAttributeValue(WP11_Session* session, WP11_Object* obj, ret = WP11_Object_SetTrust(obj, data, len); } #endif + else if (objClass == CKO_DATA) { + ret = WP11_Object_DataObject(obj, data, len); + } else { /* Set the value and length of key specific attributes * Old key data is cleared. @@ -952,7 +969,6 @@ static CK_RV CreateObject(WP11_Session* session, CK_ATTRIBUTE_PTR pTemplate, FindAttributeType(pTemplate, ulCount, CKA_VALUE, &attr); if (attr == NULL) return CKR_TEMPLATE_INCOMPLETE; - objType = CKK_HKDF; } #ifdef WOLFPKCS11_NSS else if (objectClass == CKO_NSS_TRUST) { diff --git a/src/internal.c b/src/internal.c index 26dc59d6..e6686148 100644 --- a/src/internal.c +++ b/src/internal.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#include "wolfpkcs11/pkcs11.h" #ifdef HAVE_CONFIG_H #include #endif @@ -227,6 +228,7 @@ struct WP11_Object { WP11_DhKey* dhKey; /* DH parameters object */ #endif WP11_Data* symmKey; /* Symmetric key object */ + WP11_Data* genericData; /* Generic data object */ WP11_Cert cert; /* Certificate object */ #ifdef WOLFPKCS11_NSS WP11_Trust trust; /* Trust object */ @@ -910,6 +912,7 @@ static int wolfPKCS11_Store_GetMaxSize(int type, int variableSz) case WOLFPKCS11_STORE_DHKEY_PUB: case WOLFPKCS11_STORE_CERT: case WOLFPKCS11_STORE_TRUST: + case WOLFPKCS11_STOR_DATA: maxSz = sizeof(word32) + variableSz; break; @@ -2251,59 +2254,59 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) int derSz = 0; /* Initialize destination ECC key */ - ret = wc_ecc_init_ex(&dest->data.ecKey, NULL, + ret = wc_ecc_init_ex(&dest->data.ecKey, NULL, dest->slot->devId); if (ret != 0) break; - /* Determine if this is a private or public key and get DER + /* Determine if this is a private or public key and get DER * size */ if (src->objClass == CKO_PRIVATE_KEY) { ret = wc_EccPrivateKeyToDer(&src->data.ecKey, NULL, 0); } else { ret = wc_EccPublicKeyToDer(&src->data.ecKey, NULL, 0, 1); } - + if (ret == 0) /* Should not happen */ ret = BUFFER_E; if (ret > 0) { derSz = ret; ret = 0; } - + if (ret == 0) { - derBuf = (byte*)XMALLOC(derSz, NULL, + derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (derBuf == NULL) ret = MEMORY_E; } - + if (ret == 0) { /* Encode the source key to DER */ if (src->objClass == CKO_PRIVATE_KEY) { - ret = wc_EccPrivateKeyToDer(&src->data.ecKey, derBuf, + ret = wc_EccPrivateKeyToDer(&src->data.ecKey, derBuf, derSz); } else { - ret = wc_EccPublicKeyToDer(&src->data.ecKey, derBuf, + ret = wc_EccPublicKeyToDer(&src->data.ecKey, derBuf, derSz, 1); } - + if (ret == 0) /* Should not happen */ ret = BUFFER_E; if (ret > 0) ret = 0; } - + if (ret == 0) { /* Decode the DER data into the destination key */ word32 idx = 0; if (src->objClass == CKO_PRIVATE_KEY) { - ret = wc_EccPrivateKeyDecode(derBuf, &idx, - &dest->data.ecKey, + ret = wc_EccPrivateKeyDecode(derBuf, &idx, + &dest->data.ecKey, (word32)derSz); } else { - ret = wc_EccPublicKeyDecode(derBuf, &idx, - &dest->data.ecKey, + ret = wc_EccPublicKeyDecode(derBuf, &idx, + &dest->data.ecKey, (word32)derSz); } } @@ -2313,12 +2316,12 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) XMEMSET(derBuf, 0, derSz); /* Clear sensitive data */ XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); } - + /* Free destination key on failure */ if (ret != 0) { wc_ecc_free(&dest->data.ecKey); } - + break; } #endif @@ -2443,6 +2446,13 @@ static void wp11_Object_Decode_Trust(WP11_Object* object) } #endif +static void wp11_Object_Decode_Data(WP11_Object* object) +{ + XMEMCPY((unsigned char*)&object->data.genericData, object->keyData, + object->keyDataLen); + object->encoded = 0; +} + /** * Load a certificate from storage. * @@ -2506,6 +2516,24 @@ static int wp11_Object_Load_Trust(WP11_Object* object, int tokenId, int objId) } #endif +static int wp11_Object_Load_Data(WP11_Object* object, int tokenId, int objId) +{ + int ret; + void* storage = NULL; + + /* Open access to data. */ + ret = wp11_storage_open_readonly(WOLFPKCS11_STORE_DATA, tokenId, objId, + &storage); + if (ret == 0) { + /* Read data. */ + ret = wp11_storage_read_alloc_array(storage, &object->keyData, + &object->keyDataLen); + wp11_storage_close(storage); + wp11_Object_Decode_Data(object); + } + + return ret; +} #ifdef WOLFSSL_MAXQ10XX_CRYPTO #ifdef MAXQ10XX_PRODUCTION_KEY @@ -2984,6 +3012,24 @@ static int WP11_Object_EncodeTpmKey(WP11_Object* object, byte* keyData, #endif /* WOLFPKCS11_TPM */ +static int wp11_Object_Store_Data(WP11_Object* object, int tokenId, int objId) +{ + int ret; + void* storage = NULL; + + /* Open access to data. */ + ret = wp11_storage_open(WOLFPKCS11_STORE_DATA, tokenId, objId, + sizeof(WP11_Data), &storage); + if (ret == 0) { + /* Write data to storage. */ + ret = wp11_storage_write_array(storage, + (unsigned char*)&object->data.genericData, sizeof(WP11_Data)); + wp11_storage_close(storage); + } + + return ret; +} + #ifndef NO_RSA /** * Decode the RSA key. @@ -4144,6 +4190,9 @@ static int wp11_Object_Load(WP11_Object* object, int tokenId, int objId) ret = wp11_Object_Load_Trust(object, tokenId, objId); } #endif + else if (object->objClass == CKO_DATA) { + ret = wp11_Object_Load_Data(object, tokenId, objId); + } else { /* Load separate key data. */ switch (object->type) { @@ -4301,6 +4350,9 @@ static int wp11_Object_Store(WP11_Object* object, int tokenId, int objId) ret = wp11_Object_Store_Trust(object, tokenId, objId); } #endif + else if (object->objClass == CKO_DATA) { + ret = wp11_Object_Store_Data(object, tokenId, objId); + } else { /* Store key data separately. */ switch (object->type) { @@ -4358,6 +4410,10 @@ static int wp11_Object_Decode(WP11_Object* object) ret = 0; } #endif + else if (object->objClass == CKO_DATA) { + wp11_Object_Decode_Data(object); + ret = 0; + } else { switch (object->type) { #ifndef NO_RSA @@ -4412,6 +4468,9 @@ static int wp11_Object_Encode(WP11_Object* object, int protect) if (object->objClass == CKO_CERTIFICATE) #endif ret = 0; + else if (object->objClass == CKO_DATA) { + ret = 0; + } else { switch (object->type) { #ifndef NO_RSA @@ -4492,6 +4551,9 @@ static int wp11_Object_Unstore(WP11_Object* object, int tokenId, int objId) storeObjType = WOLFPKCS11_STORE_TRUST; } #endif + else if (object->objClass == CKO_DATA) { + storeObjType = WOLFPKCS11_STORE_DATA; + } else { /* Open access to symmetric key. */ switch (object->type) { @@ -7541,6 +7603,28 @@ int WP11_Object_SetTrust(WP11_Object* object, unsigned char** data, } #endif +int WP11_Object_DataObject(WP11_Object* object, unsigned char** data, + CK_ULONG* len) +{ + int ret = 0; + + if (object->onToken) + WP11_Lock_LockRW(object->lock); + + if (data[1] == NULL || len[1] == 0 || len[1] > WP11_MAX_SYM_KEY_SZ) + ret = BAD_FUNC_ARG; + else if (data[1] != NULL) { + XMEMCPY(object->data.genericData.data, data[1], len[1]); + object->data.genericData.len = len[1]; + } + + + if (object->onToken) + WP11_Lock_UnlockRW(object->lock); + + return ret; +} + int WP11_Object_SetCert(WP11_Object* object, unsigned char** data, CK_ULONG* len) { @@ -7827,6 +7911,27 @@ static int GetCertAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, return ret; } +static int GetDataAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, + byte* data, CK_ULONG* len) +{ + int ret = 0; + + if (object == NULL || len == NULL) + return BAD_FUNC_ARG; + + switch (type) { + case CKA_VALUE: + ret = GetData((byte*)object->data.genericData.data, + object->data.genericData.len, data, len); + break; + default: + ret = NOT_AVAILABLE_E; + break; + } + + return ret; +} + #ifdef WOLFPKCS11_NSS static int GetTrustAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, CK_ULONG* len) @@ -8468,6 +8573,10 @@ int WP11_Object_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, break; } #endif + else if (object->objClass == CKO_DATA) { + ret = GetDataAttr(object, type, data, len); + break; + } else { switch (object->type) { #ifndef NO_RSA @@ -8779,6 +8888,9 @@ int WP11_Object_SetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, if (object->objClass == CKO_CERTIFICATE) { break; /* Handled in WP11_Object_SetCert */ } + else if (object->objClass == CKO_DATA) { + break; /* Handled in WP11_Object_SetDataObject */ + } switch (object->type) { #ifdef HAVE_ECC case CKK_EC: diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index ebb9ef1a..316aed04 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -87,6 +87,7 @@ static CK_OBJECT_CLASS pubKeyClass = CKO_PUBLIC_KEY; static CK_OBJECT_CLASS privKeyClass = CKO_PRIVATE_KEY; static CK_OBJECT_CLASS secretKeyClass = CKO_SECRET_KEY; static CK_OBJECT_CLASS certificateClass = CKO_CERTIFICATE; +static CK_OBJECT_CLASS dataClass = CKO_DATA; #if defined(HAVE_ECC) || !defined(NO_DH) static CK_BBOOL ckFalse = CK_FALSE; @@ -2185,7 +2186,7 @@ static CK_RV test_copy_object_ecc_key(void* args) /* ECC key generation template */ CK_ATTRIBUTE pubKeyTmpl[] = { - { CKA_EC_PARAMS, ecc_p256_params, + { CKA_EC_PARAMS, ecc_p256_params, sizeof(ecc_p256_params) }, { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, @@ -2195,7 +2196,7 @@ static CK_RV test_copy_object_ecc_key(void* args) CK_ULONG pubKeyTmplCnt = sizeof(pubKeyTmpl) / sizeof(*pubKeyTmpl); CK_ATTRIBUTE privKeyTmpl[] = { - { CKA_EC_PARAMS, ecc_p256_params, + { CKA_EC_PARAMS, ecc_p256_params, sizeof(ecc_p256_params) }, { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, @@ -2209,7 +2210,7 @@ static CK_RV test_copy_object_ecc_key(void* args) /* Template for copying with modifications */ CK_ATTRIBUTE copyTmpl[] = { - { CKA_LABEL, modifiedLabel, + { CKA_LABEL, modifiedLabel, sizeof(modifiedLabel)-1 }, }; CK_ULONG copyTmplCnt = sizeof(copyTmpl) / sizeof(*copyTmpl); @@ -2297,7 +2298,7 @@ static CK_RV test_copy_object_ecc_key(void* args) getOriginalPrivAttrs[3].pValue = origPrivParams; getOriginalPrivAttrs[3].ulValueLen = sizeof(origPrivParams); - ret = funcList->C_GetAttributeValue(session, privKey, + ret = funcList->C_GetAttributeValue(session, privKey, getOriginalPrivAttrs, getOriginalPrivAttrsCnt); CHECK_CKR(ret, "Get original ECC private key attributes"); @@ -2315,14 +2316,14 @@ static CK_RV test_copy_object_ecc_key(void* args) getCopiedPrivAttrs[3].ulValueLen = sizeof(copiedPrivParams); ret = funcList->C_GetAttributeValue(session, copiedPrivKey, - getCopiedPrivAttrs, + getCopiedPrivAttrs, getCopiedPrivAttrsCnt); CHECK_CKR(ret, "Get copied ECC private key attributes"); } /* Verify private key attributes */ if (ret == CKR_OK) { - if (getOriginalPrivAttrs[0].ulValueLen != + if (getOriginalPrivAttrs[0].ulValueLen != getCopiedPrivAttrs[0].ulValueLen || XMEMCMP(origPrivId, copiedPrivId, getOriginalPrivAttrs[0].ulValueLen) != 0) { @@ -2334,7 +2335,7 @@ static CK_RV test_copy_object_ecc_key(void* args) if (ret == CKR_OK) { if (origPrivExtractable != copiedPrivExtractable) { ret = -1; - CHECK_CKR(ret, + CHECK_CKR(ret, "Copied ECC private key EXTRACTABLE should match original"); } } @@ -2351,12 +2352,12 @@ static CK_RV test_copy_object_ecc_key(void* args) if (ret == CKR_OK) { /* Verify EC_PARAMS matches */ - if (getOriginalPrivAttrs[3].ulValueLen != + if (getOriginalPrivAttrs[3].ulValueLen != getCopiedPrivAttrs[3].ulValueLen || XMEMCMP(origPrivParams, copiedPrivParams, getOriginalPrivAttrs[3].ulValueLen) != 0) { ret = -1; - CHECK_CKR(ret, + CHECK_CKR(ret, "Copied ECC private key EC_PARAMS should match original"); } } @@ -2373,7 +2374,7 @@ static CK_RV test_copy_object_ecc_key(void* args) getOriginalPubAttrs[3].pValue = origPubPoint; getOriginalPubAttrs[3].ulValueLen = sizeof(origPubPoint); - ret = funcList->C_GetAttributeValue(session, pubKey, + ret = funcList->C_GetAttributeValue(session, pubKey, getOriginalPubAttrs, getOriginalPubAttrsCnt); CHECK_CKR(ret, "Get original ECC public key attributes"); @@ -2391,14 +2392,14 @@ static CK_RV test_copy_object_ecc_key(void* args) getCopiedPubAttrs[3].ulValueLen = sizeof(copiedPubPoint); ret = funcList->C_GetAttributeValue(session, copiedPubKey, - getCopiedPubAttrs, + getCopiedPubAttrs, getCopiedPubAttrsCnt); CHECK_CKR(ret, "Get copied ECC public key attributes"); } /* Verify public key attributes */ if (ret == CKR_OK) { - if (getOriginalPubAttrs[0].ulValueLen != + if (getOriginalPubAttrs[0].ulValueLen != getCopiedPubAttrs[0].ulValueLen || XMEMCMP(origPubId, copiedPubId, getOriginalPubAttrs[0].ulValueLen) != 0) { @@ -2419,17 +2420,17 @@ static CK_RV test_copy_object_ecc_key(void* args) if (ret == CKR_OK) { /* Verify EC_POINT matches (deep copy of ECC key structure) */ - if (getOriginalPubAttrs[3].ulValueLen != + if (getOriginalPubAttrs[3].ulValueLen != getCopiedPubAttrs[3].ulValueLen || XMEMCMP(origPubPoint, copiedPubPoint, getOriginalPubAttrs[3].ulValueLen) != 0) { ret = -1; - CHECK_CKR(ret, + CHECK_CKR(ret, "Copied ECC public key EC_POINT should match original"); } } - /* Test that both private keys can be used for signing (verifying key + /* Test that both private keys can be used for signing (verifying key * structure is intact) */ if (ret == CKR_OK) { CK_MECHANISM signMech; @@ -2445,7 +2446,7 @@ static CK_RV test_copy_object_ecc_key(void* args) /* Sign with original private key */ ret = funcList->C_SignInit(session, &signMech, privKey); if (ret == CKR_OK) { - ret = funcList->C_Sign(session, data, sizeof(data)-1, + ret = funcList->C_Sign(session, data, sizeof(data)-1, signature1, &sigLen1); CHECK_CKR(ret, "Sign with original ECC private key"); } @@ -3066,6 +3067,220 @@ static CK_RV test_attribute_get(void* args) return ret; } +static CK_RV test_data_object(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret = CKR_OK; + CK_OBJECT_HANDLE dataObj = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE dataObjToken = CK_INVALID_HANDLE; + + /* Sample data for the data object */ + static byte testData[] = { + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, + 0x72, 0x6C, 0x64, 0x21 /* "Hello World!" */ + }; + static byte testLabel[] = "TestDataObject"; + + /* Template for creating a session data object */ + CK_ATTRIBUTE dataTemplate[] = { + { CKA_CLASS, &dataClass, sizeof(dataClass) }, + { CKA_LABEL, testLabel, sizeof(testLabel) }, + { CKA_VALUE, testData, sizeof(testData) }, + { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_MODIFIABLE, &ckTrue, sizeof(ckTrue) } + }; + CK_ULONG dataTemplateCnt = sizeof(dataTemplate) / sizeof(*dataTemplate); + + /* Template for creating a token data object */ + CK_ATTRIBUTE tokenDataTemplate[] = { + { CKA_CLASS, &dataClass, sizeof(dataClass) }, + { CKA_LABEL, testLabel, sizeof(testLabel) }, + { CKA_VALUE, testData, sizeof(testData) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_MODIFIABLE, &ckTrue, sizeof(ckTrue) } + }; + CK_ULONG tokenDataTemplateCnt = sizeof(tokenDataTemplate) / + sizeof(*tokenDataTemplate); + + /* Templates for retrieving attributes */ + CK_ATTRIBUTE getTemplate[] = { + { CKA_CLASS, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_VALUE, NULL, 0 }, + { CKA_TOKEN, NULL, 0 }, + { CKA_PRIVATE, NULL, 0 }, + { CKA_MODIFIABLE, NULL, 0 } + }; + CK_ULONG getTemplateCnt = sizeof(getTemplate) / sizeof(*getTemplate); + + /* Buffers for retrieved attributes */ + CK_OBJECT_CLASS retClass; + byte retLabel[32]; + byte retValue[32]; + CK_BBOOL retToken; + CK_BBOOL retPrivate; + CK_BBOOL retModifiable; + + + + /* Test creating a session data object */ + ret = funcList->C_CreateObject(session, dataTemplate, dataTemplateCnt, + &dataObj); + CHECK_CKR(ret, "Create CKO_DATA session object"); + + /* Test creating a token data object */ + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, tokenDataTemplate, + tokenDataTemplateCnt, &dataObjToken); + CHECK_CKR(ret, "Create CKO_DATA token object"); + } + + /* Test C_GetAttributeValue - first get the lengths */ + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, dataObj, getTemplate, + getTemplateCnt); + CHECK_CKR(ret, "Get CKO_DATA attribute lengths"); + } + + /* Allocate buffers and set up pointers */ + if (ret == CKR_OK) { + getTemplate[0].pValue = &retClass; + getTemplate[0].ulValueLen = sizeof(retClass); + + getTemplate[1].pValue = retLabel; + getTemplate[1].ulValueLen = sizeof(retLabel); + + getTemplate[2].pValue = retValue; + getTemplate[2].ulValueLen = sizeof(retValue); + + getTemplate[3].pValue = &retToken; + getTemplate[3].ulValueLen = sizeof(retToken); + + getTemplate[4].pValue = &retPrivate; + getTemplate[4].ulValueLen = sizeof(retPrivate); + + getTemplate[5].pValue = &retModifiable; + getTemplate[5].ulValueLen = sizeof(retModifiable); + } + + /* Test C_GetAttributeValue - get the actual values */ + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, dataObj, getTemplate, + getTemplateCnt); + CHECK_CKR(ret, "Get CKO_DATA attribute values"); + } + + /* Verify the retrieved values match what we set */ + if (ret == CKR_OK) { + if (retClass != dataClass) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA class attribute verification"); + } + } + + if (ret == CKR_OK) { + if (XMEMCMP(retLabel, testLabel, sizeof(testLabel)) != 0) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA label attribute verification"); + } + } + + if (ret == CKR_OK) { + if (XMEMCMP(retValue, testData, sizeof(testData)) != 0) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA value attribute verification"); + } + } + + if (ret == CKR_OK) { + if (retToken != ckFalse) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA token attribute verification"); + } + } + + if (ret == CKR_OK) { + if (retPrivate != ckFalse) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA private attribute verification"); + } + } + + if (ret == CKR_OK) { + if (retModifiable != ckTrue) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA modifiable attribute verification"); + } + } + + /* Test getting individual attributes */ + if (ret == CKR_OK) { + CK_ATTRIBUTE singleAttr = { CKA_VALUE, retValue, sizeof(retValue) }; + XMEMSET(retValue, 0, sizeof(retValue)); + + ret = funcList->C_GetAttributeValue(session, dataObj, &singleAttr, + 1); + CHECK_CKR(ret, "Get single CKO_DATA attribute"); + + if (ret == CKR_OK) { + if (XMEMCMP(retValue, testData, sizeof(testData)) != 0) { + ret = -1; + CHECK_CKR(ret, "Single CKO_DATA value verification"); + } + } + } + + /* Test error cases */ + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(CK_INVALID_HANDLE, dataObj, + getTemplate, 1); + CHECK_CKR_FAIL(ret, CKR_SESSION_HANDLE_INVALID, + "Get attribute invalid session"); + } + + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, CK_INVALID_HANDLE, + getTemplate, 1); + CHECK_CKR_FAIL(ret, CKR_OBJECT_HANDLE_INVALID, + "Get attribute invalid object"); + } + + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, dataObj, NULL, 1); + CHECK_CKR_FAIL(ret, CKR_ARGUMENTS_BAD, + "Get attribute null template"); + } + + /* Test token data object attribute retrieval */ + if (ret == CKR_OK) { + CK_ATTRIBUTE tokenAttr = { CKA_TOKEN, &retToken, sizeof(retToken) }; + + ret = funcList->C_GetAttributeValue(session, dataObjToken, + &tokenAttr, 1); + CHECK_CKR(ret, "Get token CKO_DATA attribute"); + + if (ret == CKR_OK) { + if (retToken != ckTrue) { + ret = -1; + CHECK_CKR(ret, + "Token CKO_DATA token attribute verification"); + } + } + } + + /* Clean up */ + if (dataObj != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, dataObj); + } + if (dataObjToken != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, dataObjToken); + } + + return ret; +} + static CK_RV get_generic_key(CK_SESSION_HANDLE session, unsigned char* data, CK_ULONG len, CK_BBOOL extractable, CK_OBJECT_HANDLE* key) @@ -14579,6 +14794,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_data_object), PKCS11TEST_FUNC_SESS_DECL(test_attributes_secret), #ifndef NO_RSA PKCS11TEST_FUNC_SESS_DECL(test_attributes_rsa), diff --git a/wolfpkcs11/internal.h b/wolfpkcs11/internal.h index 616300b3..f6a10fc5 100644 --- a/wolfpkcs11/internal.h +++ b/wolfpkcs11/internal.h @@ -397,6 +397,8 @@ WP11_LOCAL int WP11_Object_SetSecretKey(WP11_Object* object, unsigned char** dat CK_ULONG* len); WP11_LOCAL int WP11_Object_SetCert(WP11_Object* object, unsigned char** data, CK_ULONG* len); +WP11_LOCAL int WP11_Object_DataObject(WP11_Object* object, unsigned char** data, + CK_ULONG* len); WP11_LOCAL int WP11_Object_SetClass(WP11_Object* object, CK_OBJECT_CLASS objClass); WP11_LOCAL CK_OBJECT_CLASS WP11_Object_GetClass(WP11_Object* object); diff --git a/wolfpkcs11/store.h b/wolfpkcs11/store.h index 3330a882..7ec48faa 100644 --- a/wolfpkcs11/store.h +++ b/wolfpkcs11/store.h @@ -35,6 +35,7 @@ #define WOLFPKCS11_STORE_DHKEY_PUB 0x08 #define WOLFPKCS11_STORE_CERT 0x09 #define WOLFPKCS11_STORE_TRUST 0x0A +#define WOLFPKCS11_STORE_DATA 0x0B /* * Opens access to location to read/write token data. From bbf8061d1f8466aba0ea55196936a2952c38f86c Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Tue, 8 Jul 2025 22:46:32 +0200 Subject: [PATCH 10/50] Check that the whole file path fits --- src/internal.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/internal.c b/src/internal.c index e6686148..0e1816fc 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1154,8 +1154,12 @@ int wolfPKCS11_Store_OpenSz(int type, CK_ULONG id1, CK_ULONG id2, int read, word32 nvAttributes; int maxSz; WOLFTPM2_HANDLE parent; +#else +#ifdef WOLFPKCS11_NSS + char name[600] = "\0"; #else char name[120] = "\0"; +#endif XFILE file = XBADFILE; #endif @@ -1231,6 +1235,12 @@ int wolfPKCS11_Store_OpenSz(int type, CK_ULONG id1, CK_ULONG id2, int read, /* build filename */ ret = wolfPKCS11_Store_Name(type, id1, id2, name, sizeof(name)); + /* Check that the string fits in name */ + if (ret > 0 && ret < (int) sizeof(name)) + ret = 0; + else + ret = -1; + /* Open file for read or write. */ if (ret == 0) { if (read) { From c989c84e85352893d7c256994ae7fa54ebefc416 Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Tue, 8 Jul 2025 18:29:55 +0100 Subject: [PATCH 11/50] Move debugging functions They were getting local API designations in `internal.c` which suddenly started breaking the build. --- src/internal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index 0e1816fc..734a2437 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7625,7 +7625,7 @@ int WP11_Object_DataObject(WP11_Object* object, unsigned char** data, ret = BAD_FUNC_ARG; else if (data[1] != NULL) { XMEMCPY(object->data.genericData.data, data[1], len[1]); - object->data.genericData.len = len[1]; + object->data.genericData.len = (word32)len[1]; } From 7124768ed9927a5e20f3e22b9b72b4137405f6b2 Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Wed, 9 Jul 2025 07:41:49 +0100 Subject: [PATCH 12/50] More support for CKO_DATA --- src/crypto.c | 11 +- src/internal.c | 218 +++++++++++++++++++++++++++++++++---- tests/pkcs11test.c | 262 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 467 insertions(+), 24 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 0395eecc..c450780d 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -109,8 +109,9 @@ static CK_ATTRIBUTE_TYPE secretKeyParams[] = { /* Generic data attributes */ static CK_ATTRIBUTE_TYPE genericDataParams[] = { - CKA_VALUE_LEN, CKA_VALUE, + CKA_APPLICATION, + CKA_OBJECT_ID }; /* Count of generic data attributes */ @@ -604,8 +605,11 @@ static CK_RV SetAttributeValue(WP11_Session* session, WP11_Object* obj, if (attrs[i] == pTemplate[j].type) { attrsFound = 1; data[i] = (unsigned char*)pTemplate[j].pValue; - if (data[i] == NULL) - return CKR_ATTRIBUTE_VALUE_INVALID; + if (data[i] == NULL) { + /* For CKO_DATA, values can be NULL */ + if (objClass != CKO_DATA) + return CKR_ATTRIBUTE_VALUE_INVALID; + } len[i] = (int)pTemplate[j].ulValueLen; break; } @@ -666,6 +670,7 @@ static CK_RV SetAttributeValue(WP11_Session* session, WP11_Object* obj, /* Set remaining attributes - key specific attributes ignored. */ for (i = 0; i < (int)ulCount; i++) { attr = &pTemplate[i]; + /* Cannot change sensitive from true to false */ if (attr->type == CKA_SENSITIVE) { rv = WP11_Object_GetAttr(obj, CKA_SENSITIVE, &getVar, &getVarLen); diff --git a/src/internal.c b/src/internal.c index 734a2437..cc8698da 100644 --- a/src/internal.c +++ b/src/internal.c @@ -190,6 +190,15 @@ typedef struct WP11_Data { word32 len; /* Length of key data in bytes */ } WP11_Data; +typedef struct WP11_GenericData { + byte *data; + word32 dataLen; + byte *application; + word32 applicationLen; + byte *objectId; /* CKA_OBJECT_ID, a DER encoded ID */ + word32 objectIdLen; +} WP11_GenericData; + /* Certificate */ typedef struct WP11_Cert { byte *data; /* Certificate data */ @@ -228,7 +237,7 @@ struct WP11_Object { WP11_DhKey* dhKey; /* DH parameters object */ #endif WP11_Data* symmKey; /* Symmetric key object */ - WP11_Data* genericData; /* Generic data object */ + WP11_GenericData genericData; /* Generic data object */ WP11_Cert cert; /* Certificate object */ #ifdef WOLFPKCS11_NSS WP11_Trust trust; /* Trust object */ @@ -2458,8 +2467,8 @@ static void wp11_Object_Decode_Trust(WP11_Object* object) static void wp11_Object_Decode_Data(WP11_Object* object) { - XMEMCPY((unsigned char*)&object->data.genericData, object->keyData, - object->keyDataLen); + /* No longer needed since wp11_Object_Load_Data handles + * deserialization directly */ object->encoded = 0; } @@ -2530,16 +2539,65 @@ static int wp11_Object_Load_Data(WP11_Object* object, int tokenId, int objId) { int ret; void* storage = NULL; + int tempLen; /* Open access to data. */ ret = wp11_storage_open_readonly(WOLFPKCS11_STORE_DATA, tokenId, objId, &storage); if (ret == 0) { - /* Read data. */ - ret = wp11_storage_read_alloc_array(storage, &object->keyData, - &object->keyDataLen); + /* Read data length and data. */ + ret = wp11_storage_read_word32(storage, + &object->data.genericData.dataLen); + if (ret == 0 && object->data.genericData.dataLen > 0) { + tempLen = (int)object->data.genericData.dataLen; + ret = wp11_storage_read_alloc_array(storage, + &object->data.genericData.data, + &tempLen); + object->data.genericData.dataLen = (word32)tempLen; + } + else if (ret == 0) { + /* Ensure data is NULL when length is 0 */ + object->data.genericData.data = NULL; + object->data.genericData.dataLen = 0; + } + + /* Read application length and application. */ + if (ret == 0) { + ret = wp11_storage_read_word32(storage, + &object->data.genericData.applicationLen); + } + if (ret == 0 && object->data.genericData.applicationLen > 0) { + tempLen = (int)object->data.genericData.applicationLen; + ret = wp11_storage_read_alloc_array(storage, + &object->data.genericData.application, + &tempLen); + object->data.genericData.applicationLen = (word32)tempLen; + } + else if (ret == 0) { + /* Ensure application is NULL when length is 0 */ + object->data.genericData.application = NULL; + object->data.genericData.applicationLen = 0; + } + + /* Read object ID length and object ID. */ + if (ret == 0) { + ret = wp11_storage_read_word32(storage, + &object->data.genericData.objectIdLen); + } + if (ret == 0 && object->data.genericData.objectIdLen > 0) { + tempLen = (int)object->data.genericData.objectIdLen; + ret = wp11_storage_read_alloc_array(storage, + &object->data.genericData.objectId, + &tempLen); + object->data.genericData.objectIdLen = (word32)tempLen; + } + else if (ret == 0) { + /* Ensure objectId is NULL when length is 0 */ + object->data.genericData.objectId = NULL; + object->data.genericData.objectIdLen = 0; + } + wp11_storage_close(storage); - wp11_Object_Decode_Data(object); } return ret; @@ -3029,11 +3087,39 @@ static int wp11_Object_Store_Data(WP11_Object* object, int tokenId, int objId) /* Open access to data. */ ret = wp11_storage_open(WOLFPKCS11_STORE_DATA, tokenId, objId, - sizeof(WP11_Data), &storage); + sizeof(WP11_GenericData), &storage); if (ret == 0) { - /* Write data to storage. */ - ret = wp11_storage_write_array(storage, - (unsigned char*)&object->data.genericData, sizeof(WP11_Data)); + /* Write data length and data. */ + ret = wp11_storage_write_word32(storage, + object->data.genericData.dataLen); + if (ret == 0 && object->data.genericData.dataLen > 0) { + ret = wp11_storage_write_array(storage, + object->data.genericData.data, + object->data.genericData.dataLen); + } + + /* Write application length and application. */ + if (ret == 0) { + ret = wp11_storage_write_word32(storage, + object->data.genericData.applicationLen); + } + if (ret == 0 && object->data.genericData.applicationLen > 0) { + ret = wp11_storage_write_array(storage, + object->data.genericData.application, + object->data.genericData.applicationLen); + } + + /* Write object ID length and object ID. */ + if (ret == 0) { + ret = wp11_storage_write_word32(storage, + object->data.genericData.objectIdLen); + } + if (ret == 0 && object->data.genericData.objectIdLen > 0) { + ret = wp11_storage_write_array(storage, + object->data.genericData.objectId, + object->data.genericData.objectIdLen); + } + wp11_storage_close(storage); } @@ -7115,6 +7201,11 @@ void WP11_Object_Free(WP11_Object* object) XFREE(object->data.cert.data, NULL, DYNAMIC_TYPE_CERT); certFreed = 1; } + else if (object->objClass == CKO_DATA) { + XFREE(object->data.genericData.data, NULL, DYNAMIC_TYPE_CERT); + XFREE(object->data.genericData.application, NULL, DYNAMIC_TYPE_CERT); + XFREE(object->data.genericData.objectId, NULL, DYNAMIC_TYPE_CERT); + } else { #ifndef NO_RSA if (object->type == CKK_RSA && object->data.rsaKey != NULL) { @@ -7621,13 +7712,74 @@ int WP11_Object_DataObject(WP11_Object* object, unsigned char** data, if (object->onToken) WP11_Lock_LockRW(object->lock); - if (data[1] == NULL || len[1] == 0 || len[1] > WP11_MAX_SYM_KEY_SZ) - ret = BAD_FUNC_ARG; - else if (data[1] != NULL) { - XMEMCPY(object->data.genericData.data, data[1], len[1]); - object->data.genericData.len = (word32)len[1]; + if (data[0] != NULL && len[0] > 0) { + if (object->data.genericData.data != NULL) { + XFREE(object->data.genericData.data, NULL, DYNAMIC_TYPE_CERT); + } + object->data.genericData.data = + XMALLOC(len[0], NULL, DYNAMIC_TYPE_CERT); + if (object->data.genericData.data == NULL) { + ret = MEMORY_E; + } + else { + XMEMCPY(object->data.genericData.data, data[0], len[0]); + object->data.genericData.dataLen = (word32)len[0]; + } + } + else if (data[0] == NULL) { + /* Clear data if not provided */ + if (object->data.genericData.data != NULL) { + XFREE(object->data.genericData.data, NULL, DYNAMIC_TYPE_CERT); + object->data.genericData.data = NULL; + } + object->data.genericData.dataLen = 0; + } + + if (ret == 0 && data[1] != NULL && len[1] > 0) { + if (object->data.genericData.application != NULL) { + XFREE(object->data.genericData.application, NULL, DYNAMIC_TYPE_CERT); + } + object->data.genericData.application = + XMALLOC(len[1], NULL, DYNAMIC_TYPE_CERT); + if (object->data.genericData.application == NULL) { + ret = MEMORY_E; + } + else { + XMEMCPY(object->data.genericData.application, data[1], len[1]); + object->data.genericData.applicationLen = (word32)len[1]; + } + } + else if (ret == 0 && data[1] == NULL) { + /* Clear application if not provided */ + if (object->data.genericData.application != NULL) { + XFREE(object->data.genericData.application, NULL, DYNAMIC_TYPE_CERT); + object->data.genericData.application = NULL; + } + object->data.genericData.applicationLen = 0; } + if (ret == 0 && data[2] != NULL && len[2] > 0) { + if (object->data.genericData.objectId != NULL) { + XFREE(object->data.genericData.objectId, NULL, DYNAMIC_TYPE_CERT); + } + object->data.genericData.objectId = + XMALLOC(len[2], NULL, DYNAMIC_TYPE_CERT); + if (object->data.genericData.objectId == NULL) { + ret = MEMORY_E; + } + else { + XMEMCPY(object->data.genericData.objectId, data[2], len[2]); + object->data.genericData.objectIdLen = (word32)len[2]; + } + } + else if (ret == 0 && data[2] == NULL) { + /* Clear object ID if not provided */ + if (object->data.genericData.objectId != NULL) { + XFREE(object->data.genericData.objectId, NULL, DYNAMIC_TYPE_CERT); + object->data.genericData.objectId = NULL; + } + object->data.genericData.objectIdLen = 0; + } if (object->onToken) WP11_Lock_UnlockRW(object->lock); @@ -7932,7 +8084,15 @@ static int GetDataAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, switch (type) { case CKA_VALUE: ret = GetData((byte*)object->data.genericData.data, - object->data.genericData.len, data, len); + object->data.genericData.dataLen, data, len); + break; + case CKA_APPLICATION: + ret = GetData((byte*)object->data.genericData.application, + object->data.genericData.applicationLen, data, len); + break; + case CKA_OBJECT_ID: + ret = GetData((byte*)object->data.genericData.objectId, + object->data.genericData.objectIdLen, data, len); break; default: ret = NOT_AVAILABLE_E; @@ -8482,7 +8642,13 @@ int WP11_Object_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, ret = GetBool(CK_TRUE, data, len); break; case CKA_APPLICATION: - /* Not available */ + if (object->objClass == CKO_DATA) { + ret = GetDataAttr(object, type, data, len); + } + else { + /* Not available for other object types */ + ret = NOT_AVAILABLE_E; + } break; case CKA_ID: ret = GetData(object->keyId, object->keyIdLen, data, len); @@ -8921,6 +9087,22 @@ int WP11_Object_SetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, break; } break; + case CKA_APPLICATION: + if (object->objClass == CKO_DATA) { + break; /* Handled in WP11_Object_DataObject */ + } + else { + ret = BAD_FUNC_ARG; + } + break; + case CKA_OBJECT_ID: + if (object->objClass == CKO_DATA) { + break; /* Handled in WP11_Object_DataObject */ + } + else { + ret = BAD_FUNC_ARG; + } + break; #ifdef WOLFPKCS11_NSS case CKA_CERT_SHA1_HASH: case CKA_CERT_MD5_HASH: diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index 316aed04..5e8d79f0 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -3080,6 +3080,8 @@ static CK_RV test_data_object(void* args) 0x72, 0x6C, 0x64, 0x21 /* "Hello World!" */ }; static byte testLabel[] = "TestDataObject"; + static byte testApplication[] = "TestApplication"; + static byte testObjectId[] = {0x01, 0x02, 0x03, 0x04}; /* Template for creating a session data object */ CK_ATTRIBUTE dataTemplate[] = { @@ -3088,7 +3090,9 @@ static CK_RV test_data_object(void* args) { CKA_VALUE, testData, sizeof(testData) }, { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, - { CKA_MODIFIABLE, &ckTrue, sizeof(ckTrue) } + { CKA_MODIFIABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_APPLICATION, testApplication, sizeof(testApplication) }, + { CKA_OBJECT_ID, testObjectId, sizeof(testObjectId) } }; CK_ULONG dataTemplateCnt = sizeof(dataTemplate) / sizeof(*dataTemplate); @@ -3099,7 +3103,9 @@ static CK_RV test_data_object(void* args) { CKA_VALUE, testData, sizeof(testData) }, { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, - { CKA_MODIFIABLE, &ckTrue, sizeof(ckTrue) } + { CKA_MODIFIABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_APPLICATION, testApplication, sizeof(testApplication) }, + { CKA_OBJECT_ID, testObjectId, sizeof(testObjectId) } }; CK_ULONG tokenDataTemplateCnt = sizeof(tokenDataTemplate) / sizeof(*tokenDataTemplate); @@ -3111,7 +3117,9 @@ static CK_RV test_data_object(void* args) { CKA_VALUE, NULL, 0 }, { CKA_TOKEN, NULL, 0 }, { CKA_PRIVATE, NULL, 0 }, - { CKA_MODIFIABLE, NULL, 0 } + { CKA_MODIFIABLE, NULL, 0 }, + { CKA_APPLICATION, NULL, 0 }, + { CKA_OBJECT_ID, NULL, 0 } }; CK_ULONG getTemplateCnt = sizeof(getTemplate) / sizeof(*getTemplate); @@ -3122,6 +3130,8 @@ static CK_RV test_data_object(void* args) CK_BBOOL retToken; CK_BBOOL retPrivate; CK_BBOOL retModifiable; + byte retApplication[32]; + byte retObjectId[32]; @@ -3163,6 +3173,12 @@ static CK_RV test_data_object(void* args) getTemplate[5].pValue = &retModifiable; getTemplate[5].ulValueLen = sizeof(retModifiable); + + getTemplate[6].pValue = retApplication; + getTemplate[6].ulValueLen = sizeof(retApplication); + + getTemplate[7].pValue = retObjectId; + getTemplate[7].ulValueLen = sizeof(retObjectId); } /* Test C_GetAttributeValue - get the actual values */ @@ -3215,6 +3231,20 @@ static CK_RV test_data_object(void* args) } } + if (ret == CKR_OK) { + if (XMEMCMP(retApplication, testApplication, sizeof(testApplication)) != 0) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA application attribute verification"); + } + } + + if (ret == CKR_OK) { + if (XMEMCMP(retObjectId, testObjectId, sizeof(testObjectId)) != 0) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA object ID attribute verification"); + } + } + /* Test getting individual attributes */ if (ret == CKR_OK) { CK_ATTRIBUTE singleAttr = { CKA_VALUE, retValue, sizeof(retValue) }; @@ -3281,6 +3311,231 @@ static CK_RV test_data_object(void* args) return ret; } +static CK_RV test_data_object_null_value(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret = CKR_OK; + CK_OBJECT_HANDLE dataObj = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE dataObjToken = CK_INVALID_HANDLE; + + /* Test data for the data object - no value data */ + static byte testLabel[] = "TestDataObjectNullValue"; + static byte testApplication[] = "TestApplicationNull"; + static byte testObjectId[] = {0x05, 0x06, 0x07, 0x08}; + + /* Template for creating a session data object with NULL value */ + static CK_BBOOL sessionFalse = CK_FALSE; + CK_ATTRIBUTE dataTemplate[] = { + { CKA_CLASS, &dataClass, sizeof(dataClass) }, + { CKA_LABEL, testLabel, sizeof(testLabel) }, + { CKA_VALUE, NULL, 0 }, + { CKA_TOKEN, &sessionFalse, sizeof(sessionFalse) }, + { CKA_PRIVATE, &sessionFalse, sizeof(sessionFalse) }, + { CKA_MODIFIABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_APPLICATION, testApplication, sizeof(testApplication) }, + { CKA_OBJECT_ID, testObjectId, sizeof(testObjectId) } + }; + CK_ULONG dataTemplateCnt = sizeof(dataTemplate) / sizeof(*dataTemplate); + + /* Template for creating a token data object with NULL value */ + CK_ATTRIBUTE tokenDataTemplate[] = { + { CKA_CLASS, &dataClass, sizeof(dataClass) }, + { CKA_LABEL, testLabel, sizeof(testLabel) }, + { CKA_VALUE, NULL, 0 }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_MODIFIABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_APPLICATION, testApplication, sizeof(testApplication) }, + { CKA_OBJECT_ID, testObjectId, sizeof(testObjectId) } + }; + CK_ULONG tokenDataTemplateCnt = sizeof(tokenDataTemplate) / + sizeof(*tokenDataTemplate); + + /* Template for retrieving attributes */ + CK_ATTRIBUTE getTemplate[] = { + { CKA_CLASS, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_VALUE, NULL, 0 }, + { CKA_TOKEN, NULL, 0 }, + { CKA_PRIVATE, NULL, 0 }, + { CKA_MODIFIABLE, NULL, 0 }, + { CKA_APPLICATION, NULL, 0 }, + { CKA_OBJECT_ID, NULL, 0 } + }; + CK_ULONG getTemplateCnt = sizeof(getTemplate) / sizeof(*getTemplate); + + /* Buffers for retrieved attributes */ + CK_OBJECT_CLASS retClass; + byte retLabel[32]; + byte retValue[32]; + CK_BBOOL retToken; + CK_BBOOL retPrivate; + CK_BBOOL retModifiable; + byte retApplication[32]; + byte retObjectId[32]; + + /* Test creating a session data object with NULL value */ + ret = funcList->C_CreateObject(session, dataTemplate, dataTemplateCnt, + &dataObj); + CHECK_CKR(ret, "Create CKO_DATA session object with NULL value"); + + /* Test creating a token data object with NULL value */ + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, tokenDataTemplate, + tokenDataTemplateCnt, &dataObjToken); + CHECK_CKR(ret, "Create CKO_DATA token object with NULL value"); + } + + /* Test C_GetAttributeValue - first get the lengths */ + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, dataObj, getTemplate, + getTemplateCnt); + CHECK_CKR(ret, "Get CKO_DATA attribute lengths for NULL value"); + } + + /* Verify that CKA_VALUE has length 0 */ + if (ret == CKR_OK) { + if (getTemplate[2].ulValueLen != 0) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value should have length 0"); + } + } + + /* Allocate buffers and set up pointers */ + if (ret == CKR_OK) { + getTemplate[0].pValue = &retClass; + getTemplate[0].ulValueLen = sizeof(retClass); + + getTemplate[1].pValue = retLabel; + getTemplate[1].ulValueLen = sizeof(retLabel); + + getTemplate[2].pValue = retValue; + getTemplate[2].ulValueLen = sizeof(retValue); + + getTemplate[3].pValue = &retToken; + getTemplate[3].ulValueLen = sizeof(retToken); + + getTemplate[4].pValue = &retPrivate; + getTemplate[4].ulValueLen = sizeof(retPrivate); + + getTemplate[5].pValue = &retModifiable; + getTemplate[5].ulValueLen = sizeof(retModifiable); + + getTemplate[6].pValue = retApplication; + getTemplate[6].ulValueLen = sizeof(retApplication); + + getTemplate[7].pValue = retObjectId; + getTemplate[7].ulValueLen = sizeof(retObjectId); + } + + /* Test C_GetAttributeValue - get the actual values */ + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, dataObj, getTemplate, + getTemplateCnt); + CHECK_CKR(ret, "Get CKO_DATA attribute values for NULL value"); + } + + /* Verify the retrieved values match what we set */ + if (ret == CKR_OK) { + if (retClass != dataClass) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value class attribute verification"); + } + } + + if (ret == CKR_OK) { + if (XMEMCMP(retLabel, testLabel, sizeof(testLabel)) != 0) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value label attribute verification"); + } + } + + /* Verify that CKA_VALUE is indeed empty/NULL */ + if (ret == CKR_OK) { + if (getTemplate[2].ulValueLen != 0) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value should remain length 0"); + } + } + + if (ret == CKR_OK) { + if (retToken != sessionFalse) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value token attribute verification"); + } + } + + if (ret == CKR_OK) { + if (retPrivate != sessionFalse) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value private attribute verification"); + } + } + + if (ret == CKR_OK) { + if (retModifiable != ckTrue) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value modifiable attribute verification"); + } + } + + if (ret == CKR_OK) { + if (XMEMCMP(retApplication, testApplication, sizeof(testApplication)) != 0) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value application attribute verification"); + } + } + + if (ret == CKR_OK) { + if (XMEMCMP(retObjectId, testObjectId, sizeof(testObjectId)) != 0) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value object ID attribute verification"); + } + } + + /* Test getting CKA_VALUE individually to confirm it's NULL/empty */ + if (ret == CKR_OK) { + CK_ATTRIBUTE singleAttr = { CKA_VALUE, NULL, 0 }; + + ret = funcList->C_GetAttributeValue(session, dataObj, &singleAttr, 1); + CHECK_CKR(ret, "Get single CKA_VALUE attribute for NULL value"); + + if (ret == CKR_OK) { + if (singleAttr.ulValueLen != 0) { + ret = -1; + CHECK_CKR(ret, "Single CKA_VALUE NULL verification"); + } + } + } + + /* Test token data object attribute retrieval */ + if (ret == CKR_OK) { + CK_ATTRIBUTE tokenAttr = { CKA_TOKEN, &retToken, sizeof(retToken) }; + + ret = funcList->C_GetAttributeValue(session, dataObjToken, + &tokenAttr, 1); + CHECK_CKR(ret, "Get token CKO_DATA attribute for NULL value"); + + if (ret == CKR_OK) { + if (retToken != ckTrue) { + ret = -1; + CHECK_CKR(ret, + "Token CKO_DATA NULL value token attribute verification"); + } + } + } + + /* Clean up */ + if (dataObj != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, dataObj); + } + if (dataObjToken != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, dataObjToken); + } + + return ret; +} + static CK_RV get_generic_key(CK_SESSION_HANDLE session, unsigned char* data, CK_ULONG len, CK_BBOOL extractable, CK_OBJECT_HANDLE* key) @@ -14795,6 +15050,7 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_attribute_types), PKCS11TEST_FUNC_SESS_DECL(test_attribute_get), PKCS11TEST_FUNC_SESS_DECL(test_data_object), + PKCS11TEST_FUNC_SESS_DECL(test_data_object_null_value), PKCS11TEST_FUNC_SESS_DECL(test_attributes_secret), #ifndef NO_RSA PKCS11TEST_FUNC_SESS_DECL(test_attributes_rsa), From c254db9decb3ff60fa2fe693ca7260fb570ccfc9 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 9 Jul 2025 17:28:21 +0200 Subject: [PATCH 13/50] Try to return invalid sig when applicable --- src/internal.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index cc8698da..7a4ba928 100644 --- a/src/internal.c +++ b/src/internal.c @@ -10187,8 +10187,12 @@ int WP11_RsaPKCSPSS_Verify(unsigned char* sig, word32 sigLen, if (ret == 0) { ret = wc_RsaPSS_CheckPadding_ex(hash, hashLen, decSig, decSz, pss->hashType, pss->saltLen, 0); - if (ret == 0) { + if (ret == 0) *stat = 1; + /* Both can indicate that the verification failed */ + if (ret == BAD_PADDING_E || ret == PSS_SALTLEN_E) { + *stat = 0; + ret = 0; } } /* Make sure bad padding returns success, but verify failed. From b3759f76a1959dbd29ee682075d0d5cf3c8dd41e Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Thu, 10 Jul 2025 06:44:34 +0100 Subject: [PATCH 14/50] Fix typos and wolfSSL 5.6.6 compatibility --- src/internal.c | 59 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/src/internal.c b/src/internal.c index 7a4ba928..d6dab0d3 100644 --- a/src/internal.c +++ b/src/internal.c @@ -921,7 +921,7 @@ static int wolfPKCS11_Store_GetMaxSize(int type, int variableSz) case WOLFPKCS11_STORE_DHKEY_PUB: case WOLFPKCS11_STORE_CERT: case WOLFPKCS11_STORE_TRUST: - case WOLFPKCS11_STOR_DATA: + case WOLFPKCS11_STORE_DATA: maxSz = sizeof(word32) + variableSz; break; @@ -2271,6 +2271,7 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) case CKK_EC: { byte* derBuf = NULL; int derSz = 0; + int initialDerSz = 0; /* Initialize destination ECC key */ ret = wc_ecc_init_ex(&dest->data.ecKey, NULL, @@ -2281,18 +2282,26 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) /* Determine if this is a private or public key and get DER * size */ if (src->objClass == CKO_PRIVATE_KEY) { - ret = wc_EccPrivateKeyToDer(&src->data.ecKey, NULL, 0); + initialDerSz = wc_EccPrivateKeyToDer(&src->data.ecKey, + NULL, 0); } else { - ret = wc_EccPublicKeyToDer(&src->data.ecKey, NULL, 0, 1); + initialDerSz = wc_EccPublicKeyToDer(&src->data.ecKey, + NULL, 0, 1); } - if (ret == 0) /* Should not happen */ - ret = BUFFER_E; - if (ret > 0) { - derSz = ret; + /* Handle different return values for size estimation */ + if (initialDerSz == LENGTH_ONLY_E || initialDerSz == 0) { + /* wolfSSL 5.6.6 compatibility */ + derSz = 256; /* Conservative estimate for ECC key DER */ ret = 0; + } else if (initialDerSz > 0) { + derSz = initialDerSz; + ret = 0; + } else { + ret = initialDerSz; /* Pass through the error */ } + /* Allocate buffer with retry logic */ if (ret == 0) { derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -2301,7 +2310,7 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) } if (ret == 0) { - /* Encode the source key to DER */ + /* Encode the source key to DER with retry logic */ if (src->objClass == CKO_PRIVATE_KEY) { ret = wc_EccPrivateKeyToDer(&src->data.ecKey, derBuf, derSz); @@ -2310,10 +2319,30 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) derSz, 1); } - if (ret == 0) /* Should not happen */ - ret = BUFFER_E; - if (ret > 0) + /* Handle buffer too small case */ + if (ret == BUFFER_E && derSz < 1024) { + /* Reallocate buffer with larger size */ + derSz = 1024; /* Larger buffer size */ + derBuf = (byte*)XREALLOC(derBuf, derSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + ret = MEMORY_E; + } else { + if (src->objClass == CKO_PRIVATE_KEY) { + ret = wc_EccPrivateKeyToDer(&src->data.ecKey, + derBuf, derSz); + } else { + ret = wc_EccPublicKeyToDer(&src->data.ecKey, + derBuf, derSz, 1); + } + } + } + + /* Normalize positive return to success */ + if (ret > 0) { + derSz = ret; /* Update actual size used */ ret = 0; + } } if (ret == 0) { @@ -2546,12 +2575,12 @@ static int wp11_Object_Load_Data(WP11_Object* object, int tokenId, int objId) &storage); if (ret == 0) { /* Read data length and data. */ - ret = wp11_storage_read_word32(storage, + ret = wp11_storage_read_word32(storage, &object->data.genericData.dataLen); if (ret == 0 && object->data.genericData.dataLen > 0) { tempLen = (int)object->data.genericData.dataLen; ret = wp11_storage_read_alloc_array(storage, - &object->data.genericData.data, + &object->data.genericData.data, &tempLen); object->data.genericData.dataLen = (word32)tempLen; } @@ -2569,7 +2598,7 @@ static int wp11_Object_Load_Data(WP11_Object* object, int tokenId, int objId) if (ret == 0 && object->data.genericData.applicationLen > 0) { tempLen = (int)object->data.genericData.applicationLen; ret = wp11_storage_read_alloc_array(storage, - &object->data.genericData.application, + &object->data.genericData.application, &tempLen); object->data.genericData.applicationLen = (word32)tempLen; } @@ -2587,7 +2616,7 @@ static int wp11_Object_Load_Data(WP11_Object* object, int tokenId, int objId) if (ret == 0 && object->data.genericData.objectIdLen > 0) { tempLen = (int)object->data.genericData.objectIdLen; ret = wp11_storage_read_alloc_array(storage, - &object->data.genericData.objectId, + &object->data.genericData.objectId, &tempLen); object->data.genericData.objectIdLen = (word32)tempLen; } From 62ff5c222bd19fde6387c7b43253949e1d322faf Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Thu, 10 Jul 2025 06:58:22 +0100 Subject: [PATCH 15/50] Address things in the review --- src/crypto.c | 6 +-- src/internal.c | 40 +++++++++++++--- tests/pkcs11test.c | 116 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 9 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index c450780d..a6bc4a13 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -6469,9 +6469,6 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; word32 serialSize = 0; byte* serialBuff = NULL; -#ifndef NO_RSA - word32 encDataLen; -#endif WOLFPKCS11_ENTER("C_WrapKey"); #ifdef DEBUG_WOLFPKCS11 @@ -6589,6 +6586,8 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, #endif #ifndef NO_RSA case CKM_RSA_PKCS: + { + word32 encDataLen; if (wrapkeyType != CKK_RSA) { rv = CKR_WRAPPING_KEY_TYPE_INCONSISTENT; goto err_out; @@ -6624,6 +6623,7 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, *pulWrappedKeyLen = encDataLen; break; + } #endif default: rv = CKR_MECHANISM_INVALID; diff --git a/src/internal.c b/src/internal.c index d6dab0d3..2c03e04d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -503,7 +503,7 @@ struct WP11_Slot { /* Number of slots. */ -static const int slotCnt = 1; +#define slotCnt 1 /* List of slot objects. */ static WP11_Slot slotList[1]; /* Global random used in random API, cryptographic operations and generating @@ -2238,7 +2238,20 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) byte* derBuf = NULL; int derSz = 0; - ret = wc_RsaKeyToDer(&src->data.rsaKey, NULL, 0); + /* Initialize destination RSA key */ + ret = wc_InitRsaKey_ex(&dest->data.rsaKey, NULL, + dest->slot->devId); + if (ret != 0) + break; + + /* Determine if this is a private or public key and get DER + * size */ + if (src->objClass == CKO_PRIVATE_KEY) { + ret = wc_RsaKeyToDer(&src->data.rsaKey, NULL, 0); + } else { + ret = wc_RsaKeyToPublicDer(&src->data.rsaKey, NULL, 0); + } + if (ret == 0) /* Should not happen */ ret = BUFFER_E; if (ret > 0) { @@ -2246,21 +2259,36 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) ret = 0; } if (ret == 0) { - derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + derBuf = (byte*)XMALLOC(derSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); if (derBuf == NULL) ret = MEMORY_E; } if (ret == 0) { - ret = wc_RsaKeyToDer(&src->data.rsaKey, derBuf, derSz); + /* Encode the source key to DER */ + if (src->objClass == CKO_PRIVATE_KEY) { + ret = wc_RsaKeyToDer(&src->data.rsaKey, derBuf, derSz); + } else { + ret = wc_RsaKeyToPublicDer(&src->data.rsaKey, derBuf, + derSz); + } if (ret == 0) /* Should not happen */ ret = BUFFER_E; if (ret > 0) ret = 0; } if (ret == 0) { + /* Decode the DER data into the destination key */ word32 idx = 0; - ret = wc_RsaPrivateKeyDecode(derBuf, &idx, & - dest->data.rsaKey, (word32)derSz); + if (src->objClass == CKO_PRIVATE_KEY) { + ret = wc_RsaPrivateKeyDecode(derBuf, &idx, + &dest->data.rsaKey, + (word32)derSz); + } else { + ret = wc_RsaPublicKeyDecode(derBuf, &idx, + &dest->data.rsaKey, + (word32)derSz); + } } XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index 5e8d79f0..9f2e976f 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -1950,6 +1950,7 @@ static CK_RV test_copy_object_rsa_key(void* args) CK_OBJECT_HANDLE pubKey = CK_INVALID_HANDLE; CK_OBJECT_HANDLE privKey = CK_INVALID_HANDLE; CK_OBJECT_HANDLE copiedPrivKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE copiedPubKey = CK_INVALID_HANDLE; CK_MECHANISM mech; CK_ULONG bits = 2048; static byte keyId[] = { 0xAA, 0xBB, 0xCC, 0xDD }; @@ -2008,11 +2009,33 @@ static CK_RV test_copy_object_rsa_key(void* args) CK_ULONG getCopiedAttrsCnt = sizeof(getCopiedAttrs) / sizeof(*getCopiedAttrs); + CK_ATTRIBUTE getOriginalPubAttrs[] = { + { CKA_ID, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_MODULUS, NULL, 0 }, + { CKA_PUBLIC_EXPONENT, NULL, 0 }, + }; + CK_ULONG getOriginalPubAttrsCnt = sizeof(getOriginalPubAttrs) / + sizeof(*getOriginalPubAttrs); + + CK_ATTRIBUTE getCopiedPubAttrs[] = { + { CKA_ID, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_MODULUS, NULL, 0 }, + { CKA_PUBLIC_EXPONENT, NULL, 0 }, + }; + CK_ULONG getCopiedPubAttrsCnt = sizeof(getCopiedPubAttrs) / + sizeof(*getCopiedPubAttrs); + /* Buffers for retrieved attributes */ byte origId[32], copiedId[32]; byte origLabel[64], copiedLabel[64]; byte origModulus[512], copiedModulus[512]; CK_BBOOL origExtractable, copiedExtractable; + byte origPubId[32], copiedPubId[32]; + byte origPubLabel[64], copiedPubLabel[64]; + byte origPubModulus[512], copiedPubModulus[512]; + byte origPubExponent[8], copiedPubExponent[8]; /* Generate RSA key pair */ mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; @@ -2031,6 +2054,13 @@ static CK_RV test_copy_object_rsa_key(void* args) CHECK_CKR(ret, "Copy RSA private key"); } + /* Test: Copy RSA public key */ + if (ret == CKR_OK) { + ret = funcList->C_CopyObject(session, pubKey, copyTmpl, copyTmplCnt, + &copiedPubKey); + CHECK_CKR(ret, "Copy RSA public key"); + } + /* Verify that both keys exist and have expected attributes */ if (ret == CKR_OK) { /* Set up buffers for original key attributes */ @@ -2101,6 +2131,79 @@ static CK_RV test_copy_object_rsa_key(void* args) } } + /* Verify that both public keys exist and have expected attributes */ + if (ret == CKR_OK) { + /* Set up buffers for original public key attributes */ + getOriginalPubAttrs[0].pValue = origPubId; + getOriginalPubAttrs[0].ulValueLen = sizeof(origPubId); + getOriginalPubAttrs[1].pValue = origPubLabel; + getOriginalPubAttrs[1].ulValueLen = sizeof(origPubLabel); + getOriginalPubAttrs[2].pValue = origPubModulus; + getOriginalPubAttrs[2].ulValueLen = sizeof(origPubModulus); + getOriginalPubAttrs[3].pValue = origPubExponent; + getOriginalPubAttrs[3].ulValueLen = sizeof(origPubExponent); + + ret = funcList->C_GetAttributeValue(session, pubKey, getOriginalPubAttrs, + getOriginalPubAttrsCnt); + CHECK_CKR(ret, "Get original RSA public key attributes"); + } + + if (ret == CKR_OK) { + /* Set up buffers for copied public key attributes */ + getCopiedPubAttrs[0].pValue = copiedPubId; + getCopiedPubAttrs[0].ulValueLen = sizeof(copiedPubId); + getCopiedPubAttrs[1].pValue = copiedPubLabel; + getCopiedPubAttrs[1].ulValueLen = sizeof(copiedPubLabel); + getCopiedPubAttrs[2].pValue = copiedPubModulus; + getCopiedPubAttrs[2].ulValueLen = sizeof(copiedPubModulus); + getCopiedPubAttrs[3].pValue = copiedPubExponent; + getCopiedPubAttrs[3].ulValueLen = sizeof(copiedPubExponent); + + ret = funcList->C_GetAttributeValue(session, copiedPubKey, + getCopiedPubAttrs, getCopiedPubAttrsCnt); + CHECK_CKR(ret, "Get copied RSA public key attributes"); + } + + /* Verify that public key attributes match */ + if (ret == CKR_OK) { + if (getOriginalPubAttrs[0].ulValueLen != getCopiedPubAttrs[0].ulValueLen || + XMEMCMP(origPubId, copiedPubId, + getOriginalPubAttrs[0].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied RSA public key ID should match original"); + } + } + + if (ret == CKR_OK) { + /* Verify LABEL is different (modified) */ + if (getCopiedPubAttrs[1].ulValueLen != sizeof(modifiedLabel)-1 || + XMEMCMP(copiedPubLabel, modifiedLabel, + sizeof(modifiedLabel)-1) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied RSA public key LABEL should be modified"); + } + } + + if (ret == CKR_OK) { + /* Verify MODULUS matches (deep copy of RSA key structure) */ + if (getOriginalPubAttrs[2].ulValueLen != getCopiedPubAttrs[2].ulValueLen || + XMEMCMP(origPubModulus, copiedPubModulus, + getOriginalPubAttrs[2].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied RSA public key MODULUS should match original"); + } + } + + if (ret == CKR_OK) { + /* Verify PUBLIC_EXPONENT matches */ + if (getOriginalPubAttrs[3].ulValueLen != getCopiedPubAttrs[3].ulValueLen || + XMEMCMP(origPubExponent, copiedPubExponent, + getOriginalPubAttrs[3].ulValueLen) != 0) { + ret = -1; + CHECK_CKR(ret, "Copied RSA public key PUBLIC_EXPONENT should match original"); + } + } + /* Test that both keys can be used for signing (verifying key structure * is intact) */ if (ret == CKR_OK) { @@ -2153,6 +2256,16 @@ static CK_RV test_copy_object_rsa_key(void* args) CHECK_CKR(ret, "Verify signature from copied RSA key"); } } + + /* Also verify with copied public key */ + if (ret == CKR_OK) { + ret = funcList->C_VerifyInit(session, &signMech, copiedPubKey); + if (ret == CKR_OK) { + ret = funcList->C_Verify(session, data, sizeof(data)-1, + signature1, sigLen1); + CHECK_CKR(ret, "Verify signature with copied RSA public key"); + } + } } /* Clean up */ @@ -2165,6 +2278,9 @@ static CK_RV test_copy_object_rsa_key(void* args) if (copiedPrivKey != CK_INVALID_HANDLE) { funcList->C_DestroyObject(session, copiedPrivKey); } + if (copiedPubKey != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, copiedPubKey); + } return ret; } From 0abebe445b61f88fab381ed7c42a8123b0306f95 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Thu, 10 Jul 2025 13:07:00 +0200 Subject: [PATCH 16/50] Fix styling and other nits Assume free(NULL) is a no-op to simplify logic --- .gitignore | 5 +++ src/internal.c | 108 +++++++++++++++++++++++-------------------------- 2 files changed, 56 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index 3c09ac0b..ca0a60dd 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,11 @@ examples/obj_list examples/slot_info examples/token_info store/wp11* +store/object +store/pkcs11mtt +store/pkcs11test +store/rsa +store/str test/* *.gcda *.gcno diff --git a/src/internal.c b/src/internal.c index 2c03e04d..79db8f76 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2248,7 +2248,8 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) * size */ if (src->objClass == CKO_PRIVATE_KEY) { ret = wc_RsaKeyToDer(&src->data.rsaKey, NULL, 0); - } else { + } + else { ret = wc_RsaKeyToPublicDer(&src->data.rsaKey, NULL, 0); } @@ -2268,7 +2269,8 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) /* Encode the source key to DER */ if (src->objClass == CKO_PRIVATE_KEY) { ret = wc_RsaKeyToDer(&src->data.rsaKey, derBuf, derSz); - } else { + } + else { ret = wc_RsaKeyToPublicDer(&src->data.rsaKey, derBuf, derSz); } @@ -2284,7 +2286,8 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) ret = wc_RsaPrivateKeyDecode(derBuf, &idx, &dest->data.rsaKey, (word32)derSz); - } else { + } + else { ret = wc_RsaPublicKeyDecode(derBuf, &idx, &dest->data.rsaKey, (word32)derSz); @@ -2312,7 +2315,8 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) if (src->objClass == CKO_PRIVATE_KEY) { initialDerSz = wc_EccPrivateKeyToDer(&src->data.ecKey, NULL, 0); - } else { + } + else { initialDerSz = wc_EccPublicKeyToDer(&src->data.ecKey, NULL, 0, 1); } @@ -2322,10 +2326,12 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) /* wolfSSL 5.6.6 compatibility */ derSz = 256; /* Conservative estimate for ECC key DER */ ret = 0; - } else if (initialDerSz > 0) { + } + else if (initialDerSz > 0) { derSz = initialDerSz; ret = 0; - } else { + } + else { ret = initialDerSz; /* Pass through the error */ } @@ -2342,7 +2348,8 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) if (src->objClass == CKO_PRIVATE_KEY) { ret = wc_EccPrivateKeyToDer(&src->data.ecKey, derBuf, derSz); - } else { + } + else { ret = wc_EccPublicKeyToDer(&src->data.ecKey, derBuf, derSz, 1); } @@ -2355,11 +2362,13 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) DYNAMIC_TYPE_TMP_BUFFER); if (derBuf == NULL) { ret = MEMORY_E; - } else { + } + else { if (src->objClass == CKO_PRIVATE_KEY) { ret = wc_EccPrivateKeyToDer(&src->data.ecKey, derBuf, derSz); - } else { + } + else { ret = wc_EccPublicKeyToDer(&src->data.ecKey, derBuf, derSz, 1); } @@ -2380,7 +2389,8 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) ret = wc_EccPrivateKeyDecode(derBuf, &idx, &dest->data.ecKey, (word32)derSz); - } else { + } + else { ret = wc_EccPublicKeyDecode(derBuf, &idx, &dest->data.ecKey, (word32)derSz); @@ -7770,9 +7780,7 @@ int WP11_Object_DataObject(WP11_Object* object, unsigned char** data, WP11_Lock_LockRW(object->lock); if (data[0] != NULL && len[0] > 0) { - if (object->data.genericData.data != NULL) { - XFREE(object->data.genericData.data, NULL, DYNAMIC_TYPE_CERT); - } + XFREE(object->data.genericData.data, NULL, DYNAMIC_TYPE_CERT); object->data.genericData.data = XMALLOC(len[0], NULL, DYNAMIC_TYPE_CERT); if (object->data.genericData.data == NULL) { @@ -7785,17 +7793,13 @@ int WP11_Object_DataObject(WP11_Object* object, unsigned char** data, } else if (data[0] == NULL) { /* Clear data if not provided */ - if (object->data.genericData.data != NULL) { - XFREE(object->data.genericData.data, NULL, DYNAMIC_TYPE_CERT); - object->data.genericData.data = NULL; - } + XFREE(object->data.genericData.data, NULL, DYNAMIC_TYPE_CERT); + object->data.genericData.data = NULL; object->data.genericData.dataLen = 0; } if (ret == 0 && data[1] != NULL && len[1] > 0) { - if (object->data.genericData.application != NULL) { - XFREE(object->data.genericData.application, NULL, DYNAMIC_TYPE_CERT); - } + XFREE(object->data.genericData.application, NULL, DYNAMIC_TYPE_CERT); object->data.genericData.application = XMALLOC(len[1], NULL, DYNAMIC_TYPE_CERT); if (object->data.genericData.application == NULL) { @@ -7808,17 +7812,13 @@ int WP11_Object_DataObject(WP11_Object* object, unsigned char** data, } else if (ret == 0 && data[1] == NULL) { /* Clear application if not provided */ - if (object->data.genericData.application != NULL) { - XFREE(object->data.genericData.application, NULL, DYNAMIC_TYPE_CERT); - object->data.genericData.application = NULL; - } + XFREE(object->data.genericData.application, NULL, DYNAMIC_TYPE_CERT); + object->data.genericData.application = NULL; object->data.genericData.applicationLen = 0; } if (ret == 0 && data[2] != NULL && len[2] > 0) { - if (object->data.genericData.objectId != NULL) { - XFREE(object->data.genericData.objectId, NULL, DYNAMIC_TYPE_CERT); - } + XFREE(object->data.genericData.objectId, NULL, DYNAMIC_TYPE_CERT); object->data.genericData.objectId = XMALLOC(len[2], NULL, DYNAMIC_TYPE_CERT); if (object->data.genericData.objectId == NULL) { @@ -7831,10 +7831,8 @@ int WP11_Object_DataObject(WP11_Object* object, unsigned char** data, } else if (ret == 0 && data[2] == NULL) { /* Clear object ID if not provided */ - if (object->data.genericData.objectId != NULL) { - XFREE(object->data.genericData.objectId, NULL, DYNAMIC_TYPE_CERT); - object->data.genericData.objectId = NULL; - } + XFREE(object->data.genericData.objectId, NULL, DYNAMIC_TYPE_CERT); + object->data.genericData.objectId = NULL; object->data.genericData.objectIdLen = 0; } @@ -8777,68 +8775,64 @@ int WP11_Object_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, ret = CKR_ATTRIBUTE_TYPE_INVALID; break; case CKA_CHECK_VALUE: - if (object->objClass == CKO_CERTIFICATE) + if (object->objClass == CKO_CERTIFICATE) { #ifndef NO_SHA ret = GetSha1CheckValue(object->data.cert.data, object->data.cert.len, data, len); #else ret = NOT_AVAILABLE_E; #endif - else if (object->objClass == CKO_SECRET_KEY) + } + else if (object->objClass == CKO_SECRET_KEY) { #ifdef HAVE_AESECB ret = GetEcbCheckValue(object, data, len); #else ret = NOT_AVAILABLE_E; #endif + } else ret = NOT_AVAILABLE_E; break; default: { - if (object->objClass == CKO_CERTIFICATE) { + if (object->objClass == CKO_CERTIFICATE) ret = GetCertAttr(object, type, data, len); - break; - } - #if defined(WOLFPKCS11_NSS) - else if (object->objClass == CKO_NSS_TRUST) { +#if defined(WOLFPKCS11_NSS) + else if (object->objClass == CKO_NSS_TRUST) ret = GetTrustAttr(object, type, data, len); - break; - } - #endif - else if (object->objClass == CKO_DATA) { +#endif + else if (object->objClass == CKO_DATA) ret = GetDataAttr(object, type, data, len); - break; - } else { switch (object->type) { - #ifndef NO_RSA +#ifndef NO_RSA case CKK_RSA: ret = RsaObject_GetAttr(object, type, data, len); break; - #endif - #ifdef HAVE_ECC +#endif +#ifdef HAVE_ECC case CKK_EC: ret = EcObject_GetAttr(object, type, data, len); break; - #endif - #ifndef NO_DH +#endif +#ifndef NO_DH case CKK_DH: ret = DhObject_GetAttr(object, type, data, len); break; - #endif - #ifndef NO_AES +#endif +#ifndef NO_AES case CKK_AES: - #endif - #ifdef WOLFPKCS11_HKDF +#endif +#ifdef WOLFPKCS11_HKDF case CKK_HKDF: - #endif +#endif case CKK_GENERIC_SECRET: ret = SecretObject_GetAttr(object, type, data, len); break; } - break; } + break; } } @@ -9146,7 +9140,7 @@ int WP11_Object_SetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, break; case CKA_APPLICATION: if (object->objClass == CKO_DATA) { - break; /* Handled in WP11_Object_DataObject */ + /* Handled in WP11_Object_DataObject */ } else { ret = BAD_FUNC_ARG; @@ -9154,7 +9148,7 @@ int WP11_Object_SetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, break; case CKA_OBJECT_ID: if (object->objClass == CKO_DATA) { - break; /* Handled in WP11_Object_DataObject */ + /* Handled in WP11_Object_DataObject */ } else { ret = BAD_FUNC_ARG; From 1aefc15a974a0f6708b9617b20e9415f755bef23 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 11 Jul 2025 18:55:05 +0200 Subject: [PATCH 17/50] Return found objects in reverse order for NSS --- src/internal.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index 79db8f76..8223c373 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7221,8 +7221,15 @@ int WP11_Session_FindGet(WP11_Session* session, CK_OBJECT_HANDLE* handle) if (session->find.curr == session->find.count) ret = FIND_NO_MORE_E; - if (ret == 0) + if (ret == 0) { +#ifdef WOLFPKCS11_NSS + /* NSS relies on the latest object being found first */ + *handle = session->find.found[session->find.count - 1 - + session->find.curr++]; +#else *handle = session->find.found[session->find.curr++]; +#endif + } return ret; } From 11cd7eda283b656dae704ee38999f9e03d79dba4 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 11 Jul 2025 18:55:17 +0200 Subject: [PATCH 18/50] Add Get/Set for MD5 --- src/internal.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/internal.c b/src/internal.c index 8223c373..b3d7606a 100644 --- a/src/internal.c +++ b/src/internal.c @@ -12944,6 +12944,11 @@ int WP11_GetOperationState(WP11_Session* session, unsigned char* stateData, *stateDataLen = sizeof(session->mechanism); switch (session->mechanism) { +#ifndef NO_MD5 + case CKM_MD5: + mechSize = sizeof(wc_Md5); + break; +#endif #ifndef NO_SHA case CKM_SHA1: mechSize = sizeof(wc_Sha); @@ -12991,6 +12996,11 @@ int WP11_GetOperationState(WP11_Session* session, unsigned char* stateData, switch (session->mechanism) { +#ifndef NO_MD5 + case CKM_MD5: + wc_Md5Copy(&hashAlg->md5, (wc_Md5*)stateData); + break; +#endif #ifndef NO_SHA case CKM_SHA1: wc_ShaCopy(&hashAlg->sha, (wc_Sha*)stateData); @@ -13038,6 +13048,11 @@ int WP11_SetOperationState(WP11_Session* session, unsigned char* stateData, XMEMCPY(&session->mechanism, stateData, sizeof(session->mechanism)); switch (session->mechanism) { +#ifndef NO_MD5 + case CKM_MD5: + mechSize = sizeof(wc_Md5); + break; +#endif #ifndef NO_SHA case CKM_SHA1: mechSize = sizeof(wc_Sha); @@ -13090,6 +13105,11 @@ int WP11_SetOperationState(WP11_Session* session, unsigned char* stateData, #endif switch (session->mechanism) { +#ifndef NO_MD5 + case CKM_MD5: + wc_Md5Copy((wc_Md5*)stateData, &hashAlg->md5); + break; +#endif #ifndef NO_SHA case CKM_SHA1: wc_ShaCopy((wc_Sha*)stateData, &hashAlg->sha); From a7fd68597d7d5ef972a841a755a1126991cc0851 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Mon, 14 Jul 2025 09:41:34 +0200 Subject: [PATCH 19/50] Differentiate between CKO_DATA and other object classes in HKDF derivation This fixes a regression of revision c929ebf, which improved support for CKO_DATA. Since the data in CKO_DATA objects is now stored in a different format, we need to differentiate on the object class used for the input key when performing an HKDF derivation. --- src/internal.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/internal.c b/src/internal.c index b3d7606a..dfc72111 100644 --- a/src/internal.c +++ b/src/internal.c @@ -10737,6 +10737,8 @@ int WP11_KDF_Derive(WP11_Session* session, CK_HKDF_PARAMS_PTR params, unsigned char* key, word32* keyLen, WP11_Object* priv) { int ret = 0; + byte* privData = NULL; + word32 privLen = 0; byte* salt = NULL; unsigned long saltLen = 0; WP11_Object* saltKey = NULL; @@ -10776,24 +10778,30 @@ int WP11_KDF_Derive(WP11_Session* session, CK_HKDF_PARAMS_PTR params, } PRIVATE_KEY_UNLOCK(); + if (priv->objClass == CKO_DATA) { + privData = priv->data.genericData.data; + privLen = priv->data.genericData.dataLen; + } + else { + privData = priv->data.symmKey.data; + privLen = priv->data.symmKey.len; + } if (params->bExtract && !params->bExpand) { ret = wc_HKDF_Extract(hashType, salt, (word32)saltLen, - priv->data.symmKey->data, priv->data.symmKey->len, key); + privData, privLen, key); if (!ret) *keyLen = hashLen; } else if (!params->bExtract && params->bExpand) { - ret = wc_HKDF_Expand(hashType, priv->data.symmKey->data, - priv->data.symmKey->len, params->pInfo, (word32)params->ulInfoLen, + ret = wc_HKDF_Expand(hashType, privData, privLen, + params->pInfo, (word32)params->ulInfoLen, key, *keyLen); } else { /* Both */ - ret = wc_HKDF(hashType, priv->data.symmKey->data, - priv->data.symmKey->len, - salt, (word32)saltLen, params->pInfo, (word32)params->ulInfoLen, - key, *keyLen); + ret = wc_HKDF(hashType, privData, privLen, salt, (word32)saltLen, + params->pInfo, (word32)params->ulInfoLen, key, *keyLen); } PRIVATE_KEY_LOCK(); From 290b564c669ed007650d0cf5807e422d0cb28fc8 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Tue, 15 Jul 2025 14:35:18 +0200 Subject: [PATCH 20/50] Cache WP11_Slot_Has_Empty_Pin result WP11_Slot_CheckUserPin is very resource intensive and caching this result helps with speeding up tests --- src/internal.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/internal.c b/src/internal.c index dfc72111..b4136173 100644 --- a/src/internal.c +++ b/src/internal.c @@ -484,6 +484,10 @@ typedef struct WP11_Token { int objCnt; /* Count of objects on token */ int tokenFlags; /* Flags for token */ int nextObjId; + byte userPinEmpty:2; /* Indicates user PIN is empty + * 0 = not set + * 1 = empty + * 2 = not empty */ } WP11_Token; struct WP11_Slot { @@ -713,9 +717,28 @@ int WP11_Slot_Has_Empty_Pin(WP11_Slot* slot) if (slot == NULL) return 0; - if ((slot->token.tokenFlags & WP11_TOKEN_FLAG_USER_PIN_SET) && - (WP11_Slot_CheckUserPin(slot, (char*)"", 0) == 0)) - return 1; + if (slot->token.tokenFlags & WP11_TOKEN_FLAG_USER_PIN_SET) { + switch (slot->token.userPinEmpty) { + case 1: + /* Empty user PIN */ + return 1; + case 2: + /* Non-empty user PIN */ + return 0; + default: + /* Cache result as WP11_Slot_CheckUserPin is very expensive */ + if (WP11_Slot_CheckUserPin(slot, (char*)"", 0) == 0) { + /* Empty user PIN */ + slot->token.userPinEmpty = 1; + return 1; + } + else { + /* Non-empty user PIN */ + slot->token.userPinEmpty = 2; + return 0; + } + } + } return 0; } @@ -4855,6 +4878,7 @@ static int wp11_Token_Load(WP11_Slot* slot, int tokenId, WP11_Token* token) } if (ret == 0) { /* Read User's PIN. (32) */ + token->userPinEmpty = 0; ret = wp11_storage_read_array(storage, token->userPin, &len, sizeof(token->userPin)); } @@ -6047,6 +6071,7 @@ int WP11_Slot_SetUserPin(WP11_Slot* slot, char* pin, int pinLen) if (ret == 0) { WP11_Lock_UnlockRW(&slot->lock); /* Costly Operation done out of lock. */ + token->userPinEmpty = 0; ret = HashPIN(pin, pinLen, token->userPinSeed, sizeof(token->userPinSeed), token->userPin, sizeof(token->userPin)); From 3063acb19eaebc9db23406f1b2a435b319ec6149 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Tue, 15 Jul 2025 14:37:50 +0200 Subject: [PATCH 21/50] CKM_*_HMAC can use any opaque secret --- src/crypto.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/crypto.c b/src/crypto.c index a6bc4a13..977ee75b 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -5110,7 +5110,9 @@ CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, case CKM_SHA3_512_HMAC: #endif #endif - if (type != CKK_GENERIC_SECRET) + if (type != CKK_GENERIC_SECRET && + type != CKK_AES && + type != CKK_HKDF) return CKR_KEY_TYPE_INCONSISTENT; if (pMechanism->pParameter != NULL || pMechanism->ulParameterLen != 0) { From 994912e5c3b74359412cb06160a2869662f21f34 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 17 Jul 2025 13:43:08 +0200 Subject: [PATCH 22/50] CKM_*_HMAC: check digest size based on algorithm --- src/crypto.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crypto.c b/src/crypto.c index 977ee75b..21dd0da9 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -3963,6 +3963,7 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, WP11_Object* obj = NULL; CK_KEY_TYPE type; int init = 0; + CK_ULONG digestSize = 0; CK_RV rv; WOLFPKCS11_ENTER("C_SignInit"); From 6e0b679bfd006a95f3cce79b2a184324cdb318e3 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 18 Jul 2025 11:17:55 +0200 Subject: [PATCH 23/50] Avoid branch on uninit memory --- src/internal.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/internal.c b/src/internal.c index b4136173..61f21f5b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -13012,12 +13012,12 @@ int WP11_GetOperationState(WP11_Session* session, unsigned char* stateData, } *stateDataLen += mechSize; - if (bufferAvailable < *stateDataLen) - return CKR_BUFFER_TOO_SMALL; - if (stateData == NULL) return CKR_OK; + if (bufferAvailable < *stateDataLen) + return CKR_BUFFER_TOO_SMALL; + XMEMCPY(stateData, &session->mechanism, sizeof(session->mechanism)); stateData += sizeof(session->mechanism); From 987ffaaa0c0064afe662e868cc7533812e4564d8 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 18 Jul 2025 17:29:55 +0200 Subject: [PATCH 24/50] Allow wrapping hkdf with ckm_aes_ecb --- src/crypto.c | 38 +++++++++++++++++++++++++++++++------- src/internal.c | 3 ++- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 21dd0da9..96c4f6b8 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -55,7 +55,8 @@ ( \ (kc == CKO_PRIVATE_KEY && kt == CKK_RSA) || \ (kc == CKO_SECRET_KEY && kt == CKK_AES) || \ - (kc == CKO_SECRET_KEY && kt == CKK_GENERIC_SECRET) \ + (kc == CKO_SECRET_KEY && kt == CKK_GENERIC_SECRET) || \ + (kc == CKO_SECRET_KEY && kt == CKK_HKDF) \ ) \ ? CKR_OK: CKR_KEY_NOT_WRAPPABLE @@ -6540,6 +6541,7 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, #ifndef NO_AES case CKK_AES: #endif + case CKK_HKDF: case CKK_GENERIC_SECRET: ret = WP11_Generic_SerializeKey(key, NULL, &serialSize); if (ret != 0) { @@ -6572,6 +6574,7 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, case CKM_AES_KEY_WRAP_PAD: #endif case CKM_AES_CBC_PAD: + case CKM_AES_ECB: if (wrapkeyType != CKK_AES) { rv = CKR_WRAPPING_KEY_TYPE_INCONSISTENT; goto err_out; @@ -6759,6 +6762,7 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, case CKM_AES_KEY_WRAP_PAD: #endif case CKM_AES_CBC_PAD: + case CKM_AES_ECB: if (wrapkeyType != CKK_AES) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; @@ -6824,6 +6828,7 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, #ifndef NO_AES case CKK_AES: #endif + case CKK_HKDF: case CKK_GENERIC_SECRET: { WP11_Object* keyObj = NULL; unsigned char* keyData[2] = { @@ -6879,7 +6884,7 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, * @param symmKeyLen [out] Length of symmetric key in bytes. * @return 0 on success. */ -static int SymmKeyLen(WP11_Object* obj, word32 len, word32* symmKeyLen) +static int SymmKeyLen(WP11_Object* obj, word32 len, CK_ULONG* symmKeyLen) { int ret; word32 valueLen = 0; @@ -6894,12 +6899,27 @@ static int SymmKeyLen(WP11_Object* obj, word32 len, word32* symmKeyLen) switch (WP11_Object_GetType(obj)) { case CKK_AES: +#ifdef WOLFPKCS11_NSS + /* This is the only wrapping mechanism that we support. NSS chooses + * the wrapping mechanism from the list in wrapMechanismList in + * PK11_GetBestWrapMechanism. Unfortunately this relies on a default + * key length value so let's default to the strongest key. */ + if (valueLen == 0) { + if (len >= AES_256_KEY_SIZE) + valueLen = AES_256_KEY_SIZE; + else if (len >= AES_192_KEY_SIZE) + valueLen = AES_192_KEY_SIZE; + else + valueLen = AES_128_KEY_SIZE; + } + FALL_THROUGH; +#endif case CKK_HKDF: case CKK_GENERIC_SECRET: default: if (valueLen > 0 && valueLen <= len) len = valueLen; - *symmKeyLen = len; + *symmKeyLen = (CK_ULONG)len; break; } @@ -6914,7 +6934,7 @@ static int SetKeyExtract(WP11_Session* session, byte* ptr, CK_ULONG length, { WP11_Object* secret = NULL; int ret; - word32 symmKeyLen; + CK_ULONG symmKeyLen; CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; CK_BBOOL ckTrue = CK_TRUE; CK_BBOOL ckFalse = CK_FALSE; @@ -6928,8 +6948,10 @@ static int SetKeyExtract(WP11_Session* session, byte* ptr, CK_ULONG length, ret = SymmKeyLen(secret, (word32)length, &symmKeyLen); if (ret == 0) { /* Only use the bottom part of the secret for the key. */ + secretKeyData[0] = (unsigned char*)&symmKeyLen; + secretKeyLen[0] = sizeof(CK_ULONG); secretKeyData[1] = ptr + (length - symmKeyLen); - secretKeyLen[1] = length; + secretKeyLen[1] = symmKeyLen; ret = WP11_Object_SetSecretKey(secret, secretKeyData, secretKeyLen); if (ret != CKR_OK) return CKR_FUNCTION_FAILED; @@ -7084,7 +7106,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, #if defined(HAVE_ECC) || !defined(NO_DH) || defined(WOLFPKCS11_HKDF) byte* derivedKey = NULL; word32 keyLen; - word32 symmKeyLen; + CK_ULONG symmKeyLen; unsigned char* secretKeyData[2] = { NULL, NULL }; CK_ULONG secretKeyLen[2] = { 0, 0 }; #endif @@ -7359,8 +7381,10 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, ret = SymmKeyLen(obj, keyLen, &symmKeyLen); if (ret == 0) { /* Only use the bottom part of the secret for the key. */ + secretKeyData[0] = (unsigned char*)&symmKeyLen; + secretKeyLen[0] = sizeof(CK_ULONG); secretKeyData[1] = derivedKey + (keyLen - symmKeyLen); - secretKeyLen[1] = keyLen; + secretKeyLen[1] = symmKeyLen; ret = WP11_Object_SetSecretKey(obj, secretKeyData, secretKeyLen); if (ret != 0) diff --git a/src/internal.c b/src/internal.c index 61f21f5b..a40a7f15 100644 --- a/src/internal.c +++ b/src/internal.c @@ -8522,7 +8522,8 @@ int WP11_Generic_SerializeKey(WP11_Object* object, byte* output, word32* poutsz) if (object == NULL || poutsz == NULL) return PARAM_E; - if (object->type != CKK_AES && object->type != CKK_GENERIC_SECRET) + if (object->type != CKK_AES && object->type != CKK_GENERIC_SECRET + && object->type != CKK_HKDF) return OBJ_TYPE_E; if (object->objClass != CKO_SECRET_KEY) From f9791eba12e181578eaba2e83dc5e72b288d2430 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 18 Jul 2025 18:26:23 +0200 Subject: [PATCH 25/50] Fix uninit variable errors --- src/crypto.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/crypto.c b/src/crypto.c index 96c4f6b8..53329da4 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -7166,6 +7166,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, derivedKey = (byte*)XMALLOC(keyLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (derivedKey == NULL) return CKR_DEVICE_MEMORY; + XMEMSET(derivedKey, 0, keyLen); ret = WP11_EC_Derive(params->pPublicData, (int)params->ulPublicDataLen, derivedKey, @@ -7203,6 +7204,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, derivedKey = (byte*)XMALLOC(keyLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (derivedKey == NULL) return CKR_DEVICE_MEMORY; + XMEMSET(derivedKey, 0, keyLen); ret = WP11_KDF_Derive(session, kdfParams, derivedKey, &keyLen, obj); @@ -7222,6 +7224,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, derivedKey = (byte*)XMALLOC(keyLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (derivedKey == NULL) return CKR_DEVICE_MEMORY; + XMEMSET(derivedKey, 0, keyLen); ret = WP11_Dh_Derive((unsigned char*)pMechanism->pParameter, (int)pMechanism->ulParameterLen, derivedKey, @@ -7247,6 +7250,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, derivedKey = (byte*)XMALLOC(keyLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (derivedKey == NULL) return CKR_DEVICE_MEMORY; + XMEMSET(derivedKey, 0, keyLen); ret = WP11_AesCbc_DeriveKey(params->pData, (word32)params->length, derivedKey, params->iv, obj); @@ -7281,6 +7285,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, derivedKey = (byte*)XMALLOC(keyLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (derivedKey == NULL) return CKR_DEVICE_MEMORY; + XMEMSET(derivedKey, 0, keyLen); ret = WP11_Tls12_Master_Key_Derive(&tlsParams->RandomInfo, tlsParams->prfHashMechanism, "key expansion", 13, @@ -7327,6 +7332,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, derivedKey = (byte*)XMALLOC(keyLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (derivedKey == NULL) return CKR_DEVICE_MEMORY; + XMEMSET(derivedKey, 0, keyLen); ret = WP11_Tls12_Master_Key_Derive(&prfParams->RandomInfo, prfParams->prfHashMechanism, @@ -7355,6 +7361,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, derivedKey = (byte*)XMALLOC(keyLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (derivedKey == NULL) return CKR_DEVICE_MEMORY; + XMEMSET(derivedKey, 0, keyLen); ret = WP11_Nss_Tls12_Master_Key_Derive(nssParams->pSessionHash, nssParams->ulSessionHashLen, From d47bf0eb02a3d5b8f47ff52f03be439fd8936e34 Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Mon, 21 Jul 2025 11:16:50 +0100 Subject: [PATCH 26/50] Fix `test_rsa_gen_keys` for NSS builds --- tests/pkcs11test.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index 9f2e976f..ca270b0e 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -5713,9 +5713,11 @@ static CK_RV find_rsa_pub_key_label(CK_SESSION_HANDLE session, CK_ATTRIBUTE pubKeyTmpl[] = { #ifndef WOLFPKCS11_KEYPAIR_GEN_COMMON_LABEL { CKA_LABEL, (unsigned char*)"", 0 }, + { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, #else { CKA_CLASS, &pubKeyClass, sizeof(privKeyClass) }, { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) }, + { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, #endif }; CK_ULONG pubKeyTmplCnt = sizeof(pubKeyTmpl) / sizeof(*pubKeyTmpl); @@ -5747,6 +5749,7 @@ static CK_RV find_rsa_priv_key_label(CK_SESSION_HANDLE session, { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) }, { CKA_LABEL, (unsigned char*)"priv_label", 10 }, + { CKA_TOKEN, &ckFalse, sizeof(ckFalse) }, }; CK_ULONG privKeyTmplCnt = sizeof(privKeyTmpl) / sizeof(*privKeyTmpl); CK_ULONG count; From 069ed8c71ff4b1fd439dd5dbe88ba449877b1aa9 Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Mon, 21 Jul 2025 11:26:17 +0100 Subject: [PATCH 27/50] Fix `NO_HMAC` compiling --- src/crypto.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/crypto.c b/src/crypto.c index 53329da4..8fa598f7 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -3964,7 +3964,9 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, WP11_Object* obj = NULL; CK_KEY_TYPE type; int init = 0; +#ifndef NO_HMAC CK_ULONG digestSize = 0; +#endif CK_RV rv; WOLFPKCS11_ENTER("C_SignInit"); From ecc2a5b79c4b22841e3afcb05644c7c267bbc153 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 21 Jul 2025 13:01:58 +0200 Subject: [PATCH 28/50] Get the correct key length when deriving CKM_ECDH1_DERIVE --- src/crypto.c | 2 +- src/internal.c | 4 ++-- wolfpkcs11/internal.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 8fa598f7..f024e238 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -7172,7 +7172,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, ret = WP11_EC_Derive(params->pPublicData, (int)params->ulPublicDataLen, derivedKey, - keyLen, obj); + &keyLen, obj); if (ret != 0) rv = CKR_FUNCTION_FAILED; break; diff --git a/src/internal.c b/src/internal.c index a40a7f15..6efb06b3 100644 --- a/src/internal.c +++ b/src/internal.c @@ -10636,7 +10636,7 @@ int WP11_Ec_Verify(unsigned char* sig, word32 sigLen, unsigned char* hash, * 0 on success. */ int WP11_EC_Derive(unsigned char* point, word32 pointLen, unsigned char* key, - word32 keyLen, WP11_Object* priv) + word32* keyLen, WP11_Object* priv) { int ret; ecc_key pubKey; @@ -10703,7 +10703,7 @@ int WP11_EC_Derive(unsigned char* point, word32 pointLen, unsigned char* key, #endif { PRIVATE_KEY_UNLOCK(); - ret = wc_ecc_shared_secret(priv->data.ecKey, &pubKey, key, &keyLen); + ret = wc_ecc_shared_secret(&priv->data.ecKey, &pubKey, key, keyLen); PRIVATE_KEY_LOCK(); #ifdef WOLFPKCS11_TPM diff --git a/wolfpkcs11/internal.h b/wolfpkcs11/internal.h index f6a10fc5..97f37d15 100644 --- a/wolfpkcs11/internal.h +++ b/wolfpkcs11/internal.h @@ -476,7 +476,7 @@ WP11_LOCAL int WP11_Ec_Sign(unsigned char* hash, word32 hashLen, unsigned char* WP11_LOCAL int WP11_Ec_Verify(unsigned char* sig, word32 sigLen, unsigned char* hash, word32 hashLen, int* stat, WP11_Object* pub); WP11_LOCAL int WP11_EC_Derive(unsigned char* point, word32 pointLen, unsigned char* key, - word32 keyLen, WP11_Object* priv); + word32* keyLen, WP11_Object* priv); WP11_LOCAL int WP11_Dh_GenerateKeyPair(WP11_Object* pub, WP11_Object* priv, WP11_Slot* slot); From ae080bb26d335b7de77778f14c1055c4b7ed4ab7 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Mon, 21 Jul 2025 17:38:30 +0200 Subject: [PATCH 29/50] Allow zero-length key in AES --- src/internal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index 6efb06b3..cde6253a 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7738,7 +7738,8 @@ int WP11_Object_SetSecretKey(WP11_Object* object, unsigned char** data, ret = BAD_FUNC_ARG; #ifndef NO_AES if (ret == 0 && object->type == CKK_AES && data[0] != NULL) { - if (*(CK_ULONG*)data[0] != AES_128_KEY_SIZE && + if (*(CK_ULONG*)data[0] != 0 && + *(CK_ULONG*)data[0] != AES_128_KEY_SIZE && *(CK_ULONG*)data[0] != AES_192_KEY_SIZE && *(CK_ULONG*)data[0] != AES_256_KEY_SIZE) { ret = BAD_FUNC_ARG; From 61d68b60e2c45782f5b504253a9dcb90937dae59 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 22 Jul 2025 14:57:22 +0200 Subject: [PATCH 30/50] Support non-standard CKM_NSS_TLS_PRF_GENERAL_SHA256 --- src/crypto.c | 34 ++++++++++++++++++++++++++++++++-- src/internal.c | 13 ++++++++++--- wolfpkcs11/pkcs11.h | 1 + 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index f024e238..4e7abd83 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -4197,6 +4197,14 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, return ret; init = WP11_INIT_TLS_MAC_SIGN; break; +#ifdef WOLFPKCS11_NSS + case CKM_NSS_TLS_PRF_GENERAL_SHA256: + ret = WP11_TLS_MAC_init(CKM_SHA256_HMAC, 0, 0, hKey, session); + if (ret != 0) + return CKR_FUNCTION_FAILED; + init = WP11_INIT_TLS_MAC_SIGN; + break; +#endif #endif default: (void)type; @@ -4520,6 +4528,9 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, #endif #ifdef WOLFSSL_HAVE_PRF case CKM_TLS_MAC: +#ifdef WOLFPKCS11_NSS + case CKM_NSS_TLS_PRF_GENERAL_SHA256: +#endif if (!WP11_Session_IsOpInitialized(session, WP11_INIT_TLS_MAC_SIGN)) return CKR_OPERATION_NOT_INITIALIZED; @@ -4650,6 +4661,9 @@ CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, #endif #ifdef WOLFSSL_HAVE_PRF case CKM_TLS_MAC: +#ifdef WOLFPKCS11_NSS + case CKM_NSS_TLS_PRF_GENERAL_SHA256: +#endif if (!WP11_Session_IsOpInitialized(session, WP11_INIT_TLS_MAC_SIGN)) return CKR_OPERATION_NOT_INITIALIZED; @@ -4788,7 +4802,11 @@ CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, #endif #endif #ifdef WOLFSSL_HAVE_PRF - case CKM_TLS_MAC: { + case CKM_TLS_MAC: +#ifdef WOLFPKCS11_NSS + case CKM_NSS_TLS_PRF_GENERAL_SHA256: +#endif + { byte* data = NULL; word32 dataLen = 0; @@ -5166,6 +5184,14 @@ CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, return ret; init = WP11_INIT_TLS_MAC_VERIFY; break; +#ifdef WOLFPKCS11_NSS + case CKM_NSS_TLS_PRF_GENERAL_SHA256: + ret = WP11_TLS_MAC_init(CKM_SHA256_HMAC, 0, 0, hKey, session); + if (ret != 0) + return CKR_FUNCTION_FAILED; + init = WP11_INIT_TLS_MAC_VERIFY; + break; +#endif #endif default: (void)type; @@ -5440,7 +5466,11 @@ CK_RV C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, #endif #endif #ifdef WOLFSSL_HAVE_PRF - case CKM_TLS_MAC: { + case CKM_TLS_MAC: +#ifdef WOLFPKCS11_NSS + case CKM_NSS_TLS_PRF_GENERAL_SHA256: +#endif + { if (!WP11_Session_IsOpInitialized(session, WP11_INIT_TLS_MAC_VERIFY)) return CKR_OPERATION_NOT_INITIALIZED; diff --git a/src/internal.c b/src/internal.c index cde6253a..8e987040 100644 --- a/src/internal.c +++ b/src/internal.c @@ -12862,6 +12862,7 @@ int WP11_TLS_MAC_sign(byte* data, word32 dataLen, byte* sig, word32* sigLen, "server finished" : "client finished"); WP11_Data* key = NULL; WP11_Object* secret = NULL; + word32 outLen = 0; if (mac->macSz > *sigLen) return BAD_FUNC_ARG; @@ -12878,11 +12879,17 @@ int WP11_TLS_MAC_sign(byte* data, word32 dataLen, byte* sig, word32* sigLen, PRIVATE_KEY_UNLOCK(); if (mac->isTlsPrf) { - ret = wc_PRF_TLSv1(sig, mac->macSz, key->data, key->len, label, 15, + outLen = mac->macSz; + ret = wc_PRF_TLSv1(sig, outLen, key->data, key->len, label, 15, data, dataLen, NULL, secret->slot->devId); } else { - ret = wc_PRF_TLS(sig, mac->macSz, key->data, key->len, label, 15, + /* Use maximum requested size if MAC size is unspecified */ + if (mac->macSz == 0) + outLen = *sigLen; + else + outLen = mac->macSz; + ret = wc_PRF_TLS(sig, outLen, key->data, key->len, label, 15, data, dataLen, 1, mac->mac, NULL, secret->slot->devId); } PRIVATE_KEY_LOCK(); @@ -12891,7 +12898,7 @@ int WP11_TLS_MAC_sign(byte* data, word32 dataLen, byte* sig, word32* sigLen, WP11_Lock_UnlockRO(secret->lock); if (ret == 0) - *sigLen = mac->macSz; + *sigLen = outLen; session->init = 0; return ret; diff --git a/wolfpkcs11/pkcs11.h b/wolfpkcs11/pkcs11.h index b2a66dcc..f66e68bf 100644 --- a/wolfpkcs11/pkcs11.h +++ b/wolfpkcs11/pkcs11.h @@ -322,6 +322,7 @@ extern "C" { #define CKM_HKDF_KEY_GEN 0x0000402CUL #ifdef WOLFPKCS11_NSS +#define CKM_NSS_TLS_PRF_GENERAL_SHA256 (CKM_NSS + 21) #define CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE (CKM_NSS + 25) #define CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH (CKM_NSS + 26) #endif From 053c59c5e398d77f1582d8649b9862ab6c12f72e Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 23 Jul 2025 17:52:43 +0200 Subject: [PATCH 31/50] Check if object supports operation For some reason C_DeriveKey does not check if CKA_DERIVE is set --- src/crypto.c | 158 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 105 insertions(+), 53 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 4e7abd83..15f85788 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -339,6 +339,20 @@ static CK_RV CheckAttributes(CK_ATTRIBUTE* pTemplate, CK_ULONG ulCount, int set) return CKR_OK; } +static CK_RV CheckOpSupported(WP11_Object* obj, CK_ATTRIBUTE_TYPE op) +{ + CK_BBOOL haveOp = 0; + CK_ULONG dataLen = sizeof(haveOp); + int ret = WP11_Object_GetAttr(obj, op, &haveOp, &dataLen); + if (ret != 0) + return ret; + if (!haveOp) { + WOLFPKCS11_MSG("Operation not supported by object"); + return CKR_KEY_TYPE_INCONSISTENT; + } + return CKR_OK; +} + static CK_RV SetInitialStates(WP11_Object* key) { CK_RV rv; @@ -1685,28 +1699,9 @@ CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession) } -/** - * Initialize encryption operation. - * - * @param hSession [in] Handle of session. - * @param pMechanism [in] Type of operation to perform with parameters. - * @param hKey [in] Handle to key object. - * @return CKR_CRYPTOKI_NOT_INITIALIZED when library not initialized. - * CKR_SESSION_HANDLE_INVALID when session handle is not valid. - * CKR_ARGUMENTS_BAD when pMechanism is NULL. - * CKR_OBJECT_HANDLE_INVALID when key object handle is not valid. - * CKR_KEY_TYPE_INCONSISTENT when the key type is not valid for the - * mechanism (operation). - * CKR_MECHANISM_PARAM_INVALID when mechanism's parameters are not - * valid for the operation. - * CKR_MECHANISM_INVALID when the mechanism is not supported with this - * type of operation. - * CKR_DEVICE_MEMORY when dynamic memory allocation fails. - * CKR_FUNCTION_FAILED when initializing fails. - * CKR_OK on success. - */ -CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession, - CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +static CK_RV EncryptInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, + byte skipOpCheck) { CK_RV rv; int ret; @@ -1745,6 +1740,12 @@ CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession, return rv; } + if (!skipOpCheck) { + ret = CheckOpSupported(obj, CKA_ENCRYPT); + if (ret != CKR_OK) + return ret; + } + type = WP11_Object_GetType(obj); switch (pMechanism->mechanism) { #ifndef NO_RSA @@ -1967,6 +1968,33 @@ CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession, return CKR_OK; } + +/** + * Initialize encryption operation. + * + * @param hSession [in] Handle of session. + * @param pMechanism [in] Type of operation to perform with parameters. + * @param hKey [in] Handle to key object. + * @return CKR_CRYPTOKI_NOT_INITIALIZED when library not initialized. + * CKR_SESSION_HANDLE_INVALID when session handle is not valid. + * CKR_ARGUMENTS_BAD when pMechanism is NULL. + * CKR_OBJECT_HANDLE_INVALID when key object handle is not valid. + * CKR_KEY_TYPE_INCONSISTENT when the key type is not valid for the + * mechanism (operation). + * CKR_MECHANISM_PARAM_INVALID when mechanism's parameters are not + * valid for the operation. + * CKR_MECHANISM_INVALID when the mechanism is not supported with this + * type of operation. + * CKR_DEVICE_MEMORY when dynamic memory allocation fails. + * CKR_FUNCTION_FAILED when initializing fails. + * CKR_OK on success. + */ +CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + return EncryptInit(hSession, pMechanism, hKey, 0); +} + /** * Encrypt single-part data. * @@ -2654,28 +2682,9 @@ CK_RV C_EncryptFinal(CK_SESSION_HANDLE hSession, return CKR_OK; } -/** - * Initialize decryption operation. - * - * @param hSession [in] Handle of session. - * @param pMechanism [in] Type of operation to perform with parameters. - * @param hKey [in] Handle to key object. - * @return CKR_CRYPTOKI_NOT_INITIALIZED when library not initialized. - * CKR_SESSION_HANDLE_INVALID when session handle is not valid. - * CKR_ARGUMENTS_BAD when pMechanism is NULL. - * CKR_OBJECT_HANDLE_INVALID when key object handle is not valid. - * CKR_KEY_TYPE_INCONSISTENT when the key type is not valid for the - * mechanism (operation). - * CKR_MECHANISM_PARAM_INVALID when mechanism's parameters are not - * valid for the operation. - * CKR_MECHANISM_INVALID when the mechanism is not supported with this - * type of operation. - * CKR_DEVICE_MEMORY when dynamic memory allocation fails. - * CKR_FUNCTION_FAILED when initializing fails. - * CKR_OK on success. - */ -CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, - CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +static CK_RV DecryptInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, + byte skipOpCheck) { int ret; WP11_Session* session; @@ -2705,6 +2714,12 @@ CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, if (ret != 0) return CKR_OBJECT_HANDLE_INVALID; + if (!skipOpCheck) { + ret = CheckOpSupported(obj, CKA_DECRYPT); + if (ret != CKR_OK) + return ret; + } + type = WP11_Object_GetType(obj); switch (pMechanism->mechanism) { #ifndef NO_RSA @@ -2920,6 +2935,32 @@ CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, return CKR_OK; } +/** + * Initialize decryption operation. + * + * @param hSession [in] Handle of session. + * @param pMechanism [in] Type of operation to perform with parameters. + * @param hKey [in] Handle to key object. + * @return CKR_CRYPTOKI_NOT_INITIALIZED when library not initialized. + * CKR_SESSION_HANDLE_INVALID when session handle is not valid. + * CKR_ARGUMENTS_BAD when pMechanism is NULL. + * CKR_OBJECT_HANDLE_INVALID when key object handle is not valid. + * CKR_KEY_TYPE_INCONSISTENT when the key type is not valid for the + * mechanism (operation). + * CKR_MECHANISM_PARAM_INVALID when mechanism's parameters are not + * valid for the operation. + * CKR_MECHANISM_INVALID when the mechanism is not supported with this + * type of operation. + * CKR_DEVICE_MEMORY when dynamic memory allocation fails. + * CKR_FUNCTION_FAILED when initializing fails. + * CKR_OK on success. + */ +CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + return DecryptInit(hSession, pMechanism, hKey, 0); +} + /** * Decrypt single-part data. * @@ -4006,6 +4047,10 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, return CKR_OBJECT_HANDLE_INVALID; } + ret = CheckOpSupported(obj, CKA_SIGN); + if (ret != CKR_OK) + return ret; + type = WP11_Object_GetType(obj); init = GetInitValue(pMechanism->mechanism); switch (pMechanism->mechanism) { @@ -5005,6 +5050,10 @@ CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, return rv; } + ret = CheckOpSupported(obj, CKA_VERIFY); + if (ret != CKR_OK) + return ret; + type = WP11_Object_GetType(obj); init = GetInitValue(pMechanism->mechanism); switch (pMechanism->mechanism) { @@ -5751,8 +5800,6 @@ CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, int init = 0; WP11_Session* session; WP11_Object* obj; - CK_BBOOL getVar; - CK_ULONG getVarLen = sizeof(CK_BBOOL); CK_RV rv; WOLFPKCS11_ENTER("C_VerifyRecoverInit"); @@ -5810,12 +5857,9 @@ CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, return CKR_KEY_TYPE_INCONSISTENT; } - ret = WP11_Object_GetAttr(obj, CKA_VERIFY, &getVar, &getVarLen); + ret = CheckOpSupported(obj, CKA_VERIFY); if (ret != CKR_OK) - return CKR_FUNCTION_FAILED; - - if (getVar != CK_TRUE) - return CKR_KEY_FUNCTION_NOT_PERMITTED; + return ret; WP11_Session_SetMechanism(session, pMechanism->mechanism); WP11_Session_SetObject(session, obj); @@ -6540,6 +6584,10 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, if (ret != 0) return CKR_WRAPPING_KEY_HANDLE_INVALID; + ret = CheckOpSupported(wrappingKey, CKA_WRAP); + if (ret != CKR_OK) + return ret; + wrapkeyType = WP11_Object_GetType(wrappingKey); keyType = WP11_Object_GetType(key); @@ -6612,7 +6660,7 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, goto err_out; } - rv = C_EncryptInit(hSession, pMechanism, hWrappingKey); + rv = EncryptInit(hSession, pMechanism, hWrappingKey, 1); if (rv != CKR_OK) goto err_out; @@ -6760,6 +6808,10 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, if (ret != 0) return CKR_UNWRAPPING_KEY_HANDLE_INVALID; + ret = CheckOpSupported(unwrappingKey, CKA_UNWRAP); + if (ret != CKR_OK) + return ret; + rv = FindValidAttributeType(pTemplate, ulAttributeCount, CKA_KEY_TYPE, &attr, sizeof(CK_KEY_TYPE)); if (rv != CKR_OK) @@ -6804,7 +6856,7 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, if (workBuffer == NULL) return CKR_HOST_MEMORY; - rv = C_DecryptInit(hSession, pMechanism, hUnwrappingKey); + rv = DecryptInit(hSession, pMechanism, hUnwrappingKey, 1); if (rv != CKR_OK) goto err_out; From 56b9591ac979fc1fe36951823277f6120cbe7be6 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Wed, 23 Jul 2025 18:22:44 +0200 Subject: [PATCH 32/50] Disable AES key length check in NSS --- src/internal.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/internal.c b/src/internal.c index 8e987040..836d88ff 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7736,10 +7736,9 @@ int WP11_Object_SetSecretKey(WP11_Object* object, unsigned char** data, /* First item is the key's length. */ if (ret == 0 && data[0] != NULL && len[0] != (int)sizeof(CK_ULONG)) ret = BAD_FUNC_ARG; -#ifndef NO_AES +#if !defined(NO_AES) && !defined(WOLFPKCS11_NSS) if (ret == 0 && object->type == CKK_AES && data[0] != NULL) { - if (*(CK_ULONG*)data[0] != 0 && - *(CK_ULONG*)data[0] != AES_128_KEY_SIZE && + if (*(CK_ULONG*)data[0] != AES_128_KEY_SIZE && *(CK_ULONG*)data[0] != AES_192_KEY_SIZE && *(CK_ULONG*)data[0] != AES_256_KEY_SIZE) { ret = BAD_FUNC_ARG; From 76d4a4e43e4171bba3ca9e8592f0a16b1e70e767 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Thu, 24 Jul 2025 14:42:58 +0200 Subject: [PATCH 33/50] Implement CKM_SHA1_RSA_PKCS and CKM_SHA1_RSA_PKCS_PSS --- src/crypto.c | 36 ++++++++++++++++++++++++++++++++++++ src/internal.c | 5 +++++ src/slot.c | 12 ++++++++++++ wolfpkcs11/pkcs11.h | 2 ++ 4 files changed, 55 insertions(+) diff --git a/src/crypto.c b/src/crypto.c index 15f85788..5f4e63ca 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -4064,6 +4064,12 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, } init = WP11_INIT_RSA_X_509_SIGN; break; + #ifndef NO_SHA + case CKM_SHA1_RSA_PKCS: + if (init == 0) + init = WP11_INIT_SHA1; + FALL_THROUGH; + #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS: #endif @@ -4086,6 +4092,12 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, init |= WP11_INIT_RSA_PKCS_SIGN; break; #ifdef WC_RSA_PSS + #ifndef NO_SHA256 + case CKM_SHA1_RSA_PKCS_PSS: + if (init == 0) + init = WP11_INIT_SHA1; + FALL_THROUGH; + #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS_PSS: #endif @@ -4342,6 +4354,9 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, *pulSignatureLen = sigLen; break; #endif + #ifndef NO_SHA + case CKM_SHA1_RSA_PKCS: + #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS: #endif @@ -4402,6 +4417,9 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, break; } #ifdef WC_RSA_PSS + #ifndef NO_SHA + case CKM_SHA1_RSA_PKCS_PSS: + #endif #ifndef NO_SHA256 case CKM_SHA256_RSA_PKCS_PSS: #endif @@ -5067,6 +5085,12 @@ CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, } init = WP11_INIT_RSA_X_509_VERIFY; break; + #ifndef NO_SHA + case CKM_SHA1_RSA_PKCS: + if (init == 0) + init = WP11_INIT_SHA1; + FALL_THROUGH; + #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS: #endif @@ -5089,6 +5113,12 @@ CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, init |= WP11_INIT_RSA_PKCS_VERIFY; break; #ifdef WC_RSA_PSS + #ifndef NO_SHA + case CKM_SHA1_RSA_PKCS_PSS: + if (init == 0) + init = WP11_INIT_SHA1; + FALL_THROUGH; + #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS_PSS: #endif @@ -5327,6 +5357,9 @@ CK_RV C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, (int)ulDataLen, &stat, obj); break; #endif + #ifndef NO_SHA + case CKM_SHA1_RSA_PKCS: + #endif #ifndef NO_SHA256 case CKM_SHA256_RSA_PKCS: #endif @@ -5378,6 +5411,9 @@ CK_RV C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, break; } #ifdef WC_RSA_PSS + #ifndef NO_SHA + case CKM_SHA1_RSA_PKCS_PSS: + #endif #ifndef NO_SHA256 case CKM_SHA256_RSA_PKCS_PSS: #endif diff --git a/src/internal.c b/src/internal.c index 836d88ff..6b8e53f9 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6371,6 +6371,11 @@ static int MechanismToHash(int mechanism) #endif #endif #ifndef NO_RSA +#ifndef NO_SHA + case CKM_SHA1_RSA_PKCS: + case CKM_SHA1_RSA_PKCS_PSS: + return WP11_INIT_SHA1; +#endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS: case CKM_SHA224_RSA_PKCS_PSS: diff --git a/src/slot.c b/src/slot.c index 39489173..7d59ecbc 100644 --- a/src/slot.c +++ b/src/slot.c @@ -306,6 +306,9 @@ static CK_MECHANISM_TYPE mechanismList[] = { CKM_RSA_PKCS_KEY_PAIR_GEN, #endif CKM_RSA_X_509, +#ifndef NO_SHA + CKM_SHA1_RSA_PKCS, +#endif CKM_RSA_PKCS, #ifdef WOLFSSL_SHA224 CKM_SHA224_RSA_PKCS, @@ -324,6 +327,9 @@ static CK_MECHANISM_TYPE mechanismList[] = { #endif #ifdef WC_RSA_PSS CKM_RSA_PKCS_PSS, +#ifndef NO_SHA + CKM_SHA1_RSA_PKCS, +#endif #ifdef WOLFSSL_SHA224 CKM_SHA224_RSA_PKCS_PSS, #endif @@ -853,6 +859,9 @@ CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, XMEMCPY(pInfo, &rsaOaepMechInfo, sizeof(CK_MECHANISM_INFO)); break; #endif + #ifndef NO_SHA + case CKM_SHA1_RSA_PKCS: + #endif #ifndef NO_SHA256 case CKM_SHA256_RSA_PKCS: #endif @@ -871,6 +880,9 @@ CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, case CKM_RSA_PKCS_PSS: XMEMCPY(pInfo, &rsaPssMechInfo, sizeof(CK_MECHANISM_INFO)); break; + #ifndef NO_SHA + case CKM_SHA1_RSA_PKCS_PSS: + #endif #ifndef NO_SHA256 case CKM_SHA256_RSA_PKCS_PSS: #endif diff --git a/wolfpkcs11/pkcs11.h b/wolfpkcs11/pkcs11.h index f66e68bf..c7a628ff 100644 --- a/wolfpkcs11/pkcs11.h +++ b/wolfpkcs11/pkcs11.h @@ -256,8 +256,10 @@ extern "C" { #define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000UL #define CKM_RSA_PKCS 0x00000001UL #define CKM_RSA_X_509 0x00000003UL +#define CKM_SHA1_RSA_PKCS 0x00000006UL #define CKM_RSA_PKCS_OAEP 0x00000009UL #define CKM_RSA_PKCS_PSS 0x0000000DUL +#define CKM_SHA1_RSA_PKCS_PSS 0x0000000EUL #define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020UL #define CKM_DH_PKCS_DERIVE 0x00000021UL #define CKM_SHA256_RSA_PKCS 0x00000040UL From 41d3f403e989d7d2cdbe74973365b470e61d4802 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Thu, 24 Jul 2025 18:07:04 +0200 Subject: [PATCH 34/50] Fix WP11_Rsa_Verify_Recover No longer returns the length but for now NSS doesn't use it to check length --- src/internal.c | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/src/internal.c b/src/internal.c index 6b8e53f9..854942c0 100644 --- a/src/internal.c +++ b/src/internal.c @@ -10003,38 +10003,26 @@ int WP11_Rsa_Verify_Recover(CK_MECHANISM_TYPE mechanism, unsigned char* sig, CK_ULONG_PTR outLen, WP11_Object* pub) { int ret; - byte* data_out = NULL; switch (mechanism) { case CKM_RSA_PKCS: - ret = wc_RsaSSL_VerifyInline(sig, sigLen, &data_out, - pub->data.rsaKey); + ret = wc_RsaSSL_Verify(sig, sigLen, out, (word32)*outLen, + &pub->data.rsaKey); + if (ret == RSA_BUFFER_E) + return CKR_BUFFER_TOO_SMALL; if (ret < 0) - return ret; + return CKR_FUNCTION_FAILED; *outLen = ret; - if (out == NULL) { - return CKR_OK; - } - else { - if (*outLen < (CK_ULONG)ret) { - return CKR_BUFFER_TOO_SMALL; - } - else { - XMEMCPY(out, data_out, ret); - } - } break; - case CKM_RSA_X_509: - { + case CKM_RSA_X_509: { + byte* data_out = NULL; byte* pos; - - ret = wc_RsaDirect(sig, sigLen, out, (word32*)outLen, - pub->data.rsaKey, RSA_PUBLIC_DECRYPT, NULL); + ret = wc_RsaDirect(sig, sigLen, out, (word32*)outLen, + &pub->data.rsaKey, RSA_PUBLIC_DECRYPT, NULL); if (ret < 0) - return ret; - + return CKR_FUNCTION_FAILED; /* Result is front padded with 0x00 */ for (pos = out; pos < out + *outLen; pos++) { if (*pos != 0x00) { From 6cea762351e927382f1c823adddd9c07d682eebc Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Thu, 24 Jul 2025 19:04:45 +0200 Subject: [PATCH 35/50] Increase dh key size --- src/internal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/internal.c b/src/internal.c index 854942c0..79a9a1e3 100644 --- a/src/internal.c +++ b/src/internal.c @@ -101,7 +101,11 @@ #define RNG_SEED_SZ 32 /* Maximum size of storage for generated/derived DH key. */ +#ifdef WOLFPKCS11_NSS +#define WP11_MAX_DH_KEY_SZ (8192/8) +#else #define WP11_MAX_DH_KEY_SZ (4096/8) +#endif /* Maximum size of storage for generated/derived symmetric key. */ #ifdef WOLFPKCS11_NSS From 539571dfa08a394a086ddd28eccd3b90300f7eb9 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Tue, 29 Jul 2025 11:56:38 +0200 Subject: [PATCH 36/50] remove fall_through Disabling SHA3 causes the following ``` In file included from lib/wolfssl/wolfssl/wolfcrypt/error-crypt.h:34, from lib/wolfPKCS11/src/crypto.c:33: lib/wolfPKCS11/src/crypto.c: In function 'C_SignInit': lib/wolfssl/wolfssl/wolfcrypt/types.h:446:36: error: attribute 'fallthrough' not preceding a case label or default label [-Werror] 446 | #define FALL_THROUGH ; __attribute__ ((fallthrough)) | ^~~~~~~~~~~~~ lib/wolfPKCS11/src/crypto.c:4000:13: note: in expansion of macro 'FALL_THROUGH' 4000 | FALL_THROUGH; | ^~~~~~~~~~~~ lib/wolfPKCS11/src/crypto.c: In function 'C_VerifyInit': lib/wolfssl/wolfssl/wolfcrypt/types.h:446:36: error: attribute 'fallthrough' not preceding a case label or default label [-Werror] 446 | #define FALL_THROUGH ; __attribute__ ((fallthrough)) | ^~~~~~~~~~~~~ lib/wolfPKCS11/src/crypto.c:5019:13: note: in expansion of macro 'FALL_THROUGH' 5019 | FALL_THROUGH; ``` --- src/crypto.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 5f4e63ca..d72a3c57 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -3893,6 +3893,10 @@ static int CKM_TLS_MAC_init(CK_KEY_TYPE type, CK_MECHANISM_PTR pMechanism, static int GetInitValue(CK_MECHANISM_TYPE mechanism) { switch (mechanism) { #ifndef NO_RSA +#ifndef NO_SHA + case CKM_SHA1_RSA_PKCS: + return WP11_INIT_SHA1; +#endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS: return WP11_INIT_SHA224; @@ -3910,6 +3914,10 @@ static int GetInitValue(CK_MECHANISM_TYPE mechanism) { return WP11_INIT_SHA512; #endif #ifdef WC_RSA_PSS +#ifndef NO_SHA + case CKM_SHA1_RSA_PKCS_PSS: + return WP11_INIT_SHA1; +#endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS_PSS: return WP11_INIT_SHA224; @@ -4005,9 +4013,6 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, WP11_Object* obj = NULL; CK_KEY_TYPE type; int init = 0; -#ifndef NO_HMAC - CK_ULONG digestSize = 0; -#endif CK_RV rv; WOLFPKCS11_ENTER("C_SignInit"); @@ -4066,9 +4071,6 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, break; #ifndef NO_SHA case CKM_SHA1_RSA_PKCS: - if (init == 0) - init = WP11_INIT_SHA1; - FALL_THROUGH; #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS: @@ -4092,11 +4094,8 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, init |= WP11_INIT_RSA_PKCS_SIGN; break; #ifdef WC_RSA_PSS - #ifndef NO_SHA256 + #ifndef NO_SHA case CKM_SHA1_RSA_PKCS_PSS: - if (init == 0) - init = WP11_INIT_SHA1; - FALL_THROUGH; #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS_PSS: @@ -4420,12 +4419,12 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, #ifndef NO_SHA case CKM_SHA1_RSA_PKCS_PSS: #endif - #ifndef NO_SHA256 - case CKM_SHA256_RSA_PKCS_PSS: - #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS_PSS: #endif + #ifndef NO_SHA256 + case CKM_SHA256_RSA_PKCS_PSS: + #endif #ifdef WOLFSSL_SHA384 case CKM_SHA384_RSA_PKCS_PSS: #endif @@ -5087,9 +5086,6 @@ CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, break; #ifndef NO_SHA case CKM_SHA1_RSA_PKCS: - if (init == 0) - init = WP11_INIT_SHA1; - FALL_THROUGH; #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS: @@ -5115,9 +5111,6 @@ CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, #ifdef WC_RSA_PSS #ifndef NO_SHA case CKM_SHA1_RSA_PKCS_PSS: - if (init == 0) - init = WP11_INIT_SHA1; - FALL_THROUGH; #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS_PSS: @@ -5414,12 +5407,12 @@ CK_RV C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, #ifndef NO_SHA case CKM_SHA1_RSA_PKCS_PSS: #endif - #ifndef NO_SHA256 - case CKM_SHA256_RSA_PKCS_PSS: - #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS_PSS: #endif + #ifndef NO_SHA256 + case CKM_SHA256_RSA_PKCS_PSS: + #endif #ifdef WOLFSSL_SHA384 case CKM_SHA384_RSA_PKCS_PSS: #endif From d2346c243daefdb743f08113e21beab9ea1f3fe2 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 29 Jul 2025 16:25:17 +0200 Subject: [PATCH 37/50] Fix CheckOpSupported return type --- src/crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto.c b/src/crypto.c index d72a3c57..97007ae7 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -339,7 +339,7 @@ static CK_RV CheckAttributes(CK_ATTRIBUTE* pTemplate, CK_ULONG ulCount, int set) return CKR_OK; } -static CK_RV CheckOpSupported(WP11_Object* obj, CK_ATTRIBUTE_TYPE op) +static int CheckOpSupported(WP11_Object* obj, CK_ATTRIBUTE_TYPE op) { CK_BBOOL haveOp = 0; CK_ULONG dataLen = sizeof(haveOp); From 15a927f25a330fc19d27f6961cea4dbbf93c30f9 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Wed, 30 Jul 2025 01:02:59 +0200 Subject: [PATCH 38/50] Fix most of pkcs11test --- src/crypto.c | 6 +++++- tests/pkcs11test.c | 12 ++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 97007ae7..42e849f0 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -431,6 +431,10 @@ static CK_RV SetAttributeDefaults(WP11_Object* obj, CK_OBJECT_CLASS keyType, derive = CK_FALSE; break; */ + case CKK_RSA: + derive = CK_FALSE; + sign = CK_TRUE; + break; case CKK_DH: verify = CK_FALSE; derive = CK_TRUE; @@ -440,7 +444,7 @@ static CK_RV SetAttributeDefaults(WP11_Object* obj, CK_OBJECT_CLASS keyType, break; case CKK_EC: derive = CK_FALSE; - verify = CK_FALSE; + verify = CK_TRUE; encrypt = CK_FALSE; recover = CK_FALSE; wrap = CK_FALSE; diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index ca270b0e..f877105b 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -7254,14 +7254,14 @@ static CK_RV test_rsa_pkcs_sig_fail(void* args) } if (ret == CKR_OK) { mech.pParameter = data; - ret = funcList->C_VerifyInit(session, &mech, priv); + ret = funcList->C_VerifyInit(session, &mech, pub); CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, "Verify Init bad parameter"); mech.pParameter = NULL; } if (ret == CKR_OK) { mech.ulParameterLen = 1; - ret = funcList->C_VerifyInit(session, &mech, priv); + ret = funcList->C_VerifyInit(session, &mech, pub); CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, "Verify Init bad parameter length"); mech.ulParameterLen = 0; @@ -7323,28 +7323,28 @@ static CK_RV test_rsa_pkcs_pss_sig_fail(void* args) } if (ret == CKR_OK) { mech.pParameter = NULL; - ret = funcList->C_VerifyInit(session, &mech, priv); + ret = funcList->C_VerifyInit(session, &mech, pub); CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, "Verify Init NULL parameter"); mech.pParameter = ¶ms; } if (ret == CKR_OK) { mech.ulParameterLen = 0; - ret = funcList->C_VerifyInit(session, &mech, priv); + ret = funcList->C_VerifyInit(session, &mech, pub); CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, "Verify Init bad parameter length"); mech.ulParameterLen = sizeof(params); } if (ret == CKR_OK) { params.hashAlg = CKM_RSA_PKCS; - ret = funcList->C_VerifyInit(session, &mech, priv); + ret = funcList->C_VerifyInit(session, &mech, pub); CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, "Verify Init bad hash algorithm"); params.hashAlg = CKM_SHA256; } if (ret == CKR_OK) { params.mgf = 0; - ret = funcList->C_VerifyInit(session, &mech, priv); + ret = funcList->C_VerifyInit(session, &mech, pub); CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, "Verify Init bad mgf algorithm"); params.mgf = CKG_MGF1_SHA256; From 07b906a66952aec1b4bc05721c74f170f74a9182 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 30 Jul 2025 10:47:47 +0200 Subject: [PATCH 39/50] Fix aes failures --- tests/pkcs11test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index f877105b..c278de96 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -3981,6 +3981,8 @@ static CK_RV get_aes_128_key(CK_SESSION_HANDLE session, unsigned char* id, #endif { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, #ifndef NO_AES { CKA_VALUE, aes_128_key, sizeof(aes_128_key) }, #endif From c078b1349785f87a6722b6fd51d50dd09e1f7278 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 30 Jul 2025 11:20:35 +0200 Subject: [PATCH 40/50] Add verify to priv key --- tests/pkcs11mtt.c | 1 + tests/pkcs11test.c | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/pkcs11mtt.c b/tests/pkcs11mtt.c index d3e57215..c58cea02 100644 --- a/tests/pkcs11mtt.c +++ b/tests/pkcs11mtt.c @@ -2044,6 +2044,7 @@ static CK_RV get_rsa_priv_key(CK_SESSION_HANDLE session, unsigned char* privId, { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) }, { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, { CKA_MODULUS, rsa_2048_modulus, sizeof(rsa_2048_modulus) }, { CKA_PRIVATE_EXPONENT, rsa_2048_priv_exp, sizeof(rsa_2048_priv_exp) }, { CKA_PRIME_1, rsa_2048_p, sizeof(rsa_2048_p) }, diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index c278de96..1370afb1 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -5540,6 +5540,7 @@ static CK_RV get_rsa_priv_key(CK_SESSION_HANDLE session, unsigned char* privId, { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) }, { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, { CKA_MODULUS, rsa_2048_modulus, sizeof(rsa_2048_modulus) }, { CKA_PRIVATE_EXPONENT, rsa_2048_priv_exp, sizeof(rsa_2048_priv_exp) }, { CKA_PRIME_1, rsa_2048_p, sizeof(rsa_2048_p) }, From 92ea343652841ce5b1e43e57da1e4d67e696c660 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 30 Jul 2025 11:43:46 +0200 Subject: [PATCH 41/50] clang fixes --- src/crypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 42e849f0..2518fbb0 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -4585,7 +4585,7 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, if (ret != CKR_OK || pSignature == NULL) return ret; - sigLen = *pulSignatureLen; + sigLen = (word32)*pulSignatureLen; ret = WP11_Aes_Cmac_Sign(pData, (word32)ulDataLen, pSignature, &sigLen, session); *pulSignatureLen = sigLen; @@ -4861,7 +4861,7 @@ CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, if (ret != CKR_OK || pSignature == NULL) return ret; - sigLen = *pulSignatureLen; + sigLen = (word32)*pulSignatureLen; ret = WP11_Aes_Cmac_Sign_Final(pSignature, &sigLen, session); *pulSignatureLen = sigLen; break; From d94f0e5883f2ae12dba8996ee426b294f7e1262e Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 30 Jul 2025 13:54:49 +0200 Subject: [PATCH 42/50] Fix msan errors --- src/internal.c | 1 + tests/pkcs11test.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/internal.c b/src/internal.c index 79a9a1e3..2fd95896 100644 --- a/src/internal.c +++ b/src/internal.c @@ -8663,6 +8663,7 @@ static int GetEcbCheckValue(WP11_Object* secret, byte* dataOut, } XFREE(hash, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(input, NULL, DYNAMIC_TYPE_TMP_BUFFER); return CKR_OK; } diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index 1370afb1..c9eddb53 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -10816,6 +10816,7 @@ static CK_RV test_aes_ccm_encdec(CK_SESSION_HANDLE session, encSz = sizeof(enc); decSz = sizeof(dec); + ccmParams.ulDataLen = 0; ccmParams.pIv = iv; ccmParams.ulIvLen = sizeof(iv); ccmParams.pAAD = aad; From 9cf48ee3868ade2b7a8d0692127d0d5cc170df2e Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Wed, 30 Jul 2025 15:10:59 +0100 Subject: [PATCH 43/50] Fix CKO_DATA storage for TPM Length calculation was incorrect, causing an error. In addition, lengths for arrays were double-stored. --- src/internal.c | 131 +++++++++++++++++++------------------------------ 1 file changed, 50 insertions(+), 81 deletions(-) diff --git a/src/internal.c b/src/internal.c index 2fd95896..6fb8258e 100644 --- a/src/internal.c +++ b/src/internal.c @@ -939,6 +939,15 @@ static int wolfPKCS11_Store_GetMaxSize(int type, int variableSz) variableSz /* keyIdLen + labelLen + issuerLen + serialLen + subjectLen */ ; break; + case WOLFPKCS11_STORE_DATA: + maxSz = + sizeof(word32) /* id */ + + sizeof(word32) /* dataLen */ + + sizeof(word32) /* applicationLen */ + + sizeof(word32) /* objectIdLen */ + + variableSz /* dataLen + applicationLen + objectIdLen */ + ; + break; case WOLFPKCS11_STORE_SYMMKEY: case WOLFPKCS11_STORE_RSAKEY_PRIV: case WOLFPKCS11_STORE_RSAKEY_PUB: @@ -948,7 +957,6 @@ static int wolfPKCS11_Store_GetMaxSize(int type, int variableSz) case WOLFPKCS11_STORE_DHKEY_PUB: case WOLFPKCS11_STORE_CERT: case WOLFPKCS11_STORE_TRUST: - case WOLFPKCS11_STORE_DATA: maxSz = sizeof(word32) + variableSz; break; @@ -2639,61 +2647,30 @@ static int wp11_Object_Load_Data(WP11_Object* object, int tokenId, int objId) ret = wp11_storage_open_readonly(WOLFPKCS11_STORE_DATA, tokenId, objId, &storage); if (ret == 0) { - /* Read data length and data. */ - ret = wp11_storage_read_word32(storage, - &object->data.genericData.dataLen); - if (ret == 0 && object->data.genericData.dataLen > 0) { - tempLen = (int)object->data.genericData.dataLen; - ret = wp11_storage_read_alloc_array(storage, - &object->data.genericData.data, - &tempLen); - object->data.genericData.dataLen = (word32)tempLen; - } - else if (ret == 0) { - /* Ensure data is NULL when length is 0 */ - object->data.genericData.data = NULL; - object->data.genericData.dataLen = 0; - } - - /* Read application length and application. */ - if (ret == 0) { - ret = wp11_storage_read_word32(storage, - &object->data.genericData.applicationLen); - } - if (ret == 0 && object->data.genericData.applicationLen > 0) { - tempLen = (int)object->data.genericData.applicationLen; - ret = wp11_storage_read_alloc_array(storage, - &object->data.genericData.application, - &tempLen); - object->data.genericData.applicationLen = (word32)tempLen; - } - else if (ret == 0) { - /* Ensure application is NULL when length is 0 */ - object->data.genericData.application = NULL; - object->data.genericData.applicationLen = 0; - } + ret = wp11_storage_read_alloc_array(storage, + &object->data.genericData.data, + &tempLen); + object->data.genericData.dataLen = (word32)tempLen; + } - /* Read object ID length and object ID. */ - if (ret == 0) { - ret = wp11_storage_read_word32(storage, - &object->data.genericData.objectIdLen); - } - if (ret == 0 && object->data.genericData.objectIdLen > 0) { - tempLen = (int)object->data.genericData.objectIdLen; - ret = wp11_storage_read_alloc_array(storage, - &object->data.genericData.objectId, - &tempLen); - object->data.genericData.objectIdLen = (word32)tempLen; - } - else if (ret == 0) { - /* Ensure objectId is NULL when length is 0 */ - object->data.genericData.objectId = NULL; - object->data.genericData.objectIdLen = 0; - } + /* Read application length and application. */ + if (ret == 0) { + ret = wp11_storage_read_alloc_array(storage, + &object->data.genericData.application, + &tempLen); + object->data.genericData.applicationLen = (word32)tempLen; + } - wp11_storage_close(storage); + /* Read object ID length and object ID. */ + if (ret == 0) { + ret = wp11_storage_read_alloc_array(storage, + &object->data.genericData.objectId, + &tempLen); + object->data.genericData.objectIdLen = (word32)tempLen; } + wp11_storage_close(storage); + return ret; } @@ -3179,44 +3156,36 @@ static int wp11_Object_Store_Data(WP11_Object* object, int tokenId, int objId) int ret; void* storage = NULL; + int variableSz = (object->data.genericData.dataLen + + object->data.genericData.applicationLen + + object->data.genericData.objectIdLen); + /* Open access to data. */ ret = wp11_storage_open(WOLFPKCS11_STORE_DATA, tokenId, objId, - sizeof(WP11_GenericData), &storage); + variableSz, &storage); + /* Write data length and data. */ if (ret == 0) { - /* Write data length and data. */ - ret = wp11_storage_write_word32(storage, + ret = wp11_storage_write_array(storage, + object->data.genericData.data, object->data.genericData.dataLen); - if (ret == 0 && object->data.genericData.dataLen > 0) { - ret = wp11_storage_write_array(storage, - object->data.genericData.data, - object->data.genericData.dataLen); - } + } - /* Write application length and application. */ - if (ret == 0) { - ret = wp11_storage_write_word32(storage, - object->data.genericData.applicationLen); - } - if (ret == 0 && object->data.genericData.applicationLen > 0) { - ret = wp11_storage_write_array(storage, - object->data.genericData.application, - object->data.genericData.applicationLen); - } + /* Write application length and application. */ + if (ret == 0) { + ret = wp11_storage_write_array(storage, + object->data.genericData.application, + object->data.genericData.applicationLen); + } /* Write object ID length and object ID. */ - if (ret == 0) { - ret = wp11_storage_write_word32(storage, - object->data.genericData.objectIdLen); - } - if (ret == 0 && object->data.genericData.objectIdLen > 0) { - ret = wp11_storage_write_array(storage, - object->data.genericData.objectId, - object->data.genericData.objectIdLen); - } - - wp11_storage_close(storage); + if (ret == 0) { + ret = wp11_storage_write_array(storage, + object->data.genericData.objectId, + object->data.genericData.objectIdLen); } + wp11_storage_close(storage); + return ret; } From 8d1e4ea0f312f3f38265eda2fc62380c107d479a Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 30 Jul 2025 18:40:48 +0200 Subject: [PATCH 44/50] Simplify copying ecc keys --- src/internal.c | 49 ++++++------------------------------------------- 1 file changed, 6 insertions(+), 43 deletions(-) diff --git a/src/internal.c b/src/internal.c index 6fb8258e..8cdceb07 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2337,7 +2337,6 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) case CKK_EC: { byte* derBuf = NULL; int derSz = 0; - int initialDerSz = 0; /* Initialize destination ECC key */ ret = wc_ecc_init_ex(&dest->data.ecKey, NULL, @@ -2347,28 +2346,13 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) /* Determine if this is a private or public key and get DER * size */ - if (src->objClass == CKO_PRIVATE_KEY) { - initialDerSz = wc_EccPrivateKeyToDer(&src->data.ecKey, - NULL, 0); - } - else { - initialDerSz = wc_EccPublicKeyToDer(&src->data.ecKey, - NULL, 0, 1); - } + if (src->objClass == CKO_PRIVATE_KEY) + derSz = wc_EccKeyDerSize(&src->data.ecKey, 0); + else + derSz = wc_EccPublicKeyDerSize(&src->data.ecKey, 1); - /* Handle different return values for size estimation */ - if (initialDerSz == LENGTH_ONLY_E || initialDerSz == 0) { - /* wolfSSL 5.6.6 compatibility */ - derSz = 256; /* Conservative estimate for ECC key DER */ - ret = 0; - } - else if (initialDerSz > 0) { - derSz = initialDerSz; - ret = 0; - } - else { - ret = initialDerSz; /* Pass through the error */ - } + if (derSz < 0) + ret = derSz; /* Allocate buffer with retry logic */ if (ret == 0) { @@ -2389,27 +2373,6 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) derSz, 1); } - /* Handle buffer too small case */ - if (ret == BUFFER_E && derSz < 1024) { - /* Reallocate buffer with larger size */ - derSz = 1024; /* Larger buffer size */ - derBuf = (byte*)XREALLOC(derBuf, derSz, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (derBuf == NULL) { - ret = MEMORY_E; - } - else { - if (src->objClass == CKO_PRIVATE_KEY) { - ret = wc_EccPrivateKeyToDer(&src->data.ecKey, - derBuf, derSz); - } - else { - ret = wc_EccPublicKeyToDer(&src->data.ecKey, - derBuf, derSz, 1); - } - } - } - /* Normalize positive return to success */ if (ret > 0) { derSz = ret; /* Update actual size used */ From 506c24f4c5a60c1753213287a704a8fe0503c379 Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Wed, 30 Jul 2025 18:50:45 +0100 Subject: [PATCH 45/50] Fix object copy for TPM --- src/internal.c | 302 +++++++++++++++++++++++++++++-------------------- 1 file changed, 182 insertions(+), 120 deletions(-) diff --git a/src/internal.c b/src/internal.c index 8cdceb07..eec69137 100644 --- a/src/internal.c +++ b/src/internal.c @@ -100,6 +100,8 @@ /* Length of seed from global random to seed local random. */ #define RNG_SEED_SZ 32 + + /* Maximum size of storage for generated/derived DH key. */ #ifdef WOLFPKCS11_NSS #define WP11_MAX_DH_KEY_SZ (8192/8) @@ -2244,6 +2246,12 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) OBJ_COPY_DATA(src, dest, keyData); XMEMCPY(dest->iv, src->iv, sizeof(dest->iv)); dest->encoded = src->encoded; +#endif +#ifdef WOLFPKCS11_TPM + /* For TPM keys, copy keyData */ + if (src->opFlag & WP11_FLAG_TPM) { + OBJ_COPY_DATA(src, dest, keyData); + } #endif dest->objClass = src->objClass; dest->keyGenMech = src->keyGenMech; @@ -2267,162 +2275,216 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) } #endif else { - switch (src->type) { -#ifndef NO_RSA - case CKK_RSA: { - byte* derBuf = NULL; - int derSz = 0; - - /* Initialize destination RSA key */ - ret = wc_InitRsaKey_ex(&dest->data.rsaKey, NULL, - dest->slot->devId); - if (ret != 0) - break; +#ifdef WOLFPKCS11_TPM + /* Handle TPM keys - copy tpmKey structure directly */ + if (src->opFlag & WP11_FLAG_TPM) { + /* Copy the TPM key blob structure directly */ + XMEMCPY(&dest->tpmKey, &src->tpmKey, sizeof(WOLFTPM2_KEYBLOB)); - /* Determine if this is a private or public key and get DER - * size */ - if (src->objClass == CKO_PRIVATE_KEY) { - ret = wc_RsaKeyToDer(&src->data.rsaKey, NULL, 0); - } - else { - ret = wc_RsaKeyToPublicDer(&src->data.rsaKey, NULL, 0); - } + /* Initialize TPM handle to NULL for the destination */ + dest->tpmKey.handle.hndl = TPM_RH_NULL; - if (ret == 0) /* Should not happen */ - ret = BUFFER_E; - if (ret > 0) { - derSz = ret; + /* Initialize the wolf key structures based on key type */ + switch (src->type) { +#ifndef NO_RSA + case CKK_RSA: + ret = wc_InitRsaKey_ex(&dest->data.rsaKey, NULL, + dest->slot->devId); + break; +#endif +#ifdef HAVE_ECC + case CKK_EC: + ret = wc_ecc_init_ex(&dest->data.ecKey, NULL, + dest->slot->devId); + break; +#endif + default: ret = 0; + break; + } + /* Populate wolf key structures from copied tpmKey */ + if (ret == 0) { + switch (src->type) { +#ifndef NO_RSA + case CKK_RSA: + /* Load public portion into wolf RsaKey structure */ + ret = wolfTPM2_RsaKey_TpmToWolf(&dest->slot->tpmDev, + (WOLFTPM2_KEY*)&dest->tpmKey, &dest->data.rsaKey); + break; +#endif +#ifdef HAVE_ECC + case CKK_EC: + /* Load public portion into wolf EccKey structure */ + ret = wolfTPM2_EccKey_TpmToWolf(&dest->slot->tpmDev, + (WOLFTPM2_KEY*)&dest->tpmKey, &dest->data.ecKey); + break; +#endif + default: + /* For other key types, no decode needed */ + break; } - if (ret == 0) { - derBuf = (byte*)XMALLOC(derSz, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (derBuf == NULL) - ret = MEMORY_E; - } - if (ret == 0) { - /* Encode the source key to DER */ + } + } + else +#endif + { + switch (src->type) { +#ifndef NO_RSA + case CKK_RSA: { + byte* derBuf = NULL; + int derSz = 0; + + /* Initialize destination RSA key */ + ret = wc_InitRsaKey_ex(&dest->data.rsaKey, NULL, + dest->slot->devId); + if (ret != 0) + break; + + /* Determine if this is a private or public key and get DER + * size */ if (src->objClass == CKO_PRIVATE_KEY) { - ret = wc_RsaKeyToDer(&src->data.rsaKey, derBuf, derSz); + ret = wc_RsaKeyToDer(&src->data.rsaKey, NULL, 0); } else { - ret = wc_RsaKeyToPublicDer(&src->data.rsaKey, derBuf, - derSz); + ret = wc_RsaKeyToPublicDer(&src->data.rsaKey, NULL, 0); } + if (ret == 0) /* Should not happen */ ret = BUFFER_E; - if (ret > 0) + if (ret > 0) { + derSz = ret; ret = 0; - } - if (ret == 0) { - /* Decode the DER data into the destination key */ - word32 idx = 0; - if (src->objClass == CKO_PRIVATE_KEY) { - ret = wc_RsaPrivateKeyDecode(derBuf, &idx, - &dest->data.rsaKey, - (word32)derSz); } - else { - ret = wc_RsaPublicKeyDecode(derBuf, &idx, - &dest->data.rsaKey, - (word32)derSz); + if (ret == 0) { + derBuf = (byte*)XMALLOC(derSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) + ret = MEMORY_E; + } + if (ret == 0) { + /* Encode the source key to DER */ + if (src->objClass == CKO_PRIVATE_KEY) { + ret = wc_RsaKeyToDer(&src->data.rsaKey, derBuf, derSz); + } + else { + ret = wc_RsaKeyToPublicDer(&src->data.rsaKey, derBuf, + derSz); + } + if (ret == 0) /* Should not happen */ + ret = BUFFER_E; + if (ret > 0) + ret = 0; + } + if (ret == 0) { + /* Decode the DER data into the destination key */ + word32 idx = 0; + if (src->objClass == CKO_PRIVATE_KEY) { + ret = wc_RsaPrivateKeyDecode(derBuf, &idx, + &dest->data.rsaKey, + (word32)derSz); + } + else { + ret = wc_RsaPublicKeyDecode(derBuf, &idx, + &dest->data.rsaKey, + (word32)derSz); + } } - } - XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - break; - } + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + break; + } #endif #ifdef HAVE_ECC - case CKK_EC: { - byte* derBuf = NULL; - int derSz = 0; + case CKK_EC: { + byte* derBuf = NULL; + int derSz = 0; + + /* Initialize destination ECC key */ + ret = wc_ecc_init_ex(&dest->data.ecKey, NULL, + dest->slot->devId); + if (ret != 0) + break; - /* Initialize destination ECC key */ - ret = wc_ecc_init_ex(&dest->data.ecKey, NULL, - dest->slot->devId); - if (ret != 0) - break; + /* Determine if this is a private or public key and get DER + * size */ + if (src->objClass == CKO_PRIVATE_KEY) + derSz = wc_EccKeyDerSize(&src->data.ecKey, 0); + else + derSz = wc_EccPublicKeyDerSize(&src->data.ecKey, 1); - /* Determine if this is a private or public key and get DER - * size */ - if (src->objClass == CKO_PRIVATE_KEY) - derSz = wc_EccKeyDerSize(&src->data.ecKey, 0); - else - derSz = wc_EccPublicKeyDerSize(&src->data.ecKey, 1); + if (derSz < 0) + ret = derSz; - if (derSz < 0) - ret = derSz; + /* Allocate buffer with retry logic */ + if (ret == 0) { + derBuf = (byte*)XMALLOC(derSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) + ret = MEMORY_E; + } - /* Allocate buffer with retry logic */ - if (ret == 0) { - derBuf = (byte*)XMALLOC(derSz, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (derBuf == NULL) - ret = MEMORY_E; - } + if (ret == 0) { + /* Encode the source key to DER with retry logic */ + if (src->objClass == CKO_PRIVATE_KEY) { + ret = wc_EccPrivateKeyToDer(&src->data.ecKey, + derBuf, derSz); + } + else { + ret = wc_EccPublicKeyToDer(&src->data.ecKey, derBuf, + derSz, 1); + } - if (ret == 0) { - /* Encode the source key to DER with retry logic */ - if (src->objClass == CKO_PRIVATE_KEY) { - ret = wc_EccPrivateKeyToDer(&src->data.ecKey, derBuf, - derSz); - } - else { - ret = wc_EccPublicKeyToDer(&src->data.ecKey, derBuf, - derSz, 1); + /* Normalize positive return to success */ + if (ret > 0) { + derSz = ret; /* Update actual size used */ + ret = 0; + } } - /* Normalize positive return to success */ - if (ret > 0) { - derSz = ret; /* Update actual size used */ - ret = 0; + if (ret == 0) { + /* Decode the DER data into the destination key */ + word32 idx = 0; + if (src->objClass == CKO_PRIVATE_KEY) { + ret = wc_EccPrivateKeyDecode(derBuf, &idx, + &dest->data.ecKey, + (word32)derSz); + } + else { + ret = wc_EccPublicKeyDecode(derBuf, &idx, + &dest->data.ecKey, + (word32)derSz); + } } - } - if (ret == 0) { - /* Decode the DER data into the destination key */ - word32 idx = 0; - if (src->objClass == CKO_PRIVATE_KEY) { - ret = wc_EccPrivateKeyDecode(derBuf, &idx, - &dest->data.ecKey, - (word32)derSz); - } - else { - ret = wc_EccPublicKeyDecode(derBuf, &idx, - &dest->data.ecKey, - (word32)derSz); + /* Clean up */ + if (derBuf != NULL) { + XMEMSET(derBuf, 0, derSz); /* Clear sensitive data */ + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); } - } - /* Clean up */ - if (derBuf != NULL) { - XMEMSET(derBuf, 0, derSz); /* Clear sensitive data */ - XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - } + /* Free destination key on failure */ + if (ret != 0) { + wc_ecc_free(&dest->data.ecKey); + } - /* Free destination key on failure */ - if (ret != 0) { - wc_ecc_free(&dest->data.ecKey); + break; } - - break; - } #endif #ifndef NO_DH - case CKK_DH: - return BAD_FUNC_ARG; + case CKK_DH: + return BAD_FUNC_ARG; #endif #ifndef NO_AES - case CKK_AES: + case CKK_AES: #endif #ifdef WOLFPKCS11_HKDF - case CKK_HKDF: + case CKK_HKDF: #endif - case CKK_GENERIC_SECRET: - XMEMCPY(&dest->data.symmKey, &src->data.symmKey, - sizeof(dest->data.symmKey)); - break; + case CKK_GENERIC_SECRET: + XMEMCPY(&dest->data.symmKey, &src->data.symmKey, + sizeof(dest->data.symmKey)); + break; + } } } From 56a2a5913b0bd35064a781473afd51f83be70995 Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Mon, 4 Aug 2025 16:46:06 +0100 Subject: [PATCH 46/50] Fix PR for dynamically allocated keys --- src/crypto.c | 2 -- src/internal.c | 56 ++++++++++++++++++++++++++------------------------ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 2518fbb0..2391a538 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -1211,8 +1211,6 @@ CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, if (ret != 0) return CKR_FUNCTION_FAILED; - /* Use get and set attribute value to fill in object. */ - rv = C_GetAttributeValue(hSession, hObject, pTemplate, ulCount); /* copy all the attributes from the original object to the new object */ rv = WP11_Object_Copy(obj, newObj); if (rv != CKR_OK) { diff --git a/src/internal.c b/src/internal.c index eec69137..b071e254 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2282,19 +2282,19 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) XMEMCPY(&dest->tpmKey, &src->tpmKey, sizeof(WOLFTPM2_KEYBLOB)); /* Initialize TPM handle to NULL for the destination */ - dest->tpmKey.handle.hndl = TPM_RH_NULL; + dest->tpmKey->handle.hndl = TPM_RH_NULL; /* Initialize the wolf key structures based on key type */ switch (src->type) { #ifndef NO_RSA case CKK_RSA: - ret = wc_InitRsaKey_ex(&dest->data.rsaKey, NULL, + ret = wc_InitRsaKey_ex(dest->data.rsaKey, NULL, dest->slot->devId); break; #endif #ifdef HAVE_ECC case CKK_EC: - ret = wc_ecc_init_ex(&dest->data.ecKey, NULL, + ret = wc_ecc_init_ex(dest->data.ecKey, NULL, dest->slot->devId); break; #endif @@ -2309,14 +2309,14 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) case CKK_RSA: /* Load public portion into wolf RsaKey structure */ ret = wolfTPM2_RsaKey_TpmToWolf(&dest->slot->tpmDev, - (WOLFTPM2_KEY*)&dest->tpmKey, &dest->data.rsaKey); + (WOLFTPM2_KEY*)&dest->tpmKey, dest->data.rsaKey); break; #endif #ifdef HAVE_ECC case CKK_EC: /* Load public portion into wolf EccKey structure */ ret = wolfTPM2_EccKey_TpmToWolf(&dest->slot->tpmDev, - (WOLFTPM2_KEY*)&dest->tpmKey, &dest->data.ecKey); + (WOLFTPM2_KEY*)&dest->tpmKey, dest->data.ecKey); break; #endif default: @@ -2335,7 +2335,7 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) int derSz = 0; /* Initialize destination RSA key */ - ret = wc_InitRsaKey_ex(&dest->data.rsaKey, NULL, + ret = wc_InitRsaKey_ex(dest->data.rsaKey, NULL, dest->slot->devId); if (ret != 0) break; @@ -2343,10 +2343,10 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) /* Determine if this is a private or public key and get DER * size */ if (src->objClass == CKO_PRIVATE_KEY) { - ret = wc_RsaKeyToDer(&src->data.rsaKey, NULL, 0); + ret = wc_RsaKeyToDer(src->data.rsaKey, NULL, 0); } else { - ret = wc_RsaKeyToPublicDer(&src->data.rsaKey, NULL, 0); + ret = wc_RsaKeyToPublicDer(src->data.rsaKey, NULL, 0); } if (ret == 0) /* Should not happen */ @@ -2364,10 +2364,11 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) if (ret == 0) { /* Encode the source key to DER */ if (src->objClass == CKO_PRIVATE_KEY) { - ret = wc_RsaKeyToDer(&src->data.rsaKey, derBuf, derSz); + ret = wc_RsaKeyToDer(src->data.rsaKey, derBuf, + derSz); } else { - ret = wc_RsaKeyToPublicDer(&src->data.rsaKey, derBuf, + ret = wc_RsaKeyToPublicDer(src->data.rsaKey, derBuf, derSz); } if (ret == 0) /* Should not happen */ @@ -2380,12 +2381,12 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) word32 idx = 0; if (src->objClass == CKO_PRIVATE_KEY) { ret = wc_RsaPrivateKeyDecode(derBuf, &idx, - &dest->data.rsaKey, + dest->data.rsaKey, (word32)derSz); } else { ret = wc_RsaPublicKeyDecode(derBuf, &idx, - &dest->data.rsaKey, + dest->data.rsaKey, (word32)derSz); } } @@ -2400,7 +2401,7 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) int derSz = 0; /* Initialize destination ECC key */ - ret = wc_ecc_init_ex(&dest->data.ecKey, NULL, + ret = wc_ecc_init_ex(dest->data.ecKey, NULL, dest->slot->devId); if (ret != 0) break; @@ -2408,9 +2409,9 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) /* Determine if this is a private or public key and get DER * size */ if (src->objClass == CKO_PRIVATE_KEY) - derSz = wc_EccKeyDerSize(&src->data.ecKey, 0); + derSz = wc_EccKeyDerSize(src->data.ecKey, 0); else - derSz = wc_EccPublicKeyDerSize(&src->data.ecKey, 1); + derSz = wc_EccPublicKeyDerSize(src->data.ecKey, 1); if (derSz < 0) ret = derSz; @@ -2426,11 +2427,11 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) if (ret == 0) { /* Encode the source key to DER with retry logic */ if (src->objClass == CKO_PRIVATE_KEY) { - ret = wc_EccPrivateKeyToDer(&src->data.ecKey, + ret = wc_EccPrivateKeyToDer(src->data.ecKey, derBuf, derSz); } else { - ret = wc_EccPublicKeyToDer(&src->data.ecKey, derBuf, + ret = wc_EccPublicKeyToDer(src->data.ecKey, derBuf, derSz, 1); } @@ -2446,12 +2447,12 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) word32 idx = 0; if (src->objClass == CKO_PRIVATE_KEY) { ret = wc_EccPrivateKeyDecode(derBuf, &idx, - &dest->data.ecKey, + dest->data.ecKey, (word32)derSz); } else { ret = wc_EccPublicKeyDecode(derBuf, &idx, - &dest->data.ecKey, + dest->data.ecKey, (word32)derSz); } } @@ -2464,7 +2465,7 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) /* Free destination key on failure */ if (ret != 0) { - wc_ecc_free(&dest->data.ecKey); + wc_ecc_free(dest->data.ecKey); } break; @@ -2481,8 +2482,9 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) case CKK_HKDF: #endif case CKK_GENERIC_SECRET: - XMEMCPY(&dest->data.symmKey, &src->data.symmKey, - sizeof(dest->data.symmKey)); + XMEMCPY(dest->data.symmKey->data, src->data.symmKey->data, + src->data.symmKey->len); + dest->data.symmKey->len = src->data.symmKey->len; break; } } @@ -10006,7 +10008,7 @@ int WP11_Rsa_Verify_Recover(CK_MECHANISM_TYPE mechanism, unsigned char* sig, switch (mechanism) { case CKM_RSA_PKCS: ret = wc_RsaSSL_Verify(sig, sigLen, out, (word32)*outLen, - &pub->data.rsaKey); + pub->data.rsaKey); if (ret == RSA_BUFFER_E) return CKR_BUFFER_TOO_SMALL; if (ret < 0) @@ -10019,7 +10021,7 @@ int WP11_Rsa_Verify_Recover(CK_MECHANISM_TYPE mechanism, unsigned char* sig, byte* data_out = NULL; byte* pos; ret = wc_RsaDirect(sig, sigLen, out, (word32*)outLen, - &pub->data.rsaKey, RSA_PUBLIC_DECRYPT, NULL); + pub->data.rsaKey, RSA_PUBLIC_DECRYPT, NULL); if (ret < 0) return CKR_FUNCTION_FAILED; /* Result is front padded with 0x00 */ @@ -10695,7 +10697,7 @@ int WP11_EC_Derive(unsigned char* point, word32 pointLen, unsigned char* key, #endif { PRIVATE_KEY_UNLOCK(); - ret = wc_ecc_shared_secret(&priv->data.ecKey, &pubKey, key, keyLen); + ret = wc_ecc_shared_secret(priv->data.ecKey, &pubKey, key, keyLen); PRIVATE_KEY_LOCK(); #ifdef WOLFPKCS11_TPM @@ -10801,8 +10803,8 @@ int WP11_KDF_Derive(WP11_Session* session, CK_HKDF_PARAMS_PTR params, privLen = priv->data.genericData.dataLen; } else { - privData = priv->data.symmKey.data; - privLen = priv->data.symmKey.len; + privData = priv->data.symmKey->data; + privLen = priv->data.symmKey->len; } if (params->bExtract && !params->bExpand) { ret = wc_HKDF_Extract(hashType, salt, (word32)saltLen, From ceb4a1fdb12d288dc2e0e6b9e3f51e4fc6c60bc0 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Mon, 4 Aug 2025 20:23:06 +0200 Subject: [PATCH 47/50] Fix debug_test again --- src/internal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index b071e254..94019a0e 100644 --- a/src/internal.c +++ b/src/internal.c @@ -19,7 +19,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -#include "wolfpkcs11/pkcs11.h" #ifdef HAVE_CONFIG_H #include #endif From 815123cde040dd667895835e5b65838709380950 Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Tue, 5 Aug 2025 11:24:55 +0100 Subject: [PATCH 48/50] Fix file store naming --- src/internal.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/internal.c b/src/internal.c index 94019a0e..f88af89c 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1092,15 +1092,16 @@ static int wolfPKCS11_Store_Name(int type, CK_ULONG id1, CK_ULONG id2, char* nam ret = XSNPRINTF(name, nameLen, "%s/wp11_trust_%016lx_%016lx", str, id1, id2); break; + case WOLFPKCS11_STORE_DATA: + ret = XSNPRINTF(name, nameLen, "%s/wp11_data_%016lx_%016lx", + str, id1, id2); + break; default: ret = -1; break; } - if (ret > 0 && ret < (int) sizeof(name)) - ret = 0; - else - ret = -1; + return ret; } #endif From fa786be4b04e6d6a31ed621a05882cff668fb087 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 5 Aug 2025 08:22:51 -0700 Subject: [PATCH 49/50] Fix issue with CopyObject on TPM --- src/internal.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/internal.c b/src/internal.c index f88af89c..3c189ce5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2246,12 +2246,6 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) OBJ_COPY_DATA(src, dest, keyData); XMEMCPY(dest->iv, src->iv, sizeof(dest->iv)); dest->encoded = src->encoded; -#endif -#ifdef WOLFPKCS11_TPM - /* For TPM keys, copy keyData */ - if (src->opFlag & WP11_FLAG_TPM) { - OBJ_COPY_DATA(src, dest, keyData); - } #endif dest->objClass = src->objClass; dest->keyGenMech = src->keyGenMech; @@ -2279,7 +2273,7 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) /* Handle TPM keys - copy tpmKey structure directly */ if (src->opFlag & WP11_FLAG_TPM) { /* Copy the TPM key blob structure directly */ - XMEMCPY(&dest->tpmKey, &src->tpmKey, sizeof(WOLFTPM2_KEYBLOB)); + XMEMCPY(dest->tpmKey, src->tpmKey, sizeof(WOLFTPM2_KEYBLOB)); /* Initialize TPM handle to NULL for the destination */ dest->tpmKey->handle.hndl = TPM_RH_NULL; @@ -2309,14 +2303,14 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) case CKK_RSA: /* Load public portion into wolf RsaKey structure */ ret = wolfTPM2_RsaKey_TpmToWolf(&dest->slot->tpmDev, - (WOLFTPM2_KEY*)&dest->tpmKey, dest->data.rsaKey); + (WOLFTPM2_KEY*)dest->tpmKey, dest->data.rsaKey); break; #endif #ifdef HAVE_ECC case CKK_EC: /* Load public portion into wolf EccKey structure */ ret = wolfTPM2_EccKey_TpmToWolf(&dest->slot->tpmDev, - (WOLFTPM2_KEY*)&dest->tpmKey, dest->data.ecKey); + (WOLFTPM2_KEY*)dest->tpmKey, dest->data.ecKey); break; #endif default: From a38e37a5eeda5ad2c3bfdb2bfa6eeca43293b2f4 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 5 Aug 2025 10:55:59 -0700 Subject: [PATCH 50/50] Fix some minor sanitizer issues with use of NULL. --- src/internal.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/internal.c b/src/internal.c index 3c189ce5..58dfbfa5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6794,7 +6794,8 @@ int WP11_Session_SetAesWrapParams(WP11_Session* session, byte* iv, word32 ivLen, WP11_Lock_UnlockRO(object->lock); } if (ret == 0) { - XMEMCPY(wrap->iv, iv, ivLen); + if (iv != NULL) + XMEMCPY(wrap->iv, iv, ivLen); wrap->ivSz = ivLen; } @@ -8123,7 +8124,8 @@ static int GetData(byte* data, CK_ULONG dataLen, byte* out, CK_ULONG* outLen) ret = BUFFER_E; else { *outLen = dataLen; - XMEMCPY(out, data, dataLen); + if (data != NULL) + XMEMCPY(out, data, dataLen); } return ret; @@ -8912,10 +8914,10 @@ static int WP11_Object_SetKeyId(WP11_Object* object, unsigned char* keyId, DYNAMIC_TYPE_TMP_BUFFER); if (object->keyId == NULL) ret = MEMORY_E; - } - if (ret == 0) { - XMEMCPY(object->keyId, keyId, keyIdLen); - object->keyIdLen = keyIdLen; + if (ret == 0) { + XMEMCPY(object->keyId, keyId, keyIdLen); + object->keyIdLen = keyIdLen; + } } return ret; @@ -8943,10 +8945,10 @@ static int WP11_Object_SetData(byte** attribute, int* attributeLen, byte* data, DYNAMIC_TYPE_TMP_BUFFER); if (*attribute == NULL) ret = MEMORY_E; - } - if (ret == 0) { - XMEMCPY(*attribute, data, dataLen); - *attributeLen = dataLen; + if (ret == 0) { + XMEMCPY(*attribute, data, dataLen); + *attributeLen = dataLen; + } } return ret;