From 25c088a9ade8879e3432fc292785b0bbf8be1f75 Mon Sep 17 00:00:00 2001 From: Ji Luo Date: Wed, 25 Jan 2023 15:58:11 +0800 Subject: [PATCH 1/7] Integrate libtrustymatter the libtrustymatter third-party lib contains the Trusty IPC infrastructure and client application in the Non-secure side. Change-Id: Id2cb5ccc0006d9f51cab06ed971174a94aa0111f Signed-off-by: Ji Luo Reviewed-on: http://androidsource.nxp.com/project/21249 Reviewed-by: Elven Wang Reviewed-on: http://androidsource.nxp.com/project/23003 --- .gitmodules | 3 ++ third_party/libtrustymatter/BUILD.gn | 48 ++++++++++++++++++++++++++++ third_party/libtrustymatter/repo | 1 + 3 files changed, 52 insertions(+) create mode 100644 third_party/libtrustymatter/BUILD.gn create mode 160000 third_party/libtrustymatter/repo diff --git a/.gitmodules b/.gitmodules index 86981aa68619aa..a3b101a40b6380 100644 --- a/.gitmodules +++ b/.gitmodules @@ -354,3 +354,6 @@ url = https://github.com/paullouisageneau/libdatachannel.git platforms = linux recursive = true +[submodule "third_party/libtrustymatter/repo"] + path = third_party/libtrustymatter/repo + url = https://github.com/nxp-imx/libtrustymatter diff --git a/third_party/libtrustymatter/BUILD.gn b/third_party/libtrustymatter/BUILD.gn new file mode 100644 index 00000000000000..f172f1251a8581 --- /dev/null +++ b/third_party/libtrustymatter/BUILD.gn @@ -0,0 +1,48 @@ +# Copyright (c) 2023 Project CHIP Authors +# Copyright 2025 NXP +# +# 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. + +import("//build_overrides/chip.gni") + +config("libtrustymatter_config") { + include_dirs = [ + "repo/matter_client/include", + "repo/libtrusty/include", + ] +} + +source_set("libtrustymatter") { + sources = [ + "repo/libtrusty/include/trusty/ipc.h", + "repo/libtrusty/include/trusty/tipc.h", + "repo/libtrusty/trusty.c", + "repo/matter_client/include/UniquePtr.h", + "repo/matter_client/include/matter_defs.h", + "repo/matter_client/include/matter_ipc.h", + "repo/matter_client/include/matter_messages.h", + "repo/matter_client/include/mem.h", + "repo/matter_client/include/serializable.h", + "repo/matter_client/include/trusty_matter.h", + "repo/matter_client/include/trusty_matter_ipc.h", + "repo/matter_client/matter_messages.cpp", + "repo/matter_client/serializable.cpp", + "repo/matter_client/trusty_matter.cpp", + "repo/matter_client/trusty_matter_ipc.cpp", + ] + + cflags = [ "-Wno-implicit-fallthrough" ] + cflags_cc = [ "-std=c++17" ] + + public_configs = [ ":libtrustymatter_config" ] +} diff --git a/third_party/libtrustymatter/repo b/third_party/libtrustymatter/repo new file mode 160000 index 00000000000000..95f8b30d83da8b --- /dev/null +++ b/third_party/libtrustymatter/repo @@ -0,0 +1 @@ +Subproject commit 95f8b30d83da8bf05f3e6b776919511f58766540 From e6e6c98e09d8cc0b6ec6b43d495c4edf6dbd38c4 Mon Sep 17 00:00:00 2001 From: Ji Luo Date: Wed, 25 Jan 2023 16:06:06 +0800 Subject: [PATCH 2/7] Support device attestation based on Trusty OS read all device attestation credentials from secure storage which is managed by TEE (Trusty OS), all credentials should be provisioned in bootloader stage. Change-Id: I59f144b92c3dfde2ab167d9f0f7f62508ed47354 Signed-off-by: Ji Luo Reviewed-on: http://androidsource.nxp.com/project/21250 Reviewed-by: Elven Wang Reviewed-on: http://androidsource.nxp.com/project/23004 --- examples/platform/linux/AppMain.cpp | 15 ++- examples/platform/linux/BUILD.gn | 18 +++ .../platform/linux/DeviceAttestationCreds.cpp | 113 ++++++++++++++++++ .../platform/linux/DeviceAttestationCreds.h | 46 +++++++ src/lib/trusty.gni | 17 +++ 5 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 examples/platform/linux/DeviceAttestationCreds.cpp create mode 100644 examples/platform/linux/DeviceAttestationCreds.h create mode 100644 src/lib/trusty.gni diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index 52fd41d79dabe8..3963ff5ed99d51 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -126,6 +126,11 @@ #include #endif // CHIP_DEVICE_LAYER_TARGET_LINUX +#if CHIP_ATTESTATION_TRUSTY_OS +#include "DeviceAttestationCreds.h" +using namespace chip::Credentials::Trusty; +#endif + using namespace chip; using namespace chip::ArgParser; using namespace chip::Credentials; @@ -710,7 +715,11 @@ void ChipLinuxAppMainLoop(AppMainLoopImplementation * impl) PrintOnboardingCodes(LinuxDeviceOptions::GetInstance().payload); // Initialize device attestation config +#if CHIP_ATTESTATION_TRUSTY_OS + SetDeviceAttestationCredentialsProvider(&TrustyDACProvider::GetTrustyDACProvider()); +#else SetDeviceAttestationCredentialsProvider(LinuxDeviceOptions::GetInstance().dacProvider); +#endif #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE ChipLogProgress(AppServer, "Starting commissioner"); @@ -737,9 +746,9 @@ void ChipLinuxAppMainLoop(AppMainLoopImplementation * impl) signal(SIGTERM, StopSignalHandler); // NOLINTEND(bugprone-signal-handler) #else - struct sigaction sa = {}; - sa.sa_handler = StopSignalHandler; - sa.sa_flags = SA_RESETHAND; + struct sigaction sa = {}; + sa.sa_handler = StopSignalHandler; + sa.sa_flags = SA_RESETHAND; sigaction(SIGINT, &sa, nullptr); sigaction(SIGTERM, &sa, nullptr); #endif diff --git a/examples/platform/linux/BUILD.gn b/examples/platform/linux/BUILD.gn index a31a72ed834e15..76c9104c13d9f1 100644 --- a/examples/platform/linux/BUILD.gn +++ b/examples/platform/linux/BUILD.gn @@ -18,6 +18,7 @@ import("${chip_root}/src/app/common_flags.gni") import("${chip_root}/src/app/icd/icd.gni") import("${chip_root}/src/lib/core/core.gni") import("${chip_root}/src/lib/lib.gni") +import("${chip_root}/src/lib/trusty.gni") import("${chip_root}/src/tracing/tracing_args.gni") if (current_os != "nuttx") { @@ -96,6 +97,13 @@ source_set("app-main") { "testing/CustomCSRResponseOperationalKeyStore.h", ] + if (chip_with_trusty_os == 1) { + sources += [ + "DeviceAttestationCreds.cpp", + "DeviceAttestationCreds.h", + ] + } + public_deps = [ ":boolean-state-configuration-test-event-trigger", ":commissioner-main", @@ -122,6 +130,16 @@ source_set("app-main") { public_deps += [ jsoncpp_root ] } + if (chip_with_trusty_os == 1) { + public_deps += [ "${chip_root}/third_party/libtrustymatter" ] + } + + if (chip_with_trusty_os == 1) { + defines += [ "CHIP_ATTESTATION_TRUSTY_OS=1" ] + } else { + defines += [ "CHIP_ATTESTATION_TRUSTY_OS=0" ] + } + if (chip_enable_pw_rpc) { defines += [ "PW_RPC_ENABLED" ] } diff --git a/examples/platform/linux/DeviceAttestationCreds.cpp b/examples/platform/linux/DeviceAttestationCreds.cpp new file mode 100644 index 00000000000000..c933136b300017 --- /dev/null +++ b/examples/platform/linux/DeviceAttestationCreds.cpp @@ -0,0 +1,113 @@ +/* + * + * Copyright (c) 2021-2022 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. + * + * Copyright 2023 NXP + */ +#include "DeviceAttestationCreds.h" + +#include +#include +#include +#include + +using namespace matter; + +namespace chip { +namespace Credentials { +namespace Trusty { + +CHIP_ERROR TrustyDACProvider::GetDeviceAttestationCert(MutableByteSpan & out_dac_buffer) +{ + size_t out_size = 0; + int rc; + + rc = trusty_matter.ExportDACCert(out_dac_buffer.data(), out_dac_buffer.size(), out_size); + if (rc == 0) + { + out_dac_buffer.reduce_size(out_size); + return CHIP_NO_ERROR; + } + else + return CHIP_ERROR_CERT_LOAD_FAILED; +} + +CHIP_ERROR TrustyDACProvider::GetProductAttestationIntermediateCert(MutableByteSpan & out_pai_buffer) +{ + size_t out_size = 0; + int rc; + + rc = trusty_matter.ExportPAICert(out_pai_buffer.data(), out_pai_buffer.size(), out_size); + if (rc == 0) + { + out_pai_buffer.reduce_size(out_size); + return CHIP_NO_ERROR; + } + else + return CHIP_ERROR_CERT_LOAD_FAILED; +} + +CHIP_ERROR TrustyDACProvider::GetCertificationDeclaration(MutableByteSpan & out_cd_buffer) +{ + size_t out_size = 0; + int rc; + + rc = trusty_matter.ExportCDCert(out_cd_buffer.data(), out_cd_buffer.size(), out_size); + if (rc == 0) + { + out_cd_buffer.reduce_size(out_size); + return CHIP_NO_ERROR; + } + else + return CHIP_ERROR_CERT_LOAD_FAILED; +} + +CHIP_ERROR TrustyDACProvider::GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) +{ + // TODO: We need a real example FirmwareInformation to be populated. + out_firmware_info_buffer.reduce_size(0); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR TrustyDACProvider::SignWithDeviceAttestationKey(const ByteSpan & message_to_sign, MutableByteSpan & out_signature_buffer) +{ + int rc = 0; + size_t out_size = 0; + + VerifyOrReturnError(IsSpanUsable(out_signature_buffer), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsSpanUsable(message_to_sign), CHIP_ERROR_INVALID_ARGUMENT); + + rc = trusty_matter.SignWithDACKey(message_to_sign.data(), message_to_sign.size(), out_signature_buffer.data(), + out_signature_buffer.size(), out_size); + if (rc == 0) + { + out_signature_buffer.reduce_size(out_size); + return CHIP_NO_ERROR; + } + else + return CHIP_ERROR_CERT_LOAD_FAILED; +} + +TrustyDACProvider & TrustyDACProvider::GetTrustyDACProvider() +{ + static TrustyDACProvider trusty_dac_provider; + + return trusty_dac_provider; +} + +} // namespace Trusty +} // namespace Credentials +} // namespace chip diff --git a/examples/platform/linux/DeviceAttestationCreds.h b/examples/platform/linux/DeviceAttestationCreds.h new file mode 100644 index 00000000000000..733fc5133418ff --- /dev/null +++ b/examples/platform/linux/DeviceAttestationCreds.h @@ -0,0 +1,46 @@ +/* + * Copyright 2023 NXP + * + * Copyright (c) 2021 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. + */ +#pragma once + +#include +#include + +using namespace matter; + +namespace chip { +namespace Credentials { +namespace Trusty { + +class TrustyDACProvider : public DeviceAttestationCredentialsProvider +{ +public: + static TrustyDACProvider & GetTrustyDACProvider(); + + CHIP_ERROR GetCertificationDeclaration(MutableByteSpan & out_cd_buffer) override; + CHIP_ERROR GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) override; + CHIP_ERROR GetDeviceAttestationCert(MutableByteSpan & out_dac_buffer) override; + CHIP_ERROR GetProductAttestationIntermediateCert(MutableByteSpan & out_pai_buffer) override; + CHIP_ERROR SignWithDeviceAttestationKey(const ByteSpan & message_to_sign, MutableByteSpan & out_signature_buffer) override; + +private: + TrustyMatter trusty_matter; +}; + +} // namespace Trusty +} // namespace Credentials +} // namespace chip diff --git a/src/lib/trusty.gni b/src/lib/trusty.gni new file mode 100644 index 00000000000000..f13c9bffe351fd --- /dev/null +++ b/src/lib/trusty.gni @@ -0,0 +1,17 @@ +# Copyright (c) 2023 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. + +declare_args() { + chip_with_trusty_os = 0 +} From afe7e37f21b0d3887994da2fda3780c311d7c3c7 Mon Sep 17 00:00:00 2001 From: Ji Luo Date: Wed, 25 Jan 2023 17:14:02 +0800 Subject: [PATCH 3/7] Support P256KeyPair based on Trusty OS move the p256keypair operations to Trusty OS to enhance the crypto security. Change-Id: I47ec6b440f91adf3e717ed8915f35b7844731c90 Signed-off-by: Ji Luo Reviewed-on: http://androidsource.nxp.com/project/21251 Reviewed-by: Elven Wang Reviewed-on: http://androidsource.nxp.com/project/23005 --- src/crypto/BUILD.gn | 13 +++ src/crypto/CHIPCryptoPAL.h | 5 + src/crypto/CHIPCryptoPALOpenSSL.cpp | 164 ++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) diff --git a/src/crypto/BUILD.gn b/src/crypto/BUILD.gn index 746126873e5b58..b950974f342c15 100644 --- a/src/crypto/BUILD.gn +++ b/src/crypto/BUILD.gn @@ -1,4 +1,5 @@ # Copyright (c) 2020 Project CHIP Authors +# Copyright 2025 NXP # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,6 +21,8 @@ import("${chip_root}/build/chip/buildconfig_header.gni") import("crypto.gni") +import("${chip_root}/src/lib/trusty.gni") + if (chip_crypto == "") { if (current_os == "android" || current_os == "freertos" || current_os == "zephyr" || current_os == "mbed" || current_os == "webos" || @@ -74,6 +77,12 @@ buildconfig_header("crypto_buildconfig") { "CHIP_CRYPTO_BORINGSSL=${chip_crypto_boringssl}", "CHIP_CRYPTO_PLATFORM=${chip_crypto_platform}", ] + + if (chip_with_trusty_os == 1) { + defines += [ "CHIP_CRYPTO_TRUSTY_OS=1" ] + } else { + defines += [ "CHIP_CRYPTO_TRUSTY_OS=0" ] + } } source_set("public_headers") { @@ -92,6 +101,10 @@ source_set("public_headers") { "${chip_root}/src/lib/support", "${nlassert_root}:nlassert", ] + + if (chip_with_trusty_os == 1) { + public_deps += [ "${chip_root}/third_party/libtrustymatter" ] + } } if (chip_crypto == "openssl") { diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index 8d6c8ba6feb21f..9e477df1df2bba 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -1,6 +1,7 @@ /* * * Copyright (c) 2020-2023 Project CHIP Authors + * Copyright 2025 NXP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -588,6 +589,10 @@ class P256Keypair : public P256KeypairBase /** Release resources associated with this key pair */ void Clear(); +#if CHIP_CRYPTO_TRUSTY_OS + uint64_t p256_handler = 0; +#endif + protected: P256PublicKey mPublicKey; mutable P256KeypairContext mKeypair; diff --git a/src/crypto/CHIPCryptoPALOpenSSL.cpp b/src/crypto/CHIPCryptoPALOpenSSL.cpp index 9f2592a12aee0c..6e30c7103af62e 100644 --- a/src/crypto/CHIPCryptoPALOpenSSL.cpp +++ b/src/crypto/CHIPCryptoPALOpenSSL.cpp @@ -1,6 +1,7 @@ /* * * Copyright (c) 2020-2023 Project CHIP Authors + * Copyright 2025 NXP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,9 +56,18 @@ #include +#if CHIP_CRYPTO_TRUSTY_OS +#include +using namespace matter; +#endif + namespace chip { namespace Crypto { +#if CHIP_CRYPTO_TRUSTY_OS +TrustyMatter trusty_matter; +#endif + // BoringSSL is designed to implement the same interface as OpenSSL in most // cases. However, it removes some APIs that can allow very weak configuration. // (Example: CCM ciphers with low tag lengths.) In order to support Matter, @@ -744,6 +754,43 @@ static inline const EC_KEY * to_const_EC_KEY(const P256KeypairContext * context) return *SafePointerCast(context); } +#if CHIP_CRYPTO_TRUSTY_OS +CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_length, P256ECDSASignature & out_signature) const +{ + CHIP_ERROR error = CHIP_NO_ERROR; + size_t sig_size = 0; + int rc = 0; + + VerifyOrReturnError((msg != nullptr) && (msg_length > 0), CHIP_ERROR_INVALID_ARGUMENT); + + uint8_t digest[kSHA256_Hash_Length]; + uint8_t sig[kP256_ECDSA_Signature_Length_Raw]; + memset(&digest[0], 0, sizeof(digest)); + memset(&sig[0], 0, sizeof(sig)); + + ReturnErrorOnFailure(Hash_SHA256(msg, msg_length, &digest[0])); + + ERR_clear_error(); + + static_assert(P256ECDSASignature::Capacity() >= kP256_ECDSA_Signature_Length_Raw, "P256ECDSASignature must be large enough"); + VerifyOrExit(mInitialized, error = CHIP_ERROR_UNINITIALIZED); + + rc = trusty_matter.P256KeypairECSignMsg(p256_handler, digest, kSHA256_Hash_Length, sig, sig_size); + VerifyOrExit(rc == MATTER_ERROR_OK, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(sig_size == kP256_ECDSA_Signature_Length_Raw, error = CHIP_ERROR_INTERNAL); + + VerifyOrExit(out_signature.SetLength(kP256_ECDSA_Signature_Length_Raw) == CHIP_NO_ERROR, error = CHIP_ERROR_INTERNAL); + memcpy(out_signature.Bytes() + 0u, sig, sig_size); + +exit: + if (error != CHIP_NO_ERROR) + { + _logSSLError(); + } + + return error; +} +#else CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_length, P256ECDSASignature & out_signature) const { CHIP_ERROR error = CHIP_NO_ERROR; @@ -799,6 +846,7 @@ CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_len return error; } +#endif CHIP_ERROR P256PublicKey::ECDSA_validate_msg_signature(const uint8_t * msg, const size_t msg_length, const P256ECDSASignature & signature) const @@ -968,6 +1016,25 @@ static CHIP_ERROR _create_evp_key_from_binary_p256_key(const P256PublicKey & key return error; } +#if CHIP_CRYPTO_TRUSTY_OS +CHIP_ERROR P256Keypair::ECDH_derive_secret(const P256PublicKey & remote_public_key, P256ECDHDerivedSecret & out_secret) const +{ + ERR_clear_error(); + CHIP_ERROR error = CHIP_NO_ERROR; + int result = -1; + size_t out_buf_length = 0; + + result = trusty_matter.P256KeypairECDH_derive_secret(p256_handler, Uint8::to_const_uchar(remote_public_key), + remote_public_key.Length(), out_secret.Bytes(), out_buf_length); + VerifyOrExit(result == MATTER_ERROR_OK, error = CHIP_ERROR_INTERNAL); + VerifyOrExit((out_buf_length > 0), error = CHIP_ERROR_INTERNAL); + SuccessOrExit(error = out_secret.SetLength(out_buf_length)); + +exit: + _logSSLError(); + return error; +} +#else CHIP_ERROR P256Keypair::ECDH_derive_secret(const P256PublicKey & remote_public_key, P256ECDHDerivedSecret & out_secret) const { ERR_clear_error(); @@ -1035,6 +1102,7 @@ CHIP_ERROR P256Keypair::ECDH_derive_secret(const P256PublicKey & remote_public_k _logSSLError(); return error; } +#endif void ClearSecretData(uint8_t * buf, size_t len) { @@ -1082,6 +1150,101 @@ static CHIP_ERROR P256PublicKeyFromECKey(EC_KEY * ec_key, P256PublicKey & pubkey return error; } +#if CHIP_CRYPTO_TRUSTY_OS +CHIP_ERROR P256Keypair::Initialize(ECPKeyTarget key_target) +{ + ERR_clear_error(); + CHIP_ERROR error = CHIP_NO_ERROR; + uint8_t public_key[kP256_PublicKey_Length]; + int rc = 0; + + rc = trusty_matter.P256KeypairInitialize(p256_handler, public_key); + VerifyOrExit(rc == MATTER_ERROR_OK, error = CHIP_ERROR_INTERNAL); + + memcpy(Uint8::to_uchar(mPublicKey), public_key, kP256_PublicKey_Length); + + mInitialized = true; + +exit: + _logSSLError(); + return error; +} + +CHIP_ERROR P256Keypair::Serialize(P256SerializedKeypair & output) const +{ + CHIP_ERROR error = CHIP_NO_ERROR; + uint8_t privkey[kP256_PrivateKey_Length]; + int rc = 0; + + rc = trusty_matter.P256KeypairSerialize(p256_handler, privkey); + VerifyOrExit(rc == MATTER_ERROR_OK, error = CHIP_ERROR_INTERNAL); + + { + size_t len = output.Length() == 0 ? output.Capacity() : output.Length(); + Encoding::BufferWriter bbuf(output.Bytes(), len); + bbuf.Put(mPublicKey, mPublicKey.Length()); + bbuf.Put(privkey, sizeof(privkey)); + VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_NO_MEMORY); + output.SetLength(bbuf.Needed()); + } + +exit: + ClearSecretData(privkey, sizeof(privkey)); + _logSSLError(); + return error; +} + +CHIP_ERROR P256Keypair::Deserialize(P256SerializedKeypair & input) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + Encoding::BufferWriter bbuf(mPublicKey, mPublicKey.Length()); + int rc = 0; + + uint8_t * pubkey = input.Bytes(); + uint8_t * privkey = input.Bytes() + mPublicKey.Length(); + + VerifyOrExit(input.Length() == mPublicKey.Length() + kP256_PrivateKey_Length, error = CHIP_ERROR_INVALID_ARGUMENT); + bbuf.Put(input.ConstBytes(), mPublicKey.Length()); + VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_NO_MEMORY); + + rc = trusty_matter.P256KeypairDeserialize(p256_handler, pubkey, mPublicKey.Length(), privkey, kP256_PrivateKey_Length); + VerifyOrExit(rc == MATTER_ERROR_OK, error = CHIP_ERROR_INTERNAL); + + mInitialized = true; + +exit: + _logSSLError(); + return error; +} + +void P256Keypair::Clear() +{ + mInitialized = false; + p256_handler = 0; +} + +P256Keypair::~P256Keypair() +{ + trusty_matter.P256KeypairDestory(p256_handler); + Clear(); +} + +CHIP_ERROR P256Keypair::NewCertificateSigningRequest(uint8_t * out_csr, size_t & csr_length) const +{ + ERR_clear_error(); + CHIP_ERROR error = CHIP_NO_ERROR; + int rc = 0; + + VerifyOrExit(mInitialized, error = CHIP_ERROR_UNINITIALIZED); + + rc = trusty_matter.P256KeypairNewCSR(p256_handler, out_csr, csr_length); + VerifyOrExit(rc == MATTER_ERROR_OK, error = CHIP_ERROR_INTERNAL); + +exit: + _logSSLError(); + return error; +} +#else CHIP_ERROR P256Keypair::Initialize(ECPKeyTarget key_target) { ERR_clear_error(); @@ -1314,6 +1477,7 @@ CHIP_ERROR P256Keypair::NewCertificateSigningRequest(uint8_t * out_csr, size_t & _logSSLError(); return error; } +#endif CHIP_ERROR VerifyCertificateSigningRequest(const uint8_t * csr, size_t csr_length, P256PublicKey & pubkey) { From dcb20ef636b57e5171d38430d76cab4794c9b40e Mon Sep 17 00:00:00 2001 From: Ji Luo Date: Mon, 13 Mar 2023 10:58:24 +0800 Subject: [PATCH 4/7] Support trusty backed operational keystore support trusty backed persistent storage operation keystore. Change-Id: I156c51bc415b1e9fb16e054deccb34415a7acc86 Signed-off-by: Ji Luo Reviewed-on: http://androidsource.nxp.com/project/21252 Reviewed-by: Elven Wang Reviewed-on: http://androidsource.nxp.com/project/23007 --- examples/platform/linux/AppMain.cpp | 10 + examples/platform/linux/BUILD.gn | 8 + ...istentStorageOperationalKeystoreTrusty.cpp | 176 ++++++++++++++++++ ...rsistentStorageOperationalKeystoreTrusty.h | 93 +++++++++ src/crypto/CHIPCryptoPAL.h | 1 + src/crypto/CHIPCryptoPALOpenSSL.cpp | 2 +- third_party/libtrustymatter/repo | 2 +- 7 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 examples/platform/linux/PersistentStorageOperationalKeystoreTrusty.cpp create mode 100644 examples/platform/linux/PersistentStorageOperationalKeystoreTrusty.h diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index 3963ff5ed99d51..b5b03fbe40ec51 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -131,6 +131,11 @@ using namespace chip::Credentials::Trusty; #endif +#if CHIP_OP_KEYSTORE_TRUSTY_OS +#include "PersistentStorageOperationalKeystoreTrusty.h" +using namespace chip::Trusty; +#endif + using namespace chip; using namespace chip::ArgParser; using namespace chip::Credentials; @@ -576,6 +581,11 @@ void ChipLinuxAppMainLoop(AppMainLoopImplementation * impl) } #endif // CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED +#if CHIP_OP_KEYSTORE_TRUSTY_OS + static chip::Trusty::PersistentStorageOperationalKeystoreTrusty sPersistentStorageOperationalKeystore; + initParams.operationalKeystore = &sPersistentStorageOperationalKeystore; +#endif + #if defined(ENABLE_CHIP_SHELL) Engine::Root().Init(); Shell::RegisterCommissioneeCommands(); diff --git a/examples/platform/linux/BUILD.gn b/examples/platform/linux/BUILD.gn index 76c9104c13d9f1..6d6b26006b500e 100644 --- a/examples/platform/linux/BUILD.gn +++ b/examples/platform/linux/BUILD.gn @@ -101,6 +101,8 @@ source_set("app-main") { sources += [ "DeviceAttestationCreds.cpp", "DeviceAttestationCreds.h", + "PersistentStorageOperationalKeystoreTrusty.cpp", + "PersistentStorageOperationalKeystoreTrusty.h", ] } @@ -140,6 +142,12 @@ source_set("app-main") { defines += [ "CHIP_ATTESTATION_TRUSTY_OS=0" ] } + if (chip_with_trusty_os == 1) { + defines += [ "CHIP_OP_KEYSTORE_TRUSTY_OS=1" ] + } else { + defines += [ "CHIP_OP_KEYSTORE_TRUSTY_OS=0" ] + } + if (chip_enable_pw_rpc) { defines += [ "PW_RPC_ENABLED" ] } diff --git a/examples/platform/linux/PersistentStorageOperationalKeystoreTrusty.cpp b/examples/platform/linux/PersistentStorageOperationalKeystoreTrusty.cpp new file mode 100644 index 00000000000000..00f937c17d5349 --- /dev/null +++ b/examples/platform/linux/PersistentStorageOperationalKeystoreTrusty.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * 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. + * + * Copyright 2023 NXP + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PersistentStorageOperationalKeystoreTrusty.h" + +using namespace matter; + +namespace chip { +namespace Trusty { + +using namespace chip::Crypto; + +bool PersistentStorageOperationalKeystoreTrusty::HasOpKeypairForFabric(FabricIndex fabricIndex) const +{ + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), false); + + // If there was a pending keypair, then there's really a usable key + if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex) && (mPendingKeypair != nullptr)) + { + return true; + } + + return trusty_matter.HasOpKeypairForFabric(fabricIndex); +} + +CHIP_ERROR PersistentStorageOperationalKeystoreTrusty::NewOpKeypairForFabric(FabricIndex fabricIndex, + MutableByteSpan & outCertificateSigningRequest) +{ + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + // If a key is pending, we cannot generate for a different fabric index until we commit or revert. + if ((mPendingFabricIndex != kUndefinedFabricIndex) && (fabricIndex != mPendingFabricIndex)) + { + return CHIP_ERROR_INVALID_FABRIC_INDEX; + } + VerifyOrReturnError(outCertificateSigningRequest.size() >= Crypto::kMIN_CSR_Buffer_Size, CHIP_ERROR_BUFFER_TOO_SMALL); + + // Replace previous pending keypair, if any was previously allocated + ResetPendingKey(); + + mPendingKeypair = Platform::New(); + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_NO_MEMORY); + + mPendingKeypair->fabricIndex = fabricIndex; + mPendingKeypair->Initialize(Crypto::ECPKeyTarget::ECDSA); + size_t csrLength = outCertificateSigningRequest.size(); + CHIP_ERROR err = mPendingKeypair->NewCertificateSigningRequest(outCertificateSigningRequest.data(), csrLength); + if (err != CHIP_NO_ERROR) + { + ResetPendingKey(); + return err; + } + + outCertificateSigningRequest.reduce_size(csrLength); + mPendingFabricIndex = fabricIndex; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PersistentStorageOperationalKeystoreTrusty::ActivateOpKeypairForFabric(FabricIndex fabricIndex, + const Crypto::P256PublicKey & nocPublicKey) +{ + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + // Validate public key being activated matches last generated pending keypair + VerifyOrReturnError(mPendingKeypair->Pubkey().Matches(nocPublicKey), CHIP_ERROR_INVALID_PUBLIC_KEY); + + mIsPendingKeypairActive = true; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PersistentStorageOperationalKeystoreTrusty::CommitOpKeypairForFabric(FabricIndex fabricIndex) +{ + int rc = 0; + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + VerifyOrReturnError(mIsPendingKeypairActive == true, CHIP_ERROR_INCORRECT_STATE); + + // Try to store persistent key. On failure, leave everything pending as-is + rc = trusty_matter.CommitOpKeypairForFabric(mPendingKeypair->p256_handler, fabricIndex); + if (rc != MATTER_ERROR_OK) + ReturnErrorOnFailure(CHIP_ERROR_INTERNAL); + + // If we got here, we succeeded and can reset the pending key: next `SignWithOpKeypair` will use the stored key. + ResetPendingKey(); + return CHIP_NO_ERROR; +} + +CHIP_ERROR PersistentStorageOperationalKeystoreTrusty::RemoveOpKeypairForFabric(FabricIndex fabricIndex) +{ + int rc = 0; + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + // Remove pending state if matching + if ((mPendingKeypair != nullptr) && (fabricIndex == mPendingFabricIndex)) + { + RevertPendingKeypair(); + } + + rc = trusty_matter.RemoveOpKeypairForFabric(fabricIndex); + if (rc != MATTER_ERROR_OK) + return CHIP_ERROR_INVALID_FABRIC_INDEX; + + return CHIP_NO_ERROR; +} + +void PersistentStorageOperationalKeystoreTrusty::RevertPendingKeypair() +{ + // Just reset the pending key, it hasn't been stored into secure storage. + ResetPendingKey(); +} + +CHIP_ERROR PersistentStorageOperationalKeystoreTrusty::SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message, + Crypto::P256ECDSASignature & outSignature) const +{ + int rc = 0; + size_t sig_size = 0; + uint8_t sig[kP256_ECDSA_Signature_Length_Raw]; + + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex)) + { + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INTERNAL); + // We have an override key: sign with it! + return mPendingKeypair->ECDSA_sign_msg(message.data(), message.size(), outSignature); + } + + rc = trusty_matter.SignWithStoredOpKey(fabricIndex, message.data(), message.size(), sig, sig_size); + if (rc != MATTER_ERROR_OK) + return CHIP_ERROR_INTERNAL; + + VerifyOrReturnError(sig_size == kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(outSignature.SetLength(sig_size) == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL); + memcpy(outSignature.Bytes(), sig, sig_size); + return CHIP_NO_ERROR; +} + +Crypto::P256Keypair * PersistentStorageOperationalKeystoreTrusty::AllocateEphemeralKeypairForCASE() +{ + return Platform::New(); +} + +void PersistentStorageOperationalKeystoreTrusty::ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair) +{ + Platform::Delete(keypair); +} + +} // namespace Trusty +} // namespace chip diff --git a/examples/platform/linux/PersistentStorageOperationalKeystoreTrusty.h b/examples/platform/linux/PersistentStorageOperationalKeystoreTrusty.h new file mode 100644 index 00000000000000..04ff0f8ba709f0 --- /dev/null +++ b/examples/platform/linux/PersistentStorageOperationalKeystoreTrusty.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * 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. + * + * Copyright 2023 NXP + */ + +#pragma once + +#include +#include +#include +#include + +#include + +using namespace matter; + +namespace chip { +namespace Trusty { + +/** + * @brief OperationalKeystore implementation making use of Trusty secure storage + * to load/store keypairs. + * + */ +class PersistentStorageOperationalKeystoreTrusty : public Crypto::OperationalKeystore +{ +public: + PersistentStorageOperationalKeystoreTrusty() = default; + virtual ~PersistentStorageOperationalKeystoreTrusty() { Finish(); } + + // Non-copyable + PersistentStorageOperationalKeystoreTrusty(PersistentStorageOperationalKeystoreTrusty const &) = delete; + void operator=(PersistentStorageOperationalKeystoreTrusty const &) = delete; + + /** + * @brief Finalize the keystore, so that subsequent operations fail + */ + void Finish() { ResetPendingKey(); } + + bool HasPendingOpKeypair() const override { return (mPendingKeypair != nullptr); } + + bool HasOpKeypairForFabric(FabricIndex fabricIndex) const override; + CHIP_ERROR NewOpKeypairForFabric(FabricIndex fabricIndex, MutableByteSpan & outCertificateSigningRequest) override; + CHIP_ERROR ActivateOpKeypairForFabric(FabricIndex fabricIndex, const Crypto::P256PublicKey & nocPublicKey) override; + CHIP_ERROR CommitOpKeypairForFabric(FabricIndex fabricIndex) override; + CHIP_ERROR RemoveOpKeypairForFabric(FabricIndex fabricIndex) override; + void RevertPendingKeypair() override; + CHIP_ERROR SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message, + Crypto::P256ECDSASignature & outSignature) const override; + Crypto::P256Keypair * AllocateEphemeralKeypairForCASE() override; + void ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair) override; + +protected: + void ResetPendingKey() + { + if (!mIsExternallyOwnedKeypair && (mPendingKeypair != nullptr)) + { + Platform::Delete(mPendingKeypair); + } + mPendingKeypair = nullptr; + mIsExternallyOwnedKeypair = false; + mIsPendingKeypairActive = false; + mPendingFabricIndex = kUndefinedFabricIndex; + } + + FabricIndex mPendingFabricIndex = kUndefinedFabricIndex; + Crypto::P256Keypair * mPendingKeypair = nullptr; + bool mIsPendingKeypairActive = false; + + // If overridding NewOpKeypairForFabric method in a subclass, set this to true in + // `NewOpKeypairForFabric` if the mPendingKeypair should not be deleted when no longer in use. + bool mIsExternallyOwnedKeypair = false; + +private: + mutable TrustyMatter trusty_matter; +}; + +} // namespace Trusty +} // namespace chip diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index 9e477df1df2bba..c69bc12594de8d 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -591,6 +591,7 @@ class P256Keypair : public P256KeypairBase #if CHIP_CRYPTO_TRUSTY_OS uint64_t p256_handler = 0; + uint8_t fabricIndex = 0; #endif protected: diff --git a/src/crypto/CHIPCryptoPALOpenSSL.cpp b/src/crypto/CHIPCryptoPALOpenSSL.cpp index 6e30c7103af62e..6fe04fa9408e8d 100644 --- a/src/crypto/CHIPCryptoPALOpenSSL.cpp +++ b/src/crypto/CHIPCryptoPALOpenSSL.cpp @@ -1158,7 +1158,7 @@ CHIP_ERROR P256Keypair::Initialize(ECPKeyTarget key_target) uint8_t public_key[kP256_PublicKey_Length]; int rc = 0; - rc = trusty_matter.P256KeypairInitialize(p256_handler, public_key); + rc = trusty_matter.P256KeypairInitialize(p256_handler, fabricIndex, public_key); VerifyOrExit(rc == MATTER_ERROR_OK, error = CHIP_ERROR_INTERNAL); memcpy(Uint8::to_uchar(mPublicKey), public_key, kP256_PublicKey_Length); diff --git a/third_party/libtrustymatter/repo b/third_party/libtrustymatter/repo index 95f8b30d83da8b..2be9d3c10c4ba9 160000 --- a/third_party/libtrustymatter/repo +++ b/third_party/libtrustymatter/repo @@ -1 +1 @@ -Subproject commit 95f8b30d83da8bf05f3e6b776919511f58766540 +Subproject commit 2be9d3c10c4ba947d09e300ca03d0cb69df65143 From 83272266777b7855f513bd9af3f5b81d37dce1d2 Mon Sep 17 00:00:00 2001 From: "Haoran.Wang" Date: Fri, 28 Apr 2023 15:13:07 +0800 Subject: [PATCH 5/7] Refine imxlinux_example.sh build script Now the build script are refined to use parameter for different option: Usage:./scripts/examples/imxlinux_example.sh -s|--src -o|--out [-d|--debug] [-n|--no-init] [-t|--trusty] -s, --src Source folder -o, --out Output folder -d, --debug Debug build (optional) -n, --no-init No init mode (optional) -t, --trusty Build with Trusty OS backed security enhancement (optional) example: ./scripts/examples/imxlinux_example.sh -s examples/chip-tool -o out -dnt #will build examples/chip-tool to out/ folder with debug build and skip init and use Trusty OS. Change-Id: I3ac3b60395255b3bfe45fdf21184ba0b6c7ba265 Signed-off-by: Haoran.Wang Reviewed-on: http://androidsource.nxp.com/project/21564 Reviewed-by: Faqiang Zhu Reviewed-on: http://androidsource.nxp.com/project/23009 --- scripts/examples/imxlinux_example.sh | 75 +++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/scripts/examples/imxlinux_example.sh b/scripts/examples/imxlinux_example.sh index 36ad7923d8c706..af78789ba0287c 100755 --- a/scripts/examples/imxlinux_example.sh +++ b/scripts/examples/imxlinux_example.sh @@ -1,7 +1,7 @@ -#!/usr/bin/env bash - +#!/bin/bash # # Copyright (c) 2022 Project CHIP Authors +# Copyright 2023, 2025 NXP # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,11 +18,66 @@ set -e set -x -if [ "$#" != 2 && "$#" != 3 ]; then - exit -1 +helpFunction() { + cat < -o|--out [-d|--debug] [-n|--no-init] [-t|--trusty] + -s, --src Source folder + -o, --out Output folder + -d, --debug Debug build (optional) + -n, --no-init No init mode (optional) + -t, --trusty Build with Trusty OS backed security enhancement (optional) +EOF + exit 1 +} + +trusty=0 +release_build=true +PARSED_OPTIONS="$(getopt -o s:o:tdn --long src:,out:,trusty,debug,no-init -- "$@")" +if [ $? -ne 0 ]; then + helpFunction fi +eval set -- "$PARSED_OPTIONS" +while true; do + case "$1" in + -s | --src) + src="$2" + shift 2 + ;; + -o | --out) + out="$2" + shift 2 + ;; + -t | --trusty) + trusty=1 + shift + ;; + -d | --debug) + release_build=false + shift + ;; + -n | --no-init) + no_init=1 + shift + ;; + --) + shift + break + ;; + *) + echo "Invalid option: $1" >&2 + exit 1 + ;; + esac +done -source "$(dirname "$0")/../../scripts/activate.sh" +if [ -z "$src" ] || [ -z "$out" ]; then + echo "Some or all of the required -s|--src and -o|--out parameters are empty." + helpFunction +fi + +if [ "$no_init" != 1 ]; then + source "$(dirname "$0")/../../scripts/activate.sh" +fi if [ "$IMX_SDK_ROOT" = "" -o ! -d "$IMX_SDK_ROOT" ]; then echo "the Yocto SDK path is not specified with the shell env IMX_SDK_ROOT or an invalid path is specified" @@ -100,13 +155,9 @@ if [ -z "$target_cpu" -o -z "$cross_compile" ]; then exit 1 fi -release_build=true -if [ "$3" = "debug" ]; then - release_build=false -fi - PLATFORM_CFLAGS='-DCHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME=\"mlan0\"", "-DCHIP_DEVICE_CONFIG_LINUX_DHCPC_CMD=\"udhcpc -b -i %s \"' -gn gen --check --fail-on-unused-args --root="$1" "$2" --args="target_os=\"linux\" target_cpu=\"$target_cpu\" arm_arch=\"$arm_arch\" +gn gen --check --fail-on-unused-args --root="$src" "$out" --args="target_os=\"linux\" target_cpu=\"$target_cpu\" arm_arch=\"$arm_arch\" +chip_with_trusty_os=$trusty treat_warnings_as_errors=false import(\"//build_overrides/build.gni\") sysroot=\"$sdk_target_sysroot\" @@ -117,4 +168,4 @@ target_cxx=\"$IMX_SDK_ROOT/sysroots/x86_64-pokysdk-linux/usr/bin/$cross_compile/ target_ar=\"$IMX_SDK_ROOT/sysroots/x86_64-pokysdk-linux/usr/bin/$cross_compile/$cross_compile-ar\" $(if [ "$release_build" = "true" ]; then echo "is_debug=false"; else echo "optimize_debug=true"; fi)" -ninja -C "$2" +ninja -C "$out" From e385c0f6f3bea12645c84b7edd88b25576b1576d Mon Sep 17 00:00:00 2001 From: Ji Luo Date: Thu, 3 Aug 2023 14:14:45 +0800 Subject: [PATCH 6/7] Support ele backed operational keystore Support the ELE (EdgeLock Enclave) backed persistent storage operation keystore. It's availble for i.MX 93 only. Change-Id: Id9e624040c57f80d9cc84511cf9a28c01084a60d Signed-off-by: Ji Luo Reviewed-on: http://androidsource.nxp.com/project/22450 Reviewed-by: Elven Wang Reviewed-on: http://androidsource.nxp.com/project/23010 --- .gitmodules | 4 + examples/platform/linux/AppMain.cpp | 10 + examples/platform/linux/BUILD.gn | 19 + ...ersistentStorageOperationalKeystoreEle.cpp | 638 ++++++++++++++++++ .../PersistentStorageOperationalKeystoreEle.h | 81 +++ scripts/examples/imxlinux_example.sh | 21 +- src/crypto/BUILD.gn | 1 + src/lib/imx_ele.gni | 17 + third_party/imx-secure-enclave/BUILD.gn | 184 +++++ third_party/imx-secure-enclave/repo | 1 + 10 files changed, 974 insertions(+), 2 deletions(-) create mode 100644 examples/platform/linux/PersistentStorageOperationalKeystoreEle.cpp create mode 100644 examples/platform/linux/PersistentStorageOperationalKeystoreEle.h mode change 100755 => 100644 scripts/examples/imxlinux_example.sh create mode 100644 src/lib/imx_ele.gni create mode 100644 third_party/imx-secure-enclave/BUILD.gn create mode 160000 third_party/imx-secure-enclave/repo diff --git a/.gitmodules b/.gitmodules index a3b101a40b6380..9f69906a4909aa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -357,3 +357,7 @@ [submodule "third_party/libtrustymatter/repo"] path = third_party/libtrustymatter/repo url = https://github.com/nxp-imx/libtrustymatter +[submodule "repo"] + path = third_party/imx-secure-enclave/repo + url = https://github.com/nxp-imx/imx-secure-enclave.git + branch = lf-6.12.3_1.0.0 diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index b5b03fbe40ec51..6ed837f738b593 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -136,6 +136,11 @@ using namespace chip::Credentials::Trusty; using namespace chip::Trusty; #endif +#if CHIP_OP_KEYSTORE_ELE +#include "PersistentStorageOperationalKeystoreEle.h" +using namespace chip::ele; +#endif + using namespace chip; using namespace chip::ArgParser; using namespace chip::Credentials; @@ -586,6 +591,11 @@ void ChipLinuxAppMainLoop(AppMainLoopImplementation * impl) initParams.operationalKeystore = &sPersistentStorageOperationalKeystore; #endif +#if CHIP_OP_KEYSTORE_ELE + static chip::ele::PersistentStorageOperationalKeystoreEle sPersistentStorageOperationalKeystore; + initParams.operationalKeystore = &sPersistentStorageOperationalKeystore; +#endif + #if defined(ENABLE_CHIP_SHELL) Engine::Root().Init(); Shell::RegisterCommissioneeCommands(); diff --git a/examples/platform/linux/BUILD.gn b/examples/platform/linux/BUILD.gn index 6d6b26006b500e..e3f6de29bb84c3 100644 --- a/examples/platform/linux/BUILD.gn +++ b/examples/platform/linux/BUILD.gn @@ -17,6 +17,7 @@ import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") import("${chip_root}/src/app/common_flags.gni") import("${chip_root}/src/app/icd/icd.gni") import("${chip_root}/src/lib/core/core.gni") +import("${chip_root}/src/lib/imx_ele.gni") import("${chip_root}/src/lib/lib.gni") import("${chip_root}/src/lib/trusty.gni") import("${chip_root}/src/tracing/tracing_args.gni") @@ -106,6 +107,13 @@ source_set("app-main") { ] } + if (chip_with_imx_ele == 1) { + sources += [ + "PersistentStorageOperationalKeystoreEle.cpp", + "PersistentStorageOperationalKeystoreEle.h", + ] + } + public_deps = [ ":boolean-state-configuration-test-event-trigger", ":commissioner-main", @@ -136,6 +144,11 @@ source_set("app-main") { public_deps += [ "${chip_root}/third_party/libtrustymatter" ] } + if (chip_with_imx_ele == 1) { + public_deps += + [ "${chip_root}/third_party/imx-secure-enclave:libelematter" ] + } + if (chip_with_trusty_os == 1) { defines += [ "CHIP_ATTESTATION_TRUSTY_OS=1" ] } else { @@ -148,6 +161,12 @@ source_set("app-main") { defines += [ "CHIP_OP_KEYSTORE_TRUSTY_OS=0" ] } + if (chip_with_imx_ele == 1) { + defines += [ "CHIP_OP_KEYSTORE_ELE=1" ] + } else { + defines += [ "CHIP_OP_KEYSTORE_ELE=0" ] + } + if (chip_enable_pw_rpc) { defines += [ "PW_RPC_ENABLED" ] } diff --git a/examples/platform/linux/PersistentStorageOperationalKeystoreEle.cpp b/examples/platform/linux/PersistentStorageOperationalKeystoreEle.cpp new file mode 100644 index 00000000000000..d556288dc7d63e --- /dev/null +++ b/examples/platform/linux/PersistentStorageOperationalKeystoreEle.cpp @@ -0,0 +1,638 @@ +/* + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * 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. + * + * Copyright 2023 NXP + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PersistentStorageOperationalKeystoreEle.h" + +const uint8_t kTlvHeader = 2; + +#define KEY_STORE_ID (0xAAAA) +#define AUTHEN_NONCE (0x1111) +#define KEY_GROUP (1) +#define PUBKEY_SIZE (65) +#define KEY_GROUP_SYNC (0x1U << 7) + +/* Used for CSR generation */ +// Organisation info. +#define SUBJECT_STR "CSR" +#define ASN1_BIT_STRING 0x03 +#define ASN1_NULL 0x05 +#define ASN1_OID 0x06 +#define ASN1_SEQUENCE 0x10 +#define ASN1_SET 0x11 +#define ASN1_UTF8_STRING 0x0C +#define ASN1_CONSTRUCTED 0x20 +#define ASN1_CONTEXT_SPECIFIC 0x80 + +namespace chip { +namespace ele { + +using namespace chip::Crypto; + +PersistentStorageOperationalKeystoreEle::PersistentStorageOperationalKeystoreEle() +{ + hsm_err_t err; + + // open the session + open_session_args_t open_session_args = { 0 }; + open_session_args.mu_type = HSM1; + err = hsm_open_session(&open_session_args, &hsm_session_hdl); + if (err != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "ELE session open failed. ret: 0x%x\n", err); + return; + } + else + { + ChipLogDetail(Crypto, "ELE session open successfully.\n"); + } + + // open the keystore + open_svc_key_store_args_t open_svc_key_store_args = { 0 }; + open_svc_key_store_args.key_store_identifier = KEY_STORE_ID; + open_svc_key_store_args.authentication_nonce = AUTHEN_NONCE; + // try to create a new keystore, if it already exist, open it + open_svc_key_store_args.flags = 1; + err = hsm_open_key_store_service(hsm_session_hdl, &open_svc_key_store_args, &key_store_hdl); + if (err == HSM_KEY_STORE_CONFLICT) + { + ChipLogDetail(Crypto, "keystore already existed, open it...\n"); + open_svc_key_store_args.flags = 0; + err = hsm_open_key_store_service(hsm_session_hdl, &open_svc_key_store_args, &key_store_hdl); + if (err != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "keystore open failed. ret:0x%x\n", err); + return; + } + else + ChipLogDetail(Crypto, "keystore open successfully.\n"); + } + else + { + ChipLogDetail(Crypto, "keystore created successfully.\n"); + } + + // open key managerment service + open_svc_key_management_args_t key_mgmt_args = { 0 }; + memset(&key_mgmt_args, 0, sizeof(key_mgmt_args)); + err = hsm_open_key_management_service(key_store_hdl, &key_mgmt_args, &key_mgmt_hdl); + if (err != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "key management service open failed. ret:0x%x\n", err); + return; + } + else + ChipLogDetail(Crypto, "key management service open successfully.\n"); +} + +PersistentStorageOperationalKeystoreEle::~PersistentStorageOperationalKeystoreEle() +{ + hsm_err_t err; + + ResetPendingKey(true); + + ChipLogDetail(Crypto, "close all ELE services.\n"); + + err = hsm_close_key_management_service(key_mgmt_hdl); + key_mgmt_hdl = 0; + ChipLogDetail(Crypto, "close key management service returns:0x%x\n", err); + + err = hsm_close_key_store_service(key_store_hdl); + key_store_hdl = 0; + ChipLogDetail(Crypto, "close key store service returns:0x%x\n", err); + + err = hsm_close_session(hsm_session_hdl); + hsm_session_hdl = 0; + ChipLogDetail(Crypto, "close ELE session returns:0x%x\n", err); +} + +void PersistentStorageOperationalKeystoreEle::ResetPendingKey(bool delete_key) +{ + if ((mPendingFabricIndex != kUndefinedFabricIndex) && (delete_key)) + { + EleDeleteKey(mPendingFabricIndex); + } + mIsExternallyOwnedKeypair = false; + mIsPendingKeypairActive = false; + mPendingFabricIndex = kUndefinedFabricIndex; +} + +hsm_err_t PersistentStorageOperationalKeystoreEle::EleDeleteKey(uint32_t keyId) +{ + hsm_err_t err; + op_delete_key_args_t del_args; + + memset(&del_args, 0, sizeof(del_args)); + del_args.key_identifier = keyId; + del_args.flags = 0; + + err = hsm_delete_key(key_mgmt_hdl, &del_args); + if (err != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "Delete key %d failed. ret:0x%x\n", keyId, err); + } + else + { + ChipLogDetail(Crypto, "Delete key %d successfully.\n", keyId); + } + + return err; +} + +hsm_err_t PersistentStorageOperationalKeystoreEle::EleSignMessage(uint32_t keyId, const uint8_t * msg, size_t msgSize, + uint8_t * sig, size_t sigSize) const +{ + open_svc_sign_gen_args_t open_sig_gen_args; + op_generate_sign_args_t sig_gen_args; + hsm_hdl_t sig_gen_hdl; + hsm_err_t hsmret; + + if ((msg == nullptr) || (sig == nullptr) || (sigSize == 0)) + { + ChipLogDetail(Crypto, "Invalid parameters for generating signature.\n"); + return HSM_INVALID_PARAM; + } + + // open signature generation service + memset(&open_sig_gen_args, 0, sizeof(open_sig_gen_args)); + hsmret = hsm_open_signature_generation_service(key_store_hdl, &open_sig_gen_args, &sig_gen_hdl); + if (hsmret != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "open signature generation service failed. ret:0x%x\n", hsmret); + return hsmret; + } + + // generate signature + memset(&sig_gen_args, 0, sizeof(sig_gen_args)); + sig_gen_args.key_identifier = keyId; + sig_gen_args.scheme_id = HSM_SIGNATURE_SCHEME_ECDSA_SHA256; + sig_gen_args.message = (uint8_t *) msg; + sig_gen_args.signature = sig; + sig_gen_args.message_size = msgSize; + sig_gen_args.signature_size = sigSize; + sig_gen_args.flags = HSM_OP_GENERATE_SIGN_FLAGS_INPUT_MESSAGE; + hsmret = hsm_generate_signature(sig_gen_hdl, &sig_gen_args); + if (hsmret != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "generate signature failed. ret:0x%x\n", hsmret); + return hsmret; + } + + // close signature generation service + hsmret = hsm_close_signature_generation_service(sig_gen_hdl); + if (hsmret != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "close signature generation service failed. ret:0x%x\n", hsmret); + } + + return hsmret; +} + +static void add_tlv(uint8_t * buf, size_t buf_index, uint8_t tag, size_t len, uint8_t * val) +{ + buf[buf_index++] = (uint8_t) tag; + buf[buf_index++] = (uint8_t) len; + if (len > 0 && val != NULL) + { + memcpy(&buf[buf_index], val, len); + buf_index = buf_index + len; + } +} + +/* + * CSR format used in the below function, + * + * + * (ASN1_CONSTRUCTED | ASN1_SEQUENCE) LENGTH + * + * (ASN1_CONSTRUCTED | ASN1_SEQUENCE) LENGTH + * + * VERSION ::= INTEGER { v1(0), v2(1), v3(2) } + * + * (ASN1_CONSTRUCTED | ASN1_SEQUENCE) LENGTH + * + * (ASN1_CONSTRUCTED | ASN1_SET) LENGTH + * + * (ASN1_CONSTRUCTED | ASN1_SEQUENCE) LENGTH + * + * (ASN1_OID) LENGTH VALUE(Organisation OID) + * + * (ASN1_UTF8_STRING) LENGTH VALUE(Subject Str == "CSR") + * + * PUBLIC KEY {WITH HEADER. 91 Bytes} + * + * (ASN1_CONSTRUCTED | ASN1_SEQUENCE) LENGTH + * + * (ASN1_OID) LENGTH VALUE(ECDSA SHA256 OID) + * + * (ASN1_NULL) 0x00 + * + * (ASN1_BIT_STRING) LENGTH VALUE(SIGNATURE) + * + */ +CHIP_ERROR PersistentStorageOperationalKeystoreEle::EleGenerateCSR(uint32_t keyId, uint8_t * csr, size_t & csrLength) +{ + CHIP_ERROR error = CHIP_ERROR_INTERNAL; + hsm_err_t hsmret = HSM_NO_ERROR; + + uint8_t data_to_hash[128] = { 0 }; + size_t data_to_hash_len = sizeof(data_to_hash); + uint8_t pubKey[128] = { 0 }; + size_t pubKeyLen = 0; + uint8_t signature[128] = { 0 }; + size_t signature_len = 0x44; + int signature_index = 0; + uint8_t signature_data[64]; + size_t csrIndex = 0; + size_t buffer_index = data_to_hash_len; + + uint8_t organisation_oid[3] = { 0x55, 0x04, 0x0a }; + // Version ::= INTEGER { v1(0), v2(1), v3(2) } + uint8_t version[3] = { 0x02, 0x01, 0x00 }; + uint8_t signature_oid[8] = { 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02 }; + uint8_t nist256_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 }; + uint8_t signature_header_t1[] = { 0x02, 0x20 }; + uint8_t signature_header_t2[] = { 0x02, 0x21, 0x00 }; + + // No extensions are copied + buffer_index -= kTlvHeader; + add_tlv(data_to_hash, buffer_index, (ASN1_CONSTRUCTED | ASN1_CONTEXT_SPECIFIC), 0, NULL); + + // Copy public key (with header) + { + // copy header first + memcpy(pubKey, nist256_header, sizeof(nist256_header)); + pubKeyLen = pubKeyLen + sizeof(nist256_header); + + // public key size is 65 + pubKey[pubKeyLen] = 0x04; + pubKeyLen++; + + op_pub_key_recovery_args_t args = { 0 }; + args.key_identifier = keyId; + args.out_key_size = 64; + args.out_key = (pubKey + pubKeyLen); + hsmret = hsm_pub_key_recovery(key_store_hdl, &args); + VerifyOrExit(hsmret == HSM_NO_ERROR, error = CHIP_ERROR_HSM); + pubKeyLen += 64; + } + + buffer_index -= pubKeyLen; + VerifyOrExit(buffer_index > 0, error = CHIP_ERROR_INTERNAL); + memcpy((void *) &data_to_hash[buffer_index], pubKey, pubKeyLen); + + // Copy subject (in the current implementation only organisation name info is added) and organisation OID + buffer_index -= (kTlvHeader + sizeof(SUBJECT_STR) - 1); + VerifyOrExit(buffer_index > 0, error = CHIP_ERROR_INTERNAL); + add_tlv(data_to_hash, buffer_index, ASN1_UTF8_STRING, sizeof(SUBJECT_STR) - 1, (uint8_t *) SUBJECT_STR); + + buffer_index -= (kTlvHeader + sizeof(organisation_oid)); + VerifyOrExit(buffer_index > 0, error = CHIP_ERROR_INTERNAL); + add_tlv(data_to_hash, buffer_index, ASN1_OID, sizeof(organisation_oid), organisation_oid); + + // Add length + buffer_index -= kTlvHeader; + // Subject TLV ==> 1 + 1 + len(subject) + // Org OID TLV ==> 1 + 1 + len(organisation_oid) + VerifyOrExit(buffer_index > 0, error = CHIP_ERROR_INTERNAL); + add_tlv(data_to_hash, buffer_index, (ASN1_CONSTRUCTED | ASN1_SEQUENCE), + ((2 * kTlvHeader) + (sizeof(SUBJECT_STR) - 1) + sizeof(organisation_oid)), NULL); + + buffer_index -= kTlvHeader; + VerifyOrExit(buffer_index > 0, error = CHIP_ERROR_INTERNAL); + add_tlv(data_to_hash, buffer_index, (ASN1_CONSTRUCTED | ASN1_SET), + ((3 * kTlvHeader) + (sizeof(SUBJECT_STR) - 1) + sizeof(organisation_oid)), NULL); + + buffer_index -= kTlvHeader; + VerifyOrExit(buffer_index > 0, error = CHIP_ERROR_INTERNAL); + add_tlv(data_to_hash, buffer_index, (ASN1_CONSTRUCTED | ASN1_SEQUENCE), + ((4 * kTlvHeader) + (sizeof(SUBJECT_STR) - 1) + sizeof(organisation_oid)), NULL); + + buffer_index -= 3; + VerifyOrExit(buffer_index > 0, error = CHIP_ERROR_INTERNAL); + memcpy((void *) &data_to_hash[buffer_index], version, sizeof(version)); + + buffer_index -= kTlvHeader; + VerifyOrExit(buffer_index > 0, error = CHIP_ERROR_INTERNAL); + add_tlv(data_to_hash, buffer_index, (ASN1_CONSTRUCTED | ASN1_SEQUENCE), (data_to_hash_len - buffer_index - kTlvHeader), NULL); + + // TLV data is created by copying from backwards. move it to start of buffer. + data_to_hash_len = (data_to_hash_len - buffer_index); + memmove(data_to_hash, (data_to_hash + buffer_index), data_to_hash_len); + + hsmret = EleSignMessage(keyId, (uint8_t *) data_to_hash, data_to_hash_len, signature_data, sizeof(signature_data)); + VerifyOrExit(hsmret == HSM_NO_ERROR, error = CHIP_ERROR_HSM); + + if (signature_data[0] > 0x7F) + { + signature_len += 1; + memcpy(signature, signature_header_t2, sizeof(signature_header_t2)); + signature_index += 3; + } + else + { + memcpy(signature, signature_header_t1, sizeof(signature_header_t1)); + signature_index += 2; + } + memcpy(&signature[signature_index], signature_data, 32); + signature_index += 32; + if (signature_data[32] > 0x7F) + { + signature_len += 1; + memcpy(&signature[signature_index], signature_header_t2, 3); + signature_index += 3; + } + else + { + memcpy(&signature[signature_index], signature_header_t1, 2); + signature_index += 2; + } + memcpy(&signature[signature_index], &signature_data[32], 32); + + VerifyOrExit((csrIndex + 3) <= csrLength, error = CHIP_ERROR_INTERNAL); + csr[csrIndex++] = (ASN1_CONSTRUCTED | ASN1_SEQUENCE); + if ((data_to_hash_len + 14 + kTlvHeader + signature_len) >= 0x80) + csr[csrIndex++] = 0x81; + csr[csrIndex++] = (uint8_t) (data_to_hash_len + sizeof(signature_oid) + (kTlvHeader * 2) + 5 + signature_len); + + VerifyOrExit((csrIndex + data_to_hash_len) <= csrLength, error = CHIP_ERROR_INTERNAL); + memcpy((csr + csrIndex), data_to_hash, data_to_hash_len); + csrIndex = csrIndex + data_to_hash_len; + + // ECDSA SHA256 Signature OID TLV ==> 1 + 1 + len(signature_oid) (8) + // ASN_NULL ==> 1 + 1 + VerifyOrExit((csrIndex + kTlvHeader) <= csrLength, error = CHIP_ERROR_INTERNAL); + add_tlv(csr, csrIndex, (ASN1_CONSTRUCTED | ASN1_SEQUENCE), 0x0A, NULL); + csrIndex = csrIndex + kTlvHeader; + + VerifyOrExit((csrIndex + sizeof(signature_oid) + kTlvHeader) <= csrLength, error = CHIP_ERROR_INTERNAL); + add_tlv(csr, csrIndex, ASN1_OID, sizeof(signature_oid), signature_oid); + csrIndex = csrIndex + kTlvHeader + sizeof(signature_oid); + + // VerifyOrExit((csrIndex + kTlvHeader) <= csrLength, error = CHIP_ERROR_INTERNAL); + // add_tlv(csr, csrIndex, ASN1_NULL, 0x00, NULL); + // csrIndex = csrIndex + kTlvHeader; + + VerifyOrExit((csrIndex + 5) <= csrLength, error = CHIP_ERROR_INTERNAL); + csr[csrIndex++] = ASN1_BIT_STRING; + csr[csrIndex++] = signature_len + 3; + csr[csrIndex++] = 0x00; + csr[csrIndex++] = (ASN1_CONSTRUCTED | ASN1_SEQUENCE); + csr[csrIndex++] = signature_len; + + VerifyOrExit((csrIndex + signature_len) <= csrLength, error = CHIP_ERROR_INTERNAL); + memcpy(&csr[csrIndex], signature, signature_len); + csrLength = (csrIndex + signature_len); + + error = CHIP_NO_ERROR; + +exit: + return error; +} + +bool PersistentStorageOperationalKeystoreEle::HasOpKeypairForFabric(FabricIndex fabricIndex) const +{ + op_get_key_attr_args_t keyattr_args; + hsm_err_t err; + + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), false); + // If there was a pending keypair, then there's really a usable key + if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex)) + { + return true; + } + + // get the key attributes, it shall fail if no such key + memset(&keyattr_args, 0, sizeof(keyattr_args)); + keyattr_args.key_identifier = fabricIndex; + err = hsm_get_key_attr(key_mgmt_hdl, &keyattr_args); + if (err != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "No keypair for fabric: %d found. ELE returns: 0x%x\n", fabricIndex, err); + return false; + } + else + { + ChipLogDetail(Crypto, "Found keypair for fabric: %d.\n", fabricIndex); + return true; + } +} + +CHIP_ERROR PersistentStorageOperationalKeystoreEle::NewOpKeypairForFabric(FabricIndex fabricIndex, + MutableByteSpan & outCertificateSigningRequest) +{ + op_generate_key_args_t key_gen_args; + op_get_key_attr_args_t keyattr_args; + uint32_t keyId; + hsm_err_t hsm_err; + CHIP_ERROR err; + + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + // If a key is pending, we cannot generate for a different fabric index until we commit or revert. + if ((mPendingFabricIndex != kUndefinedFabricIndex) && (fabricIndex != mPendingFabricIndex)) + { + return CHIP_ERROR_INVALID_FABRIC_INDEX; + } + VerifyOrReturnError(outCertificateSigningRequest.size() >= Crypto::kMIN_CSR_Buffer_Size, CHIP_ERROR_BUFFER_TOO_SMALL); + + // Replace previous pending keypair + ResetPendingKey(true); + + // Delete the key if alrady existed + memset(&keyattr_args, 0, sizeof(keyattr_args)); + keyattr_args.key_identifier = fabricIndex; + hsm_err = hsm_get_key_attr(key_mgmt_hdl, &keyattr_args); + if (hsm_err == HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "Keypair for fabric: %d exists, delete it...\n", fabricIndex); + EleDeleteKey(fabricIndex); + } + + // Generate new key + memset(&key_gen_args, 0, sizeof(key_gen_args)); + keyId = fabricIndex; + key_gen_args.key_identifier = &keyId; + key_gen_args.key_group = KEY_GROUP; + key_gen_args.key_lifetime = HSM_SE_KEY_STORAGE_PERSISTENT; + key_gen_args.key_usage = + HSM_KEY_USAGE_SIGN_HASH | HSM_KEY_USAGE_VERIFY_HASH | HSM_KEY_USAGE_SIGN_MSG | HSM_KEY_USAGE_VERIFY_MSG; + key_gen_args.permitted_algo = PERMITTED_ALGO_ECDSA_SHA256; + // "sync" flag is not set so the key won't be committed to NVM immediately. + // we will commit the key in the CommitOpKeypairForFabric(). + key_gen_args.flags = 0; + key_gen_args.key_type = HSM_KEY_TYPE_ECC_NIST; + key_gen_args.bit_key_sz = HSM_KEY_SIZE_ECC_NIST_256; + key_gen_args.key_lifecycle = (hsm_key_lifecycle_t) 0; + hsm_err = hsm_generate_key(key_mgmt_hdl, &key_gen_args); + ChipLogDetail(Crypto, "Generate new keypair returns: 0x%x\n", hsm_err); + if (hsm_err != HSM_NO_ERROR) + return CHIP_ERROR_HSM; + + // generate the CSR + size_t csrLength = outCertificateSigningRequest.size(); + err = EleGenerateCSR(keyId, outCertificateSigningRequest.data(), csrLength); + if (err != CHIP_NO_ERROR) + { + ResetPendingKey(true); + return err; + } + + outCertificateSigningRequest.reduce_size(csrLength); + mPendingFabricIndex = fabricIndex; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PersistentStorageOperationalKeystoreEle::ActivateOpKeypairForFabric(FabricIndex fabricIndex, + const Crypto::P256PublicKey & nocPublicKey) +{ + uint8_t pubkey[PUBKEY_SIZE]; + hsm_err_t hsmret = HSM_NO_ERROR; + + VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + // Validate public key being activated matches last generated pending keypair + // public key size is 65 + pubkey[0] = 0x04; + + op_pub_key_recovery_args_t args = { 0 }; + args.key_identifier = fabricIndex; + args.out_key_size = 64; + args.out_key = &pubkey[1]; + hsmret = hsm_pub_key_recovery(key_store_hdl, &args); + if (hsmret != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "recover public key failed. ret:0x%x\n", hsmret); + return CHIP_ERROR_HSM; + } + + if (memcmp(pubkey, nocPublicKey.ConstBytes(), sizeof(pubkey))) + { + ChipLogDetail(Crypto, "the public key being activated doesn't match pending key.\n"); + return CHIP_ERROR_INVALID_PUBLIC_KEY; + } + + mIsPendingKeypairActive = true; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PersistentStorageOperationalKeystoreEle::CommitOpKeypairForFabric(FabricIndex fabricIndex) +{ + hsm_err_t hsmret = HSM_NO_ERROR; + VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + VerifyOrReturnError(mIsPendingKeypairActive == true, CHIP_ERROR_INCORRECT_STATE); + + // Try to store persistent key. On failure, leave everything pending as-is + op_manage_key_group_args_t keygroup_args; + memset(&keygroup_args, 0, sizeof(keygroup_args)); + keygroup_args.key_group = KEY_GROUP; + keygroup_args.flags = KEY_GROUP_SYNC; + hsmret = hsm_manage_key_group(key_mgmt_hdl, &keygroup_args); + if (hsmret != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "commit key failed. ret: 0x%x\n", hsmret); + ReturnErrorOnFailure(CHIP_ERROR_INTERNAL); + } + else + { + ChipLogDetail(Crypto, "commit key successfully.\n"); + } + + // If we got here, we succeeded and can reset the pending key: next `SignWithOpKeypair` will use the stored key. + ResetPendingKey(false); + return CHIP_NO_ERROR; +} + +CHIP_ERROR PersistentStorageOperationalKeystoreEle::RemoveOpKeypairForFabric(FabricIndex fabricIndex) +{ + hsm_err_t hsmret = HSM_NO_ERROR; + op_get_key_attr_args_t keyattr_args; + + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + // Remove pending state if matching + if ((fabricIndex == mPendingFabricIndex)) + { + ResetPendingKey(true); + return CHIP_NO_ERROR; + } + + // get the key attributes, it shall fail if no such key. + memset(&keyattr_args, 0, sizeof(keyattr_args)); + keyattr_args.key_identifier = fabricIndex; + hsmret = hsm_get_key_attr(key_mgmt_hdl, &keyattr_args); + if (hsmret != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "No keypair for fabric: %d found. No need to delete\n", fabricIndex); + return CHIP_NO_ERROR; + } + else + { + hsmret = EleDeleteKey(fabricIndex); + if (hsmret != HSM_NO_ERROR) + return CHIP_ERROR_HSM; + } + + return CHIP_NO_ERROR; +} + +void PersistentStorageOperationalKeystoreEle::RevertPendingKeypair() +{ + // Just reset the pending key, it hasn't been stored into secure storage. + ResetPendingKey(true); +} + +CHIP_ERROR PersistentStorageOperationalKeystoreEle::SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message, + Crypto::P256ECDSASignature & outSignature) const +{ + uint8_t sig[kP256_ECDSA_Signature_Length_Raw]; + hsm_err_t hsmret = HSM_NO_ERROR; + + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + hsmret = EleSignMessage(fabricIndex, message.data(), message.size(), sig, kP256_ECDSA_Signature_Length_Raw); + VerifyOrReturnError(hsmret == HSM_NO_ERROR, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(outSignature.SetLength(kP256_ECDSA_Signature_Length_Raw) == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL); + memcpy(outSignature.Bytes(), sig, kP256_ECDSA_Signature_Length_Raw); + + return CHIP_NO_ERROR; +} + +Crypto::P256Keypair * PersistentStorageOperationalKeystoreEle::AllocateEphemeralKeypairForCASE() +{ + return Platform::New(); +} + +void PersistentStorageOperationalKeystoreEle::ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair) +{ + Platform::Delete(keypair); +} + +} // namespace ele +} // namespace chip diff --git a/examples/platform/linux/PersistentStorageOperationalKeystoreEle.h b/examples/platform/linux/PersistentStorageOperationalKeystoreEle.h new file mode 100644 index 00000000000000..1a74ab2760415c --- /dev/null +++ b/examples/platform/linux/PersistentStorageOperationalKeystoreEle.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * 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. + * + * Copyright 2023 NXP + */ + +#pragma once + +#include +#include +#include +#include + +#include "hsm_api.h" + +namespace chip { +namespace ele { + +/** + * @brief OperationalKeystore implementation making use of ELE secure storage + * to load/store keypairs. + * + */ +class PersistentStorageOperationalKeystoreEle : public Crypto::OperationalKeystore +{ +public: + PersistentStorageOperationalKeystoreEle(); + ~PersistentStorageOperationalKeystoreEle(); + + // Non-copyable + PersistentStorageOperationalKeystoreEle(PersistentStorageOperationalKeystoreEle const &) = delete; + void operator=(PersistentStorageOperationalKeystoreEle const &) = delete; + + bool HasPendingOpKeypair() const override { return (mPendingFabricIndex != kUndefinedFabricIndex); } + + bool HasOpKeypairForFabric(FabricIndex fabricIndex) const override; + CHIP_ERROR NewOpKeypairForFabric(FabricIndex fabricIndex, MutableByteSpan & outCertificateSigningRequest) override; + CHIP_ERROR ActivateOpKeypairForFabric(FabricIndex fabricIndex, const Crypto::P256PublicKey & nocPublicKey) override; + CHIP_ERROR CommitOpKeypairForFabric(FabricIndex fabricIndex) override; + CHIP_ERROR RemoveOpKeypairForFabric(FabricIndex fabricIndex) override; + void RevertPendingKeypair() override; + CHIP_ERROR SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message, + Crypto::P256ECDSASignature & outSignature) const override; + + Crypto::P256Keypair * AllocateEphemeralKeypairForCASE() override; + void ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair) override; + +protected: + FabricIndex mPendingFabricIndex = kUndefinedFabricIndex; + bool mIsPendingKeypairActive = false; + + // If overridding NewOpKeypairForFabric method in a subclass, set this to true in + // `NewOpKeypairForFabric` if the mPendingKeypair should not be deleted when no longer in use. + bool mIsExternallyOwnedKeypair = false; + +private: + void ResetPendingKey(bool delete_key); + hsm_err_t EleDeleteKey(uint32_t keyId); + CHIP_ERROR EleGenerateCSR(uint32_t keyId, uint8_t * csr, size_t & csrLength); + hsm_err_t EleSignMessage(uint32_t keyId, const uint8_t * msg, size_t msgSize, uint8_t * sig, size_t sigSize) const; + + hsm_hdl_t hsm_session_hdl = 0; + hsm_hdl_t key_store_hdl = 0; + hsm_hdl_t key_mgmt_hdl = 0; +}; + +} // namespace ele +} // namespace chip diff --git a/scripts/examples/imxlinux_example.sh b/scripts/examples/imxlinux_example.sh old mode 100755 new mode 100644 index af78789ba0287c..055ec996e7a331 --- a/scripts/examples/imxlinux_example.sh +++ b/scripts/examples/imxlinux_example.sh @@ -20,19 +20,22 @@ set -e set -x helpFunction() { cat < -o|--out [-d|--debug] [-n|--no-init] [-t|--trusty] +Usage: $0 -s|--src -o|--out [-d|--debug] [-n|--no-init] [-t|--trusty] [-m|--imx_ele] -s, --src Source folder -o, --out Output folder -d, --debug Debug build (optional) -n, --no-init No init mode (optional) -t, --trusty Build with Trusty OS backed security enhancement (optional) + -m, --imx_ele Build with IMX ELE (EdgeLock Enclave) based security enhancement (optional) EOF exit 1 } trusty=0 +imx_ele=0 +imx_ele_path="third_party/imx-secure-enclave/repo/" release_build=true -PARSED_OPTIONS="$(getopt -o s:o:tdn --long src:,out:,trusty,debug,no-init -- "$@")" +PARSED_OPTIONS="$(getopt -o s:o:tdmn --long src:,out:,trusty,imx_ele,debug,no-init -- "$@")" if [ $? -ne 0 ]; then helpFunction fi @@ -51,6 +54,10 @@ while true; do trusty=1 shift ;; + -m | --imx_ele) + imx_ele=1 + shift + ;; -d | --debug) release_build=false shift @@ -155,9 +162,19 @@ if [ -z "$target_cpu" -o -z "$cross_compile" ]; then exit 1 fi +if [ "$imx_ele" -ne 0 ]; then + if [ -f "$imx_ele_path/Makefile" ]; then + make -C "third_party/imx-secure-enclave/repo" "install_version" + else + echo "Makefile does not exist in $imx_ele_path." + exit 1 + fi +fi + PLATFORM_CFLAGS='-DCHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME=\"mlan0\"", "-DCHIP_DEVICE_CONFIG_LINUX_DHCPC_CMD=\"udhcpc -b -i %s \"' gn gen --check --fail-on-unused-args --root="$src" "$out" --args="target_os=\"linux\" target_cpu=\"$target_cpu\" arm_arch=\"$arm_arch\" chip_with_trusty_os=$trusty +chip_with_imx_ele=$imx_ele treat_warnings_as_errors=false import(\"//build_overrides/build.gni\") sysroot=\"$sdk_target_sysroot\" diff --git a/src/crypto/BUILD.gn b/src/crypto/BUILD.gn index b950974f342c15..29dc2ae7289ca7 100644 --- a/src/crypto/BUILD.gn +++ b/src/crypto/BUILD.gn @@ -21,6 +21,7 @@ import("${chip_root}/build/chip/buildconfig_header.gni") import("crypto.gni") +import("${chip_root}/src/lib/imx_ele.gni") import("${chip_root}/src/lib/trusty.gni") if (chip_crypto == "") { diff --git a/src/lib/imx_ele.gni b/src/lib/imx_ele.gni new file mode 100644 index 00000000000000..35963045eaae6e --- /dev/null +++ b/src/lib/imx_ele.gni @@ -0,0 +1,17 @@ +# Copyright (c) 2023 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. + +declare_args() { + chip_with_imx_ele = 0 +} diff --git a/third_party/imx-secure-enclave/BUILD.gn b/third_party/imx-secure-enclave/BUILD.gn new file mode 100644 index 00000000000000..7ca2da17563a4a --- /dev/null +++ b/third_party/imx-secure-enclave/BUILD.gn @@ -0,0 +1,184 @@ +# Copyright (c) 2023 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. + +import("//build_overrides/chip.gni") + +declare_args() { + NOT_SUPPORTED = 0 + ROM = 1 + FMW = 2 + + MAJOR_VER = 1 + MINOR_VER = 0 + + PLAT_PATH = "src/plat/ele" + PLAT_COMMON_PATH = "src/common" +} + +config("libele_config") { + defines = [ + "DEBUG=0", + "LIB_MAJOR_VERSION=${MAJOR_VER}", + "LIB_MINOR_VERSION=${MINOR_VER}", + + "CONFIG_PLAT_ELE=1", + "PLAT_ELE_FEAT_NOT_SUPPORTED=0", + "PSA_COMPLIANT=1", + "SECONDARY_API_SUPPORTED=1", + + "MT_SAB_SIGN_GEN=${FMW}", + "MT_SAB_VERIFY_SIGN=${FMW}", + "MT_SAB_KEY_GENERATE=${FMW}", + "MT_SAB_MANAGE_KEY_GROUP=${FMW}", + "MT_SAB_IMPORT_KEY=${FMW}", + "MT_SAB_DELETE_KEY=${FMW}", + "MT_SAB_GET_KEY_ATTR=${FMW}", + "MT_SAB_HASH_GEN=${FMW}", + "MT_SAB_CIPHER=${FMW}", + "MT_SAB_SESSION=${FMW}", + "MT_SAB_KEY_STORE=${FMW}", + "MT_SAB_KEY_STORE_REPROV_EN=${FMW}", + "MT_SAB_KEY_MANAGEMENT=${FMW}", + "MT_SAB_MAC=${FMW}", + "MT_SAB_RNG=${FMW}", + "MT_SAB_KEY_RECOVERY=${FMW}", + "MT_SAB_GET_INFO=${FMW}", + "MT_SAB_AUTH_ENC=${FMW}", + "MT_SAB_AUTH_ENC_NEW=${FMW}", + "MT_SAB_DATA_STORAGE=${FMW}", + "MT_SAB_DATA_STORAGE_DELETE=${FMW}", + "MT_SAB_DEBUG_DUMP=${ROM}", + "MT_SAB_DEV_ATTEST=${ROM}", + "MT_SAB_DEV_GETINFO=${ROM}", + "MT_SAB_LC_UPDATE=${ROM}", + "MT_SAB_STORAGE_MASTER_IMPORT=${FMW}", + "MT_SAB_STORAGE_MASTER_EXPORT_REQ=${FMW}", + "MT_SAB_STORAGE_EXPORT_FINISH_REQ=${FMW}", + "MT_SAB_STORAGE_CHUNK_GET_REQ=${FMW}", + "MT_SAB_STORAGE_CHUNK_GET_DONE_REQ=${FMW}", + "MT_SAB_STORAGE_CHUNK_EXPORT_REQ=${FMW}", + "MT_SAB_STORAGE_OPEN=${FMW}", + "MT_SAB_STORAGE_CLOSE=${FMW}", + "MT_SAB_STORAGE_KEY_DB_REQ=${FMW}", + "MT_SAB_ENC_DATA_STORAGE=${FMW}", + + "HSM_SIGN_GEN=1", + "HSM_VERIFY_SIGN=1", + "HSM_KEY_GENERATE=1", + "HSM_MANAGE_KEY_GROUP=1", + "HSM_IMPORT_KEY=1", + "HSM_DELETE_KEY=1", + "HSM_GET_KEY_ATTR=1", + "HSM_HASH_GEN=1", + "HSM_CIPHER=1", + "HSM_SESSION=1", + "HSM_KEY_STORE=1", + "HSM_KEY_MANAGEMENT=1", + "HSM_MAC=1", + "HSM_RNG=1", + "HSM_KEY_RECOVERY=1", + "HSM_GET_INFO=1", + "HSM_AUTH_ENC=1", + "HSM_DATA_STORAGE=1", + "HSM_DEBUG_DUMP=1", + "HSM_DEV_ATTEST=1", + "HSM_DEV_GETINFO=1", + "HSM_LC_UPDATE=1", + "HSM_ENC_DATA_STORAGE=1", + ] + + include_dirs = [ + "repo/src/plat/ele/include", + "repo/src/common/include", + "repo/src/common/sab_msg/include", + "repo/include", + "repo/include/common", + "repo/include/hsm", + "repo/include/she", + ] +} + +source_set("libelematter") { + sources = [ + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_auth_enc.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_cipher.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_data_storage.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_debug_dump.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_delete_key.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_dev_attest.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_dev_getinfo.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_get_info.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_get_key_attr.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_handle.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_hash.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_importkey.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_key_generate.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_key_management.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_key_recovery.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_key_store.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_lc_update.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_mac.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_manage_key_group.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_rng.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_session.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_sign_gen.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_utils.c", + "repo/${PLAT_COMMON_PATH}/hsm_api/hsm_verify_sign.c", + "repo/${PLAT_COMMON_PATH}/hsm_lib.c", + "repo/${PLAT_COMMON_PATH}/sab_common_err.c", + "repo/${PLAT_COMMON_PATH}/sab_messaging.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_auth_enc.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_cipher.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_data_storage.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_debug_dump.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_delete_key.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_dev_attest.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_dev_getinfo.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_get_info.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_get_key_attr.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_hash.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_import_key.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_init_proc_msg.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_key_generate.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_key_management.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_key_recovery.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_key_store.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_lc_update.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_mac.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_manage_key_group.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_process_msg.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_rng.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_session.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_sign_gen.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_storage_chunk_export.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_storage_close.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_storage_export_finish.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_storage_get_chunk.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_storage_get_chunk_done.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_storage_key_db.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_storage_master_export.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_storage_master_import.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_storage_open.c", + "repo/${PLAT_COMMON_PATH}/sab_msg/sab_verify_sign.c", + "repo/${PLAT_COMMON_PATH}/se_global_info.c", + "repo/${PLAT_PATH}/ele_os_abs_linux.c", + "repo/${PLAT_PATH}/ele_utils.c", + "repo/${PLAT_PATH}/plat_err.c", + ] + + cflags = [ "-Wno-implicit-fallthrough -O1 -Werror -Wformat -fPIC" ] + cflags_cc = [ "-std=c++17" ] + + public_configs = [ ":libele_config" ] +} diff --git a/third_party/imx-secure-enclave/repo b/third_party/imx-secure-enclave/repo new file mode 160000 index 00000000000000..1b8582de2f6d18 --- /dev/null +++ b/third_party/imx-secure-enclave/repo @@ -0,0 +1 @@ +Subproject commit 1b8582de2f6d18ee05ecac23f4ce6abeb104cff5 From ab42e1fe86d1e1df538faa20156611aeeb9f2bb3 Mon Sep 17 00:00:00 2001 From: Ji Luo Date: Tue, 26 Sep 2023 10:33:04 +0800 Subject: [PATCH 7/7] Add device attestation based on ELE Support device attestation based on EdgeLock Enclave(ELE). Attestation certifications and keys should be provisioned into device in advance. The official tool to provide signed content is not ready, so we disable the device attestation feature based on ELE first. It's currently only supported by i.MX 93 platform. Change-Id: I39c79efa17a99266113e2bf28204d0c23b81af1d Signed-off-by: Ji Luo Reviewed-on: http://androidsource.nxp.com/project/23345 Reviewed-by: Elven Wang --- examples/platform/linux/AppMain.cpp | 8 +- examples/platform/linux/BUILD.gn | 11 +- .../linux/DeviceAttestationCredsEle.cpp | 219 ++++++++++++++++++ .../linux/DeviceAttestationCredsEle.h | 46 ++++ ...s.cpp => DeviceAttestationCredsTrusty.cpp} | 5 +- ...Creds.h => DeviceAttestationCredsTrusty.h} | 3 +- ...ersistentStorageOperationalKeystoreEle.cpp | 7 +- 7 files changed, 287 insertions(+), 12 deletions(-) create mode 100644 examples/platform/linux/DeviceAttestationCredsEle.cpp create mode 100644 examples/platform/linux/DeviceAttestationCredsEle.h rename examples/platform/linux/{DeviceAttestationCreds.cpp => DeviceAttestationCredsTrusty.cpp} (97%) rename examples/platform/linux/{DeviceAttestationCreds.h => DeviceAttestationCredsTrusty.h} (98%) diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index 6ed837f738b593..d836300bf3ee0f 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -1,6 +1,7 @@ /* * * Copyright (c) 2021-2022 Project CHIP Authors + * Copyright 2023, 2025 NXP * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -127,8 +128,11 @@ #endif // CHIP_DEVICE_LAYER_TARGET_LINUX #if CHIP_ATTESTATION_TRUSTY_OS -#include "DeviceAttestationCreds.h" +#include "DeviceAttestationCredsTrusty.h" using namespace chip::Credentials::Trusty; +#elif CHIP_ATTESTATION_ELE +#include "DeviceAttestationCredsEle.h" +using namespace chip::Credentials::ele; #endif #if CHIP_OP_KEYSTORE_TRUSTY_OS @@ -737,6 +741,8 @@ void ChipLinuxAppMainLoop(AppMainLoopImplementation * impl) // Initialize device attestation config #if CHIP_ATTESTATION_TRUSTY_OS SetDeviceAttestationCredentialsProvider(&TrustyDACProvider::GetTrustyDACProvider()); +#elif CHIP_ATTESTATION_ELE + SetDeviceAttestationCredentialsProvider(&EleDACProvider::GetEleDACProvider()); #else SetDeviceAttestationCredentialsProvider(LinuxDeviceOptions::GetInstance().dacProvider); #endif diff --git a/examples/platform/linux/BUILD.gn b/examples/platform/linux/BUILD.gn index e3f6de29bb84c3..4cab99fa5c91bd 100644 --- a/examples/platform/linux/BUILD.gn +++ b/examples/platform/linux/BUILD.gn @@ -1,4 +1,5 @@ # Copyright (c) 2020 Project CHIP Authors +# Copyright 2025 NXP # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -100,8 +101,8 @@ source_set("app-main") { if (chip_with_trusty_os == 1) { sources += [ - "DeviceAttestationCreds.cpp", - "DeviceAttestationCreds.h", + "DeviceAttestationCredsTrusty.cpp", + "DeviceAttestationCredsTrusty.h", "PersistentStorageOperationalKeystoreTrusty.cpp", "PersistentStorageOperationalKeystoreTrusty.h", ] @@ -109,6 +110,9 @@ source_set("app-main") { if (chip_with_imx_ele == 1) { sources += [ + #TODO enable this when official tool ready + # "DeviceAttestationCredsEle.cpp", + # "DeviceAttestationCredsEle.h", "PersistentStorageOperationalKeystoreEle.cpp", "PersistentStorageOperationalKeystoreEle.h", ] @@ -163,8 +167,11 @@ source_set("app-main") { if (chip_with_imx_ele == 1) { defines += [ "CHIP_OP_KEYSTORE_ELE=1" ] + #TODO enable this when official tool ready + # defines += [ "CHIP_ATTESTATION_ELE=1" ] } else { defines += [ "CHIP_OP_KEYSTORE_ELE=0" ] + defines += [ "CHIP_ATTESTATION_ELE=0" ] } if (chip_enable_pw_rpc) { diff --git a/examples/platform/linux/DeviceAttestationCredsEle.cpp b/examples/platform/linux/DeviceAttestationCredsEle.cpp new file mode 100644 index 00000000000000..03a0fe948b275b --- /dev/null +++ b/examples/platform/linux/DeviceAttestationCredsEle.cpp @@ -0,0 +1,219 @@ +/* + * + * Copyright (c) 2021-2022 Project CHIP Authors + * Copyright 2023, 2025 NXP + * + * 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. + * + */ +#include "DeviceAttestationCredsEle.h" + +#include +#include +#include + +#define KEY_STORE_ID (0xBBBB) +#define AUTHEN_NONCE (0x2222) +#define PAI_DATA_ID 0x1111 +#define DAC_DATA_ID 0x1112 +#define CD_DATA_ID 0x1113 +#define DAC_PRIVATE_KEY_ID 0x1114 + +namespace chip { +namespace Credentials { +namespace ele { + +EleDACProvider::EleDACProvider() +{ + hsm_err_t err; + + // open the session + open_session_args_t open_session_args = { 0 }; + open_session_args.mu_type = HSM1; + err = hsm_open_session(&open_session_args, &hsm_session_hdl); + if (err != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "ELE device attestation session open failed. ret: 0x%x\n", err); + return; + } + else + { + ChipLogDetail(Crypto, "ELE device attestation session open successfully.\n"); + } + + // open the keystore + open_svc_key_store_args_t open_svc_key_store_args = { 0 }; + open_svc_key_store_args.key_store_identifier = KEY_STORE_ID; + open_svc_key_store_args.authentication_nonce = AUTHEN_NONCE; + // try to create a new keystore, if it already exist, open it + open_svc_key_store_args.flags = (HSM_SVC_KEY_STORE_FLAGS_CREATE | HSM_SVC_KEY_STORE_FLAGS_STRICT_OPERATION); + err = hsm_open_key_store_service(hsm_session_hdl, &open_svc_key_store_args, &key_store_hdl); + if (err == HSM_KEY_STORE_CONFLICT) + { + ChipLogDetail(Crypto, "device attestation keystore already existed, open it...\n"); + open_svc_key_store_args.flags = HSM_SVC_KEY_STORE_FLAGS_LOAD; + err = hsm_open_key_store_service(hsm_session_hdl, &open_svc_key_store_args, &key_store_hdl); + if (err != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "device attestation keystore open failed. ret:0x%x\n", err); + return; + } + else + ChipLogDetail(Crypto, "device attestation keystore open successfully.\n"); + } + else + { + ChipLogDetail(Crypto, "device attestation keystore created successfully.\n"); + } +} + +EleDACProvider::~EleDACProvider() +{ + hsm_err_t err; + + ChipLogDetail(Crypto, "close all ELE device attestation services.\n"); + + err = hsm_close_key_store_service(key_store_hdl); + key_store_hdl = 0; + ChipLogDetail(Crypto, "close device attestation key store service returns:0x%x\n", err); + + err = hsm_close_session(hsm_session_hdl); + hsm_session_hdl = 0; + ChipLogDetail(Crypto, "close ELE device attestation session returns:0x%x\n", err); +} + +CHIP_ERROR EleDACProvider::GetDeviceAttestationCert(MutableByteSpan & out_dac_buffer) +{ + op_data_storage_args_t data_storage_args; + hsm_err_t err; + + data_storage_args.svc_flags = 0; + data_storage_args.data = out_dac_buffer.data(); + data_storage_args.data_size = out_dac_buffer.size(); + data_storage_args.data_id = DAC_DATA_ID; + data_storage_args.flags |= HSM_OP_DATA_STORAGE_FLAGS_RETRIEVE; + err = hsm_data_ops(key_store_hdl, &data_storage_args); + if (err) + { + ChipLogDetail(Crypto, "ELE get DAC failed. ret: 0x%x\n", err); + return CHIP_ERROR_CERT_LOAD_FAILED; + } + + out_dac_buffer.reduce_size(data_storage_args.exp_output_size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR EleDACProvider::GetProductAttestationIntermediateCert(MutableByteSpan & out_pai_buffer) +{ + op_data_storage_args_t data_storage_args; + hsm_err_t err; + + data_storage_args.svc_flags = 0; + data_storage_args.data = out_pai_buffer.data(); + data_storage_args.data_size = out_pai_buffer.size(); + data_storage_args.data_id = PAI_DATA_ID; + data_storage_args.flags |= HSM_OP_DATA_STORAGE_FLAGS_RETRIEVE; + err = hsm_data_ops(key_store_hdl, &data_storage_args); + if (err) + { + ChipLogDetail(Crypto, "ELE get PAI failed. ret: 0x%x\n", err); + return CHIP_ERROR_CERT_LOAD_FAILED; + } + + out_pai_buffer.reduce_size(data_storage_args.exp_output_size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR EleDACProvider::GetCertificationDeclaration(MutableByteSpan & out_cd_buffer) +{ + op_data_storage_args_t data_storage_args; + hsm_err_t err; + + data_storage_args.svc_flags = 0; + data_storage_args.data = out_cd_buffer.data(); + data_storage_args.data_size = out_cd_buffer.size(); + data_storage_args.data_id = CD_DATA_ID; + data_storage_args.flags |= HSM_OP_DATA_STORAGE_FLAGS_RETRIEVE; + err = hsm_data_ops(key_store_hdl, &data_storage_args); + if (err) + { + ChipLogDetail(Crypto, "ELE get CD failed. ret: 0x%x\n", err); + return CHIP_ERROR_CERT_LOAD_FAILED; + } + + out_cd_buffer.reduce_size(data_storage_args.exp_output_size); + return CHIP_NO_ERROR; +} + +CHIP_ERROR EleDACProvider::GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) +{ + // TODO: We need a real example FirmwareInformation to be populated. + out_firmware_info_buffer.reduce_size(0); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR EleDACProvider::SignWithDeviceAttestationKey(const ByteSpan & message_to_sign, MutableByteSpan & out_signature_buffer) +{ + open_svc_sign_gen_args_t open_sig_gen_args; + op_generate_sign_args_t sig_gen_args; + uint8_t signature[64]; + hsm_hdl_t sig_gen_hdl; + size_t out_size = 0; + hsm_err_t hsmret; + + VerifyOrReturnError(IsSpanUsable(out_signature_buffer), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsSpanUsable(message_to_sign), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_signature_buffer.size() >= sizeof(signature), CHIP_ERROR_BUFFER_TOO_SMALL); + + // open signature generation service + memset(&open_sig_gen_args, 0, sizeof(open_sig_gen_args)); + hsmret = hsm_open_signature_generation_service(key_store_hdl, &open_sig_gen_args, &sig_gen_hdl); + if (hsmret != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "open signature generation service failed. ret:0x%x\n", hsmret); + return CHIP_ERROR_HSM; + } + + // generate signature + memset(&sig_gen_args, 0, sizeof(sig_gen_args)); + sig_gen_args.key_identifier = DAC_PRIVATE_KEY_ID; + sig_gen_args.scheme_id = HSM_SIGNATURE_SCHEME_ECDSA_SHA256; + sig_gen_args.message = (uint8_t *) (message_to_sign.data()); + sig_gen_args.signature = signature; + sig_gen_args.message_size = message_to_sign.size(); + sig_gen_args.signature_size = sizeof(signature); + sig_gen_args.flags = HSM_OP_GENERATE_SIGN_FLAGS_INPUT_MESSAGE; + hsmret = hsm_generate_signature(sig_gen_hdl, &sig_gen_args); + hsm_close_signature_generation_service(sig_gen_hdl); + if (hsmret != HSM_NO_ERROR) + { + ChipLogDetail(Crypto, "generate signature failed. ret:0x%x\n", hsmret); + return CHIP_ERROR_HSM; + } + + memcpy(out_signature_buffer.data(), signature, sizeof(signature)); + out_signature_buffer.reduce_size(sizeof(signature)); + return CHIP_NO_ERROR; +} + +EleDACProvider & EleDACProvider::GetEleDACProvider() +{ + static EleDACProvider ele_dac_provider; + + return ele_dac_provider; +} + +} // namespace ele +} // namespace Credentials +} // namespace chip diff --git a/examples/platform/linux/DeviceAttestationCredsEle.h b/examples/platform/linux/DeviceAttestationCredsEle.h new file mode 100644 index 00000000000000..5d027bcbe23738 --- /dev/null +++ b/examples/platform/linux/DeviceAttestationCredsEle.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 Project CHIP Authors + * Copyright 2023, 2025 NXP + * + * 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. + */ +#pragma once + +#include "hsm_api.h" +#include + +namespace chip { +namespace Credentials { +namespace ele { + +class EleDACProvider : public DeviceAttestationCredentialsProvider +{ +public: + EleDACProvider(); + ~EleDACProvider(); + static EleDACProvider & GetEleDACProvider(); + + CHIP_ERROR GetCertificationDeclaration(MutableByteSpan & out_cd_buffer) override; + CHIP_ERROR GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) override; + CHIP_ERROR GetDeviceAttestationCert(MutableByteSpan & out_dac_buffer) override; + CHIP_ERROR GetProductAttestationIntermediateCert(MutableByteSpan & out_pai_buffer) override; + CHIP_ERROR SignWithDeviceAttestationKey(const ByteSpan & message_to_sign, MutableByteSpan & out_signature_buffer) override; + +private: + hsm_hdl_t hsm_session_hdl = 0; + hsm_hdl_t key_store_hdl = 0; +}; + +} // namespace ele +} // namespace Credentials +} // namespace chip diff --git a/examples/platform/linux/DeviceAttestationCreds.cpp b/examples/platform/linux/DeviceAttestationCredsTrusty.cpp similarity index 97% rename from examples/platform/linux/DeviceAttestationCreds.cpp rename to examples/platform/linux/DeviceAttestationCredsTrusty.cpp index c933136b300017..7667a8c745a494 100644 --- a/examples/platform/linux/DeviceAttestationCreds.cpp +++ b/examples/platform/linux/DeviceAttestationCredsTrusty.cpp @@ -1,6 +1,7 @@ /* * * Copyright (c) 2021-2022 Project CHIP Authors + * Copyright 2023, 2025 NXP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +14,8 @@ * 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. - * - * Copyright 2023 NXP */ -#include "DeviceAttestationCreds.h" +#include "DeviceAttestationCredsTrusty.h" #include #include diff --git a/examples/platform/linux/DeviceAttestationCreds.h b/examples/platform/linux/DeviceAttestationCredsTrusty.h similarity index 98% rename from examples/platform/linux/DeviceAttestationCreds.h rename to examples/platform/linux/DeviceAttestationCredsTrusty.h index 733fc5133418ff..a8906b7802390d 100644 --- a/examples/platform/linux/DeviceAttestationCreds.h +++ b/examples/platform/linux/DeviceAttestationCredsTrusty.h @@ -1,7 +1,6 @@ /* - * Copyright 2023 NXP - * * Copyright (c) 2021 Project CHIP Authors + * Copyright 2023, 2025 NXP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/examples/platform/linux/PersistentStorageOperationalKeystoreEle.cpp b/examples/platform/linux/PersistentStorageOperationalKeystoreEle.cpp index d556288dc7d63e..8547ad4948098f 100644 --- a/examples/platform/linux/PersistentStorageOperationalKeystoreEle.cpp +++ b/examples/platform/linux/PersistentStorageOperationalKeystoreEle.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2022 Project CHIP Authors + * Copyright 2023, 2025 NXP * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,8 +14,6 @@ * 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. - * - * Copyright 2023 NXP */ #include @@ -76,12 +75,12 @@ PersistentStorageOperationalKeystoreEle::PersistentStorageOperationalKeystoreEle open_svc_key_store_args.key_store_identifier = KEY_STORE_ID; open_svc_key_store_args.authentication_nonce = AUTHEN_NONCE; // try to create a new keystore, if it already exist, open it - open_svc_key_store_args.flags = 1; + open_svc_key_store_args.flags = (HSM_SVC_KEY_STORE_FLAGS_CREATE | HSM_SVC_KEY_STORE_FLAGS_STRICT_OPERATION); err = hsm_open_key_store_service(hsm_session_hdl, &open_svc_key_store_args, &key_store_hdl); if (err == HSM_KEY_STORE_CONFLICT) { ChipLogDetail(Crypto, "keystore already existed, open it...\n"); - open_svc_key_store_args.flags = 0; + open_svc_key_store_args.flags = HSM_SVC_KEY_STORE_FLAGS_LOAD; err = hsm_open_key_store_service(hsm_session_hdl, &open_svc_key_store_args, &key_store_hdl); if (err != HSM_NO_ERROR) {