/* * Copyright 2018-2020 NXP * SPDX-License-Identifier: Apache-2.0 */ #include #if SSS_HAVE_A71CH || SSS_HAVE_A71CH_SIM #include #include #include #include #include #include #include #include #include "ax_sss_scp.h" #include "sm_apdu.h" #include "stdlib.h" //#define NX_LOG_ENABLE_SSCP_DEBUG 1 #include #include #include /* ************************************************************************** */ /* Includes */ /* ************************************************************************** */ /* ************************************************************************** */ /* Local Defines */ /* ************************************************************************** */ #define DER_ECC_NISTP256_HEADER 26 #define ADD_DER_ECC_NISTP256_HEADER(x) (x) + DER_ECC_NISTP256_HEADER #define REMOVE_DER_ECC_NISTP256_HEADER(x) (x) - DER_ECC_NISTP256_HEADER #define CONVERT_BYTE(x) (x) / 8 #define CONVERT_BIT(x) (x) * 8 /* ************************************************************************** */ /* Structures and Typedefs */ /* ************************************************************************** */ /* ************************************************************************** */ /* Global Variables */ /* ************************************************************************** */ keyStoreTable_t gkeystore_shadow_ch; keyIdAndTypeIndexLookup_t gLookupEntires_ch[KS_N_ENTIRES]; typedef struct { /** Fixed - Unique 32bit magic number. * * In case some one over-writes we can know. */ uint32_t magic; /** Fixed - constant based on version number */ uint16_t version; uint16_t maxEntries; /** Dynamic entries */ keyIdAndTypeIndexLookup_t entries[KS_N_ENTIRES]; } keyStoreTableEEPROM_t; /* ************************************************************************** */ /* Static function declarations */ /* ************************************************************************** */ static HLSE_RET_CODE a71ch_GenerateKey( keyStoreTable_t *keystore_shadow, uint8_t keyType, uint8_t cipherType, uint32_t extKeyID); static HLSE_RET_CODE a71ch_EraseKey( keyStoreTable_t *keystore_shadow, uint8_t keyType, uint8_t cipherType, uint32_t extKeyID); static HLSE_RET_CODE a71ch_FreezeKey( keyStoreTable_t *keystore_shadow, uint8_t keyType, uint8_t cipherType, uint32_t extKeyID); static sss_status_t swToSSSResult(uint16_t checkSW); static HLSE_RET_CODE a71ch_AllocateKeyStore(sss_a71ch_key_store_t *keyStore, uint32_t keyStoreID); static HLSE_RET_CODE a71ch_loadKeyStore(sss_a71ch_key_store_t *keyStore); static HLSE_RET_CODE a71ch_saveKeyStore(sss_a71ch_key_store_t *keyStore); static HLSE_RET_CODE a71ch_AllocateKeyObject(sss_a71ch_key_store_t *keyStore, uint32_t extKeyID, sss_key_part_t keyPart, sss_cipher_type_t cipherType, size_t keyByteLenMax, uint32_t options, uint8_t *a71ch_slotid); static HLSE_RET_CODE a71ch_KeyObjectGetHandle( sss_a71ch_key_store_t *keyStore, uint32_t extKeyID, uint32_t *keyType, uint32_t *cipherType); static HLSE_RET_CODE a71ch_getKey(keyStoreTable_t *keystore_shadow, sss_key_part_t key_part, sss_cipher_type_t cipher_type, uint32_t extId, uint8_t *key, uint32_t *keyByteLen, uint32_t *keyBitLen); static HLSE_RET_CODE a71ch_setKey(keyStoreTable_t *keystore_shadow, sss_key_part_t key_part, sss_cipher_type_t cipher_type, uint32_t extId, uint8_t *key, size_t keyLen, size_t keyBitLen); static HLSE_RET_CODE a71ch_DhDeriveKey(sss_a71ch_key_store_t *keyStore, uint32_t extKeyID, uint8_t *pubKeyBuf, size_t pubKeyBufBitLen, uint8_t *pDerivekey, size_t *pDerivekeykeyBitlen); static HLSE_RET_CODE a71ch_SymDeriveKey(sss_a71ch_key_store_t *keyStore, uint32_t extKeyID, const uint8_t *saltData, size_t saltLen, const uint8_t *info, size_t infoLen, uint8_t *pDerivekey, size_t derivekeykeylen); static HLSE_RET_CODE a71ch_CalHmacSha256(sss_a71ch_key_store_t *keyStore, uint32_t extKeyID, const uint8_t *info, size_t infoLen, uint8_t *hmac, size_t hmaclen); static HLSE_RET_CODE a71ch_eccSign(keyStoreTable_t *keystore_shadow, uint32_t extKeyID, uint8_t *pHash, uint16_t hashLen, uint8_t *pSignature, uint16_t *pSignatureLen); static HLSE_RET_CODE a71ch_eccVerify(keyStoreTable_t *keystore_shadow, uint32_t extKeyID, uint8_t *pHash, uint16_t hashLen, uint8_t *pSignature, uint16_t SignatureLen); /* ************************************************************************** */ /* Public Functions */ /* ************************************************************************** */ sss_status_t sscp_a71ch_openSession(void *connectionData, sss_sscp_session_t *openSession) { uint32_t retval = kStatus_SSS_Fail; if (connectionData == NULL) { return kStatus_SSS_InvalidArgument; } SE_Connect_Ctx_t *pA71Auth = (SE_Connect_Ctx_t *)connectionData; memset(openSession, 0, sizeof(*openSession)); SmCommState_t CommState = {0}; CommState.connType = pA71Auth->connType; uint8_t atr[100]; uint16_t atrLen = ARRAY_SIZE(atr); U16 lReturn; #if defined(SMCOM_JRCP_V1) || defined(SMCOM_JRCP_V2) || defined(RJCT_VCOM) || defined(SMCOM_PCSC) lReturn = SM_RjctConnect(NULL, pA71Auth->portName, &CommState, atr, &atrLen); { if (lReturn == SW_OK) { openSession->fp_closeConnection = &sscp_a71ch_closeConnect; retval = kStatus_SSS_Success; } else if (lReturn == ERR_COM_ALREADY_OPEN) retval = kStatus_SSS_Success; else if (lReturn == ERR_API_ERROR) retval = kStatus_SSS_InvalidArgument; } #else /* AX_EMBEDDED Or Native */ lReturn = SM_Connect(NULL, &CommState, atr, &atrLen); if (lReturn != SW_OK) { LOG_E("SM_Connect Failed. Status %04X", lReturn); return retval; } else { retval = kStatus_SSS_Success; } #endif if (retval == kStatus_SSS_Success) { #if SSS_HAVE_SCP_SCP03_SSS if ((retval == kStatus_SSS_Success) && (pA71Auth->auth.authType == kSSS_AuthType_SCP03)) { retval = kStatus_SSS_Fail; LOG_I("Invoking SM_ChannelAuthenticate()"); lReturn = SM_ChannelAuthenticate(&pA71Auth->auth.ctx.a71chAuthKeys, NULL); if (lReturn == SW_OK) { retval = kStatus_SSS_Success; } else { LOG_E("SM_ChannelAuthenticate() failed."); } } #endif } return (sss_status_t)retval; } void sscp_a71chkey_store_context_free(sss_a71ch_key_store_t *context) { memset(&gLookupEntires_ch, 0, sizeof(gLookupEntires_ch)); memset(&gkeystore_shadow_ch, 0, sizeof(gkeystore_shadow_ch)); } void sscp_a71ch_closeSession(sss_sscp_session_t *closeSession) { if (closeSession->sessionId != 0) { } if (closeSession->fp_closeConnection != NULL) { closeSession->fp_closeConnection(); closeSession->fp_closeConnection = NULL; } } void sscp_a71ch_closeConnect(void) { HLSE_CloseConnection(HLSE_CLOSE_CONNECTION_NO_RESET); } sss_status_t sscp_a71ch_init(sscp_a71ch_context_t *context, sss_a71ch_key_store_t *keyStore) { /* assign A71ch implementation of ::sscp_invoke_command() */ context->keyStore = keyStore; context->invoke = &sscp_a71ch_invoke_command; keyStore->session->sscp_context = (sscp_context_t *)context; return kStatus_SSS_Success; } void sscp_a71ch_free(sscp_a71ch_context_t *context) { if (context != NULL) { memset(context, 0, sizeof(*context)); } } void getA7CHKeyStore(sss_a71ch_key_store_t **ks, sscp_context_reference_t *ref) { switch (ref->type) { case kSSCP_ParamContextType_SSS_Symmetric: { sss_sscp_symmetric_t *ctx = (sss_sscp_symmetric_t *)ref->ptr; *ks = (sss_a71ch_key_store_t *)ctx->keyObject->keyStore; } break; case kSSCP_ParamContextType_SSS_Aead: break; case kSSCP_ParamContextType_SSS_Digest: break; case kSSCP_ParamContextType_SSS_Mac: { sss_mac_t *ctx = (sss_mac_t *)ref->ptr; *ks = (sss_a71ch_key_store_t *)ctx->keyObject->keyStore; break; } case kSSCP_ParamContextType_SSS_Tunnel: break; case kSSCP_ParamContextType_SSS_DeriveKey: { sss_derive_key_t *ctx = (sss_derive_key_t *)ref->ptr; *ks = (sss_a71ch_key_store_t *)ctx->keyObject->keyStore; break; } case kSSCP_ParamContextType_SSS_Asymmetric: { sss_asymmetric_t *ctx = (sss_asymmetric_t *)ref->ptr; *ks = (sss_a71ch_key_store_t *)ctx->keyObject->keyStore; break; } case kSSCP_ParamContextType_SSS_Object: { sss_object_t *pobj = (sss_object_t *)ref->ptr; *ks = (sss_a71ch_key_store_t *)pobj->keyStore; break; } case kSSCP_ParamContextType_SSS_KeyStore: { *ks = (sss_a71ch_key_store_t *)ref->ptr; break; } case kSSCP_ParamContextType_SSS_RandomGen: *ks = (sss_a71ch_key_store_t *)ref->ptr; break; } } sscp_status_t sscp_a71ch_invoke_command( sscp_context_t *a71chContext, uint32_t commandID, sscp_operation_t *op, uint32_t *returnOrigin) { uint16_t resSW = SMCOM_SND_FAILED; sscp_status_t retSSCP = kStatus_SSCP_Success; uint32_t keyId; sss_a71ch_key_store_t *a71ch_keystore = NULL; sss_derive_key_t *derctx; sscp_a71ch_context_t *context = (sscp_a71ch_context_t *)a71chContext; if (kSSCP_ParamType_ContextReference == SSCP_OP_GET_PARAM(0, op->paramTypes)) { getA7CHKeyStore(&a71ch_keystore, &op->params[0].context); } #if SSS_HAVE_A71CH_SIM if (a71ch_keystore != NULL) { if (a71ch_keystore->session->sessionId != 0) { set_SessionId_Tlv(a71ch_keystore->session->sessionId); } } #endif switch (commandID) { case kSSCP_CMD_GENERATE_KEY: resSW = a71ch_GenerateKey( a71ch_keystore->keystore_shadow, op->params[1].value.a, op->params[2].value.b, op->params[1].value.b); break; case kSSCP_CMD_ERASE_KEY: resSW = a71ch_EraseKey( a71ch_keystore->keystore_shadow, op->params[1].value.a, op->params[2].value.a, op->params[1].value.b); if (resSW == SMCOM_OK) { resSW = a71ch_saveKeyStore(a71ch_keystore); } break; case kSSCP_CMD_GET_KEY: resSW = a71ch_getKey(a71ch_keystore->keystore_shadow, op->params[1].value.a, op->params[3].value.b, op->params[1].value.b, op->params[2].memref.buffer, &op->params[3].value.a, &op->params[3].value.b); break; case kSSCP_CMD_FREEZE_KEY: resSW = a71ch_FreezeKey( a71ch_keystore->keystore_shadow, op->params[1].value.a, op->params[2].value.a, op->params[1].value.b); break; case kSSCP_CMD_ALLOCATE_KEYSTORE: resSW = a71ch_AllocateKeyStore(a71ch_keystore, op->params[1].value.a); break; case kSSCP_CMD_LOAD_KEYSTORE: if (a71ch_keystore->shadow_handle == 0) { /* It's OK. Allocate + Load here. */ resSW = a71ch_AllocateKeyStore(a71ch_keystore, __LINE__); } else { resSW = a71ch_loadKeyStore(a71ch_keystore); } break; case kSSCP_CMD_SAVE_KEYSTORE: resSW = a71ch_saveKeyStore(a71ch_keystore); break; case kSSCP_CMD_SET_KEY: { resSW = a71ch_setKey(a71ch_keystore->keystore_shadow, op->params[1].value.a, op->params[3].value.b, op->params[1].value.b, op->params[2].memref.buffer, op->params[2].memref.size, op->params[3].value.a); } break; case kSSCP_KEYOBJ_CMD_ALLOCATE_HANDLE: { uint8_t a71ch_slotid = 0; resSW = a71ch_AllocateKeyObject(a71ch_keystore, op->params[1].value.a, op->params[1].value.b, op->params[3].value.a, op->params[2].value.a, op->params[2].value.b, &a71ch_slotid); op->params[4].value.a = a71ch_slotid; } break; case kSSCP_KEYOBJ_CMD_GET_HANDLE: resSW = a71ch_KeyObjectGetHandle( a71ch_keystore, op->params[1].value.a, &(op->params[2].value.a), &(op->params[2].value.b)); break; case kSSCP_ASYMMETRIC_CTX_INIT: op->params[3].value.a = (0xFFFFFFFFu ^ op->params[2].value.a); resSW = SMCOM_OK; break; case kSSCP_ASYMMETRIC_CMD_ENCRYPT: break; case kSSCP_ASYMMETRIC_CMD_DECRYPT: break; case kSSCP_ASYMMETRIC_CMD_SIGN_DIGEST: keyId = (0xFFFFFFFFu ^ op->params[1].value.a); resSW = a71ch_eccSign(a71ch_keystore->keystore_shadow, keyId, op->params[2].memref.buffer, (uint16_t)op->params[2].memref.size, op->params[3].memref.buffer, (uint16_t *)&op->params[3].memref.size); break; case kSSCP_ASYMMETRIC_CMD_VERIFY_DIGEST: keyId = (0xFFFFFFFFu ^ op->params[1].value.a); resSW = a71ch_eccVerify(context->keyStore->keystore_shadow, keyId, op->params[2].memref.buffer, (uint16_t)op->params[2].memref.size, op->params[3].memref.buffer, (uint16_t)op->params[3].memref.size); break; case kSSCP_SYMM_CIPHER_CTX_INIT: op->params[2].value.a = (0xFFFFFFFFu ^ op->params[1].value.a); resSW = SMCOM_OK; break; case kSSCP_DERIVE_CTX_INIT: op->params[3].value.a = (0xFFFFFFFFu ^ op->params[2].value.a); resSW = SMCOM_OK; break; case kSSCP_ASYMM_DH_DERIVE_KEY: { resSW = a71ch_DhDeriveKey(a71ch_keystore, (0xFFFFFFFFu ^ (op->params[1].value.a)), /* = context->sessionId*/ op->params[2].memref.buffer, /* key*/ op->params[2].memref.size, /*keylen*/ op->params[3].memref.buffer, /* derivekey*/ &(op->params[4].memref.size)); /* derivekeykeylen;*/ } break; case kSSCP_DERIVE_KEY: derctx = (sss_derive_key_t *)op->params[0].context.ptr; if (derctx != NULL) { if ((derctx->algorithm == kAlgorithm_SSS_HMAC_SHA256) && (derctx->mode == kMode_SSS_Mac)) { resSW = a71ch_CalHmacSha256(a71ch_keystore, (0xFFFFFFFFu ^ (op->params[1].value.a)), /* extKeyID = ~context->sessionId*/ op->params[3].memref.buffer, /* info */ op->params[3].memref.size, /* infoLen */ op->params[4].memref.buffer, /* hmac*/ op->params[4].memref.size); /* hmaclen;*/ } else if ((derctx->algorithm == kAlgorithm_SSS_HMAC_SHA256) && (derctx->mode == kMode_SSS_ComputeSharedSecret)) { resSW = a71ch_SymDeriveKey(a71ch_keystore, (0xFFFFFFFFu ^ (op->params[1].value.a)), /* extKeyID = ~context->sessionId*/ op->params[2].memref.buffer, /* (void *)saltData*/ op->params[2].memref.size, /* saltLen */ op->params[3].memref.buffer, /* info */ op->params[3].memref.size, /* infoLen */ op->params[4].memref.buffer, /* derivekey*/ op->params[4].memref.size); /* derivekeykeylen;*/ } } break; case kSSCP_CMD_SSS_MacOneGo: derctx = (sss_derive_key_t *)op->params[0].context.ptr; if (derctx != NULL) { if ((derctx->algorithm == kAlgorithm_SSS_HMAC_SHA256) && (derctx->mode == kMode_SSS_Mac)) { resSW = a71ch_CalHmacSha256(a71ch_keystore, op->params[3].value.a, op->params[1].memref.buffer, /* info */ op->params[1].memref.size, /* infoLen */ op->params[2].memref.buffer, /* hmac*/ op->params[2].memref.size); /* hmaclen;*/ if (HLSE_SW_OK == resSW) { op->params[2].memref.size = 32; //Only HMAC SHA256 is supported } } } break; case kSSCP_CMD_SSS_MacInit: { derctx = (sss_derive_key_t *)op->params[0].context.ptr; if (derctx != NULL) { if ((derctx->algorithm == kAlgorithm_SSS_HMAC_SHA256) && (derctx->mode == kMode_SSS_Mac)) { uint16_t intId = 0; uint8_t nBlock = 1; sss_status_t status = ks_common_extId_to_int_index(a71ch_keystore->keystore_shadow, op->params[1].value.a, &intId); if (status != kStatus_SSS_Success) { LOG_E("Could not find Ext ID 0x%X in keystore_shadow", op->params[1].value.a); resSW = HLSE_ERR_API_ERROR; } else { nBlock = (intId & 0xF0) >> 4; resSW = A71_HmacSha256Init((intId & 0x0F), nBlock); } } } } break; case kSSCP_CMD_SSS_MacUpdate: { derctx = (sss_derive_key_t *)op->params[0].context.ptr; if (derctx != NULL) { if ((derctx->algorithm == kAlgorithm_SSS_HMAC_SHA256) && (derctx->mode == kMode_SSS_Mac)) { uint16_t intId = 0; uint8_t nBlock = 1; sss_status_t status = ks_common_extId_to_int_index(a71ch_keystore->keystore_shadow, op->params[1].value.a, &intId); if (status != kStatus_SSS_Success) { LOG_E("Could not find Ext ID 0x%X in keystore_shadow", op->params[1].value.a); resSW = HLSE_ERR_API_ERROR; } else { nBlock = (intId & 0xF0) >> 4; resSW = A71_HmacSha256Update( (intId & 0x0F), nBlock, op->params[2].memref.buffer, (U16)op->params[2].memref.size); } } } } break; case kSSCP_CMD_SSS_MacFinish: { derctx = (sss_derive_key_t *)op->params[0].context.ptr; if (derctx != NULL) { if ((derctx->algorithm == kAlgorithm_SSS_HMAC_SHA256) && (derctx->mode == kMode_SSS_Mac)) { uint16_t intId = 0; uint8_t nBlock = 1; U16 dataLen = (U16)op->params[2].memref.size; sss_status_t status = ks_common_extId_to_int_index(a71ch_keystore->keystore_shadow, op->params[1].value.a, &intId); if (status != kStatus_SSS_Success) { LOG_E("Could not find Ext ID 0x%X in keystore_shadow", op->params[1].value.a); resSW = HLSE_ERR_API_ERROR; } else { nBlock = (intId & 0xF0) >> 4; resSW = A71_HmacSha256Final((intId & 0x0F), nBlock, op->params[2].memref.buffer, &dataLen); if (HLSE_SW_OK == resSW) { op->params[2].memref.size = 32; //Only HMAC SHA256 is supported } } } } } break; case kSSCP_GEN_RANDOM_NUM: { resSW = A71_GetRandom(op->params[2].memref.buffer, (uint8_t)op->params[2].memref.size); } break; case kSSCP_CMD_SSS_DigestOneGo: { U16 shaLen = (U16)op->params[2].memref.size; resSW = A71_GetSha256( op->params[1].memref.buffer, (U16)op->params[1].memref.size, op->params[2].memref.buffer, &shaLen); op->params[2].memref.size = shaLen; } break; case kSSCP_CMD_SSS_DigestInit: { resSW = A71_Sha256Init(); } break; case kSSCP_CMD_SSS_DigestUpdate: { resSW = A71_Sha256Update(op->params[1].memref.buffer, (U16)op->params[1].memref.size); } break; case kSSCP_CMD_SSS_DigestFinish: { U16 shaLen = (U16)op->params[1].memref.size; resSW = A71_Sha256Final(op->params[1].memref.buffer, &shaLen); op->params[1].memref.size = shaLen; } break; case kSSCP_GET_UID: { U16 bufSize = (U16)op->params[1].memref.size; resSW = A71_GetUniqueID(op->params[1].memref.buffer, &bufSize); op->params[1].memref.size = bufSize; } break; case kSSCP_GET_CERT_UID: { U16 bufSize = (U16)op->params[1].memref.size; resSW = A71_GetCertUid(op->params[1].memref.buffer, &bufSize); op->params[1].memref.size = bufSize; } break; default: retSSCP = kStatus_SSCP_Fail; LOG_E("Not a SSCP command"); } *returnOrigin = (uint32_t)swToSSSResult(resSW); return (retSSCP); } /* ************************************************************************** */ /* Private Functions */ /* ************************************************************************** */ static HLSE_RET_CODE a71ch_CalHmacSha256(sss_a71ch_key_store_t *keyStore, uint32_t extKeyID, const uint8_t *info, size_t infoLen, uint8_t *pDerivekey, size_t derivekeykeylen) { HLSE_RET_CODE hlseret; uint16_t intId = 0; uint8_t nBlock = 1; U16 Hmaclen = 64; sss_status_t status = ks_common_extId_to_int_index(keyStore->keystore_shadow, extKeyID, &intId); if (status != kStatus_SSS_Success) { LOG_E("Could not find Ext ID 0x%X in keytore_shadow", extKeyID); hlseret = HLSE_ERR_API_ERROR; } else { nBlock = (intId & 0xF0) >> 4; hlseret = A71_GetHmacSha256((U8)(intId & 0x0F), nBlock, info, (U16)infoLen, pDerivekey, &Hmaclen); } return hlseret; } static HLSE_RET_CODE a71ch_SymDeriveKey(sss_a71ch_key_store_t *keyStore, uint32_t extKeyID, const uint8_t *saltData, size_t saltLen, const uint8_t *info, size_t infoLen, uint8_t *pDerivekey, size_t derivekeykeylen) { HLSE_RET_CODE hlseret; uint16_t intId = 0; uint8_t nBlock = 1; sss_status_t status = ks_common_extId_to_int_index(keyStore->keystore_shadow, extKeyID, &intId); if (status != kStatus_SSS_Success) { LOG_E("Could not find Ext ID 0x%X in keytore_shadow", extKeyID); hlseret = HLSE_ERR_API_ERROR; } else { nBlock = (intId & 0xF0) >> 4; hlseret = A71_HkdfSymKey((U8)(intId & 0x0F), nBlock, saltData, (uint16_t)saltLen, info, (uint16_t)infoLen, pDerivekey, (uint16_t)derivekeykeylen); } return hlseret; } static HLSE_RET_CODE a71ch_DhDeriveKey(sss_a71ch_key_store_t *keyStore, uint32_t extKeyID, uint8_t *pubKeyBuf, size_t pubKeyBufBitLen, uint8_t *pDerivekey, size_t *pDerivekeykeyBitlen) { HLSE_RET_CODE hlseret; sss_status_t asn_retval = kStatus_SSS_Fail; uint16_t intId = 0; uint16_t derivekeyBytelen; uint16_t pubKeyBufByteLen; size_t publicKeyLen = 0; uint16_t publicKeyIndex = 0; sss_status_t status = ks_common_extId_to_int_index(keyStore->keystore_shadow, extKeyID, &intId); if (status != kStatus_SSS_Success) { LOG_E("Could not find Ext ID 0x%X in keytore_shadow", extKeyID); hlseret = HLSE_ERR_API_ERROR; } else { pubKeyBufByteLen = (uint16_t)CONVERT_BYTE(pubKeyBufBitLen); derivekeyBytelen = (uint16_t)CONVERT_BYTE(*pDerivekeykeyBitlen); asn_retval = sss_util_pkcs8_asn1_get_ec_public_key_index(pubKeyBuf, pubKeyBufByteLen, &publicKeyIndex, &publicKeyLen); if (asn_retval != kStatus_SSS_Success) { LOG_W("error in sss_util_pkcs8_asn1_get_ec_public_key_index"); return HLSE_ERR_API_ERROR; } hlseret = A71_EcdhGetSharedSecret( (U8)intId, &pubKeyBuf[publicKeyIndex], (U16)publicKeyLen, pDerivekey, &derivekeyBytelen); *pDerivekeykeyBitlen = CONVERT_BIT(derivekeyBytelen); } return hlseret; } static HLSE_RET_CODE a71ch_GenerateKey( keyStoreTable_t *keystore_shadow, uint8_t keyType, uint8_t cipherType, uint32_t extKeyID) { HLSE_RET_CODE hlseret = HLSE_ERR_API_ERROR; if (keyType == kSSS_KeyPart_Pair && cipherType == kSSS_CipherType_EC_NIST_P) { uint16_t intId = 0; sss_status_t status = ks_common_extId_to_int_index(keystore_shadow, extKeyID, &intId); if (status == kStatus_SSS_Success) { hlseret = A71_GenerateEccKeyPair((U8)intId); } else { LOG_E("Could not find Ext ID 0x%X in keytore_shadow", extKeyID); hlseret = HLSE_ERR_API_ERROR; } } return hlseret; } static HLSE_RET_CODE a71ch_EraseKey( keyStoreTable_t *keystore_shadow, uint8_t keyType, uint8_t cipherType, uint32_t extKeyID) { HLSE_RET_CODE hlseret = HLSE_ERR_API_ERROR; uint16_t intId = 0; sss_status_t status = ks_common_extId_to_int_index(keystore_shadow, extKeyID, &intId); if (status != kStatus_SSS_Success) { LOG_E("Could not find Ext ID 0x%X in keytore_shadow", extKeyID); hlseret = HLSE_ERR_API_ERROR; } else { if (keyType == kSSS_KeyPart_Pair && cipherType == kSSS_CipherType_EC_NIST_P) { hlseret = A71_EraseEccKeyPair((U8)intId); } else if (keyType == kSSS_KeyPart_Public && cipherType == kSSS_CipherType_EC_NIST_P) { hlseret = A71_EraseEccPublicKey((U8)intId); } else if (keyType == kSSS_KeyPart_Default && (cipherType == kSSS_CipherType_AES || cipherType == kSSS_CipherType_HMAC)) { hlseret = A71_EraseSymKey((U8)(intId & 0x0F)); } else if (keyType == kSSS_KeyPart_Default && cipherType == kSSS_CipherType_Binary) { HLSE_OBJECT_HANDLE Handles[5]; U16 HandlesNum = sizeof(Handles) / sizeof(HLSE_OBJECT_HANDLE); U16 HandlesNum_copy; U8 i = 0; hlseret = HLSE_EnumerateObjects(HLSE_CERTIFICATE, Handles, &HandlesNum); if (hlseret == HLSE_SW_OK) { HandlesNum_copy = HandlesNum; while (HandlesNum_copy) { if (HLSE_GET_OBJECT_INDEX(Handles[i]) == intId) { break; } i++; HandlesNum_copy--; } hlseret = HLSE_EraseObject(Handles[i]); } } } if (hlseret == HLSE_SW_OK) { status = ks_common_remove_fat(keystore_shadow, extKeyID); if (status != kStatus_SSS_Success) { hlseret = HLSE_ERR_API_ERROR; } } return hlseret; } static HLSE_RET_CODE a71ch_FreezeKey( keyStoreTable_t *keystore_shadow, uint8_t keyType, uint8_t cipherType, uint32_t extKeyID) { HLSE_RET_CODE hlseret = HLSE_ERR_API_ERROR; uint16_t intId = 0; sss_status_t status = ks_common_extId_to_int_index(keystore_shadow, extKeyID, &intId); if (status != kStatus_SSS_Success) { LOG_E("Could not find Ext ID 0x%X in keytore_shadow", extKeyID); hlseret = HLSE_ERR_API_ERROR; } else { if (keyType == kSSS_KeyPart_Pair && cipherType == kSSS_CipherType_EC_NIST_P) { hlseret = A71_FreezeEccKeyPair((U8)intId); } if (keyType == kSSS_KeyPart_Public && cipherType == kSSS_CipherType_EC_NIST_P) { hlseret = A71_FreezeEccPublicKey((U8)intId); } if (keyType == kSSS_KeyPart_Default && (cipherType == kSSS_CipherType_AES || cipherType == kSSS_CipherType_HMAC)) { hlseret = A71_FreezeSymKey((U8)intId); } } return hlseret; } static sss_status_t swToSSSResult(uint16_t checkSW) { switch (checkSW) { case SMCOM_OK: return kStatus_SSS_Success; default: return kStatus_SSS_Fail; } } static HLSE_RET_CODE a71ch_AllocateKeyStore(sss_a71ch_key_store_t *keyStore, uint32_t keyStoreID) { HLSE_RET_CODE hlseret = HLSE_ERR_API_ERROR; HLSE_OBJECT_HANDLE Handles[5]; U16 HandlesNum = sizeof(Handles) / sizeof(HLSE_OBJECT_HANDLE); U16 HandlesNum_copy; U8 i = 0; HLSE_OBJECT_INDEX index = 0; /* Search for our data table @ index */ if (keyStore->shadow_handle == 0) { hlseret = HLSE_EnumerateObjects(HLSE_DATA, Handles, &HandlesNum); if (hlseret == HLSE_SW_OK) { HandlesNum_copy = HandlesNum; while (HandlesNum_copy) { if (HLSE_GET_OBJECT_INDEX(Handles[i]) == index) { keyStore->shadow_handle = Handles[i]; ks_common_init_fat(&gkeystore_shadow_ch, gLookupEntires_ch, ARRAY_SIZE(gLookupEntires_ch)); break; } i++; HandlesNum_copy--; } } } if (gkeystore_shadow_ch.magic == 0) { ks_common_init_fat(&gkeystore_shadow_ch, gLookupEntires_ch, ARRAY_SIZE(gLookupEntires_ch)); } keyStore->keystore_shadow = &gkeystore_shadow_ch; /* If it was never there, create it @ index */ if (keyStore->shadow_handle == 0) { /* Could not find it yet*/ HLSE_OBJECT_TYPE objType = HLSE_DATA; U16 templateSize = 3; HLSE_ATTRIBUTE attr[3]; keyStoreTableEEPROM_t eeKeyStore; eeKeyStore.magic = gkeystore_shadow_ch.magic; eeKeyStore.version = gkeystore_shadow_ch.version; eeKeyStore.maxEntries = gkeystore_shadow_ch.maxEntries; memcpy(eeKeyStore.entries, gkeystore_shadow_ch.entries, sizeof(eeKeyStore.entries)); attr[0].type = HLSE_ATTR_OBJECT_TYPE; attr[0].value = &objType; attr[0].valueLen = sizeof(objType); attr[1].type = HLSE_ATTR_OBJECT_INDEX; attr[1].value = &index; attr[1].valueLen = sizeof(index); attr[2].type = HLSE_ATTR_OBJECT_VALUE; attr[2].value = &eeKeyStore; attr[2].valueLen = sizeof(eeKeyStore); hlseret = HLSE_CreateObject(attr, templateSize, &keyStore->shadow_handle); } /* Either we created it. Or it was already existing, read it. */ if (keyStore->shadow_handle != 0) { hlseret = a71ch_loadKeyStore(keyStore); } return hlseret; } static HLSE_RET_CODE a71ch_loadKeyStore(sss_a71ch_key_store_t *keyStore) { HLSE_RET_CODE hlseret; HLSE_ATTRIBUTE attr; keyStoreTableEEPROM_t eeKeyStore = {0}; if (keyStore->shadow_handle == 0) { /* With shadow handle == 0, no point of reading. */ hlseret = HLSE_ERR_MEMORY; goto cleanup; } attr.type = HLSE_ATTR_OBJECT_VALUE; attr.value = &eeKeyStore; attr.valueLen = sizeof(eeKeyStore); /* Read from Key Store and load it here in gkeystore_shadow_ch */ hlseret = HLSE_GetObjectAttribute(keyStore->shadow_handle, &attr); if (hlseret != HLSE_SW_OK) goto cleanup; if (eeKeyStore.magic == gkeystore_shadow_ch.magic && eeKeyStore.maxEntries == gkeystore_shadow_ch.maxEntries) { keyStore->keystore_shadow = &gkeystore_shadow_ch; if (eeKeyStore.version > gkeystore_shadow_ch.version) { LOG_E("Keystore version mismatch"); hlseret = HLSE_ERR_NOT_SUPPORTED; goto cleanup; } memcpy(gkeystore_shadow_ch.entries, eeKeyStore.entries, sizeof(eeKeyStore.entries)); keyStore->keystore_shadow->version = eeKeyStore.version; } else { LOG_E(" Mismatch in eeKeyStore == gkeystore_shadow_ch"); /* This is the case when there is mismatch between KeyStore and Middleware */ hlseret = HLSE_ERR_MEMORY; } cleanup: return hlseret; } static HLSE_RET_CODE a71ch_saveKeyStore(sss_a71ch_key_store_t *keyStore) { HLSE_RET_CODE hlseret; if (keyStore->shadow_handle == 0) { hlseret = HLSE_ERR_API_ERROR; } else { keyStoreTableEEPROM_t eeKeyStore; if (KEYSTORE_VERSION > gkeystore_shadow_ch.version) { gkeystore_shadow_ch.version = KEYSTORE_VERSION; } eeKeyStore.magic = gkeystore_shadow_ch.magic; eeKeyStore.version = gkeystore_shadow_ch.version; eeKeyStore.maxEntries = gkeystore_shadow_ch.maxEntries; memcpy(eeKeyStore.entries, gkeystore_shadow_ch.entries, sizeof(eeKeyStore.entries)); HLSE_ATTRIBUTE attr; attr.type = HLSE_ATTR_OBJECT_VALUE; attr.value = &eeKeyStore; attr.valueLen = sizeof(eeKeyStore); /* write gkeystore_shadow_ch */ hlseret = HLSE_SetObjectAttribute(keyStore->shadow_handle, &attr); } return hlseret; } static HLSE_RET_CODE a71ch_KeyObjectGetHandle( sss_a71ch_key_store_t *keyStore, uint32_t extKeyID, uint32_t *keyType, uint32_t *cipherType) { HLSE_RET_CODE hlseret = HLSE_ERR_GENERAL_ERROR; sss_status_t ks_status = kStatus_SSS_Success; *keyType = kSSS_KeyPart_NONE; ks_status = ks_common_get_keyType_from_keyid(keyStore->keystore_shadow, extKeyID, keyType, cipherType); if (ks_status == kStatus_SSS_Success) hlseret = HLSE_SW_OK; return hlseret; } static HLSE_RET_CODE a71ch_AllocateKeyObject(sss_a71ch_key_store_t *keyStore, uint32_t extKeyID, sss_key_part_t key_part, sss_cipher_type_t cipherType, size_t keyByteLenMax, uint32_t options, uint8_t *a71ch_slotid) { HLSE_RET_CODE hlseret = HLSE_SW_OK; uint16_t intIndex = 0; sss_status_t ks_status; ks_status = ks_common_check_available_int_index( keyStore->keystore_shadow, (uint8_t)key_part, cipherType, &intIndex, (uint16_t)keyByteLenMax); if (ks_status != kStatus_SSS_Success) { hlseret = HLSE_ERR_MEMORY; } *a71ch_slotid = (uint8_t)intIndex; if (hlseret == HLSE_SW_OK) { ks_status = ks_common_update_fat(keyStore->keystore_shadow, extKeyID, (uint8_t)key_part, (uint8_t)cipherType, (uint8_t)intIndex, 0, (uint16_t)keyByteLenMax); } if (ks_status != kStatus_SSS_Success) { hlseret = HLSE_ERR_MEMORY; } if (hlseret == HLSE_SW_OK) { switch (cipherType) { case kSSS_CipherType_Binary: { HLSE_OBJECT_INDEX index = intIndex; HLSE_OBJECT_TYPE objType = HLSE_CERTIFICATE; U16 templateSize = 3; HLSE_ATTRIBUTE attr[3]; HLSE_OBJECT_HANDLE handle = 0; void *pMem; pMem = SSS_MALLOC(keyByteLenMax); if (NULL != pMem) { attr[0].type = HLSE_ATTR_OBJECT_TYPE; attr[0].value = &objType; attr[0].valueLen = sizeof(objType); attr[1].type = HLSE_ATTR_OBJECT_INDEX; attr[1].value = &index; attr[1].valueLen = sizeof(index); attr[2].type = HLSE_ATTR_OBJECT_VALUE; /* This is dummy value we write... Actually this source code */ attr[2].value = pMem; attr[2].valueLen = (U16)keyByteLenMax; memset(pMem, 0, keyByteLenMax); hlseret = HLSE_CreateObject(attr, templateSize, &handle); /* TODO: if object is already present and all attributes are same then mark it as success*/ if (hlseret == HLSE_OBJ_ALREADY_EXISTS) hlseret = HLSE_SW_OK; } if (NULL != pMem) { SSS_FREE(pMem); } break; } case kSSS_CipherType_EC_NIST_P: case kSSS_CipherType_AES: case kSSS_CipherType_HMAC: case kSSS_CipherType_UserID: break; default: hlseret = HLSE_ERR_API_ERROR; } } if (hlseret == HLSE_SW_OK) { /* Persist to EEPROM */ hlseret = a71ch_saveKeyStore(keyStore); } else { /* Reset the structure based on EEPROM */ a71ch_loadKeyStore(keyStore); } return hlseret; } static HLSE_RET_CODE a71ch_getKey(keyStoreTable_t *keystore_shadow, sss_key_part_t key_part, sss_cipher_type_t cipher_type, uint32_t extId, uint8_t *key, uint32_t *keyByteLen, uint32_t *keyBitLen) { HLSE_RET_CODE resSW = HLSE_ERR_API_ERROR; uint16_t intId = 0; U8 i = 0; HLSE_OBJECT_HANDLE Handles[5]; HLSE_OBJECT_HANDLE GetHandle = 0; U16 HandlesNum = sizeof(Handles) / sizeof(HLSE_OBJECT_HANDLE); U16 HandlesNum_copy; HLSE_ATTRIBUTE attr; U16 keyLen = *keyByteLen; /* clang-format off */ const uint8_t der_header[DER_ECC_NISTP256_HEADER] = { 0x30, 0x59, 0x30, 0x13,0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02,0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D,0x03, 0x01, 0x07, 0x03, 0x42, 0x00 }; /* clang-format on */ sss_status_t status = ks_common_extId_to_int_index(keystore_shadow, extId, &intId); if (status == kStatus_SSS_Success) { if (key_part == kSSS_KeyPart_Pair && cipher_type == kSSS_CipherType_EC_NIST_P) { if (keyLen < DER_ECC_NISTP256_HEADER + 65 /* NIST256 public key len */) { LOG_E("Buffer size insufficient "); return resSW; } memcpy(key, der_header, DER_ECC_NISTP256_HEADER); resSW = A71_GetPublicKeyEccKeyPair((U8)intId, ADD_DER_ECC_NISTP256_HEADER(key), &keyLen); /* Return the Key length including the ECC DER Header */ keyLen = ADD_DER_ECC_NISTP256_HEADER(keyLen); /* Return the Key length in bits */ *keyByteLen = keyLen; *keyBitLen = 256; } else if (key_part == kSSS_KeyPart_Public && cipher_type == kSSS_CipherType_EC_NIST_P) { if (keyLen < DER_ECC_NISTP256_HEADER + 32 /* NIST256 public key len */) { LOG_E("Buffer size insufficient "); return resSW; } memcpy(key, der_header, DER_ECC_NISTP256_HEADER); resSW = A71_GetEccPublicKey((U8)intId, ADD_DER_ECC_NISTP256_HEADER(key), &keyLen); /* Return the Key length including the ECC DER Header */ keyLen = ADD_DER_ECC_NISTP256_HEADER(keyLen); /* Return the Key length in bits */ *keyByteLen = keyLen; *keyBitLen = 256; } else if (key_part == kSSS_KeyPart_Default && cipher_type == kSSS_CipherType_Binary) { resSW = HLSE_EnumerateObjects(HLSE_CERTIFICATE, Handles, &HandlesNum); if (resSW == HLSE_SW_OK) { HandlesNum_copy = HandlesNum; while (HandlesNum_copy) { if (HLSE_GET_OBJECT_INDEX(Handles[i]) == intId) { GetHandle = Handles[i]; break; } i++; HandlesNum_copy--; } } if (GetHandle != 0) { attr.type = HLSE_ATTR_OBJECT_VALUE; attr.value = key; attr.valueLen = keyLen; resSW = HLSE_GetObjectAttribute(GetHandle, &attr); *keyByteLen = attr.valueLen; *keyBitLen = (attr.valueLen * 8); } } } else { LOG_E("Could not find Ext ID 0x%X in keystore_shadow", extId); } return resSW; } static HLSE_RET_CODE a71ch_setKey(keyStoreTable_t *keystore_shadow, sss_key_part_t key_part, sss_cipher_type_t cipher_type, uint32_t extId, uint8_t *key, size_t keyLen, size_t keyBitLen) { HLSE_RET_CODE resSW = HLSE_ERR_API_ERROR; sss_status_t asn_retval = kStatus_SSS_Fail; uint16_t intId = 0; U8 i = 0; HLSE_OBJECT_HANDLE Handles[5]; HLSE_OBJECT_HANDLE GetHandle = 0; U16 HandlesNum = sizeof(Handles) / sizeof(HLSE_OBJECT_HANDLE); U16 HandlesNum_copy; HLSE_ATTRIBUTE attr; sss_status_t status = ks_common_extId_to_int_index(keystore_shadow, extId, &intId); if (status == kStatus_SSS_Success) { if (key_part == kSSS_KeyPart_Public && cipher_type == kSSS_CipherType_EC_NIST_P) { size_t publicKeyLen = 0; uint16_t publicKeyIndex = 0; const uint8_t *pPublicKey = NULL; if (keyBitLen != 256) { LOG_E("Invalid bit length. Only NIST256 is supported in A71CH"); return resSW; } asn_retval = sss_util_pkcs8_asn1_get_ec_public_key_index(key, keyLen, &publicKeyIndex, &publicKeyLen); if (asn_retval != kStatus_SSS_Success) { LOG_E("error in sss_util_pkcs8_asn1_get_ec_public_key_index"); return resSW; } if (publicKeyLen == 0) { LOG_E("Public key len is 0"); return resSW; } pPublicKey = &key[publicKeyIndex]; resSW = A71_SetEccPublicKey((U8)intId, pPublicKey, (U16)publicKeyLen); } else if (key_part == kSSS_KeyPart_Default && (cipher_type == kSSS_CipherType_AES || cipher_type == kSSS_CipherType_HMAC)) { uint8_t slot_id = intId & 0x0F; uint8_t slot_length = (intId & 0xF0) >> 4; uint8_t j = 0; U16 maxKeyLen = 16; size_t keyLenRem = keyLen; size_t KeyLenToWrite = 0; size_t keyLen_roundoff = ((keyLen / 16) * 16) + ((keyLen % 16) == 0 ? 0 : 16); size_t slots_req = (keyLen_roundoff / 16); if (slot_length != slots_req) { return resSW; } while (j < slot_length) { KeyLenToWrite = (keyLenRem < maxKeyLen) ? keyLenRem : maxKeyLen; if (KeyLenToWrite < maxKeyLen) { uint8_t temp_key[16] = { 0, }; memcpy(temp_key, (key + (j * maxKeyLen)), KeyLenToWrite); resSW = A71_SetSymKey((U8)slot_id, temp_key, (U16)maxKeyLen); } else { resSW = A71_SetSymKey((U8)slot_id, (key + (j * maxKeyLen)), (U16)maxKeyLen); } if (HLSE_SW_OK != resSW) { break; } j++; slot_id++; keyLenRem = keyLenRem - KeyLenToWrite; } } else if (key_part == kSSS_KeyPart_Pair && cipher_type == kSSS_CipherType_EC_NIST_P) { uint8_t *pPrivateKey = NULL; size_t privateKeyLen = 0; uint8_t *pPublicKey = NULL; size_t publicKeyLen = 0; uint16_t privateKeyIndex = 0; uint16_t publicKeyIndex = 0; if (keyBitLen != 256) { LOG_E("Invalid bit length. Only NIST256 is supported in A71CH"); return resSW; } asn_retval = sss_util_pkcs8_asn1_get_ec_pair_key_index( key, keyLen, &publicKeyIndex, &publicKeyLen, &privateKeyIndex, &privateKeyLen); if (asn_retval != kStatus_SSS_Success) { LOG_W("error in sss_util_pkcs8_asn1_get_ec_pair_key_index"); return resSW; } if (privateKeyLen == 0) { LOG_E("private key len is 0"); return resSW; } if (publicKeyLen == 0) { LOG_E("Public key len is 0"); return resSW; } pPrivateKey = &key[privateKeyIndex]; pPublicKey = &key[publicKeyIndex]; resSW = A71_SetEccKeyPair((U8)intId, pPublicKey, (U16)publicKeyLen, pPrivateKey, (U16)privateKeyLen); } else if (key_part == kSSS_KeyPart_Default && cipher_type == kSSS_CipherType_Binary) { resSW = HLSE_EnumerateObjects(HLSE_CERTIFICATE, Handles, &HandlesNum); if (resSW == HLSE_SW_OK) { HandlesNum_copy = HandlesNum; while (HandlesNum_copy) { if (HLSE_GET_OBJECT_INDEX(Handles[i]) == intId) { GetHandle = Handles[i]; break; } i++; HandlesNum_copy--; } } if (GetHandle != 0) { attr.type = HLSE_ATTR_OBJECT_VALUE; attr.value = key; attr.valueLen = (U16)keyLen; resSW = HLSE_SetObjectAttribute(GetHandle, &attr); } } } else { LOG_E("Could not find Ext ID 0x%X in keystore_shadow", extId); } return resSW; } static HLSE_RET_CODE a71ch_eccSign(keyStoreTable_t *keystore_shadow, uint32_t extKeyID, uint8_t *pHash, uint16_t hashLen, uint8_t *pSignature, uint16_t *pSignatureLen) { uint16_t intId = 0; HLSE_RET_CODE resSW = HLSE_ERR_API_ERROR; sss_status_t status = ks_common_extId_to_int_index(keystore_shadow, extKeyID, &intId); /* A71CH Max hashlen is AX_SHA256_LEN*/ if (hashLen != AX_SHA256_LEN) { LOG_E("Only SHA256(input) is supported "); return resSW; } if (status == kStatus_SSS_Success) { resSW = A71_EccSign((SST_Index_t)intId, pHash, hashLen, pSignature, pSignatureLen); } return resSW; } static HLSE_RET_CODE a71ch_eccVerify(keyStoreTable_t *keystore_shadow, uint32_t extKeyID, uint8_t *pHash, uint16_t hashLen, uint8_t *pSignature, uint16_t SignatureLen) { uint16_t intId = 0; uint8_t result = 0; HLSE_RET_CODE resSW = HLSE_ERR_API_ERROR; sss_status_t status = ks_common_extId_to_int_index(keystore_shadow, extKeyID, &intId); if (status == kStatus_SSS_Success) { resSW = A71_EccVerify((SST_Index_t)intId, pHash, hashLen, pSignature, SignatureLen, &result); } if (resSW == SW_OK) if (result == 0) resSW = ERR_GENERAL_ERROR; return resSW; } #endif /* SSS_HAVE_A71CH */