#include "cpa.h"
#include "cpa_cy_sym.h"
#include "icp_accel_devices.h"
#include "icp_adf_debug.h"
#include "lac_common.h"
#include "lac_mem.h"
#include "lac_sym.h"
#include "lac_session.h"
#include "lac_sym_hash.h"
#include "lac_log.h"
#include "lac_sym_qat_hash.h"
#include "lac_sym_qat_hash_defs_lookup.h"
#include "lac_sym_cb.h"
#include "lac_sync.h"
#define LAC_HASH_ALG_MODE_NOT_SUPPORTED(alg, mode) \
((((CPA_CY_SYM_HASH_KASUMI_F9 == (alg)) || \
(CPA_CY_SYM_HASH_SNOW3G_UIA2 == (alg)) || \
(CPA_CY_SYM_HASH_AES_XCBC == (alg)) || \
(CPA_CY_SYM_HASH_AES_CCM == (alg)) || \
(CPA_CY_SYM_HASH_AES_GCM == (alg)) || \
(CPA_CY_SYM_HASH_AES_GMAC == (alg)) || \
(CPA_CY_SYM_HASH_AES_CMAC == (alg)) || \
(CPA_CY_SYM_HASH_ZUC_EIA3 == (alg))) && \
(CPA_CY_SYM_HASH_MODE_AUTH != (mode))) || \
((LAC_HASH_IS_SHA3(alg)) && (CPA_CY_SYM_HASH_MODE_NESTED == (mode))))
void LacSync_GenBufListVerifyCb(void *pCallbackTag,
CpaStatus status,
CpaCySymOp operationType,
void *pOpData,
CpaBufferList *pDstBuffer,
CpaBoolean opResult);
static void
LacHash_SyncPrecomputeDoneCb(void *pCallbackTag)
{
LacSync_GenWakeupSyncCaller(pCallbackTag, CPA_STATUS_SUCCESS);
}
CpaStatus
LacHash_StatePrefixAadBufferInit(
sal_service_t *pService,
const CpaCySymHashSetupData *pHashSetupData,
icp_qat_la_bulk_req_ftr_t *pReq,
icp_qat_hw_auth_mode_t qatHashMode,
Cpa8U *pHashStateBuffer,
lac_sym_qat_hash_state_buffer_info_t *pHashStateBufferInfo)
{
pHashStateBufferInfo->pData = pHashStateBuffer;
pHashStateBufferInfo->pDataPhys = LAC_MEM_CAST_PTR_TO_UINT64(
LAC_OS_VIRT_TO_PHYS_EXTERNAL((*pService), pHashStateBuffer));
if (pHashStateBufferInfo->pDataPhys == 0) {
LAC_LOG_ERROR("Unable to get the physical address of "
"the hash state buffer\n");
return CPA_STATUS_FAIL;
}
LacSymQat_HashStatePrefixAadBufferSizeGet(pReq, pHashStateBufferInfo);
if (CPA_CY_SYM_HASH_MODE_NESTED == pHashSetupData->hashMode) {
LacSymQat_HashStatePrefixAadBufferPopulate(
pHashStateBufferInfo,
pReq,
pHashSetupData->nestedModeSetupData.pInnerPrefixData,
(Cpa8U)pHashSetupData->nestedModeSetupData
.innerPrefixLenInBytes,
pHashSetupData->nestedModeSetupData.pOuterPrefixData,
(Cpa8U)pHashSetupData->nestedModeSetupData
.outerPrefixLenInBytes);
}
else if (IS_HASH_MODE_2_AUTH(qatHashMode, pHashSetupData->hashMode)) {
LacSymQat_HashStatePrefixAadBufferPopulate(
pHashStateBufferInfo,
pReq,
pHashSetupData->authModeSetupData.authKey,
(Cpa8U)pHashSetupData->authModeSetupData.authKeyLenInBytes,
pHashSetupData->authModeSetupData.authKey,
(Cpa8U)pHashSetupData->authModeSetupData.authKeyLenInBytes);
}
return CPA_STATUS_SUCCESS;
}
CpaStatus
LacHash_PrecomputeDataCreate(const CpaInstanceHandle instanceHandle,
CpaCySymSessionSetupData *pSessionSetup,
lac_hash_precompute_done_cb_t callbackFn,
void *pCallbackTag,
Cpa8U *pWorkingBuffer,
Cpa8U *pState1,
Cpa8U *pState2)
{
CpaStatus status = CPA_STATUS_SUCCESS;
Cpa8U *pAuthKey = NULL;
Cpa32U authKeyLenInBytes = 0;
CpaCySymHashAlgorithm hashAlgorithm =
pSessionSetup->hashSetupData.hashAlgorithm;
CpaCySymHashAuthModeSetupData *pAuthModeSetupData =
&pSessionSetup->hashSetupData.authModeSetupData;
if (NULL == callbackFn) {
lac_sync_op_data_t *pSyncCallbackData = NULL;
status = LacSync_CreateSyncCookie(&pSyncCallbackData);
if (CPA_STATUS_SUCCESS == status) {
status = LacHash_PrecomputeDataCreate(
instanceHandle,
pSessionSetup,
LacHash_SyncPrecomputeDoneCb,
pSyncCallbackData,
pWorkingBuffer,
pState1,
pState2);
} else {
return status;
}
if (CPA_STATUS_SUCCESS == status) {
CpaStatus syncStatus = CPA_STATUS_SUCCESS;
syncStatus = LacSync_WaitForCallback(
pSyncCallbackData,
LAC_SYM_SYNC_CALLBACK_TIMEOUT,
&status,
NULL);
if (CPA_STATUS_SUCCESS != syncStatus) {
QAT_UTILS_LOG(
"callback functions for precomputes did not return\n");
status = syncStatus;
}
} else {
LacSync_SetSyncCookieComplete(pSyncCallbackData);
}
LacSync_DestroySyncCookie(&pSyncCallbackData);
return status;
}
pAuthKey = pAuthModeSetupData->authKey;
authKeyLenInBytes = pAuthModeSetupData->authKeyLenInBytes;
if (CPA_CY_SYM_HASH_AES_XCBC == hashAlgorithm) {
status = LacSymHash_AesECBPreCompute(instanceHandle,
hashAlgorithm,
authKeyLenInBytes,
pAuthKey,
pWorkingBuffer,
pState2,
callbackFn,
pCallbackTag);
} else if (CPA_CY_SYM_HASH_AES_CMAC == hashAlgorithm) {
memcpy(pState2, pAuthKey, authKeyLenInBytes);
status = LacSymHash_AesECBPreCompute(instanceHandle,
hashAlgorithm,
authKeyLenInBytes,
pAuthKey,
pWorkingBuffer,
pState2,
callbackFn,
pCallbackTag);
} else if (CPA_CY_SYM_HASH_AES_CCM == hashAlgorithm) {
if (pSessionSetup->cipherSetupData.cipherKeyLenInBytes ==
ICP_QAT_HW_AES_128_KEY_SZ) {
memcpy(
pState2,
pSessionSetup->cipherSetupData.pCipherKey,
pSessionSetup->cipherSetupData.cipherKeyLenInBytes);
LAC_OS_BZERO(pState2 +
pSessionSetup->cipherSetupData
.cipherKeyLenInBytes,
ICP_QAT_HW_AES_CCM_CBC_E_CTR0_SZ);
}
callbackFn(pCallbackTag);
} else if (CPA_CY_SYM_HASH_AES_GCM == hashAlgorithm ||
CPA_CY_SYM_HASH_AES_GMAC == hashAlgorithm) {
LAC_OS_BZERO(pState2,
ICP_QAT_HW_GALOIS_H_SZ +
ICP_QAT_HW_GALOIS_LEN_A_SZ +
ICP_QAT_HW_GALOIS_E_CTR0_SZ);
status = LacSymHash_AesECBPreCompute(
instanceHandle,
hashAlgorithm,
pSessionSetup->cipherSetupData.cipherKeyLenInBytes,
pSessionSetup->cipherSetupData.pCipherKey,
pWorkingBuffer,
pState2,
callbackFn,
pCallbackTag);
if (CPA_STATUS_SUCCESS == status) {
*(Cpa32U *)&pState2[ICP_QAT_HW_GALOIS_H_SZ] =
LAC_MEM_WR_32(pAuthModeSetupData->aadLenInBytes);
}
} else if (CPA_CY_SYM_HASH_KASUMI_F9 == hashAlgorithm) {
Cpa32U wordIndex = 0;
Cpa32U *pTempKey = (Cpa32U *)(pState2 + authKeyLenInBytes);
memcpy(pState2, pAuthKey, authKeyLenInBytes);
memcpy(pTempKey, pAuthKey, authKeyLenInBytes);
for (wordIndex = 0;
wordIndex < LAC_BYTES_TO_LONGWORDS(authKeyLenInBytes);
wordIndex++) {
pTempKey[wordIndex] ^=
LAC_HASH_KASUMI_F9_KEY_MODIFIER_4_BYTES;
}
callbackFn(pCallbackTag);
} else if (CPA_CY_SYM_HASH_SNOW3G_UIA2 == hashAlgorithm) {
LAC_OS_BZERO(pState2, ICP_QAT_HW_SNOW_3G_UIA2_STATE2_SZ);
callbackFn(pCallbackTag);
} else if (CPA_CY_SYM_HASH_ZUC_EIA3 == hashAlgorithm) {
LAC_OS_BZERO(pState2, ICP_QAT_HW_ZUC_3G_EIA3_STATE2_SZ);
memcpy(pState2, pAuthKey, authKeyLenInBytes);
callbackFn(pCallbackTag);
} else if (CPA_CY_SYM_HASH_POLY == hashAlgorithm) {
callbackFn(pCallbackTag);
} else
{
status = LacSymHash_HmacPreComputes(instanceHandle,
hashAlgorithm,
authKeyLenInBytes,
pAuthKey,
pWorkingBuffer,
pState1,
pState2,
callbackFn,
pCallbackTag);
}
return status;
}
CpaStatus
LacHash_HashContextCheck(CpaInstanceHandle instanceHandle,
const CpaCySymHashSetupData *pHashSetupData)
{
lac_sym_qat_hash_alg_info_t *pHashAlgInfo = NULL;
lac_sym_qat_hash_alg_info_t *pOuterHashAlgInfo = NULL;
CpaCySymCapabilitiesInfo capInfo;
if (pHashSetupData->hashAlgorithm >= CPA_CY_SYM_HASH_CAP_BITMAP_SIZE) {
LAC_INVALID_PARAM_LOG("hashAlgorithm");
return CPA_STATUS_INVALID_PARAM;
}
cpaCySymQueryCapabilities(instanceHandle, &capInfo);
if (!CPA_BITMAP_BIT_TEST(capInfo.hashes,
pHashSetupData->hashAlgorithm) &&
pHashSetupData->hashAlgorithm != CPA_CY_SYM_HASH_AES_CBC_MAC) {
LAC_INVALID_PARAM_LOG("hashAlgorithm");
return CPA_STATUS_INVALID_PARAM;
}
switch (pHashSetupData->hashMode) {
case CPA_CY_SYM_HASH_MODE_PLAIN:
case CPA_CY_SYM_HASH_MODE_AUTH:
case CPA_CY_SYM_HASH_MODE_NESTED:
break;
default: {
LAC_INVALID_PARAM_LOG("hashMode");
return CPA_STATUS_INVALID_PARAM;
}
}
if (LAC_HASH_ALG_MODE_NOT_SUPPORTED(pHashSetupData->hashAlgorithm,
pHashSetupData->hashMode)) {
LAC_UNSUPPORTED_PARAM_LOG(
"hashAlgorithm and hashMode combination");
return CPA_STATUS_UNSUPPORTED;
}
LacSymQat_HashAlgLookupGet(instanceHandle,
pHashSetupData->hashAlgorithm,
&pHashAlgInfo);
if ((CPA_CY_SYM_HASH_MODE_PLAIN == pHashSetupData->hashMode) ||
(CPA_CY_SYM_HASH_MODE_AUTH == pHashSetupData->hashMode)) {
if ((0 == pHashSetupData->digestResultLenInBytes) ||
(pHashSetupData->digestResultLenInBytes >
pHashAlgInfo->digestLength)) {
LAC_INVALID_PARAM_LOG("digestResultLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
}
if (CPA_CY_SYM_HASH_MODE_AUTH == pHashSetupData->hashMode) {
if (CPA_CY_SYM_HASH_AES_GCM == pHashSetupData->hashAlgorithm ||
CPA_CY_SYM_HASH_AES_GMAC == pHashSetupData->hashAlgorithm) {
Cpa32U aadDataSize = 0;
if ((pHashSetupData->digestResultLenInBytes !=
LAC_HASH_AES_GCM_ICV_SIZE_8) &&
(pHashSetupData->digestResultLenInBytes !=
LAC_HASH_AES_GCM_ICV_SIZE_12) &&
(pHashSetupData->digestResultLenInBytes !=
LAC_HASH_AES_GCM_ICV_SIZE_16)) {
LAC_INVALID_PARAM_LOG("digestResultLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
aadDataSize =
pHashSetupData->authModeSetupData.aadLenInBytes;
aadDataSize =
LAC_ALIGN_POW2_ROUNDUP(aadDataSize,
LAC_HASH_AES_GCM_BLOCK_SIZE);
if (aadDataSize > ICP_QAT_FW_CCM_GCM_AAD_SZ_MAX &&
CPA_CY_SYM_HASH_AES_GMAC !=
pHashSetupData->hashAlgorithm) {
LAC_INVALID_PARAM_LOG("aadLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
} else if (CPA_CY_SYM_HASH_AES_CCM ==
pHashSetupData->hashAlgorithm) {
Cpa32U aadDataSize = 0;
if ((pHashSetupData->digestResultLenInBytes >=
LAC_HASH_AES_CCM_ICV_SIZE_MIN) &&
(pHashSetupData->digestResultLenInBytes <=
LAC_HASH_AES_CCM_ICV_SIZE_MAX)) {
if ((pHashSetupData->digestResultLenInBytes &
0x01) != 0) {
LAC_INVALID_PARAM_LOG(
"digestResultLenInBytes must be a multiple of 2");
return CPA_STATUS_INVALID_PARAM;
}
} else {
LAC_INVALID_PARAM_LOG("digestResultLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
aadDataSize = LAC_HASH_AES_CCM_BLOCK_SIZE;
if (pHashSetupData->authModeSetupData.aadLenInBytes >
0) {
aadDataSize += sizeof(Cpa16U);
aadDataSize += pHashSetupData->authModeSetupData
.aadLenInBytes;
}
aadDataSize =
LAC_ALIGN_POW2_ROUNDUP(aadDataSize,
LAC_HASH_AES_CCM_BLOCK_SIZE);
if (aadDataSize > ICP_QAT_FW_CCM_GCM_AAD_SZ_MAX) {
LAC_INVALID_PARAM_LOG("aadLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
} else if (CPA_CY_SYM_HASH_KASUMI_F9 ==
pHashSetupData->hashAlgorithm) {
if (pHashSetupData->authModeSetupData
.authKeyLenInBytes !=
ICP_QAT_HW_KASUMI_KEY_SZ) {
LAC_INVALID_PARAM_LOG("authKeyLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
} else if (CPA_CY_SYM_HASH_SNOW3G_UIA2 ==
pHashSetupData->hashAlgorithm) {
if (pHashSetupData->authModeSetupData
.authKeyLenInBytes !=
ICP_QAT_HW_SNOW_3G_UEA2_KEY_SZ) {
LAC_INVALID_PARAM_LOG("authKeyLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
if (pHashSetupData->authModeSetupData.aadLenInBytes !=
ICP_QAT_HW_SNOW_3G_UEA2_IV_SZ) {
LAC_INVALID_PARAM_LOG("aadLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
} else if (CPA_CY_SYM_HASH_AES_XCBC ==
pHashSetupData->hashAlgorithm ||
CPA_CY_SYM_HASH_AES_CMAC ==
pHashSetupData->hashAlgorithm ||
CPA_CY_SYM_HASH_AES_CBC_MAC ==
pHashSetupData->hashAlgorithm) {
if ((pHashSetupData->authModeSetupData
.authKeyLenInBytes !=
ICP_QAT_HW_AES_128_KEY_SZ)) {
LAC_INVALID_PARAM_LOG("authKeyLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
} else if (CPA_CY_SYM_HASH_ZUC_EIA3 ==
pHashSetupData->hashAlgorithm) {
if (pHashSetupData->authModeSetupData
.authKeyLenInBytes !=
ICP_QAT_HW_ZUC_3G_EEA3_KEY_SZ) {
LAC_INVALID_PARAM_LOG("authKeyLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
if (pHashSetupData->authModeSetupData.aadLenInBytes !=
ICP_QAT_HW_ZUC_3G_EEA3_IV_SZ) {
LAC_INVALID_PARAM_LOG("aadLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
} else if (CPA_CY_SYM_HASH_POLY ==
pHashSetupData->hashAlgorithm) {
if (pHashSetupData->digestResultLenInBytes !=
ICP_QAT_HW_SPC_CTR_SZ) {
LAC_INVALID_PARAM_LOG("Digest Length for CCP");
return CPA_STATUS_INVALID_PARAM;
}
if (pHashSetupData->authModeSetupData.aadLenInBytes >
ICP_QAT_FW_CCM_GCM_AAD_SZ_MAX) {
LAC_INVALID_PARAM_LOG("AAD Length for CCP");
return CPA_STATUS_INVALID_PARAM;
}
} else {
if (pHashSetupData->authModeSetupData
.authKeyLenInBytes >
pHashAlgInfo->blockLength) {
LAC_INVALID_PARAM_LOG("authKeyLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
}
if (CPA_CY_SYM_HASH_AES_CCM != pHashSetupData->hashAlgorithm &&
CPA_CY_SYM_HASH_AES_GCM != pHashSetupData->hashAlgorithm &&
pHashSetupData->authModeSetupData.authKeyLenInBytes > 0) {
LAC_CHECK_NULL_PARAM(
pHashSetupData->authModeSetupData.authKey);
}
} else if (CPA_CY_SYM_HASH_MODE_NESTED == pHashSetupData->hashMode) {
if (!CPA_BITMAP_BIT_TEST(capInfo.hashes,
pHashSetupData->nestedModeSetupData
.outerHashAlgorithm)) {
LAC_INVALID_PARAM_LOG("outerHashAlgorithm");
return CPA_STATUS_INVALID_PARAM;
}
if (LAC_HASH_ALG_MODE_NOT_SUPPORTED(
pHashSetupData->nestedModeSetupData.outerHashAlgorithm,
pHashSetupData->hashMode)) {
LAC_INVALID_PARAM_LOG(
"outerHashAlgorithm and hashMode combination");
return CPA_STATUS_INVALID_PARAM;
}
LacSymQat_HashAlgLookupGet(
instanceHandle,
pHashSetupData->nestedModeSetupData.outerHashAlgorithm,
&pOuterHashAlgInfo);
if ((0 == pHashSetupData->digestResultLenInBytes) ||
(pHashSetupData->digestResultLenInBytes >
pOuterHashAlgInfo->digestLength)) {
LAC_INVALID_PARAM_LOG("digestResultLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
if (pHashSetupData->nestedModeSetupData.innerPrefixLenInBytes >
LAC_MAX_INNER_OUTER_PREFIX_SIZE_BYTES) {
LAC_INVALID_PARAM_LOG("innerPrefixLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
if (pHashSetupData->nestedModeSetupData.innerPrefixLenInBytes >
0) {
LAC_CHECK_NULL_PARAM(pHashSetupData->nestedModeSetupData
.pInnerPrefixData);
}
if (pHashSetupData->nestedModeSetupData.outerPrefixLenInBytes >
LAC_MAX_INNER_OUTER_PREFIX_SIZE_BYTES) {
LAC_INVALID_PARAM_LOG("outerPrefixLenInBytes");
return CPA_STATUS_INVALID_PARAM;
}
if (pHashSetupData->nestedModeSetupData.outerPrefixLenInBytes >
0) {
LAC_CHECK_NULL_PARAM(pHashSetupData->nestedModeSetupData
.pOuterPrefixData);
}
}
return CPA_STATUS_SUCCESS;
}
CpaStatus
LacHash_PerformParamCheck(CpaInstanceHandle instanceHandle,
lac_session_desc_t *pSessionDesc,
const CpaCySymOpData *pOpData,
Cpa64U srcPktSize,
const CpaBoolean *pVerifyResult)
{
CpaStatus status = CPA_STATUS_SUCCESS;
lac_sym_qat_hash_alg_info_t *pHashAlgInfo = NULL;
CpaBoolean digestIsAppended = pSessionDesc->digestIsAppended;
CpaBoolean digestVerify = pSessionDesc->digestVerify;
CpaCySymOp symOperation = pSessionDesc->symOperation;
CpaCySymHashAlgorithm hashAlgorithm = pSessionDesc->hashAlgorithm;
if (digestIsAppended && digestVerify &&
(CPA_CY_SYM_OP_HASH == symOperation)) {
LAC_INVALID_PARAM_LOG(
"digestVerify and digestIsAppended set "
"on Hash-Only operation is not supported");
return CPA_STATUS_INVALID_PARAM;
}
if ((CPA_CY_SYM_PACKET_TYPE_PARTIAL != pOpData->packetType) &&
!digestIsAppended && (NULL == pOpData->pDigestResult)) {
LAC_INVALID_PARAM_LOG("pDigestResult is NULL");
return CPA_STATUS_INVALID_PARAM;
}
if ((CPA_TRUE == digestVerify) &&
(CPA_CY_SYM_PACKET_TYPE_PARTIAL != pOpData->packetType) &&
(LacSync_GenBufListVerifyCb == pSessionDesc->pSymCb)) {
if (NULL == pVerifyResult) {
LAC_INVALID_PARAM_LOG(
"Null pointer pVerifyResult for hash op");
return CPA_STATUS_INVALID_PARAM;
}
}
if ((CPA_CY_SYM_HASH_AES_CCM == hashAlgorithm) ||
(CPA_CY_SYM_HASH_AES_GCM == hashAlgorithm)) {
if ((pSessionDesc->aadLenInBytes > 0) &&
(NULL == pOpData->pAdditionalAuthData)) {
LAC_INVALID_PARAM_LOG("pAdditionalAuthData is NULL");
return CPA_STATUS_INVALID_PARAM;
}
} else {
if ((pOpData->hashStartSrcOffsetInBytes +
pOpData->messageLenToHashInBytes) > srcPktSize) {
LAC_INVALID_PARAM_LOG(
"hashStartSrcOffsetInBytes + "
"messageLenToHashInBytes > Src Buffer Packet Length");
return CPA_STATUS_INVALID_PARAM;
}
}
if ((CPA_CY_SYM_HASH_SNOW3G_UIA2 == hashAlgorithm) ||
(CPA_CY_SYM_HASH_ZUC_EIA3 == hashAlgorithm)) {
if (NULL == pOpData->pAdditionalAuthData) {
LAC_INVALID_PARAM_LOG("pAdditionalAuthData is NULL");
return CPA_STATUS_INVALID_PARAM;
}
}
if ((CPA_CY_SYM_PACKET_TYPE_PARTIAL == pOpData->packetType) &&
(CPA_CY_SYM_OP_HASH == symOperation)) {
LacSymQat_HashAlgLookupGet(instanceHandle,
hashAlgorithm,
&pHashAlgInfo);
if (pOpData->messageLenToHashInBytes %
pHashAlgInfo->blockLength !=
0) {
LAC_INVALID_PARAM_LOG2(
"message(%d) not block-size(%d) multiple",
pOpData->messageLenToHashInBytes,
pHashAlgInfo->blockLength);
return CPA_STATUS_INVALID_PARAM;
}
}
return status;
}