diff --git a/src/crypto/BUILD.gn b/src/crypto/BUILD.gn index d1751178f33115..3e17c095415fb9 100644 --- a/src/crypto/BUILD.gn +++ b/src/crypto/BUILD.gn @@ -86,8 +86,11 @@ static_library("crypto") { } if (chip_with_se05x == 1) { - sources += [ "hsm/nxp/CHIPCryptoPALHsm_SE05X_Spake2p.cpp" ] - sources += [ "hsm/nxp/CHIPCryptoPALHsm_SE05X_utils.cpp" ] + sources += [ + "hsm/nxp/CHIPCryptoPALHsm_SE05X_P256.cpp", + "hsm/nxp/CHIPCryptoPALHsm_SE05X_Spake2p.cpp", + "hsm/nxp/CHIPCryptoPALHsm_SE05X_utils.cpp", + ] public_deps += [ "${chip_root}/third_party/simw-top-mini:se05x" ] public_configs += [ "${chip_root}/third_party/simw-top-mini:se05x_config" ] } diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index 1bd00bb9e9116c..6ee129e3de0e9e 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -243,17 +243,17 @@ class P256Keypair : public ECPKeypair + +#if ENABLE_HSM_GENERATE_EC_KEY + +#define MAX_SHA_ONE_SHOT_DATA_LEN 900 +#define NIST256_HEADER_OFFSET 26 + +namespace chip { +namespace Crypto { + +P256KeypairHSM::~P256KeypairHSM() +{ + if (keyid != kKeyId_NotInitialized) + { + if (provisioned_key == false) + { + ChipLogDetail(Crypto, "Deleting key with id - %x !", keyid); + se05x_delete_key(keyid); + } + else + { + ChipLogDetail(Crypto, "Provisioned key ! Not deleting key in HSM"); + } + } +} + +CHIP_ERROR P256KeypairHSM::Initialize() +{ + CHIP_ERROR error = CHIP_ERROR_INTERNAL; + sss_status_t status = kStatus_SSS_Success; + sss_object_t keyObject = { 0 }; + uint8_t pubkey[128] = { + 0, + }; + size_t pubKeyLen = sizeof(pubkey); + size_t pbKeyBitLen = sizeof(pubkey) * 8; + + if (keyid == 0) + { + ChipLogDetail(Crypto, "Keyid not set !. Set key id using 'SetKeyId' member class !"); + ExitNow(); + } + + se05x_sessionOpen(); + + status = sss_key_object_init(&keyObject, &gex_sss_chip_ctx.ks); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + if (provisioned_key == false) + { + + status = sss_key_object_allocate_handle(&keyObject, keyid, kSSS_KeyPart_Pair, kSSS_CipherType_EC_NIST_P, 256, + kKeyObject_Mode_Transient); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + ChipLogDetail(Crypto, "Creating Nist256 key on SE05X !"); + + status = sss_key_store_generate_key(&gex_sss_chip_ctx.ks, &keyObject, 256, 0); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + } + else + { + + // if the key is provisioned already, only get the public key, + // and set it in public key member of this class. + ChipLogDetail(Crypto, "Provisioned key ! Not creating key in HSM"); + + status = sss_key_object_get_handle(&keyObject, keyid); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + } + + status = sss_key_store_get_key(&gex_sss_chip_ctx.ks, &keyObject, pubkey, &pubKeyLen, &pbKeyBitLen); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + { + /* Set the public key */ + const P256PublicKey & public_key = Pubkey(); + VerifyOrExit(pubKeyLen > NIST256_HEADER_OFFSET, error = CHIP_ERROR_INTERNAL); + VerifyOrExit((pubKeyLen - NIST256_HEADER_OFFSET) <= kP256_PublicKey_Length, error = CHIP_ERROR_INTERNAL); + memcpy((void *) Uint8::to_const_uchar(public_key), pubkey + NIST256_HEADER_OFFSET, pubKeyLen - NIST256_HEADER_OFFSET); + } + + error = CHIP_NO_ERROR; +exit: + return error; +} + +CHIP_ERROR P256KeypairHSM::ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) +{ + CHIP_ERROR error = CHIP_ERROR_INTERNAL; + sss_digest_t digest_ctx = { 0 }; + sss_asymmetric_t asymm_ctx = { 0 }; + uint8_t hash[kSHA256_Hash_Length] = { + 0, + }; + size_t hashLen = sizeof(hash); + sss_status_t status = kStatus_SSS_Success; + sss_object_t keyObject = { 0 }; + size_t siglen = out_signature.Capacity(); + + VerifyOrExit(msg != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(msg_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(out_signature != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(keyid != kKeyId_NotInitialized, error = CHIP_ERROR_HSM); + + ChipLogDetail(Crypto, "ECDSA_sign_msg: Using SE05X for Ecc Sign!"); + + se05x_sessionOpen(); + + status = sss_digest_context_init(&digest_ctx, &gex_sss_chip_ctx.session, kAlgorithm_SSS_SHA256, kMode_SSS_Digest); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + if (msg_length <= MAX_SHA_ONE_SHOT_DATA_LEN) + { + status = sss_digest_one_go(&digest_ctx, msg, msg_length, hash, &hashLen); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + } + else + { + /* Calculate SHA using multistep calls */ + size_t datalenTemp = 0; + size_t rem_len = msg_length; + + status = sss_digest_init(&digest_ctx); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + while (rem_len > 0) + { + datalenTemp = (rem_len > MAX_SHA_ONE_SHOT_DATA_LEN) ? MAX_SHA_ONE_SHOT_DATA_LEN : rem_len; + status = sss_digest_update(&digest_ctx, (msg + (msg_length - rem_len)), datalenTemp); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + rem_len = rem_len - datalenTemp; + } + + status = sss_digest_finish(&digest_ctx, hash, &hashLen); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + } + + status = sss_key_object_init(&keyObject, &gex_sss_chip_ctx.ks); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + status = sss_key_object_get_handle(&keyObject, keyid); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + status = sss_asymmetric_context_init(&asymm_ctx, &gex_sss_chip_ctx.session, &keyObject, kAlgorithm_SSS_SHA256, kMode_SSS_Sign); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + status = sss_asymmetric_sign_digest(&asymm_ctx, hash, hashLen, Uint8::to_uchar(out_signature), &siglen); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + SuccessOrExit(out_signature.SetLength(siglen)); + + error = CHIP_NO_ERROR; +exit: + if (asymm_ctx.session != nullptr) + { + sss_asymmetric_context_free(&asymm_ctx); + } + if (digest_ctx.session != nullptr) + { + sss_digest_context_free(&digest_ctx); + } + return error; +} + +CHIP_ERROR P256KeypairHSM::ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, P256ECDSASignature & out_signature) +{ + CHIP_ERROR error = CHIP_ERROR_INTERNAL; + sss_asymmetric_t asymm_ctx = { 0 }; + sss_status_t status = kStatus_SSS_Success; + sss_object_t keyObject = { 0 }; + size_t siglen = out_signature.Capacity(); + + VerifyOrExit(hash != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(hash_length == kSHA256_Hash_Length, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(out_signature != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(keyid != kKeyId_NotInitialized, error = CHIP_ERROR_HSM); + + ChipLogDetail(Crypto, "ECDSA_sign_hash: Using SE05X for Ecc Sign!"); + + se05x_sessionOpen(); + + status = sss_key_object_init(&keyObject, &gex_sss_chip_ctx.ks); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + status = sss_key_object_get_handle(&keyObject, keyid); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + status = sss_asymmetric_context_init(&asymm_ctx, &gex_sss_chip_ctx.session, &keyObject, kAlgorithm_SSS_SHA256, kMode_SSS_Sign); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + status = + sss_asymmetric_sign_digest(&asymm_ctx, const_cast(hash), hash_length, Uint8::to_uchar(out_signature), &siglen); + VerifyOrExit(status == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL); + + SuccessOrExit(out_signature.SetLength(siglen)); + + error = CHIP_NO_ERROR; +exit: + if (asymm_ctx.session != nullptr) + { + sss_asymmetric_context_free(&asymm_ctx); + } + + return error; +} + +CHIP_ERROR P256KeypairHSM::Serialize(P256SerializedKeypair & output) +{ + CHIP_ERROR error = CHIP_ERROR_INTERNAL; + size_t len = output.Length() == 0 ? output.Capacity() : output.Length(); + Encoding::BufferWriter bbuf(output, len); + uint8_t privkey[kP256_PrivateKey_Length] = { + 0, + }; + + { + /* Set the public key */ + P256PublicKey & public_key = const_cast(Pubkey()); + bbuf.Put(Uint8::to_uchar(public_key), public_key.Length()); + } + + VerifyOrExit(bbuf.Available() == sizeof(privkey), error = CHIP_ERROR_INTERNAL); + VerifyOrExit(sizeof(privkey) >= 4, error = CHIP_ERROR_INTERNAL); + + { + /* When HSM is used for ECC key generation, store key info in private key buffer */ + Encoding::LittleEndian::BufferWriter privkey_bbuf(privkey, sizeof(privkey)); + privkey_bbuf.Put32(keyid); + } + + bbuf.Put(privkey, sizeof(privkey)); + VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_BUFFER_TOO_SMALL); + + output.SetLength(bbuf.Needed()); + + error = CHIP_NO_ERROR; +exit: + return error; +} + +CHIP_ERROR P256KeypairHSM::Deserialize(P256SerializedKeypair & input) +{ + CHIP_ERROR error = CHIP_ERROR_INTERNAL; + + /* Set the public key */ + const P256PublicKey & public_key = Pubkey(); + Encoding::BufferWriter bbuf((uint8_t *) Uint8::to_const_uchar(public_key), public_key.Length()); + + VerifyOrExit(input.Length() == public_key.Length() + kP256_PrivateKey_Length, error = CHIP_ERROR_INVALID_ARGUMENT); + bbuf.Put(static_cast(input), public_key.Length()); + + /* Set private key info */ + VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_NO_MEMORY); + { + /* When HSM is used for ECC key generation, key info in stored in private key buffer */ + const uint8_t * privkey = Uint8::to_const_uchar(input) + public_key.Length(); + keyid = Encoding::LittleEndian::Get32(privkey); + } + + error = CHIP_NO_ERROR; +exit: + return error; +} + +CHIP_ERROR P256KeypairHSM::ECDH_derive_secret(const P256PublicKey & remote_public_key, P256ECDHDerivedSecret & out_secret) const +{ + CHIP_ERROR error = CHIP_ERROR_INTERNAL; + const uint8_t * rem_pubKey = nullptr; + size_t rem_pubKeyLen = 0; + size_t secret_length = (out_secret.Length() == 0) ? out_secret.Capacity() : out_secret.Length(); + smStatus_t smstatus = SM_NOT_OK; + + VerifyOrExit(keyid != kKeyId_NotInitialized, error = CHIP_ERROR_HSM); + + ChipLogDetail(Crypto, "ECDH_derive_secret: Using SE05X for ECDH !"); + + se05x_sessionOpen(); + + rem_pubKey = Uint8::to_const_uchar(remote_public_key); + rem_pubKeyLen = remote_public_key.Length(); + + VerifyOrExit(gex_sss_chip_ctx.ks.session != nullptr, error = CHIP_ERROR_INTERNAL); + + smstatus = Se05x_API_ECGenSharedSecret(&((sss_se05x_session_t *) &gex_sss_chip_ctx.session)->s_ctx, keyid, rem_pubKey, + rem_pubKeyLen, Uint8::to_uchar(out_secret), &secret_length); + VerifyOrExit(smstatus == SM_OK, error = CHIP_ERROR_INTERNAL); + + SuccessOrExit(out_secret.SetLength(secret_length)); + + error = CHIP_NO_ERROR; +exit: + return error; +} + +} // namespace Crypto +} // namespace chip + +#endif //#if ENABLE_HSM_GENERATE_EC_KEY diff --git a/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_utils.h b/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_utils.h index 3fec9affb33d03..9b384326df58e7 100644 --- a/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_utils.h +++ b/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_utils.h @@ -39,6 +39,12 @@ extern ex_sss_boot_ctx_t gex_sss_chip_ctx; +/* SE predefined keyid values */ +enum keyid_values +{ + kKeyId_NotInitialized = 0, +}; + // Enable the below macro to make spake HSM imlementation reentrant. #define ENABLE_REENTRANCY 0 diff --git a/src/crypto/tests/CHIPCryptoPALTest.cpp b/src/crypto/tests/CHIPCryptoPALTest.cpp index 903ffd35b17304..42d2953b80d83a 100644 --- a/src/crypto/tests/CHIPCryptoPALTest.cpp +++ b/src/crypto/tests/CHIPCryptoPALTest.cpp @@ -49,9 +49,28 @@ #include #include +#define HSM_ECC_KEYID 0x11223344 + using namespace chip; using namespace chip::Crypto; +#ifdef ENABLE_HSM_EC_KEY +class Test_P256Keypair : public P256KeypairHSM +{ +public: + Test_P256Keypair() { SetKeyId(HSM_ECC_KEYID); } + Test_P256Keypair(int keyId) { SetKeyId(keyId); } +}; +#else +using Test_P256Keypair = P256Keypair; +#endif + +#ifdef ENABLE_HSM_SPAKE +using TestSpake2p_P256_SHA256_HKDF_HMAC = Spake2pHSM_P256_SHA256_HKDF_HMAC; +#else +using TestSpake2p_P256_SHA256_HKDF_HMAC = Spake2p_P256_SHA256_HKDF_HMAC; +#endif + static uint32_t gs_test_entropy_source_called = 0; static int test_entropy_source(void * data, uint8_t * output, size_t len, size_t * olen) { @@ -662,7 +681,8 @@ static void TestECDSA_Signing_SHA256_Msg(nlTestSuite * inSuite, void * inContext const char * msg = "Hello World!"; size_t msg_length = strlen(msg); - P256Keypair keypair; + Test_P256Keypair keypair; + NL_TEST_ASSERT(inSuite, keypair.Initialize() == CHIP_NO_ERROR); P256ECDSASignature signature; @@ -680,7 +700,8 @@ static void TestECDSA_Signing_SHA256_Hash(nlTestSuite * inSuite, void * inContex 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }; size_t hash_length = sizeof(hash); - P256Keypair keypair; + Test_P256Keypair keypair; + NL_TEST_ASSERT(inSuite, keypair.Initialize() == CHIP_NO_ERROR); P256ECDSASignature signature; @@ -849,10 +870,14 @@ static void TestECDSA_ValidationHashInvalidParam(nlTestSuite * inSuite, void * i static void TestECDH_EstablishSecret(nlTestSuite * inSuite, void * inContext) { - P256Keypair keypair1; + Test_P256Keypair keypair1; NL_TEST_ASSERT(inSuite, keypair1.Initialize() == CHIP_NO_ERROR); - P256Keypair keypair2; +#ifdef ENABLE_HSM_EC_KEY + Test_P256Keypair keypair2(HSM_ECC_KEYID + 1); +#else + Test_P256Keypair keypair2; +#endif NL_TEST_ASSERT(inSuite, keypair2.Initialize() == CHIP_NO_ERROR); P256ECDHDerivedSecret out_secret1; @@ -959,13 +984,14 @@ static void TestCSR_Gen(nlTestSuite * inSuite, void * inContext) static void TestKeypair_Serialize(nlTestSuite * inSuite, void * inContext) { - P256Keypair keypair; + Test_P256Keypair keypair; + NL_TEST_ASSERT(inSuite, keypair.Initialize() == CHIP_NO_ERROR); P256SerializedKeypair serialized; NL_TEST_ASSERT(inSuite, keypair.Serialize(serialized) == CHIP_NO_ERROR); - P256Keypair keypair_dup; + Test_P256Keypair keypair_dup; NL_TEST_ASSERT(inSuite, keypair_dup.Deserialize(serialized) == CHIP_NO_ERROR); const char * msg = "Test Message for Keygen"; @@ -989,11 +1015,9 @@ static void TestSPAKE2P_spake2p_FEMul(nlTestSuite * inSuite, void * inContext) for (int vectorIndex = 0; vectorIndex < numOfTestVectors; vectorIndex++) { const struct spake2p_fe_mul_tv * vector = fe_mul_tvs[vectorIndex]; -#if CHIP_CRYPTO_HSM - Spake2pHSM_P256_SHA256_HKDF_HMAC spake2p; -#else - Spake2p_P256_SHA256_HKDF_HMAC spake2p; -#endif + + TestSpake2p_P256_SHA256_HKDF_HMAC spake2p; + CHIP_ERROR err = spake2p.Init(nullptr, 0); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); @@ -1026,11 +1050,8 @@ static void TestSPAKE2P_spake2p_FELoadWrite(nlTestSuite * inSuite, void * inCont { const struct spake2p_fe_rw_tv * vector = fe_rw_tvs[vectorIndex]; -#if CHIP_CRYPTO_HSM - Spake2pHSM_P256_SHA256_HKDF_HMAC spake2p; -#else - Spake2p_P256_SHA256_HKDF_HMAC spake2p; -#endif + TestSpake2p_P256_SHA256_HKDF_HMAC spake2p; + CHIP_ERROR err = spake2p.Init(nullptr, 0); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); @@ -1057,11 +1078,8 @@ static void TestSPAKE2P_spake2p_Mac(nlTestSuite * inSuite, void * inContext) { const struct spake2p_hmac_tv * vector = hmac_tvs[vectorIndex]; -#if CHIP_CRYPTO_HSM - Spake2pHSM_P256_SHA256_HKDF_HMAC spake2p; -#else - Spake2p_P256_SHA256_HKDF_HMAC spake2p; -#endif + TestSpake2p_P256_SHA256_HKDF_HMAC spake2p; + CHIP_ERROR err = spake2p.Init(nullptr, 0); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); @@ -1091,11 +1109,8 @@ static void TestSPAKE2P_spake2p_PointMul(nlTestSuite * inSuite, void * inContext out_len = sizeof(output); const struct spake2p_point_mul_tv * vector = point_mul_tvs[vectorIndex]; -#if CHIP_CRYPTO_HSM - Spake2pHSM_P256_SHA256_HKDF_HMAC spake2p; -#else - Spake2p_P256_SHA256_HKDF_HMAC spake2p; -#endif + TestSpake2p_P256_SHA256_HKDF_HMAC spake2p; + CHIP_ERROR err = spake2p.Init(nullptr, 0); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); @@ -1131,11 +1146,8 @@ static void TestSPAKE2P_spake2p_PointMulAdd(nlTestSuite * inSuite, void * inCont out_len = sizeof(output); const struct spake2p_point_muladd_tv * vector = point_muladd_tvs[vectorIndex]; -#if CHIP_CRYPTO_HSM - Spake2pHSM_P256_SHA256_HKDF_HMAC spake2p; -#else - Spake2p_P256_SHA256_HKDF_HMAC spake2p; -#endif + TestSpake2p_P256_SHA256_HKDF_HMAC spake2p; + CHIP_ERROR err = spake2p.Init(nullptr, 0); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); @@ -1177,11 +1189,8 @@ static void TestSPAKE2P_spake2p_PointLoadWrite(nlTestSuite * inSuite, void * inC out_len = sizeof(output); const struct spake2p_point_rw_tv * vector = point_rw_tvs[vectorIndex]; -#if CHIP_CRYPTO_HSM - Spake2pHSM_P256_SHA256_HKDF_HMAC spake2p; -#else - Spake2p_P256_SHA256_HKDF_HMAC spake2p; -#endif + TestSpake2p_P256_SHA256_HKDF_HMAC spake2p; + CHIP_ERROR err = spake2p.Init(nullptr, 0); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); @@ -1207,11 +1216,8 @@ static void TestSPAKE2P_spake2p_PointIsValid(nlTestSuite * inSuite, void * inCon { const struct spake2p_point_valid_tv * vector = point_valid_tvs[vectorIndex]; -#if CHIP_CRYPTO_HSM - Spake2pHSM_P256_SHA256_HKDF_HMAC spake2p; -#else - Spake2p_P256_SHA256_HKDF_HMAC spake2p; -#endif + TestSpake2p_P256_SHA256_HKDF_HMAC spake2p; + CHIP_ERROR err = spake2p.Init(nullptr, 0); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); @@ -1231,7 +1237,7 @@ static void TestSPAKE2P_spake2p_PointIsValid(nlTestSuite * inSuite, void * inCon // We need to "generate" specific field elements // to do so we need to override the specific method class Test_Spake2p_P256_SHA256_HKDF_HMAC : -#if CHIP_CRYPTO_HSM +#ifdef ENABLE_HSM_SPAKE public Spake2pHSM_P256_SHA256_HKDF_HMAC #else public Spake2p_P256_SHA256_HKDF_HMAC