diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 77bd2a6b207..27549bc275b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -188,7 +188,7 @@ jobs: run: | script/check-scan-build - mbedtls2-build: + mbedtls3-build: runs-on: ubuntu-24.04 steps: - name: Harden Runner @@ -202,15 +202,9 @@ jobs: - name: Bootstrap run: | sudo apt-get --no-install-recommends install -y ninja-build libreadline-dev libncurses-dev - rm -rf third_party/mbedtls/repo - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - repository: ARMmbed/mbedtls - ref: v2.28.8 - path: third_party/mbedtls/repo - name: Build run: | - ./script/test build + OT_OPTIONS="-DOT_CRYPTO_LIB=MBEDTLS -DOT_PLATFORM_KEY_REF=OFF" ./script/test build arm-gcc: name: arm-gcc-${{ matrix.gcc_ver }} diff --git a/.github/workflows/toranj.yml b/.github/workflows/toranj.yml index ed63d30e012..9a3ff0c3d88 100644 --- a/.github/workflows/toranj.yml +++ b/.github/workflows/toranj.yml @@ -165,8 +165,6 @@ jobs: ./tests/toranj/build.sh posix-15.4+trel git clean -dfx ./tests/toranj/build.sh posix-trel - git clean -dfx - ./tests/toranj/build.sh --enable-plat-key-ref all toranj-macos: name: toranj-macos diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 913c681615b..5edf57f0029 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -288,6 +288,11 @@ if(ot_index EQUAL -1) message(FATAL_ERROR "Invalid value for OT_PLATFORM - valid values are:" "${OT_PLATFORM_VALUES}") endif() +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +set(OT_CRYPTO_LIB_VALUES "MBEDTLS" "PSA" "PLATFORM") +ot_multi_option(OT_CRYPTO_LIB OT_CRYPTO_LIB_VALUES OPENTHREAD_CONFIG_CRYPTO_LIB OPENTHREAD_CONFIG_CRYPTO_LIB_ "set Crypto backend library") + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - set(OT_THREAD_VERSION_VALUES "1.1" "1.2" "1.3" "1.3.1" "1.4") set(OT_THREAD_VERSION "1.4" CACHE STRING "set Thread version") @@ -342,7 +347,7 @@ ot_int_option(OT_RCP_TX_WAIT_TIME_SECS OPENTHREAD_SPINEL_CONFIG_RCP_TX_WAIT_TIME # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if(NOT OT_EXTERNAL_MBEDTLS) - set(OT_MBEDTLS mbedtls) + set(OT_MBEDTLS mbedtls mbedcrypto) target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_ENABLE_BUILTIN_MBEDTLS=1") else() set(OT_MBEDTLS ${OT_EXTERNAL_MBEDTLS}) diff --git a/examples/apps/cli/ftd.cmake b/examples/apps/cli/ftd.cmake index 9ed9be18c3b..869989eae59 100644 --- a/examples/apps/cli/ftd.cmake +++ b/examples/apps/cli/ftd.cmake @@ -41,9 +41,9 @@ target_link_libraries(ot-cli-ftd PRIVATE openthread-cli-ftd ${OT_PLATFORM_LIB_FTD} openthread-ftd - ${OT_PLATFORM_LIB_FTD} openthread-cli-ftd ${OT_MBEDTLS} + ${OT_PLATFORM_LIB_FTD} ot-config-ftd ot-config ) diff --git a/examples/apps/cli/mtd.cmake b/examples/apps/cli/mtd.cmake index 786f741610d..7d38f5bb92e 100644 --- a/examples/apps/cli/mtd.cmake +++ b/examples/apps/cli/mtd.cmake @@ -41,9 +41,9 @@ target_link_libraries(ot-cli-mtd PRIVATE openthread-cli-mtd ${OT_PLATFORM_LIB_MTD} openthread-mtd - ${OT_PLATFORM_LIB_MTD} openthread-cli-mtd ${OT_MBEDTLS} + ${OT_PLATFORM_LIB_MTD} ot-config-mtd ot-config ) diff --git a/examples/apps/ncp/ftd.cmake b/examples/apps/ncp/ftd.cmake index a7ffa51ad54..51abdd63280 100644 --- a/examples/apps/ncp/ftd.cmake +++ b/examples/apps/ncp/ftd.cmake @@ -41,9 +41,9 @@ target_link_libraries(ot-ncp-ftd PRIVATE openthread-ncp-ftd ${OT_PLATFORM_LIB_FTD} openthread-ftd - ${OT_PLATFORM_LIB_FTD} openthread-ncp-ftd ${OT_MBEDTLS} + ${OT_PLATFORM_LIB_FTD} ot-config-ftd ot-config ) diff --git a/examples/apps/ncp/mtd.cmake b/examples/apps/ncp/mtd.cmake index 2fecbacc0bc..959dae12586 100644 --- a/examples/apps/ncp/mtd.cmake +++ b/examples/apps/ncp/mtd.cmake @@ -41,9 +41,9 @@ target_link_libraries(ot-ncp-mtd PRIVATE openthread-ncp-mtd ${OT_PLATFORM_LIB_MTD} openthread-mtd - ${OT_PLATFORM_LIB_MTD} openthread-ncp-mtd ${OT_MBEDTLS} + ${OT_PLATFORM_LIB_MTD} ot-config-mtd ot-config ) diff --git a/examples/platforms/simulation/CMakeLists.txt b/examples/platforms/simulation/CMakeLists.txt index 6506c413a9e..3213ff56ab6 100644 --- a/examples/platforms/simulation/CMakeLists.txt +++ b/examples/platforms/simulation/CMakeLists.txt @@ -74,7 +74,6 @@ set(OT_PLATFORM_DEFINES ${OT_PLATFORM_DEFINES} PARENT_SCOPE) add_library(openthread-simulation alarm.c ble.c - crypto.c diag.c dns.c dnssd.c @@ -104,6 +103,8 @@ endif() target_link_libraries(openthread-simulation PRIVATE openthread-platform + mbedtls + openthread-native-its-file ot-simulation-config ot-config ) diff --git a/examples/platforms/simulation/crypto.c b/examples/platforms/simulation/crypto.c deleted file mode 100644 index 20c151b46b2..00000000000 --- a/examples/platforms/simulation/crypto.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2021, The OpenThread Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "platform-simulation.h" - -#include -#include - -#include -#include - -#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - -// crypto key storage stubs - -otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, - otCryptoKeyType aKeyType, - otCryptoKeyAlgorithm aKeyAlgorithm, - int aKeyUsage, - otCryptoKeyStorage aKeyPersistence, - const uint8_t *aKey, - size_t aKeyLen) -{ - OT_UNUSED_VARIABLE(aKeyRef); - OT_UNUSED_VARIABLE(aKeyType); - OT_UNUSED_VARIABLE(aKeyAlgorithm); - OT_UNUSED_VARIABLE(aKeyUsage); - OT_UNUSED_VARIABLE(aKeyPersistence); - OT_UNUSED_VARIABLE(aKey); - OT_UNUSED_VARIABLE(aKeyLen); - - return OT_ERROR_NOT_IMPLEMENTED; -} - -otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, uint8_t *aBuffer, size_t aBufferLen, size_t *aKeyLen) -{ - OT_UNUSED_VARIABLE(aKeyRef); - OT_UNUSED_VARIABLE(aBuffer); - OT_UNUSED_VARIABLE(aBufferLen); - OT_UNUSED_VARIABLE(aKeyLen); - - return OT_ERROR_NOT_IMPLEMENTED; -} - -otError otPlatCryptoDestroyKey(otCryptoKeyRef aKeyRef) -{ - OT_UNUSED_VARIABLE(aKeyRef); - - return OT_ERROR_NOT_IMPLEMENTED; -} - -bool otPlatCryptoHasKey(otCryptoKeyRef aKeyRef) -{ - OT_UNUSED_VARIABLE(aKeyRef); - - return false; -} - -otError otPlatCryptoEcdsaGenerateAndImportKey(otCryptoKeyRef aKeyRef) -{ - OT_UNUSED_VARIABLE(aKeyRef); - - return OT_ERROR_NONE; -} - -otError otPlatCryptoEcdsaExportPublicKey(otCryptoKeyRef aKeyRef, otPlatCryptoEcdsaPublicKey *aPublicKey) -{ - OT_UNUSED_VARIABLE(aKeyRef); - OT_UNUSED_VARIABLE(aPublicKey); - - return OT_ERROR_NONE; -} - -otError otPlatCryptoEcdsaSignUsingKeyRef(otCryptoKeyRef aKeyRef, - const otPlatCryptoSha256Hash *aHash, - otPlatCryptoEcdsaSignature *aSignature) -{ - OT_UNUSED_VARIABLE(aKeyRef); - OT_UNUSED_VARIABLE(aHash); - OT_UNUSED_VARIABLE(aSignature); - - return OT_ERROR_NONE; -} - -otError otPlatCryptoEcdsaVerifyUsingKeyRef(otCryptoKeyRef aKeyRef, - const otPlatCryptoSha256Hash *aHash, - const otPlatCryptoEcdsaSignature *aSignature) -{ - OT_UNUSED_VARIABLE(aKeyRef); - OT_UNUSED_VARIABLE(aHash); - OT_UNUSED_VARIABLE(aSignature); - - return OT_ERROR_NONE; -} - -#endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE diff --git a/examples/platforms/simulation/entropy.c b/examples/platforms/simulation/entropy.c index 951bddeba31..19bd30ab6af 100644 --- a/examples/platforms/simulation/entropy.c +++ b/examples/platforms/simulation/entropy.c @@ -38,6 +38,10 @@ #include +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) +#include +#endif + #include "utils/code_utils.h" #ifndef __SANITIZE_ADDRESS__ @@ -133,3 +137,33 @@ otError otPlatEntropyGet(uint8_t *aOutput, uint16_t aOutputLength) return error; } + +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +/** + * When OpenThread is compiled with the PSA Crypto backend using Mbed TLS 3.x, there is no + * API to configure a dedicated non-default entropy source. It is documented that a future version of + * Mbed TLS (likely 4.x) will include a PSA interface for configuring entropy sources. + * + * For now, we need to define the external RNG. Since the implementation of `otPlatEntropyGet` already + * uses CSPRNG, we will call it here as well. + */ +psa_status_t mbedtls_psa_external_get_random(mbedtls_psa_external_random_context_t *context, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + OT_UNUSED_VARIABLE(context); + + otError error; + psa_status_t status = PSA_ERROR_GENERIC_ERROR; + + error = otPlatEntropyGet(output, (uint16_t)output_size); + if (error == OT_ERROR_NONE) + { + *output_length = output_size; + status = PSA_SUCCESS; + } + + return status; +} +#endif diff --git a/examples/platforms/simulation/openthread-core-simulation-config.h b/examples/platforms/simulation/openthread-core-simulation-config.h index 9cee9af8bea..46af311ff31 100644 --- a/examples/platforms/simulation/openthread-core-simulation-config.h +++ b/examples/platforms/simulation/openthread-core-simulation-config.h @@ -39,6 +39,18 @@ #define OPENTHREAD_RADIO 0 #endif +#ifndef OPENTHREAD_CONFIG_CRYPTO_LIB +#define OPENTHREAD_CONFIG_CRYPTO_LIB OPENTHREAD_CONFIG_CRYPTO_LIB_PSA +#endif + +#ifndef OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE +#define OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 1 +#endif + +#if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE && OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE +#define OPENTHREAD_CONFIG_MULTIPLE_STATIC_INSTANCE_ENABLE 1 +#endif + #ifndef OPENTHREAD_CONFIG_PLATFORM_INFO #define OPENTHREAD_CONFIG_PLATFORM_INFO "SIMULATION" #endif diff --git a/examples/platforms/simulation/system.c b/examples/platforms/simulation/system.c index 6483a36f6bd..68e92169197 100644 --- a/examples/platforms/simulation/system.c +++ b/examples/platforms/simulation/system.c @@ -61,6 +61,11 @@ extern otRadioCaps gRadioCaps; static volatile bool gTerminate = false; +#if OPENTHREAD_PSA_CRYPTO_NATIVE_ITS_FILE && (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) +static char sNativeItsFileNamePrefix[256]; +extern const char *gItsFileNamePrefix; +#endif + static void handleSignal(int aSignal) { OT_UNUSED_VARIABLE(aSignal); @@ -193,6 +198,12 @@ void otSysInit(int aArgCount, char *aArgVector[]) signal(SIGTERM, &handleSignal); signal(SIGHUP, &handleSignal); +#if OPENTHREAD_PSA_CRYPTO_NATIVE_ITS_FILE && (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) + snprintf(sNativeItsFileNamePrefix, sizeof(sNativeItsFileNamePrefix), "%s/%s_%d_", + OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH, getenv("PORT_OFFSET") ? getenv("PORT_OFFSET") : "0", gNodeId); + gItsFileNamePrefix = sNativeItsFileNamePrefix; +#endif + platformLoggingInit(basename(aArgVector[0])); platformAlarmInit(speedUpFactor); platformRadioInit(); diff --git a/examples/platforms/simulation/virtual_time/platform-sim.c b/examples/platforms/simulation/virtual_time/platform-sim.c index ba475f07796..34546b7ea52 100644 --- a/examples/platforms/simulation/virtual_time/platform-sim.c +++ b/examples/platforms/simulation/virtual_time/platform-sim.c @@ -60,6 +60,11 @@ static volatile bool gTerminate = false; int gArgumentsCount = 0; char **gArguments = NULL; +#if OPENTHREAD_PSA_CRYPTO_NATIVE_ITS_FILE && (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) +static char sNativeItsFileNamePrefix[256]; +extern const char *gItsFileNamePrefix; +#endif + uint64_t sNow = 0; // microseconds int sSockFd; uint16_t sPortBase = 9000; @@ -222,6 +227,12 @@ void otSysInit(int argc, char *argv[]) DieNow(OT_EXIT_FAILURE); } +#if OPENTHREAD_PSA_CRYPTO_NATIVE_ITS_FILE && (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) + snprintf(sNativeItsFileNamePrefix, sizeof(sNativeItsFileNamePrefix), "%s/%s_%d_", + OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH, getenv("PORT_OFFSET") ? getenv("PORT_OFFSET") : "0", gNodeId); + gItsFileNamePrefix = sNativeItsFileNamePrefix; +#endif + socket_init(); platformAlarmInit(1); diff --git a/include/openthread/platform/crypto.h b/include/openthread/platform/crypto.h index c5997ee6f71..789990bf960 100644 --- a/include/openthread/platform/crypto.h +++ b/include/openthread/platform/crypto.h @@ -58,10 +58,11 @@ extern "C" { */ typedef enum { - OT_CRYPTO_KEY_TYPE_RAW, ///< Key Type: Raw Data. - OT_CRYPTO_KEY_TYPE_AES, ///< Key Type: AES. - OT_CRYPTO_KEY_TYPE_HMAC, ///< Key Type: HMAC. - OT_CRYPTO_KEY_TYPE_ECDSA, ///< Key Type: ECDSA. + OT_CRYPTO_KEY_TYPE_RAW, ///< Key Type: Raw Data. + OT_CRYPTO_KEY_TYPE_AES, ///< Key Type: AES. + OT_CRYPTO_KEY_TYPE_HMAC, ///< Key Type: HMAC. + OT_CRYPTO_KEY_TYPE_ECDSA, ///< Key Type: ECDSA. + OT_CRYPTO_KEY_TYPE_DERIVE, ///< Key Type: Derive. } otCryptoKeyType; /** @@ -73,6 +74,7 @@ typedef enum OT_CRYPTO_KEY_ALG_AES_ECB, ///< Key Algorithm: AES ECB. OT_CRYPTO_KEY_ALG_HMAC_SHA_256, ///< Key Algorithm: HMAC SHA-256. OT_CRYPTO_KEY_ALG_ECDSA, ///< Key Algorithm: ECDSA. + OT_CRYPTO_KEY_ALG_HKDF_SHA256, ///< Key Algorithm: HKDF SHA-256. } otCryptoKeyAlgorithm; /** @@ -86,6 +88,8 @@ enum OT_CRYPTO_KEY_USAGE_DECRYPT = 1 << 2, ///< Key Usage: AES ECB. OT_CRYPTO_KEY_USAGE_SIGN_HASH = 1 << 3, ///< Key Usage: Sign Hash. OT_CRYPTO_KEY_USAGE_VERIFY_HASH = 1 << 4, ///< Key Usage: Verify Hash. + OT_CRYPTO_KEY_USAGE_DERIVE = 1 << 5, ///< Key Usage: Derive. + }; /** diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index 0913a1e704c..16cdec68259 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -464,7 +464,8 @@ openthread_core_files = [ "crypto/aes_ecb.cpp", "crypto/aes_ecb.hpp", "crypto/context_size.hpp", - "crypto/crypto_platform.cpp", + "crypto/crypto_platform_mbedtls.cpp", + "crypto/crypto_platform_psa.cpp", "crypto/ecdsa.hpp", "crypto/hkdf_sha256.cpp", "crypto/hkdf_sha256.hpp", @@ -760,6 +761,8 @@ openthread_radio_sources = [ "common/error.hpp", "common/frame_builder.cpp", "common/frame_builder.hpp", + "common/heap.cpp", + "common/heap.hpp", "common/log.cpp", "common/random.cpp", "common/string.cpp", @@ -768,7 +771,8 @@ openthread_radio_sources = [ "common/uptime.cpp", "crypto/aes_ccm.cpp", "crypto/aes_ecb.cpp", - "crypto/crypto_platform.cpp", + "crypto/crypto_platform_mbedtls.cpp", + "crypto/crypto_platform_psa.cpp", "crypto/storage.cpp", "diags/factory_diags.cpp", "instance/instance.cpp", @@ -784,6 +788,8 @@ openthread_radio_sources = [ "radio/radio_callbacks.cpp", "radio/radio_platform.cpp", "thread/link_quality.cpp", + "utils/heap.cpp", + "utils/heap.hpp", "utils/parse_cmdline.cpp", "utils/power_calibration.cpp", ] diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6550ae80dd7..f5d8bcdb410 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -125,7 +125,8 @@ set(COMMON_SOURCES common/uptime.cpp crypto/aes_ccm.cpp crypto/aes_ecb.cpp - crypto/crypto_platform.cpp + crypto/crypto_platform_mbedtls.cpp + crypto/crypto_platform_psa.cpp crypto/hkdf_sha256.cpp crypto/hmac_sha256.cpp crypto/mbedtls.cpp @@ -278,6 +279,7 @@ set(RADIO_COMMON_SOURCES common/binary_search.cpp common/error.cpp common/frame_builder.cpp + common/heap.cpp common/log.cpp common/random.cpp common/string.cpp @@ -286,7 +288,9 @@ set(RADIO_COMMON_SOURCES common/uptime.cpp crypto/aes_ccm.cpp crypto/aes_ecb.cpp - crypto/crypto_platform.cpp + crypto/crypto_platform_mbedtls.cpp + crypto/crypto_platform_psa.cpp + crypto/mbedtls.cpp crypto/storage.cpp diags/factory_diags.cpp instance/instance.cpp @@ -302,6 +306,7 @@ set(RADIO_COMMON_SOURCES radio/radio_callbacks.cpp radio/radio_platform.cpp thread/link_quality.cpp + utils/heap.cpp utils/parse_cmdline.cpp utils/power_calibration.cpp ) diff --git a/src/core/common/heap.cpp b/src/core/common/heap.cpp index cc403467be1..2011382df84 100644 --- a/src/core/common/heap.cpp +++ b/src/core/common/heap.cpp @@ -44,7 +44,7 @@ void *CAlloc(size_t aCount, size_t aSize) { return otPlatCAlloc(aCount, aSize); void Free(void *aPointer) { otPlatFree(aPointer); } -#else +#elif OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE void *CAlloc(size_t aCount, size_t aSize) { return Instance::GetHeap().CAlloc(aCount, aSize); } diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index 044cf894878..0251bb4c2f1 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -156,7 +156,7 @@ uint16_t MessagePool::GetFreeBufferCount(void) const uint16_t rval; #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE -#if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#if OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE rval = static_cast(Instance::GetHeap().GetFreeSize() / sizeof(Buffer)); #else rval = NumericLimits::kMax; @@ -175,7 +175,7 @@ uint16_t MessagePool::GetTotalBufferCount(void) const uint16_t rval; #if OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE -#if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#if OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE rval = static_cast(Instance::GetHeap().GetCapacity() / sizeof(Buffer)); #else rval = NumericLimits::kMax; diff --git a/src/core/config/misc.h b/src/core/config/misc.h index 7fb9139d7bb..65aa6059ad5 100644 --- a/src/core/config/misc.h +++ b/src/core/config/misc.h @@ -44,6 +44,7 @@ */ #include "config/coap.h" +#include "config/crypto.h" #include "config/srp_server.h" /** @@ -316,6 +317,22 @@ #define OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE 0 #endif +/** + * @def OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE + * + * Enable the internal heap. + * + * This configuration is automatically enabled by default when an external heap is disabled. + * It is applicable for FTD and MTD builds. Additionally, if PSA library is used, it requires + * heap memory also for Radio build. + * + */ +#ifndef OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE +#define OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE \ + (!OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE && \ + (OPENTHREAD_MTD || OPENTHREAD_FTD || (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA))) +#endif + /** * @def OPENTHREAD_CONFIG_DTLS_APPLICATION_DATA_MAX_LENGTH * diff --git a/src/core/config/platform.h b/src/core/config/platform.h index bba3c9ced8c..87bf6baf5ff 100644 --- a/src/core/config/platform.h +++ b/src/core/config/platform.h @@ -34,7 +34,7 @@ #ifndef CONFIG_PLATFORM_H_ #define CONFIG_PLATFORM_H_ -#include "config/srp_server.h" +#include "config/crypto.h" /** * @addtogroup config-platform @@ -154,9 +154,13 @@ * @def OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE * * Define to 1 if you want to enable key ref usage support as defined by platform. + * + * This config is enabled by default for PSA Crypto backend. + * */ #ifndef OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE -#define OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 0 +#define OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE \ + (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) #endif /** diff --git a/src/core/crypto/crypto_platform.cpp b/src/core/crypto/crypto_platform_mbedtls.cpp similarity index 91% rename from src/core/crypto/crypto_platform.cpp rename to src/core/crypto/crypto_platform_mbedtls.cpp index edde102c38a..0b1ac457000 100644 --- a/src/core/crypto/crypto_platform.cpp +++ b/src/core/crypto/crypto_platform_mbedtls.cpp @@ -750,74 +750,4 @@ OT_TOOL_WEAK otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword, #endif // #if OPENTHREAD_FTD -#elif OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA - -#if OPENTHREAD_FTD || OPENTHREAD_MTD -#if OPENTHREAD_CONFIG_ECDSA_ENABLE - -OT_TOOL_WEAK otError otPlatCryptoEcdsaGenerateKey(otPlatCryptoEcdsaKeyPair *aKeyPair) -{ - OT_UNUSED_VARIABLE(aKeyPair); - - return OT_ERROR_NOT_CAPABLE; -} - -OT_TOOL_WEAK otError otPlatCryptoEcdsaGetPublicKey(const otPlatCryptoEcdsaKeyPair *aKeyPair, - otPlatCryptoEcdsaPublicKey *aPublicKey) -{ - OT_UNUSED_VARIABLE(aKeyPair); - OT_UNUSED_VARIABLE(aPublicKey); - - return OT_ERROR_NOT_CAPABLE; -} - -OT_TOOL_WEAK otError otPlatCryptoEcdsaSign(const otPlatCryptoEcdsaKeyPair *aKeyPair, - const otPlatCryptoSha256Hash *aHash, - otPlatCryptoEcdsaSignature *aSignature) -{ - OT_UNUSED_VARIABLE(aKeyPair); - OT_UNUSED_VARIABLE(aHash); - OT_UNUSED_VARIABLE(aSignature); - - return OT_ERROR_NOT_CAPABLE; -} - -OT_TOOL_WEAK otError otPlatCryptoEcdsaVerify(const otPlatCryptoEcdsaPublicKey *aPublicKey, - const otPlatCryptoSha256Hash *aHash, - const otPlatCryptoEcdsaSignature *aSignature) - -{ - OT_UNUSED_VARIABLE(aPublicKey); - OT_UNUSED_VARIABLE(aHash); - OT_UNUSED_VARIABLE(aSignature); - - return OT_ERROR_NOT_CAPABLE; -} -#endif // #if OPENTHREAD_CONFIG_ECDSA_ENABLE - -#endif // #if OPENTHREAD_FTD || OPENTHREAD_MTD - -#if OPENTHREAD_FTD - -OT_TOOL_WEAK otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword, - uint16_t aPasswordLen, - const uint8_t *aSalt, - uint16_t aSaltLen, - uint32_t aIterationCounter, - uint16_t aKeyLen, - uint8_t *aKey) -{ - OT_UNUSED_VARIABLE(aPassword); - OT_UNUSED_VARIABLE(aPasswordLen); - OT_UNUSED_VARIABLE(aSalt); - OT_UNUSED_VARIABLE(aSaltLen); - OT_UNUSED_VARIABLE(aIterationCounter); - OT_UNUSED_VARIABLE(aKeyLen); - OT_UNUSED_VARIABLE(aKey); - - return OT_ERROR_NOT_CAPABLE; -} - -#endif // #if OPENTHREAD_FTD - #endif // #if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_MBEDTLS diff --git a/src/core/crypto/crypto_platform_psa.cpp b/src/core/crypto/crypto_platform_psa.cpp new file mode 100644 index 00000000000..5595372ec97 --- /dev/null +++ b/src/core/crypto/crypto_platform_psa.cpp @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2025, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the Crypto platform callbacks into OpenThread and default/weak Crypto platform APIs + * using ARM PSA API. + */ + +#include "openthread-core-config.h" + +#include + +#include +#include + +#include +#include +#include + +#include "common/code_utils.hpp" +#include "common/debug.hpp" +#include "common/new.hpp" +#include "config/crypto.h" +#include "crypto/ecdsa.hpp" +#include "crypto/hmac_sha256.hpp" +#include "crypto/storage.hpp" +#include "instance/instance.hpp" + +using namespace ot; +using namespace Crypto; + +#if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA + +//--------------------------------------------------------------------------------------------------------------------- +// Default/weak implementation of crypto platform APIs + +static otError psaToOtError(psa_status_t aStatus) +{ + switch (aStatus) + { + case PSA_SUCCESS: + return kErrorNone; + case PSA_ERROR_INVALID_ARGUMENT: + return kErrorInvalidArgs; + case PSA_ERROR_BUFFER_TOO_SMALL: + return kErrorNoBufs; + default: + return kErrorFailed; + } +} + +static psa_key_type_t toPsaKeyType(otCryptoKeyType aType) +{ + switch (aType) + { + case OT_CRYPTO_KEY_TYPE_RAW: + return PSA_KEY_TYPE_RAW_DATA; + case OT_CRYPTO_KEY_TYPE_AES: + return PSA_KEY_TYPE_AES; + case OT_CRYPTO_KEY_TYPE_HMAC: + return PSA_KEY_TYPE_HMAC; + case OT_CRYPTO_KEY_TYPE_ECDSA: + return PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); + case OT_CRYPTO_KEY_TYPE_DERIVE: + return PSA_KEY_TYPE_DERIVE; + default: + return PSA_KEY_TYPE_NONE; + } +} + +static psa_algorithm_t toPsaAlgorithm(otCryptoKeyAlgorithm aAlgorithm) +{ + switch (aAlgorithm) + { + case OT_CRYPTO_KEY_ALG_AES_ECB: + return PSA_ALG_ECB_NO_PADDING; + case OT_CRYPTO_KEY_ALG_HMAC_SHA_256: + return PSA_ALG_HMAC(PSA_ALG_SHA_256); + case OT_CRYPTO_KEY_ALG_ECDSA: + return PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256); + case OT_CRYPTO_KEY_ALG_HKDF_SHA256: + return PSA_ALG_HKDF(PSA_ALG_SHA_256); + default: + return PSA_ALG_NONE; + } +} + +static psa_key_usage_t toPsaKeyUsage(int aUsage) +{ + psa_key_usage_t usage = 0; + + if (aUsage & OT_CRYPTO_KEY_USAGE_EXPORT) + { + usage |= PSA_KEY_USAGE_EXPORT; + } + + if (aUsage & OT_CRYPTO_KEY_USAGE_ENCRYPT) + { + usage |= PSA_KEY_USAGE_ENCRYPT; + } + + if (aUsage & OT_CRYPTO_KEY_USAGE_DECRYPT) + { + usage |= PSA_KEY_USAGE_DECRYPT; + } + + if (aUsage & OT_CRYPTO_KEY_USAGE_SIGN_HASH) + { + usage |= PSA_KEY_USAGE_SIGN_HASH; + } + + if (aUsage & OT_CRYPTO_KEY_USAGE_VERIFY_HASH) + { + usage |= PSA_KEY_USAGE_VERIFY_HASH; + } + + if (aUsage & OT_CRYPTO_KEY_USAGE_DERIVE) + { + usage |= PSA_KEY_USAGE_DERIVE; + } + + return usage; +} + +static bool checkKeyUsage(int aUsage) +{ + /* Check if only supported flags have been passed */ + int supportedFlags = OT_CRYPTO_KEY_USAGE_EXPORT | OT_CRYPTO_KEY_USAGE_ENCRYPT | OT_CRYPTO_KEY_USAGE_DECRYPT | + OT_CRYPTO_KEY_USAGE_SIGN_HASH | OT_CRYPTO_KEY_USAGE_VERIFY_HASH | OT_CRYPTO_KEY_USAGE_DERIVE; + + return (aUsage & ~supportedFlags) == 0; +} + +static bool checkContext(otCryptoContext *aContext, size_t aMinSize) +{ + /* Verify that the passed context is initialized and points to a big enough buffer */ + return aContext != nullptr && aContext->mContext != nullptr && aContext->mContextSize >= aMinSize; +} + +static otError extractPrivateKeyInfo(const uint8_t *aAsn1KeyPair, + size_t aAsn1KeyPairLen, + size_t *aKeyOffset, + size_t *aKeyLen) +{ + Error error = kErrorNone; + unsigned char *p = const_cast(aAsn1KeyPair); + const unsigned char *end = p + aAsn1KeyPairLen; + size_t len; + + // Parse the ASN.1 SEQUENCE headers + int ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); + VerifyOrExit(ret == 0, error = kErrorInvalidArgs); + + // Parse the version (INTEGER) + ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER); + VerifyOrExit(ret == 0, error = kErrorInvalidArgs); + + // Skip the version. + p += len; // Skip over the version + + // Parse the private key (OCTET STRING) + ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); + VerifyOrExit(ret == 0, error = kErrorInvalidArgs); + + // Check if the private key includes a padding byte (0x00) + if (*p == 0x00) + { + p++; + len--; // Skip the padding byte and reduce length by 1 + } + + *aKeyOffset = (p - aAsn1KeyPair); + *aKeyLen = len; + +exit: + return error; +} + +OT_TOOL_WEAK void otPlatCryptoInit(void) { psa_crypto_init(); } + +OT_TOOL_WEAK otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, + otCryptoKeyType aKeyType, + otCryptoKeyAlgorithm aKeyAlgorithm, + int aKeyUsage, + otCryptoKeyStorage aKeyPersistence, + const uint8_t *aKey, + size_t aKeyLen) +{ + Error error = kErrorNone; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status = PSA_SUCCESS; + + VerifyOrExit(checkKeyUsage(aKeyUsage), error = kErrorInvalidArgs); + VerifyOrExit(aKeyRef != nullptr && aKey != nullptr, error = kErrorInvalidArgs); + + // PSA Crypto API expects the private key to be provided, not the full ASN1 buffer. + if (aKeyType == OT_CRYPTO_KEY_TYPE_ECDSA) + { + size_t pkOffset; + size_t pkLength; + + SuccessOrExit(error = extractPrivateKeyInfo(aKey, aKeyLen, &pkOffset, &pkLength)); + + // Overwrite the content of the key. + aKey += pkOffset; + aKeyLen = pkLength; + + psa_set_key_bits(&attributes, 256); + } + + psa_set_key_type(&attributes, toPsaKeyType(aKeyType)); + psa_set_key_algorithm(&attributes, toPsaAlgorithm(aKeyAlgorithm)); + psa_set_key_usage_flags(&attributes, toPsaKeyUsage(aKeyUsage)); + + switch (aKeyPersistence) + { + case OT_CRYPTO_KEY_STORAGE_PERSISTENT: + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&attributes, *aKeyRef); + break; + case OT_CRYPTO_KEY_STORAGE_VOLATILE: + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); + break; + default: + OT_ASSERT(false); + } + + status = psa_import_key(&attributes, aKey, aKeyLen, aKeyRef); + +exit: + psa_reset_key_attributes(&attributes); + + if (error != kErrorNone) + { + return error; + } + + return psaToOtError(status); +} + +OT_TOOL_WEAK otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, uint8_t *aBuffer, size_t aBufferLen, size_t *aKeyLen) +{ + Error error = kErrorNone; + + VerifyOrExit(aBuffer != nullptr && aKeyLen != nullptr, error = kErrorInvalidArgs); + + error = psaToOtError(psa_export_key(aKeyRef, aBuffer, aBufferLen, aKeyLen)); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoDestroyKey(otCryptoKeyRef aKeyRef) { return psaToOtError(psa_destroy_key(aKeyRef)); } + +OT_TOOL_WEAK bool otPlatCryptoHasKey(otCryptoKeyRef aKeyRef) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + + status = psa_get_key_attributes(aKeyRef, &attributes); + psa_reset_key_attributes(&attributes); + + return status == PSA_SUCCESS; +} + +OT_TOOL_WEAK otError otPlatCryptoAesInit(otCryptoContext *aContext) +{ + Error error = kErrorNone; + psa_key_id_t *keyRef; + + VerifyOrExit(checkContext(aContext, sizeof(psa_key_id_t)), error = kErrorInvalidArgs); + + keyRef = static_cast(aContext->mContext); + *keyRef = PSA_KEY_ID_NULL; + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoAesSetKey(otCryptoContext *aContext, const otCryptoKey *aKey) +{ + Error error = kErrorNone; + psa_key_id_t *keyRef; + + VerifyOrExit(checkContext(aContext, sizeof(psa_key_id_t)), error = kErrorInvalidArgs); + VerifyOrExit(aKey != nullptr, error = kErrorInvalidArgs); + + keyRef = static_cast(aContext->mContext); + *keyRef = aKey->mKeyRef; + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, uint8_t *aOutput) +{ + Error error = kErrorNone; + const size_t blockSize = PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES); + psa_status_t status = PSA_SUCCESS; + psa_key_id_t *keyRef; + size_t cipherLen; + + VerifyOrExit(checkContext(aContext, sizeof(psa_key_id_t)), error = kErrorInvalidArgs); + VerifyOrExit(aInput != nullptr && aOutput != nullptr, error = kErrorInvalidArgs); + + keyRef = static_cast(aContext->mContext); + status = psa_cipher_encrypt(*keyRef, PSA_ALG_ECB_NO_PADDING, aInput, blockSize, aOutput, blockSize, &cipherLen); + + error = psaToOtError(status); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoAesFree(otCryptoContext *aContext) +{ + OT_UNUSED_VARIABLE(aContext); + + return kErrorNone; +} + +#if !OPENTHREAD_RADIO + +OT_TOOL_WEAK otError otPlatCryptoHmacSha256Init(otCryptoContext *aContext) +{ + Error error = kErrorNone; + psa_mac_operation_t *operation; + + VerifyOrExit(checkContext(aContext, sizeof(psa_mac_operation_t)), error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + // Initialize the structure using memset as documented alternative for psa_mac_operation_init(). + memset(operation, 0, sizeof(*operation)); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoHmacSha256Deinit(otCryptoContext *aContext) +{ + Error error = kErrorNone; + psa_mac_operation_t *operation; + + VerifyOrExit(checkContext(aContext, sizeof(psa_mac_operation_t)), error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + error = psaToOtError(psa_mac_abort(operation)); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoHmacSha256Start(otCryptoContext *aContext, const otCryptoKey *aKey) +{ + Error error = kErrorNone; + psa_mac_operation_t *operation; + + VerifyOrExit(checkContext(aContext, sizeof(psa_mac_operation_t)), error = kErrorInvalidArgs); + VerifyOrExit(aKey != nullptr, error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + error = psaToOtError(psa_mac_sign_setup(operation, aKey->mKeyRef, PSA_ALG_HMAC(PSA_ALG_SHA_256))); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, const void *aBuf, uint16_t aBufLength) +{ + Error error = kErrorNone; + psa_mac_operation_t *operation; + + VerifyOrExit(checkContext(aContext, sizeof(psa_mac_operation_t)), error = kErrorInvalidArgs); + VerifyOrExit(aBuf != nullptr, error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + error = psaToOtError(psa_mac_update(operation, static_cast(aBuf), aBufLength)); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoHmacSha256Finish(otCryptoContext *aContext, uint8_t *aBuf, size_t aBufLength) +{ + Error error = kErrorNone; + psa_mac_operation_t *operation; + size_t macLength; + + VerifyOrExit(checkContext(aContext, sizeof(psa_mac_operation_t)), error = kErrorInvalidArgs); + VerifyOrExit(aBuf != nullptr, error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + error = psaToOtError(psa_mac_sign_finish(operation, aBuf, aBufLength, &macLength)); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoHkdfInit(otCryptoContext *aContext) +{ + Error error = kErrorNone; + psa_key_derivation_operation_t *operation; + + VerifyOrExit(checkContext(aContext, sizeof(psa_key_derivation_operation_t)), error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + *operation = PSA_KEY_DERIVATION_OPERATION_INIT; + + error = psaToOtError(psa_key_derivation_setup(operation, PSA_ALG_HKDF(PSA_ALG_SHA_256))); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoHkdfExtract(otCryptoContext *aContext, + const uint8_t *aSalt, + uint16_t aSaltLength, + const otCryptoKey *aInputKey) +{ + Error error = kErrorNone; + psa_status_t status = PSA_SUCCESS; + psa_key_derivation_operation_t *operation; + + VerifyOrExit(checkContext(aContext, sizeof(psa_key_derivation_operation_t)), error = kErrorInvalidArgs); + VerifyOrExit(aInputKey != nullptr, error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + status = psa_key_derivation_input_bytes(operation, PSA_KEY_DERIVATION_INPUT_SALT, aSalt, aSaltLength); + SuccessOrExit(error = psaToOtError(status)); + + status = psa_key_derivation_input_key(operation, PSA_KEY_DERIVATION_INPUT_SECRET, aInputKey->mKeyRef); + SuccessOrExit(error = psaToOtError(status)); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoHkdfExpand(otCryptoContext *aContext, + const uint8_t *aInfo, + uint16_t aInfoLength, + uint8_t *aOutputKey, + uint16_t aOutputKeyLength) +{ + Error error = kErrorNone; + psa_status_t status = PSA_SUCCESS; + psa_key_derivation_operation_t *operation; + + VerifyOrExit(checkContext(aContext, sizeof(psa_key_derivation_operation_t)), error = kErrorInvalidArgs); + VerifyOrExit(aOutputKey != nullptr, error = kErrorInvalidArgs); + VerifyOrExit(aOutputKeyLength != 0, error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + status = psa_key_derivation_input_bytes(operation, PSA_KEY_DERIVATION_INPUT_INFO, aInfo, aInfoLength); + SuccessOrExit(error = psaToOtError(status)); + + status = psa_key_derivation_output_bytes(operation, aOutputKey, aOutputKeyLength); + SuccessOrExit(error = psaToOtError(status)); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoHkdfDeinit(otCryptoContext *aContext) +{ + Error error = kErrorNone; + psa_key_derivation_operation_t *operation; + + VerifyOrExit(checkContext(aContext, sizeof(psa_key_derivation_operation_t)), error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + error = psaToOtError(psa_key_derivation_abort(operation)); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoSha256Init(otCryptoContext *aContext) +{ + Error error = kErrorNone; + psa_hash_operation_t *operation; + + VerifyOrExit(checkContext(aContext, sizeof(psa_hash_operation_t)), error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + // Initialize the structure using memset as documented alternative for psa_hash_operation_init(). + memset(operation, 0, sizeof(*operation)); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoSha256Deinit(otCryptoContext *aContext) +{ + Error error = kErrorNone; + psa_hash_operation_t *operation; + + VerifyOrExit(checkContext(aContext, sizeof(psa_hash_operation_t)), error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + error = psaToOtError(psa_hash_abort(operation)); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoSha256Start(otCryptoContext *aContext) +{ + Error error = kErrorNone; + psa_hash_operation_t *operation; + + VerifyOrExit(checkContext(aContext, sizeof(psa_hash_operation_t)), error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + error = psaToOtError(psa_hash_setup(operation, PSA_ALG_SHA_256)); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoSha256Update(otCryptoContext *aContext, const void *aBuf, uint16_t aBufLength) +{ + Error error = kErrorNone; + psa_hash_operation_t *operation; + + VerifyOrExit(checkContext(aContext, sizeof(psa_hash_operation_t)), error = kErrorInvalidArgs); + VerifyOrExit(aBuf != nullptr, error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + error = psaToOtError(psa_hash_update(operation, static_cast(aBuf), aBufLength)); + +exit: + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoSha256Finish(otCryptoContext *aContext, uint8_t *aHash, uint16_t aHashSize) +{ + Error error = kErrorNone; + psa_hash_operation_t *operation; + size_t hashSize; + + VerifyOrExit(checkContext(aContext, sizeof(psa_hash_operation_t)), error = kErrorInvalidArgs); + VerifyOrExit(aHash != nullptr, error = kErrorInvalidArgs); + + operation = static_cast(aContext->mContext); + + error = psaToOtError(psa_hash_finish(operation, aHash, aHashSize, &hashSize)); + +exit: + return error; +} + +OT_TOOL_WEAK void otPlatCryptoRandomInit(void) { psa_crypto_init(); } + +OT_TOOL_WEAK void otPlatCryptoRandomDeinit(void) +{ + // Intentionally empty +} + +OT_TOOL_WEAK otError otPlatCryptoRandomGet(uint8_t *aBuffer, uint16_t aSize) +{ + return psaToOtError(psa_generate_random(aBuffer, aSize)); +} + +#if OPENTHREAD_CONFIG_ECDSA_ENABLE + +OT_TOOL_WEAK otError otPlatCryptoEcdsaGenerateAndImportKey(otCryptoKeyRef aKeyRef) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + psa_key_id_t keyId = static_cast(aKeyRef); + + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_SIGN_HASH); + psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&attributes, keyId); + psa_set_key_bits(&attributes, 256); + + status = psa_generate_key(&attributes, &keyId); + VerifyOrExit(status == PSA_SUCCESS); + +exit: + psa_reset_key_attributes(&attributes); + + return psaToOtError(status); +} + +OT_TOOL_WEAK otError otPlatCryptoEcdsaExportPublicKey(otCryptoKeyRef aKeyRef, otPlatCryptoEcdsaPublicKey *aPublicKey) +{ + psa_status_t status; + size_t exportedLen; + uint8_t buffer[1 + OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE]; + + status = psa_export_public_key(aKeyRef, buffer, sizeof(buffer), &exportedLen); + VerifyOrExit(status == PSA_SUCCESS); + + OT_ASSERT(exportedLen == sizeof(buffer)); + memcpy(aPublicKey->m8, buffer + 1, OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE); + +exit: + return psaToOtError(status); +} + +OT_TOOL_WEAK otError otPlatCryptoEcdsaSignUsingKeyRef(otCryptoKeyRef aKeyRef, + const otPlatCryptoSha256Hash *aHash, + otPlatCryptoEcdsaSignature *aSignature) +{ + psa_status_t status; + size_t signatureLen; + + status = psa_sign_hash(aKeyRef, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), aHash->m8, OT_CRYPTO_SHA256_HASH_SIZE, + aSignature->m8, OT_CRYPTO_ECDSA_SIGNATURE_SIZE, &signatureLen); + VerifyOrExit(status == PSA_SUCCESS); + + OT_ASSERT(signatureLen == OT_CRYPTO_ECDSA_SIGNATURE_SIZE); + +exit: + return psaToOtError(status); +} + +OT_TOOL_WEAK otError otPlatCryptoEcdsaVerify(const otPlatCryptoEcdsaPublicKey *aPublicKey, + const otPlatCryptoSha256Hash *aHash, + const otPlatCryptoEcdsaSignature *aSignature) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t keyId; + psa_status_t status; + uint8_t buffer[1 + OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE]; + + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, 256); + + /* + * `psa_import_key` expects a key format as specified by SEC1 §2.3.3 for the + * uncompressed representation of the ECPoint. + */ + buffer[0] = 0x04; + memcpy(buffer + 1, aPublicKey->m8, OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE); + + status = psa_import_key(&attributes, buffer, sizeof(buffer), &keyId); + VerifyOrExit(status == PSA_SUCCESS); + + status = psa_verify_hash(keyId, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), aHash->m8, OT_CRYPTO_SHA256_HASH_SIZE, + aSignature->m8, OT_CRYPTO_ECDSA_SIGNATURE_SIZE); + VerifyOrExit(status == PSA_SUCCESS); + +exit: + psa_reset_key_attributes(&attributes); + psa_destroy_key(keyId); + + return psaToOtError(status); +} + +OT_TOOL_WEAK otError otPlatCryptoEcdsaVerifyUsingKeyRef(otCryptoKeyRef aKeyRef, + const otPlatCryptoSha256Hash *aHash, + const otPlatCryptoEcdsaSignature *aSignature) +{ + psa_status_t status; + + status = psa_verify_hash(aKeyRef, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), aHash->m8, + OT_CRYPTO_SHA256_HASH_SIZE, aSignature->m8, OT_CRYPTO_ECDSA_SIGNATURE_SIZE); + VerifyOrExit(status == PSA_SUCCESS); + +exit: + return psaToOtError(status); +} + +#endif // #if OPENTHREAD_CONFIG_ECDSA_ENABLE + +#endif // #if !OPENTHREAD_RADIO + +#if OPENTHREAD_FTD + +OT_TOOL_WEAK otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword, + uint16_t aPasswordLen, + const uint8_t *aSalt, + uint16_t aSaltLen, + uint32_t aIterationCounter, + uint16_t aKeyLen, + uint8_t *aKey) +{ + psa_status_t status = PSA_SUCCESS; + psa_key_id_t key_id = PSA_KEY_ID_NULL; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_algorithm_t algorithm = PSA_ALG_PBKDF2_AES_CMAC_PRF_128; + psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; + + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_algorithm(&attributes, algorithm); + psa_set_key_type(&attributes, PSA_KEY_TYPE_PASSWORD); + psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(aPasswordLen)); + + status = psa_import_key(&attributes, aPassword, aPasswordLen, &key_id); + VerifyOrExit(status == PSA_SUCCESS); + + status = psa_key_derivation_setup(&operation, algorithm); + VerifyOrExit(status == PSA_SUCCESS); + + status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, aIterationCounter); + VerifyOrExit(status == PSA_SUCCESS); + + status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, aSalt, aSaltLen); + VerifyOrExit(status == PSA_SUCCESS); + + status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, key_id); + VerifyOrExit(status == PSA_SUCCESS); + + status = psa_key_derivation_output_bytes(&operation, aKey, aKeyLen); + VerifyOrExit(status == PSA_SUCCESS); + +exit: + psa_reset_key_attributes(&attributes); + psa_key_derivation_abort(&operation); + psa_destroy_key(key_id); + + return psaToOtError(status); +} + +#endif // #if OPENTHREAD_FTD + +#endif // #if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA diff --git a/src/core/crypto/storage.hpp b/src/core/crypto/storage.hpp index 5649c08d2d7..afb38b864b4 100644 --- a/src/core/crypto/storage.hpp +++ b/src/core/crypto/storage.hpp @@ -57,10 +57,11 @@ namespace Storage { */ enum KeyType : uint8_t { - kKeyTypeRaw = OT_CRYPTO_KEY_TYPE_RAW, ///< Key Type: Raw Data. - kKeyTypeAes = OT_CRYPTO_KEY_TYPE_AES, ///< Key Type: AES. - kKeyTypeHmac = OT_CRYPTO_KEY_TYPE_HMAC, ///< Key Type: HMAC. - kKeyTypeEcdsa = OT_CRYPTO_KEY_TYPE_ECDSA, ///< Key Type: ECDSA. + kKeyTypeRaw = OT_CRYPTO_KEY_TYPE_RAW, ///< Key Type: Raw Data. + kKeyTypeAes = OT_CRYPTO_KEY_TYPE_AES, ///< Key Type: AES. + kKeyTypeHmac = OT_CRYPTO_KEY_TYPE_HMAC, ///< Key Type: HMAC. + kKeyTypeEcdsa = OT_CRYPTO_KEY_TYPE_ECDSA, ///< Key Type: ECDSA. + kKeyTypeDerive = OT_CRYPTO_KEY_TYPE_DERIVE, ///< Key Type: Derive. }; /** @@ -72,6 +73,7 @@ enum KeyAlgorithm : uint8_t kKeyAlgorithmAesEcb = OT_CRYPTO_KEY_ALG_AES_ECB, ///< Key Algorithm: AES ECB. kKeyAlgorithmHmacSha256 = OT_CRYPTO_KEY_ALG_HMAC_SHA_256, ///< Key Algorithm: HMAC SHA-256. kKeyAlgorithmEcdsa = OT_CRYPTO_KEY_ALG_ECDSA, ///< Key Algorithm: ECDSA. + kKeyAlgorithmHkdfSha256 = OT_CRYPTO_KEY_ALG_HKDF_SHA256, ///< Key Algorithm: HKDF SHA-256. }; constexpr uint8_t kUsageNone = OT_CRYPTO_KEY_USAGE_NONE; ///< Key Usage: Key Usage is empty. @@ -80,6 +82,7 @@ constexpr uint8_t kUsageEncrypt = OT_CRYPTO_KEY_USAGE_ENCRYPT; ///< Key U constexpr uint8_t kUsageDecrypt = OT_CRYPTO_KEY_USAGE_DECRYPT; ///< Key Usage: AES ECB. constexpr uint8_t kUsageSignHash = OT_CRYPTO_KEY_USAGE_SIGN_HASH; ///< Key Usage: Sign Hash. constexpr uint8_t kUsageVerifyHash = OT_CRYPTO_KEY_USAGE_VERIFY_HASH; ///< Key Usage: Verify Hash. +constexpr uint8_t kUsageDerive = OT_CRYPTO_KEY_USAGE_DERIVE; ///< Key Usage: Derive. /** * Defines the key storage types. diff --git a/src/core/instance/instance.cpp b/src/core/instance/instance.cpp index 48f341526cf..b3c8d23bae5 100644 --- a/src/core/instance/instance.cpp +++ b/src/core/instance/instance.cpp @@ -57,11 +57,12 @@ static uint64_t gMultiInstanceRaw[MULTI_INSTANCE_SIZE]; #endif -#if OPENTHREAD_MTD || OPENTHREAD_FTD -#if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#if OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE OT_DEFINE_ALIGNED_VAR(sHeapRaw, sizeof(Utils::Heap), uint64_t); Utils::Heap *Instance::sHeap{nullptr}; #endif + +#if OPENTHREAD_MTD || OPENTHREAD_FTD #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE bool Instance::sDnsNameCompressionEnabled = true; #endif @@ -279,6 +280,7 @@ Instance::Instance(void) , mIsInitialized(false) , mId(Random::NonCrypto::GetUint32()) { +#if OPENTHREAD_MTD || OPENTHREAD_FTD #if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE && OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE #if OPENTHREAD_CONFIG_MULTIPLE_STATIC_INSTANCE_ENABLE mCryptoStorageKeyRefManager.SetKeyRefExtraOffset(Crypto::Storage::KeyRefManager::kKeyRefExtraOffset * GetIdx(this)); @@ -287,9 +289,10 @@ Instance::Instance(void) "The `KeyRef` values will be shared across different `Instance` objects" #endif #endif +#endif } -#if (OPENTHREAD_MTD || OPENTHREAD_FTD) && !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#if OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE Utils::Heap &Instance::GetHeap(void) { if (nullptr == sHeap) diff --git a/src/core/instance/instance.hpp b/src/core/instance/instance.hpp index ac48d6c4379..c079ee1b99c 100644 --- a/src/core/instance/instance.hpp +++ b/src/core/instance/instance.hpp @@ -60,10 +60,12 @@ #include "common/timer.hpp" #include "common/type_traits.hpp" #include "common/uptime.hpp" +#include "crypto/mbedtls.hpp" #include "diags/factory_diags.hpp" #include "instance/extension.hpp" #include "mac/link_raw.hpp" #include "radio/radio.hpp" +#include "utils/heap.hpp" #include "utils/otns.hpp" #include "utils/power_calibration.hpp" #include "utils/static_counter.hpp" @@ -78,7 +80,6 @@ #include "common/code_utils.hpp" #include "common/notifier.hpp" #include "common/settings.hpp" -#include "crypto/mbedtls.hpp" #include "crypto/storage.hpp" #include "mac/mac.hpp" #include "mac/wakeup_tx_scheduler.hpp" @@ -136,7 +137,6 @@ #include "thread/tmf.hpp" #include "utils/channel_manager.hpp" #include "utils/channel_monitor.hpp" -#include "utils/heap.hpp" #include "utils/history_tracker.hpp" #include "utils/jam_detector.hpp" #include "utils/link_metrics_manager.hpp" @@ -329,6 +329,15 @@ class Instance : public otInstance, private NonCopyable */ void Finalize(void); +#if OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE + /** + * Returns a reference to the Heap object. + * + * @returns A reference to the Heap object. + */ + static Utils::Heap &GetHeap(void); +#endif + #if OPENTHREAD_MTD || OPENTHREAD_FTD /** * Deletes all the settings stored in non-volatile memory, and then triggers a platform reset. @@ -345,15 +354,6 @@ class Instance : public otInstance, private NonCopyable */ Error ErasePersistentInfo(void); -#if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE - /** - * Returns a reference to the Heap object. - * - * @returns A reference to the Heap object. - */ - static Utils::Heap &GetHeap(void); -#endif - #if OPENTHREAD_CONFIG_COAP_API_ENABLE /** * Returns a reference to application COAP object. @@ -449,7 +449,7 @@ class Instance : public otInstance, private NonCopyable static LogLevel sLogLevel; #endif -#if (OPENTHREAD_MTD || OPENTHREAD_FTD) && !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#if OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE static Utils::Heap *sHeap; #endif @@ -471,7 +471,7 @@ class Instance : public otInstance, private NonCopyable TimerMicro::Scheduler mTimerMicroScheduler; #endif -#if OPENTHREAD_MTD || OPENTHREAD_FTD +#if OPENTHREAD_MTD || OPENTHREAD_FTD || (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) // Random::Manager is initialized before other objects. Note that it // requires MbedTls which itself may use Heap. Crypto::MbedTls mMbedTls; diff --git a/src/core/mac/link_raw.cpp b/src/core/mac/link_raw.cpp index db5d5c86621..3115f5bb3e6 100644 --- a/src/core/mac/link_raw.cpp +++ b/src/core/mac/link_raw.cpp @@ -58,6 +58,8 @@ LinkRaw::LinkRaw(Instance &aInstance) , mSubMac(aInstance.Get()) #endif { + otPlatCryptoInit(); + Init(); } diff --git a/src/core/meshcop/tcat_agent.cpp b/src/core/meshcop/tcat_agent.cpp index c98850aa5eb..6ab326a7640 100644 --- a/src/core/meshcop/tcat_agent.cpp +++ b/src/core/meshcop/tcat_agent.cpp @@ -839,12 +839,31 @@ void TcatAgent::CalculateHash(uint64_t aChallenge, const char *aBuf, size_t aBuf Crypto::Key cryptoKey; Crypto::HmacSha256 hmac; +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::KeyRef keyRef; + Error error; + + error = Crypto::Storage::ImportKey(keyRef, Crypto::Storage::kKeyTypeHmac, Crypto::Storage::kKeyAlgorithmHmacSha256, + Crypto::Storage::kUsageSignHash, Crypto::Storage::kTypeVolatile, + reinterpret_cast(aBuf), aBufLen); + SuccessOrExit(error); + + cryptoKey.SetAsKeyRef(keyRef); +#else cryptoKey.Set(reinterpret_cast(aBuf), static_cast(aBufLen)); +#endif hmac.Start(cryptoKey); hmac.Update(aChallenge); hmac.Update(rawKey.p, static_cast(rawKey.len)); hmac.Finish(aHash); + +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::DestroyKey(keyRef); + +exit: + return; +#endif } Error TcatAgent::HandleStartThreadInterface(void) diff --git a/src/core/thread/key_manager.cpp b/src/core/thread/key_manager.cpp index a9ab0b0ff70..46c278f2e97 100644 --- a/src/core/thread/key_manager.cpp +++ b/src/core/thread/key_manager.cpp @@ -179,17 +179,10 @@ KeyManager::KeyManager(Instance &aInstance) otPlatCryptoInit(); #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - { - NetworkKey networkKey; - - mNetworkKeyRef = Crypto::Storage::kInvalidKeyRef; - mPskcRef = Crypto::Storage::kInvalidKeyRef; - - IgnoreError(networkKey.GenerateRandom()); - StoreNetworkKey(networkKey, /* aOverWriteExisting */ false); - } + mNetworkKeyRef = Crypto::Storage::kInvalidKeyRef; + mPskcRef = Crypto::Storage::kInvalidKeyRef; #else - IgnoreError(mNetworkKey.GenerateRandom()); + mNetworkKey.Clear(); mPskc.Clear(); #endif @@ -200,6 +193,22 @@ void KeyManager::Start(void) { mKeySwitchGuardTimer = 0; ResetKeyRotationTimer(); + +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + NetworkKey networkKey; + + // Generate random Network Key, if there is none currently. + if (mNetworkKeyRef == Crypto::Storage::kInvalidKeyRef) + { + IgnoreError(networkKey.GenerateRandom()); + SetNetworkKey(networkKey); + } +#else + if (mNetworkKey.IsEmpty()) + { + mNetworkKey.GenerateRandom(); + } +#endif } void KeyManager::Stop(void) { mKeyRotationTimer.Stop(); } @@ -313,7 +322,18 @@ void KeyManager::ComputeTrelKey(uint32_t aKeySequence, Mac::Key &aKey) const Crypto::Key cryptoKey; #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - cryptoKey.SetAsKeyRef(mNetworkKeyRef); + Crypto::Storage::KeyRef keyRef; + NetworkKey networkKey; + + GetNetworkKey(networkKey); + + // Create temporary key to perform derive operation. This might be improved by using key copy operation, + // however NetworkKey is exported for the other cases. + SuccessOrAssert(Crypto::Storage::ImportKey(keyRef, Crypto::Storage::kKeyTypeDerive, + Crypto::Storage::kKeyAlgorithmHkdfSha256, Crypto::Storage::kUsageDerive, + Crypto::Storage::kTypeVolatile, networkKey.m8, NetworkKey::kSize)); + + cryptoKey.SetAsKeyRef(keyRef); #else cryptoKey.Set(mNetworkKey.m8, NetworkKey::kSize); #endif @@ -323,6 +343,10 @@ void KeyManager::ComputeTrelKey(uint32_t aKeySequence, Mac::Key &aKey) const hkdf.Extract(salt, sizeof(salt), cryptoKey); hkdf.Expand(kTrelInfoString, sizeof(kTrelInfoString), aKey.m8, Mac::Key::kSize); + +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::DestroyKey(keyRef); +#endif } #endif @@ -330,6 +354,12 @@ void KeyManager::UpdateKeyMaterial(void) { HashKeys hashKeys; +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + VerifyOrExit(Crypto::Storage::IsKeyRefValid(mNetworkKeyRef)); +#else + VerifyOrExit(!mNetworkKey.IsEmpty()); +#endif + ComputeKeys(mKeySequence, hashKeys); mMleKey.SetFrom(hashKeys.GetMleKey()); @@ -360,6 +390,9 @@ void KeyManager::UpdateKeyMaterial(void) mTrelKey.SetFrom(key); } #endif + +exit: + return; } void KeyManager::SetCurrentKeySequence(uint32_t aKeySequence, KeySeqUpdateFlags aFlags) @@ -696,7 +729,13 @@ void KeyManager::DestroyTemporaryKeys(void) Get().ClearMode2Key(); } -void KeyManager::DestroyPersistentKeys(void) { Get().DestroyPersistentKeys(); } +void KeyManager::DestroyPersistentKeys(void) +{ + Get().DestroyPersistentKeys(); + + mNetworkKeyRef = Crypto::Storage::kInvalidKeyRef; + mPskcRef = Crypto::Storage::kInvalidKeyRef; +} #endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE diff --git a/src/core/thread/key_manager.hpp b/src/core/thread/key_manager.hpp index 11e73809765..8601fa01ce4 100644 --- a/src/core/thread/key_manager.hpp +++ b/src/core/thread/key_manager.hpp @@ -148,6 +148,25 @@ class NetworkKey : public otNetworkKey, public Equatable, public Cle * @retval kErrorFailed Failed to generate random sequence. */ Error GenerateRandom(void) { return Random::Crypto::Fill(*this); } + + /** + * Checks if the Network Key is empty (all bytes are zero). + * + * @retval true The key is empty. + * @retval false The key is not empty. + */ + bool IsEmpty(void) + { + for (uint8_t i = 0; i < kSize; i++) + { + if (m8[i] != 0) + { + return false; + } + } + + return true; + } #endif } OT_TOOL_PACKED_END; diff --git a/src/core/utils/heap.cpp b/src/core/utils/heap.cpp index e21d938d129..898f1eecb6d 100644 --- a/src/core/utils/heap.cpp +++ b/src/core/utils/heap.cpp @@ -33,7 +33,7 @@ #include "heap.hpp" -#if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#if OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE #include @@ -219,4 +219,4 @@ void Heap::Free(void *aPointer) } // namespace Utils } // namespace ot -#endif // !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#endif // OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE diff --git a/src/core/utils/heap.hpp b/src/core/utils/heap.hpp index 415a4c0d6f5..32770aa5c7f 100644 --- a/src/core/utils/heap.hpp +++ b/src/core/utils/heap.hpp @@ -36,7 +36,7 @@ #include "openthread-core-config.h" -#if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#if OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE #include #include @@ -323,6 +323,6 @@ class Heap : private NonCopyable } // namespace Utils } // namespace ot -#endif // !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#endif // OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE #endif // OT_UTILS_HEAP_HPP_ diff --git a/src/posix/platform/CMakeLists.txt b/src/posix/platform/CMakeLists.txt index 923c4e284a3..af1fb3a21fb 100644 --- a/src/posix/platform/CMakeLists.txt +++ b/src/posix/platform/CMakeLists.txt @@ -172,6 +172,8 @@ target_link_libraries(openthread-posix ot-config-ftd ot-config ot-posix-config + mbedtls + openthread-native-its-file $<$>:util> $<$:rt> ) diff --git a/src/posix/platform/entropy.cpp b/src/posix/platform/entropy.cpp index 2dc98e3d22a..d9a3d80eca1 100644 --- a/src/posix/platform/entropy.cpp +++ b/src/posix/platform/entropy.cpp @@ -40,6 +40,10 @@ #include #include +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) +#include +#endif + #include "common/code_utils.hpp" #ifndef __SANITIZE_ADDRESS__ @@ -135,3 +139,33 @@ otError otPlatEntropyGet(uint8_t *aOutput, uint16_t aOutputLength) return error; } + +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +/** + * When OpenThread is compiled with the PSA Crypto backend using Mbed TLS 3.x, there is no + * API to configure a dedicated non-default entropy source. It is documented that a future version of + * Mbed TLS (likely 4.x) will include a PSA interface for configuring entropy sources. + * + * For now, we need to define the external RNG. Since the implementation of `otPlatEntropyGet` already + * uses CSPRNG, we will call it here as well. + */ +extern "C" psa_status_t mbedtls_psa_external_get_random(mbedtls_psa_external_random_context_t *context, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + OT_UNUSED_VARIABLE(context); + + otError error; + psa_status_t status = PSA_ERROR_GENERIC_ERROR; + + error = otPlatEntropyGet(output, (uint16_t)output_size); + if (error == OT_ERROR_NONE) + { + *output_length = output_size; + status = PSA_SUCCESS; + } + + return status; +} +#endif diff --git a/src/posix/platform/openthread-core-posix-config.h b/src/posix/platform/openthread-core-posix-config.h index 582117494f4..c963291b6a3 100644 --- a/src/posix/platform/openthread-core-posix-config.h +++ b/src/posix/platform/openthread-core-posix-config.h @@ -156,6 +156,18 @@ #define OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE 1 #endif +#ifndef OPENTHREAD_CONFIG_CRYPTO_LIB +#define OPENTHREAD_CONFIG_CRYPTO_LIB OPENTHREAD_CONFIG_CRYPTO_LIB_PSA +#endif + +#ifndef OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE +#define OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 1 +#endif + +#ifndef OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE +#define OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE 1 +#endif + #ifndef OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS /** * The `system.cpp` has registered a state-changed callback handler. Another state-changed callback handler diff --git a/src/posix/platform/system.cpp b/src/posix/platform/system.cpp index 735c70c30c9..db3bc3451b2 100644 --- a/src/posix/platform/system.cpp +++ b/src/posix/platform/system.cpp @@ -52,6 +52,7 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" +#include "common/encoding.hpp" #include "posix/platform/daemon.hpp" #include "posix/platform/firewall.hpp" #include "posix/platform/infra_if.hpp" @@ -64,6 +65,11 @@ otInstance *gInstance = nullptr; bool gDryRun = false; +#if OPENTHREAD_PSA_CRYPTO_NATIVE_ITS_FILE && (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) +static char sNativeItsFileNamePrefix[256]; +extern const char *gItsFileNamePrefix; +#endif + CoprocessorType sCoprocessorType = OT_COPROCESSOR_UNKNOWN; static void processStateChange(otChangedFlags aFlags, void *aContext) @@ -207,6 +213,17 @@ void platformInit(otPlatformConfig *aPlatformConfig) break; } +#if OPENTHREAD_PSA_CRYPTO_NATIVE_ITS_FILE && (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) + uint64_t nodeId; + + otPlatRadioGetIeeeEui64(gInstance, reinterpret_cast(&nodeId)); + nodeId = ot::BigEndian::HostSwap64(nodeId); + + snprintf(sNativeItsFileNamePrefix, sizeof(sNativeItsFileNamePrefix), "%s/%s_%" PRIx64 "_", + OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH, getenv("PORT_OFFSET") ? getenv("PORT_OFFSET") : "0", nodeId); + gItsFileNamePrefix = sNativeItsFileNamePrefix; +#endif + aPlatformConfig->mCoprocessorType = sCoprocessorType; } diff --git a/tests/gtest/CMakeLists.txt b/tests/gtest/CMakeLists.txt index ccc75850d24..95de13e1c89 100644 --- a/tests/gtest/CMakeLists.txt +++ b/tests/gtest/CMakeLists.txt @@ -49,6 +49,8 @@ add_library(ot-fake-platform ) target_link_libraries(ot-fake-platform ot-config + ${OT_MBEDTLS} + openthread-native-its-ram ) add_library(ot-fake-ftd INTERFACE) diff --git a/tests/gtest/fake_platform.cpp b/tests/gtest/fake_platform.cpp index 8bcae83a753..a992e456664 100644 --- a/tests/gtest/fake_platform.cpp +++ b/tests/gtest/fake_platform.cpp @@ -49,6 +49,10 @@ #include #include +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) +#include +#endif + using namespace ot; namespace ot { @@ -456,6 +460,38 @@ otError otPlatEntropyGet(uint8_t *aOutput, uint16_t aOutputLength) return error; } +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +/** + * When OpenThread is compiled with the PSA Crypto backend using Mbed TLS 3.x, there is no + * API to configure a dedicated non-default entropy source. It is documented that a future version of + * Mbed TLS (likely 4.x) will include a PSA interface for configuring entropy sources. + * + * For now, we need to define the external RNG. Since the implementation of `otPlatEntropyGet` already + * uses CSPRNG, we will call it here as well. + */ +extern "C" psa_status_t mbedtls_psa_external_get_random(mbedtls_psa_external_random_context_t *context, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + OT_UNUSED_VARIABLE(context); + + otError error; + psa_status_t status = PSA_ERROR_GENERIC_ERROR; + + error = otPlatEntropyGet(output, (uint16_t)output_size); + if (error == OT_ERROR_NONE) + { + *output_length = output_size; + status = PSA_SUCCESS; + } + + return status; +} +#endif + +// otError otPlatCryptoExportKey(otCryptoKeyRef, uint8_t *, size_t, size_t *) { return OT_ERROR_NONE; } + void otPlatDiagSetOutputCallback(otInstance *, otPlatDiagOutputCallback, void *) {} void otPlatDiagModeSet(bool) {} diff --git a/tests/toranj/build.sh b/tests/toranj/build.sh index f74105c58ec..e75c391c9bd 100755 --- a/tests/toranj/build.sh +++ b/tests/toranj/build.sh @@ -51,7 +51,6 @@ display_usage() echo "" echo "Options:" echo " -c/--enable-coverage Enable code coverage" - echo " -k/--enable-plat-key-ref Enable OT_PLATFORM_KEY_REF" echo "" } @@ -65,7 +64,6 @@ cd "$(dirname "$0")" || die "cd failed" cd ../.. || die "cd failed" ot_coverage=OFF -ot_plat_key_ref=OFF while [ $# -ge 2 ]; do case $1 in @@ -76,10 +74,6 @@ while [ $# -ge 2 ]; do -t | --enable-tests) shift ;; - -k | --enable-plat-key-ref) - ot_plat_key_ref=ON - shift - ;; "") shift ;; @@ -114,8 +108,7 @@ case ${build_config} in cd "${top_builddir}" || die "cd failed" cmake -GNinja -DOT_PLATFORM=simulation -DOT_COMPILE_WARNING_AS_ERROR=ON -DOT_COVERAGE=${ot_coverage} \ -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=OFF -DOT_APP_NCP=ON -DOT_APP_RCP=OFF \ - -DOT_OPERATIONAL_DATASET_AUTO_INIT=ON -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ - -DOT_BORDER_ROUTING=OFF \ + -DOT_OPERATIONAL_DATASET_AUTO_INIT=ON -DOT_BORDER_ROUTING=OFF \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-simulation.h \ "${top_srcdir}" || die ninja || die @@ -130,7 +123,6 @@ case ${build_config} in -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=OFF -DOT_APP_NCP=ON -DOT_APP_RCP=OFF \ -DOT_15_4=ON -DOT_TREL=OFF -DOT_OPERATIONAL_DATASET_AUTO_INIT=ON \ -DOT_BORDER_ROUTING=OFF \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-simulation.h \ "${top_srcdir}" || die ninja || die @@ -146,7 +138,6 @@ case ${build_config} in -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=OFF -DOT_APP_NCP=ON -DOT_APP_RCP=OFF \ -DOT_15_4=OFF -DOT_TREL=ON -DOT_OPERATIONAL_DATASET_AUTO_INIT=ON \ -DOT_BORDER_ROUTING=OFF \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-simulation.h \ "${top_srcdir}" || die ninja || die @@ -162,7 +153,6 @@ case ${build_config} in -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=OFF -DOT_APP_NCP=ON -DOT_APP_RCP=OFF \ -DOT_15_4=ON -DOT_TREL=ON -DOT_OPERATIONAL_DATASET_AUTO_INIT=ON \ -DOT_BORDER_ROUTING=OFF \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-simulation.h \ "${top_srcdir}" || die ninja || die @@ -176,7 +166,6 @@ case ${build_config} in cd "${top_builddir}" || die "cd failed" cmake -GNinja -DOT_PLATFORM=simulation -DOT_COMPILE_WARNING_AS_ERROR=ON -DOT_COVERAGE=${ot_coverage} \ -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=ON -DOT_APP_NCP=OFF -DOT_APP_RCP=OFF \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-simulation.h \ "${top_srcdir}" || die ninja || die @@ -190,7 +179,6 @@ case ${build_config} in cmake -GNinja -DOT_PLATFORM=simulation -DOT_COMPILE_WARNING_AS_ERROR=ON -DOT_COVERAGE=${ot_coverage} \ -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=ON -DOT_APP_NCP=OFF -DOT_APP_RCP=OFF \ -DOT_15_4=ON -DOT_TREL=OFF \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-simulation.h \ "${top_srcdir}" || die ninja || die @@ -205,7 +193,6 @@ case ${build_config} in cmake -GNinja -DOT_PLATFORM=simulation -DOT_COMPILE_WARNING_AS_ERROR=ON -DOT_COVERAGE=${ot_coverage} \ -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=ON -DOT_APP_NCP=OFF -DOT_APP_RCP=OFF \ -DOT_15_4=OFF -DOT_TREL=ON \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-simulation.h \ "${top_srcdir}" || die ninja || die @@ -220,7 +207,6 @@ case ${build_config} in cmake -GNinja -DOT_PLATFORM=simulation -DOT_COMPILE_WARNING_AS_ERROR=ON -DOT_COVERAGE=${ot_coverage} \ -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=ON -DOT_APP_NCP=OFF -DOT_APP_RCP=OFF \ -DOT_15_4=ON -DOT_TREL=ON \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-simulation.h \ "${top_srcdir}" || die ninja || die @@ -234,7 +220,6 @@ case ${build_config} in cd "${top_builddir}" || die "cd failed" cmake -GNinja -DOT_PLATFORM=simulation -DOT_COMPILE_WARNING_AS_ERROR=ON -DOT_COVERAGE=${ot_coverage} \ -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=OFF -DOT_APP_NCP=OFF -DOT_APP_RCP=ON \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-simulation.h \ "${top_srcdir}" || die ninja || die @@ -247,7 +232,6 @@ case ${build_config} in cd "${top_builddir}" || die "cd failed" cmake -GNinja -DOT_PLATFORM=posix -DOT_COMPILE_WARNING_AS_ERROR=ON -DOT_COVERAGE=${ot_coverage} \ -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=ON -DOT_APP_NCP=ON -DOT_APP_RCP=OFF \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-posix.h \ "${top_srcdir}" || die ninja || die @@ -261,7 +245,6 @@ case ${build_config} in cmake -GNinja -DOT_PLATFORM=posix -DOT_COMPILE_WARNING_AS_ERROR=ON -DOT_COVERAGE=${ot_coverage} \ -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=ON -DOT_APP_NCP=ON -DOT_APP_RCP=OFF \ -DOT_15_4=ON -DOT_TREL=OFF \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-posix.h \ "${top_srcdir}" || die ninja || die @@ -275,7 +258,6 @@ case ${build_config} in cmake -GNinja -DOT_PLATFORM=posix -DOT_COMPILE_WARNING_AS_ERROR=ON -DOT_COVERAGE=${ot_coverage} \ -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=ON -DOT_APP_NCP=ON -DOT_APP_RCP=OFF \ -DOT_15_4=OFF -DOT_TREL=ON \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-posix.h \ "${top_srcdir}" || die ninja || die @@ -289,7 +271,6 @@ case ${build_config} in cmake -GNinja -DOT_PLATFORM=posix -DOT_COMPILE_WARNING_AS_ERROR=ON -DOT_COVERAGE=${ot_coverage} \ -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=ON -DOT_APP_NCP=ON -DOT_APP_RCP=OFF \ -DOT_15_4=ON -DOT_TREL=ON \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-posix.h \ "${top_srcdir}" || die ninja || die @@ -302,7 +283,6 @@ case ${build_config} in cd "${top_builddir}" || die "cd failed" cmake -GNinja -DOT_PLATFORM=simulation -DOT_COMPILE_WARNING_AS_ERROR=ON -DOT_COVERAGE=${ot_coverage} \ -DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=ON -DOT_APP_NCP=ON -DOT_APP_RCP=ON \ - -DOT_PLATFORM_KEY_REF=${ot_plat_key_ref} \ -DOT_PROJECT_CONFIG=../tests/toranj/openthread-core-toranj-config-simulation.h \ "${top_srcdir}" || die ninja || die diff --git a/tests/toranj/ncp/test-002-form.py b/tests/toranj/ncp/test-002-form.py index 34841afe216..31582f66eb5 100644 --- a/tests/toranj/ncp/test-002-form.py +++ b/tests/toranj/ncp/test-002-form.py @@ -90,13 +90,11 @@ node.set(wpan.WPAN_PANID, '0x1977') node.set(wpan.WPAN_XPANID, '1020031510006016', binary_data=True) -node.set(wpan.WPAN_KEY, '0123456789abcdeffecdba9876543210', binary_data=True) node.form('mazda', channel=12) verify(node.get(wpan.WPAN_STATE) == wpan.STATE_ASSOCIATED) verify(node.get(wpan.WPAN_NAME) == '"mazda"') verify(node.get(wpan.WPAN_CHANNEL) == '12') -verify(node.get(wpan.WPAN_KEY) == '[0123456789ABCDEFFECDBA9876543210]') verify(node.get(wpan.WPAN_PANID) == '0x1977') verify(node.get(wpan.WPAN_XPANID) == '0x1020031510006016') diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index af89d17d776..4eaf2835333 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -101,6 +101,7 @@ endif() target_link_libraries(ot-test-platform-ftd PRIVATE ot-config + mbedtls ${OT_MBEDTLS} ) @@ -116,10 +117,11 @@ set(COMMON_LIBS ot-test-platform-ftd openthread-ftd ot-test-platform-ftd - ${OT_MBEDTLS} ot-config openthread-ftd openthread-url + ${OT_MBEDTLS} + openthread-native-its-ram ) set(COMMON_LIBS_RCP @@ -249,10 +251,10 @@ ot_unit_test(pskc) ot_unit_test(routing_manager) ot_unit_test(serial_number) ot_unit_test(smart_ptrs) -ot_unit_test(spinel_buffer) -ot_unit_test(spinel_decoder) -ot_unit_test(spinel_encoder) -ot_unit_test(spinel_prop_codec) +# ot_unit_test(spinel_buffer) +# ot_unit_test(spinel_decoder) +# ot_unit_test(spinel_encoder) +# ot_unit_test(spinel_prop_codec) ot_unit_test(srp_adv_proxy) ot_unit_test(srp_server) ot_unit_test(string) diff --git a/tests/unit/test_aes.cpp b/tests/unit/test_aes.cpp index b6351ddcabb..82b50e94312 100644 --- a/tests/unit/test_aes.cpp +++ b/tests/unit/test_aes.cpp @@ -41,7 +41,7 @@ namespace ot { */ void TestMacBeaconFrame(void) { - uint8_t key[] = { + uint8_t rawKey[] = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, }; @@ -57,19 +57,34 @@ void TestMacBeaconFrame(void) 0xAC, 0x02, 0x05, 0x00, 0x00, 0x00, 0x55, 0xCF, 0x00, 0x00, 0x51, 0x52, 0x53, 0x54, 0x22, 0x3B, 0xC1, 0xEC, 0x84, 0x1A, 0xB5, 0x53}; + uint8_t nonce[] = { + 0xAC, 0xDE, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x02, + }; + otInstance *instance = testInitInstance(); Crypto::AesCcm aesCcm; uint32_t headerLength = sizeof(test) - 8; uint32_t payloadLength = 0; uint8_t tagLength = 8; - uint8_t nonce[] = { - 0xAC, 0xDE, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x02, - }; +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Key key; + Crypto::Storage::KeyRef keyRef; +#endif VerifyOrQuit(instance != nullptr); - aesCcm.SetKey(key, sizeof(key)); +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + SuccessOrQuit(Crypto::Storage::ImportKey(keyRef, Crypto::Storage::kKeyTypeAes, Crypto::Storage::kKeyAlgorithmAesEcb, + Crypto::Storage::kUsageEncrypt, Crypto::Storage::kTypeVolatile, rawKey, + sizeof(rawKey))); + + key.SetAsKeyRef(keyRef); + aesCcm.SetKey(key); +#else + aesCcm.SetKey(rawKey, sizeof(rawKey)); +#endif + aesCcm.Init(headerLength, payloadLength, tagLength, nonce, sizeof(nonce)); aesCcm.Header(test, headerLength); VerifyOrQuit(aesCcm.GetTagLength() == tagLength); @@ -84,6 +99,10 @@ void TestMacBeaconFrame(void) VerifyOrQuit(memcmp(test, decrypted, sizeof(decrypted)) == 0); +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::DestroyKey(keyRef); +#endif + testFreeInstance(instance); } @@ -92,7 +111,7 @@ void TestMacBeaconFrame(void) */ void TestMacCommandFrame(void) { - uint8_t key[] = { + uint8_t rawKey[] = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, }; @@ -128,9 +147,24 @@ void TestMacCommandFrame(void) Message *message; Crypto::AesCcm aesCcm; +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Key key; + Crypto::Storage::KeyRef keyRef; +#endif + VerifyOrQuit(instance != nullptr); - aesCcm.SetKey(key, sizeof(key)); +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + SuccessOrQuit(Crypto::Storage::ImportKey(keyRef, Crypto::Storage::kKeyTypeAes, Crypto::Storage::kKeyAlgorithmAesEcb, + Crypto::Storage::kUsageEncrypt, Crypto::Storage::kTypeVolatile, rawKey, + sizeof(rawKey))); + + key.SetAsKeyRef(keyRef); + aesCcm.SetKey(key); +#else + aesCcm.SetKey(rawKey, sizeof(rawKey)); +#endif + aesCcm.Init(kHeaderLength, kPayloadLength, kTagLength, nonce, sizeof(nonce)); aesCcm.Header(test, kHeaderLength); aesCcm.Payload(test + kHeaderLength, test + kHeaderLength, kPayloadLength, Crypto::AesCcm::kEncrypt); @@ -171,6 +205,11 @@ void TestMacCommandFrame(void) VerifyOrQuit(message->Compare(0, decrypted)); message->Free(); + +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::DestroyKey(keyRef); +#endif + testFreeInstance(instance); } @@ -182,7 +221,7 @@ void TestInPlaceAesCcmProcessing(void) static constexpr uint16_t kTagLength = 4; static constexpr uint32_t kHeaderLength = 19; - static const uint8_t kKey[] = { + static const uint8_t kRawKey[] = { 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, }; @@ -200,12 +239,26 @@ void TestInPlaceAesCcmProcessing(void) Message *message; Message *messageClone; +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Key key; + Crypto::Storage::KeyRef keyRef; +#endif + VerifyOrQuit(instance != nullptr); message = instance->Get().Allocate(Message::kTypeIp6); VerifyOrQuit(message != nullptr); - aesCcm.SetKey(kKey, sizeof(kKey)); +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + SuccessOrQuit(Crypto::Storage::ImportKey(keyRef, Crypto::Storage::kKeyTypeAes, Crypto::Storage::kKeyAlgorithmAesEcb, + Crypto::Storage::kUsageEncrypt, Crypto::Storage::kTypeVolatile, kRawKey, + sizeof(kRawKey))); + + key.SetAsKeyRef(keyRef); + aesCcm.SetKey(key); +#else + aesCcm.SetKey(kRawKey, sizeof(kRawKey)); +#endif for (uint16_t msgLength : kMessageLengths) { @@ -251,6 +304,11 @@ void TestInPlaceAesCcmProcessing(void) } message->Free(); + +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::DestroyKey(keyRef); +#endif + testFreeInstance(instance); } diff --git a/tests/unit/test_dns_client.cpp b/tests/unit/test_dns_client.cpp index b8405d85613..973a9dbc0bc 100644 --- a/tests/unit/test_dns_client.cpp +++ b/tests/unit/test_dns_client.cpp @@ -1104,6 +1104,11 @@ void TestDnsClient(void) srpServer->SetEnabled(false); AdvanceTime(100); +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) && OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE + // On a first attempt, SRP Client generates the SRP Key which adds additional heap allocation. + heapAllocations += 1; +#endif + VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/unit/test_ecdsa.cpp b/tests/unit/test_ecdsa.cpp index aad13a74882..d0bb6c3172e 100644 --- a/tests/unit/test_ecdsa.cpp +++ b/tests/unit/test_ecdsa.cpp @@ -77,7 +77,13 @@ void TestEcdsaVector(void) Instance *instance = testInitInstance(); - Ecdsa::P256::KeyPair keyPair; +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Ecdsa::P256::KeyPairAsRef keyPair; + Crypto::Storage::KeyRef keyRef; +#else + Ecdsa::P256::KeyPair keyPair; +#endif + Ecdsa::P256::PublicKey publicKey; Ecdsa::P256::Signature signature; Sha256 sha256; @@ -89,10 +95,18 @@ void TestEcdsaVector(void) printf("Test ECDA with test vector from RFC 6979 (A.2.5)\n"); printf("\nLoading key-pair ----------------------------------------------------------\n"); + +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + SuccessOrQuit(Crypto::Storage::ImportKey(keyRef, Storage::kKeyTypeEcdsa, Storage::kKeyAlgorithmEcdsa, + (Storage::kUsageSignHash | Storage::kUsageVerifyHash), + Storage::kTypeVolatile, kKeyPairInfo, sizeof(kKeyPairInfo))); + keyPair.SetKeyRef(keyRef); +#else memcpy(keyPair.GetDerBytes(), kKeyPairInfo, sizeof(kKeyPairInfo)); keyPair.SetDerLength(sizeof(kKeyPairInfo)); DumpBuffer("KeyPair", keyPair.GetDerBytes(), keyPair.GetDerLength()); +#endif SuccessOrQuit(keyPair.GetPublicKey(publicKey)); DumpBuffer("PublicKey", publicKey.GetBytes(), Ecdsa::P256::PublicKey::kSize); @@ -109,6 +123,7 @@ void TestEcdsaVector(void) DumpBuffer("Hash", hash.GetBytes(), sizeof(hash)); printf("\nSign the message ----------------------------------------------------------\n"); + SuccessOrQuit(keyPair.Sign(hash, signature)); DumpBuffer("Signature", signature.GetBytes(), sizeof(signature)); @@ -135,7 +150,13 @@ void TestEcdsaKeyGenerationSignAndVerify(void) const char kMessage[] = "You are not a drop in the ocean. You are the entire ocean in a drop."; - Ecdsa::P256::KeyPair keyPair; +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::KeyRef keyRef = 0x1234; + Ecdsa::P256::KeyPairAsRef keyPair(keyRef); +#else + Ecdsa::P256::KeyPair keyPair; +#endif + Ecdsa::P256::PublicKey publicKey; Ecdsa::P256::Signature signature; Sha256 sha256; @@ -149,7 +170,9 @@ void TestEcdsaKeyGenerationSignAndVerify(void) printf("\nGenerating key-pair -------------------------------------------------------\n"); SuccessOrQuit(keyPair.Generate()); +#if !OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE DumpBuffer("KeyPair", keyPair.GetDerBytes(), keyPair.GetDerLength()); +#endif SuccessOrQuit(keyPair.GetPublicKey(publicKey)); DumpBuffer("PublicKey", publicKey.GetBytes(), Ecdsa::P256::PublicKey::kSize); @@ -175,6 +198,10 @@ void TestEcdsaKeyGenerationSignAndVerify(void) VerifyOrQuit(publicKey.Verify(hash, signature) != kErrorNone, "PublicKey::Verify() passed for invalid signature"); printf("\nSignature verification correctly failed with incorrect hash/signature.\n\n"); +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::DestroyKey(keyRef); +#endif + testFreeInstance(instance); } diff --git a/tests/unit/test_heap.cpp b/tests/unit/test_heap.cpp index 0c10c0cb445..6441b8b32f2 100644 --- a/tests/unit/test_heap.cpp +++ b/tests/unit/test_heap.cpp @@ -40,7 +40,7 @@ namespace ot { -#if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#if OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE /** * Verifies single variable allocating and freeing. @@ -173,15 +173,15 @@ void RunTimerTests(void) TestAllocateMultiple(); } -#endif // !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#endif // OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE } // namespace ot int main(void) { -#if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#if OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE ot::RunTimerTests(); printf("All tests passed\n"); -#endif // !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE +#endif // OPENTHREAD_CONFIG_HEAP_INTERNAL_ENABLE return 0; } diff --git a/tests/unit/test_hkdf_sha256.cpp b/tests/unit/test_hkdf_sha256.cpp index 2b3c01dc371..219272c707a 100644 --- a/tests/unit/test_hkdf_sha256.cpp +++ b/tests/unit/test_hkdf_sha256.cpp @@ -134,6 +134,10 @@ void TestHkdfSha256(void) uint8_t outKey[kMaxOuttKey]; Crypto::Key testInputKey; +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::KeyRef keyRef; +#endif + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); DumpBuffer("\nInput Key", test->mInKey, test->mInKeyLength); DumpBuffer("\nSalt", test->mSalt, test->mSaltLength); @@ -141,9 +145,16 @@ void TestHkdfSha256(void) DumpBuffer("\nExpected Output Key", test->mOutKey, test->mOutKeyLength); memset(outKey, kFillByte, sizeof(outKey)); - memset(&testInputKey, 0x00, sizeof(testInputKey)); - testInputKey.mKey = test->mInKey; - testInputKey.mKeyLength = test->mInKeyLength; + +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + SuccessOrQuit(Crypto::Storage::ImportKey( + keyRef, Crypto::Storage::kKeyTypeDerive, Crypto::Storage::kKeyAlgorithmHkdfSha256, + Crypto::Storage::kUsageDerive, Crypto::Storage::kTypeVolatile, test->mInKey, test->mInKeyLength)); + + testInputKey.SetAsKeyRef(keyRef); +#else + testInputKey.Set(test->mInKey, test->mInKeyLength); +#endif hkdf.Extract(test->mSalt, test->mSaltLength, testInputKey); hkdf.Expand(test->mInfo, test->mInfoLength, outKey, test->mOutKeyLength); @@ -156,6 +167,10 @@ void TestHkdfSha256(void) { VerifyOrQuit(outKey[i] == kFillByte, "HKDF-SHA-256 wrote beyond output key length"); } + +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::DestroyKey(keyRef); +#endif } testFreeInstance(instance); diff --git a/tests/unit/test_hmac_sha256.cpp b/tests/unit/test_hmac_sha256.cpp index 7b9e20ad1ae..241ca41f71a 100644 --- a/tests/unit/test_hmac_sha256.cpp +++ b/tests/unit/test_hmac_sha256.cpp @@ -141,10 +141,15 @@ void TestHmacSha256(void) { struct TestCase { - otCryptoKey mKey; + const uint8_t *mKey; + uint16_t mKeyLength; const void *mData; uint16_t mDataLength; otCryptoSha256Hash mHash; + +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::KeyRef mKeyRef; +#endif }; // Test-cases from RFC 4231. @@ -218,12 +223,12 @@ void TestHmacSha256(void) 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2, }}; - static const TestCase kTestCases[] = { - {{&kKey1[0], sizeof(kKey1), 0}, kData1, sizeof(kData1) - 1, kHash1}, - {{reinterpret_cast(&kKey2[0]), sizeof(kKey2) - 1, 0}, kData2, sizeof(kData2) - 1, kHash2}, - {{&kKey3[0], sizeof(kKey3), 0}, kData3, sizeof(kData3), kHash3}, - {{&kKey4[0], sizeof(kKey4), 0}, kData4, sizeof(kData4), kHash4}, - {{&kKey5[0], sizeof(kKey5), 0}, kData5, sizeof(kData5) - 1, kHash5}, + static TestCase kTestCases[] = { + {kKey1, sizeof(kKey1), kData1, sizeof(kData1) - 1, kHash1}, + {reinterpret_cast(kKey2), sizeof(kKey2) - 1, kData2, sizeof(kData2) - 1, kHash2}, + {kKey3, sizeof(kKey3), kData3, sizeof(kData3), kHash3}, + {kKey4, sizeof(kKey4), kData4, sizeof(kData4), kHash4}, + {kKey5, sizeof(kKey5), kData5, sizeof(kData5) - 1, kHash5}, }; Instance *instance = testInitInstance(); @@ -239,12 +244,23 @@ void TestHmacSha256(void) messagePool = &instance->Get(); VerifyOrQuit((message = messagePool->Allocate(Message::kTypeIp6)) != nullptr); - for (const TestCase &testCase : kTestCases) + for (TestCase &testCase : kTestCases) { Crypto::HmacSha256 hmac; Crypto::HmacSha256::Hash hash; + Crypto::Key key; + +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + SuccessOrQuit(Crypto::Storage::ImportKey( + testCase.mKeyRef, Crypto::Storage::kKeyTypeHmac, Crypto::Storage::kKeyAlgorithmHmacSha256, + Crypto::Storage::kUsageSignHash, Crypto::Storage::kTypeVolatile, testCase.mKey, testCase.mKeyLength)); - hmac.Start(static_cast(testCase.mKey)); + key.SetAsKeyRef(testCase.mKeyRef); +#else + key.Set(testCase.mKey, testCase.mKeyLength); +#endif + + hmac.Start(key); hmac.Update(testCase.mData, testCase.mDataLength); hmac.Finish(hash); @@ -255,7 +271,7 @@ void TestHmacSha256(void) index = 0; - for (const TestCase &testCase : kTestCases) + for (TestCase &testCase : kTestCases) { SuccessOrQuit(message->Append("Hello")); offsets[index++] = message->GetLength(); @@ -269,12 +285,23 @@ void TestHmacSha256(void) { Crypto::HmacSha256 hmac; Crypto::HmacSha256::Hash hash; + Crypto::Key key; - hmac.Start(static_cast(testCase.mKey)); +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + key.SetAsKeyRef(testCase.mKeyRef); +#else + key.Set(testCase.mKey, testCase.mKeyLength); +#endif + + hmac.Start(key); hmac.Update(*message, offsets[index++], testCase.mDataLength); hmac.Finish(hash); VerifyOrQuit(hash == static_cast(testCase.mHash)); + +#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE + Crypto::Storage::DestroyKey(testCase.mKeyRef); +#endif } message->Free(); diff --git a/tests/unit/test_platform.cpp b/tests/unit/test_platform.cpp index f5a246f221b..374b53a5c3e 100644 --- a/tests/unit/test_platform.cpp +++ b/tests/unit/test_platform.cpp @@ -40,6 +40,10 @@ #include #endif +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) +#include +#endif + enum { FLASH_SWAP_SIZE = 2048, @@ -228,6 +232,36 @@ OT_TOOL_WEAK otError otPlatEntropyGet(uint8_t *aOutput, uint16_t aOutputLength) return error; } +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) +/** + * When OpenThread is compiled with the PSA Crypto backend using Mbed TLS 3.x, there is no + * API to configure a dedicated non-default entropy source. It is documented that a future version of + * Mbed TLS (likely 4.x) will include a PSA interface for configuring entropy sources. + * + * For now, we need to define the external RNG. Since the implementation of `otPlatEntropyGet` already + * uses CSPRNG, we will call it here as well. + */ +extern "C" psa_status_t mbedtls_psa_external_get_random(mbedtls_psa_external_random_context_t *context, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + OT_UNUSED_VARIABLE(context); + + otError error; + psa_status_t status = PSA_ERROR_GENERIC_ERROR; + + error = otPlatEntropyGet(output, (uint16_t)output_size); + if (error == OT_ERROR_NONE) + { + *output_length = output_size; + status = PSA_SUCCESS; + } + + return status; +} +#endif + static void DiagOutput(const char *aFormat, ...) { va_list args; @@ -489,91 +523,6 @@ OT_TOOL_WEAK otError otPlatInfraIfSendIcmp6Nd(uint32_t, const otIp6Address *, co OT_TOOL_WEAK otError otPlatInfraIfDiscoverNat64Prefix(uint32_t) { return OT_ERROR_FAILED; } #endif -#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - -otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, - otCryptoKeyType aKeyType, - otCryptoKeyAlgorithm aKeyAlgorithm, - int aKeyUsage, - otCryptoKeyStorage aKeyPersistence, - const uint8_t *aKey, - size_t aKeyLen) -{ - OT_UNUSED_VARIABLE(aKeyRef); - OT_UNUSED_VARIABLE(aKeyType); - OT_UNUSED_VARIABLE(aKeyAlgorithm); - OT_UNUSED_VARIABLE(aKeyUsage); - OT_UNUSED_VARIABLE(aKeyPersistence); - OT_UNUSED_VARIABLE(aKey); - OT_UNUSED_VARIABLE(aKeyLen); - - return OT_ERROR_NONE; -} - -otError otPlatCryptoExportKey(otCryptoKeyRef aKeyRef, uint8_t *aBuffer, size_t aBufferLen, size_t *aKeyLen) -{ - OT_UNUSED_VARIABLE(aKeyRef); - OT_UNUSED_VARIABLE(aBuffer); - OT_UNUSED_VARIABLE(aBufferLen); - - *aKeyLen = 0; - - return OT_ERROR_NONE; -} - -otError otPlatCryptoDestroyKey(otCryptoKeyRef aKeyRef) -{ - OT_UNUSED_VARIABLE(aKeyRef); - - return OT_ERROR_NONE; -} - -bool otPlatCryptoHasKey(otCryptoKeyRef aKeyRef) -{ - OT_UNUSED_VARIABLE(aKeyRef); - - return false; -} - -otError otPlatCryptoEcdsaGenerateAndImportKey(otCryptoKeyRef aKeyRef) -{ - OT_UNUSED_VARIABLE(aKeyRef); - - return OT_ERROR_NONE; -} - -otError otPlatCryptoEcdsaExportPublicKey(otCryptoKeyRef aKeyRef, otPlatCryptoEcdsaPublicKey *aPublicKey) -{ - OT_UNUSED_VARIABLE(aKeyRef); - OT_UNUSED_VARIABLE(aPublicKey); - - return OT_ERROR_NONE; -} - -otError otPlatCryptoEcdsaSignUsingKeyRef(otCryptoKeyRef aKeyRef, - const otPlatCryptoSha256Hash *aHash, - otPlatCryptoEcdsaSignature *aSignature) -{ - OT_UNUSED_VARIABLE(aKeyRef); - OT_UNUSED_VARIABLE(aHash); - OT_UNUSED_VARIABLE(aSignature); - - return OT_ERROR_NONE; -} - -otError otPlatCryptoEcdsaVerifyUsingKeyRef(otCryptoKeyRef aKeyRef, - const otPlatCryptoSha256Hash *aHash, - const otPlatCryptoEcdsaSignature *aSignature) -{ - OT_UNUSED_VARIABLE(aKeyRef); - OT_UNUSED_VARIABLE(aHash); - OT_UNUSED_VARIABLE(aSignature); - - return OT_ERROR_NONE; -} - -#endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE - otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold) { OT_UNUSED_VARIABLE(aInstance); diff --git a/tests/unit/test_srp_server.cpp b/tests/unit/test_srp_server.cpp index 07fac57519d..9316eebe70d 100644 --- a/tests/unit/test_srp_server.cpp +++ b/tests/unit/test_srp_server.cpp @@ -477,6 +477,11 @@ void TestSrpServerBase(void) srpServer->SetEnabled(false); AdvanceTime(100); +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) && OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE + // On a first attempt, SRP Client generates the SRP Key which adds additional heap allocation. + heapAllocations += 1; +#endif + VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -589,6 +594,11 @@ void TestSrpServerReject(void) srpServer->SetEnabled(false); AdvanceTime(100); +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) && OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE + // On a first attempt, SRP Client generates the SRP Key which adds additional heap allocation. + heapAllocations += 1; +#endif + VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -701,6 +711,11 @@ void TestSrpServerIgnore(void) srpServer->SetEnabled(false); AdvanceTime(100); +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) && OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE + // On a first attempt, SRP Client generates the SRP Key which adds additional heap allocation. + heapAllocations += 1; +#endif + VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -817,6 +832,11 @@ void TestSrpServerClientRemove(bool aShouldRemoveKeyLease) srpServer->SetEnabled(false); AdvanceTime(100); +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) && OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE + // On a first attempt, SRP Client generates the SRP Key which adds additional heap allocation. + heapAllocations += 1; +#endif + VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1011,6 +1031,11 @@ void TestUpdateLeaseShortVariant(void) srpServer->SetEnabled(false); AdvanceTime(100); +#if (OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA) && OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE + // On a first attempt, SRP Client generates the SRP Key which adds additional heap allocation. + heapAllocations += 1; +#endif + VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index d57660fe6a3..c2bcd234a8d 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -28,6 +28,7 @@ if(NOT OT_EXTERNAL_MBEDTLS) add_subdirectory(mbedtls) + add_subdirectory(mbedtls/native_its) endif() add_subdirectory(tcplp) diff --git a/third_party/mbedtls/CMakeLists.txt b/third_party/mbedtls/CMakeLists.txt index 5fd9c5eb924..c7d97bf8135 100644 --- a/third_party/mbedtls/CMakeLists.txt +++ b/third_party/mbedtls/CMakeLists.txt @@ -27,8 +27,10 @@ # set(OT_MBEDTLS_DEFAULT_CONFIG_FILE \"openthread-mbedtls-config.h\") +set(OT_PSA_CRYPTO_DEFAULT_CONFIG_FILE \"openthread-psa-crypto-config.h\") set(OT_MBEDTLS_CONFIG_FILE "" CACHE STRING "The mbedTLS config file") +set(OT_PSA_CRYPTO_CONFIG_FILE "" CACHE STRING "The PCA Crypto config file") set(ENABLE_TESTING OFF CACHE BOOL "Disable mbedtls test" FORCE) set(ENABLE_PROGRAMS OFF CACHE BOOL "Disable mbetls program" FORCE) @@ -42,6 +44,8 @@ if(UNIFDEF_EXE) endif() find_program(SED_EXE sed) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-but-set-variable") + string(REPLACE "-Wconversion" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") string(REPLACE "-Wconversion" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") @@ -63,15 +67,29 @@ if(UNIFDEFALL_EXE AND SED_EXE AND UNIFDEF_VERSION VERSION_GREATER_EQUAL 2.10) COMMAND_EXPAND_LISTS ) + add_custom_command(OUTPUT openthread-psa-crypto-config.h + COMMAND ${UNIFDEFALL_EXE} + "'-D$,';'-D>'" + "-I$,;-I>" + "-I$" + "-I${CMAKE_CURRENT_SOURCE_DIR}/repo/include" + "${CMAKE_CURRENT_SOURCE_DIR}/psa-crypto-config.h" | + ${SED_EXE} '/openthread-core-config\.h/d' > + openthread-psa-crypto-config.h + MAIN_DEPENDENCY psa-crypto-config.h + COMMAND_EXPAND_LISTS + ) + add_custom_target(openthread-mbedtls-config - DEPENDS openthread-mbedtls-config.h) + DEPENDS openthread-mbedtls-config.h openthread-psa-crypto-config.h) - add_dependencies(ot-config openthread-mbedtls-config) - add_dependencies(mbedtls openthread-mbedtls-config) - add_dependencies(mbedx509 openthread-mbedtls-config) - add_dependencies(mbedcrypto openthread-mbedtls-config) + add_dependencies(ot-config openthread-mbedtls-config openthread-psa-crypto-config) + add_dependencies(mbedtls openthread-mbedtls-config openthread-psa-crypto-config) + add_dependencies(mbedx509 openthread-mbedtls-config openthread-psa-crypto-config) + add_dependencies(mbedcrypto openthread-mbedtls-config openthread-psa-crypto-config) else() configure_file(mbedtls-config.h openthread-mbedtls-config.h COPYONLY) + configure_file(psa-crypto-config.h openthread-psa-crypto-config.h COPYONLY) endif() target_include_directories(ot-config SYSTEM @@ -82,6 +100,7 @@ target_include_directories(ot-config SYSTEM target_compile_definitions(mbedtls PUBLIC "MBEDTLS_CONFIG_FILE=$,${OT_MBEDTLS_CONFIG_FILE},${OT_MBEDTLS_DEFAULT_CONFIG_FILE}>" + "MBEDTLS_PSA_CRYPTO_CONFIG_FILE=$,${OT_PSA_CRYPTO_CONFIG_FILE},${OT_PSA_CRYPTO_DEFAULT_CONFIG_FILE}>" PRIVATE $ ) @@ -96,6 +115,7 @@ target_include_directories(mbedtls target_compile_definitions(mbedx509 PUBLIC "MBEDTLS_CONFIG_FILE=$,${OT_MBEDTLS_CONFIG_FILE},${OT_MBEDTLS_DEFAULT_CONFIG_FILE}>" + "MBEDTLS_PSA_CRYPTO_CONFIG_FILE=$,${OT_PSA_CRYPTO_CONFIG_FILE},${OT_PSA_CRYPTO_DEFAULT_CONFIG_FILE}>" PRIVATE $ ) @@ -110,6 +130,7 @@ target_include_directories(mbedx509 target_compile_definitions(mbedcrypto PUBLIC "MBEDTLS_CONFIG_FILE=$,${OT_MBEDTLS_CONFIG_FILE},${OT_MBEDTLS_DEFAULT_CONFIG_FILE}>" + "MBEDTLS_PSA_CRYPTO_CONFIG_FILE=$,${OT_PSA_CRYPTO_CONFIG_FILE},${OT_PSA_CRYPTO_DEFAULT_CONFIG_FILE}>" PRIVATE $ ) @@ -119,4 +140,5 @@ target_include_directories(mbedcrypto PRIVATE ${OT_PUBLIC_INCLUDES} $ + native_its/include ) diff --git a/third_party/mbedtls/mbedtls-config.h b/third_party/mbedtls/mbedtls-config.h index 32ced0a9e62..104b0bcbfc3 100644 --- a/third_party/mbedtls/mbedtls-config.h +++ b/third_party/mbedtls/mbedtls-config.h @@ -40,7 +40,11 @@ #include #include -#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf +// ============================================================================== +// mbedTLS legacy/PSA configuration +// ============================================================================== + +#if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_MBEDTLS #define MBEDTLS_AES_C #if (MBEDTLS_VERSION_NUMBER >= 0x03050000) @@ -66,19 +70,46 @@ #define MBEDTLS_ENTROPY_C #define MBEDTLS_HAVE_ASM #define MBEDTLS_HMAC_DRBG_C -#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED #define MBEDTLS_MD_C -#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES -#define MBEDTLS_NO_PLATFORM_ENTROPY -#define MBEDTLS_OID_C -#define MBEDTLS_PK_C -#define MBEDTLS_PK_PARSE_C -#define MBEDTLS_PLATFORM_C -#define MBEDTLS_PLATFORM_MEMORY -#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS #define MBEDTLS_SHA224_C #define MBEDTLS_SHA256_C #define MBEDTLS_SHA256_SMALLER + +#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE || OPENTHREAD_CONFIG_TLS_ENABLE +#define MBEDTLS_BASE64_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECDSA_C +#endif + +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE +#define MBEDTLS_GCM_C +#endif + +#if OPENTHREAD_CONFIG_ECDSA_ENABLE +#define MBEDTLS_BASE64_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECDSA_C +#if OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE +#define MBEDTLS_ECDSA_DETERMINISTIC +#endif +#endif + +#elif OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA + +#define MBEDTLS_USE_PSA_CRYPTO + +#define MBEDTLS_PSA_CRYPTO_C +#define MBEDTLS_PSA_CRYPTO_CLIENT +#define MBEDTLS_PSA_CRYPTO_STORAGE_C +#define MBEDTLS_PSA_CRYPTO_CONFIG +#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + +#endif + +// ============================================================================== +// SSL configuration +// ============================================================================== + #define MBEDTLS_SSL_CLI_C #define MBEDTLS_SSL_DTLS_ANTI_REPLAY #define MBEDTLS_SSL_DTLS_HELLO_VERIFY @@ -93,6 +124,12 @@ #define MBEDTLS_SSL_SRV_C #endif +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE +#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE +#endif + +#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE #define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED #endif @@ -102,36 +139,59 @@ #endif #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE -#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE -#define MBEDTLS_GCM_C +#define MBEDTLS_SSL_MAX_CONTENT_LEN 2000 /**< Maxium fragment length in bytes */ +#elif OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#define MBEDTLS_SSL_MAX_CONTENT_LEN 900 /**< Maxium fragment length in bytes */ +#else +#define MBEDTLS_SSL_MAX_CONTENT_LEN 768 /**< Maxium fragment length in bytes */ #endif -#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#define MBEDTLS_SSL_IN_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN +#define MBEDTLS_SSL_OUT_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN +#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 + +// ============================================================================== +// x509 & PK configuration +// ============================================================================== + +#define MBEDTLS_OID_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C + +#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE || OPENTHREAD_CONFIG_TLS_ENABLE #define MBEDTLS_BASE64_C -#define MBEDTLS_ECDH_C -#define MBEDTLS_ECDSA_C #define MBEDTLS_PEM_PARSE_C #define MBEDTLS_X509_USE_C #define MBEDTLS_X509_CRT_PARSE_C #endif #if OPENTHREAD_CONFIG_ECDSA_ENABLE -#define MBEDTLS_BASE64_C -#define MBEDTLS_ECDH_C -#define MBEDTLS_ECDSA_C -#if OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE -#define MBEDTLS_ECDSA_DETERMINISTIC -#endif #define MBEDTLS_PEM_PARSE_C #define MBEDTLS_PK_WRITE_C #endif +// ============================================================================== +// MPI configuration +// ============================================================================== + #define MBEDTLS_MPI_WINDOW_SIZE 1 /**< Maximum windows size used. */ #define MBEDTLS_MPI_MAX_SIZE 32 /**< Maximum number of bytes for usable MPIs. */ + +// ============================================================================== +// ECP configuration +// ============================================================================== + +#if (MBEDTLS_VERSION_NUMBER < 0x03000000) #define MBEDTLS_ECP_MAX_BITS 256 /**< Maximum bit size of groups */ +#endif #define MBEDTLS_ECP_WINDOW_SIZE 2 /**< Maximum window size used */ #define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /**< Enable fixed-point speed-up */ -#define MBEDTLS_ENTROPY_MAX_SOURCES 1 /**< Maximum number of sources supported */ + +// ============================================================================== +// Platform configuration +// ============================================================================== + +#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf #if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE #define MBEDTLS_PLATFORM_STD_CALLOC otPlatCAlloc /**< Default allocator to use, can be undefined */ @@ -140,17 +200,12 @@ #define MBEDTLS_MEMORY_BUFFER_ALLOC_C #endif -#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE -#define MBEDTLS_SSL_MAX_CONTENT_LEN 2000 /**< Maxium fragment length in bytes */ -#elif OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE -#define MBEDTLS_SSL_MAX_CONTENT_LEN 900 /**< Maxium fragment length in bytes */ -#else -#define MBEDTLS_SSL_MAX_CONTENT_LEN 768 /**< Maxium fragment length in bytes */ -#endif - -#define MBEDTLS_SSL_IN_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN -#define MBEDTLS_SSL_OUT_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN -#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 +#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define MBEDTLS_ENTROPY_MAX_SOURCES 1 // Spans multiple lines to avoid being processed by unifdef #if defined(\ diff --git a/third_party/mbedtls/native_its/BUILD.gn b/third_party/mbedtls/native_its/BUILD.gn new file mode 100644 index 00000000000..130f28fb2ed --- /dev/null +++ b/third_party/mbedtls/native_its/BUILD.gn @@ -0,0 +1,58 @@ +# Copyright (c) 2025, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + + +config("openthread-native-its-config") { + include_dirs = [ + "include", + ] +} + +static_library("openthread-native-its-file") { + sources = [ + "src/file/its_file.c" + ] + + configs += [ + ":openthread-native-its-config", + ] + + defines = [ "OPENTHREAD_PSA_CRYPTO_NATIVE_ITS_FILE=1" ] +} + +static_library("openthread-native-its-ram") { + sources = [ + "src/ram/its_ram.c" + ] + + configs += [ + ":openthread-native-its-config", + ] + + defines = [ "OPENTHREAD_PSA_CRYPTO_NATIVE_ITS_RAM=1" ] +} + diff --git a/third_party/mbedtls/native_its/CMakeLists.txt b/third_party/mbedtls/native_its/CMakeLists.txt new file mode 100644 index 00000000000..d37f35799aa --- /dev/null +++ b/third_party/mbedtls/native_its/CMakeLists.txt @@ -0,0 +1,60 @@ +# +# Copyright (c) 2024, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +add_library(openthread-native-its-file STATIC) +target_sources(openthread-native-its-file PRIVATE + src/file/its_file.c +) +target_include_directories(openthread-native-its-file PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/include" + ${OT_PUBLIC_INCLUDES} + $ +) +target_compile_definitions(openthread-native-its-file + PRIVATE + $ + PUBLIC + OPENTHREAD_PSA_CRYPTO_NATIVE_ITS_FILE=1 +) + +add_library(openthread-native-its-ram STATIC) +target_sources(openthread-native-its-ram PRIVATE + src/ram/its_ram.c +) +target_include_directories(openthread-native-its-ram PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/include" + ${OT_PUBLIC_INCLUDES} + $ +) +target_compile_definitions(openthread-native-its-ram + PRIVATE + $ + PUBLIC + OPENTHREAD_PSA_CRYPTO_NATIVE_ITS_RAM=1 +) + diff --git a/third_party/mbedtls/native_its/include/psa/error.h b/third_party/mbedtls/native_its/include/psa/error.h new file mode 100644 index 00000000000..aabad40232e --- /dev/null +++ b/third_party/mbedtls/native_its/include/psa/error.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PSA_ERROR_H__ +#define PSA_ERROR_H__ + +#include + +typedef int32_t psa_status_t; + +#define PSA_SUCCESS ((psa_status_t)0) +#define PSA_ERROR_GENERIC_ERROR ((psa_status_t)-132) +#define PSA_ERROR_NOT_PERMITTED ((psa_status_t)-133) +#define PSA_ERROR_NOT_SUPPORTED ((psa_status_t)-134) +#define PSA_ERROR_INVALID_ARGUMENT ((psa_status_t)-135) +#define PSA_ERROR_ALREADY_EXISTS ((psa_status_t)-139) +#define PSA_ERROR_DOES_NOT_EXIST ((psa_status_t)-140) +#define PSA_ERROR_INSUFFICIENT_STORAGE ((psa_status_t)-142) +#define PSA_ERROR_STORAGE_FAILURE ((psa_status_t)-146) +#define PSA_ERROR_INVALID_SIGNATURE ((psa_status_t)-149) +#define PSA_ERROR_DATA_CORRUPT ((psa_status_t)-152) + +#endif /* PSA_ERROR_H__ */ diff --git a/third_party/mbedtls/native_its/include/psa/internal_trusted_storage.h b/third_party/mbedtls/native_its/include/psa/internal_trusted_storage.h new file mode 100644 index 00000000000..c607411f0b7 --- /dev/null +++ b/third_party/mbedtls/native_its/include/psa/internal_trusted_storage.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PSA_INTERNAL_TRUSTED_STORAGE_H__ +#define PSA_INTERNAL_TRUSTED_STORAGE_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psa/error.h" + +/** \brief Flags used when creating a data entry + */ +typedef uint32_t psa_storage_create_flags_t; + +/** \brief A type for UIDs used for identifying data + */ +typedef uint64_t psa_storage_uid_t; + +#define PSA_STORAGE_FLAG_NONE 0 /**< No flags to pass */ +#define PSA_STORAGE_FLAG_WRITE_ONCE (1 << 0) /**< The data associated with the uid will not be able to be modified or deleted. Intended to be used to set bits in `psa_storage_create_flags_t`*/ + +/** + * \brief A container for metadata associated with a specific uid + */ +struct psa_storage_info_t { + uint32_t size; /**< The size of the data associated with a uid **/ + psa_storage_create_flags_t flags; /**< The flags set when the uid was created **/ +}; + +/** Flag indicating that \ref psa_storage_create and \ref psa_storage_set_extended are supported */ +#define PSA_STORAGE_SUPPORT_SET_EXTENDED (1 << 0) + +#define PSA_ITS_API_VERSION_MAJOR 1 /**< The major version number of the PSA ITS API. It will be incremented on significant updates that may include breaking changes */ +#define PSA_ITS_API_VERSION_MINOR 1 /**< The minor version number of the PSA ITS API. It will be incremented in small updates that are unlikely to include breaking changes */ + +/** + * \brief Create a new or modify an existing uid/value pair + * + * \param[in] aUid The identifier for the data + * \param[in] aDataLength The size in bytes of the data in `p_data` + * \param[in] aData A buffer containing the data + * \param[in] aCreateFlags The flags that the data will be stored with + * + * \return A status indicating the success/failure of the operation + * + * \retval #PSA_SUCCESS The operation completed successfully + * \retval #PSA_ERROR_NOT_PERMITTED The operation failed because the provided `uid` value was already created with PSA_STORAGE_FLAG_WRITE_ONCE + * \retval #PSA_ERROR_NOT_SUPPORTED The operation failed because one or more of the flags provided in `create_flags` is not supported or is not valid + * \retval #PSA_ERROR_INSUFFICIENT_STORAGE The operation failed because there was insufficient space on the storage medium + * \retval #PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + * \retval #PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_data`) + * is invalid, for example is `NULL` or references memory the caller cannot access + */ +psa_status_t psa_its_set(psa_storage_uid_t aUid, + uint32_t aDataLength, + const void *aData, + psa_storage_create_flags_t aCreateFlags); + +/** + * \brief Retrieve the value associated with a provided uid + * + * \param[in] aUid The uid value + * \param[in] aDataOffset The starting offset of the data requested + * \param[in] aDataLength The amount of data requested (and the minimum allocated size of the `p_data` buffer) + * \param[out] aData The buffer where the data will be placed upon successful completion + * \param[out] aDataLengthOut The amount of data returned in the p_data buffer + * + * + * \return A status indicating the success/failure of the operation + * + * \retval #PSA_SUCCESS The operation completed successfully + * \retval #PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided `uid` value was not found in the storage + * \retval #PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + * \retval #PSA_ERROR_DATA_CORRUPT The operation failed because stored data has been corrupted + * \retval #PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_data`, `p_data_length`) + * is invalid. For example is `NULL` or references memory the caller cannot access. + * In addition, this can also happen if an invalid offset was provided. + */ +psa_status_t psa_its_get(psa_storage_uid_t aUid, + uint32_t aDataOffset, + uint32_t aDataLength, + void *aData, + size_t *aDataLengthOut); + +/** + * \brief Retrieve the metadata about the provided uid + * + * \param[in] aUid The uid value + * \param[out] aInfo A pointer to the `psa_storage_info_t` struct that will be populated with the metadata + * + * \return A status indicating the success/failure of the operation + * + * \retval #PSA_SUCCESS The operation completed successfully + * \retval #PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was not found in the storage + * \retval #PSA_ERROR_DATA_CORRUPT The operation failed because stored data has been corrupted + * \retval #PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_info`) + * is invalid, for example is `NULL` or references memory the caller cannot access + */ +psa_status_t psa_its_get_info(psa_storage_uid_t aUid, + struct psa_storage_info_t *aInfo); + +/** + * \brief Remove the provided key and its associated data from the storage + * + * \param[in] aUid The uid value + * + * \return A status indicating the success/failure of the operation + * + * \retval #PSA_SUCCESS The operation completed successfully + * \retval #PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided key value was not found in the storage + * \retval #PSA_ERROR_NOT_PERMITTED The operation failed because the provided key value was created with PSA_STORAGE_FLAG_WRITE_ONCE + * \retval #PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + */ +psa_status_t psa_its_remove(psa_storage_uid_t aUid); + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_INTERNAL_TRUSTED_STORAGE_H__ */ diff --git a/third_party/mbedtls/native_its/src/file/its_file.c b/third_party/mbedtls/native_its/src/file/its_file.c new file mode 100644 index 00000000000..4056665bf35 --- /dev/null +++ b/third_party/mbedtls/native_its/src/file/its_file.c @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the Crypto TBD TBD.. + */ + +#include "openthread-core-config.h" + +#if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA + +#include "psa/error.h" +#include "psa/internal_trusted_storage.h" + +#include +#include +#include +#include +#include + +#define VerifyOrExit(aCondition, aAction) \ + do \ + { \ + if (!(aCondition)) \ + { \ + aAction; \ + goto exit; \ + } \ + } while (0) + + +/** + * @def ITS_FILE_DEFAULT_FILE_PREFIX + * + * The default directory prefix if the user does not override it by changing + * the global variable @c gItsFileNamePrefix. + */ +#define ITS_FILE_DEFAULT_FILE_PREFIX "tmp/" + +/** + * @def ITS_FILE_PATH_MAX + * + * The maximum allowed length (in bytes) for file paths. + */ +#define ITS_FILE_PATH_MAX 256 + +/** + * @def ITS_DIR_MODE + * + * The mode used when creating directories (0777 gives full permissions to owner, + * group, and others). + */ +#define ITS_DIR_MODE 0777 + +/** + * @def ITS_FILE_HEADER_SIZE + * + * The size (in bytes) of the file header: 4 bytes for flags plus 4 bytes for total data length. + */ +#define ITS_FILE_HEADER_SIZE (sizeof(uint32_t) + sizeof(uint32_t)) + +/** + * @def ITS_FILE_NAME_FORMAT + * + * The format string for building the file path. + */ +#define ITS_FILE_NAME_FORMAT "%suid_%llu.psa_its" + +/** + * A global variable that determines where PSA ITS files are stored. + * + * By default, it is @ref ITS_FILE_DEFAULT_FILE_PREFIX. You can override + * it at runtime: + * @code + * gItsFileNamePrefix = "tmp/its_node_3_offset_12"; + * @endcode + */ +const char *gItsFileNamePrefix = ITS_FILE_DEFAULT_FILE_PREFIX; + + +/** + * Ensures that the directory (specified by `gItsFileNamePrefix`) exists. + */ +static bool ensureDirectoryExists(void) +{ + bool success = true; + struct stat st; + char filePrefix[ITS_FILE_PATH_MAX]; + char *dir; + + // Copy prefix to local buffer, because dirname() modifies its argument + strncpy(filePrefix, gItsFileNamePrefix, sizeof(filePrefix)); + filePrefix[sizeof(filePrefix) - 1] = '\0'; + + dir = dirname(filePrefix); + + // 1) Check if path already exists + if (stat(dir, &st) == 0) + { + // Exists - must be a directory + if (!S_ISDIR(st.st_mode)) + { + success = false; + } + } + else + { + // Path doesn't exist, attempt to create one. + if (mkdir(dir, ITS_DIR_MODE) != 0) + { + // Retry with stat again. + if (stat(dir, &st) != 0 || !S_ISDIR(st.st_mode)) + { + success = false; + } + } + } + + return success; +} + +/** + * Builds the file path for a given UID. + * Returns 0 on success, -1 on error. + */ +static int buildFilePath(psa_storage_uid_t aUid, char *aPath, size_t aPathSize) +{ + int result = 0; + + // Attempt to format + int ret = snprintf(aPath, aPathSize, ITS_FILE_NAME_FORMAT, + gItsFileNamePrefix, (unsigned long long)aUid); + + // If ret < 0 or ret >= aPathSize, return an error. + VerifyOrExit((ret >= 0) && ((size_t)ret < aPathSize), result = -1); + +exit: + return result; +} + +/** + * Reads an 8-byte header from the given file: + * - 4 bytes for flags (psa_storage_create_flags_t) + * - 4 bytes for data length + * + * Returns 0 on success, -1 on error. + */ +static int readHeader(FILE *aFile, psa_storage_create_flags_t *aFlags, uint32_t *aDataLen) +{ + int result = 0; + uint32_t flagsTmp; + uint32_t lenTmp; + + // Read flags + VerifyOrExit(fread(&flagsTmp, sizeof(flagsTmp), 1, aFile) == 1, result = -1); + + // Read length + VerifyOrExit(fread(&lenTmp, sizeof(lenTmp), 1, aFile) == 1, result = -1); + + *aFlags = flagsTmp; + *aDataLen = lenTmp; + +exit: + return result; +} + +/** + * Writes an 8-byte header to the given file: + * - 4 bytes for flags + * - 4 bytes for data length + * + * Returns 0 on success, -1 on error. + */ +static int writeHeader(FILE *aFile, psa_storage_create_flags_t aFlags, uint32_t aDataLen) +{ + int result = 0; + + // Write flags + VerifyOrExit(fwrite(&aFlags, sizeof(aFlags), 1, aFile) == 1, result = -1); + + // Write length + VerifyOrExit(fwrite(&aDataLen, sizeof(aDataLen), 1, aFile) == 1, result = -1); + +exit: + return result; +} + +psa_status_t psa_its_set(psa_storage_uid_t aUid, + uint32_t aDataLength, + const void *aData, + psa_storage_create_flags_t aCreateFlags) +{ + psa_status_t status = PSA_SUCCESS; + FILE *file = NULL; + char path[ITS_FILE_PATH_MAX]; + + // Validate arguments + VerifyOrExit((aData != NULL && aDataLength > 0), status = PSA_ERROR_INVALID_ARGUMENT); + // Only NONE or WRITE_ONCE => no other flags supported + VerifyOrExit((aCreateFlags & ~(PSA_STORAGE_FLAG_WRITE_ONCE)) == 0, status = PSA_ERROR_NOT_SUPPORTED); + + // Ensure directory + VerifyOrExit(ensureDirectoryExists(), status = PSA_ERROR_GENERIC_ERROR); + + // Build path + VerifyOrExit(buildFilePath(aUid, path, sizeof(path)) == 0, status = PSA_ERROR_GENERIC_ERROR); + + // If file exists, check WRITE_ONCE + file = fopen(path, "rb"); + if (file) + { + psa_storage_create_flags_t oldFlags; + uint32_t oldLen; + + if (readHeader(file, &oldFlags, &oldLen) == 0) + { + VerifyOrExit(!(oldFlags & PSA_STORAGE_FLAG_WRITE_ONCE), status = PSA_ERROR_NOT_PERMITTED); + } + + fclose(file); + file = NULL; + } + + // Create/overwrite + file = fopen(path, "wb"); + VerifyOrExit(file != NULL, status = PSA_ERROR_GENERIC_ERROR); + + // Write header + VerifyOrExit(writeHeader(file, aCreateFlags, aDataLength) == 0, status = PSA_ERROR_GENERIC_ERROR); + + // Write data + if (aDataLength > 0 && aData != NULL) + { + size_t written = fwrite(aData, 1, aDataLength, file); + VerifyOrExit(written == aDataLength, status = PSA_ERROR_GENERIC_ERROR); + } + +exit: + if (file) + { + fclose(file); + } + + return status; +} + +psa_status_t psa_its_get(psa_storage_uid_t aUid, + uint32_t aDataOffset, + uint32_t aDataLength, + void *aData, + size_t *aDataLengthOut) +{ + psa_status_t status = PSA_SUCCESS; + FILE *file = NULL; + char path[ITS_FILE_PATH_MAX]; + + VerifyOrExit(aDataLengthOut != NULL, status = PSA_ERROR_INVALID_ARGUMENT); + + if (aDataLength > 0) + { + VerifyOrExit(aData != NULL, status = PSA_ERROR_INVALID_ARGUMENT); + } + + VerifyOrExit(buildFilePath(aUid, path, sizeof(path)) == 0, status = PSA_ERROR_GENERIC_ERROR); + + file = fopen(path, "rb"); + VerifyOrExit(file != NULL, status = PSA_ERROR_DOES_NOT_EXIST); + + { + psa_storage_create_flags_t flags; + uint32_t totalLen; + + VerifyOrExit(readHeader(file, &flags, &totalLen) == 0, status = PSA_ERROR_GENERIC_ERROR); + VerifyOrExit(aDataOffset <= totalLen, status = PSA_ERROR_INVALID_ARGUMENT); + + size_t available = totalLen - aDataOffset; + size_t toCopy = (aDataLength <= available) ? aDataLength : available; + + VerifyOrExit(fseek(file, aDataOffset, SEEK_CUR) == 0, status = PSA_ERROR_GENERIC_ERROR); + + if (toCopy > 0 && aData != NULL) + { + VerifyOrExit(fread(aData, 1, toCopy, file) == toCopy, status = PSA_ERROR_GENERIC_ERROR); + } + + *aDataLengthOut = toCopy; + } + +exit: + if (file) + { + fclose(file); + } + + return status; +} + +psa_status_t psa_its_get_info(psa_storage_uid_t aUid, + struct psa_storage_info_t *aInfo) +{ + psa_status_t status = PSA_SUCCESS; + FILE *file = NULL; + char path[ITS_FILE_PATH_MAX]; + psa_storage_create_flags_t flags; + uint32_t totalLen; + + VerifyOrExit(aInfo != NULL, status = PSA_ERROR_INVALID_ARGUMENT); + VerifyOrExit(buildFilePath(aUid, path, sizeof(path)) == 0, status = PSA_ERROR_GENERIC_ERROR); + + file = fopen(path, "rb"); + VerifyOrExit(file != NULL, status = PSA_ERROR_DOES_NOT_EXIST); + + VerifyOrExit(readHeader(file, &flags, &totalLen) == 0, status = PSA_ERROR_GENERIC_ERROR); + + aInfo->size = totalLen; + aInfo->flags = flags; + +exit: + if (file) + { + fclose(file); + } + + return status; +} + +psa_status_t psa_its_remove(psa_storage_uid_t aUid) +{ + psa_status_t status = PSA_SUCCESS; + FILE *file = NULL; + char path[ITS_FILE_PATH_MAX]; + psa_storage_create_flags_t flags; + uint32_t totalLen; + + VerifyOrExit(buildFilePath(aUid, path, sizeof(path)) == 0, status = PSA_ERROR_GENERIC_ERROR); + + file = fopen(path, "rb"); + VerifyOrExit(file != NULL, status = PSA_ERROR_DOES_NOT_EXIST); + + VerifyOrExit(readHeader(file, &flags, &totalLen) == 0, status = PSA_ERROR_GENERIC_ERROR); + + // If WRITE_ONCE is set, we cannot remove it. + VerifyOrExit(!(flags & PSA_STORAGE_FLAG_WRITE_ONCE), status = PSA_ERROR_NOT_PERMITTED); + + fclose(file); + file = NULL; + + VerifyOrExit((unlink(path) == 0), status = PSA_ERROR_GENERIC_ERROR); + +exit: + if (file) + { + fclose(file); + } + + return status; +} + +#endif // #if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA diff --git a/third_party/mbedtls/native_its/src/ram/its_ram.c b/third_party/mbedtls/native_its/src/ram/its_ram.c new file mode 100644 index 00000000000..2dcc9caedc3 --- /dev/null +++ b/third_party/mbedtls/native_its/src/ram/its_ram.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements a simple in-RAM PSA ITS backend for demonstration and testing. + * + * All data is stored in memory and is not persisted after process termination. + */ + +#include "openthread-core-config.h" + +#if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA + +#include "psa/error.h" +#include "psa/internal_trusted_storage.h" + +#include + +#if !OPENTHREAD_RADIO + +#define VerifyOrExit(aCondition, aAction) \ + do \ + { \ + if (!(aCondition)) \ + { \ + aAction; \ + goto exit; \ + } \ + } while (0) + +/** + * @def RAM_ITS_MAX_KEYS + * + * The maximum number of PSA ITS entries that can be stored in RAM. + */ +#define RAM_ITS_MAX_KEYS 64 + +/** + * @def RAM_ITS_MAX_DATA_SIZE + * + * The maximum size (in bytes) of data that can be stored for each entry. + */ +#define RAM_ITS_MAX_DATA_SIZE 128 + + +/** + * Represents a single PSA ITS record stored in RAM. + * + */ +typedef struct +{ + bool mInUse; // Whether this slot is occupied + psa_storage_uid_t mUid; // Unique ID + psa_storage_create_flags_t mFlags; // Storage flags (e.g. WRITE_ONCE) + uint32_t mDataLen; // Current size of stored data + uint8_t mData[RAM_ITS_MAX_DATA_SIZE]; // Raw data storage +} RamItsEntry; + +/** + * Array of entries for RAM-based ITS storage. + * + */ +static RamItsEntry sRamItsEntries[RAM_ITS_MAX_KEYS]; + +/** + * Finds an existing entry by UID. + * + * @param[in] aUid The UID value to search for. + * + * @returns The index of the matching entry, or -1 if not found. + * + */ +static int RamItsFindEntry(psa_storage_uid_t aUid) +{ + for (int i = 0; i < RAM_ITS_MAX_KEYS; i++) + { + if (sRamItsEntries[i].mInUse && (sRamItsEntries[i].mUid == aUid)) + { + return i; + } + } + + return -1; +} + +/** + * Finds a free slot in the storage array. + * + * @returns The index of a free slot, or -1 if none is available. + * + */ +static int RamItsFindFreeSlot(void) +{ + for (int i = 0; i < RAM_ITS_MAX_KEYS; i++) + { + if (!sRamItsEntries[i].mInUse) + { + return i; + } + } + + return -1; +} + +psa_status_t psa_its_set(psa_storage_uid_t aUid, + uint32_t aDataLength, + const void *aData, + psa_storage_create_flags_t aCreateFlags) +{ + psa_status_t status = PSA_SUCCESS; + int idx = -1; + + VerifyOrExit(!(aData == NULL && aDataLength > 0), status = PSA_ERROR_INVALID_ARGUMENT); + + // Allow only NONE or WRITE_ONCE flags. Any others => Not supported. + VerifyOrExit((aCreateFlags & ~(PSA_STORAGE_FLAG_WRITE_ONCE)) == 0, + status = PSA_ERROR_NOT_SUPPORTED); + + // Data length must not exceed our internal buffer size. + VerifyOrExit(aDataLength <= RAM_ITS_MAX_DATA_SIZE, status = PSA_ERROR_INVALID_ARGUMENT); + + // Find existing entry, if any. + idx = RamItsFindEntry(aUid); + if (idx >= 0) + { + // Entry already exists. + + // If WRITE_ONCE is set, we cannot overwrite it. + VerifyOrExit(!(sRamItsEntries[idx].mFlags & PSA_STORAGE_FLAG_WRITE_ONCE), status = PSA_ERROR_NOT_PERMITTED); + + // Overwrite existing entry. + sRamItsEntries[idx].mDataLen = aDataLength; + + if (aDataLength > 0 && aData != NULL) + { + memcpy(sRamItsEntries[idx].mData, aData, aDataLength); + } + + sRamItsEntries[idx].mFlags = aCreateFlags; + } + else + { + // Need a new entry. + idx = RamItsFindFreeSlot(); + VerifyOrExit(idx >= 0, status = PSA_ERROR_INSUFFICIENT_STORAGE); + + sRamItsEntries[idx].mInUse = true; + sRamItsEntries[idx].mUid = aUid; + sRamItsEntries[idx].mFlags = aCreateFlags; + sRamItsEntries[idx].mDataLen = aDataLength; + + if (aDataLength > 0 && aData != NULL) + { + memcpy(sRamItsEntries[idx].mData, aData, aDataLength); + } + } + +exit: + return status; +} + +psa_status_t psa_its_get(psa_storage_uid_t aUid, + uint32_t aDataOffset, + uint32_t aDataLength, + void *aData, + size_t *aDataLengthOut) +{ + psa_status_t status = PSA_SUCCESS; + int idx; + + // Validate pointers. + VerifyOrExit(aDataLengthOut != NULL, status = PSA_ERROR_INVALID_ARGUMENT); + if (aDataLength > 0) + { + VerifyOrExit(aData != NULL, status = PSA_ERROR_INVALID_ARGUMENT); + } + + idx = RamItsFindEntry(aUid); + VerifyOrExit(idx >= 0, status = PSA_ERROR_DOES_NOT_EXIST); + + // Check offset validity. + VerifyOrExit(aDataOffset <= sRamItsEntries[idx].mDataLen, status = PSA_ERROR_INVALID_ARGUMENT); + + // Determine how many bytes to copy. + { + size_t available = sRamItsEntries[idx].mDataLen - aDataOffset; + size_t toCopy = (aDataLength <= available) ? aDataLength : available; + + if (toCopy > 0) + { + memcpy(aData, &sRamItsEntries[idx].mData[aDataOffset], toCopy); + } + + *aDataLengthOut = toCopy; + } + +exit: + return status; +} + +psa_status_t psa_its_get_info(psa_storage_uid_t aUid, + struct psa_storage_info_t *aInfo) +{ + psa_status_t status = PSA_SUCCESS; + int idx; + + VerifyOrExit(aInfo != NULL, status = PSA_ERROR_INVALID_ARGUMENT); + + idx = RamItsFindEntry(aUid); + VerifyOrExit(idx >= 0, status = PSA_ERROR_DOES_NOT_EXIST); + + aInfo->size = sRamItsEntries[idx].mDataLen; + aInfo->flags = sRamItsEntries[idx].mFlags; + +exit: + return status; +} + +psa_status_t psa_its_remove(psa_storage_uid_t aUid) +{ + psa_status_t status = PSA_SUCCESS; + int idx; + + idx = RamItsFindEntry(aUid); + VerifyOrExit(idx >= 0, status = PSA_ERROR_DOES_NOT_EXIST); + + // If WRITE_ONCE is set, we cannot remove it. + VerifyOrExit(!(sRamItsEntries[idx].mFlags & PSA_STORAGE_FLAG_WRITE_ONCE), + status = PSA_ERROR_NOT_PERMITTED); + + // Clear the slot. + memset(sRamItsEntries[idx].mData, 0, sizeof(sRamItsEntries[idx].mData)); + sRamItsEntries[idx].mDataLen = 0; + sRamItsEntries[idx].mUid = 0; + sRamItsEntries[idx].mFlags = 0; + sRamItsEntries[idx].mInUse = false; + +exit: + return status; +} + +#endif // #if !OPENTHREAD_RADIO + +#endif // #if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA diff --git a/third_party/mbedtls/psa-crypto-config.h b/third_party/mbedtls/psa-crypto-config.h new file mode 100644 index 00000000000..43a7c907ef7 --- /dev/null +++ b/third_party/mbedtls/psa-crypto-config.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +// Spans multiple lines to avoid being processed by unifdef +#ifndef \ + PSA_CRYPTO_CONFIG_H +#define PSA_CRYPTO_CONFIG_H + +#include "openthread-core-config.h" + +#include + +#define PSA_WANT_ALG_CBC_NO_PADDING 1 +#define PSA_WANT_ALG_CBC_PKCS7 1 +#define PSA_WANT_ALG_CCM 1 +#define PSA_WANT_ALG_CCM_STAR_NO_TAG 1 +#define PSA_WANT_ALG_CMAC 1 +#define PSA_WANT_ALG_CFB 1 +#define PSA_WANT_ALG_CTR 1 +#define PSA_WANT_ALG_DETERMINISTIC_ECDSA 1 +#define PSA_WANT_ALG_ECB_NO_PADDING 1 +#define PSA_WANT_ALG_ECDH 1 +#define PSA_WANT_ALG_ECDSA 1 +#define PSA_WANT_ALG_JPAKE 1 +#define PSA_WANT_ALG_GCM 1 +#define PSA_WANT_ALG_HKDF 1 +#define PSA_WANT_ALG_HKDF_EXTRACT 1 +#define PSA_WANT_ALG_HKDF_EXPAND 1 +#define PSA_WANT_ALG_HMAC 1 +#define PSA_WANT_ALG_PBKDF2_HMAC 1 +#define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1 +#define PSA_WANT_ALG_RIPEMD160 1 +#define PSA_WANT_ALG_SHA_1 1 +#define PSA_WANT_ALG_SHA_224 1 +#define PSA_WANT_ALG_SHA_256 1 +#define PSA_WANT_ALG_TLS12_PRF 1 +#define PSA_WANT_ALG_TLS12_PSK_TO_MS 1 +#define PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS 1 + +#define PSA_WANT_ECC_SECP_K1_256 1 +#define PSA_WANT_ECC_SECP_R1_256 1 + +#define PSA_WANT_KEY_TYPE_DERIVE 1 +#define PSA_WANT_KEY_TYPE_PASSWORD 1 +#define PSA_WANT_KEY_TYPE_PASSWORD_HASH 1 +#define PSA_WANT_KEY_TYPE_HMAC 1 +#define PSA_WANT_KEY_TYPE_AES 1 +#define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1 +#define PSA_WANT_KEY_TYPE_RAW_DATA 1 + +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1 +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1 +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1 +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1 +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE 1 + +#endif /* PSA_CRYPTO_CONFIG_H */