| /* |
| * |
| * 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" |
| |
| #if ((ENABLE_HSM_SPAKE_VERIFIER) || (ENABLE_HSM_SPAKE_PROVER)) |
| |
| #if ENABLE_HSM_SPAKE_VERIFIER |
| const uint32_t w0in_id_v = 0x7D200001; |
| const uint32_t Lin_id_v = 0x7D200002; |
| #endif |
| |
| #if ENABLE_HSM_SPAKE_PROVER |
| const uint32_t w0in_id_p = 0x7D200003; |
| const uint32_t w1in_id_p = 0x7D200004; |
| #endif |
| |
| void Spake2p_Finish_HSM(hsm_pake_context_t * phsm_pake_context) |
| { |
| #if ENABLE_REENTRANCY |
| if (gex_sss_chip_ctx.ks.session != NULL) |
| { |
| Se05x_API_DeleteCryptoObject(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, phsm_pake_context->spake_objId); |
| setObjID(phsm_pake_context->spake_objId, OBJ_ID_TABLE_OBJID_STATUS_FREE); |
| |
| if (spake_objects_created > 0) |
| { |
| spake_objects_created--; |
| } |
| } |
| #endif //#if ENABLE_REENTRANCY |
| return; |
| } |
| |
| CHIP_ERROR create_init_crypto_obj(chip::Crypto::CHIP_SPAKE2P_ROLE role, hsm_pake_context_t * phsm_pake_context) |
| { |
| smStatus_t smstatus = SM_NOT_OK; |
| SE05x_CryptoModeSubType_t subtype; |
| |
| #if ENABLE_REENTRANCY |
| SE05x_CryptoObjectID_t spakeObjectId = getObjID(); |
| #else |
| SE05x_CryptoObjectID_t spakeObjectId = |
| (role == chip::Crypto::CHIP_SPAKE2P_ROLE::VERIFIER) ? kSE05x_CryptoObject_PAKE_TYPE_B : kSE05x_CryptoObject_PAKE_TYPE_A; |
| uint8_t list[1024] = { |
| 0, |
| }; |
| size_t listlen = sizeof(list); |
| size_t i = 0; |
| uint8_t create_crypto_obj = 1; |
| #endif |
| |
| ChipLogProgress(Crypto, "SE05x: Using Object Id --> %d", spakeObjectId); |
| |
| if (spakeObjectId != 0) |
| { |
| phsm_pake_context->spake_objId = spakeObjectId; |
| } |
| else |
| { |
| return CHIP_ERROR_INTERNAL; |
| } |
| |
| se05x_sessionOpen(); |
| VerifyOrReturnError(gex_sss_chip_ctx.ks.session != NULL, CHIP_ERROR_INTERNAL); |
| |
| subtype.pakeMode = kSE05x_SPAKE2PLUS_P256_SHA256_HKDF_HMAC; |
| |
| #if ENABLE_REENTRANCY |
| VerifyOrReturnError(spake_objects_created < LIMIT_CRYPTO_OBJECTS, CHIP_ERROR_INTERNAL); |
| |
| smstatus = Se05x_API_CreateCryptoObject(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, spakeObjectId, |
| kSE05x_CryptoContext_PAKE, subtype); |
| VerifyOrReturnError(smstatus == SM_OK, CHIP_ERROR_INTERNAL); |
| |
| /* Increment number of crypto objects created */ |
| spake_objects_created++; |
| |
| #else |
| smstatus = Se05x_API_ReadCryptoObjectList(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, list, &listlen); |
| for (i = 0; i < listlen; i += 4) |
| { |
| uint32_t cryptoObjectId = static_cast<uint32_t>(list[i + 1] | (list[i + 0] << 8)); |
| if (cryptoObjectId == spakeObjectId) |
| { |
| create_crypto_obj = 0; |
| } |
| } |
| |
| if (create_crypto_obj) |
| { |
| smstatus = Se05x_API_CreateCryptoObject(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, spakeObjectId, |
| kSE05x_CryptoContext_PAKE, subtype); |
| VerifyOrReturnError(smstatus == SM_OK, CHIP_ERROR_INTERNAL); |
| } |
| #endif |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR Spake2p_ComputeRoundOne_HSM(hsm_pake_context_t * phsm_pake_context, chip::Crypto::CHIP_SPAKE2P_ROLE role, |
| const uint8_t * pab, size_t pab_len, uint8_t * out, size_t * out_len) |
| { |
| SE05x_CryptoObjectID_t spakeObjectId = phsm_pake_context->spake_objId; |
| |
| ChipLogProgress(Crypto, "SE05x: Using HSM for spake2p ComputeRoundOne"); |
| |
| VerifyOrReturnError(out != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(out_len != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| if (pab_len > 0) |
| { |
| VerifyOrReturnError(pab != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| } |
| |
| if (role == chip::Crypto::CHIP_SPAKE2P_ROLE::VERIFIER) |
| { |
| /* Need X/Y value to verify abort condition */ |
| VerifyOrReturnError(pab != NULL, CHIP_ERROR_INVALID_ARGUMENT); |
| } |
| |
| smStatus_t smstatus = Se05x_API_PAKEComputeKeyShare(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, spakeObjectId, |
| (uint8_t *) pab, pab_len, out, out_len); |
| VerifyOrReturnError(smstatus == SM_OK, CHIP_ERROR_INTERNAL); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR Spake2p_ComputeRoundTwo_HSM(hsm_pake_context_t * phsm_pake_context, chip::Crypto::CHIP_SPAKE2P_ROLE role, |
| const uint8_t * in, size_t in_len, uint8_t * out, size_t * out_len, uint8_t * pKeyKe, |
| size_t * pkeyKeLen) |
| { |
| VerifyOrReturnError(in != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(out != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(out_len != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(pKeyKe != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(pkeyKeLen != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| |
| ChipLogProgress(Crypto, "SE05x: Using HSM for spake2p ComputeRoundTwo"); |
| |
| const uint8_t * const pab = (role == chip::Crypto::CHIP_SPAKE2P_ROLE::VERIFIER) ? NULL : in; |
| const size_t pab_len = (role == chip::Crypto::CHIP_SPAKE2P_ROLE::VERIFIER) ? 0 : in_len; |
| |
| VerifyOrReturnError(gex_sss_chip_ctx.ks.session != NULL, CHIP_ERROR_INTERNAL); |
| |
| const SE05x_CryptoObjectID_t spakeObjectId = phsm_pake_context->spake_objId; |
| const smStatus_t smstatus = |
| Se05x_API_PAKEComputeSessionKeys(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, spakeObjectId, |
| (uint8_t *) pab, pab_len, pKeyKe, pkeyKeLen, out, out_len); |
| VerifyOrReturnError(smstatus == SM_OK, CHIP_ERROR_INTERNAL); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR Spake2p_KeyConfirm_HSM(hsm_pake_context_t * phsm_pake_context, chip::Crypto::CHIP_SPAKE2P_ROLE role, const uint8_t * in, |
| size_t in_len) |
| { |
| VerifyOrReturnError(in != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(gex_sss_chip_ctx.ks.session != NULL, CHIP_ERROR_INTERNAL); |
| |
| ChipLogProgress(Crypto, "SE05x: Using HSM for spake2p KeyConfirm"); |
| |
| uint8_t presult = 0; |
| const SE05x_CryptoObjectID_t spakeObjectId = phsm_pake_context->spake_objId; |
| const smStatus_t smstatus = Se05x_API_PAKEVerifySessionKeys(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, |
| spakeObjectId, (uint8_t *) in, in_len, &presult); |
| VerifyOrReturnError(smstatus == SM_OK, CHIP_ERROR_INTERNAL); |
| |
| return (presult == 1) ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; |
| } |
| |
| namespace chip { |
| namespace Crypto { |
| |
| CHIP_ERROR Spake2pHSM_P256_SHA256_HKDF_HMAC::Init(const uint8_t * context, size_t context_len) |
| { |
| state = CHIP_SPAKE2P_STATE::PREINIT; |
| |
| #if ENABLE_REENTRANCY |
| static uint8_t alreadyInitialised = 0; |
| if (alreadyInitialised == false) |
| { |
| delete_crypto_objects(); |
| init_cryptoObj_mutex(); |
| alreadyInitialised = true; |
| } |
| #endif //#if ENABLE_REENTRANCY |
| |
| if (context_len > 0) |
| { |
| VerifyOrReturnError(context != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| } |
| VerifyOrReturnError(context_len <= sizeof(hsm_pake_context.spake_context), CHIP_ERROR_INTERNAL); |
| memset(hsm_pake_context.spake_context, 0, sizeof(hsm_pake_context.spake_context)); |
| if (context_len > 0) |
| { |
| memcpy(hsm_pake_context.spake_context, context, context_len); |
| } |
| hsm_pake_context.spake_context_len = context_len; |
| |
| const CHIP_ERROR error = Spake2p::Init(context, context_len); |
| if (error == CHIP_NO_ERROR) |
| { |
| state = CHIP_SPAKE2P_STATE::INIT; |
| } |
| |
| return error; |
| } |
| |
| #if ENABLE_HSM_SPAKE_VERIFIER |
| CHIP_ERROR Spake2pHSM_P256_SHA256_HKDF_HMAC::BeginVerifier(const uint8_t * my_identity, size_t my_identity_len, |
| const uint8_t * peer_identity, size_t peer_identity_len, |
| const uint8_t * w0in, size_t w0in_len, const uint8_t * Lin, |
| size_t Lin_len) |
| { |
| uint8_t w0in_mod[32] = { |
| 0, |
| }; |
| size_t w0in_mod_len = 32; |
| smStatus_t smstatus = SM_NOT_OK; |
| |
| VerifyOrReturnError(w0in != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(Lin != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::INIT, CHIP_ERROR_INTERNAL); |
| if (my_identity_len > 0) |
| { |
| VerifyOrReturnError(my_identity != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| } |
| if (peer_identity_len > 0) |
| { |
| VerifyOrReturnError(peer_identity != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| } |
| |
| ChipLogProgress(Crypto, "SE05x: HSM - BeginVerifier"); |
| |
| ReturnErrorOnFailure(FELoad(w0in, w0in_len, w0)); |
| ReturnErrorOnFailure(FEWrite(w0, w0in_mod, w0in_mod_len)); |
| ReturnErrorOnFailure(create_init_crypto_obj(chip::Crypto::CHIP_SPAKE2P_ROLE::VERIFIER, &hsm_pake_context)); |
| |
| smstatus = Se05x_API_PAKEConfigDevice(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, hsm_pake_context.spake_objId, |
| SE05x_SPAKE2PLUS_DEVICE_TYPE_B); |
| VerifyOrReturnError(smstatus == SM_OK, CHIP_ERROR(chip::ChipError::Range::kPlatform, smstatus)); |
| |
| ReturnErrorOnFailure(se05x_set_key_for_spake(w0in_id_v, w0in_mod, w0in_mod_len, kSSS_KeyPart_Default, kSSS_CipherType_HMAC)); |
| ReturnErrorOnFailure(se05x_set_key_for_spake(Lin_id_v, Lin, Lin_len, kSSS_KeyPart_Default, kSSS_CipherType_HMAC)); |
| |
| smstatus = Se05x_API_PAKEInitDevice(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, hsm_pake_context.spake_objId, |
| (uint8_t *) hsm_pake_context.spake_context, hsm_pake_context.spake_context_len, |
| (uint8_t *) peer_identity, peer_identity_len, (uint8_t *) my_identity, my_identity_len); |
| VerifyOrReturnError(smstatus == SM_OK, CHIP_ERROR(chip::ChipError::Range::kPlatform, smstatus)); |
| |
| smstatus = Se05x_API_PAKEInitCredentials(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, |
| hsm_pake_context.spake_objId, w0in_id_v, 0, Lin_id_v); |
| VerifyOrReturnError(smstatus == SM_OK, CHIP_ERROR(chip::ChipError::Range::kPlatform, smstatus)); |
| |
| state = CHIP_SPAKE2P_STATE::STARTED; |
| role = CHIP_SPAKE2P_ROLE::VERIFIER; |
| |
| return CHIP_NO_ERROR; |
| } |
| #endif |
| |
| #if ENABLE_HSM_SPAKE_PROVER |
| CHIP_ERROR Spake2pHSM_P256_SHA256_HKDF_HMAC::BeginProver(const uint8_t * my_identity, size_t my_identity_len, |
| const uint8_t * peer_identity, size_t peer_identity_len, |
| const uint8_t * w0in, size_t w0in_len, const uint8_t * w1in, |
| size_t w1in_len) |
| { |
| smStatus_t smstatus = SM_NOT_OK; |
| uint8_t w0in_mod[32] = { |
| 0, |
| }; |
| size_t w0in_mod_len = 32; |
| uint8_t w1in_mod[32] = { |
| 0, |
| }; |
| size_t w1in_mod_len = 32; |
| |
| VerifyOrReturnError(w0in != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(w1in != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| if (my_identity_len > 0) |
| { |
| VerifyOrReturnError(my_identity != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| } |
| if (peer_identity_len > 0) |
| { |
| VerifyOrReturnError(peer_identity != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| } |
| |
| VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::INIT, CHIP_ERROR_INTERNAL); |
| |
| ChipLogProgress(Crypto, "SE05x: HSM - BeginProver"); |
| |
| ReturnErrorOnFailure(FELoad(w0in, w0in_len, w0)); |
| ReturnErrorOnFailure(FEWrite(w0, w0in_mod, w0in_mod_len)); |
| ReturnErrorOnFailure(FELoad(w1in, w1in_len, w1)); |
| ReturnErrorOnFailure(FEWrite(w1, w1in_mod, w1in_mod_len)); |
| ReturnErrorOnFailure(create_init_crypto_obj(chip::Crypto::CHIP_SPAKE2P_ROLE::PROVER, &hsm_pake_context)); |
| |
| smstatus = Se05x_API_PAKEConfigDevice(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, hsm_pake_context.spake_objId, |
| SE05x_SPAKE2PLUS_DEVICE_TYPE_A); |
| VerifyOrReturnError(smstatus == SM_OK, CHIP_ERROR(chip::ChipError::Range::kPlatform, smstatus)); |
| |
| ReturnErrorOnFailure(se05x_set_key_for_spake(w0in_id_p, w0in_mod, w0in_mod_len, kSSS_KeyPart_Default, kSSS_CipherType_HMAC)); |
| ReturnErrorOnFailure(se05x_set_key_for_spake(w1in_id_p, w1in_mod, w1in_mod_len, kSSS_KeyPart_Default, kSSS_CipherType_HMAC)); |
| |
| smstatus = Se05x_API_PAKEInitDevice(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, hsm_pake_context.spake_objId, |
| (uint8_t *) hsm_pake_context.spake_context, hsm_pake_context.spake_context_len, |
| (uint8_t *) my_identity, my_identity_len, (uint8_t *) peer_identity, peer_identity_len); |
| VerifyOrReturnError(smstatus == SM_OK, CHIP_ERROR(chip::ChipError::Range::kPlatform, smstatus)); |
| |
| smstatus = Se05x_API_PAKEInitCredentials(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, |
| hsm_pake_context.spake_objId, w0in_id_p, w1in_id_p, 0); |
| VerifyOrReturnError(smstatus == SM_OK, CHIP_ERROR(chip::ChipError::Range::kPlatform, smstatus)); |
| |
| state = CHIP_SPAKE2P_STATE::STARTED; |
| role = CHIP_SPAKE2P_ROLE::PROVER; |
| |
| return CHIP_NO_ERROR; |
| } |
| #endif |
| |
| CHIP_ERROR Spake2pHSM_P256_SHA256_HKDF_HMAC::ComputeRoundOne(const uint8_t * pab, size_t pab_len, uint8_t * out, size_t * out_len) |
| { |
| VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::STARTED, CHIP_ERROR_INTERNAL); |
| VerifyOrReturnError(*out_len >= point_size, CHIP_ERROR_INTERNAL); |
| |
| #if !ENABLE_HSM_SPAKE_VERIFIER |
| const bool sw_rollback_verifier = (role == chip::Crypto::CHIP_SPAKE2P_ROLE::VERIFIER); |
| #else |
| constexpr bool sw_rollback_verifier = false; |
| #endif |
| |
| #if ((CHIP_CRYPTO_HSM) && (!ENABLE_HSM_SPAKE_PROVER)) |
| const bool sw_rollback_prover = (role == chip::Crypto::CHIP_SPAKE2P_ROLE::PROVER); |
| #else |
| constexpr bool sw_rollback_prover = false; |
| #endif |
| |
| if (sw_rollback_verifier || sw_rollback_prover) |
| { |
| return Spake2p::ComputeRoundOne(pab, pab_len, out, out_len); |
| } |
| |
| CHIP_ERROR error = Spake2p_ComputeRoundOne_HSM(&hsm_pake_context, role, pab, pab_len, out, out_len); |
| if (CHIP_NO_ERROR == error) |
| { |
| state = CHIP_SPAKE2P_STATE::R1; |
| } |
| return error; |
| } |
| |
| CHIP_ERROR Spake2pHSM_P256_SHA256_HKDF_HMAC::ComputeRoundTwo(const uint8_t * in, size_t in_len, uint8_t * out, size_t * out_len) |
| { |
| VerifyOrReturnError(*out_len >= hash_size, CHIP_ERROR_INTERNAL); |
| VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::R1, CHIP_ERROR_INTERNAL); |
| VerifyOrReturnError(in_len == point_size, CHIP_ERROR_INTERNAL); |
| |
| #if !ENABLE_HSM_SPAKE_VERIFIER |
| const bool sw_rollback_verifier = (role == chip::Crypto::CHIP_SPAKE2P_ROLE::VERIFIER); |
| #else |
| constexpr bool sw_rollback_verifier = false; |
| #endif |
| |
| #if !ENABLE_HSM_SPAKE_PROVER |
| const bool sw_rollback_prover = (role == chip::Crypto::CHIP_SPAKE2P_ROLE::PROVER); |
| #else |
| constexpr bool sw_rollback_prover = false; |
| #endif |
| |
| if (sw_rollback_verifier || sw_rollback_prover) |
| { |
| return Spake2p::ComputeRoundTwo(in, in_len, out, out_len); |
| } |
| |
| uint8_t pKeyKe[16] = { |
| 0, |
| }; |
| size_t pkeyKeLen = sizeof(pKeyKe); |
| |
| const CHIP_ERROR error = Spake2p_ComputeRoundTwo_HSM(&hsm_pake_context, role, in, in_len, out, out_len, pKeyKe, &pkeyKeLen); |
| if (CHIP_NO_ERROR == error) |
| { |
| memcpy((Kae + 16), pKeyKe, pkeyKeLen); |
| state = CHIP_SPAKE2P_STATE::R2; |
| } |
| return error; |
| } |
| |
| CHIP_ERROR Spake2pHSM_P256_SHA256_HKDF_HMAC::KeyConfirm(const uint8_t * in, size_t in_len) |
| { |
| VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::R2, CHIP_ERROR_INTERNAL); |
| |
| #if !ENABLE_HSM_SPAKE_VERIFIER |
| const bool sw_rollback_verifier = (role == chip::Crypto::CHIP_SPAKE2P_ROLE::VERIFIER); |
| #else |
| constexpr bool sw_rollback_verifier = false; |
| #endif |
| |
| #if !ENABLE_HSM_SPAKE_PROVER |
| const bool sw_rollback_prover = (role == chip::Crypto::CHIP_SPAKE2P_ROLE::PROVER); |
| #else |
| constexpr bool sw_rollback_prover = false; |
| #endif |
| |
| if (sw_rollback_verifier || sw_rollback_prover) |
| { |
| return Spake2p::KeyConfirm(in, in_len); |
| } |
| const CHIP_ERROR error = Spake2p_KeyConfirm_HSM(&hsm_pake_context, role, in, in_len); |
| if (CHIP_NO_ERROR == error) |
| { |
| state = CHIP_SPAKE2P_STATE::KC; |
| } |
| |
| Spake2p_Finish_HSM(&hsm_pake_context); |
| |
| return error; |
| } |
| |
| } // namespace Crypto |
| } // namespace chip |
| |
| #endif //#if ((ENABLE_HSM_SPAKE_VERIFIER) || (ENABLE_HSM_SPAKE_PROVER)) |