diff --git a/src/crypto.c b/src/crypto.c index 0326e02c..99e7492c 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -42,6 +42,13 @@ #define PRF_KEY_SIZE 48 +/* Check that a CK_ULONG value fits in word32 with room for overhead such as + * authentication tags, key wrap blocks, or padding. On LP64 platforms CK_ULONG + * is 64-bit but wolfCrypt functions use word32/int for lengths. */ +#define CK_ULONG_MAX_OVERHEAD ((CK_ULONG)64) +#define CK_ULONG_FITS_WORD32(v) \ + ((v) <= (CK_ULONG)0xFFFFFFFF - CK_ULONG_MAX_OVERHEAD) + #define CHECK_KEYTYPE(kt) \ (kt == CKK_RSA || kt == CKK_EC || kt == CKK_DH || \ kt == CKK_AES || kt == CKK_HKDF || kt == CKK_GENERIC_SECRET) ? \ @@ -256,6 +263,16 @@ static AttributeType attrType[] = { /* Count of elements in attribute type list. */ #define ATTR_TYPE_SIZE (sizeof(attrType) / sizeof(*attrType)) +static int IsKnownAttrType(CK_ATTRIBUTE_TYPE type) +{ + int j; + for (j = 0; j < (int)ATTR_TYPE_SIZE; j++) { + if (attrType[j].attr == type) + return 1; + } + return 0; +} + /** * Find the attribute type in the template. * @@ -584,7 +601,8 @@ static CK_RV SetAttributeValue(WP11_Session* session, WP11_Object* obj, if (pTemplate == NULL) return CKR_ARGUMENTS_BAD; - if (!WP11_Session_IsRW(session)) + /* Only require R/W session for token objects */ + if (!WP11_Session_IsRW(session) && WP11_Object_OnToken(obj)) return CKR_SESSION_READ_ONLY; rv = CheckAttributes(pTemplate, ulCount, 1); @@ -1134,10 +1152,23 @@ CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, WOLFPKCS11_LEAVE("C_CreateObject", rv); return rv; } + /* Only require R/W session for token objects */ if (!WP11_Session_IsRW(session)) { - rv = CKR_SESSION_READ_ONLY; - WOLFPKCS11_LEAVE("C_CreateObject", rv); - return rv; + CK_ATTRIBUTE* tokenAttr = NULL; + FindAttributeType(pTemplate, ulCount, CKA_TOKEN, &tokenAttr); + if (tokenAttr != NULL) { + if (tokenAttr->pValue == NULL || + tokenAttr->ulValueLen != sizeof(CK_BBOOL)) { + rv = CKR_ATTRIBUTE_VALUE_INVALID; + WOLFPKCS11_LEAVE("C_CreateObject", rv); + return rv; + } + if (*(CK_BBOOL*)tokenAttr->pValue == CK_TRUE) { + rv = CKR_SESSION_READ_ONLY; + WOLFPKCS11_LEAVE("C_CreateObject", rv); + return rv; + } + } } rv = CreateObject(session, pTemplate, ulCount, &object); @@ -1216,19 +1247,12 @@ CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, WOLFPKCS11_LEAVE("C_CopyObject", rv); return rv; } - if (!WP11_Session_IsRW(session)) { - rv = CKR_SESSION_READ_ONLY; - 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 * new object from template. @@ -1236,6 +1260,23 @@ CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, ret = WP11_Object_Find(session, hObject, &obj); if (ret != 0) return CKR_OBJECT_HANDLE_INVALID; + + /* Only require R/W session for token objects. The copy inherits the + * source object's CKA_TOKEN unless the template overrides it. */ + if (!WP11_Session_IsRW(session)) { + int willBeOnToken = WP11_Object_OnToken(obj); + CK_ATTRIBUTE* tokenAttr = NULL; + FindAttributeType(pTemplate, ulCount, CKA_TOKEN, &tokenAttr); + if (tokenAttr != NULL && tokenAttr->pValue != NULL && + tokenAttr->ulValueLen == sizeof(CK_BBOOL)) { + willBeOnToken = *(CK_BBOOL*)tokenAttr->pValue; + } + if (willBeOnToken) { + rv = CKR_SESSION_READ_ONLY; + WOLFPKCS11_LEAVE("C_CopyObject", rv); + return rv; + } + } keyType = WP11_Object_GetType(obj); FindAttributeType(pTemplate, ulCount, CKA_TOKEN, &attr); @@ -1333,11 +1374,6 @@ CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, WOLFPKCS11_LEAVE("C_DestroyObject", rv); return rv; } - if (!WP11_Session_IsRW(session)) { - rv = CKR_SESSION_READ_ONLY; - WOLFPKCS11_LEAVE("C_DestroyObject", rv); - return rv; - } ret = WP11_Object_Find(session, hObject, &obj); if (ret != 0) { @@ -1346,6 +1382,13 @@ CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, return rv; } + /* Only require R/W session for token objects */ + if (!WP11_Session_IsRW(session) && WP11_Object_OnToken(obj)) { + rv = CKR_SESSION_READ_ONLY; + WOLFPKCS11_LEAVE("C_DestroyObject", rv); + return rv; + } + rv = WP11_Session_RemoveObject(session, obj); WP11_Object_Free(obj); @@ -1475,35 +1518,38 @@ CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession, return rv; } - /* Check the value and lengths of attributes based on data type. */ - rv = CheckAttributes(pTemplate, ulCount, 0); - if (rv != CKR_OK) { - WOLFPKCS11_LEAVE("C_GetAttributeValue", rv); - return rv; - } - + rv = CKR_OK; for (i = 0; i < (int)ulCount; i++) { attr = &pTemplate[i]; + if (!IsKnownAttrType(attr->type)) { + attr->ulValueLen = (CK_ULONG)-1; + if (rv == CKR_OK) + rv = CKR_ATTRIBUTE_TYPE_INVALID; + continue; + } + ret = WP11_Object_GetAttr(obj, attr->type, (byte*)attr->pValue, &attr->ulValueLen); if (ret == BAD_FUNC_ARG) { - rv = CKR_ATTRIBUTE_TYPE_INVALID; - WOLFPKCS11_LEAVE("C_GetAttributeValue", rv); - return rv; + attr->ulValueLen = (CK_ULONG)-1; + if (rv == CKR_OK) + rv = CKR_ATTRIBUTE_TYPE_INVALID; + } + else if (ret == NOT_AVAILABLE_E) { + attr->ulValueLen = (CK_ULONG)-1; + if (rv == CKR_OK) + rv = CK_UNAVAILABLE_INFORMATION; } else if (ret == BUFFER_E) { - rv = CKR_BUFFER_TOO_SMALL; - WOLFPKCS11_LEAVE("C_GetAttributeValue", rv); - return rv; + if (rv == CKR_OK) + rv = CKR_BUFFER_TOO_SMALL; } - else if (ret == NOT_AVAILABLE_E) { - rv = CK_UNAVAILABLE_INFORMATION; - WOLFPKCS11_LEAVE("C_GetAttributeValue", rv); - return rv; + else if (ret == CKR_ATTRIBUTE_SENSITIVE) { + attr->ulValueLen = (CK_ULONG)-1; + if (rv == CKR_OK) + rv = ret; } - else if (ret == CKR_ATTRIBUTE_SENSITIVE) - rv = ret; else if (ret != 0) { rv = CKR_FUNCTION_FAILED; WOLFPKCS11_LEAVE("C_GetAttributeValue", rv); @@ -1569,11 +1615,6 @@ CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession, WOLFPKCS11_LEAVE("C_SetAttributeValue", rv); return rv; } - if (!WP11_Session_IsRW(session)) { - rv = CKR_SESSION_READ_ONLY; - WOLFPKCS11_LEAVE("C_SetAttributeValue", rv); - return rv; - } ret = WP11_Object_Find(session, hObject, &obj); if (ret != 0) { @@ -1582,6 +1623,13 @@ CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession, return rv; } + /* Only require R/W session for token objects */ + if (!WP11_Session_IsRW(session) && WP11_Object_OnToken(obj)) { + rv = CKR_SESSION_READ_ONLY; + WOLFPKCS11_LEAVE("C_SetAttributeValue", rv); + return rv; + } + rv = SetAttributeValue(session, obj, pTemplate, ulCount, CK_FALSE); WOLFPKCS11_LEAVE("C_SetAttributeValue", rv); return rv; @@ -1709,6 +1757,12 @@ CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, return rv; } + if (!WP11_Session_IsFindActive(session)) { + rv = CKR_OPERATION_NOT_INITIALIZED; + WOLFPKCS11_LEAVE("C_FindObjects", rv); + return rv; + } + for (i = 0; i < (int)ulMaxObjectCount; i++) { if (WP11_Session_FindGet(session, &handle) == FIND_NO_MORE_E) break; @@ -1753,6 +1807,12 @@ CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession) return rv; } + if (!WP11_Session_IsFindActive(session)) { + rv = CKR_OPERATION_NOT_INITIALIZED; + WOLFPKCS11_LEAVE("C_FindObjectsFinal", rv); + return rv; + } + WP11_Session_FindFinal(session); rv = CKR_OK; @@ -2187,6 +2247,8 @@ CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, case CKM_AES_CBC: if (!WP11_Session_IsOpInitialized(session, WP11_INIT_AES_CBC_ENC)) return CKR_OPERATION_NOT_INITIALIZED; + if (!CK_ULONG_FITS_WORD32(ulDataLen)) + return CKR_DATA_LEN_RANGE; encDataLen = (word32)ulDataLen; if (pEncryptedData == NULL) { @@ -2207,6 +2269,8 @@ CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, WP11_INIT_AES_CBC_PAD_ENC)) { return CKR_OPERATION_NOT_INITIALIZED; } + if (!CK_ULONG_FITS_WORD32(ulDataLen)) + return CKR_DATA_LEN_RANGE; /* PKCS#5 pad makes the output a multiple of 16 */ encDataLen = (word32)((ulDataLen + AES_BLOCK_SIZE - 1) / @@ -2249,6 +2313,8 @@ CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, case CKM_AES_GCM: if (!WP11_Session_IsOpInitialized(session, WP11_INIT_AES_GCM_ENC)) return CKR_OPERATION_NOT_INITIALIZED; + if (!CK_ULONG_FITS_WORD32(ulDataLen)) + return CKR_DATA_LEN_RANGE; encDataLen = (word32)ulDataLen + WP11_AesGcm_GetTagBits(session) / 8; @@ -2270,6 +2336,8 @@ CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, case CKM_AES_CCM: if (!WP11_Session_IsOpInitialized(session, WP11_INIT_AES_CCM_ENC)) return CKR_OPERATION_NOT_INITIALIZED; + if (!CK_ULONG_FITS_WORD32(ulDataLen)) + return CKR_DATA_LEN_RANGE; encDataLen = (word32)ulDataLen + WP11_AesCcm_GetMacLen(session); @@ -2291,6 +2359,8 @@ CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, case CKM_AES_ECB: if (!WP11_Session_IsOpInitialized(session, WP11_INIT_AES_ECB_ENC)) return CKR_OPERATION_NOT_INITIALIZED; + if (!CK_ULONG_FITS_WORD32(ulDataLen)) + return CKR_DATA_LEN_RANGE; encDataLen = (word32)ulDataLen; if (pEncryptedData == NULL) { @@ -2331,6 +2401,8 @@ CK_RV C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, case CKM_AES_KEY_WRAP: if (!WP11_Session_IsOpInitialized(session, WP11_INIT_AES_KEYWRAP_ENC)) return CKR_OPERATION_NOT_INITIALIZED; + if (!CK_ULONG_FITS_WORD32(ulDataLen)) + return CKR_DATA_LEN_RANGE; /* AES Key Wrap adds 8 bytes for the integrity check value */ encDataLen = (word32)(ulDataLen + KEYWRAP_BLOCK_SIZE); @@ -2461,6 +2533,8 @@ CK_RV C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, WOLFPKCS11_LEAVE("C_EncryptUpdate", rv); return rv; } + if (!CK_ULONG_FITS_WORD32(ulPartLen)) + return CKR_DATA_LEN_RANGE; encPartLen = (word32)ulPartLen + WP11_AesCbc_PartLen(session); encPartLen &= ~0xf; @@ -2491,6 +2565,8 @@ CK_RV C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, WP11_INIT_AES_CBC_PAD_ENC)) { return CKR_OPERATION_NOT_INITIALIZED; } + if (!CK_ULONG_FITS_WORD32(ulPartLen)) + return CKR_DATA_LEN_RANGE; encPartLen = (word32)ulPartLen + WP11_AesCbc_PartLen(session); encPartLen &= ~0xf; @@ -3149,6 +3225,8 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, case CKM_AES_CBC: if (!WP11_Session_IsOpInitialized(session, WP11_INIT_AES_CBC_DEC)) return CKR_OPERATION_NOT_INITIALIZED; + if (!CK_ULONG_FITS_WORD32(ulEncryptedDataLen)) + return CKR_DATA_LEN_RANGE; decDataLen = (word32)ulEncryptedDataLen; if (pData == NULL) { @@ -3169,6 +3247,8 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, WP11_INIT_AES_CBC_PAD_DEC)) { return CKR_OPERATION_NOT_INITIALIZED; } + if (!CK_ULONG_FITS_WORD32(ulEncryptedDataLen)) + return CKR_DATA_LEN_RANGE; decDataLen = (word32)ulEncryptedDataLen; if (pData == NULL) { @@ -3254,6 +3334,8 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, case CKM_AES_ECB: if (!WP11_Session_IsOpInitialized(session, WP11_INIT_AES_ECB_DEC)) return CKR_OPERATION_NOT_INITIALIZED; + if (!CK_ULONG_FITS_WORD32(ulEncryptedDataLen)) + return CKR_DATA_LEN_RANGE; decDataLen = (word32)ulEncryptedDataLen; if (pData == NULL) { @@ -3421,6 +3503,8 @@ CK_RV C_DecryptUpdate(CK_SESSION_HANDLE hSession, case CKM_AES_CBC: if (!WP11_Session_IsOpInitialized(session, WP11_INIT_AES_CBC_DEC)) return CKR_OPERATION_NOT_INITIALIZED; + if (!CK_ULONG_FITS_WORD32(ulEncryptedPartLen)) + return CKR_DATA_LEN_RANGE; decPartLen = (word32)ulEncryptedPartLen + WP11_AesCbc_PartLen(session); @@ -3444,6 +3528,8 @@ CK_RV C_DecryptUpdate(CK_SESSION_HANDLE hSession, WP11_INIT_AES_CBC_PAD_DEC)) { return CKR_OPERATION_NOT_INITIALIZED; } + if (!CK_ULONG_FITS_WORD32(ulEncryptedPartLen)) + return CKR_DATA_LEN_RANGE; decPartLen = (word32)ulEncryptedPartLen + WP11_AesCbc_PartLen(session); @@ -6088,11 +6174,14 @@ CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, if (ret != CKR_OK) return ret; + if (WP11_Session_IsOpInitialized(session, init)) { + return CKR_OPERATION_ACTIVE; + } + WP11_Session_SetMechanism(session, pMechanism->mechanism); WP11_Session_SetObject(session, obj); WP11_Session_SetOpInitialized(session, init); - return CKR_OK; } @@ -7034,10 +7123,16 @@ CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, rv = SetInitialStates(priv); } - if (rv != CKR_OK && pub != NULL) + if (rv != CKR_OK && pub != NULL) { + if (*phPublicKey != CK_INVALID_HANDLE) + (void)WP11_Session_RemoveObject(session, pub); WP11_Object_Free(pub); - if (rv != CKR_OK && priv != NULL) + } + if (rv != CKR_OK && priv != NULL) { + if (*phPrivateKey != CK_INVALID_HANDLE) + (void)WP11_Session_RemoveObject(session, priv); WP11_Object_Free(priv); + } return rv; } @@ -7110,9 +7205,6 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, return rv; } - if (! WP11_Session_IsRW(session)) - return CKR_SESSION_READ_ONLY; - ret = WP11_Object_Find(session, hKey, &key); if (ret != 0) return CKR_OBJECT_HANDLE_INVALID; @@ -7369,12 +7461,6 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, return rv; } - if (!WP11_Session_IsRW(session)) { - rv = CKR_SESSION_READ_ONLY; - WOLFPKCS11_LEAVE("C_UnwrapKey", rv); - return rv; - } - if (pMechanism == NULL || pWrappedKey == NULL || ulWrappedKeyLen == 0 || pTemplate == NULL || phKey == NULL) { rv = CKR_ARGUMENTS_BAD; @@ -7382,6 +7468,25 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, return rv; } + /* Only require R/W session for token objects */ + if (!WP11_Session_IsRW(session)) { + CK_ATTRIBUTE* tokenAttr = NULL; + FindAttributeType(pTemplate, ulAttributeCount, CKA_TOKEN, &tokenAttr); + if (tokenAttr != NULL) { + if (tokenAttr->pValue == NULL || + tokenAttr->ulValueLen != sizeof(CK_BBOOL)) { + rv = CKR_ATTRIBUTE_VALUE_INVALID; + WOLFPKCS11_LEAVE("C_UnwrapKey", rv); + return rv; + } + if (*(CK_BBOOL*)tokenAttr->pValue == CK_TRUE) { + rv = CKR_SESSION_READ_ONLY; + WOLFPKCS11_LEAVE("C_UnwrapKey", rv); + return rv; + } + } + } + *phKey = CK_INVALID_HANDLE; ret = WP11_Object_Find(session, hUnwrappingKey, &unwrappingKey); diff --git a/src/internal.c b/src/internal.c index 883796c0..97b17eb9 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6578,6 +6578,8 @@ int WP11_Slot_CheckSOPin(WP11_Slot* slot, char* pin, int pinLen) ret = PIN_INVALID_E; WP11_Lock_UnlockRO(&slot->lock); + wc_ForceZero(hash, sizeof(hash)); + return ret; } @@ -6619,6 +6621,8 @@ int WP11_Slot_CheckUserPin(WP11_Slot* slot, char* pin, int pinLen) ret = PIN_INVALID_E; WP11_Lock_UnlockRO(&slot->lock); + wc_ForceZero(hash, sizeof(hash)); + return ret; } @@ -6922,6 +6926,25 @@ int WP11_Slot_SetUserPin(WP11_Slot* slot, char* pin, int pinLen) * * @param slot [in] Slot object referencing token. */ +/** + * Check whether any user is logged in to the token. + * + * @param slot [in] Slot object referencing token. + * @return 1 when a user (SO or normal) is logged in. + * 0 when no user is logged in (public session). + */ +int WP11_Slot_IsLoggedIn(WP11_Slot* slot) +{ + int state; + + WP11_Lock_LockRO(&slot->lock); + state = slot->token.loginState; + WP11_Lock_UnlockRO(&slot->lock); + + return (state != WP11_APP_STATE_RO_PUBLIC && + state != WP11_APP_STATE_RW_PUBLIC); +} + void WP11_Slot_Logout(WP11_Slot* slot) { #ifndef WOLFPKCS11_NO_STORE @@ -7494,6 +7517,9 @@ int WP11_Session_SetOaepParams(WP11_Session* session, CK_MECHANISM_TYPE hashAlg, int ret; WP11_OaepParams* oaep = &session->params.oaep; + if (session->mechanism == CKM_RSA_PKCS_OAEP && oaep->label != NULL) { + XFREE(oaep->label, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } XMEMSET(oaep, 0, sizeof(*oaep)); ret = wp11_hash_type(hashAlg, &oaep->hashType); if (ret == 0) @@ -7774,6 +7800,9 @@ int WP11_Session_SetGcmParams(WP11_Session* session, unsigned char* iv, ret = BAD_FUNC_ARG; if (ret == 0) { + if (session->mechanism == CKM_AES_GCM && gcm->aad != NULL) { + XFREE(gcm->aad, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } XMEMSET(gcm, 0, sizeof(*gcm)); XMEMCPY(gcm->iv, iv, ivSz); gcm->ivSz = ivSz; @@ -7821,6 +7850,9 @@ int WP11_Session_SetCcmParams(WP11_Session* session, int dataSz, ret = BAD_FUNC_ARG; if (ret == 0) { + if (session->mechanism == CKM_AES_CCM && ccm->aad != NULL) { + XFREE(ccm->aad, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } XMEMSET(ccm, 0, sizeof(*ccm)); ccm->dataSz = dataSz; XMEMCPY(ccm->iv, iv, ivSz); @@ -8216,6 +8248,18 @@ void WP11_Session_FindFinal(WP11_Session* session) session->find.state = WP11_FIND_STATE_NULL; } +/** + * Check whether a find operation is active on the session. + * + * @param session [in] Session object. + * @return 1 when a find operation is active. + * 0 when no find operation is active. + */ +int WP11_Session_IsFindActive(WP11_Session* session) +{ + return session->find.state != WP11_FIND_STATE_NULL; +} + /** * Free the object and take it out of the linked list. @@ -8315,6 +8359,18 @@ CK_OBJECT_HANDLE WP11_Object_GetHandle(WP11_Object* object) return object->handle; } +/** + * Check whether the object is stored on the token. + * + * @param object [in] Object object. + * @return 1 when object is on token. + * 0 when object is a session object. + */ +int WP11_Object_OnToken(WP11_Object* object) +{ + return object->onToken; +} + /** * Get the object's type - for example the key type. * @@ -11277,6 +11333,9 @@ int WP11_Rsa_Sign(unsigned char* in, word32 inLen, unsigned char* sig, byte data[RSA_MAX_SIZE / 8]; word32 keyLen; + if (priv->onToken) + WP11_Lock_LockRO(priv->lock); + keyLen = wc_RsaEncryptSize(priv->data.rsaKey); if (inLen < keyLen) { XMEMSET(data, 0, keyLen - inLen); @@ -11285,8 +11344,6 @@ int WP11_Rsa_Sign(unsigned char* in, word32 inLen, unsigned char* sig, inLen = keyLen; } - if (priv->onToken) - WP11_Lock_LockRO(priv->lock); ret = Rng_New(&slot->token.rng, &slot->token.rngLock, &rng); if (ret == 0) { #ifdef WOLFPKCS11_TPM @@ -11333,16 +11390,23 @@ int WP11_Rsa_Verify_Recover(CK_MECHANISM_TYPE mechanism, unsigned char* sig, { int ret; + if (pub->onToken) + WP11_Lock_LockRO(pub->lock); + switch (mechanism) { case CKM_RSA_PKCS: 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 CKR_FUNCTION_FAILED; - - *outLen = ret; + if (ret == RSA_BUFFER_E) { + ret = CKR_BUFFER_TOO_SMALL; + } + else if (ret < 0) { + ret = CKR_FUNCTION_FAILED; + } + else { + *outLen = ret; + ret = CKR_OK; + } break; case CKM_RSA_X_509: { @@ -11350,27 +11414,35 @@ int WP11_Rsa_Verify_Recover(CK_MECHANISM_TYPE mechanism, unsigned char* sig, byte* pos; ret = wc_RsaDirect(sig, sigLen, out, (word32*)outLen, pub->data.rsaKey, RSA_PUBLIC_DECRYPT, NULL); - if (ret < 0) - return CKR_FUNCTION_FAILED; - /* Result is front padded with 0x00 */ - for (pos = out; pos < out + *outLen; pos++) { - if (*pos != 0x00) { - data_out = pos; - break; - } + if (ret < 0) { + ret = CKR_FUNCTION_FAILED; } - if (data_out != NULL) { - *outLen = (out + *outLen) - data_out; - XMEMMOVE(out, data_out, *outLen); + else { + ret = CKR_OK; + /* Result is front padded with 0x00 */ + for (pos = out; pos < out + *outLen; pos++) { + if (*pos != 0x00) { + data_out = pos; + break; + } + } + if (data_out != NULL) { + *outLen = (out + *outLen) - data_out; + XMEMMOVE(out, data_out, *outLen); + } } break; } default: /* Should never happen */ - return CKR_FUNCTION_FAILED; + ret = CKR_FUNCTION_FAILED; + break; } - return CKR_OK; + if (pub->onToken) + WP11_Lock_UnlockRO(pub->lock); + + return ret; } /** @@ -11970,6 +12042,9 @@ int WP11_EC_Derive(unsigned char* point, word32 pointLen, unsigned char* key, WC_RNG rng; #endif + if (priv->onToken) + WP11_Lock_LockRO(priv->lock); + /* Check if the point data is DER-encoded (starts with OCTET STRING tag) */ if (pointLen >= 3 && point[0] == ASN_OCTET_STRING) { /* Strip DER encoding - similar to EcSetPoint function */ @@ -12012,12 +12087,11 @@ int WP11_EC_Derive(unsigned char* point, word32 pointLen, unsigned char* key, (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) if (ret == 0) { ret = Rng_New(&priv->slot->token.rng, &priv->slot->token.rngLock, &rng); - wc_ecc_set_rng(priv->data.ecKey, &rng); + if (ret == 0) + wc_ecc_set_rng(priv->data.ecKey, &rng); } #endif if (ret == 0) { - if (priv->onToken) - WP11_Lock_LockRO(priv->lock); #ifdef WOLFPKCS11_TPM ret = WP11_Object_LoadTpmKey(priv); if (ret == 0) @@ -12031,14 +12105,15 @@ int WP11_EC_Derive(unsigned char* point, word32 pointLen, unsigned char* key, wolfTPM2_UnloadHandle(&priv->slot->tpmDev, &priv->tpmKey->handle); #endif } - if (priv->onToken) - WP11_Lock_UnlockRO(priv->lock); #if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) Rng_Free(&rng); #endif } + if (priv->onToken) + WP11_Lock_UnlockRO(priv->lock); + wc_ecc_free(&pubKey); return ret; diff --git a/src/slot.c b/src/slot.c index bf99f8f0..25ea05f5 100644 --- a/src/slot.c +++ b/src/slot.c @@ -1930,6 +1930,13 @@ CK_RV C_Logout(CK_SESSION_HANDLE hSession) } slot = WP11_Session_GetSlot(session); + + if (!WP11_Slot_IsLoggedIn(slot)) { + rv = CKR_USER_NOT_LOGGED_IN; + WOLFPKCS11_LEAVE("C_Logout", rv); + return rv; + } + WP11_Slot_Logout(slot); rv = CKR_OK; diff --git a/tests/pkcs11mtt.c b/tests/pkcs11mtt.c index 4fd187fc..c3099e51 100644 --- a/tests/pkcs11mtt.c +++ b/tests/pkcs11mtt.c @@ -435,10 +435,21 @@ static CK_RV test_object(void* args) CHECK_CKR(ret, "Open Session - read-only"); } #ifndef WOLFPKCS11_NSS + /* Session objects can be created/copied/destroyed in RO sessions */ if (ret == CKR_OK) { ret = funcList->C_CreateObject(sessionRO, tmpl, tmplCnt, &obj); + CHECK_CKR(ret, "Create session Object in read-only session"); + } + if (ret == CKR_OK) { + funcList->C_DestroyObject(sessionRO, obj); + obj = CK_INVALID_HANDLE; + } + /* Token objects must be blocked in RO sessions */ + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(sessionRO, tmplOnToken, tmplOnTokenCnt, + &obj); CHECK_CKR_FAIL(ret, CKR_SESSION_READ_ONLY, - "Create Object in read-only session"); + "Create token Object in read-only session"); } if (ret == CKR_OK) { ret = funcList->C_CopyObject(sessionRO, objOnToken, copyTmpl, diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index 17a3e62f..2606cdb7 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -1016,6 +1016,13 @@ static CK_RV test_login_logout(void* args) CHECK_CKR_FAIL(ret, CKR_SESSION_HANDLE_INVALID, "Logout invalid session handle"); } + /* C_Logout should return CKR_USER_NOT_LOGGED_IN when no user is + * currently logged in. */ + if (ret == CKR_OK) { + ret = funcList->C_Logout(session); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "Logout when not logged in"); + } if (ret == CKR_OK) { ret = funcList->C_GetTokenInfo(slot, &tokenInfo); @@ -2182,21 +2189,17 @@ static CK_RV test_object(void* args) CHECK_CKR(ret, "Open Session - read-only"); } + /* Token objects must be blocked in RO sessions */ if (ret == CKR_OK) { - ret = funcList->C_CreateObject(sessionRO, tmpl, tmplCnt, &obj); - CHECK_CKR_FAIL(ret, CKR_SESSION_READ_ONLY, - "Create Object in read-only session"); - } - if (ret == CKR_OK) { - ret = funcList->C_CopyObject(sessionRO, objOnToken, copyTmpl, - copyTmplCnt, ©Obj); + ret = funcList->C_CreateObject(sessionRO, tmplOnToken, tmplOnTokenCnt, + &obj); CHECK_CKR_FAIL(ret, CKR_SESSION_READ_ONLY, - "Copy Object symmetric key in read-only session"); + "Create token Object in read-only session"); } if (ret == CKR_OK) { ret = funcList->C_DestroyObject(sessionRO, objOnToken); CHECK_CKR_FAIL(ret, CKR_SESSION_READ_ONLY, - "Destroy object in read-only session"); + "Destroy token object in read-only session"); } if (ret == CKR_OK && sessionRO != CK_INVALID_HANDLE) { @@ -4569,6 +4572,18 @@ static CK_RV test_find_objects(void* args) CHECK_CKR_FAIL(ret, CKR_SESSION_HANDLE_INVALID, "Find Objects Final invalid session handle"); } + /* C_FindObjects and C_FindObjectsFinal should return + * CKR_OPERATION_NOT_INITIALIZED when called without C_FindObjectsInit. */ + if (ret == CKR_OK) { + ret = funcList->C_FindObjects(session, &found, 1, &count); + CHECK_CKR_FAIL(ret, CKR_OPERATION_NOT_INITIALIZED, + "Find Objects without Init"); + } + if (ret == CKR_OK) { + ret = funcList->C_FindObjectsFinal(session); + CHECK_CKR_FAIL(ret, CKR_OPERATION_NOT_INITIALIZED, + "Find Objects Final without Init"); + } if (ret == CKR_OK) { ret = funcList->C_FindObjectsInit(session, findTmpl, findTmplCnt); @@ -16160,6 +16175,484 @@ static CK_RV test_private_object_access(void* args) return ret; } +/* C_GetAttributeValue must process all attributes in the template even when one + * returns an error, setting ulValueLen to (CK_ULONG)-1 for invalid types and + * returning the accumulated error. */ +static CK_RV test_get_attr_value_all_processed(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj; + static byte keyData[] = { 0x00 }; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + }; + CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); + CK_ATTRIBUTE getTmpl[3]; + + ret = funcList->C_CreateObject(session, tmpl, tmplCnt, &obj); + CHECK_CKR(ret, "Create Object for get attr test"); + + if (ret == CKR_OK) { + /* Query: valid attr, invalid attr (0xFFFFFFFF), valid attr. + * Per PKCS#11 spec, all attrs should be processed. */ + getTmpl[0].type = CKA_CLASS; + getTmpl[0].pValue = NULL; + getTmpl[0].ulValueLen = 0; + getTmpl[1].type = 0xFFFFFFFF; + getTmpl[1].pValue = NULL; + getTmpl[1].ulValueLen = 0; + getTmpl[2].type = CKA_KEY_TYPE; + getTmpl[2].pValue = NULL; + getTmpl[2].ulValueLen = 0; + + ret = funcList->C_GetAttributeValue(session, obj, getTmpl, 3); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_TYPE_INVALID, + "Get Attr Value with invalid type in middle"); + } + if (ret == CKR_OK) { + /* First attr should have its size set */ + CHECK_COND(getTmpl[0].ulValueLen == sizeof(CK_OBJECT_CLASS), ret, + "First attr ulValueLen set"); + } + if (ret == CKR_OK) { + /* Invalid attr should have ulValueLen set to (CK_ULONG)-1 */ + CHECK_COND(getTmpl[1].ulValueLen == (CK_ULONG)-1, ret, + "Invalid attr ulValueLen set to -1"); + } + if (ret == CKR_OK) { + /* Third attr must also be processed (not skipped by early return) */ + CHECK_COND(getTmpl[2].ulValueLen == sizeof(CK_KEY_TYPE), ret, + "Third attr ulValueLen set (not skipped)"); + } + + return ret; +} + +#ifndef WOLFPKCS11_NSS +/* Creating, copying, destroying, and setting attributes on session objects + * should be allowed in read-only sessions per the PKCS#11 spec. Only token + * objects require a R/W session. */ +static CK_RV test_create_session_obj_ro_session(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_SESSION_HANDLE sessionRO = CK_INVALID_HANDLE; + CK_RV ret; + + static byte keyData[] = { 0x00 }; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + }; + CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); + CK_ATTRIBUTE tmplOnToken[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + }; + CK_ULONG tmplOnTokenCnt = sizeof(tmplOnToken) / sizeof(*tmplOnToken); + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE, objOnToken = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE copyObj = CK_INVALID_HANDLE, copyBad = CK_INVALID_HANDLE; + CK_ATTRIBUTE copyTmpl[] = { + { CKA_VALUE, keyData, sizeof(keyData) }, + }; + CK_ULONG copyTmplCnt = sizeof(copyTmpl) / sizeof(*copyTmpl); + char newLabel[] = "updated"; + CK_ATTRIBUTE setTmpl[] = { + { CKA_LABEL, newLabel, sizeof(newLabel)-1 }, + }; + + ret = funcList->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, + &sessionRO); + CHECK_CKR(ret, "Open RO session"); + + /* Create session object in RO session - spec says this is allowed */ + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(sessionRO, tmpl, tmplCnt, &obj); + CHECK_CKR(ret, "Create session object in RO session"); + } + /* Create token object in RO session - spec says this must fail */ + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(sessionRO, tmplOnToken, tmplOnTokenCnt, + &objOnToken); + CHECK_CKR_FAIL(ret, CKR_SESSION_READ_ONLY, + "Create token object in RO session blocked"); + } + /* SetAttributeValue on session object from RO session */ + if (ret == CKR_OK) { + ret = funcList->C_SetAttributeValue(sessionRO, obj, setTmpl, 1); + CHECK_CKR(ret, "SetAttributeValue session obj in RO session"); + } + /* CopyObject session object in RO session */ + if (ret == CKR_OK) { + ret = funcList->C_CopyObject(sessionRO, obj, copyTmpl, copyTmplCnt, + ©Obj); + CHECK_CKR(ret, "Copy session object in RO session"); + } + /* CopyObject token object from RO session - must fail even with empty + * template, because copy inherits source's CKA_TOKEN. */ + if (ret == CKR_OK) { + /* Create a token object via the RW session */ + ret = funcList->C_CreateObject(session, tmplOnToken, tmplOnTokenCnt, + &objOnToken); + CHECK_CKR(ret, "Create token object via RW session"); + } + if (ret == CKR_OK) { + ret = funcList->C_CopyObject(sessionRO, objOnToken, copyTmpl, + copyTmplCnt, ©Bad); + CHECK_CKR_FAIL(ret, CKR_SESSION_READ_ONLY, + "Copy token object in RO session blocked"); + } + /* DestroyObject session object from RO session */ + if (ret == CKR_OK) { + ret = funcList->C_DestroyObject(sessionRO, obj); + CHECK_CKR(ret, "Destroy session object in RO session"); + } + if (ret == CKR_OK) { + ret = funcList->C_DestroyObject(sessionRO, copyObj); + CHECK_CKR(ret, "Destroy copied session object in RO session"); + } + + if (sessionRO != CK_INVALID_HANDLE) + funcList->C_CloseSession(sessionRO); + if (objOnToken != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, objOnToken); + + return ret; +} +#endif /* !WOLFPKCS11_NSS */ + +#if defined(HAVE_AES_KEYWRAP) && !defined(WOLFPKCS11_NO_STORE) && \ + !defined(WOLFPKCS11_NSS) +/* C_WrapKey should not require a R/W session since it creates no new object. + * C_UnwrapKey should allow creating session objects in R/O sessions. */ +static CK_RV test_wrap_key_ro_session(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_SESSION_HANDLE sessionRO = CK_INVALID_HANDLE; + CK_RV ret; + CK_MECHANISM mech = { CKM_AES_KEY_WRAP, NULL, 0 }; + CK_OBJECT_HANDLE wrappingKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE key = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE unwrappedKey = CK_INVALID_HANDLE; + byte wrappedKey[40], keyData[32]; + CK_ULONG wrappedKeyLen; + unsigned char keyId[] = { 0xBB }; + CK_ATTRIBUTE keyTmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_ID, keyId, sizeof(keyId) }, + }; + CK_ULONG keyTmplCnt = sizeof(keyTmpl) / sizeof(*keyTmpl); + CK_ATTRIBUTE unwrapTmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &aesKeyType, sizeof(aesKeyType) }, + }; + CK_ULONG unwrapTmplCnt = sizeof(unwrapTmpl) / sizeof(*unwrapTmpl); + + memset(keyData, 7, sizeof(keyData)); + wrappedKeyLen = sizeof(wrappedKey); + + /* Use token-based keys so they're visible from the RO session */ + { + unsigned char wrapId[] = { 0xAA }; + ret = get_aes_128_key(session, wrapId, sizeof(wrapId), &wrappingKey); + } + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, keyTmpl, keyTmplCnt, &key); + CHECK_CKR(ret, "Create token key for wrap"); + } + + /* Open RO session */ + if (ret == CKR_OK) { + ret = funcList->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, + &sessionRO); + CHECK_CKR(ret, "Open RO session for wrap"); + } + + /* Wrap using the RW session first */ + if (ret == CKR_OK) { + ret = funcList->C_WrapKey(session, &mech, wrappingKey, key, + wrappedKey, &wrappedKeyLen); + CHECK_CKR(ret, "WrapKey in RW session"); + } + + /* C_WrapKey from RO session should succeed (token keys visible) */ + if (ret == CKR_OK) { + wrappedKeyLen = sizeof(wrappedKey); + ret = funcList->C_WrapKey(sessionRO, &mech, wrappingKey, key, + wrappedKey, &wrappedKeyLen); + CHECK_CKR(ret, "WrapKey in RO session"); + } + + /* C_UnwrapKey creating session object from RO session should succeed */ + if (ret == CKR_OK) { + ret = funcList->C_UnwrapKey(sessionRO, &mech, wrappingKey, + wrappedKey, wrappedKeyLen, + unwrapTmpl, unwrapTmplCnt, &unwrappedKey); + CHECK_CKR(ret, "UnwrapKey session object in RO session"); + } + + if (sessionRO != CK_INVALID_HANDLE) + funcList->C_CloseSession(sessionRO); + funcList->C_DestroyObject(session, wrappingKey); + if (key != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, key); + if (unwrappedKey != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, unwrappedKey); + + return ret; +} +#endif + +#ifndef NO_AES +#ifdef HAVE_AES_CBC +/* Verify that C_Encrypt rejects data lengths that exceed word32 range on + * platforms where CK_ULONG is 64-bit (LP64). */ +static CK_RV test_encrypt_data_len_range(void* args) +{ +#if SIZEOF_LONG > 4 + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE key; + byte plain[16], enc[32], iv[16]; + CK_ULONG encSz; + CK_MECHANISM mech; + + memset(plain, 9, sizeof(plain)); + memset(iv, 9, sizeof(iv)); + encSz = sizeof(enc); + + mech.mechanism = CKM_AES_CBC; + mech.ulParameterLen = sizeof(iv); + mech.pParameter = iv; + + ret = get_aes_128_key(session, NULL, 0, &key); + if (ret == CKR_OK) { + ret = funcList->C_EncryptInit(session, &mech, key); + CHECK_CKR(ret, "AES-CBC Encrypt Init for data len range test"); + } + /* Pass a data length that overflows word32 */ + if (ret == CKR_OK) { + CK_ULONG bigLen = ((CK_ULONG)1 << 32) + 16; + ret = funcList->C_Encrypt(session, plain, bigLen, enc, &encSz); + CHECK_CKR_FAIL(ret, CKR_DATA_LEN_RANGE, + "AES-CBC Encrypt rejects oversized data length"); + } + + return ret; +#else + (void)args; + return CKR_SKIPPED; +#endif +} +#endif /* HAVE_AES_CBC */ +#endif /* !NO_AES */ + +#if !defined(NO_RSA) && !defined(WC_NO_RSA_OAEP) +/* Calling C_EncryptInit with OAEP twice in a row without completing the first + * operation exercises the re-initialization path in SetOaepParams. Any label + * from the first init must be freed before being overwritten. */ +static CK_RV test_oaep_reinit(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE; + CK_MECHANISM mech; + CK_RSA_PKCS_OAEP_PARAMS params; + byte plain[32], enc[2048/8]; + CK_ULONG plainSz = sizeof(plain), encSz = sizeof(enc); + unsigned char label1[] = "first-label"; + unsigned char label2[] = "second-label-longer"; + + ret = get_rsa_priv_key(session, NULL, 0, CK_FALSE, &priv); + if (ret == CKR_OK) + ret = get_rsa_pub_key(session, NULL, 0, &pub); + + params.hashAlg = CKM_SHA256; + params.mgf = CKG_MGF1_SHA256; + params.source = CKZ_DATA_SPECIFIED; + params.pSourceData = label1; + params.ulSourceDataLen = sizeof(label1); + + mech.mechanism = CKM_RSA_PKCS_OAEP; + mech.ulParameterLen = sizeof(params); + mech.pParameter = ¶ms; + + /* First init with label1 */ + if (ret == CKR_OK) { + ret = funcList->C_EncryptInit(session, &mech, pub); + CHECK_CKR(ret, "OAEP Encrypt Init #1 with label"); + } + /* Second init with label2 — old label must be freed, not leaked */ + if (ret == CKR_OK) { + params.pSourceData = label2; + params.ulSourceDataLen = sizeof(label2); + ret = funcList->C_EncryptInit(session, &mech, pub); + CHECK_CKR(ret, "OAEP Encrypt Init #2 with different label (reinit)"); + } + /* Complete the operation so session state is clean */ + if (ret == CKR_OK) { + memset(plain, 9, sizeof(plain)); + ret = funcList->C_Encrypt(session, plain, plainSz, enc, &encSz); + CHECK_CKR(ret, "OAEP Encrypt after reinit"); + } + + return ret; +} +#endif + +#ifdef HAVE_AESGCM +/* Calling C_EncryptInit with AES-GCM twice in a row without completing the + * first operation exercises the re-initialization path in SetGcmParams. Any + * AAD from the first init must be freed before being overwritten. */ +static CK_RV test_gcm_reinit(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE key; + CK_MECHANISM mech; + CK_GCM_PARAMS gcmParams; + byte iv[12], aad1[10], aad2[20]; + byte plain[32], enc[48]; + CK_ULONG plainSz = sizeof(plain), encSz = sizeof(enc); + + memset(iv, 9, sizeof(iv)); + memset(aad1, 1, sizeof(aad1)); + memset(aad2, 2, sizeof(aad2)); + memset(plain, 9, sizeof(plain)); + + gcmParams.pIv = iv; + gcmParams.ulIvLen = sizeof(iv); + gcmParams.pAAD = aad1; + gcmParams.ulAADLen = sizeof(aad1); + gcmParams.ulTagBits = 128; + + mech.mechanism = CKM_AES_GCM; + mech.ulParameterLen = sizeof(gcmParams); + mech.pParameter = &gcmParams; + + ret = get_aes_128_key(session, NULL, 0, &key); + /* First init with aad1 */ + if (ret == CKR_OK) { + ret = funcList->C_EncryptInit(session, &mech, key); + CHECK_CKR(ret, "AES-GCM Encrypt Init #1 with AAD"); + } + /* Second init with aad2 — old AAD must be freed, not leaked */ + if (ret == CKR_OK) { + gcmParams.pAAD = aad2; + gcmParams.ulAADLen = sizeof(aad2); + ret = funcList->C_EncryptInit(session, &mech, key); + CHECK_CKR(ret, "AES-GCM Encrypt Init #2 with different AAD (reinit)"); + } + /* Complete the operation */ + if (ret == CKR_OK) { + ret = funcList->C_Encrypt(session, plain, plainSz, enc, &encSz); + CHECK_CKR(ret, "AES-GCM Encrypt after reinit"); + } + + return ret; +} +#endif /* HAVE_AESGCM */ + +#ifdef HAVE_AESCCM +/* Same as GCM reinit test but for AES-CCM. */ +static CK_RV test_ccm_reinit(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE key; + CK_MECHANISM mech; + CK_CCM_PARAMS ccmParams; + byte iv[13], aad1[10], aad2[20]; + byte plain[32], enc[48]; + CK_ULONG plainSz = sizeof(plain), encSz = sizeof(enc); + + memset(iv, 9, sizeof(iv)); + memset(aad1, 1, sizeof(aad1)); + memset(aad2, 2, sizeof(aad2)); + memset(plain, 9, sizeof(plain)); + + ccmParams.ulDataLen = 0; + ccmParams.pIv = iv; + ccmParams.ulIvLen = sizeof(iv); + ccmParams.pAAD = aad1; + ccmParams.ulAADLen = sizeof(aad1); + ccmParams.ulMacLen = 16; + + mech.mechanism = CKM_AES_CCM; + mech.ulParameterLen = sizeof(ccmParams); + mech.pParameter = &ccmParams; + + ret = gen_aes_key(session, 16, NULL, 0, 0, &key); + /* First init with aad1 */ + if (ret == CKR_OK) { + ret = funcList->C_EncryptInit(session, &mech, key); + CHECK_CKR(ret, "AES-CCM Encrypt Init #1 with AAD"); + } + /* Second init with aad2 — old AAD must be freed, not leaked */ + if (ret == CKR_OK) { + ccmParams.pAAD = aad2; + ccmParams.ulAADLen = sizeof(aad2); + ret = funcList->C_EncryptInit(session, &mech, key); + CHECK_CKR(ret, "AES-CCM Encrypt Init #2 with different AAD (reinit)"); + } + /* Complete the operation */ + if (ret == CKR_OK) { + ret = funcList->C_Encrypt(session, plain, plainSz, enc, &encSz); + CHECK_CKR(ret, "AES-CCM Encrypt after reinit"); + } + + return ret; +} +#endif /* HAVE_AESCCM */ + +#if !defined(NO_RSA) && defined(WC_RSA_DIRECT) +/* C_VerifyRecoverInit should return CKR_OPERATION_ACTIVE when called twice + * without completing the first operation. */ +static CK_RV test_verify_recover_init_double(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_MECHANISM verifyMech = { CKM_RSA_PKCS, NULL, 0 }; + CK_OBJECT_HANDLE pubKey; + CK_ATTRIBUTE pubTmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VERIFY_RECOVER, &ckTrue, sizeof(ckTrue) }, + { CKA_MODULUS, rsa_2048_modulus, sizeof(rsa_2048_modulus) }, + { CKA_PUBLIC_EXPONENT, rsa_2048_pub_exp, sizeof(rsa_2048_pub_exp) }, + }; + CK_ULONG pubTmplCnt = sizeof(pubTmpl) / sizeof(*pubTmpl); + + ret = funcList->C_CreateObject(session, pubTmpl, pubTmplCnt, &pubKey); + CHECK_CKR(ret, "Create RSA public key for verify recover"); + + if (ret == CKR_OK) { + ret = funcList->C_VerifyRecoverInit(session, &verifyMech, pubKey); + CHECK_CKR(ret, "First C_VerifyRecoverInit"); + } + if (ret == CKR_OK) { + ret = funcList->C_VerifyRecoverInit(session, &verifyMech, pubKey); + CHECK_CKR_FAIL(ret, CKR_OPERATION_ACTIVE, + "Second C_VerifyRecoverInit without completing first"); + } + + return ret; +} +#endif + static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_NO_INIT_DECL(test_get_function_list), PKCS11TEST_FUNC_NO_INIT_DECL(test_not_initialized), @@ -16182,6 +16675,9 @@ static TEST_FUNC testFunc[] = { #endif PKCS11TEST_FUNC_SESS_DECL(test_op_state_fail), PKCS11TEST_FUNC_SESS_DECL(test_object), +#ifndef WOLFPKCS11_NSS + PKCS11TEST_FUNC_SESS_DECL(test_create_session_obj_ro_session), +#endif PKCS11TEST_FUNC_SESS_DECL(test_copy_object_deep_copy), #if (!defined(NO_RSA) && !defined(WOLFPKCS11_TPM) && defined(WOLFSSL_KEY_GEN)) PKCS11TEST_FUNC_SESS_DECL(test_copy_object_rsa_key), @@ -16209,6 +16705,7 @@ static TEST_FUNC testFunc[] = { #ifndef NO_DH PKCS11TEST_FUNC_SESS_DECL(test_attributes_dh), #endif + PKCS11TEST_FUNC_SESS_DECL(test_get_attr_value_all_processed), PKCS11TEST_FUNC_SESS_DECL(test_find_objects), PKCS11TEST_FUNC_SESS_DECL(test_private_object_access), PKCS11TEST_FUNC_SESS_DECL(test_encrypt_decrypt), @@ -16218,6 +16715,7 @@ static TEST_FUNC testFunc[] = { #if !defined(NO_RSA) && defined(WC_RSA_DIRECT) PKCS11TEST_FUNC_SESS_DECL(test_verify_recover_pkcs), PKCS11TEST_FUNC_SESS_DECL(test_verify_recover_x509), + PKCS11TEST_FUNC_SESS_DECL(test_verify_recover_init_double), #endif PKCS11TEST_FUNC_SESS_DECL(test_encdec_digest), PKCS11TEST_FUNC_SESS_DECL(test_encdec_signverify), @@ -16231,6 +16729,9 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_wrap_unwrap_key), PKCS11TEST_FUNC_SESS_DECL(test_wrap_key_unextractable), PKCS11TEST_FUNC_SESS_DECL(test_wrap_key_wrap_with_trusted), +#if !defined(WOLFPKCS11_NSS) + PKCS11TEST_FUNC_SESS_DECL(test_wrap_key_ro_session), +#endif #endif /* HAVE_AES_KEYWRAP && !WOLFPKCS11_NO_STORE */ #if (!defined(NO_RSA) && !defined(WOLFPKCS11_NO_STORE)) PKCS11TEST_FUNC_SESS_DECL(test_rsa_wrap_unwrap_key), @@ -16251,6 +16752,7 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_rsa_fixed_keys_pkcs15_enc), #ifndef WC_NO_RSA_OAEP PKCS11TEST_FUNC_SESS_DECL(test_rsa_fixed_keys_oaep), + PKCS11TEST_FUNC_SESS_DECL(test_oaep_reinit), #endif #ifdef WC_RSA_DIRECT PKCS11TEST_FUNC_SESS_DECL(test_rsa_fixed_keys_x_509_sig), @@ -16310,6 +16812,7 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_aes_cbc_pad_fail), PKCS11TEST_FUNC_SESS_DECL(test_aes_cbc_pad_gen_key), PKCS11TEST_FUNC_SESS_DECL(test_aes_cbc_pad_gen_key_id), + PKCS11TEST_FUNC_SESS_DECL(test_encrypt_data_len_range), #endif #ifdef HAVE_AESCTR PKCS11TEST_FUNC_SESS_DECL(test_aes_ctr_fixed_key), @@ -16319,9 +16822,11 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_aes_gcm_fail), PKCS11TEST_FUNC_SESS_DECL(test_aes_gcm_gen_key), PKCS11TEST_FUNC_SESS_DECL(test_aes_gcm_gen_key_id), + PKCS11TEST_FUNC_SESS_DECL(test_gcm_reinit), #endif #ifdef HAVE_AESCCM PKCS11TEST_FUNC_SESS_DECL(test_aes_ccm_gen_key), + PKCS11TEST_FUNC_SESS_DECL(test_ccm_reinit), #endif #ifdef HAVE_AESCTS PKCS11TEST_FUNC_SESS_DECL(test_aes_cts_fixed_key), diff --git a/wolfpkcs11/internal.h b/wolfpkcs11/internal.h index f7494dde..66d357fe 100644 --- a/wolfpkcs11/internal.h +++ b/wolfpkcs11/internal.h @@ -353,6 +353,7 @@ WP11_LOCAL int WP11_Slot_Has_Empty_Pin(WP11_Slot* slot); WP11_LOCAL int WP11_Slot_SOPin_IsSet(WP11_Slot* slot); WP11_LOCAL int WP11_Slot_SOLogin(WP11_Slot* slot, char* pin, int pinLen); WP11_LOCAL int WP11_Slot_UserLogin(WP11_Slot* slot, char* pin, int pinLen); +WP11_LOCAL int WP11_Slot_IsLoggedIn(WP11_Slot* slot); WP11_LOCAL void WP11_Slot_Logout(WP11_Slot* slot); WP11_LOCAL int WP11_Slot_SetSOPin(WP11_Slot* slot, char* pin, int pinLen); WP11_LOCAL int WP11_Slot_SetUserPin(WP11_Slot* slot, char* pin, int pinLen); @@ -411,6 +412,7 @@ WP11_LOCAL void WP11_Session_Find(WP11_Session* session, int onToken, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); WP11_LOCAL int WP11_Session_FindGet(WP11_Session* session, CK_OBJECT_HANDLE* id); WP11_LOCAL void WP11_Session_FindFinal(WP11_Session* session); +WP11_LOCAL int WP11_Session_IsFindActive(WP11_Session* session); WP11_LOCAL int WP11_ConstantCompare(const byte* a, const byte* b, int length); @@ -421,6 +423,7 @@ 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 int WP11_Object_OnToken(WP11_Object* object); WP11_LOCAL CK_KEY_TYPE WP11_Object_GetType(WP11_Object* object); WP11_LOCAL CK_ULONG WP11_Object_GetDevId(WP11_Object* object);