| /* |
| * |
| * 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 |