/** * \file * \brief PKCS11 Library Object Find/Searching * * \copyright (c) 2017 Microchip Technology Inc. and its subsidiaries. * You may use this software and any derivatives exclusively with * Microchip products. * * \page License * * (c) 2017 Microchip Technology Inc. and its subsidiaries. You may use this * software and any derivatives exclusively with Microchip products. * * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A * PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION * WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION. * * IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, * INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND * WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS * BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE * FULLEST EXTENT ALLOWED BY LAW, MICROCHIPS TOTAL LIABILITY ON ALL CLAIMS IN * ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. * * MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE * TERMS. */ #include "pkcs11_config.h" #include "pkcs11_debug.h" #include "pkcs11_init.h" #include "pkcs11_slot.h" #include "pkcs11_session.h" #include "pkcs11_find.h" #include "pkcs11_util.h" #include "cryptoauthlib.h" /** * \defgroup pkcs11 Find (pkcs11_find_) @{ */ #if PKCS11_USE_STATIC_MEMORY static CK_BYTE pkcs11_find_template_cache[PKCS11_SEARCH_CACHE_SIZE]; #endif /** * \brief Copy an array of CK_ATTRIBUTE structures */ static CK_RV pkcs11_find_copy_template(CK_BYTE_PTR pBuffer, CK_ULONG ulBufSize, CK_ATTRIBUTE_PTR pTemplate, const CK_ULONG ulCount) { CK_ULONG bytes_required; CK_ATTRIBUTE_PTR pCopy; CK_ULONG i; if (!pBuffer || !ulBufSize || !pTemplate || !ulCount) { return CKR_ARGUMENTS_BAD; } /* Start with the amount of memory required to hold the Array */ bytes_required = sizeof(CK_ATTRIBUTE) * ulCount; /* Check the template pValue requirements */ for (i = 0; i < ulCount; i++) { if (pTemplate[i].pValue && pTemplate[i].ulValueLen) { bytes_required += pTemplate[i].ulValueLen; /* Check for overflow */ if (bytes_required < pTemplate[i].ulValueLen) { return CKR_HOST_MEMORY; } } } if (ulBufSize < bytes_required) { return CKR_HOST_MEMORY; } /* Good to copy */ bytes_required = sizeof(CK_ATTRIBUTE) * ulCount; /* Set up the Copied Template */ pCopy = (CK_ATTRIBUTE_PTR)pBuffer; /* Move to the data section */ pBuffer += bytes_required; /* Copy the template */ for (i = 0; i < ulCount; i++) { pCopy[i].type = pTemplate[i].type; /* Sanity check the input to see if we need to allocate any memory for this */ if (pTemplate[i].pValue && pTemplate[i].ulValueLen) { pCopy[i].pValue = pBuffer; pCopy[i].ulValueLen = pTemplate[i].ulValueLen; pBuffer += pTemplate[i].ulValueLen; memcpy(pCopy[i].pValue, pTemplate[i].pValue, pTemplate[i].ulValueLen); } else { pCopy[i].pValue = NULL_PTR; pCopy[i].ulValueLen = 0; } } return CKR_OK; } static pkcs11_attrib_model_ptr pkcs11_find_attrib(const pkcs11_attrib_model_ptr pAttributeList, const CK_ULONG ulCount, const CK_ATTRIBUTE_PTR pTemplate) { CK_ULONG i; pkcs11_attrib_model_ptr pAttribute = NULL_PTR; if (pAttributeList && ulCount && pTemplate) { for (i = 0; i < ulCount; i++) { pAttribute = &pAttributeList[i]; if (pAttribute->type == pTemplate->type) { return pAttribute; } } } return NULL_PTR; } static pkcs11_attrib_model_ptr pkcs11_find_attrib_match(pkcs11_object_ptr pObject, const pkcs11_attrib_model_ptr pAttributeList, const CK_ULONG ulCount, const CK_ATTRIBUTE_PTR pTemplate) { CK_BBOOL found = FALSE; pkcs11_attrib_model_ptr pAttribute = NULL_PTR; pAttribute = pkcs11_find_attrib(pAttributeList, ulCount, pTemplate); if (pAttribute && pObject) { CK_BBOOL must_full_match = FALSE; /* Special rules - only return CKO_HW_FEATURE (Sec 4.3.2) or CKO_MECHANISM (Sec 4.12.2) if the search attributes contain them */ if (CKA_CLASS == pAttribute->type) { if ((CKO_HW_FEATURE == pObject->class_id) || (CKO_MECHANISM == pObject->class_id)) { must_full_match = TRUE; } } /* Search criteria has a value to we must match it */ if (pTemplate->pValue && pAttribute->func) { CK_UTF8CHAR buf[PKCS11_MAX_LABEL_SIZE]; CK_ATTRIBUTE temp = { 0, buf, sizeof(buf) }; /* Get the attribute */ if (!pAttribute->func(pObject, &temp)) { if ((temp.ulValueLen == pTemplate->ulValueLen)) { if (!memcmp(temp.pValue, pTemplate->pValue, pTemplate->ulValueLen)) { found = TRUE; } } } } else if (!must_full_match) { found = TRUE; } } if (found) { return pAttribute; } return NULL_PTR; } static CK_OBJECT_HANDLE pkcs11_find_handle(const CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_ULONG_PTR index) { CK_ULONG i; CK_ULONG j; CK_OBJECT_HANDLE rv = NULL_PTR; /* Finds the first or next match - Iterate through objects */ for (i = (index) ? *index : 0; i < PKCS11_MAX_OBJECTS_ALLOWED; i++) { pkcs11_object_ptr pObject = pkcs11_object_cache[i].object; if (pObject) { /* Iterate through attribute list */ for (j = 0; j < ulCount; j++) { /* See if a match failed */ if (!pkcs11_find_attrib_match(pObject, (const pkcs11_attrib_model_ptr)pObject->attributes, pObject->count, &pTemplate[j])) { break; } } if (j == ulCount) { /* Full match */ if (ulCount) { rv = pkcs11_object_cache[i].handle; break; } else if ((CKO_HW_FEATURE != pObject->class_id) && (CKO_MECHANISM != pObject->class_id)) { /* Special condition where ulCount is zero we match all objects except HW Features and Mechanisms */ rv = pkcs11_object_cache[i].handle; break; } } } } if (index) { *index = i; } return rv; } CK_RV pkcs11_find_init(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { pkcs11_session_ctx_ptr pSession; CK_ULONG index = 0; CK_RV rv; static int called; rv = pkcs11_init_check(NULL, FALSE); if (rv) { return rv; } if (!pTemplate && ulCount) { return CKR_ARGUMENTS_BAD; } rv = pkcs11_session_check(&pSession, hSession); if (rv) { return rv; } pkcs11_debug_attributes(pTemplate, ulCount); /* Check Public/Private Session info - although I don't think we can actually get private unless we're using a shared key system - and that will only be for secured data and not key info */ if (pkcs11_find_handle(pTemplate, ulCount, &index)) { if (ulCount) { rv = pkcs11_find_copy_template(pkcs11_find_template_cache, PKCS11_SEARCH_CACHE_SIZE, pTemplate, ulCount); if (rv) { return rv; } pSession->attrib_list = (CK_ATTRIBUTE_PTR)pkcs11_find_template_cache; } else { pSession->attrib_list = NULL_PTR; } pSession->attrib_count = ulCount; pSession->object_index = index; pSession->object_count = 1; index++; while (pkcs11_find_handle(pSession->attrib_list, ulCount, &index)) { pSession->object_count++; index++; } } return CKR_OK; } CK_RV pkcs11_find_continue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) { pkcs11_session_ctx_ptr pSession; CK_ULONG i; CK_RV rv; rv = pkcs11_init_check(NULL, FALSE); if (rv) { return rv; } if (!phObject || !pulObjectCount) { return CKR_ARGUMENTS_BAD; } rv = pkcs11_session_check(&pSession, hSession); if (rv) { return rv; } *pulObjectCount = (pSession->object_count < ulMaxObjectCount) ? pSession->object_count : ulMaxObjectCount; for (i = 0; i < *pulObjectCount; i++) { phObject[i] = pkcs11_find_handle(pSession->attrib_list, pSession->attrib_count, &pSession->object_index); if (!phObject[i]) { pSession->object_count = 0; *pulObjectCount = i; break; } pSession->object_index++; if (pSession->object_count) { pSession->object_count--; } } return CKR_OK; } CK_RV pkcs11_find_finish(CK_SESSION_HANDLE hSession) { pkcs11_session_ctx_ptr pSession; CK_RV rv; rv = pkcs11_init_check(NULL, FALSE); if (rv) { return rv; } rv = pkcs11_session_check(&pSession, hSession); if (rv) { return rv; } pSession->attrib_list = NULL_PTR; pSession->attrib_count = 0; pSession->object_count = 0; return CKR_OK; } CK_RV pkcs11_find_get_attribute(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { pkcs11_lib_ctx_ptr pLibCtx; pkcs11_session_ctx_ptr pSession; pkcs11_object_ptr pObject; CK_ULONG i; CK_RV rv; rv = pkcs11_init_check(&pLibCtx, FALSE); if (rv) { return rv; } if (!pTemplate || !ulCount) { return CKR_ARGUMENTS_BAD; } rv = pkcs11_session_check(&pSession, hSession); if (rv) { return rv; } rv = pkcs11_object_check(&pObject, hObject); if (rv) { return rv; } pkcs11_debug_attributes(pTemplate, ulCount); for (i = 0; i < ulCount; i++) { pkcs11_attrib_model_ptr pAttribute = pkcs11_find_attrib((const pkcs11_attrib_model_ptr)pObject->attributes, pObject->count, &pTemplate[i]); if (!pAttribute) { /* 2. Otherwise, if the specified value for the object is invalid(the object does not possess such an attribute), then the ulValueLen field in that triple is modified to hold the value CK_UNAVAILABLE_INFORMATION. */ pTemplate[i].ulValueLen = CK_UNAVAILABLE_INFORMATION; if (!rv) { rv = CKR_ATTRIBUTE_TYPE_INVALID; } } else if (pAttribute->func) { if (CKR_OK == pkcs11_lock_context(pLibCtx)) { /* Attribute function found so try to execute it */ CK_RV temp = pAttribute->func(pObject, &pTemplate[i]); if (!rv) { rv = temp; } pkcs11_unlock_context(pLibCtx); } } else { /* Assume if there is no function for the attribute we're keeping it private */ pTemplate[i].ulValueLen = CK_UNAVAILABLE_INFORMATION; if (!rv) { rv = CKR_ATTRIBUTE_SENSITIVE; } } } return rv; } /** @} */