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/crypto.c b/src/crypto.c index c1352f30..2391a538 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 @@ -103,9 +104,20 @@ 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, + CKA_APPLICATION, + CKA_OBJECT_ID +}; + +/* Count of generic data attributes */ +#define DATA_PARAMS_CNT (sizeof(genericDataParams)/sizeof(*genericDataParams)) + /* Certificate data attributes */ static CK_ATTRIBUTE_TYPE certParams[] = { CKA_CERTIFICATE_TYPE, @@ -327,6 +339,20 @@ static CK_RV CheckAttributes(CK_ATTRIBUTE* pTemplate, CK_ULONG ulCount, int set) return CKR_OK; } +static int 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; @@ -405,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; @@ -414,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; @@ -548,6 +578,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) { @@ -590,8 +624,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; } @@ -607,6 +644,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. @@ -649,6 +689,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); @@ -952,7 +993,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) { @@ -1117,7 +1157,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; @@ -1127,6 +1167,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 @@ -1164,16 +1211,19 @@ 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) { 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); @@ -1651,28 +1701,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; @@ -1711,6 +1742,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 @@ -1933,6 +1970,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. * @@ -2620,28 +2684,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; @@ -2671,6 +2716,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 @@ -2886,6 +2937,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. * @@ -2960,7 +3037,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: @@ -2980,7 +3057,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 @@ -3002,7 +3079,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 @@ -3024,7 +3101,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: @@ -3043,7 +3120,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 @@ -3063,7 +3140,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 @@ -3084,7 +3161,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 @@ -3105,7 +3182,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 @@ -3125,7 +3202,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 @@ -3147,7 +3224,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 @@ -3171,15 +3248,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; } @@ -3818,6 +3895,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; @@ -3835,6 +3916,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; @@ -3969,6 +4054,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) { @@ -3982,6 +4071,9 @@ 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: + #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS: #endif @@ -4004,6 +4096,9 @@ 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_SHA + case CKM_SHA1_RSA_PKCS_PSS: + #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS_PSS: #endif @@ -4160,6 +4255,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; @@ -4252,6 +4355,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 @@ -4312,12 +4418,15 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, break; } #ifdef WC_RSA_PSS - #ifndef NO_SHA256 - case CKM_SHA256_RSA_PKCS_PSS: + #ifndef NO_SHA + case CKM_SHA1_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 @@ -4474,7 +4583,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; @@ -4483,6 +4592,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; @@ -4613,6 +4725,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; @@ -4744,14 +4859,18 @@ 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; #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; @@ -4950,6 +5069,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) { @@ -4963,6 +5086,9 @@ CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, } init = WP11_INIT_RSA_X_509_VERIFY; break; + #ifndef NO_SHA + case CKM_SHA1_RSA_PKCS: + #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS: #endif @@ -4985,6 +5111,9 @@ 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: + #endif #ifdef WOLFSSL_SHA224 case CKM_SHA224_RSA_PKCS_PSS: #endif @@ -5077,7 +5206,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) { @@ -5127,6 +5258,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; @@ -5213,6 +5352,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 @@ -5264,12 +5406,15 @@ CK_RV C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, break; } #ifdef WC_RSA_PSS - #ifndef NO_SHA256 - case CKM_SHA256_RSA_PKCS_PSS: + #ifndef NO_SHA + case CKM_SHA1_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 @@ -5401,7 +5546,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; @@ -5682,8 +5831,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"); @@ -5741,12 +5888,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); @@ -6471,6 +6615,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); @@ -6504,6 +6652,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) { @@ -6536,12 +6685,13 @@ 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; } - rv = C_EncryptInit(hSession, pMechanism, hWrappingKey); + rv = EncryptInit(hSession, pMechanism, hWrappingKey, 1); if (rv != CKR_OK) goto err_out; @@ -6550,6 +6700,47 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, goto err_out; break; +#endif +#ifndef NO_RSA + case CKM_RSA_PKCS: + { + word32 encDataLen; + 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; @@ -6607,6 +6798,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 @@ -6645,6 +6839,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) @@ -6679,6 +6877,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; @@ -6688,7 +6887,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; @@ -6699,6 +6898,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, decryptedLen, + 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; @@ -6714,6 +6943,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] = { @@ -6769,7 +6999,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; @@ -6784,12 +7014,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; } @@ -6804,7 +7049,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; @@ -6818,8 +7063,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; @@ -6974,7 +7221,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 @@ -7034,10 +7281,11 @@ 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, - keyLen, obj); + &keyLen, obj); if (ret != 0) rv = CKR_FUNCTION_FAILED; break; @@ -7071,6 +7319,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); @@ -7090,6 +7339,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, @@ -7115,6 +7365,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); @@ -7149,6 +7400,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, @@ -7195,6 +7447,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, @@ -7223,6 +7476,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, @@ -7249,8 +7503,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 cc161d1e..58dfbfa5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -99,8 +99,14 @@ /* 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) +#else #define WP11_MAX_DH_KEY_SZ (4096/8) +#endif /* Maximum size of storage for generated/derived symmetric key. */ #ifdef WOLFPKCS11_NSS @@ -189,6 +195,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 */ @@ -214,6 +229,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 @@ -226,6 +242,7 @@ struct WP11_Object { WP11_DhKey* dhKey; /* DH parameters object */ #endif WP11_Data* symmKey; /* Symmetric key object */ + WP11_GenericData genericData; /* Generic data object */ WP11_Cert cert; /* Certificate object */ #ifdef WOLFPKCS11_NSS WP11_Trust trust; /* Trust object */ @@ -472,6 +489,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 { @@ -491,7 +512,7 @@ struct WP11_Slot { /* Number of slots. */ -static 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 @@ -701,9 +722,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; } @@ -900,6 +940,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: @@ -935,6 +984,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 +1050,59 @@ 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; + case WOLFPKCS11_STORE_DATA: + ret = XSNPRINTF(name, nameLen, "%s/wp11_data_%016lx_%016lx", str, id1, id2); break; default: - return -1; + ret = -1; break; } - return 0; + + return ret; } #endif @@ -1099,6 +1154,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. @@ -1127,8 +1200,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 @@ -1204,6 +1281,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) { @@ -2127,6 +2210,284 @@ 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; + } +#ifdef WOLFPKCS11_NSS + else if (src->objClass == CKO_NSS_TRUST) { + return BAD_FUNC_ARG; + } +#endif + else { +#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)); + + /* Initialize TPM handle to NULL for the destination */ + 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, + 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; + } + } + } + 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, NULL, 0); + } + else { + ret = wc_RsaKeyToPublicDer(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) { + /* 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; + } +#endif +#ifdef HAVE_ECC + 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) + derSz = wc_EccKeyDerSize(src->data.ecKey, 0); + else + derSz = wc_EccPublicKeyDerSize(src->data.ecKey, 1); + + 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; + } + + 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; + } + } + + 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: + 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->data, src->data.symmKey->data, + src->data.symmKey->len); + dest->data.symmKey->len = src->data.symmKey->len; + break; + } + } + } + + + return ret; +} + #ifndef WOLFPKCS11_NO_STORE /** * Encrypt the data with AES-GCM. @@ -2227,6 +2588,13 @@ static void wp11_Object_Decode_Trust(WP11_Object* object) } #endif +static void wp11_Object_Decode_Data(WP11_Object* object) +{ + /* No longer needed since wp11_Object_Load_Data handles + * deserialization directly */ + object->encoded = 0; +} + /** * Load a certificate from storage. * @@ -2290,6 +2658,42 @@ 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; + int tempLen; + + /* Open access to data. */ + ret = wp11_storage_open_readonly(WOLFPKCS11_STORE_DATA, tokenId, objId, + &storage); + if (ret == 0) { + ret = wp11_storage_read_alloc_array(storage, + &object->data.genericData.data, + &tempLen); + object->data.genericData.dataLen = (word32)tempLen; + } + + /* 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; + } + + /* 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; +} #ifdef WOLFSSL_MAXQ10XX_CRYPTO #ifdef MAXQ10XX_PRODUCTION_KEY @@ -2768,6 +3172,44 @@ 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; + + 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, + variableSz, &storage); + /* Write data length and data. */ + if (ret == 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_array(storage, + object->data.genericData.application, + object->data.genericData.applicationLen); + } + + /* Write object ID length and object ID. */ + if (ret == 0) { + ret = wp11_storage_write_array(storage, + object->data.genericData.objectId, + object->data.genericData.objectIdLen); + } + + wp11_storage_close(storage); + + return ret; +} + #ifndef NO_RSA /** * Decode the RSA key. @@ -3928,6 +4370,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) { @@ -4085,6 +4530,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) { @@ -4142,6 +4590,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 @@ -4196,6 +4648,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 @@ -4256,7 +4711,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; } @@ -4276,6 +4731,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) { @@ -4414,6 +4872,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)); } @@ -4936,6 +5395,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++) @@ -5602,6 +6065,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)); @@ -5901,6 +6365,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: @@ -6225,9 +6694,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; @@ -6327,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; } @@ -6778,8 +7246,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; } @@ -6825,6 +7300,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) { @@ -7256,7 +7736,7 @@ 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] != AES_128_KEY_SIZE && *(CK_ULONG*)data[0] != AES_192_KEY_SIZE && @@ -7323,6 +7803,77 @@ 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[0] != NULL && len[0] > 0) { + 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 */ + 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) { + 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 */ + 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) { + 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 */ + 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); + + return ret; +} + int WP11_Object_SetCert(WP11_Object* object, unsigned char** data, CK_ULONG* len) { @@ -7573,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; @@ -7609,6 +8161,35 @@ 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.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; + break; + } + + return ret; +} + #ifdef WOLFPKCS11_NSS static int GetTrustAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, CK_ULONG* len) @@ -7942,7 +8523,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) @@ -8073,6 +8655,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; } @@ -8149,7 +8732,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); @@ -8221,64 +8810,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 +#endif + else if (object->objClass == CKO_DATA) + ret = GetDataAttr(object, type, data, len); 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; } } @@ -8325,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; @@ -8356,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; @@ -8561,6 +9150,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: @@ -8581,6 +9173,22 @@ int WP11_Object_SetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, break; } break; + case CKA_APPLICATION: + if (object->objClass == CKO_DATA) { + /* Handled in WP11_Object_DataObject */ + } + else { + ret = BAD_FUNC_ARG; + } + break; + case CKA_OBJECT_ID: + if (object->objClass == CKO_DATA) { + /* Handled in WP11_Object_DataObject */ + } + else { + ret = BAD_FUNC_ARG; + } + break; #ifdef WOLFPKCS11_NSS case CKA_CERT_SHA1_HASH: case CKA_CERT_MD5_HASH: @@ -9392,38 +10000,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, + 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) { @@ -9665,8 +10261,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. @@ -10026,7 +10626,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; @@ -10048,14 +10648,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; + } } } @@ -10085,7 +10693,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 @@ -10100,7 +10708,6 @@ int WP11_EC_Derive(unsigned char* point, word32 pointLen, unsigned char* key, #endif } -cleanup: wc_ecc_free(&pubKey); return ret; @@ -10146,6 +10753,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; @@ -10185,24 +10794,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(); @@ -12236,6 +12851,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; @@ -12252,11 +12868,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(); @@ -12265,7 +12887,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; @@ -12353,6 +12975,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); @@ -12383,12 +13010,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); @@ -12400,6 +13027,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); @@ -12447,6 +13079,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); @@ -12499,6 +13136,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); diff --git a/src/slot.c b/src/slot.c index 41e6fae8..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 @@ -361,6 +367,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, @@ -612,6 +619,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. */ @@ -849,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 @@ -867,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 @@ -926,6 +942,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..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,6 +124,63 @@ CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) return ret; } +#if (defined(WOLFPKCS11_NSS) && !defined(WOLFPKCS11_NO_STORE)) +/* + * 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."); +#if (defined(WOLFPKCS11_NSS) && !defined(WOLFPKCS11_NO_STORE)) + 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; } @@ -158,7 +241,7 @@ CK_RV C_Finalize(CK_VOID_PTR pReserved) { CK_RV ret; WOLFPKCS11_ENTER("C_Finalize"); - + WP11_Library_Final(); (void)pReserved; @@ -188,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); @@ -205,4 +288,3 @@ CK_RV C_GetInfo(CK_INFO_PTR pInfo) WOLFPKCS11_LEAVE("C_GetInfo", ret); return ret; } - diff --git a/tests/pkcs11mtt.c b/tests/pkcs11mtt.c index b479f882..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) }, @@ -3251,13 +3252,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 +3280,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..c9eddb53 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; @@ -1674,568 +1675,1979 @@ static CK_RV test_object(void* args) return ret; } -#if ((defined(WOLFPKCS11_NSS)) && ((WP11_SESSION_CNT_MAX != 1) || \ - (WP11_SESSION_CNT_MIN != 1))) -static CK_RV test_cross_session_object(void* args) +static CK_RV test_copy_object_deep_copy(void* args) { CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; CK_RV ret = CKR_OK; - CK_SESSION_HANDLE sessionRO; - CK_OBJECT_HANDLE obj; - CK_ULONG size; - static byte keyData[] = { 0x00 }; - CK_ATTRIBUTE tmpl[] = { - { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + 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 tmplCnt = sizeof(tmpl) / sizeof(*tmpl); - - ret = funcList->C_CreateObject(session, tmpl, tmplCnt, &obj); - CHECK_CKR(ret, "Create object"); + CK_ULONG originalTmplCnt = sizeof(originalTmpl) / sizeof(*originalTmpl); - if (ret == CKR_OK) { - sessionRO = CK_INVALID_HANDLE; - ret = funcList->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, - &sessionRO); - CHECK_CKR(ret, "Open Session - read-only"); - } + /* Template for copying with modifications */ + CK_ATTRIBUTE copyWithModTmpl[] = { + { CKA_LABEL, modifiedLabel, sizeof(modifiedLabel)-1 }, + }; + CK_ULONG copyWithModTmplCnt = sizeof(copyWithModTmpl) / + sizeof(*copyWithModTmpl); - if (ret == CKR_OK) { - ret = funcList->C_GetObjectSize(sessionRO, obj, &size); - CHECK_CKR(ret, "Get Object size"); - if (size != CK_UNAVAILABLE_INFORMATION) { - ret = -1; - CHECK_CKR(ret, "Get Object size not available"); - } - } + /* 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); - if (ret == CKR_OK) { - ret = funcList->C_DestroyObject(sessionRO, obj); - CHECK_CKR(ret, "Cross-session deletion"); - } + 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); - return ret; -} -#endif + /* Buffers for retrieved attributes */ + byte origValue[32], copiedValue[32]; + byte origId[32], copiedId[32]; + byte origLabel[64], copiedLabel[64]; + CK_BBOOL origExtractable, copiedExtractable; -static CK_RV test_attribute(void* args) -{ - CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; - CK_RV ret; - CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; - static byte keyData[] = { 0x00 }; - byte retKeyData[1]; - CK_ULONG valueLen = 1; - CK_BBOOL badBool = 2; - CK_DATE date = { { 0, }, { 0, }, { 0, } }; - CK_ATTRIBUTE tmpl[] = { - { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, - { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, - { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, - { CKA_VALUE, keyData, sizeof(keyData) }, - }; - CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); - CK_ULONG count; - CK_ATTRIBUTE badTmpl[] = { - { CKA_TOKEN, &ckTrue, 0 } - }; - CK_ATTRIBUTE badAttrType[] = { - { -1, &ckTrue, sizeof(ckTrue) } - }; - CK_ATTRIBUTE badAttrLen[] = { - { CKA_VALUE, retKeyData, 0 } - }; - CK_ATTRIBUTE attrNotAvail[] = { - { CKA_APPLICATION, retKeyData, 1 } - }; - CK_ATTRIBUTE tmplLongNull[] = { - { CKA_VALUE_LEN, NULL, sizeof(valueLen) } - }; - CK_ATTRIBUTE tmplLongLenBad[] = { - { CKA_VALUE_LEN, &valueLen, 1 } - }; - CK_ATTRIBUTE tmplBoolNull[] = { - { CKA_ENCRYPT, NULL, sizeof(CK_BBOOL) } - }; - CK_ATTRIBUTE tmplBoolLenBad[] = { - { CKA_ENCRYPT, &ckTrue, 0 } - }; - CK_ATTRIBUTE tmplBoolVal[] = { - { CKA_ENCRYPT, &badBool, sizeof(CK_BBOOL) } - }; - CK_ATTRIBUTE tmplDateNull[] = { - { CKA_START_DATE, NULL, sizeof(CK_DATE) } - }; - CK_ATTRIBUTE tmplDateLenBad[] = { - { CKA_START_DATE, &date, 1 } - }; - CK_ATTRIBUTE tmplDataUnavail[] = { - { CKA_VALUE, keyData, CK_UNAVAILABLE_INFORMATION } - }; + /* Create original object */ + ret = funcList->C_CreateObject(session, originalTmpl, originalTmplCnt, + &originalObj); + CHECK_CKR(ret, "Create original object for copy test"); - ret = funcList->C_CreateObject(session, tmpl, tmplCnt, &obj); - CHECK_CKR(ret, "Create Object"); + /* Test 1: Copy without modifications (pure copy) */ if (ret == CKR_OK) { - ret = funcList->C_GetAttributeValue(CK_INVALID_HANDLE, obj, tmpl, - tmplCnt); - CHECK_CKR_FAIL(ret, CKR_SESSION_HANDLE_INVALID, - "Get Attribute Value invalid session handle"); + 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) { - ret = funcList->C_GetAttributeValue(session, CK_INVALID_HANDLE, tmpl, - tmplCnt); - CHECK_CKR_FAIL(ret, CKR_OBJECT_HANDLE_INVALID, - "Get Attribute Value invalid object handle"); + /* 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) { - ret = funcList->C_GetAttributeValue(session, obj, NULL, tmplCnt); - CHECK_CKR_FAIL(ret, CKR_ARGUMENTS_BAD, - "Get Attribute Value no template"); + /* 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) { - count = sizeof(badTmpl) / sizeof(*badTmpl); - ret = funcList->C_GetAttributeValue(session, obj, badTmpl, count); - CHECK_CKR_FAIL(ret, CKR_BUFFER_TOO_SMALL, - "Get Attribute Value bad template"); + 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) { - count = sizeof(badAttrType) / sizeof(*badAttrType); - ret = funcList->C_GetAttributeValue(session, obj, badAttrType, count); - CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_TYPE_INVALID, - "Get Attribute Value bad attribute type"); + 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) { - count = sizeof(badAttrLen) / sizeof(*badAttrLen); - ret = funcList->C_GetAttributeValue(session, obj, badAttrLen, count); - CHECK_CKR_FAIL(ret, CKR_BUFFER_TOO_SMALL, - "Get Attribute Value bad attribute length"); + 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) { - count = sizeof(attrNotAvail) / sizeof(*attrNotAvail); - ret = funcList->C_GetAttributeValue(session, obj, attrNotAvail, count); - CHECK_CKR_FAIL(ret, CK_UNAVAILABLE_INFORMATION, - "Get Attribute Value attribute not available"); + 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_SetAttributeValue(CK_INVALID_HANDLE, obj, tmpl, - tmplCnt); - CHECK_CKR_FAIL(ret, CKR_SESSION_HANDLE_INVALID, - "Set Attribute Value invalid session handle"); + 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_SetAttributeValue(session, CK_INVALID_HANDLE, tmpl, - tmplCnt); - CHECK_CKR_FAIL(ret, CKR_OBJECT_HANDLE_INVALID, - "Set Attribute Value invalid object handle"); + 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) { - ret = funcList->C_SetAttributeValue(session, obj, NULL, tmplCnt); - CHECK_CKR_FAIL(ret, CKR_ARGUMENTS_BAD, - "Set Attribute Value no template"); + 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) { - count = sizeof(tmplLongNull) / sizeof(*tmplLongNull); - ret = funcList->C_SetAttributeValue(session, obj, tmplLongNull, count); - CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, - "Set Attribute Value NULL value for data type long"); + /* 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) { - count = sizeof(tmplLongLenBad) / sizeof(*tmplLongLenBad); - ret = funcList->C_SetAttributeValue(session, obj, tmplLongLenBad, - count); - CHECK_CKR_FAIL(ret, CKR_BUFFER_TOO_SMALL, - "Set Attribute Value small length for data type long"); + 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) { - count = sizeof(tmplBoolNull) / sizeof(*tmplBoolNull); - ret = funcList->C_SetAttributeValue(session, obj, tmplBoolNull, count); - CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, - "Set Attribute Value NULL value for data type bool"); + /* 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) { - count = sizeof(tmplBoolLenBad) / sizeof(*tmplBoolLenBad); - ret = funcList->C_SetAttributeValue(session, obj, tmplBoolLenBad, - count); - CHECK_CKR_FAIL(ret, CKR_BUFFER_TOO_SMALL, - "Set Attribute Value small length for data type bool"); + 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) { - count = sizeof(tmplBoolVal) / sizeof(*tmplBoolVal); - ret = funcList->C_SetAttributeValue(session, obj, tmplBoolVal, count); - CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, - "Set Attribute Value bad value for data type bool"); + /* 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) { - count = sizeof(tmplDateNull) / sizeof(*tmplDateNull); - ret = funcList->C_SetAttributeValue(session, obj, tmplDateNull, count); - CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, - "Set Attribute Value NULL value for data type date"); + /* 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) { - count = sizeof(tmplDateLenBad) / sizeof(*tmplDateLenBad); - ret = funcList->C_SetAttributeValue(session, obj, tmplDateLenBad, - count); - CHECK_CKR_FAIL(ret, CKR_BUFFER_TOO_SMALL, - "Set Attribute Value small length for data type date"); + /* 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) { - count = sizeof(tmplDataUnavail) / sizeof(*tmplDataUnavail); - ret = funcList->C_SetAttributeValue(session, obj, tmplDataUnavail, - count); - CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, - "Set Attribute Value unavailable for data type data"); + /* 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)"); + } } - if (obj != CK_INVALID_HANDLE) - funcList->C_DestroyObject(session, obj); + /* Clean up */ + if (originalObj != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, originalObj); + } + if (copiedObj != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, copiedObj); + } return ret; } -static CK_RV test_attribute_types(void* args) +#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; - CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; - static byte keyData[] = { 0x00 }; - CK_ATTRIBUTE tmpl[] = { - { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, - { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, - { CKA_VALUE, keyData, sizeof(keyData) }, - { CKA_SUBJECT, NULL, 0 }, + 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; + 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 tmplCnt = sizeof(tmpl) / sizeof(*tmpl); - CK_BBOOL privateBool, sensitive, extractable, modifiable, alwaysSensitive; - CK_BBOOL neverExtractable, alwaysAuthenticate, copyable, destroyable, local; - CK_BBOOL wrapWithTrusted, trusted; - CK_BBOOL encrypt, decrypt, verify, verifyRecover, sign, signRecover; - CK_BBOOL wrap, unwrap, derive; - CK_ATTRIBUTE boolTmpl[] = { - { CKA_PRIVATE, &privateBool, sizeof(CK_BBOOL) }, - { CKA_SENSITIVE, &sensitive, sizeof(CK_BBOOL) }, - { CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL) }, - { CKA_MODIFIABLE, &modifiable, sizeof(CK_BBOOL) }, - { CKA_ALWAYS_SENSITIVE, &alwaysSensitive, sizeof(CK_BBOOL) }, - { CKA_NEVER_EXTRACTABLE, &neverExtractable, sizeof(CK_BBOOL) }, - { CKA_ALWAYS_AUTHENTICATE, &alwaysAuthenticate, sizeof(CK_BBOOL) }, - { CKA_WRAP_WITH_TRUSTED, &wrapWithTrusted, sizeof(CK_BBOOL) }, - { CKA_TRUSTED, &trusted, sizeof(CK_BBOOL) }, - { CKA_COPYABLE, ©able, sizeof(CK_BBOOL) }, - { CKA_DESTROYABLE, &destroyable, sizeof(CK_BBOOL) }, - { CKA_LOCAL, &local, sizeof(CK_BBOOL) }, - { CKA_ENCRYPT, &encrypt, sizeof(CK_BBOOL) }, - { CKA_DECRYPT, &decrypt, sizeof(CK_BBOOL) }, - { CKA_VERIFY, &verify, sizeof(CK_BBOOL) }, - { CKA_VERIFY_RECOVER, &verifyRecover, sizeof(CK_BBOOL) }, - { CKA_SIGN, &sign, sizeof(CK_BBOOL) }, - { CKA_SIGN_RECOVER, &signRecover, sizeof(CK_BBOOL) }, - { CKA_WRAP, &wrap, sizeof(CK_BBOOL) }, - { CKA_UNWRAP, &unwrap, sizeof(CK_BBOOL) }, - { CKA_DERIVE, &derive, sizeof(CK_BBOOL) }, - }; - CK_ULONG boolTmplCnt = sizeof(boolTmpl) / sizeof(*boolTmpl); - CK_ATTRIBUTE boolSetTmpl[] = { - { CKA_PRIVATE, &privateBool, sizeof(CK_BBOOL) }, - { CKA_SENSITIVE, &sensitive, sizeof(CK_BBOOL) }, - { CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL) }, - { CKA_MODIFIABLE, &modifiable, sizeof(CK_BBOOL) }, - { CKA_ALWAYS_SENSITIVE, &alwaysSensitive, sizeof(CK_BBOOL) }, - { CKA_NEVER_EXTRACTABLE, &neverExtractable, sizeof(CK_BBOOL) }, - { CKA_ALWAYS_AUTHENTICATE, &alwaysAuthenticate, sizeof(CK_BBOOL) }, - { CKA_WRAP_WITH_TRUSTED, &wrapWithTrusted, sizeof(CK_BBOOL) }, - { CKA_TRUSTED, &trusted, sizeof(CK_BBOOL) }, - { CKA_ENCRYPT, &encrypt, sizeof(CK_BBOOL) }, - { CKA_DECRYPT, &decrypt, sizeof(CK_BBOOL) }, - { CKA_VERIFY, &verify, sizeof(CK_BBOOL) }, - { CKA_VERIFY_RECOVER, &verifyRecover, sizeof(CK_BBOOL) }, - { CKA_SIGN, &sign, sizeof(CK_BBOOL) }, - { CKA_SIGN_RECOVER, &signRecover, sizeof(CK_BBOOL) }, - { CKA_WRAP, &wrap, sizeof(CK_BBOOL) }, - { CKA_UNWRAP, &unwrap, sizeof(CK_BBOOL) }, - { CKA_DERIVE, &derive, sizeof(CK_BBOOL) }, -#if 0 - { CKA_LOCAL, &local, sizeof(CK_BBOOL) }, - { CKA_DESTROYABLE, &destroyable, sizeof(CK_BBOOL) }, - { CKA_COPYABLE, ©able, sizeof(CK_BBOOL) }, -#endif + 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 boolSetTmplCnt = sizeof(boolSetTmpl) / sizeof(*boolSetTmpl); - CK_ATTRIBUTE badAttrsTmpl[] = { - { CKA_WRAP_TEMPLATE, NULL, 0 }, - { CKA_UNWRAP_TEMPLATE, NULL, 0 }, - { CKA_ALLOWED_MECHANISMS, NULL, 0 }, + CK_ULONG privKeyTmplCnt = sizeof(privKeyTmpl) / sizeof(*privKeyTmpl); + + /* Template for copying with modifications */ + CK_ATTRIBUTE copyTmpl[] = { + { CKA_LABEL, modifiedLabel, sizeof(modifiedLabel)-1 }, }; - CK_ULONG badAttrsTmplCnt = sizeof(badAttrsTmpl) / sizeof(*badAttrsTmpl); - CK_DATE startDate = { {'2','0','1','8'}, {'0','1'}, {'0','1'} }; - CK_DATE endDate = { {'2','1','1','8'}, {'0','1'}, {'0','1'} }; - CK_CHAR label[32] = "The Key's Label!!!"; - CK_DATE emptyStartDate = { {'2','0','1','8'}, {'0','1'}, {'0','1'} }; - CK_DATE emptyEndDate = { {'2','1','1','8'}, {'0','1'}, {'0','1'} }; - CK_CHAR emptyLabel[32] = "The Key's Label!!!"; - CK_ATTRIBUTE setGetTmpl[] = { - { CKA_START_DATE, &emptyStartDate, sizeof(CK_DATE) }, - { CKA_END_DATE, &emptyEndDate, sizeof(CK_DATE) }, - { CKA_LABEL, emptyLabel, sizeof(emptyLabel) }, + 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 setGetTmplCnt = sizeof(setGetTmpl) / sizeof(*setGetTmpl); + CK_ULONG getOriginalAttrsCnt = sizeof(getOriginalAttrs) / + sizeof(*getOriginalAttrs); - /* Certificate test variables */ - CK_OBJECT_HANDLE certObj = CK_INVALID_HANDLE; - CK_CERTIFICATE_TYPE certType = CKC_X_509; - CK_BYTE subject[] = "C = US, ST = Montana, L = Bozeman, O = wolfSSL, " - "OU = Support, CN = www.wolfssl.com, emailAddress = info@wolfssl.com"; - CK_BYTE certificate[] = { 0x30, 0x82, 0x01, 0x00 }; /* Minimal cert data */ - CK_ATTRIBUTE certTmpl[] = { - { CKA_CLASS, &certificateClass, sizeof(certificateClass) }, - { CKA_CERTIFICATE_TYPE, &certType, sizeof(certType) }, - { CKA_SUBJECT, subject, sizeof(subject)-1 }, - { CKA_VALUE, certificate, sizeof(certificate) }, + CK_ATTRIBUTE getCopiedAttrs[] = { + { CKA_ID, NULL, 0 }, + { CKA_LABEL, NULL, 0 }, + { CKA_EXTRACTABLE, NULL, 0 }, + { CKA_MODULUS, NULL, 0 }, }; - CK_ULONG certTmplCnt = sizeof(certTmpl) / sizeof(*certTmpl); - CK_BYTE subjectBuffer[256]; - CK_ATTRIBUTE subjectAttr[] = { - { CKA_SUBJECT, subjectBuffer, sizeof(subjectBuffer) }, + 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 }, }; - int i; + CK_ULONG getOriginalPubAttrsCnt = sizeof(getOriginalPubAttrs) / + sizeof(*getOriginalPubAttrs); - ret = funcList->C_CreateObject(session, tmpl, tmplCnt, &obj); - CHECK_CKR(ret, "Create Object"); + 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; + 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_GetAttributeValue(session, obj, boolTmpl, - boolTmplCnt); - CHECK_CKR(ret, "Get Boolean attributes"); + ret = funcList->C_CopyObject(session, privKey, copyTmpl, copyTmplCnt, + &copiedPrivKey); + CHECK_CKR(ret, "Copy RSA private key"); } + + /* Test: Copy RSA public key */ if (ret == CKR_OK) { - ret = funcList->C_SetAttributeValue(session, obj, boolSetTmpl, - boolSetTmplCnt); - CHECK_CKR(ret, "Set Boolean attributes"); + ret = funcList->C_CopyObject(session, pubKey, copyTmpl, copyTmplCnt, + &copiedPubKey); + CHECK_CKR(ret, "Copy RSA public key"); } - for (i = 0; i < (int)badAttrsTmplCnt; i++) { - ret = funcList->C_GetAttributeValue(session, obj, &badAttrsTmpl[i], 1); - CHECK_CKR_FAIL(ret, CK_UNAVAILABLE_INFORMATION, - "Get unavailable attribute"); + + /* 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) { - ret = funcList->C_GetAttributeValue(session, obj, setGetTmpl, - setGetTmplCnt); - CHECK_CKR(ret, "Get Empty data attributes"); + /* 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) { - setGetTmpl[0].pValue = &startDate; - setGetTmpl[0].ulValueLen = sizeof(CK_DATE); - setGetTmpl[1].pValue = &endDate; - setGetTmpl[1].ulValueLen = sizeof(CK_DATE); - setGetTmpl[2].pValue = label; - setGetTmpl[2].ulValueLen = sizeof(label); - ret = funcList->C_SetAttributeValue(session, obj, setGetTmpl, - setGetTmplCnt); - CHECK_CKR(ret, "Set Empty data attributes"); + 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) { - ret = funcList->C_GetAttributeValue(session, obj, setGetTmpl, - setGetTmplCnt); - CHECK_CKR(ret, "Get Empty data attributes"); + if (origExtractable != copiedExtractable) { + ret = -1; + CHECK_CKR(ret, "Copied RSA key EXTRACTABLE should match original"); + } } - /* Test CKA_SUBJECT attribute with CKO_CERTIFICATE object - * This verifies that CKA_SUBJECT is properly supported for certificate objects - * and that the subject data can be retrieved correctly. */ if (ret == CKR_OK) { - ret = funcList->C_CreateObject(session, certTmpl, certTmplCnt, - &certObj); - CHECK_CKR(ret, "Create Certificate Object"); + /* 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) { - /* First get the required buffer size for CKA_SUBJECT */ - subjectAttr[0].pValue = NULL; - subjectAttr[0].ulValueLen = 0; - ret = funcList->C_GetAttributeValue(session, certObj, subjectAttr, 1); - CHECK_CKR(ret, "Get CKA_SUBJECT length from certificate"); + /* 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"); + } } + + /* Verify that both public keys exist and have expected attributes */ if (ret == CKR_OK) { - /* Verify the length matches our expected subject size */ - if (subjectAttr[0].ulValueLen != sizeof(subject)-1) { - ret = CKR_GENERAL_ERROR; - CHECK_CKR(ret, "CKA_SUBJECT length verification"); + /* 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) { - /* Now get the actual CKA_SUBJECT data */ - subjectAttr[0].pValue = subjectBuffer; - subjectAttr[0].ulValueLen = sizeof(subjectBuffer); - ret = funcList->C_GetAttributeValue(session, certObj, subjectAttr, 1); - CHECK_CKR(ret, "Get CKA_SUBJECT data from certificate"); + /* 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 subject data matches what we set */ - if (subjectAttr[0].ulValueLen != sizeof(subject)-1 || - XMEMCMP(subjectAttr[0].pValue, subject, sizeof(subject)-1) != 0) { - ret = CKR_GENERAL_ERROR; - CHECK_CKR(ret, "CKA_SUBJECT data verification failed"); + /* 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) { + 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"); + } + } + + /* 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 */ + 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 /* !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) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret = CKR_OK; + CK_SESSION_HANDLE sessionRO; + CK_OBJECT_HANDLE obj; + CK_ULONG size; + static byte keyData[] = { 0x00 }; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + }; + CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); + + ret = funcList->C_CreateObject(session, tmpl, tmplCnt, &obj); + CHECK_CKR(ret, "Create object"); + + if (ret == CKR_OK) { + sessionRO = CK_INVALID_HANDLE; + ret = funcList->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, + &sessionRO); + CHECK_CKR(ret, "Open Session - read-only"); + } + + if (ret == CKR_OK) { + ret = funcList->C_GetObjectSize(sessionRO, obj, &size); + CHECK_CKR(ret, "Get Object size"); + if (size != CK_UNAVAILABLE_INFORMATION) { + ret = -1; + CHECK_CKR(ret, "Get Object size not available"); + } + } + + if (ret == CKR_OK) { + ret = funcList->C_DestroyObject(sessionRO, obj); + CHECK_CKR(ret, "Cross-session deletion"); + } + + return ret; +} +#endif + +static CK_RV test_attribute(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + static byte keyData[] = { 0x00 }; + byte retKeyData[1]; + CK_ULONG valueLen = 1; + CK_BBOOL badBool = 2; + CK_DATE date = { { 0, }, { 0, }, { 0, } }; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + }; + CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); + CK_ULONG count; + CK_ATTRIBUTE badTmpl[] = { + { CKA_TOKEN, &ckTrue, 0 } + }; + CK_ATTRIBUTE badAttrType[] = { + { -1, &ckTrue, sizeof(ckTrue) } + }; + CK_ATTRIBUTE badAttrLen[] = { + { CKA_VALUE, retKeyData, 0 } + }; + CK_ATTRIBUTE attrNotAvail[] = { + { CKA_APPLICATION, retKeyData, 1 } + }; + CK_ATTRIBUTE tmplLongNull[] = { + { CKA_VALUE_LEN, NULL, sizeof(valueLen) } + }; + CK_ATTRIBUTE tmplLongLenBad[] = { + { CKA_VALUE_LEN, &valueLen, 1 } + }; + CK_ATTRIBUTE tmplBoolNull[] = { + { CKA_ENCRYPT, NULL, sizeof(CK_BBOOL) } + }; + CK_ATTRIBUTE tmplBoolLenBad[] = { + { CKA_ENCRYPT, &ckTrue, 0 } + }; + CK_ATTRIBUTE tmplBoolVal[] = { + { CKA_ENCRYPT, &badBool, sizeof(CK_BBOOL) } + }; + CK_ATTRIBUTE tmplDateNull[] = { + { CKA_START_DATE, NULL, sizeof(CK_DATE) } + }; + CK_ATTRIBUTE tmplDateLenBad[] = { + { CKA_START_DATE, &date, 1 } + }; + CK_ATTRIBUTE tmplDataUnavail[] = { + { CKA_VALUE, keyData, CK_UNAVAILABLE_INFORMATION } + }; + + ret = funcList->C_CreateObject(session, tmpl, tmplCnt, &obj); + CHECK_CKR(ret, "Create Object"); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(CK_INVALID_HANDLE, obj, tmpl, + tmplCnt); + CHECK_CKR_FAIL(ret, CKR_SESSION_HANDLE_INVALID, + "Get Attribute Value invalid session handle"); + } + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, CK_INVALID_HANDLE, tmpl, + tmplCnt); + CHECK_CKR_FAIL(ret, CKR_OBJECT_HANDLE_INVALID, + "Get Attribute Value invalid object handle"); + } + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, NULL, tmplCnt); + CHECK_CKR_FAIL(ret, CKR_ARGUMENTS_BAD, + "Get Attribute Value no template"); + } + if (ret == CKR_OK) { + count = sizeof(badTmpl) / sizeof(*badTmpl); + ret = funcList->C_GetAttributeValue(session, obj, badTmpl, count); + CHECK_CKR_FAIL(ret, CKR_BUFFER_TOO_SMALL, + "Get Attribute Value bad template"); + } + if (ret == CKR_OK) { + count = sizeof(badAttrType) / sizeof(*badAttrType); + ret = funcList->C_GetAttributeValue(session, obj, badAttrType, count); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_TYPE_INVALID, + "Get Attribute Value bad attribute type"); + } + if (ret == CKR_OK) { + count = sizeof(badAttrLen) / sizeof(*badAttrLen); + ret = funcList->C_GetAttributeValue(session, obj, badAttrLen, count); + CHECK_CKR_FAIL(ret, CKR_BUFFER_TOO_SMALL, + "Get Attribute Value bad attribute length"); + } + if (ret == CKR_OK) { + count = sizeof(attrNotAvail) / sizeof(*attrNotAvail); + ret = funcList->C_GetAttributeValue(session, obj, attrNotAvail, count); + CHECK_CKR_FAIL(ret, CK_UNAVAILABLE_INFORMATION, + "Get Attribute Value attribute not available"); + } + + if (ret == CKR_OK) { + ret = funcList->C_SetAttributeValue(CK_INVALID_HANDLE, obj, tmpl, + tmplCnt); + CHECK_CKR_FAIL(ret, CKR_SESSION_HANDLE_INVALID, + "Set Attribute Value invalid session handle"); + } + if (ret == CKR_OK) { + ret = funcList->C_SetAttributeValue(session, CK_INVALID_HANDLE, tmpl, + tmplCnt); + CHECK_CKR_FAIL(ret, CKR_OBJECT_HANDLE_INVALID, + "Set Attribute Value invalid object handle"); + } + if (ret == CKR_OK) { + ret = funcList->C_SetAttributeValue(session, obj, NULL, tmplCnt); + CHECK_CKR_FAIL(ret, CKR_ARGUMENTS_BAD, + "Set Attribute Value no template"); + } + if (ret == CKR_OK) { + count = sizeof(tmplLongNull) / sizeof(*tmplLongNull); + ret = funcList->C_SetAttributeValue(session, obj, tmplLongNull, count); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "Set Attribute Value NULL value for data type long"); + } + if (ret == CKR_OK) { + count = sizeof(tmplLongLenBad) / sizeof(*tmplLongLenBad); + ret = funcList->C_SetAttributeValue(session, obj, tmplLongLenBad, + count); + CHECK_CKR_FAIL(ret, CKR_BUFFER_TOO_SMALL, + "Set Attribute Value small length for data type long"); + } + if (ret == CKR_OK) { + count = sizeof(tmplBoolNull) / sizeof(*tmplBoolNull); + ret = funcList->C_SetAttributeValue(session, obj, tmplBoolNull, count); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "Set Attribute Value NULL value for data type bool"); + } + if (ret == CKR_OK) { + count = sizeof(tmplBoolLenBad) / sizeof(*tmplBoolLenBad); + ret = funcList->C_SetAttributeValue(session, obj, tmplBoolLenBad, + count); + CHECK_CKR_FAIL(ret, CKR_BUFFER_TOO_SMALL, + "Set Attribute Value small length for data type bool"); + } + if (ret == CKR_OK) { + count = sizeof(tmplBoolVal) / sizeof(*tmplBoolVal); + ret = funcList->C_SetAttributeValue(session, obj, tmplBoolVal, count); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "Set Attribute Value bad value for data type bool"); + } + if (ret == CKR_OK) { + count = sizeof(tmplDateNull) / sizeof(*tmplDateNull); + ret = funcList->C_SetAttributeValue(session, obj, tmplDateNull, count); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "Set Attribute Value NULL value for data type date"); + } + if (ret == CKR_OK) { + count = sizeof(tmplDateLenBad) / sizeof(*tmplDateLenBad); + ret = funcList->C_SetAttributeValue(session, obj, tmplDateLenBad, + count); + CHECK_CKR_FAIL(ret, CKR_BUFFER_TOO_SMALL, + "Set Attribute Value small length for data type date"); + } + if (ret == CKR_OK) { + count = sizeof(tmplDataUnavail) / sizeof(*tmplDataUnavail); + ret = funcList->C_SetAttributeValue(session, obj, tmplDataUnavail, + count); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "Set Attribute Value unavailable for data type data"); + } + + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + + return ret; +} + +static CK_RV test_attribute_types(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + static byte keyData[] = { 0x00 }; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_SUBJECT, NULL, 0 }, + }; + CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); + CK_BBOOL privateBool, sensitive, extractable, modifiable, alwaysSensitive; + CK_BBOOL neverExtractable, alwaysAuthenticate, copyable, destroyable, local; + CK_BBOOL wrapWithTrusted, trusted; + CK_BBOOL encrypt, decrypt, verify, verifyRecover, sign, signRecover; + CK_BBOOL wrap, unwrap, derive; + CK_ATTRIBUTE boolTmpl[] = { + { CKA_PRIVATE, &privateBool, sizeof(CK_BBOOL) }, + { CKA_SENSITIVE, &sensitive, sizeof(CK_BBOOL) }, + { CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL) }, + { CKA_MODIFIABLE, &modifiable, sizeof(CK_BBOOL) }, + { CKA_ALWAYS_SENSITIVE, &alwaysSensitive, sizeof(CK_BBOOL) }, + { CKA_NEVER_EXTRACTABLE, &neverExtractable, sizeof(CK_BBOOL) }, + { CKA_ALWAYS_AUTHENTICATE, &alwaysAuthenticate, sizeof(CK_BBOOL) }, + { CKA_WRAP_WITH_TRUSTED, &wrapWithTrusted, sizeof(CK_BBOOL) }, + { CKA_TRUSTED, &trusted, sizeof(CK_BBOOL) }, + { CKA_COPYABLE, ©able, sizeof(CK_BBOOL) }, + { CKA_DESTROYABLE, &destroyable, sizeof(CK_BBOOL) }, + { CKA_LOCAL, &local, sizeof(CK_BBOOL) }, + { CKA_ENCRYPT, &encrypt, sizeof(CK_BBOOL) }, + { CKA_DECRYPT, &decrypt, sizeof(CK_BBOOL) }, + { CKA_VERIFY, &verify, sizeof(CK_BBOOL) }, + { CKA_VERIFY_RECOVER, &verifyRecover, sizeof(CK_BBOOL) }, + { CKA_SIGN, &sign, sizeof(CK_BBOOL) }, + { CKA_SIGN_RECOVER, &signRecover, sizeof(CK_BBOOL) }, + { CKA_WRAP, &wrap, sizeof(CK_BBOOL) }, + { CKA_UNWRAP, &unwrap, sizeof(CK_BBOOL) }, + { CKA_DERIVE, &derive, sizeof(CK_BBOOL) }, + }; + CK_ULONG boolTmplCnt = sizeof(boolTmpl) / sizeof(*boolTmpl); + CK_ATTRIBUTE boolSetTmpl[] = { + { CKA_PRIVATE, &privateBool, sizeof(CK_BBOOL) }, + { CKA_SENSITIVE, &sensitive, sizeof(CK_BBOOL) }, + { CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL) }, + { CKA_MODIFIABLE, &modifiable, sizeof(CK_BBOOL) }, + { CKA_ALWAYS_SENSITIVE, &alwaysSensitive, sizeof(CK_BBOOL) }, + { CKA_NEVER_EXTRACTABLE, &neverExtractable, sizeof(CK_BBOOL) }, + { CKA_ALWAYS_AUTHENTICATE, &alwaysAuthenticate, sizeof(CK_BBOOL) }, + { CKA_WRAP_WITH_TRUSTED, &wrapWithTrusted, sizeof(CK_BBOOL) }, + { CKA_TRUSTED, &trusted, sizeof(CK_BBOOL) }, + { CKA_ENCRYPT, &encrypt, sizeof(CK_BBOOL) }, + { CKA_DECRYPT, &decrypt, sizeof(CK_BBOOL) }, + { CKA_VERIFY, &verify, sizeof(CK_BBOOL) }, + { CKA_VERIFY_RECOVER, &verifyRecover, sizeof(CK_BBOOL) }, + { CKA_SIGN, &sign, sizeof(CK_BBOOL) }, + { CKA_SIGN_RECOVER, &signRecover, sizeof(CK_BBOOL) }, + { CKA_WRAP, &wrap, sizeof(CK_BBOOL) }, + { CKA_UNWRAP, &unwrap, sizeof(CK_BBOOL) }, + { CKA_DERIVE, &derive, sizeof(CK_BBOOL) }, +#if 0 + { CKA_LOCAL, &local, sizeof(CK_BBOOL) }, + { CKA_DESTROYABLE, &destroyable, sizeof(CK_BBOOL) }, + { CKA_COPYABLE, ©able, sizeof(CK_BBOOL) }, +#endif + }; + CK_ULONG boolSetTmplCnt = sizeof(boolSetTmpl) / sizeof(*boolSetTmpl); + CK_ATTRIBUTE badAttrsTmpl[] = { + { CKA_WRAP_TEMPLATE, NULL, 0 }, + { CKA_UNWRAP_TEMPLATE, NULL, 0 }, + { CKA_ALLOWED_MECHANISMS, NULL, 0 }, + }; + CK_ULONG badAttrsTmplCnt = sizeof(badAttrsTmpl) / sizeof(*badAttrsTmpl); + CK_DATE startDate = { {'2','0','1','8'}, {'0','1'}, {'0','1'} }; + CK_DATE endDate = { {'2','1','1','8'}, {'0','1'}, {'0','1'} }; + CK_CHAR label[32] = "The Key's Label!!!"; + CK_DATE emptyStartDate = { {'2','0','1','8'}, {'0','1'}, {'0','1'} }; + CK_DATE emptyEndDate = { {'2','1','1','8'}, {'0','1'}, {'0','1'} }; + CK_CHAR emptyLabel[32] = "The Key's Label!!!"; + CK_ATTRIBUTE setGetTmpl[] = { + { CKA_START_DATE, &emptyStartDate, sizeof(CK_DATE) }, + { CKA_END_DATE, &emptyEndDate, sizeof(CK_DATE) }, + { CKA_LABEL, emptyLabel, sizeof(emptyLabel) }, + }; + CK_ULONG setGetTmplCnt = sizeof(setGetTmpl) / sizeof(*setGetTmpl); + + /* Certificate test variables */ + CK_OBJECT_HANDLE certObj = CK_INVALID_HANDLE; + CK_CERTIFICATE_TYPE certType = CKC_X_509; + CK_BYTE subject[] = "C = US, ST = Montana, L = Bozeman, O = wolfSSL, " + "OU = Support, CN = www.wolfssl.com, emailAddress = info@wolfssl.com"; + CK_BYTE certificate[] = { 0x30, 0x82, 0x01, 0x00 }; /* Minimal cert data */ + CK_ATTRIBUTE certTmpl[] = { + { CKA_CLASS, &certificateClass, sizeof(certificateClass) }, + { CKA_CERTIFICATE_TYPE, &certType, sizeof(certType) }, + { CKA_SUBJECT, subject, sizeof(subject)-1 }, + { CKA_VALUE, certificate, sizeof(certificate) }, + }; + CK_ULONG certTmplCnt = sizeof(certTmpl) / sizeof(*certTmpl); + CK_BYTE subjectBuffer[256]; + CK_ATTRIBUTE subjectAttr[] = { + { CKA_SUBJECT, subjectBuffer, sizeof(subjectBuffer) }, + }; + int i; + + ret = funcList->C_CreateObject(session, tmpl, tmplCnt, &obj); + CHECK_CKR(ret, "Create Object"); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, boolTmpl, + boolTmplCnt); + CHECK_CKR(ret, "Get Boolean attributes"); + } + if (ret == CKR_OK) { + ret = funcList->C_SetAttributeValue(session, obj, boolSetTmpl, + boolSetTmplCnt); + CHECK_CKR(ret, "Set Boolean attributes"); + } + for (i = 0; i < (int)badAttrsTmplCnt; i++) { + ret = funcList->C_GetAttributeValue(session, obj, &badAttrsTmpl[i], 1); + CHECK_CKR_FAIL(ret, CK_UNAVAILABLE_INFORMATION, + "Get unavailable attribute"); + } + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, setGetTmpl, + setGetTmplCnt); + CHECK_CKR(ret, "Get Empty data attributes"); + } + if (ret == CKR_OK) { + setGetTmpl[0].pValue = &startDate; + setGetTmpl[0].ulValueLen = sizeof(CK_DATE); + setGetTmpl[1].pValue = &endDate; + setGetTmpl[1].ulValueLen = sizeof(CK_DATE); + setGetTmpl[2].pValue = label; + setGetTmpl[2].ulValueLen = sizeof(label); + ret = funcList->C_SetAttributeValue(session, obj, setGetTmpl, + setGetTmplCnt); + CHECK_CKR(ret, "Set Empty data attributes"); + } + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, setGetTmpl, + setGetTmplCnt); + CHECK_CKR(ret, "Get Empty data attributes"); + } + + /* Test CKA_SUBJECT attribute with CKO_CERTIFICATE object + * This verifies that CKA_SUBJECT is properly supported for certificate objects + * and that the subject data can be retrieved correctly. */ + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, certTmpl, certTmplCnt, + &certObj); + CHECK_CKR(ret, "Create Certificate Object"); + } + if (ret == CKR_OK) { + /* First get the required buffer size for CKA_SUBJECT */ + subjectAttr[0].pValue = NULL; + subjectAttr[0].ulValueLen = 0; + ret = funcList->C_GetAttributeValue(session, certObj, subjectAttr, 1); + CHECK_CKR(ret, "Get CKA_SUBJECT length from certificate"); + } + if (ret == CKR_OK) { + /* Verify the length matches our expected subject size */ + if (subjectAttr[0].ulValueLen != sizeof(subject)-1) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "CKA_SUBJECT length verification"); + } + } + if (ret == CKR_OK) { + /* Now get the actual CKA_SUBJECT data */ + subjectAttr[0].pValue = subjectBuffer; + subjectAttr[0].ulValueLen = sizeof(subjectBuffer); + ret = funcList->C_GetAttributeValue(session, certObj, subjectAttr, 1); + CHECK_CKR(ret, "Get CKA_SUBJECT data from certificate"); + } + if (ret == CKR_OK) { + /* Verify subject data matches what we set */ + if (subjectAttr[0].ulValueLen != sizeof(subject)-1 || + XMEMCMP(subjectAttr[0].pValue, subject, sizeof(subject)-1) != 0) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "CKA_SUBJECT data verification failed"); + } + } + + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + if (certObj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, certObj); + + return ret; +} + +static CK_RV test_attribute_get(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE obj2 = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE obj3 = CK_INVALID_HANDLE; + static byte keyData[] = { 0x01 }; + static byte id[] = { 0x01, 0x02, 0x03 }; + int i = 0; + CK_BBOOL falseBool = 0; + CK_ATTRIBUTE createTmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_ID, id, sizeof(id) }, + { CKA_PRIVATE, &falseBool, sizeof(falseBool) } + }; + CK_ULONG tmplCnt = sizeof(createTmpl) / sizeof(*createTmpl); + CK_ATTRIBUTE createTmpl2[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_ID, id, sizeof(id) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) } + }; + CK_ULONG tmplCnt2 = sizeof(createTmpl2) / sizeof(*createTmpl2); + CK_ATTRIBUTE createTmpl3[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_ID, id, sizeof(id) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) } + }; + CK_ULONG tmplCnt3 = sizeof(createTmpl3) / sizeof(*createTmpl3); + CK_ATTRIBUTE updateTmpl[] = { + { CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) }, + }; + CK_ULONG updateTmplCnt = sizeof(updateTmpl) / sizeof(*updateTmpl); + CK_ATTRIBUTE getTmpl[] = { + { CKA_CLASS, NULL, 0 }, + { CKA_KEY_TYPE, NULL, 0 }, + { CKA_PRIVATE, NULL, 0 }, + { CKA_ID, NULL, 0 }, + }; + CK_ULONG getTmplCnt = sizeof(getTmpl) / sizeof(*getTmpl); + CK_ATTRIBUTE getTmpl2[] = { + { CKA_VALUE, NULL, 0 }, + }; + CK_ULONG getTmplCnt2 = sizeof(getTmpl2) / sizeof(*getTmpl2); + + ret = funcList->C_CreateObject(session, createTmpl, tmplCnt, &obj); + CHECK_CKR(ret, "Create Object"); + + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, getTmpl, getTmplCnt); + CHECK_CKR(ret, "C_GetAttributeValue"); + } + + if (ret == CKR_OK) { + for (i = 0; i < (int)getTmplCnt; i++) { + getTmpl[i].pValue = XMALLOC(getTmpl[i].ulValueLen * sizeof(byte), + NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (getTmpl[i].pValue == NULL) + ret = CKR_DEVICE_MEMORY; + CHECK_CKR(ret, "Allocate get attribute memory"); + } + } + + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, getTmpl, getTmplCnt); + CHECK_CKR(ret, "C_GetAttributeValue"); + } + + if (ret == CKR_OK) { + if (getTmpl[0].ulValueLen != sizeof(pubKeyClass) || + (*((CK_OBJECT_CLASS *)(getTmpl[0].pValue))) != pubKeyClass) { + ret = -1; + CHECK_CKR(ret, "CKA_CLASS value match creation params"); + } + } + + if (ret == CKR_OK) { + if (getTmpl[1].ulValueLen != sizeof(genericKeyType) || + (*((CK_OBJECT_CLASS *)(getTmpl[1].pValue))) != genericKeyType) { + ret = -1; + CHECK_CKR(ret, "CKA_KEY_TYPE value match creation params"); + } + } + + if (ret == CKR_OK) { + if (getTmpl[2].ulValueLen != sizeof(falseBool) || + (*((CK_BBOOL *)(getTmpl[2].pValue))) != falseBool) { + ret = -1; + CHECK_CKR(ret, "CKA_PRIVATE boolean match creation params"); + } + } + + if (ret == CKR_OK) { + if (getTmpl[3].ulValueLen != sizeof(id) || + XMEMCMP(getTmpl[3].pValue, id, sizeof(id)) != 0) { + ret = -1; + CHECK_CKR(ret, "CKA_ID value and len match creation params"); + } + } + + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, createTmpl2, tmplCnt2, &obj2); + CHECK_CKR(ret, "Create Object 2"); + } + + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, createTmpl3, tmplCnt3, &obj3); + CHECK_CKR(ret, "Create Object 3"); + } + + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, getTmpl2, getTmplCnt2); + CHECK_CKR(ret, "Get Attributes pass"); + } + + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj2, getTmpl2, getTmplCnt2); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "Get Attributes not extractable"); + } + + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj3, getTmpl2, getTmplCnt2); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "Get Attributes sensitive"); + } + + if (ret == CKR_OK) { + ret = funcList->C_SetAttributeValue(session, obj3, updateTmpl, + updateTmplCnt); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_READ_ONLY, + "Update attribute sensitive"); + } + + for (i = 0; i < (int)getTmplCnt; i++) + { + if (getTmpl[i].pValue != NULL) + XFREE(getTmpl[i].pValue, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + + 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"; + static byte testApplication[] = "TestApplication"; + static byte testObjectId[] = {0x01, 0x02, 0x03, 0x04}; + + /* 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) }, + { 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 */ + 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) }, + { CKA_APPLICATION, testApplication, sizeof(testApplication) }, + { CKA_OBJECT_ID, testObjectId, sizeof(testObjectId) } + }; + 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 }, + { 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 */ + 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); + + 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"); + } + + /* 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"); + } + } + + 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) }; + 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"); + } } } - if (obj != CK_INVALID_HANDLE) - funcList->C_DestroyObject(session, obj); - if (certObj != CK_INVALID_HANDLE) - funcList->C_DestroyObject(session, certObj); + /* 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 test_attribute_get(void* args) +static CK_RV test_data_object_null_value(void* args) { CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; - CK_RV ret; - CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; - CK_OBJECT_HANDLE obj2 = CK_INVALID_HANDLE; - CK_OBJECT_HANDLE obj3 = CK_INVALID_HANDLE; - static byte keyData[] = { 0x01 }; - static byte id[] = { 0x01, 0x02, 0x03 }; - int i = 0; - CK_BBOOL falseBool = 0; - CK_ATTRIBUTE createTmpl[] = { - { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, - { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, - { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, - { CKA_VALUE, keyData, sizeof(keyData) }, - { CKA_ID, id, sizeof(id) }, - { CKA_PRIVATE, &falseBool, sizeof(falseBool) } - }; - CK_ULONG tmplCnt = sizeof(createTmpl) / sizeof(*createTmpl); - CK_ATTRIBUTE createTmpl2[] = { - { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, - { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, - { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) }, - { CKA_VALUE, keyData, sizeof(keyData) }, - { CKA_ID, id, sizeof(id) }, - { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) } - }; - CK_ULONG tmplCnt2 = sizeof(createTmpl2) / sizeof(*createTmpl2); - CK_ATTRIBUTE createTmpl3[] = { - { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, - { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, - { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, - { CKA_VALUE, keyData, sizeof(keyData) }, - { CKA_ID, id, sizeof(id) }, - { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) } - }; - CK_ULONG tmplCnt3 = sizeof(createTmpl3) / sizeof(*createTmpl3); - CK_ATTRIBUTE updateTmpl[] = { - { CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) }, - }; - CK_ULONG updateTmplCnt = sizeof(updateTmpl) / sizeof(*updateTmpl); - CK_ATTRIBUTE getTmpl[] = { - { CKA_CLASS, NULL, 0 }, - { CKA_KEY_TYPE, NULL, 0 }, - { CKA_PRIVATE, NULL, 0 }, - { CKA_ID, NULL, 0 }, - }; - CK_ULONG getTmplCnt = sizeof(getTmpl) / sizeof(*getTmpl); - CK_ATTRIBUTE getTmpl2[] = { - { CKA_VALUE, NULL, 0 }, - }; - CK_ULONG getTmplCnt2 = sizeof(getTmpl2) / sizeof(*getTmpl2); + 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]; - ret = funcList->C_CreateObject(session, createTmpl, tmplCnt, &obj); - CHECK_CKR(ret, "Create Object"); + /* 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_GetAttributeValue(session, obj, getTmpl, getTmplCnt); - CHECK_CKR(ret, "C_GetAttributeValue"); + 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) { - for (i = 0; i < (int)getTmplCnt; i++) { - getTmpl[i].pValue = XMALLOC(getTmpl[i].ulValueLen * sizeof(byte), - NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (getTmpl[i].pValue == NULL) - ret = CKR_DEVICE_MEMORY; - CHECK_CKR(ret, "Allocate get attribute memory"); + 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) { - ret = funcList->C_GetAttributeValue(session, obj, getTmpl, getTmplCnt); - CHECK_CKR(ret, "C_GetAttributeValue"); + 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) { - if (getTmpl[0].ulValueLen != sizeof(pubKeyClass) || - (*((CK_OBJECT_CLASS *)(getTmpl[0].pValue))) != pubKeyClass) { - ret = -1; - CHECK_CKR(ret, "CKA_CLASS value match creation params"); + 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 (getTmpl[1].ulValueLen != sizeof(genericKeyType) || - (*((CK_OBJECT_CLASS *)(getTmpl[1].pValue))) != genericKeyType) { - ret = -1; - CHECK_CKR(ret, "CKA_KEY_TYPE value match creation params"); + 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 (getTmpl[2].ulValueLen != sizeof(falseBool) || - (*((CK_BBOOL *)(getTmpl[2].pValue))) != falseBool) { - ret = -1; - CHECK_CKR(ret, "CKA_PRIVATE boolean match creation params"); + if (getTemplate[2].ulValueLen != 0) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value should remain length 0"); } } if (ret == CKR_OK) { - if (getTmpl[3].ulValueLen != sizeof(id) || - XMEMCMP(getTmpl[3].pValue, id, sizeof(id)) != 0) { - ret = -1; - CHECK_CKR(ret, "CKA_ID value and len match creation params"); + if (retToken != sessionFalse) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value token attribute verification"); } } if (ret == CKR_OK) { - ret = funcList->C_CreateObject(session, createTmpl2, tmplCnt2, &obj2); - CHECK_CKR(ret, "Create Object 2"); + if (retPrivate != sessionFalse) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value private attribute verification"); + } } if (ret == CKR_OK) { - ret = funcList->C_CreateObject(session, createTmpl3, tmplCnt3, &obj3); - CHECK_CKR(ret, "Create Object 3"); + if (retModifiable != ckTrue) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value modifiable attribute verification"); + } } if (ret == CKR_OK) { - ret = funcList->C_GetAttributeValue(session, obj, getTmpl2, getTmplCnt2); - CHECK_CKR(ret, "Get Attributes pass"); + if (XMEMCMP(retApplication, testApplication, sizeof(testApplication)) != 0) { + ret = -1; + CHECK_CKR(ret, "CKO_DATA NULL value application attribute verification"); + } } if (ret == CKR_OK) { - ret = funcList->C_GetAttributeValue(session, obj2, getTmpl2, getTmplCnt2); - CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, - "Get Attributes not extractable"); + 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) { - ret = funcList->C_GetAttributeValue(session, obj3, getTmpl2, getTmplCnt2); - CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, - "Get Attributes sensitive"); + 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) { - ret = funcList->C_SetAttributeValue(session, obj3, updateTmpl, - updateTmplCnt); - CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_READ_ONLY, - "Update attribute sensitive"); + 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"); + } + } } - for (i = 0; i < (int)getTmplCnt; i++) - { - if (getTmpl[i].pValue != NULL) - XFREE(getTmpl[i].pValue, NULL, DYNAMIC_TYPE_TMP_BUFFER); + /* Clean up */ + if (dataObj != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, dataObj); + } + if (dataObjToken != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, dataObjToken); } - if (obj != CK_INVALID_HANDLE) - funcList->C_DestroyObject(session, obj); return ret; } @@ -2569,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 @@ -4126,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) }, @@ -4301,9 +5716,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); @@ -4335,6 +5752,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; @@ -4358,6 +5776,127 @@ 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; + 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; +} +#endif + static CK_RV test_attributes_rsa(void* args) { CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; @@ -5718,14 +7257,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; @@ -5785,48 +7324,34 @@ 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); + 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; } - 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 +8509,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 @@ -9272,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; @@ -13613,6 +15158,13 @@ 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 +#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), @@ -13620,6 +15172,8 @@ 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_data_object_null_value), PKCS11TEST_FUNC_SESS_DECL(test_attributes_secret), #ifndef NO_RSA PKCS11TEST_FUNC_SESS_DECL(test_attributes_rsa), @@ -13651,6 +15205,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 */ +#if (!defined(NO_RSA) && !defined(WOLFPKCS11_NO_STORE)) + PKCS11TEST_FUNC_SESS_DECL(test_rsa_wrap_unwrap_key), +#endif #ifndef NO_DH PKCS11TEST_FUNC_SESS_DECL(test_derive_key), #endif @@ -13700,6 +15257,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 diff --git a/wolfpkcs11/internal.h b/wolfpkcs11/internal.h index f9e3791b..97f37d15 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 @@ -374,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); @@ -388,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); @@ -395,6 +406,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, @@ -464,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); diff --git a/wolfpkcs11/pkcs11.h b/wolfpkcs11/pkcs11.h index 17e75bdf..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 @@ -322,6 +324,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 @@ -607,6 +610,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; 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.