blob: 2545ecf5a657c140bf7ba228ae6bf662af6c5cce [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* HSM based implementation of CHIP crypto primitives
* Based on configurations in CHIPCryptoPALHsm_config.h file,
* chip crypto apis use either HSM or rollback to software implementation.
*/
#include "CHIPCryptoPALHsm_SE05X_utils.h"
#include "fsl_sss_policy.h"
ex_sss_boot_ctx_t gex_sss_chip_ctx;
#if ENABLE_REENTRANCY
uint8_t objIDtable[MAX_SPAKE_CRYPTO_OBJECT][2] = {
{ kSE05x_CryptoObject_End + 0, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 1, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 2, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 3, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 4, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 5, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 6, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 7, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 8, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 9, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 10, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 11, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 12, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 13, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 14, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 15, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 16, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 17, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 18, OBJ_ID_TABLE_OBJID_STATUS_FREE },
{ kSE05x_CryptoObject_End + 19, OBJ_ID_TABLE_OBJID_STATUS_FREE },
};
int spake_objects_created = 0;
#if !CHIP_SYSTEM_CONFIG_NO_LOCKING
using namespace chip::System;
static Mutex sSEObjMutex;
#define LOCK_SECURE_ELEMENT() \
do \
{ \
sSEObjMutex.Lock(); \
} while (0)
#define UNLOCK_SECURE_ELEMENT() \
do \
{ \
sSEObjMutex.Unlock(); \
} while (0)
#else
#define LOCK_SECURE_ELEMENT()
#define UNLOCK_SECURE_ELEMENT()
#endif // !CHIP_SYSTEM_CONFIG_NO_LOCKING
#endif //#if ENABLE_REENTRANCY
/* Open session to se05x */
void se05x_sessionOpen(void)
{
static int is_session_open = 0;
if (is_session_open)
{
return;
}
memset(&gex_sss_chip_ctx, 0, sizeof(gex_sss_chip_ctx));
const char * portName = nullptr;
sss_status_t status = ex_sss_boot_connectstring(0, NULL, &portName);
if (kStatus_SSS_Success != status)
{
ChipLogError(Crypto, "se05x error: %s\n", "ex_sss_boot_connectstring failed");
return;
}
status = ex_sss_boot_open(&gex_sss_chip_ctx, portName);
if (kStatus_SSS_Success != status)
{
ChipLogError(Crypto, "se05x error: %s\n", "ex_sss_boot_open failed");
return;
}
status = ex_sss_key_store_and_object_init(&gex_sss_chip_ctx);
if (kStatus_SSS_Success != status)
{
ChipLogError(Crypto, "se05x error: %s\n", "ex_sss_key_store_and_object_init failed");
return;
}
is_session_open = 1;
}
/* Delete key in se05x */
void se05x_delete_key(uint32_t keyid)
{
smStatus_t smstatus = SM_NOT_OK;
SE05x_Result_t exists = kSE05x_Result_NA;
se05x_sessionOpen();
if (gex_sss_chip_ctx.ks.session != NULL)
{
smstatus = Se05x_API_CheckObjectExists(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, keyid, &exists);
if (smstatus == SM_OK)
{
if (exists == kSE05x_Result_SUCCESS)
{
smstatus = Se05x_API_DeleteSecureObject(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, keyid);
if (smstatus != SM_OK)
{
ChipLogError(Crypto, "se05x error: %s\n", "Error in deleting key");
}
}
else
{
ChipLogError(Crypto, "se05x warn: %s\n", "Key doesnot exists");
}
}
else
{
ChipLogError(Crypto, "se05x error: %s\n", "Error in Se05x_API_CheckObjectExists");
}
}
}
/* Set key in se05x */
CHIP_ERROR se05x_set_key_for_spake(uint32_t keyid, const uint8_t * key, size_t keylen, sss_key_part_t keyPart,
sss_cipher_type_t cipherType)
{
sss_status_t status = kStatus_SSS_Success;
sss_object_t keyObject = { 0 };
const uint8_t keyBuf[128] = {
0,
};
size_t keyBufLen = 0;
uint8_t header1[] = { 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 };
size_t bitlen = 0;
static sss_policy_u commonPol;
commonPol.type = KPolicy_Common;
commonPol.auth_obj_id = 0;
commonPol.policy.common.req_Sm = 0;
commonPol.policy.common.can_Delete = 1;
commonPol.policy.common.can_Read = 0;
commonPol.policy.common.can_Write = 1;
static sss_policy_u hmac_withPol;
hmac_withPol.type = KPolicy_Sym_Key;
hmac_withPol.auth_obj_id = 0;
hmac_withPol.policy.symmkey.can_Write = 1;
hmac_withPol.policy.symmkey.can_KA = 1;
sss_policy_t policy_for_hmac_key;
policy_for_hmac_key.nPolicies = 2;
policy_for_hmac_key.policies[0] = &hmac_withPol;
policy_for_hmac_key.policies[1] = &commonPol;
if (cipherType == kSSS_CipherType_EC_NIST_P)
{
VerifyOrReturnError(keylen < (sizeof(keyBuf) - sizeof(header1)), CHIP_ERROR_INTERNAL);
memcpy((void *) keyBuf, (const uint8_t *) header1, sizeof(header1));
keyBufLen = keyBufLen + sizeof(header1);
memcpy((void *) (keyBuf + keyBufLen), key, keylen);
keyBufLen = keyBufLen + keylen;
bitlen = 256;
}
else
{
VerifyOrReturnError(keylen < sizeof(keyBuf), CHIP_ERROR_INTERNAL);
memcpy((void *) keyBuf, (const uint8_t *) key, keylen);
keyBufLen = keylen;
bitlen = (size_t) keylen * 8;
}
status = sss_key_object_init(&keyObject, &gex_sss_chip_ctx.ks);
VerifyOrReturnError(status == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
status = sss_key_object_allocate_handle(&keyObject, keyid, keyPart, cipherType, keyBufLen, kKeyObject_Mode_Persistent);
VerifyOrReturnError(status == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
status = sss_key_store_set_key(&gex_sss_chip_ctx.ks, &keyObject, keyBuf, keyBufLen, bitlen, &policy_for_hmac_key,
sizeof(policy_for_hmac_key));
VerifyOrReturnError(status == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
return CHIP_NO_ERROR;
}
CHIP_ERROR se05xGetCertificate(uint32_t keyId, uint8_t * buf, size_t * buflen)
{
sss_object_t keyObject = { 0 };
sss_status_t status = kStatus_SSS_Fail;
size_t certBitLen = 0;
VerifyOrReturnError(buf != nullptr, CHIP_ERROR_INTERNAL);
VerifyOrReturnError(buflen != nullptr, CHIP_ERROR_INTERNAL);
certBitLen = (*buflen) * 8;
se05x_sessionOpen();
status = sss_key_object_init(&keyObject, &gex_sss_chip_ctx.ks);
VerifyOrReturnError(status == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
status = sss_key_object_get_handle(&keyObject, keyId);
VerifyOrReturnError(status == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
status = sss_key_store_get_key(&gex_sss_chip_ctx.ks, &keyObject, buf, buflen, &certBitLen);
VerifyOrReturnError(status == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
return CHIP_NO_ERROR;
}
CHIP_ERROR se05xSetCertificate(uint32_t keyId, const uint8_t * buf, size_t buflen)
{
sss_object_t keyObject = { 0 };
sss_status_t status = kStatus_SSS_Fail;
status = sss_key_object_init(&keyObject, &gex_sss_chip_ctx.ks);
VerifyOrReturnError(status == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
status = sss_key_object_allocate_handle(&keyObject, keyId, kSSS_KeyPart_Default, kSSS_CipherType_Certificate, buflen,
kKeyObject_Mode_Transient);
VerifyOrReturnError(status == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
status = sss_key_store_set_key(&gex_sss_chip_ctx.ks, &keyObject, buf, buflen, buflen * 8, NULL, 0);
VerifyOrReturnError(status == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
return CHIP_NO_ERROR;
}
CHIP_ERROR se05xPerformInternalSign(uint32_t keyId, uint8_t * sigBuf, size_t * sigBufLen)
{
#if SSS_HAVE_APPLET_SE051_H
smStatus_t status = SM_NOT_OK;
sss_se05x_session_t * pSe05xCtx = (sss_se05x_session_t *) &gex_sss_chip_ctx.session;
uint8_t hashData[chip::Crypto::kSHA256_Hash_Length] = { 0 };
size_t hashDataLen = sizeof(hashData);
status = Se05x_API_ECDSA_Internal_Sign(&(pSe05xCtx->s_ctx), keyId, kSE05x_ECSignatureAlgo_SHA_256, sigBuf, sigBufLen, hashData,
&hashDataLen);
VerifyOrReturnError(status == SM_OK, CHIP_ERROR_INTERNAL);
return CHIP_NO_ERROR;
#else
/* Enable Se051H to use internal sign */
return CHIP_ERROR_INTERNAL;
#endif
}
#if ENABLE_REENTRANCY
/* Init crypto object mutext */
void init_cryptoObj_mutex(void)
{
#if !CHIP_SYSTEM_CONFIG_NO_LOCKING
Mutex::Init(sSEObjMutex);
#endif
return;
}
/* Delete all crypto objects in se05x */
void delete_crypto_objects(void)
{
static int obj_deleted = 0;
smStatus_t smstatus = SM_NOT_OK;
uint8_t list[1024] = {
0,
};
size_t listlen = sizeof(list);
size_t i;
if (obj_deleted == 1)
{
return;
}
se05x_sessionOpen();
if (gex_sss_chip_ctx.ks.session != NULL)
{
smstatus = Se05x_API_ReadCryptoObjectList(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, list, &listlen);
if (smstatus != SM_OK)
{
return;
}
for (i = 0; i < listlen; i += 4)
{
uint32_t cryptoObjectId = list[i + 1] | (list[i + 0] << 8);
Se05x_API_DeleteCryptoObject(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx,
(SE05x_CryptoObjectID_t) cryptoObjectId);
}
}
obj_deleted = 1;
spake_objects_created = 0;
return;
}
/* Get unused object id */
SE05x_CryptoObjectID_t getObjID(void)
{
SE05x_CryptoObjectID_t objId = (SE05x_CryptoObjectID_t) 0;
SE05x_Result_t exists = kSE05x_Result_NA;
LOCK_SECURE_ELEMENT();
for (int i = 0; i < MAX_SPAKE_CRYPTO_OBJECT; i++)
{
if (objIDtable[i][OBJ_ID_TABLE_IDX_STATUS] == OBJ_ID_TABLE_OBJID_STATUS_FREE)
{
Se05x_API_CheckObjectExists(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx,
objIDtable[i][OBJ_ID_TABLE_IDX_OBJID], &exists);
if (exists == kSE05x_Result_SUCCESS)
{
// Object in use. Check for other id.
objIDtable[i][OBJ_ID_TABLE_IDX_STATUS] = OBJ_ID_TABLE_OBJID_STATUS_USED;
continue;
}
objId = (SE05x_CryptoObjectID_t) objIDtable[i][OBJ_ID_TABLE_IDX_OBJID];
objIDtable[i][OBJ_ID_TABLE_IDX_STATUS] = OBJ_ID_TABLE_OBJID_STATUS_USED;
goto exit;
}
}
exit:
UNLOCK_SECURE_ELEMENT();
return objId;
}
/* Set object id status */
void setObjID(SE05x_CryptoObjectID_t objId, uint8_t status)
{
LOCK_SECURE_ELEMENT();
for (int i = 0; i < MAX_SPAKE_CRYPTO_OBJECT; i++)
{
if (objIDtable[i][OBJ_ID_TABLE_IDX_OBJID] == objId)
{
objIDtable[i][OBJ_ID_TABLE_IDX_STATUS] = status;
break;
}
}
UNLOCK_SECURE_ELEMENT();
}
#endif //#if ENABLE_REENTRANCY