diff --git a/cmake/spe-CMakeLists.cmake b/cmake/spe-CMakeLists.cmake index 1915a9c4d..b92e97b62 100644 --- a/cmake/spe-CMakeLists.cmake +++ b/cmake/spe-CMakeLists.cmake @@ -13,7 +13,7 @@ cmake_minimum_required(VERSION 3.15) include(spe_config) include(spe_export) -set_target_properties(tfm_config psa_interface PROPERTIES IMPORTED_GLOBAL True) +set_target_properties(tfm_config psa_interface psa_crypto_config PROPERTIES IMPORTED_GLOBAL True) target_link_libraries(tfm_config INTERFACE psa_interface) # In actual NS integration, NS side build should include the source files diff --git a/cmake/version.cmake b/cmake/version.cmake index c226daeb2..cac34e033 100644 --- a/cmake/version.cmake +++ b/cmake/version.cmake @@ -16,7 +16,7 @@ execute_process(COMMAND git describe --tags --always # In a repository cloned with --no-tags option TFM_VERSION_FULL will be a hash # only hence checking it for a tag format to accept as valid version. -string(FIND ${TFM_VERSION_FULL} "TF-M" TFM_TAG) +string(FIND ${TFM_VERSION_FULL} "v" TFM_TAG) if(TFM_TAG EQUAL -1) set(TFM_VERSION_FULL v${TFM_VERSION_MANUAL}) message(WARNING "Actual TF-M version is not available from Git repository. Settled to " ${TFM_VERSION_FULL}) diff --git a/config/check_config.cmake b/config/check_config.cmake index ca05c4af5..6e613f9f3 100644 --- a/config/check_config.cmake +++ b/config/check_config.cmake @@ -17,6 +17,8 @@ tfm_invalid_config(TFM_MULTI_CORE_TOPOLOGY AND TFM_NS_MANAGE_NSID) tfm_invalid_config(TFM_PLAT_SPECIFIC_MULTI_CORE_COMM AND NOT TFM_MULTI_CORE_TOPOLOGY) tfm_invalid_config(TFM_ISOLATION_LEVEL EQUAL 3 AND CONFIG_TFM_STACK_WATERMARKS) +tfm_invalid_config(CONFIG_TFM_LOG_SHARE_UART AND NOT SECURE_UART1) + ########################## BL2 ################################################# get_property(MCUBOOT_STRATEGY_LIST CACHE MCUBOOT_UPGRADE_STRATEGY PROPERTY STRINGS) diff --git a/config/config_base.cmake b/config/config_base.cmake index 7dae0b8d8..af4256d12 100644 --- a/config/config_base.cmake +++ b/config/config_base.cmake @@ -81,6 +81,9 @@ set(CONFIG_TFM_HALT_ON_CORE_PANIC OFF CACHE BOOL "On fatal e set(CONFIG_TFM_STACK_WATERMARKS OFF CACHE BOOL "Whether to pre-fill partition stacks with a set value to help determine stack usage") +set(PROJECT_CONFIG_HEADER_FILE "${CMAKE_SOURCE_DIR}/config/config_base.h" CACHE FILEPATH "User defined header file for TF-M config") + +set(CONFIG_TFM_LOG_SHARE_UART OFF CACHE BOOL "Allow TF-M and the non-secure application to share the UART instance. TF-M will use it while it is booting, after which the non-secure application will use it until an eventual fatal error is handled and logged by TF-M. Logging from TF-M will therefore otherwise be suppressed") ############################ Platform ########################################## set(NUM_MAILBOX_QUEUE_SLOT 1 CACHE BOOL "Number of mailbox queue slots") @@ -121,6 +124,7 @@ set(BL2_TRAILER_SIZE 0x000 CACHE STRING "BL2 Trailer set(TFM_PARTITION_PROTECTED_STORAGE OFF CACHE BOOL "Enable Protected Storage partition") set(PS_ENCRYPTION ON CACHE BOOL "Enable encryption for Protected Storage partition") set(PS_CRYPTO_AEAD_ALG PSA_ALG_GCM CACHE STRING "The AEAD algorithm to use for authenticated encryption in Protected Storage") +set(PS_CRYPTO_KDF_ALG PSA_ALG_HKDF\(PSA_ALG_SHA_256\) CACHE STRING "KDF Algorithm to use for Protect Storage") set(TFM_PARTITION_INTERNAL_TRUSTED_STORAGE OFF CACHE BOOL "Enable Internal Trusted Storage partition") set(ITS_ENCRYPTION OFF CACHE BOOL "Enable authenticated encryption of ITS files using platform specific APIs") diff --git a/config/profile/config_profile_medium.h b/config/profile/config_profile_medium.h index 89f8eeb4a..a9f7e14fc 100644 --- a/config/profile/config_profile_medium.h +++ b/config/profile/config_profile_medium.h @@ -72,7 +72,7 @@ /* Enable PSA Crypto Cipher module */ #ifndef CRYPTO_CIPHER_MODULE_ENABLED -#define CRYPTO_CIPHER_MODULE_ENABLED 1 +#define CRYPTO_CIPHER_MODULE_ENABLED 0 #endif /* Enable PSA Crypto asymmetric key signature module */ diff --git a/config/profile/config_profile_medium_arotless.h b/config/profile/config_profile_medium_arotless.h index 5c7cdd092..cbfd66c89 100644 --- a/config/profile/config_profile_medium_arotless.h +++ b/config/profile/config_profile_medium_arotless.h @@ -72,7 +72,7 @@ /* Enable PSA Crypto Cipher module */ #ifndef CRYPTO_CIPHER_MODULE_ENABLED -#define CRYPTO_CIPHER_MODULE_ENABLED 1 +#define CRYPTO_CIPHER_MODULE_ENABLED 0 #endif /* Enable PSA Crypto asymmetric key signature module */ diff --git a/config/profile/config_profile_small.h b/config/profile/config_profile_small.h index fc5cbd8b0..868353c0a 100644 --- a/config/profile/config_profile_small.h +++ b/config/profile/config_profile_small.h @@ -69,7 +69,7 @@ /* Enable PSA Crypto Cipher module */ #ifndef CRYPTO_CIPHER_MODULE_ENABLED -#define CRYPTO_CIPHER_MODULE_ENABLED 1 +#define CRYPTO_CIPHER_MODULE_ENABLED 0 #endif /* Enable PSA Crypto asymmetric key signature module */ diff --git a/config/profile/profile_medium.conf b/config/profile/profile_medium.conf index 251a8864d..565dbc4b2 100644 --- a/config/profile/profile_medium.conf +++ b/config/profile/profile_medium.conf @@ -46,7 +46,7 @@ CONFIG_CRYPTO_KEY_MODULE_ENABLED=y CONFIG_CRYPTO_AEAD_MODULE_ENABLED=y CONFIG_CRYPTO_MAC_MODULE_ENABLED=y CONFIG_CRYPTO_HASH_MODULE_ENABLED=y -CONFIG_CRYPTO_CIPHER_MODULE_ENABLED=y +CONFIG_CRYPTO_CIPHER_MODULE_ENABLED=n CONFIG_CRYPTO_ASYM_SIGN_MODULE_ENABLED=y CONFIG_CRYPTO_ASYM_ENCRYPT_MODULE_ENABLED=n CONFIG_CRYPTO_KEY_DERIVATION_MODULE_ENABLED=y diff --git a/config/profile/profile_medium_arotless.conf b/config/profile/profile_medium_arotless.conf index d992606a2..8e0acfd68 100644 --- a/config/profile/profile_medium_arotless.conf +++ b/config/profile/profile_medium_arotless.conf @@ -42,7 +42,7 @@ CONFIG_CRYPTO_KEY_MODULE_ENABLED=y CONFIG_CRYPTO_AEAD_MODULE_ENABLED=y CONFIG_CRYPTO_MAC_MODULE_ENABLED=y CONFIG_CRYPTO_HASH_MODULE_ENABLED=y -CONFIG_CRYPTO_CIPHER_MODULE_ENABLED=y +CONFIG_CRYPTO_CIPHER_MODULE_ENABLED=n CONFIG_CRYPTO_ASYM_SIGN_MODULE_ENABLED=y CONFIG_CRYPTO_ASYM_ENCRYPT_MODULE_ENABLED=n CONFIG_CRYPTO_KEY_DERIVATION_MODULE_ENABLED=y diff --git a/config/profile/profile_small.conf b/config/profile/profile_small.conf index af314c79d..261430667 100644 --- a/config/profile/profile_small.conf +++ b/config/profile/profile_small.conf @@ -40,7 +40,7 @@ CONFIG_CRYPTO_KEY_MODULE_ENABLED=y CONFIG_CRYPTO_AEAD_MODULE_ENABLED=y CONFIG_CRYPTO_MAC_MODULE_ENABLED=y CONFIG_CRYPTO_HASH_MODULE_ENABLED=y -CONFIG_CRYPTO_CIPHER_MODULE_ENABLED=y +CONFIG_CRYPTO_CIPHER_MODULE_ENABLED=n CONFIG_CRYPTO_ASYM_SIGN_MODULE_ENABLED=n CONFIG_CRYPTO_ASYM_ENCRYPT_MODULE_ENABLED=n CONFIG_CRYPTO_KEY_DERIVATION_MODULE_ENABLED=y diff --git a/docs/security/security_advisories/debug_log_vulnerability.rst b/docs/security/security_advisories/debug_log_vulnerability.rst new file mode 100644 index 000000000..279dca0be --- /dev/null +++ b/docs/security/security_advisories/debug_log_vulnerability.rst @@ -0,0 +1,69 @@ +Advisory TFMV-7 +=============== + ++------------------+-----------------------------------------------------------+ +| Title | ARoT can access PRoT data via debug logging functionality | ++==================+===========================================================+ +| CVE ID | `CVE-2023-51712`_ | ++------------------+-----------------------------------------------------------+ +| Public | The issue was publicly reported on 2023.12.04 | +| Disclosure Date | | ++------------------+-----------------------------------------------------------+ +| Versions | All version up to TF-M v2.0.0 inclusive | +| Affected | | ++------------------+-----------------------------------------------------------+ +| Configurations | IPC mode with TFM_SP_LOG_RAW_ENABLED=1 | ++------------------+-----------------------------------------------------------+ +| Impact | A malicious ARoT partition can expose any part of memory | +| | via stdio interface if TFM_SP_LOG_RAW_ENABLED is set | ++------------------+-----------------------------------------------------------+ +| Fix Version | TBD | ++------------------+-----------------------------------------------------------+ +| Credit | Roman Mazurak, Infineon | ++------------------+-----------------------------------------------------------+ + +Background +---------- + +TF-M log subsystem if enabled by ``TFM_SP_LOG_RAW_ENABLED`` config option, +uses a SVC call to print logging messages on the stdio output interface. +Since the SVC handler has the highest privilege level and full memory +access, this communication channel can be exploited to expose any memory content +to stdout device, usually UART. +The logging subsystem is available to the secure side only but in isolation +level 2 and higher PSA Root of Trust partitions (PRoT) shall be protected +from an access from Application Root of Trust (ARoT) partitions. Although +a direct call of ``tfm_hal_output_sp_log()`` from ARoT partition will be +blocked by MPU raising the ``MemoryManagement()`` exception, a malicious +ARoT partition can create an alternative SVC call to output any memory +data like this: + +.. code-block:: c + + static int tfm_output_unpriv_string(const unsigned char *str, size_t len) + { + __ASM volatile("SVC %0 \n" + "BX LR \n" + : : "I" (2)); + } + +Impact +------ + +In IPC mode with PSA isolation level 2 and higher and ``TFM_SP_LOG_RAW_ENABLED`` +option enabled an ARoT partition can expose to the stdout device any memory +data using TF-M logging subsystem via SVC call. + +Mitigation +---------- + +Ensure that data sent for logging belongs to the current partition. For that purpose +``tfm_hal_memory_check(curr_partition->boundary, data, size, TFM_HAL_ACCESS_READABLE)`` +is added to the logging function of the SVC handler. If the check fails +then ``tfm_core_panic()`` is invoked and system halts. + +.. _CVE-2023-51712: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-51712 + +--------------------- + +*Copyright (c) 2024, Arm Limited. All rights reserved.* diff --git a/docs/security/security_advisories/index.rst b/docs/security/security_advisories/index.rst index 249f38255..c7829cedf 100644 --- a/docs/security/security_advisories/index.rst +++ b/docs/security/security_advisories/index.rst @@ -12,6 +12,7 @@ Security Advisories profile_small_key_id_encoding_vulnerability fwu_write_vulnerability cc3xx_partial_tag_compare_on_chacha20_poly1305 + debug_log_vulnerability +------------+-----------------------------------------------------------------+ | ID | Title | @@ -33,6 +34,8 @@ Security Advisories | |TFMV-6| | Partial tag comparison when using Chacha20-Poly1305 on the PSA | | | driver API interface in CryptoCell enabled platforms | +------------+-----------------------------------------------------------------+ +| |TFMV-7| | ARoT can access PRoT data via debug logging functionality | ++------------+-----------------------------------------------------------------+ .. |TFMV-1| replace:: :doc:`TFMV-1 ` .. |TFMV-2| replace:: :doc:`TFMV-2 ` @@ -40,6 +43,7 @@ Security Advisories .. |TFMV-4| replace:: :doc:`TFMV-4 ` .. |TFMV-5| replace:: :doc:`TFMV-5 ` .. |TFMV-6| replace:: :doc:`TFMV-6 ` +.. |TFMV-7| replace:: :doc:`TFMV-7 ` -------------- diff --git a/interface/include/psa/crypto_extra.h b/interface/include/psa/crypto_extra.h index 2dd559019..6709b7b10 100644 --- a/interface/include/psa/crypto_extra.h +++ b/interface/include/psa/crypto_extra.h @@ -127,6 +127,1365 @@ void psa_set_key_enrollment_algorithm( psa_algorithm_t psa_get_key_enrollment_algorithm( const psa_key_attributes_t *attributes); + +#define PSA_KEY_TYPE_SPAKE2P_KEY_PAIR_BASE ((psa_key_type_t) 0x7400) +#define PSA_KEY_TYPE_SPAKE2P_PUBLIC_KEY_BASE ((psa_key_type_t) 0x4400) +#define PSA_KEY_TYPE_SPAKE2P_CURVE_MASK ((psa_key_type_t) 0x00ff) + + /** SPAKE2+ key pair. Both the prover and verifier key. + * + * The size of a SPAKE2+ key is the size associated with the elliptic curve + * group. See the documentation of each elliptic curve family for details. + * To construct a SPAKE2+ key pair, it must be output from a key derivation + * operation. + * The corresponding public key can be exported using psa_export_public_key(). + * See also #PSA_KEY_TYPE_SPAKE2P_PUBLIC_KEY(). + * + * \param curve A value of type psa_ecc_family_t that identifies the elliptic + * curve family to be used. + */ +#define PSA_KEY_TYPE_SPAKE2P_KEY_PAIR(curve) \ + ((psa_key_type_t) (PSA_KEY_TYPE_SPAKE2P_KEY_PAIR_BASE | (curve))) + + /** SPAKE2+ public key. The verifier key. + * + * The size of an SPAKE2+ public key is the same as the corresponding private + * key. See #PSA_KEY_TYPE_SPAKE2P_KEY_PAIR() and the documentation of each + * elliptic curve family for details. + * To construct a SPAKE2+ public key, it must be imported. + * + * \param curve A value of type psa_ecc_family_t that identifies the elliptic + * curve family to be used. + */ +#define PSA_KEY_TYPE_SPAKE2P_PUBLIC_KEY(curve) \ + ((psa_key_type_t) (PSA_KEY_TYPE_SPAKE2P_PUBLIC_KEY_BASE | (curve))) + + /** Whether a key type is a SPAKE2+ key (pair or public-only). */ +#define PSA_KEY_TYPE_IS_SPAKE2P(type) \ + ((PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) & \ + ~PSA_KEY_TYPE_SPAKE2P_CURVE_MASK) == \ + PSA_KEY_TYPE_SPAKE2P_PUBLIC_KEY_BASE) + /** Whether a key type is a SPAKE2+ key pair. */ +#define PSA_KEY_TYPE_IS_SPAKE2P_KEY_PAIR(type) \ + (((type) & ~PSA_KEY_TYPE_SPAKE2P_CURVE_MASK) == \ + PSA_KEY_TYPE_SPAKE2P_KEY_PAIR_BASE) + /** Whether a key type is a SPAKE2+ public key. */ +#define PSA_KEY_TYPE_IS_SPAKE2P_PUBLIC_KEY(type) \ + (((type) & ~PSA_KEY_TYPE_SPAKE2P_CURVE_MASK) == \ + PSA_KEY_TYPE_SPAKE2P_PUBLIC_KEY_BASE) + /** Extract the curve from a SPAKE2+ key type. */ +#define PSA_KEY_TYPE_SPAKE2P_GET_FAMILY(type) \ + ((psa_ecc_family_t) (PSA_KEY_TYPE_IS_SPAKE2P(type) ? \ + ((type) & PSA_KEY_TYPE_SPAKE2P_CURVE_MASK) : \ + 0)) + +#define PSA_KEY_TYPE_SRP_KEY_PAIR_BASE ((psa_key_type_t) 0x7700) +#define PSA_KEY_TYPE_SRP_PUBLIC_KEY_BASE ((psa_key_type_t) 0x4700) +#define PSA_KEY_TYPE_SRP_GROUP_MASK ((psa_key_type_t) 0x00ff) + + /** SRP key pair. Both the client and server key. + * + * The size of a SRP key is the size associated with the Diffie-Hellman + * group. See the documentation of each Diffie-Hellman group for details. + * To construct a SRP key pair, the password hash must be imported. + * The corresponding public key (password verifier) can be exported using + * psa_export_public_key(). See also #PSA_KEY_TYPE_SRP_PUBLIC_KEY(). + * + * \param group A value of type ::psa_dh_family_t that identifies the + * Diffie-Hellman group to be used. + */ +#define PSA_KEY_TYPE_SRP_KEY_PAIR(group) \ + ((psa_key_type_t) (PSA_KEY_TYPE_SRP_KEY_PAIR_BASE | (group))) + + /** SRP public key. The server key (password verifier). + * + * The size of an SRP public key is the same as the corresponding private + * key. See #PSA_KEY_TYPE_SRP_KEY_PAIR() and the documentation of each + * Diffie-Hellman group for details. + * To construct a SRP public key, it must be imported. The key size + * in attributes must not be zero. + * + * \param group A value of type ::psa_dh_family_t that identifies the + * Diffie-Hellman group to be used. + */ +#define PSA_KEY_TYPE_SRP_PUBLIC_KEY(group) \ + ((psa_key_type_t) (PSA_KEY_TYPE_SRP_PUBLIC_KEY_BASE | (group))) + + /** Whether a key type is a SRP key (pair or public-only). */ +#define PSA_KEY_TYPE_IS_SRP(type) \ + ((PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) & \ + ~PSA_KEY_TYPE_SRP_GROUP_MASK) == \ + PSA_KEY_TYPE_SRP_PUBLIC_KEY_BASE) + /** Whether a key type is a SRP key pair. */ +#define PSA_KEY_TYPE_IS_SRP_KEY_PAIR(type) \ + (((type) & ~PSA_KEY_TYPE_SRP_GROUP_MASK) == \ + PSA_KEY_TYPE_SRP_KEY_PAIR_BASE) + /** Whether a key type is a SRP public key. */ +#define PSA_KEY_TYPE_IS_SRP_PUBLIC_KEY(type) \ + (((type) & ~PSA_KEY_TYPE_SRP_GROUP_MASK) == \ + PSA_KEY_TYPE_SRP_PUBLIC_KEY_BASE) + /** Extract the curve from a SRP key type. */ +#define PSA_KEY_TYPE_SRP_GET_FAMILY(type) \ + ((psa_ecc_family_t) (PSA_KEY_TYPE_IS_SRP(type) ? \ + ((type) & PSA_KEY_TYPE_SRP_GROUP_MASK) : \ + 0)) + +#define PSA_ALG_CATEGORY_PAKE ((psa_algorithm_t) 0x0a000000) + +/** Whether the specified algorithm is a password-authenticated key exchange. + * + * \param alg An algorithm identifier (value of type #psa_algorithm_t). + * + * \return 1 if \p alg is a password-authenticated key exchange (PAKE) + * algorithm, 0 otherwise. + * This macro may return either 0 or 1 if \p alg is not a supported + * algorithm identifier. + */ +#define PSA_ALG_IS_PAKE(alg) \ + (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_PAKE) + +/** The Password-authenticated key exchange by juggling (J-PAKE) algorithm. + * + * This is J-PAKE as defined by RFC 8236, instantiated with the following + * parameters: + * + * - The group can be either an elliptic curve or defined over a finite field. + * - Schnorr NIZK proof as defined by RFC 8235 and using the same group as the + * J-PAKE algorithm. + * - A cryptographic hash function. + * + * To select these parameters and set up the cipher suite, call these functions + * in any order: + * + * \code + * psa_pake_cs_set_algorithm(cipher_suite, PSA_ALG_JPAKE(hash)); + * psa_pake_cs_set_primitive(cipher_suite, + * PSA_PAKE_PRIMITIVE(type, family, bits)); + * \endcode + * + * For more information on how to set a specific curve or field, refer to the + * documentation of the individual \c PSA_PAKE_PRIMITIVE_TYPE_XXX constants. + * + * After initializing a J-PAKE operation, call + * + * \code + * psa_pake_setup(operation, key, cipher_suite); + * psa_pake_set_user(operation, ...); + * psa_pake_set_peer(operation, ...); + * \endcode + * + * The password is provided as a key. This can be the password text itself, + * in an agreed character encoding, or some value derived from the password + * as required by a higher level protocol. + * + * (The implementation converts the key material to a number as described in + * Section 2.3.8 of _SEC 1: Elliptic Curve Cryptography_ + * (https://www.secg.org/sec1-v2.pdf), before reducing it modulo \c q. Here + * \c q is order of the group defined by the primitive set in the cipher suite. + * The \c psa_pake_setup() function returns an error if the result of the + * reduction is 0.) + * + * The key exchange flow for J-PAKE is as follows: + * -# To get the first round data that needs to be sent to the peer, call + * \code + * // Get g1 + * psa_pake_output(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * // Get the ZKP public key for x1 + * psa_pake_output(operation, #PSA_PAKE_STEP_ZK_PUBLIC, ...); + * // Get the ZKP proof for x1 + * psa_pake_output(operation, #PSA_PAKE_STEP_ZK_PROOF, ...); + * // Get g2 + * psa_pake_output(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * // Get the ZKP public key for x2 + * psa_pake_output(operation, #PSA_PAKE_STEP_ZK_PUBLIC, ...); + * // Get the ZKP proof for x2 + * psa_pake_output(operation, #PSA_PAKE_STEP_ZK_PROOF, ...); + * \endcode + * -# To provide the first round data received from the peer to the operation, + * call + * \code + * // Set g3 + * psa_pake_input(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * // Set the ZKP public key for x3 + * psa_pake_input(operation, #PSA_PAKE_STEP_ZK_PUBLIC, ...); + * // Set the ZKP proof for x3 + * psa_pake_input(operation, #PSA_PAKE_STEP_ZK_PROOF, ...); + * // Set g4 + * psa_pake_input(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * // Set the ZKP public key for x4 + * psa_pake_input(operation, #PSA_PAKE_STEP_ZK_PUBLIC, ...); + * // Set the ZKP proof for x4 + * psa_pake_input(operation, #PSA_PAKE_STEP_ZK_PROOF, ...); + * \endcode + * -# To get the second round data that needs to be sent to the peer, call + * \code + * // Get A + * psa_pake_output(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * // Get ZKP public key for x2*s + * psa_pake_output(operation, #PSA_PAKE_STEP_ZK_PUBLIC, ...); + * // Get ZKP proof for x2*s + * psa_pake_output(operation, #PSA_PAKE_STEP_ZK_PROOF, ...); + * \endcode + * -# To provide the second round data received from the peer to the operation, + * call + * \code + * // Set B + * psa_pake_input(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * // Set ZKP public key for x4*s + * psa_pake_input(operation, #PSA_PAKE_STEP_ZK_PUBLIC, ...); + * // Set ZKP proof for x4*s + * psa_pake_input(operation, #PSA_PAKE_STEP_ZK_PROOF, ...); + * \endcode + * -# To access the shared secret call + * \code + * // Get Ka=Kb=K + * psa_pake_get_shared_key() + * \endcode + * + * For more information consult the documentation of the individual + * \c PSA_PAKE_STEP_XXX constants. + * + * At this point there is a cryptographic guarantee that only the authenticated + * party who used the same password is able to compute the key. But there is no + * guarantee that the peer is the party it claims to be and was able to do so. + * + * That is, the authentication is only implicit (the peer is not authenticated + * at this point, and no action should be taken that assume that they are - like + * for example accessing restricted files). + * + * To make the authentication explicit there are various methods, see Section 5 + * of RFC 8236 for two examples. + * + */ +#define PSA_ALG_JPAKE_BASE ((psa_algorithm_t) 0x0a000100) +#define PSA_ALG_JPAKE(hash_alg) (PSA_ALG_JPAKE_BASE | ((hash_alg) & PSA_ALG_HASH_MASK)) +#define PSA_ALG_IS_JPAKE(alg) (((alg) & ~PSA_ALG_HASH_MASK) == PSA_ALG_JPAKE_BASE) + + /** The SPAKE2+ algorithm. + * + * SPAKE2+ is the augmented password-authenticated key exchange protocol, + * defined by RFC9383. SPAKE2+ includes confirmation of the shared secret + * key that results from the key exchange. + * SPAKE2+ is required by Matter Specification, Version 1.2, as MATTER_PAKE. + * Matter uses an earlier draft of the SPAKE2+ protocol: "SPAKE2+, an + * Augmented PAKE (Draft 02)". + * Although the operation of the PAKE is similar for both of these variants, + * they have different key schedules for the derivation of the shared secret. + * + * When setting up a PAKE cipher suite to use the SPAKE2+ protocol defined + * in RFC9383: + * - For cipher-suites that use HMAC for key confirmation, use the + * PSA_ALG_SPAKE2P_HMAC() algorithm, parameterized by the required hash + * algorithm. + * - For cipher-suites that use CMAC-AES-128 for key confirmation, use the + * PSA_ALG_SPAKE2P_CMAC() algorithm, parameterized by the required hash + * algorithm. + * - Use a PAKE primitive for the required elliptic curve. + * + * For example, the following code creates a cipher suite to select SPAKE2+ + * using edwards25519 with the SHA-256 hash function: + * + * \code + * psa_pake_cipher_suite_t cipher_suite = PSA_PAKE_CIPHER_SUITE_INIT; + * psa_pake_cs_set_algorithm(cipher_suite, PSA_ALG_SPAKE2P_HMAC(PSA_ALG_SHA_256)); + * psa_pake_cs_set_primitive(&cipher_suite, + * PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, + * PSA_ECC_FAMILY_TWISTED_EDWARDS, 255)); + * \endcode + * + * When setting up a PAKE cipher suite to use the SPAKE2+ protocol used by + * Matter: + * - Use the PSA_ALG_SPAKE2P_MATTER algorithm. + * - Use the PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, + * PSA_ECC_FAMILY_SECP_R1, 256) + * PAKE primitive. + * + * The following code creates a cipher suite to select the Matter variant of + * SPAKE2+: + * + * \code + * psa_pake_cipher_suite_t cipher_suite = PSA_PAKE_CIPHER_SUITE_INIT; + * psa_pake_cs_set_algorithm(&cipher_suite, PSA_ALG_SPAKE2P_MATTER); + * psa_pake_cs_set_primitive(&cipher_suite, + * PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, + * PSA_ECC_FAMILY_SECP_R1, 256)); + * \endcode + * + * After initializing a SPAKE2+ operation, call + * + * \code + * psa_pake_setup(operation, password, cipher_suite); + * psa_pake_set_role(operation, ...); + * \endcode + * + * The password provided to the client side must be of type + * #PSA_KEY_TYPE_SPAKE2P_KEY_PAIR. + * The password provided to the server side must be of type + * #PSA_KEY_TYPE_SPAKE2P_PUBLIC_KEY. + * + * The role set by \c psa_pake_set_role() must be either + * \c PSA_PAKE_ROLE_CLIENT or \c PSA_PAKE_ROLE_SERVER. + * + * Then provide any additional, optional parameters: + * + * \code + * psa_pake_set_user(operation, ...); + * psa_pake_set_peer(operation, ...); + * psa_pake_set_context(operation, ...); + * \endcode + * + * + * The key exchange flow for a SPAKE2+ client is as follows: + * \code + * // send shareP + * psa_pake_output(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * // receive shareV + * psa_pake_input(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * // receive confirmV + * psa_pake_input(operation, #PSA_PAKE_STEP_CONFIRM, ...); + * // send confirmP + * psa_pake_output(operation, #PSA_PAKE_STEP_CONFIRM, ...); + * // get K_shared + * psa_pake_get_shared_key(operation, ...); + * \endcode + * + * The key exchange flow for a SPAKE2+ server is as follows: + * \code + * // receive shareP + * psa_pake_input(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * // send shareV + * psa_pake_output(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * // send confirmV + * psa_pake_output(operation, #PSA_PAKE_STEP_CONFIRM, ...); + * // receive confirmP + * psa_pake_input(operation, #PSA_PAKE_STEP_CONFIRM, ...); + * // get K_shared + * psa_pake_get_shared_key(operation, ...); + * \endcode + * + * The shared secret that is produced by SPAKE2+ is pseudorandom. Although + * it can be used directly as an encryption key, it is recommended to use + * the shared secret as an input to a key derivation operation to produce + * additional cryptographic keys. + */ +#define PSA_ALG_IS_SPAKE2P_HMAC_BASE ((psa_algorithm_t) 0x0a000400) +#define PSA_ALG_SPAKE2P_HMAC(hash_alg) (PSA_ALG_IS_SPAKE2P_HMAC_BASE | ((hash_alg) & PSA_ALG_HASH_MASK)) +#define PSA_ALG_IS_SPAKE2P_CMAC_BASE ((psa_algorithm_t) 0x0a000500) +#define PSA_ALG_SPAKE2P_CMAC(hash_alg) (PSA_ALG_IS_SPAKE2P_CMAC_BASE | ((hash_alg) & PSA_ALG_HASH_MASK)) +#define PSA_ALG_SPAKE2P_MATTER ((psa_algorithm_t) 0x0A000609) +#define PSA_ALG_IS_SPAKE2P(alg) (((alg) & ~0x000003ff) == PSA_ALG_IS_SPAKE2P_HMAC_BASE) +#define PSA_ALG_IS_SPAKE2P_HMAC(alg) (((alg) & ~PSA_ALG_HASH_MASK) == PSA_ALG_IS_SPAKE2P_HMAC_BASE) +#define PSA_ALG_IS_SPAKE2P_CMAC(alg) (((alg) & ~PSA_ALG_HASH_MASK) == PSA_ALG_IS_SPAKE2P_CMAC_BASE) + + /** The Secure Remote Passwort key exchange (SRP) algorithm. + * + * This is SRP-6 as defined by RFC 2945 and RFC 5054, instantiated with the + * following parameters: + * + * - The group is defined over a finite field using a secure prime. + * - A cryptographic hash function. + * + * To select these parameters and set up the cipher suite, call these functions: + * + * \code + * psa_pake_cipher_suite_t cipher_suite = PSA_PAKE_CIPHER_SUITE_INIT; + * psa_pake_cs_set_algorithm(cipher_suite, PSA_ALG_SRP_6(hash)); + * psa_pake_cs_set_primitive(&cipher_suite, + * PSA_PAKE_PRIMITIVE(type, family, bits)); + * \endcode + * + * After initializing a SRP operation, call: + * + * \code + * psa_pake_setup(operation, password, cipher_suite); + * psa_pake_set_role(operation, ...); + * psa_pake_set_user(operation, ...); + * \endcode + * + * The password provided to the client side must be of type + * #PSA_KEY_TYPE_SRP_KEY_PAIR. + * The password provided to the server side must be of type + * #PSA_KEY_TYPE_SRP_PUBLIC_KEY. + * + * The role set by \c psa_pake_set_role() must be either + * \c PSA_PAKE_ROLE_CLIENT or \c PSA_PAKE_ROLE_SERVER. + * + * For the SRP client key exchange call the following functions in any order: + * \code + * // get salt + * psa_pake_input(operation, #PSA_PAKE_STEP_SALT, ...); + * // get server key + * psa_pake_input(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * // write client key + * psa_pake_output(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * \endcode + * + * For the SRP server key exchange call the following functions in any order: + * \code + * // get salt + * psa_pake_input(operation, #PSA_PAKE_STEP_SALT, ...); + * // get client key + * psa_pake_input(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * // write server key + * psa_pake_output(operation, #PSA_PAKE_STEP_KEY_SHARE, ...); + * \endcode + * + * For the client proof phase call the following functions in this order: + * \code + * // send M1 + * psa_pake_input(operation, #PSA_PAKE_STEP_CONFIRM, ...); + * // receive M2 + * psa_pake_output(operation, #PSA_PAKE_STEP_CONFIRM, ...); + * // Get secret + * psa_pake_get_shared_key() + * \endcode + * + * For the server proof phase call the following functions in this order: + * \code + * // receive M1 + * psa_pake_output(operation, #PSA_PAKE_STEP_CONFIRM, ...); + * // send M2 + * psa_pake_input(operation, #PSA_PAKE_STEP_CONFIRM, ...); + * // Get secret + * psa_pake_get_shared_key() + * \endcode + * + * The shared secret that is produced by SRP is pseudorandom. Although + * it can be used directly as an encryption key, it is recommended to use + * the shared secret as an input to a key derivation operation to produce + * additional cryptographic keys. + */ +#define PSA_ALG_SRP_6_BASE ((psa_algorithm_t) 0x0a000300) +#define PSA_ALG_SRP_6(hash_alg) (PSA_ALG_SRP_6_BASE | ((hash_alg) & PSA_ALG_HASH_MASK)) +#define PSA_ALG_IS_SRP_6(alg) (((alg) & ~PSA_ALG_HASH_MASK) == PSA_ALG_SRP_6_BASE) + +/** @} */ + +/** \defgroup pake Password-authenticated key exchange (PAKE) + * + * This is a proposed PAKE interface for the PSA Crypto API. It is not part of + * the official PSA Crypto API yet. + * + * \note The content of this section is not part of the stable API and ABI + * of Mbed TLS and may change arbitrarily from version to version. + * Same holds for the corresponding macros #PSA_ALG_CATEGORY_PAKE and + * #PSA_ALG_JPAKE. + * @{ + */ + +/** A value to indicate no role in a PAKE algorithm. + * This value can be used in a call to psa_pake_set_role() for symmetric PAKE + * algorithms which do not assign roles. + */ +#define PSA_PAKE_ROLE_NONE ((psa_pake_role_t) 0x00) + +/** The first peer in a balanced PAKE. + * + * Although balanced PAKE algorithms are symmetric, some of them need an + * ordering of peers for the transcript calculations. If the algorithm does not + * need this, both #PSA_PAKE_ROLE_FIRST and #PSA_PAKE_ROLE_SECOND are + * accepted. + */ +#define PSA_PAKE_ROLE_FIRST ((psa_pake_role_t) 0x01) + +/** The second peer in a balanced PAKE. + * + * Although balanced PAKE algorithms are symmetric, some of them need an + * ordering of peers for the transcript calculations. If the algorithm does not + * need this, either #PSA_PAKE_ROLE_FIRST or #PSA_PAKE_ROLE_SECOND are + * accepted. + */ +#define PSA_PAKE_ROLE_SECOND ((psa_pake_role_t) 0x02) + +/** The client in an augmented PAKE. + * + * Augmented PAKE algorithms need to differentiate between client and server. + */ +#define PSA_PAKE_ROLE_CLIENT ((psa_pake_role_t) 0x11) + +/** The server in an augmented PAKE. + * + * Augmented PAKE algorithms need to differentiate between client and server. + */ +#define PSA_PAKE_ROLE_SERVER ((psa_pake_role_t) 0x12) + +/** The PAKE primitive type indicating the use of elliptic curves. + * + * The values of the \c family and \c bits fields of the cipher suite identify a + * specific elliptic curve, using the same mapping that is used for ECC + * (::psa_ecc_family_t) keys. + * + * (Here \c family means the value returned by PSA_PAKE_PRIMITIVE_GET_FAMILY() and + * \c bits means the value returned by PSA_PAKE_PRIMITIVE_GET_BITS().) + * + * Input and output during the operation can involve group elements and scalar + * values: + * -# The format for group elements is the same as for public keys on the + * specific curve would be. For more information, consult the documentation of + * psa_export_public_key(). + * -# The format for scalars is the same as for private keys on the specific + * curve would be. For more information, consult the documentation of + * psa_export_key(). + */ +#define PSA_PAKE_PRIMITIVE_TYPE_ECC ((psa_pake_primitive_type_t) 0x01) + +/** The PAKE primitive type indicating the use of Diffie-Hellman groups. + * + * The values of the \c family and \c bits fields of the cipher suite identify + * a specific Diffie-Hellman group, using the same mapping that is used for + * Diffie-Hellman (::psa_dh_family_t) keys. + * + * (Here \c family means the value returned by PSA_PAKE_PRIMITIVE_GET_FAMILY() and + * \c bits means the value returned by PSA_PAKE_PRIMITIVE_GET_BITS().) + * + * Input and output during the operation can involve group elements and scalar + * values: + * -# The format for group elements is the same as for public keys on the + * specific group would be. For more information, consult the documentation of + * psa_export_public_key(). + * -# The format for scalars is the same as for private keys on the specific + * group would be. For more information, consult the documentation of + * psa_export_key(). + */ +#define PSA_PAKE_PRIMITIVE_TYPE_DH ((psa_pake_primitive_type_t) 0x02) + +/** Construct a PAKE primitive from type, family and bit-size. + * + * \param pake_type The type of the primitive + * (value of type ::psa_pake_primitive_type_t). + * \param pake_family The family of the primitive + * (the type and interpretation of this parameter depends + * on \p pake_type, for more information consult the + * documentation of individual ::psa_pake_primitive_type_t + * constants). + * \param pake_bits The bit-size of the primitive + * (Value of type \c size_t. The interpretation + * of this parameter depends on \p pake_family, for more + * information consult the documentation of individual + * ::psa_pake_primitive_type_t constants). + * + * \return The constructed primitive value of type ::psa_pake_primitive_t. + * Return 0 if the requested primitive can't be encoded as + * ::psa_pake_primitive_t. + */ +#define PSA_PAKE_PRIMITIVE(pake_type, pake_family, pake_bits) \ + (((pake_bits & 0xFFFF) != pake_bits) ? 0 : \ + ((psa_pake_primitive_t) (((pake_type) << 24 | \ + (pake_family) << 16) | (pake_bits)))) + +#define PSA_PAKE_PRIMITIVE_GET_BITS(pake_primitive) \ + ((size_t)(pake_primitive & 0xFFFF)) + +#define PSA_PAKE_PRIMITIVE_GET_FAMILY(pake_primitive) \ + ((psa_pake_family_t)((pake_primitive >> 16) & 0xFF)) + +#define PSA_PAKE_PRIMITIVE_GET_TYPE(pake_primitive) \ + ((psa_pake_primitive_type_t)((pake_primitive >> 24) & 0xFF)) + +/** A key confirmation value that indicates a confirmed key in a PAKE cipher + * suite. + * + * This key confirmation value will result in the PAKE algorithm exchanging + * data to verify that the shared key is identical for both parties. This is + * the default key confirmation value in an initialized PAKE cipher suite + * object. + * Some algorithms do not include confirmation of the shared key. + */ +#define PSA_PAKE_CONFIRMED_KEY 0 + +/** A key confirmation value that indicates an unconfirmed key in a PAKE cipher + * suite. + * + * This key confirmation value will result in the PAKE algorithm terminating + * prior to confirming that the resulting shared key is identical for both + * parties. + * Some algorithms do not support returning an unconfirmed shared key. + */ +#define PSA_PAKE_UNCONFIRMED_KEY 1 + + /** The key share being sent to or received from the peer. + * + * The format for both input and output at this step is the same as for public + * keys on the group determined by the primitive (::psa_pake_primitive_t) would + * be. + * + * For more information on the format, consult the documentation of + * psa_export_public_key(). + * + * For information regarding how the group is determined, consult the + * documentation #PSA_PAKE_PRIMITIVE. + */ +#define PSA_PAKE_STEP_KEY_SHARE ((psa_pake_step_t) 0x01) + +/** A Schnorr NIZKP public key. + * + * This is the ephemeral public key in the Schnorr Non-Interactive + * Zero-Knowledge Proof (the value denoted by the letter 'V' in RFC 8235). + * + * The format for both input and output at this step is the same as for public + * keys on the group determined by the primitive (::psa_pake_primitive_t) would + * be. + * + * For more information on the format, consult the documentation of + * psa_export_public_key(). + * + * For information regarding how the group is determined, consult the + * documentation #PSA_PAKE_PRIMITIVE. + */ +#define PSA_PAKE_STEP_ZK_PUBLIC ((psa_pake_step_t) 0x02) + +/** A Schnorr NIZKP proof. + * + * This is the proof in the Schnorr Non-Interactive Zero-Knowledge Proof (the + * value denoted by the letter 'r' in RFC 8235). + * + * Both for input and output, the value at this step is an integer less than + * the order of the group selected in the cipher suite. The format depends on + * the group as well: + * + * - For Montgomery curves, the encoding is little endian. + * - For everything else the encoding is big endian (see Section 2.3.8 of + * _SEC 1: Elliptic Curve Cryptography_ at https://www.secg.org/sec1-v2.pdf). + * + * In both cases leading zeroes are allowed as long as the length in bytes does + * not exceed the byte length of the group order. + * + * For information regarding how the group is determined, consult the + * documentation #PSA_PAKE_PRIMITIVE. + */ +#define PSA_PAKE_STEP_ZK_PROOF ((psa_pake_step_t) 0x03) + +/** The key confirmation value. + * + * This value is used during the key confirmation phase of a PAKE protocol. + * The format of the value depends on the algorithm and cipher suite: + * + * For SPAKE2+ algorithms, the format for both input and output at this step is + * the same as the output of the MAC algorithm specified in the cipher suite. + * + * For PSA_ALG_SRP_6, the format for both input and output at this step is + * the same as the output of the Hash algorithm specified. + */ +#define PSA_PAKE_STEP_CONFIRM ((psa_pake_step_t)0x04) + +/** The salt. + * + * The format for both input and output at this step is plain binary data. + */ +#define PSA_PAKE_STEP_SALT ((psa_pake_step_t)0x05) + +/** Retrieve the PAKE algorithm from a PAKE cipher suite. + * + * \param[in] cipher_suite The cipher suite structure to query. + * + * \return The PAKE algorithm stored in the cipher suite structure. + */ +static psa_algorithm_t psa_pake_cs_get_algorithm( + const psa_pake_cipher_suite_t *cipher_suite); + +/** Declare the PAKE algorithm for the cipher suite. + * + * This function overwrites any PAKE algorithm + * previously set in \p cipher_suite. + * + * \param[out] cipher_suite The cipher suite structure to write to. + * \param algorithm The PAKE algorithm to write. + * (`PSA_ALG_XXX` values of type ::psa_algorithm_t + * such that #PSA_ALG_IS_PAKE(\c alg) is true.) + * If this is 0, the PAKE algorithm in + * \p cipher_suite becomes unspecified. + */ +static void psa_pake_cs_set_algorithm(psa_pake_cipher_suite_t *cipher_suite, + psa_algorithm_t algorithm); + +/** Retrieve the primitive from a PAKE cipher suite. + * + * \param[in] cipher_suite The cipher suite structure to query. + * + * \return The primitive stored in the cipher suite structure. + */ +static psa_pake_primitive_t psa_pake_cs_get_primitive( + const psa_pake_cipher_suite_t *cipher_suite); + +/** Declare the primitive for a PAKE cipher suite. + * + * This function overwrites any primitive previously set in \p cipher_suite. + * + * \param[out] cipher_suite The cipher suite structure to write to. + * \param primitive The primitive to write. If this is 0, the + * primitive type in \p cipher_suite becomes + * unspecified. + */ +static void psa_pake_cs_set_primitive(psa_pake_cipher_suite_t *cipher_suite, + psa_pake_primitive_t primitive); + +/** The type of the state data structure for PAKE operations. + * + * Before calling any function on a PAKE operation object, the application + * must initialize it by any of the following means: + * - Set the structure to all-bits-zero, for example: + * \code + * psa_pake_operation_t operation; + * memset(&operation, 0, sizeof(operation)); + * \endcode + * - Initialize the structure to logical zero values, for example: + * \code + * psa_pake_operation_t operation = {0}; + * \endcode + * - Initialize the structure to the initializer #PSA_PAKE_OPERATION_INIT, + * for example: + * \code + * psa_pake_operation_t operation = PSA_PAKE_OPERATION_INIT; + * \endcode + * - Assign the result of the function psa_pake_operation_init() + * to the structure, for example: + * \code + * psa_pake_operation_t operation; + * operation = psa_pake_operation_init(); + * \endcode + * + * This is an implementation-defined \c struct. Applications should not + * make any assumptions about the content of this structure. + * Implementation details can change in future versions without notice. */ +typedef struct psa_pake_operation_s psa_pake_operation_t; + +/** Return an initial value for a PAKE operation object. + */ +static psa_pake_operation_t psa_pake_operation_init(void); + +/** Set the session information for a password-authenticated key exchange. + * + * The sequence of operations to set up a password-authenticated key exchange + * is as follows: + * -# Allocate an operation object which will be passed to all the functions + * listed here. + * -# Initialize the operation object with one of the methods described in the + * documentation for #psa_pake_operation_t, e.g. + * #PSA_PAKE_OPERATION_INIT. + * -# Call psa_pake_setup() to specify the password key and the cipher suite. + * -# Call \c psa_pake_set_xxx() functions on the operation to complete the + * setup. The exact sequence of \c psa_pake_set_xxx() functions that needs + * to be called depends on the algorithm in use. + * + * Refer to the documentation of individual PAKE algorithm types (`PSA_ALG_XXX` + * values of type ::psa_algorithm_t such that #PSA_ALG_IS_PAKE(\c alg) is true) + * for more information. + * + * A typical sequence of calls to perform a password-authenticated key + * exchange: + * -# Call psa_pake_output(operation, #PSA_PAKE_STEP_KEY_SHARE, ...) to get the + * key share that needs to be sent to the peer. + * -# Call psa_pake_input(operation, #PSA_PAKE_STEP_KEY_SHARE, ...) to provide + * the key share that was received from the peer. + * -# Depending on the algorithm additional calls to psa_pake_output() and + * psa_pake_input() might be necessary. + * -# Call psa_pake_get_shared_key() for accessing the shared secret. + * + * Refer to the documentation of individual PAKE algorithm types (`PSA_ALG_XXX` + * values of type ::psa_algorithm_t such that #PSA_ALG_IS_PAKE(\c alg) is true) + * for more information. + * + * If an error occurs at any step after a call to psa_pake_setup(), + * the operation will need to be reset by a call to psa_pake_abort(). The + * application may call psa_pake_abort() at any time after the operation + * has been initialized. + * + * After a successful call to psa_pake_setup(), the application must + * eventually terminate the operation. The following events terminate an + * operation: + * - A call to psa_pake_abort(). + * - A successful call to psa_pake_get_shared_key(). + * + * \param[in,out] operation The operation object to set up. It must have + * been initialized but not set up yet. + * \param[in] password_key Identifier of the key holding the password or + * a value derived from the password. It must + * remain valid until the operation terminates. + * The valid key types depend on the PAKE algorithm, + * and participant role. + * \param[in] cipher_suite The cipher suite to use. (A cipher suite fully + * characterizes a PAKE algorithm and determines + * the algorithm as well.) + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INVALID_HANDLE + * \p password_key is not a valid key identifier. + * \retval #PSA_ERROR_NOT_PERMITTED + * The key does not have the #PSA_KEY_USAGE_DERIVE flag, or it does not + * permit the \p operation's algorithm. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The algorithm in \p cipher_suite is not a PAKE algorithm or encodes + * an invalid hash algorithm, or the PAKE primitive in \p cipher_suite + * is not compatible with the PAKE algorithm, or the key confirmation + * value in \p cipher_suite is not compatible with the PAKE algorithm + * and primitive, or the \p password_key is not compatible with + * \p cipher_suite. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The algorithm in \p cipher_suite is not a supported PAKE algorithm, + * or the PAKE primitive in \p cipher_suite is not supported or not + * compatible with the PAKE algorithm, or the key confirmation value + * in \p cipher_suite is not supported or not compatible with the PAKE + * algorithm and primitive, or the key type or key size of + * \p password_key is not supported with \p cipher_suite. + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid, or + * the library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_pake_setup(psa_pake_operation_t *operation, + mbedtls_svc_key_id_t password_key, + const psa_pake_cipher_suite_t *cipher_suite); + +/** Set the application role for a password-authenticated key exchange. +* +* Not all PAKE algorithms need to differentiate the communicating entities. +* It is optional to call this function for PAKEs that don't require a role +* to be specified. For such PAKEs the application role parameter is ignored, +* or #PSA_PAKE_ROLE_NONE can be passed as \c role. +* +* Refer to the documentation of individual PAKE algorithm types (`PSA_ALG_XXX` +* values of type ::psa_algorithm_t such that #PSA_ALG_IS_PAKE(\c alg) is true) +* for more information. +* +* \param[in,out] operation The operation object to specify the +* application's role for. It must have been set up +* by psa_pake_setup() and not yet in use (neither +* psa_pake_output() nor psa_pake_input() has been +* called yet). It must be an operation for which +* the application's role hasn't been specified +* (psa_pake_set_role() hasn't been called yet). +* \param role A value of type ::psa_pake_role_t indicating the +* application's role in the PAKE algorithm +* that is being set up. For more information see +* the documentation of \c PSA_PAKE_ROLE_XXX +* constants. +* +* \retval #PSA_SUCCESS +* Success. +* \retval #PSA_ERROR_INVALID_ARGUMENT +* The \p role is not a valid PAKE role in the \p operation’s algorithm. +* \retval #PSA_ERROR_NOT_SUPPORTED +* The \p role for this algorithm is not supported or is not valid. +* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription +* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription +* \retval #PSA_ERROR_BAD_STATE +* The operation state is not valid, or +* the library has not been previously initialized by psa_crypto_init(). +* It is implementation-dependent whether a failure to initialize +* results in this error code. +*/ +psa_status_t psa_pake_set_role(psa_pake_operation_t *operation, + psa_pake_role_t role); + +/** Set the user ID for a password-authenticated key exchange. + * + * Call this function to set the user ID. For PAKE algorithms that associate a + * user identifier with each side of the session you need to call + * psa_pake_set_peer() as well. For PAKE algorithms that associate a single + * user identifier with the session, call psa_pake_set_user() only. + * + * Refer to the documentation of individual PAKE algorithm types (`PSA_ALG_XXX` + * values of type ::psa_algorithm_t such that #PSA_ALG_IS_PAKE(\c alg) is true) + * for more information. + * + * \param[in,out] operation The operation object to set the user ID for. It + * must have been set up by psa_pake_setup() and + * not yet in use (neither psa_pake_output() nor + * psa_pake_input() has been called yet). It must + * be on operation for which the user ID hasn't + * been set (psa_pake_set_user() hasn't been + * called yet). + * \param[in] user_id The user ID to authenticate with. + * \param user_id_len Size of the \p user_id buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p user_id is not valid for the \p operation's algorithm and cipher + * suite. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The value of \p user_id is not supported by the implementation. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid, or + * the library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_pake_set_user(psa_pake_operation_t *operation, + const uint8_t *user_id, + size_t user_id_len); + +/** Set the peer ID for a password-authenticated key exchange. + * + * Call this function in addition to psa_pake_set_user() for PAKE algorithms + * that associate a user identifier with each side of the session. For PAKE + * algorithms that associate a single user identifier with the session, call + * psa_pake_set_user() only. + * + * Refer to the documentation of individual PAKE algorithm types (`PSA_ALG_XXX` + * values of type ::psa_algorithm_t such that #PSA_ALG_IS_PAKE(\c alg) is true) + * for more information. + * + * \param[in,out] operation The operation object to set the peer ID for. It + * must have been set up by psa_pake_setup() and + * not yet in use (neither psa_pake_output() nor + * psa_pake_input() has been called yet). It must + * be on operation for which the peer ID hasn't + * been set (psa_pake_set_peer() hasn't been + * called yet). + * \param[in] peer_id The peer's ID to authenticate. + * \param peer_id_len Size of the \p peer_id buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p peer_id is not valid for the \p operation's algorithm and cipher + * suite. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The algorithm doesn't associate a second identity with the session. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * Calling psa_pake_set_peer() is invalid with the \p operation's + * algorithm, the operation state is not valid, or the library has not + * been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_pake_set_peer(psa_pake_operation_t *operation, + const uint8_t *peer_id, + size_t peer_id_len); + +/** Set the context data for a password-authenticated key exchange. + * + * Call this function for PAKE algorithms that accept additional context data + * as part of the protocol setup. + * + * Refer to the documentation of individual PAKE algorithm types (`PSA_ALG_XXX` + * values of type ::psa_algorithm_t such that #PSA_ALG_IS_PAKE(\c alg) is true) + * for more information. + * + * \param[in,out] operation The operation object to set the context for. It + * must have been set up by psa_pake_setup() and + * not yet in use (neither psa_pake_output() nor + * psa_pake_input() has been called yet). It must + * be on operation for which the context hasn't + * been set (psa_pake_set_context() hasn't been + * called yet). + * \param[in] context The context. + * \param context_len Size of the \p context buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The \p context is not valid for the operation’s algorithm and cipher suite. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The \p context is not supported by the implementation. + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * Calling psa_pake_set_context() is invalid with the \p operation's + * algorithm, the operation state is not valid, or the library has not + * been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_pake_set_context(psa_pake_operation_t *operation, + const uint8_t *context, + size_t context_len); + +/** Get output for a step of a password-authenticated key exchange. + * + * Depending on the algorithm being executed, you might need to call this + * function several times or you might not need to call this at all. + * + * The exact sequence of calls to perform a password-authenticated key + * exchange depends on the algorithm in use. Refer to the documentation of + * individual PAKE algorithm types (`PSA_ALG_XXX` values of type + * ::psa_algorithm_t such that #PSA_ALG_IS_PAKE(\c alg) is true) for more + * information. + * + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling psa_pake_abort(). + * + * \param[in,out] operation Active PAKE operation. + * \param step The step of the algorithm for which the output + * is requested. + * \param[out] output Buffer where the output is to be written in the + * format appropriate for this \p step. Refer to + * the documentation of the individual + * \c PSA_PAKE_STEP_XXX constants for more + * information. + * \param output_size Size of the \p output buffer in bytes. This must + * be at least #PSA_PAKE_OUTPUT_SIZE(\c alg, \c + * primitive, \p output_step) where \c alg and + * \p primitive are the PAKE algorithm and primitive + * in the operation's cipher suite, and \p step is + * the output step. + * + * \param[out] output_length On success, the number of bytes of the returned + * output. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p output buffer is too small. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p step is not compatible with the operation's algorithm. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p step is not supported with the operation's algorithm. + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be active, and fully set + * up, and this call must conform to the algorithm's requirements + * for ordering of input and output steps), or the library has not + * been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_pake_output(psa_pake_operation_t *operation, + psa_pake_step_t step, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** Provide input for a step of a password-authenticated key exchange. + * + * Depending on the algorithm being executed, you might need to call this + * function several times or you might not need to call this at all. + * + * The exact sequence of calls to perform a password-authenticated key + * exchange depends on the algorithm in use. Refer to the documentation of + * individual PAKE algorithm types (`PSA_ALG_XXX` values of type + * ::psa_algorithm_t such that #PSA_ALG_IS_PAKE(\c alg) is true) for more + * information. + * + * If this function returns an error status, the operation enters an error + * state and must be aborted by calling psa_pake_abort(). + * + * \param[in,out] operation Active PAKE operation. + * \param step The step for which the input is provided. + * \param[in] input Buffer containing the input in the format + * appropriate for this \p step. Refer to the + * documentation of the individual + * \c PSA_PAKE_STEP_XXX constants for more + * information. + * \param input_length Size of the \p input buffer in bytes. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INVALID_SIGNATURE + * The verification fails for a #PSA_PAKE_STEP_ZK_PROOF input step. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \p step is not compatible with the operation's algorithm, or + * \p input_length is not compatible with the \p operation’s algorithm, + * or the \p input is not valid for the \p operation's algorithm, + * cipher suite or \p step. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \p step is not supported with the operation's algorithm, or + * \p step p is not supported with the \p operation's algorithm, or the + * \p input is not supported for the \p operation's algorithm, cipher + * suite or \p step. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The operation state is not valid (it must be active, and fully set + * up, and this call must conform to the algorithm's requirements + * for ordering of input and output steps), or the library has not + * been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_pake_input(psa_pake_operation_t *operation, + psa_pake_step_t step, + const uint8_t *input, + size_t input_length); + +/** Get shared secret from a PAKE. + * + * This is the final call in a PAKE operation, which retrieves the shared + * secret as a key. It is recommended that this key is used as an input to a + * key derivation operation to produce additional cryptographic keys. For + * some PAKE algorithms, the shared secret is also suitable for use as a key + * in cryptographic operations such as encryption. Refer to the documentation + * of individual PAKE algorithm types (`PSA_ALG_XXX` values of type + * ::psa_algorithm_t such that #PSA_ALG_IS_PAKE(\c alg) is true) for more + * information. + * + * Depending on the key confirmation requested in the cipher suite, + * psa_pake_get_shared_key() must be called either before or after the + * key-confirmation output and input steps for the PAKE algorithm. The key + * confirmation affects the guarantees that can be made about the shared key: + * + * Unconfirmed key + * If the cipher suite used to set up the operation requested an unconfirmed + * key, the application must call psa_pake_get_shared_key() after the + * key-exchange output and input steps are completed. The PAKE algorithm + * provides a cryptographic guarantee that only a peer who used the same + * password, and identity inputs, is able to compute the same key. However, + * there is no guarantee that the peer is the participant it claims to be, + * and was able to compute the same key. + * Since the peer is not authenticated, no action should be taken that assumes + * that the peer is who it claims to be. For example, do not access restricted + * files on the peer’s behalf until an explicit authentication has succeeded. + * Note: + * Some PAKE algorithms do not enable the output of the shared secret until it + * has been confirmed. + * + * Confirmed key + * If the cipher suite used to set up the operation requested a confirmed key, + * the application must call psa_pake_get_shared_key() after the key-exchange + * and key-confirmation output and input steps are completed. + * Following key confirmation, the PAKE algorithm provides a cryptographic + * guarantee that the peer used the same password and identity inputs, and has + * computed the identical shared secret key. + * Since the peer is not authenticated, no action should be taken that assumes + * that the peer is who it claims to be. For example, do not access restricted + * files on the peer’s behalf until an explicit authentication has succeeded. + * Note: + * Some PAKE algorithms do not include any key-confirmation steps. + * + * The exact sequence of calls to perform a password-authenticated key + * exchange depends on the algorithm in use. + * + * When this function returns successfully, \p operation becomes inactive. + * If this function returns an error status, both \p operation + * and \c key_derivation operations enter an error state and must be aborted + * by calling psa_pake_abort(). + * + * \param[in,out] operation Active PAKE operation. + * \param[in] attributes The attributes for the new key. + * \param[out] key On success, an identifier for the newly created + * key. #PSA_KEY_ID_NULL on failure. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_NOT_PERMITTED + * The implementation does not permit creating a key with the + * specified attributes due to some implementation-specific policy. + * \retval #PSA_ERROR_ALREADY_EXISTS + * This is an attempt to create a persistent key, and there is + * already a persistent key with the given identifier. + * \retval #PSA_ERROR_INVALID_ARGUMENT + * The key type is not valid for output from this operation’s + * algorithm, or the key size is nonzero, or the key lifetime is + * invalid, the key identifier is not valid for the key lifetime, + * or the key usage flags include invalid values, or the key’s + * permitted-usage algorithm is invalid, or the key attributes, + * as a whole, are invalid. + * \retval #PSA_ERROR_NOT_SUPPORTED + * The key attributes, as a whole, are not supported for creation + * from a PAKE secret, either by the implementation in general or + * in the specified storage location. + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription + * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription + * \retval #PSA_ERROR_DATA_INVALID \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The PAKE operation state is not valid (it must be ready to return + * the shared secret), or the library has not been previously + * initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_pake_get_shared_key(psa_pake_operation_t *operation, + const psa_key_attributes_t *attributes, + mbedtls_svc_key_id_t *key); + +/** Abort a PAKE operation. + * + * Aborting an operation frees all associated resources except for the \c + * operation structure itself. Once aborted, the operation object can be reused + * for another operation by calling psa_pake_setup() again. + * + * This function may be called at any time after the operation + * object has been initialized as described in #psa_pake_operation_t. + * + * In particular, calling psa_pake_abort() after the operation has been + * terminated by a call to psa_pake_abort() or psa_pake_get_shared_key() + * is safe and has no effect. + * + * \param[in,out] operation The operation to abort. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription + * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t psa_pake_abort(psa_pake_operation_t *operation); + +/**@}*/ + +/** A sufficient output buffer size for psa_pake_output(). + * + * If the size of the output buffer is at least this large, it is guaranteed + * that psa_pake_output() will not fail due to an insufficient output buffer + * size. The actual size of the output might be smaller in any given call. + * + * See also #PSA_PAKE_OUTPUT_MAX_SIZE + * + * \param alg A PAKE algorithm (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_PAKE(\p alg) is true). + * \param primitive A primitive of type ::psa_pake_primitive_t that is + * compatible with algorithm \p alg. + * \param output_step A value of type ::psa_pake_step_t that is valid for the + * algorithm \p alg. + * \return A sufficient output buffer size for the specified + * PAKE algorithm, primitive, and output step. If the + * PAKE algorithm, primitive, or output step is not + * recognized, or the parameters are incompatible, + * return 0. + */ +#define PSA_PAKE_OUTPUT_SIZE(alg, primitive, output_step) \ + (output_step == PSA_PAKE_STEP_KEY_SHARE ? \ + PSA_PAKE_PRIMITIVE_GET_TYPE(primitive) == PSA_PAKE_PRIMITIVE_TYPE_DH ? \ + PSA_BITS_TO_BYTES(PSA_PAKE_PRIMITIVE_GET_BITS(primitive)) : \ + PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_PAKE_PRIMITIVE_GET_BITS(primitive)) : \ + output_step == PSA_PAKE_STEP_ZK_PUBLIC ? \ + PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_PAKE_PRIMITIVE_GET_BITS(primitive)) : \ + output_step == PSA_PAKE_STEP_ZK_PROOF ? \ + PSA_BITS_TO_BYTES(PSA_PAKE_PRIMITIVE_GET_BITS(primitive)) : \ + output_step == PSA_PAKE_STEP_CONFIRM ? \ + PSA_ALG_IS_SPAKE2P_CMAC(alg) ? \ + PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128, PSA_ALG_CMAC) : \ + PSA_HASH_LENGTH(alg) : \ + 0u) + +/** A sufficient input buffer size for psa_pake_input(). + * + * The value returned by this macro is guaranteed to be large enough for any + * valid input to psa_pake_input() in an operation with the specified + * parameters. + * + * See also #PSA_PAKE_INPUT_MAX_SIZE + * + * \param alg A PAKE algorithm (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_PAKE(\p alg) is true). + * \param primitive A primitive of type ::psa_pake_primitive_t that is + * compatible with algorithm \p alg. + * \param input_step A value of type ::psa_pake_step_t that is valid for the + * algorithm \p alg. + * \return A sufficient input buffer size for the specified + * input, cipher suite and algorithm. If the cipher suite, + * the input type or PAKE algorithm is not recognized, or + * the parameters are incompatible, return 0. + */ +#define PSA_PAKE_INPUT_SIZE(alg, primitive, input_step) \ + (input_step == PSA_PAKE_STEP_KEY_SHARE ? \ + PSA_PAKE_PRIMITIVE_GET_TYPE(primitive) == PSA_PAKE_PRIMITIVE_TYPE_DH ? \ + PSA_BITS_TO_BYTES(PSA_PAKE_PRIMITIVE_GET_BITS(primitive)) : \ + PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_PAKE_PRIMITIVE_GET_BITS(primitive)) : \ + input_step == PSA_PAKE_STEP_ZK_PUBLIC ? \ + PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_PAKE_PRIMITIVE_GET_BITS(primitive)) : \ + input_step == PSA_PAKE_STEP_ZK_PROOF ? \ + PSA_BITS_TO_BYTES(PSA_PAKE_PRIMITIVE_GET_BITS(primitive)) : \ + input_step == PSA_PAKE_STEP_CONFIRM ? \ + PSA_ALG_IS_SPAKE2P_CMAC(alg) ? \ + PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128, PSA_ALG_CMAC) : \ + PSA_HASH_LENGTH(alg) : \ + input_step == PSA_PAKE_STEP_SALT ? \ + 64u : \ + 0u) + +/** Output buffer size for psa_pake_output() for any of the supported PAKE + * algorithm and primitive suites and output step. + * + * This macro must expand to a compile-time constant integer. + * + * The value of this macro must be at least as large as the largest value + * returned by PSA_PAKE_OUTPUT_SIZE() + * + * See also #PSA_PAKE_OUTPUT_SIZE(\p alg, \p primitive, \p output_step). + */ +#ifdef PSA_WANT_ALG_SRP_6 +#define PSA_PAKE_OUTPUT_MAX_SIZE PSA_BITS_TO_BYTES(PSA_VENDOR_FFDH_MAX_KEY_BITS) +#else +#define PSA_PAKE_OUTPUT_MAX_SIZE PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS) +#endif + +/** Input buffer size for psa_pake_input() for any of the supported PAKE + * algorithm and primitive suites and input step. + * + * This macro must expand to a compile-time constant integer. + * + * The value of this macro must be at least as large as the largest value + * returned by PSA_PAKE_INPUT_SIZE() + * + * See also #PSA_PAKE_INPUT_SIZE(\p alg, \p primitive, \p output_step). + */ +#ifdef PSA_WANT_ALG_SRP_6 +#define PSA_PAKE_INPUT_MAX_SIZE PSA_BITS_TO_BYTES(PSA_VENDOR_FFDH_MAX_KEY_BITS) +#else +#define PSA_PAKE_INPUT_MAX_SIZE PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS) +#endif + +static inline psa_algorithm_t psa_pake_cs_get_algorithm( + const psa_pake_cipher_suite_t *cipher_suite) +{ + return cipher_suite->algorithm; +} + +static inline void psa_pake_cs_set_algorithm( + psa_pake_cipher_suite_t *cipher_suite, + psa_algorithm_t algorithm) +{ + if (!PSA_ALG_IS_PAKE(algorithm)) { + cipher_suite->algorithm = 0; + } else { + cipher_suite->algorithm = algorithm; + } +} + +static inline psa_pake_primitive_t psa_pake_cs_get_primitive( + const psa_pake_cipher_suite_t *cipher_suite) +{ + return cipher_suite->primitive; +} + +static inline void psa_pake_cs_set_primitive( + psa_pake_cipher_suite_t *cipher_suite, + psa_pake_primitive_t primitive) +{ + cipher_suite->primitive = primitive; +} + +static inline uint32_t psa_pake_cs_get_key_confirmation( + const psa_pake_cipher_suite_t* cipher_suite) +{ + return cipher_suite->key_confirmation; +} + +static inline void psa_pake_cs_set_key_confirmation( + psa_pake_cipher_suite_t* cipher_suite, + uint32_t key_confirmation) +{ + cipher_suite->key_confirmation = key_confirmation; +} + /**@}*/ #ifdef __cplusplus diff --git a/interface/include/psa/crypto_platform.h b/interface/include/psa/crypto_platform.h index e49438aa8..c46289887 100644 --- a/interface/include/psa/crypto_platform.h +++ b/interface/include/psa/crypto_platform.h @@ -32,4 +32,25 @@ * available for reference and future compatibility */ +#if defined(__NRF_TFM__) && defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER) +/* + * This header file is provided by TF-M and is only intended to be + * used by clients of PSA, not implementations of PSA. So secure + * partitions in the TF-M image (other than the crypto partition + * itself), and non-secure images. + * + * In NCS, the TF-M crypto partition should be using PSA header files + * from Oberon as it is Oberon that implements PSA. + * + * We want to detect that a source file is in the crypto partition, + * but has accidentally used this TF-M header instead of headers + * provided by Oberon. To do this we would ideally have a + * IS_IN_CRYPTO_PARTION define, but since there is no such define at + * time of writing we check MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER + * instead, which should only be defined by the PSA implementation, + * not by PSA clients. + */ +#error "The TF-M image included the TF-M PSA headers but should have included Oberon PSA headers" +#endif + #endif /* PSA_CRYPTO_PLATFORM_H */ diff --git a/interface/include/psa/crypto_sizes.h b/interface/include/psa/crypto_sizes.h index 8906ebf5e..94da58339 100644 --- a/interface/include/psa/crypto_sizes.h +++ b/interface/include/psa/crypto_sizes.h @@ -869,6 +869,34 @@ #define PSA_KEY_EXPORT_FFDH_PUBLIC_KEY_MAX_SIZE(key_bits) \ (PSA_BITS_TO_BYTES(key_bits)) +/* Maximum size of the export encoding of an SPAKE2+ public key. + * + * An SPAKE2+ public key is represented by the secret values w0 and L. + */ +#define PSA_KEY_EXPORT_SPAKE2P_PUBLIC_KEY_MAX_SIZE(key_bits) \ + (3u * PSA_BITS_TO_BYTES(key_bits) + 1u) + +/* Maximum size of the export encoding of an SPAKE2+ key pair. + * + * An SPAKE2+ key pair is represented by the secret values w0 and w1. + */ +#define PSA_KEY_EXPORT_SPAKE2P_KEY_PAIR_MAX_SIZE(key_bits) \ + (2u * PSA_BITS_TO_BYTES(key_bits)) + +/* Maximum size of the export encoding of an SRP public key. + * + * An SRP public key is represented by the password verifier. + */ +#define PSA_KEY_EXPORT_SRP_PUBLIC_KEY_MAX_SIZE(key_bits) \ + (PSA_BITS_TO_BYTES(key_bits)) + +/* Maximum size of the export encoding of an SRP key pair. + * + * An SRP key pair is represented by the password hash. + */ +#define PSA_KEY_EXPORT_SRP_KEY_PAIR_MAX_SIZE(key_bits) \ + (PSA_HASH_MAX_SIZE) + /** Sufficient output buffer size for psa_export_key() or * psa_export_public_key(). * @@ -915,6 +943,10 @@ (key_type) == PSA_KEY_TYPE_RSA_PUBLIC_KEY ? PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(key_bits) : \ (key_type) == PSA_KEY_TYPE_DSA_KEY_PAIR ? PSA_KEY_EXPORT_DSA_KEY_PAIR_MAX_SIZE(key_bits) : \ (key_type) == PSA_KEY_TYPE_DSA_PUBLIC_KEY ? PSA_KEY_EXPORT_DSA_PUBLIC_KEY_MAX_SIZE(key_bits) : \ + PSA_KEY_TYPE_IS_SPAKE2P_KEY_PAIR(key_type) ? 2u * PSA_BITS_TO_BYTES(key_bits) : \ + PSA_KEY_TYPE_IS_SPAKE2P_PUBLIC_KEY(key_type) ? 3u * PSA_BITS_TO_BYTES(key_bits) + 1u : \ + PSA_KEY_TYPE_IS_SRP_KEY_PAIR(key_type) ? PSA_HASH_MAX_SIZE : \ + PSA_KEY_TYPE_IS_SRP_PUBLIC_KEY(key_type) ? PSA_BITS_TO_BYTES(key_bits) : \ PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type) ? PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(key_bits) : \ PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type) ? PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) : \ 0u) @@ -968,6 +1000,8 @@ (PSA_KEY_TYPE_IS_RSA(key_type) ? PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(key_bits) : \ PSA_KEY_TYPE_IS_ECC(key_type) ? PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) : \ PSA_KEY_TYPE_IS_DH(key_type) ? PSA_BITS_TO_BYTES(key_bits) : \ + PSA_KEY_TYPE_IS_SPAKE2P(key_type) ? 3u * PSA_BITS_TO_BYTES(key_bits) + 1u : \ + PSA_KEY_TYPE_IS_SRP(key_type) ? PSA_BITS_TO_BYTES(key_bits) : \ 0u) /** Sufficient buffer size for exporting any asymmetric key pair. @@ -1001,6 +1035,20 @@ #define PSA_EXPORT_KEY_PAIR_MAX_SIZE \ PSA_KEY_EXPORT_FFDH_KEY_PAIR_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS) #endif +#if defined(PSA_WANT_KEY_TYPE_SPAKE2P_KEY_PAIR_BASIC) && \ + (PSA_KEY_EXPORT_SPAKE2P_KEY_PAIR_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS) > \ + PSA_EXPORT_KEY_PAIR_MAX_SIZE) +#undef PSA_EXPORT_KEY_PAIR_MAX_SIZE +#define PSA_EXPORT_KEY_PAIR_MAX_SIZE \ + PSA_KEY_EXPORT_SPAKE2P_KEY_PAIR_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS) +#endif +#if defined(PSA_WANT_KEY_TYPE_SRP_KEY_PAIR_BASIC) && \ + (PSA_KEY_EXPORT_SRP_KEY_PAIR_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS) > \ + PSA_EXPORT_KEY_PAIR_MAX_SIZE) +#undef PSA_EXPORT_KEY_PAIR_MAX_SIZE +#define PSA_EXPORT_KEY_PAIR_MAX_SIZE \ + PSA_KEY_EXPORT_SRP_KEY_PAIR_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS) +#endif /** Sufficient buffer size for exporting any asymmetric public key. * @@ -1034,6 +1082,20 @@ #define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE \ PSA_KEY_EXPORT_FFDH_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS) #endif +#if defined(PSA_WANT_KEY_TYPE_SPAKE2P_PUBLIC_KEY) && \ + (PSA_KEY_EXPORT_SPAKE2P_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS) > \ + PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) +#undef PSA_EXPORT_PUBLIC_KEY_MAX_SIZE +#define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE \ + PSA_KEY_EXPORT_SPAKE2P_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS) +#endif +#if defined(PSA_WANT_KEY_TYPE_SRP_PUBLIC_KEY) && \ + (PSA_KEY_EXPORT_SRP_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS) > \ + PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) +#undef PSA_EXPORT_PUBLIC_KEY_MAX_SIZE +#define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE \ + PSA_KEY_EXPORT_SRP_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS) +#endif /** Sufficient output buffer size for psa_raw_key_agreement(). * diff --git a/interface/include/psa/crypto_struct.h b/interface/include/psa/crypto_struct.h index 88b6b5367..1cbbe4081 100644 --- a/interface/include/psa/crypto_struct.h +++ b/interface/include/psa/crypto_struct.h @@ -236,6 +236,30 @@ static inline size_t psa_get_key_bits( return attributes->client.bits; } +struct psa_pake_cipher_suite_s { + psa_algorithm_t algorithm; + psa_pake_primitive_t primitive; + uint32_t key_confirmation; +}; + +#define PSA_PAKE_CIPHER_SUITE_INIT {PSA_ALG_NONE, 0, 0} +static inline struct psa_pake_cipher_suite_s psa_pake_cipher_suite_init(void) +{ + const struct psa_pake_cipher_suite_s v = PSA_PAKE_CIPHER_SUITE_INIT; + return v; +} + +struct psa_pake_operation_s { + uint32_t handle; +}; + +#define PSA_PAKE_OPERATION_INIT {0} +static inline struct psa_pake_operation_s psa_pake_operation_init(void) +{ + const struct psa_pake_operation_s v = PSA_PAKE_OPERATION_INIT; + return v; +} + #ifdef __cplusplus } #endif diff --git a/interface/include/psa/crypto_types.h b/interface/include/psa/crypto_types.h index c41053d15..01feaebf9 100644 --- a/interface/include/psa/crypto_types.h +++ b/interface/include/psa/crypto_types.h @@ -450,4 +450,51 @@ typedef uint16_t psa_key_derivation_step_t; /**@}*/ +/** The type of the data structure for PAKE cipher suites. + * + * This is an implementation-defined \c struct. Applications should not + * make any assumptions about the content of this structure. + * Implementation details can change in future versions without notice. + */ +typedef struct psa_pake_cipher_suite_s psa_pake_cipher_suite_t; + +/** Encoding of the type of the PAKE's primitive. +* +* Values defined by this standard will never be in the range 0x80-0xff. +* Vendors who define additional types must use an encoding in this range. +* +* For more information see the documentation of individual +* \c PSA_PAKE_PRIMITIVE_TYPE_XXX constants. +*/ +typedef uint8_t psa_pake_primitive_type_t; + +/** \brief Encoding of the family of the primitive associated with the PAKE. +* +* For more information see the documentation of individual +* \c PSA_PAKE_PRIMITIVE_TYPE_XXX constants. +*/ +typedef uint8_t psa_pake_family_t; + +/** \brief Encoding of the primitive associated with the PAKE. +* +* For more information see the documentation of the #PSA_PAKE_PRIMITIVE macro. +*/ +typedef uint32_t psa_pake_primitive_t; + +/** \brief Encoding of the application role of PAKE + * + * Encodes the application's role in the algorithm being executed. For more + * information see the documentation of individual \c PSA_PAKE_ROLE_XXX + * constants. + */ +typedef uint8_t psa_pake_role_t; + +/** Encoding of input and output indicators for PAKE. + * + * Some PAKE algorithms need to exchange more data than just a single key share. + * This type is for encoding additional input and output data for such + * algorithms. + */ +typedef uint8_t psa_pake_step_t; + #endif /* PSA_CRYPTO_TYPES_H */ diff --git a/interface/include/psa/crypto_values.h b/interface/include/psa/crypto_values.h index 8eba1d4d0..a2b21ae3f 100644 --- a/interface/include/psa/crypto_values.h +++ b/interface/include/psa/crypto_values.h @@ -724,6 +724,14 @@ */ #define PSA_DH_FAMILY_RFC7919 ((psa_dh_family_t) 0x03) +/** Diffie-Hellman groups defined in RFC 3526. + * + * This family includes groups with the following key sizes (in bits): + * 1536, 2048, 3072, 4096, 6144, 8192. A given implementation may support + * all of these sizes or only a subset. + */ +#define PSA_DH_FAMILY_RFC3526 ((psa_dh_family_t) 0x05) /*!!OM*/ + #define PSA_GET_KEY_TYPE_BLOCK_SIZE_EXPONENT(type) \ (((type) >> 8) & 7) /** The block size of a block cipher. @@ -2094,6 +2102,8 @@ #define PSA_ALG_IS_PBKDF2_HMAC(alg) \ (((alg) & ~PSA_ALG_HASH_MASK) == PSA_ALG_PBKDF2_HMAC_BASE) +#define PSA_ALG_SP800_108_COUNTER_CMAC ((psa_algorithm_t) 0x08000800) + /** The PBKDF2-AES-CMAC-PRF-128 password hashing / key stretching algorithm. * * PBKDF2 is defined by PKCS#5, republished as RFC 8018 (section 5.2). @@ -2105,6 +2115,35 @@ */ #define PSA_ALG_PBKDF2_AES_CMAC_PRF_128 ((psa_algorithm_t) 0x08800200) +#define PSA_ALG_SRP_PASSWORD_HASH_BASE ((psa_algorithm_t) 0x08800300) + /** The SRP password to password-hash KDF. + * It takes the password p, the salt s, and the user id u. + * It calculates the password hash h as + * h = H(salt || H(u || ":" || p)) + * where H is the given hash algorithm. + * + * This key derivation algorithm uses the following inputs, which must be + * provided in the following order: + * - #PSA_KEY_DERIVATION_INPUT_INFO is the user id. + * - #PSA_KEY_DERIVATION_INPUT_PASSWORD is the password. + * - #PSA_KEY_DERIVATION_INPUT_SALT is the salt. + * The output has to be read as a key of type PSA_KEY_TYPE_SRP_KEY_PAIR. + */ +#define PSA_ALG_SRP_PASSWORD_HASH(hash_alg) \ + (PSA_ALG_SRP_PASSWORD_HASH_BASE | ((hash_alg) & PSA_ALG_HASH_MASK)) + + /** Whether the specified algorithm is a key derivation algorithm constructed + * using #PSA_ALG_SRP_PASSWORD_HASH(\p hash_alg). + * + * \param alg An algorithm identifier (value of type #psa_algorithm_t). + * + * \return 1 if \p alg is a key derivation algorithm constructed using #PSA_ALG_SRP_PASSWORD_HASH(), + * 0 otherwise. This macro may return either 0 or 1 if \c alg is not a supported + * key derivation algorithm identifier. + */ +#define PSA_ALG_IS_SRP_PASSWORD_HASH(alg) \ + (((alg) & ~PSA_ALG_HASH_MASK) == PSA_ALG_SRP_PASSWORD_HASH_BASE) + #define PSA_ALG_KEY_DERIVATION_MASK ((psa_algorithm_t) 0xfe00ffff) #define PSA_ALG_KEY_AGREEMENT_MASK ((psa_algorithm_t) 0xffff0000) diff --git a/interface/include/tfm_crypto_defs.h b/interface/include/tfm_crypto_defs.h index d32073035..4b3cfca75 100644 --- a/interface/include/tfm_crypto_defs.h +++ b/interface/include/tfm_crypto_defs.h @@ -47,7 +47,6 @@ struct tfm_crypto_pack_iovec { uint32_t op_handle; /*!< Frontend context handle associated to a * multipart operation */ - size_t capacity; /*!< Key derivation capacity */ size_t ad_length; /*!< Additional Data length for multipart AEAD */ size_t plaintext_length; /*!< Plaintext length for multipart AEAD */ @@ -58,6 +57,11 @@ struct tfm_crypto_pack_iovec { * See tfm_crypto_func_sid for detail */ uint16_t step; /*!< Key derivation step */ + psa_pake_role_t role; /*!< PAKE role */ + union { + size_t capacity; /*!< Key derivation capacity */ + uint64_t value; /*!< Key derivation integer for update*/ + }; }; /** @@ -75,6 +79,7 @@ enum tfm_crypto_group_id { TFM_CRYPTO_GROUP_ID_ASYM_SIGN, TFM_CRYPTO_GROUP_ID_ASYM_ENCRYPT, TFM_CRYPTO_GROUP_ID_KEY_DERIVATION, + TFM_CRYPTO_GROUP_ID_PAKE, }; /* Set of X macros describing each of the available PSA Crypto APIs */ @@ -153,6 +158,7 @@ enum tfm_crypto_group_id { X(TFM_CRYPTO_KEY_DERIVATION_SET_CAPACITY) \ X(TFM_CRYPTO_KEY_DERIVATION_INPUT_BYTES) \ X(TFM_CRYPTO_KEY_DERIVATION_INPUT_KEY) \ + X(TFM_CRYPTO_KEY_DERIVATION_INPUT_INTEGER) \ X(TFM_CRYPTO_KEY_DERIVATION_KEY_AGREEMENT) \ X(TFM_CRYPTO_KEY_DERIVATION_OUTPUT_BYTES) \ X(TFM_CRYPTO_KEY_DERIVATION_OUTPUT_KEY) \ @@ -161,6 +167,17 @@ enum tfm_crypto_group_id { #define RANDOM_FUNCS \ X(TFM_CRYPTO_GENERATE_RANDOM) +#define PAKE_FUNCS \ + X(TFM_CRYPTO_PAKE_SETUP) \ + X(TFM_CRYPTO_PAKE_SET_ROLE) \ + X(TFM_CRYPTO_PAKE_SET_USER) \ + X(TFM_CRYPTO_PAKE_SET_PEER) \ + X(TFM_CRYPTO_PAKE_SET_CONTEXT) \ + X(TFM_CRYPTO_PAKE_OUTPUT) \ + X(TFM_CRYPTO_PAKE_INPUT) \ + X(TFM_CRYPTO_PAKE_GET_SHARED_KEY) \ + X(TFM_CRYPTO_PAKE_ABORT) + /** * \brief Define function IDs in each group. The function ID will be encoded into * tfm_crypto_func_sid below. Each group is defined as a dedicated enum @@ -193,6 +210,9 @@ enum tfm_crypto_key_derivation_func_id { enum tfm_crypto_random_func_id { RANDOM_FUNCS }; +enum tfm_crypto_pake_func_id { + PAKE_FUNCS +}; #undef X /** @@ -268,6 +288,11 @@ enum tfm_crypto_func_sid { (TFM_CRYPTO_GROUP_ID_RANDOM & 0xFF)), RANDOM_FUNCS +#undef X +#define X(func_id) func_id ## _SID = (uint16_t)((FUNC_ID(func_id)) | \ + (TFM_CRYPTO_GROUP_ID_PAKE & 0xFF)), + PAKE_FUNCS + }; #undef X diff --git a/interface/src/tfm_crypto_api.c b/interface/src/tfm_crypto_api.c index 8c857324b..4dc7ea81d 100644 --- a/interface/src/tfm_crypto_api.c +++ b/interface/src/tfm_crypto_api.c @@ -1656,3 +1656,194 @@ TFM_CRYPTO_API(psa_status_t, psa_key_derivation_output_key)( return API_DISPATCH(in_vec, out_vec); } + +TFM_CRYPTO_API(psa_status_t, psa_pake_setup) +(psa_pake_operation_t *operation, psa_key_id_t password_key, + const psa_pake_cipher_suite_t *cipher_suite) { + struct tfm_crypto_pack_iovec iov = {.function_id = TFM_CRYPTO_PAKE_SETUP_SID, + .op_handle = operation->handle, + .key_id = password_key}; + + psa_invec in_vec[] = { + {.base = &iov, .len = sizeof(struct tfm_crypto_pack_iovec)}, + {.base = cipher_suite, .len = sizeof(psa_pake_cipher_suite_t)}, + }; + + psa_outvec out_vec[] = { + {.base = &(operation->handle), .len = sizeof(uint32_t)}, + }; + + return API_DISPATCH(in_vec, out_vec); +} + +TFM_CRYPTO_API(psa_status_t, psa_pake_set_role) +(psa_pake_operation_t *operation, psa_pake_role_t role) { + struct tfm_crypto_pack_iovec iov = { + .function_id = TFM_CRYPTO_PAKE_SET_ROLE_SID, + .op_handle = operation->handle, + .role = role, + }; + + psa_invec in_vec[] = { + {.base = &iov, .len = sizeof(struct tfm_crypto_pack_iovec)}, + }; + + return API_DISPATCH_NO_OUTVEC(in_vec); +} + +TFM_CRYPTO_API(psa_status_t, psa_pake_set_user) +(psa_pake_operation_t *operation, const uint8_t *user_id, size_t user_id_len) { + struct tfm_crypto_pack_iovec iov = { + .function_id = TFM_CRYPTO_PAKE_SET_USER_SID, + .op_handle = operation->handle, + }; + + psa_invec in_vec[] = { + {.base = &iov, .len = sizeof(struct tfm_crypto_pack_iovec)}, + {.base = user_id, .len = user_id_len}, + }; + + return API_DISPATCH_NO_OUTVEC(in_vec); +} + +TFM_CRYPTO_API(psa_status_t, psa_pake_set_peer) +(psa_pake_operation_t *operation, const uint8_t *peer_id, size_t peer_id_len) { + struct tfm_crypto_pack_iovec iov = { + .function_id = TFM_CRYPTO_PAKE_SET_PEER_SID, + .op_handle = operation->handle, + }; + + psa_invec in_vec[] = { + {.base = &iov, .len = sizeof(struct tfm_crypto_pack_iovec)}, + {.base = peer_id, .len = peer_id_len}, + }; + + return API_DISPATCH_NO_OUTVEC(in_vec); +} + +TFM_CRYPTO_API(psa_status_t, psa_pake_set_context) +(psa_pake_operation_t *operation, const uint8_t *context, size_t context_len) { + struct tfm_crypto_pack_iovec iov = { + .function_id = TFM_CRYPTO_PAKE_SET_CONTEXT_SID, + .op_handle = operation->handle, + }; + + psa_invec in_vec[] = { + {.base = &iov, .len = sizeof(struct tfm_crypto_pack_iovec)}, + {.base = context, .len = context_len}, + }; + + return API_DISPATCH_NO_OUTVEC(in_vec); +} + +TFM_CRYPTO_API(psa_status_t, psa_pake_output) +(psa_pake_operation_t *operation, psa_pake_step_t step, uint8_t *output, + size_t output_size, size_t *output_length) { + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + struct tfm_crypto_pack_iovec iov = { + .function_id = TFM_CRYPTO_PAKE_OUTPUT_SID, + .op_handle = operation->handle, + .step = step, + }; + + psa_invec in_vec[] = { + {.base = &iov, .len = sizeof(struct tfm_crypto_pack_iovec)}, + }; + + psa_outvec out_vec[] = {{.base = output, .len = output_size}}; + + status = API_DISPATCH(in_vec, out_vec); + + *output_length = out_vec[0].len; + + return status; +} + +TFM_CRYPTO_API(psa_status_t, psa_pake_input) +(psa_pake_operation_t *operation, psa_pake_step_t step, const uint8_t *input, + size_t input_length) { + struct tfm_crypto_pack_iovec iov = { + .function_id = TFM_CRYPTO_PAKE_INPUT_SID, + .op_handle = operation->handle, + .step = step, + }; + + psa_invec in_vec[] = { + {.base = &iov, .len = sizeof(struct tfm_crypto_pack_iovec)}, + {.base = input, .len = input_length}, + }; + + return API_DISPATCH_NO_OUTVEC(in_vec); +} + +TFM_CRYPTO_API(psa_status_t, psa_pake_get_shared_key) +(psa_pake_operation_t *operation, const psa_key_attributes_t *attributes, + mbedtls_svc_key_id_t *key) { + struct tfm_crypto_pack_iovec iov = { + .function_id = TFM_CRYPTO_PAKE_GET_SHARED_KEY_SID, + .op_handle = operation->handle, + }; + + psa_invec in_vec[] = { + {.base = &iov, .len = sizeof(struct tfm_crypto_pack_iovec)}, + {.base = attributes, .len = sizeof(psa_key_attributes_t)}, + }; + + psa_outvec out_vec[] = { + {.base = &(operation->handle), .len = sizeof(uint32_t)}, + {.base = key, .len = sizeof(mbedtls_svc_key_id_t)}}; + + return API_DISPATCH(in_vec, out_vec); +} + +TFM_CRYPTO_API(psa_status_t, psa_pake_abort)(psa_pake_operation_t *operation) { + struct tfm_crypto_pack_iovec iov = { + .function_id = TFM_CRYPTO_PAKE_ABORT_SID, + .op_handle = operation->handle, + }; + + psa_invec in_vec[] = { + {.base = &iov, .len = sizeof(struct tfm_crypto_pack_iovec)}, + }; + psa_outvec out_vec[] = { + {.base = &(operation->handle), .len = sizeof(uint32_t)}, + }; + + return API_DISPATCH(in_vec, out_vec); +} + +TFM_CRYPTO_API(psa_status_t, psa_key_derivation_input_integer)( + psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + uint64_t value) +{ + struct tfm_crypto_pack_iovec iov = { + .function_id = TFM_CRYPTO_KEY_DERIVATION_INPUT_INTEGER_SID, + .step = step, + .value = value, + .op_handle = operation->handle, + }; + + psa_invec in_vec[] = { + {.base = &iov, .len = sizeof(struct tfm_crypto_pack_iovec)}, + }; + + return API_DISPATCH_NO_OUTVEC(in_vec); +} + +TFM_CRYPTO_API(psa_status_t, psa_key_derivation_verify_bytes)( + psa_key_derivation_operation_t *operation, + const uint8_t *expected_output, + size_t output_length) +{ + /* To be implemented when the PSA backend supports it */ + return PSA_ERROR_NOT_SUPPORTED; +} + +TFM_CRYPTO_API(psa_status_t, psa_key_derivation_verify_key)( + psa_key_derivation_operation_t *operation, + psa_key_id_t expected) +{ + /* To be implemented when the PSA backend supports it */ + return PSA_ERROR_NOT_SUPPORTED; +} diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt index 0150d3411..6378b3cda 100644 --- a/platform/CMakeLists.txt +++ b/platform/CMakeLists.txt @@ -341,6 +341,7 @@ target_compile_definitions(platform_region_defs BL1_TRAILER_SIZE=${BL1_TRAILER_SIZE} $<$:PLATFORM_DEFAULT_BL1> $<$:SECURE_UART1> + $<$:CONFIG_TFM_LOG_SHARE_UART> DAUTH_${DEBUG_AUTHENTICATION} $<$:MCUBOOT_IMAGE_NUMBER=${MCUBOOT_IMAGE_NUMBER}> $<$:MCUBOOT_SIGNATURE_TYPE=${MCUBOOT_SIGNATURE_TYPE}> diff --git a/platform/ext/accelerator/CMakeLists.txt b/platform/ext/accelerator/CMakeLists.txt index 748522bfc..6b7b644ba 100644 --- a/platform/ext/accelerator/CMakeLists.txt +++ b/platform/ext/accelerator/CMakeLists.txt @@ -7,6 +7,15 @@ cmake_policy(SET CMP0079 NEW) +# TODO: Verify that this works for both minimal and normal configuration +target_compile_definitions(tfm_config + INTERFACE + CRYPTO_HW_ACCELERATOR +) + +# When using nrf_security we don't need these build scripts +return() + if(BL2) add_library(bl2_crypto_hw STATIC) endif() diff --git a/platform/ext/common/exception_info.c b/platform/ext/common/exception_info.c index f4fc17c07..b13469008 100644 --- a/platform/ext/common/exception_info.c +++ b/platform/ext/common/exception_info.c @@ -9,30 +9,7 @@ #include "tfm_spm_log.h" /* "exception_info.h" must be the last include because of the IAR pragma */ #include "exception_info.h" - -struct exception_info_t { - uint32_t EXC_RETURN; /* EXC_RETURN value in LR. */ - uint32_t MSP; /* (Secure) MSP. */ - uint32_t PSP; /* (Secure) PSP. */ - uint32_t *EXC_FRAME; /* Exception frame on stack. */ - uint32_t EXC_FRAME_COPY[8]; /* Copy of the basic exception frame. */ - uint32_t xPSR; /* Program Status Registers. */ - -#ifdef FAULT_STATUS_PRESENT - uint32_t CFSR; /* Configurable Fault Status Register. */ - uint32_t HFSR; /* Hard Fault Status Register. */ - uint32_t BFAR; /* Bus Fault address register. */ - uint32_t BFARVALID; /* Whether BFAR contains a valid address. */ - uint32_t MMFAR; /* MemManage Fault address register. */ - uint32_t MMARVALID; /* Whether MMFAR contains a valid address. */ -#ifdef TRUSTZONE_PRESENT - uint32_t SFSR; /* SecureFault Status Register. */ - uint32_t SFAR; /* SecureFault Address Register. */ - uint32_t SFARVALID; /* Whether SFAR contains a valid address. */ -#endif - -#endif -}; +#include "uart_stdout.h" static struct exception_info_t exception_info; @@ -101,7 +78,7 @@ uint32_t *get_exception_frame(uint32_t lr, uint32_t msp, uint32_t psp) } static void dump_exception_info(bool stack_error, - struct exception_info_t *ctx) + const struct exception_info_t *ctx) { SPMLOG_DBGMSG("Here is some context for the exception:\r\n"); SPMLOG_DBGMSGVAL(" EXC_RETURN (LR): ", ctx->EXC_RETURN); @@ -141,6 +118,16 @@ static void dump_exception_info(bool stack_error, SPMLOG_DBGMSGVAL(" PC: ", ctx->EXC_FRAME_COPY[6]); SPMLOG_DBGMSGVAL(" xPSR: ", ctx->EXC_FRAME_COPY[7]); + SPMLOG_DBGMSG(" Callee saved register state:"); + SPMLOG_DBGMSGVAL(" R4: ", ctx->CALLEE_SAVED_COPY[0]); + SPMLOG_DBGMSGVAL(" R5: ", ctx->CALLEE_SAVED_COPY[1]); + SPMLOG_DBGMSGVAL(" R6: ", ctx->CALLEE_SAVED_COPY[2]); + SPMLOG_DBGMSGVAL(" R7: ", ctx->CALLEE_SAVED_COPY[3]); + SPMLOG_DBGMSGVAL(" R8: ", ctx->CALLEE_SAVED_COPY[4]); + SPMLOG_DBGMSGVAL(" R9: ", ctx->CALLEE_SAVED_COPY[5]); + SPMLOG_DBGMSGVAL(" R10: ", ctx->CALLEE_SAVED_COPY[6]); + SPMLOG_DBGMSGVAL(" R11: ", ctx->CALLEE_SAVED_COPY[7]); + #ifdef FAULT_STATUS_PRESENT SPMLOG_DBGMSGVAL(" CFSR: ", ctx->CFSR); SPMLOG_DBGMSGVAL(" BFSR: ", @@ -172,19 +159,21 @@ static void dump_exception_info(bool stack_error, #endif } -static void dump_error(uint32_t error_type) +static void dump_error(const struct exception_info_t *ctx) { bool stack_error = false; +#if defined(CONFIG_TFM_LOG_SHARE_UART) + stdio_init(); +#endif + SPMLOG_ERRMSG("FATAL ERROR: "); - switch (error_type) { - case EXCEPTION_TYPE_SECUREFAULT: - SPMLOG_ERRMSG("SecureFault\r\n"); - break; + switch (ctx->VECTACTIVE) { case EXCEPTION_TYPE_HARDFAULT: SPMLOG_ERRMSG("HardFault\r\n"); break; - case EXCEPTION_TYPE_MEMFAULT: +#ifdef FAULT_STATUS_PRESENT + case EXCEPTION_TYPE_MEMMANAGEFAULT: SPMLOG_ERRMSG("MemManage fault\r\n"); stack_error = true; break; @@ -196,24 +185,38 @@ static void dump_error(uint32_t error_type) SPMLOG_ERRMSG("UsageFault\r\n"); stack_error = true; break; - case EXCEPTION_TYPE_PLATFORM: - SPMLOG_ERRMSG("Platform Exception\r\n"); - /* Depends on the platform, assume it may cause stack error */ - stack_error = true; +#ifdef TRUSTZONE_PRESENT + case EXCEPTION_TYPE_SECUREFAULT: + SPMLOG_ERRMSG("SecureFault\r\n"); break; +#endif +#endif + /* Platform specific external interrupt secure handler. */ default: - SPMLOG_ERRMSG("Unknown\r\n"); + if (ctx->VECTACTIVE < 16) { + SPMLOG_ERRMSGVAL("Reserved Exception ", ctx->VECTACTIVE); + } else { + SPMLOG_ERRMSGVAL("Platform external interrupt (IRQn): ", ctx->VECTACTIVE - 16); + } + /* Depends on the platform, assume it may cause stack error */ + stack_error = true; break; } - dump_exception_info(stack_error, &exception_info); + dump_exception_info(stack_error, ctx); } -void store_and_dump_context(uint32_t LR_in, uint32_t MSP_in, uint32_t PSP_in, - uint32_t exception_type) +void tfm_exception_info_get_context(struct exception_info_t *ctx) +{ + memcpy(ctx, &exception_info, sizeof(exception_info)); +} + +void store_and_dump_context(uint32_t MSP_in, uint32_t PSP_in, uint32_t LR_in, + uint32_t *callee_saved) { struct exception_info_t *ctx = &exception_info; + ctx->VECTACTIVE = SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk; ctx->xPSR = __get_xPSR(); ctx->EXC_RETURN = LR_in; ctx->MSP = MSP_in; @@ -221,6 +224,10 @@ void store_and_dump_context(uint32_t LR_in, uint32_t MSP_in, uint32_t PSP_in, ctx->EXC_FRAME = get_exception_frame(ctx->EXC_RETURN, ctx->MSP, ctx->PSP); memcpy(ctx->EXC_FRAME_COPY, ctx->EXC_FRAME, sizeof(ctx->EXC_FRAME_COPY)); + if (callee_saved) { + memcpy(ctx->CALLEE_SAVED_COPY, callee_saved, sizeof(ctx->CALLEE_SAVED_COPY)); + } + #ifdef FAULT_STATUS_PRESENT ctx->CFSR = SCB->CFSR; ctx->HFSR = SCB->HFSR; @@ -238,5 +245,5 @@ void store_and_dump_context(uint32_t LR_in, uint32_t MSP_in, uint32_t PSP_in, #endif #endif - dump_error(exception_type); + dump_error(ctx); } diff --git a/platform/ext/common/faults.c b/platform/ext/common/faults.c index 148b302e9..817bbced1 100644 --- a/platform/ext/common/faults.c +++ b/platform/ext/common/faults.c @@ -21,7 +21,7 @@ void C_HardFault_Handler(void) __attribute__((naked)) void HardFault_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_HARDFAULT); + EXCEPTION_INFO(); __ASM volatile( "bl C_HardFault_Handler \n" @@ -41,7 +41,7 @@ void C_MemManage_Handler(void) __attribute__((naked)) void MemManage_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_MEMFAULT); + EXCEPTION_INFO(); __ASM volatile( "bl C_MemManage_Handler \n" @@ -61,7 +61,7 @@ void C_BusFault_Handler(void) __attribute__((naked)) void BusFault_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_BUSFAULT); + EXCEPTION_INFO(); __ASM volatile( "bl C_BusFault_Handler \n" @@ -81,7 +81,7 @@ void C_SecureFault_Handler(void) __attribute__((naked)) void SecureFault_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_SECUREFAULT); + EXCEPTION_INFO(); __ASM volatile( "bl C_SecureFault_Handler \n" @@ -96,7 +96,7 @@ void C_UsageFault_Handler(void) __attribute__((naked)) void UsageFault_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_USAGEFAULT); + EXCEPTION_INFO(); __ASM volatile( "bl C_UsageFault_Handler \n" diff --git a/platform/ext/common/gcc/tfm_common_s.ld b/platform/ext/common/gcc/tfm_common_s.ld index d2cc2cd3b..32b982714 100644 --- a/platform/ext/common/gcc/tfm_common_s.ld +++ b/platform/ext/common/gcc/tfm_common_s.ld @@ -261,6 +261,15 @@ SECTIONS VENEERS() #endif +#if defined(CONFIG_PSA_NEED_CRACEN_KMU_DRIVER) + .nrf_kmu_reserved_push_area S_DATA_START: + { + __nrf_kmu_reserved_push_area = .; + *(.nrf_kmu_reserved_push_area) + __nrf_kmu_reserved_push_area_end = .; + } > RAM +#endif /* CONFIG_PSA_NEED_CRACEN_KMU_DRIVER */ + /**** Base address of secure data area */ .tfm_secure_data_start : { diff --git a/platform/ext/common/mpc_ppc_faults.c b/platform/ext/common/mpc_ppc_faults.c index 95c7d7898..f0e788049 100644 --- a/platform/ext/common/mpc_ppc_faults.c +++ b/platform/ext/common/mpc_ppc_faults.c @@ -25,7 +25,7 @@ void C_MPC_Handler(void) __attribute__((naked)) void MPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_MPC_Handler \n" @@ -47,7 +47,7 @@ void C_PPC_Handler(void) __attribute__((naked)) void PPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_PPC_Handler \n" diff --git a/platform/ext/target/arm/mps2/an519/faults.c b/platform/ext/target/arm/mps2/an519/faults.c index 3f663d11c..fd680c56a 100644 --- a/platform/ext/target/arm/mps2/an519/faults.c +++ b/platform/ext/target/arm/mps2/an519/faults.c @@ -29,7 +29,7 @@ void C_MPC_Handler(void) __attribute__((naked)) void MPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_MPC_Handler \n" @@ -57,7 +57,7 @@ void C_PPC_Handler(void) __attribute__((naked)) void PPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_PPC_Handler \n" diff --git a/platform/ext/target/arm/mps2/an521/faults.c b/platform/ext/target/arm/mps2/an521/faults.c index 3f663d11c..fd680c56a 100644 --- a/platform/ext/target/arm/mps2/an521/faults.c +++ b/platform/ext/target/arm/mps2/an521/faults.c @@ -29,7 +29,7 @@ void C_MPC_Handler(void) __attribute__((naked)) void MPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_MPC_Handler \n" @@ -57,7 +57,7 @@ void C_PPC_Handler(void) __attribute__((naked)) void PPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_PPC_Handler \n" diff --git a/platform/ext/target/arm/musca_b1/faults.c b/platform/ext/target/arm/musca_b1/faults.c index 8f5e5d1e8..5b658bf5c 100644 --- a/platform/ext/target/arm/musca_b1/faults.c +++ b/platform/ext/target/arm/musca_b1/faults.c @@ -32,7 +32,7 @@ void C_MPC_Handler(void) __attribute__((naked)) void MPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_MPC_Handler \n" @@ -60,7 +60,7 @@ void C_PPC_Handler(void) __attribute__((naked)) void PPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_PPC_Handler \n" @@ -84,7 +84,7 @@ void C_NMI_Handler(void) __attribute__((naked)) void NMI_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_NMI_Handler \n" diff --git a/platform/ext/target/arm/musca_s1/faults.c b/platform/ext/target/arm/musca_s1/faults.c index f2658e63c..a248c4052 100644 --- a/platform/ext/target/arm/musca_s1/faults.c +++ b/platform/ext/target/arm/musca_s1/faults.c @@ -29,7 +29,7 @@ void C_MPC_Handler(void) __attribute__((naked)) void MPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_MPC_Handler \n" @@ -57,7 +57,7 @@ void C_PPC_Handler(void) __attribute__((naked)) void PPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_PPC_Handler \n" diff --git a/platform/ext/target/arm/rss/common/faults.c b/platform/ext/target/arm/rss/common/faults.c index 95c7d7898..f0e788049 100644 --- a/platform/ext/target/arm/rss/common/faults.c +++ b/platform/ext/target/arm/rss/common/faults.c @@ -25,7 +25,7 @@ void C_MPC_Handler(void) __attribute__((naked)) void MPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_MPC_Handler \n" @@ -47,7 +47,7 @@ void C_PPC_Handler(void) __attribute__((naked)) void PPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_PPC_Handler \n" diff --git a/platform/ext/target/lairdconnectivity/bl5340_dvk_cpuapp/services/include/tfm_read_ranges.h b/platform/ext/target/lairdconnectivity/bl5340_dvk_cpuapp/services/include/tfm_platform_user_memory_ranges.h similarity index 72% rename from platform/ext/target/lairdconnectivity/bl5340_dvk_cpuapp/services/include/tfm_read_ranges.h rename to platform/ext/target/lairdconnectivity/bl5340_dvk_cpuapp/services/include/tfm_platform_user_memory_ranges.h index 83cb01431..be9c72f3b 100644 --- a/platform/ext/target/lairdconnectivity/bl5340_dvk_cpuapp/services/include/tfm_read_ranges.h +++ b/platform/ext/target/lairdconnectivity/bl5340_dvk_cpuapp/services/include/tfm_platform_user_memory_ranges.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef TFM_READ_RANGES_H__ -#define TFM_READ_RANGES_H__ +#ifndef TFM_PLATFORM_USER_MEMORY_RANGES_H__ +#define TFM_PLATFORM_USER_MEMORY_RANGES_H__ #include @@ -33,4 +33,9 @@ static const struct tfm_read_service_range ranges[] = { { .start = FICR_XOSC32MTRIM_ADDR, .size = FICR_XOSC32MTRIM_SIZE }, }; -#endif /* TFM_READ_RANGES_H__ */ +static const struct tfm_write32_service_address tfm_write32_service_addresses[] = { + /* This is a dummy value because this table cannot be empty */ + {.addr = 0xFFFFFFFF, .mask = 0x0, .allowed_values = NULL, .allowed_values_array_size = 0}, +}; + +#endif /* TFM_PLATFORM_USER_MEMORY_RANGES_H__ */ diff --git a/platform/ext/target/lairdconnectivity/common/bl5340/CMakeLists.txt b/platform/ext/target/lairdconnectivity/common/bl5340/CMakeLists.txt index 40d8380be..2bf62b926 100644 --- a/platform/ext/target/lairdconnectivity/common/bl5340/CMakeLists.txt +++ b/platform/ext/target/lairdconnectivity/common/bl5340/CMakeLists.txt @@ -19,20 +19,20 @@ set(NRF_FOLDER_PATH ${NRF_PLATFORM_PATH}/common/nrf5340) # Specify the location of platform specific build dependencies. target_sources(tfm_s PRIVATE - $<$:${CMAKE_CURRENT_SOURCE_DIR}/${NRF_FOLDER_PATH}/gcc/startup_nrf5340.c> + $<$:${CMAKE_CURRENT_SOURCE_DIR}/${NRF_PLATFORM_PATH}/common/core/startup_nrf5340.c> ) if(NS) target_sources(tfm_ns PRIVATE - $<$:${CMAKE_CURRENT_SOURCE_DIR}/${NRF_FOLDER_PATH}/gcc/startup_nrf5340.c> + $<$:${CMAKE_CURRENT_SOURCE_DIR}/${NRF_PLATFORM_PATH}/common/core/startup_nrf5340.c> ) endif() if(BL2) target_sources(bl2 PRIVATE - $<$:${CMAKE_CURRENT_SOURCE_DIR}/${NRF_FOLDER_PATH}/gcc/startup_nrf5340.c> + $<$:${CMAKE_CURRENT_SOURCE_DIR}/${NRF_PLATFORM_PATH}/common/core/startup_nrf5340.c> ) endif() diff --git a/platform/ext/target/lairdconnectivity/common/bl5340/target_cfg.h b/platform/ext/target/lairdconnectivity/common/bl5340/target_cfg.h deleted file mode 100644 index da87ff73e..000000000 --- a/platform/ext/target/lairdconnectivity/common/bl5340/target_cfg.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2017-2019 Arm Limited - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __TARGET_CFG_H__ -#define __TARGET_CFG_H__ - -/** - * \file target_cfg.h - * \brief nRF5340 target configuration header - * - * This file contains the platform specific functions to configure - * the Cortex-M33 core, memory permissions and security attribution - * on the nRF5340 platform. - * - * Memory permissions and security attribution are configured via - * the System Protection Unit (SPU) which is the nRF specific Implementation - * Defined Attribution Unit (IDAU). - */ - -#include "tfm_plat_defs.h" - -#define TFM_DRIVER_STDIO Driver_USART1 -#define NS_DRIVER_STDIO Driver_USART0 - -/** - * \brief Store the addresses of memory regions - */ -struct memory_region_limits { - uint32_t non_secure_code_start; - uint32_t non_secure_partition_base; - uint32_t non_secure_partition_limit; - uint32_t veneer_base; - uint32_t veneer_limit; -#ifdef NRF_NS_STORAGE_PARTITION_START - uint32_t non_secure_storage_partition_base; - uint32_t non_secure_storage_partition_limit; -#endif /* NRF_NS_STORAGE_PARTITION_START */ -}; - -/** - * \brief Holds the data necessary to do isolation for a specific peripheral. - */ -struct platform_data_t -{ - uint32_t periph_start; - uint32_t periph_limit; -}; - -/** - * \brief Configures memory permissions via the System Protection Unit. - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t spu_init_cfg(void); - -/** - * \brief Configures peripheral permissions via the System Protection Unit. - * - * The function does the following: - * - grants Non-Secure access to nRF peripherals that are not Secure-only - * - grants Non-Secure access to DDPI channels - * - grants Non-Secure access to GPIO pins - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t spu_periph_init_cfg(void); - -/** - * \brief Restrict access to peripheral to secure - */ -void spu_periph_configure_to_secure(uint32_t periph_num); - -/** - * \brief Allow non-secure access to peripheral - */ -void spu_periph_configure_to_non_secure(uint32_t periph_num); - -/** - * \brief Clears SPU interrupt. - */ -void spu_clear_irq(void); - -/** - * \brief Configures SAU and IDAU. - */ -void sau_and_idau_cfg(void); - -/** - * \brief Enables the fault handlers and sets priorities. - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t enable_fault_handlers(void); - -/** - * \brief Configures the system reset request properties - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t system_reset_cfg(void); - -/** - * \brief Configures the system debug properties. - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t init_debug(void); - -/** - * \brief Configures all external interrupts to target the - * NS state, apart for the ones associated to secure - * peripherals (plus SPU) - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t nvic_interrupt_target_state_cfg(void); - -/** - * \brief This function enable the interrupts associated - * to the secure peripherals (plus the isolation boundary violation - * interrupts) - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t nvic_interrupt_enable(void); - -#endif /* __TARGET_CFG_H__ */ diff --git a/platform/ext/target/nordic_nrf/common/core/CMakeLists.txt b/platform/ext/target/nordic_nrf/common/core/CMakeLists.txt index fb383085d..19e2aee64 100644 --- a/platform/ext/target/nordic_nrf/common/core/CMakeLists.txt +++ b/platform/ext/target/nordic_nrf/common/core/CMakeLists.txt @@ -19,6 +19,19 @@ if (NOT NRF_BOARD_SELECTED) "Instead of '${TFM_PLATFORM}', choose e.g. '${hint}'.") endif() +# At the time of writing there is no systematic way to identify which +# NVM technology is used by the SoC from the Kconfig, so we just +# hardcode this information here instead. +if((NRF_SOC_VARIANT STREQUAL nrf54l15) OR (target STREQUAL nrf54l15)) + # Maybe we only need to check one of these options but these + # variables keep changing so we check both to be future proof + set(HAS_RRAMC 1) + set(HAS_CRACEN 1) +else() + set(HAS_NVMC 1) + set(HAS_CRACEN 0) +endif() + #========================= Platform dependencies ===============================# include(hal_nordic.cmake) @@ -63,16 +76,33 @@ target_include_directories(platform_s services/include ) +set(nvm_sources + $<$:${CMAKE_CURRENT_SOURCE_DIR}/cmsis_drivers/Driver_Flash.c> +) + +if(HAS_RRAMC) + list(APPEND nvm_sources + ${HAL_NORDIC_PATH}/nrfx/drivers/src/nrfx_rramc.c + ) +elseif(HAS_NVMC) + list(APPEND nvm_sources + ${HAL_NORDIC_PATH}/nrfx/drivers/src/nrfx_nvmc.c + ) +else() + message(FATAL_ERROR "Unexpected device") +endif() + target_sources(platform_s - PRIVATE - cmsis_drivers/Driver_Flash.c - ${HAL_NORDIC_PATH}/nrfx/drivers/src/nrfx_nvmc.c + PRIVATE + ${nvm_sources} nrfx_glue.c native_drivers/mpu_armv8m_drv.c native_drivers/spu.c + $<$:${CMAKE_CURRENT_SOURCE_DIR}/nrf_exception_info.c> $<$,$>:${CMAKE_CURRENT_SOURCE_DIR}/plat_test.c> $<$:${CMAKE_CURRENT_SOURCE_DIR}/pal_plat_test.c> - $<$:${CMAKE_CURRENT_SOURCE_DIR}/tfm_hal_its_encryption.c> + $<$,$>:${CMAKE_CURRENT_SOURCE_DIR}/tfm_hal_its_encryption.c> + $<$,$>:${CMAKE_CURRENT_SOURCE_DIR}/tfm_hal_its_encryption_cracen.c> ) if (NRF_HW_INIT_RESET_ON_BOOT) @@ -102,6 +132,11 @@ if(TFM_SPM_LOG_RAW_ENABLED) cmsis_drivers/Driver_USART.c ${HAL_NORDIC_PATH}/nrfx/drivers/src/nrfx_uarte.c ) + + target_compile_definitions(platform_s + PUBLIC + NRF_SECURE_UART_INSTANCE=${NRF_SECURE_UART_INSTANCE} + ) endif() target_compile_options(platform_s @@ -121,10 +156,9 @@ target_compile_definitions(platform_s if(BL2) target_sources(platform_bl2 PRIVATE - cmsis_drivers/Driver_Flash.c + ${nvm_sources} cmsis_drivers/Driver_USART.c ${HAL_NORDIC_PATH}/nrfx/drivers/src/nrfx_uarte.c - ${HAL_NORDIC_PATH}/nrfx/drivers/src/nrfx_nvmc.c nrfx_glue.c ) target_sources(bl2 @@ -163,6 +197,18 @@ target_sources(tfm_spm target_cfg.c ) +target_sources(tfm_s + PRIVATE + $<$:${CMAKE_CURRENT_SOURCE_DIR}/startup_${target}.c> +) + +if(BL2) + target_sources(bl2 + PRIVATE + $<$:${CMAKE_CURRENT_SOURCE_DIR}/startup_${target}.c> + ) +endif() + #========================= Files for building NS side platform ================# configure_file(config_nordic_nrf_spe.cmake.in @@ -179,6 +225,7 @@ install(FILES ${PLATFORM_DIR}/ext/driver/Driver_Common.h install(FILES startup.c + startup_${target}.c nrfx_glue.c pal_plat_test.c pal_plat_test.h @@ -186,6 +233,7 @@ install(FILES startup.c ) install(FILES startup.h + target_cfg.h nrfx_config.h ns/CMakeLists.txt config.cmake diff --git a/platform/ext/target/nordic_nrf/common/core/cmsis_drivers/Driver_Flash.c b/platform/ext/target/nordic_nrf/common/core/cmsis_drivers/Driver_Flash.c index 833cf4f7c..e143634c4 100644 --- a/platform/ext/target/nordic_nrf/common/core/cmsis_drivers/Driver_Flash.c +++ b/platform/ext/target/nordic_nrf/common/core/cmsis_drivers/Driver_Flash.c @@ -21,14 +21,30 @@ #include #include #include + +#include + +#include + +#if defined(NRF_NVMC_S) #include +#elif defined(NRF_RRAMC_S) +#include + +#if CONFIG_NRF_RRAM_WRITE_BUFFER_SIZE > 0 +#define WRITE_BUFFER_SIZE CONFIG_NRF_RRAM_WRITE_BUFFER_SIZE +#else +#define WRITE_BUFFER_SIZE 0 +#endif + +#else +#error "Unrecognized platform" +#endif #ifndef ARG_UNUSED #define ARG_UNUSED(arg) (void)arg #endif -#define ARM_FLASH_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1, 0) - #if RTE_FLASH0 /** @@ -48,23 +64,21 @@ static const uint32_t data_width_byte[DATA_WIDTH_ENUM_SIZE] = { sizeof(uint32_t), }; -static const ARM_DRIVER_VERSION DriverVersion = { - ARM_FLASH_API_VERSION, - ARM_FLASH_DRV_VERSION -}; - static const ARM_FLASH_CAPABILITIES DriverCapabilities = { .event_ready = 0, .data_width = DATA_WIDTH_32BIT, - .erase_chip = 1 + .erase_chip = 0 }; static ARM_FLASH_INFO FlashInfo = { .sector_info = NULL, /* Uniform sector layout */ .sector_count = FLASH_TOTAL_SIZE / FLASH_AREA_IMAGE_SECTOR_SIZE, .sector_size = FLASH_AREA_IMAGE_SECTOR_SIZE, - .page_size = sizeof(uint32_t), /* 32-bit word = 4 bytes */ - .program_unit = sizeof(uint32_t), /* 32-bit word = 4 bytes */ + /* page_size denotes the optimal programming page size in bytes + * for fast programming, but is currently unused by TF-M. */ + .page_size = sizeof(uint32_t), + /* Note that program_unit must match TFM_HAL_ITS_PROGRAM_UNIT */ + .program_unit = sizeof(uint32_t), .erased_value = 0xFF }; @@ -83,11 +97,6 @@ static bool is_range_valid(uint32_t addr, uint32_t cnt) return true; } -static ARM_DRIVER_VERSION ARM_Flash_GetVersion(void) -{ - return DriverVersion; -} - static ARM_FLASH_CAPABILITIES ARM_Flash_GetCapabilities(void) { return DriverCapabilities; @@ -101,26 +110,31 @@ static int32_t ARM_Flash_Initialize(ARM_Flash_SignalEvent_t cb_event) return ARM_DRIVER_ERROR; } - return ARM_DRIVER_OK; -} +#ifdef RRAMC_PRESENT + nrfx_rramc_config_t config = NRFX_RRAMC_DEFAULT_CONFIG(WRITE_BUFFER_SIZE); -static int32_t ARM_Flash_Uninitialize(void) -{ - return ARM_DRIVER_OK; -} + config.mode_write = true; -static int32_t ARM_Flash_PowerControl(ARM_POWER_STATE state) -{ - switch (state) { - case ARM_POWER_FULL: - /* Nothing to be done */ - return ARM_DRIVER_OK; - - case ARM_POWER_OFF: - case ARM_POWER_LOW: - default: - return ARM_DRIVER_ERROR_UNSUPPORTED; - } +#if CONFIG_NRF_RRAM_READYNEXT_TIMEOUT_VALUE > 0 + config.preload_timeout_enable = true; + config.preload_timeout = CONFIG_NRF_RRAM_READYNEXT_TIMEOUT_VALUE; +#else + config.preload_timeout_enable = false; + config.preload_timeout = 0; +#endif + + /* Don't use an event handler until it's understood whether we + * want it or not + */ + nrfx_rramc_evt_handler_t handler = NULL; + + nrfx_err_t err = nrfx_rramc_init(&config, handler); + + if(err != NRFX_SUCCESS && err != NRFX_ERROR_ALREADY) { + return err; + } +#endif /* RRAMC_PRESENT */ + return ARM_DRIVER_OK; } static int32_t ARM_Flash_ReadData(uint32_t addr, void *data, uint32_t cnt) @@ -152,7 +166,20 @@ static int32_t ARM_Flash_ProgramData(uint32_t addr, const void *data, return ARM_DRIVER_ERROR_PARAMETER; } +#ifdef NRF_NVMC_S nrfx_nvmc_words_write(addr, data, cnt); +#else + nrfx_rramc_words_write(addr, data, cnt); + + /* At time of writing, the Zephyr driver commits writes, but the + * nrfx driver does not, so we commit here using the HAL to align + * Zephyr and TF-M behaviour. + * + * Not committing may cause data loss and/or high power + * consumption. + */ + nrf_rramc_task_trigger(NRF_RRAMC, NRF_RRAMC_TASK_COMMIT_WRITEBUF); +#endif /* Conversion between bytes and data items */ return cnt; @@ -160,45 +187,42 @@ static int32_t ARM_Flash_ProgramData(uint32_t addr, const void *data, static int32_t ARM_Flash_EraseSector(uint32_t addr) { +#ifdef NRF_NVMC_S nrfx_err_t err_code = nrfx_nvmc_page_erase(addr); + if (err_code != NRFX_SUCCESS) { return ARM_DRIVER_ERROR_PARAMETER; } +#else + for (uint32_t *erase_word_ptr = (uint32_t *)addr; + (uint32_t)erase_word_ptr < addr + FLASH_AREA_IMAGE_SECTOR_SIZE; erase_word_ptr++) { + if(*erase_word_ptr != 0xFFFFFFFFU) { + nrfx_rramc_word_write((uint32_t)erase_word_ptr, 0xFFFFFFFFU); + } + } - return ARM_DRIVER_OK; -} + nrf_rramc_task_trigger(NRF_RRAMC, NRF_RRAMC_TASK_COMMIT_WRITEBUF); +#endif -static int32_t ARM_Flash_EraseChip(void) -{ - nrfx_nvmc_all_erase(); return ARM_DRIVER_OK; } -static ARM_FLASH_STATUS ARM_Flash_GetStatus(void) -{ - ARM_FLASH_STATUS status = { - .busy = !nrfx_nvmc_write_done_check() - }; - - return status; -} - static ARM_FLASH_INFO * ARM_Flash_GetInfo(void) { return &FlashInfo; } ARM_DRIVER_FLASH Driver_FLASH0 = { - .GetVersion = ARM_Flash_GetVersion, + .GetVersion = NULL, .GetCapabilities = ARM_Flash_GetCapabilities, .Initialize = ARM_Flash_Initialize, - .Uninitialize = ARM_Flash_Uninitialize, - .PowerControl = ARM_Flash_PowerControl, + .Uninitialize = NULL, + .PowerControl = NULL, .ReadData = ARM_Flash_ReadData, .ProgramData = ARM_Flash_ProgramData, .EraseSector = ARM_Flash_EraseSector, - .EraseChip = ARM_Flash_EraseChip, - .GetStatus = ARM_Flash_GetStatus, + .EraseChip = NULL, + .GetStatus = NULL, .GetInfo = ARM_Flash_GetInfo }; diff --git a/platform/ext/target/nordic_nrf/common/core/cmsis_drivers/Driver_USART.c b/platform/ext/target/nordic_nrf/common/core/cmsis_drivers/Driver_USART.c index 37d6eb37f..42053ebd8 100644 --- a/platform/ext/target/nordic_nrf/common/core/cmsis_drivers/Driver_USART.c +++ b/platform/ext/target/nordic_nrf/common/core/cmsis_drivers/Driver_USART.c @@ -28,13 +28,20 @@ #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) #endif +// TODO: NCSDK-22597: Support configuring peripherals as secure +#if !(DOMAIN_NS == 1U) && defined(CONFIG_TFM_LOG_SHARE_UART) && defined(NRF_SPU) +#define SPU_CONFIGURE_UART +#include +#endif + #ifndef ARG_UNUSED #define ARG_UNUSED(arg) (void)arg #endif #define ARM_USART_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(2, 2) -#if RTE_USART0 || RTE_USART1 || RTE_USART2 || RTE_USART3 +#if RTE_USART0 || RTE_USART1 || RTE_USART2 || RTE_USART3 || \ + RTE_UART00 || RTE_USART20 || RTE_UART21 || RTE_UART22 || RTE_USART30 #define PSEL_DISCONNECTED 0xFFFFFFFFUL @@ -108,6 +115,11 @@ static int32_t ARM_USARTx_Initialize(ARM_USART_SignalEvent_t cb_event, { ARG_UNUSED(cb_event); +#ifdef SPU_CONFIGURE_UART + spu_peripheral_config_secure((uint32_t)uart_resources->uarte.p_reg, false); + NVIC_ClearTargetState(NRFX_IRQ_NUMBER_GET((uint32_t)uart_resources->uarte.p_reg)); +#endif + nrfx_uarte_config_t uart_config = UART_CONFIG_INITIALIZER(); uart_config_set_uart_pins(&uart_config, @@ -135,6 +147,12 @@ static int32_t ARM_USARTx_Uninitialize(UARTx_Resources *uart_resources) nrfx_uarte_uninit(&uart_resources->uarte); uart_resources->initialized = false; + +#ifdef SPU_CONFIGURE_UART + spu_peripheral_config_non_secure((uint32_t)uart_resources->uarte.p_reg, false); + NVIC_SetTargetState(NRFX_IRQ_NUMBER_GET((uint32_t)uart_resources->uarte.p_reg)); +#endif + return ARM_DRIVER_OK; } @@ -422,4 +440,24 @@ DRIVER_USART(2); DRIVER_USART(3); #endif -#endif /* RTE_USART0 || RTE_USART1 || RTE_USART2 || RTE_USART3 */ +#if RTE_USART00 +DRIVER_USART(00); +#endif + +#if RTE_USART20 +DRIVER_USART(20); +#endif + +#if RTE_USART21 +DRIVER_USART(21); +#endif + +#if RTE_USART22 +DRIVER_USART(22); +#endif + +#if RTE_USART30 +DRIVER_USART(30); +#endif + +#endif /* RTE_USART0 || RTE_USART1 || etc. */ diff --git a/platform/ext/target/nordic_nrf/common/core/config.cmake b/platform/ext/target/nordic_nrf/common/core/config.cmake index b5817b7cc..07e868252 100644 --- a/platform/ext/target/nordic_nrf/common/core/config.cmake +++ b/platform/ext/target/nordic_nrf/common/core/config.cmake @@ -36,3 +36,5 @@ endif() # Platform-specific configurations set(CONFIG_TFM_USE_TRUSTZONE ON) set(TFM_MULTI_CORE_TOPOLOGY OFF) + +set(NRF_SECURE_UART_INSTANCE 1 CACHE STRING "The UART instance number to use for secure UART") diff --git a/platform/ext/target/nordic_nrf/common/core/faults.c b/platform/ext/target/nordic_nrf/common/core/faults.c index 37ff846b6..40cf4d6d9 100644 --- a/platform/ext/target/nordic_nrf/common/core/faults.c +++ b/platform/ext/target/nordic_nrf/common/core/faults.c @@ -8,49 +8,117 @@ #include #include "cmsis.h" -#include "tfm_spm_log.h" #include "spu.h" #include "utilities.h" +#include "nrf_exception_info.h" /* "exception_info.h" must be the last include because of the IAR pragma */ #include "exception_info.h" -static void spu_dump_context(void) -{ - SPMLOG_ERRMSG("Platform Exception: SPU Fault\r\n"); - - /* Report which type of violation occured */ - if(NRF_SPU->EVENTS_RAMACCERR) - { - SPMLOG_DBGMSG(" RAMACCERR\r\n"); - } - if(NRF_SPU->EVENTS_PERIPHACCERR) - { - SPMLOG_DBGMSG(" PERIPHACCERR\r\n"); - } - if(NRF_SPU->EVENTS_FLASHACCERR) - { - SPMLOG_DBGMSG(" FLASHACCERR\r\n"); - } -} - void SPU_Handler(void) { - spu_dump_context(); - +#ifdef TFM_EXCEPTION_INFO_DUMP + nrf_exception_info_store_context(); +#endif /* Clear SPU interrupt flag and pending SPU IRQ */ spu_clear_events(); - NVIC_ClearPendingIRQ(SPU_IRQn); + NVIC_ClearPendingIRQ((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) - NVIC_USER_IRQ_OFFSET); tfm_core_panic(); } __attribute__((naked)) void SPU_IRQHandler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); + + __ASM volatile( + "BL SPU_Handler \n" + "B . \n" + ); +} + +#ifdef NRF_SPU00 +__attribute__((naked)) void SPU00_IRQHandler(void) +{ + EXCEPTION_INFO(); + + __ASM volatile( + "BL SPU_Handler \n" + "B . \n" + ); +} +#endif + +#ifdef NRF_SPU10 +__attribute__((naked)) void SPU10_IRQHandler(void) +{ + EXCEPTION_INFO(); + + __ASM volatile( + "BL SPU_Handler \n" + "B . \n" + ); +} +#endif + +#ifdef NRF_SPU20 +__attribute__((naked)) void SPU20_IRQHandler(void) +{ + EXCEPTION_INFO(); __ASM volatile( "BL SPU_Handler \n" "B . \n" ); } +#endif + +#ifdef NRF_SPU30 +__attribute__((naked)) void SPU30_IRQHandler(void) +{ + EXCEPTION_INFO(); + + __ASM volatile( + "BL SPU_Handler \n" + "B . \n" + ); +} +#endif + +#ifdef NRF_MPC00 +void MPC_Handler(void) +{ +#ifdef TFM_EXCEPTION_INFO_DUMP + nrf_exception_info_store_context(); +#endif + + /* Clear MPC interrupt flag and pending MPC IRQ */ + mpc_clear_events(); + + NVIC_ClearPendingIRQ(MPC00_IRQn); + + tfm_core_panic(); +} + +__attribute__((naked)) void MPC00_IRQHandler(void) +{ + EXCEPTION_INFO(); + + __ASM volatile( + "BL MPC_Handler \n" + "B . \n" + ); +} +#endif + +#ifdef NRF_TAMPC +__attribute__((naked)) void TAMPC_IRQHandler(void) +{ + EXCEPTION_INFO(); + + __ASM volatile( + "BL TAMPC_Handler \n" + "B . \n" + ); +} +#endif diff --git a/platform/ext/target/nordic_nrf/common/core/native_drivers/spu.c b/platform/ext/target/nordic_nrf/common/core/native_drivers/spu.c index 8ba5b5776..3d93de8b6 100644 --- a/platform/ext/target/nordic_nrf/common/core/native_drivers/spu.c +++ b/platform/ext/target/nordic_nrf/common/core/native_drivers/spu.c @@ -16,8 +16,14 @@ #include "spu.h" #include "region_defs.h" +#include "array.h" /* Platform-specific configuration */ +#if NRF_SPU_HAS_MEMORY + +#define DEVICE_FLASH_BASE_ADDRESS FLASH_BASE_ADDRESS +#define DEVICE_SRAM_BASE_ADDRESS SRAM_BASE_ADDRESS + #define FLASH_SECURE_ATTRIBUTION_REGION_SIZE SPU_FLASH_REGION_SIZE #define SRAM_SECURE_ATTRIBUTION_REGION_SIZE SPU_SRAM_REGION_SIZE @@ -29,9 +35,6 @@ #define NUM_SRAM_SECURE_ATTRIBUTION_REGIONS \ (TOTAL_RAM_SIZE / SRAM_SECURE_ATTRIBUTION_REGION_SIZE) -#define DEVICE_FLASH_BASE_ADDRESS FLASH_BASE_ADDRESS -#define DEVICE_SRAM_BASE_ADDRESS SRAM_BASE_ADDRESS - /* Convenience macros for SPU Non-Secure Callable (NCS) attribution */ /* @@ -56,20 +59,24 @@ */ #define FLASH_NSC_SIZE_REG(size) ((31 - __builtin_clz(size)) - 4) - -void spu_enable_interrupts(void) +#if defined(REGION_PCD_SRAM_ADDRESS) +static bool spu_region_is_sram_region_in_address_range(uint8_t region_id, uint32_t start_address, uint32_t end_address) { - nrf_spu_int_enable(NRF_SPU, - NRF_SPU_INT_FLASHACCERR_MASK | - NRF_SPU_INT_RAMACCERR_MASK | - NRF_SPU_INT_PERIPHACCERR_MASK); + size_t start_id = (start_address - DEVICE_SRAM_BASE_ADDRESS) / SRAM_SECURE_ATTRIBUTION_REGION_SIZE; + size_t end_id = (end_address - DEVICE_SRAM_BASE_ADDRESS) / SRAM_SECURE_ATTRIBUTION_REGION_SIZE; + return region_id >= start_id && region_id <= end_id; } +#endif -void spu_clear_events(void) +static bool spu_region_is_pcd_region(NRF_SPU_Type * p_reg, uint8_t region_id) { - nrf_spu_event_clear(NRF_SPU, NRF_SPU_EVENT_RAMACCERR); - nrf_spu_event_clear(NRF_SPU, NRF_SPU_EVENT_FLASHACCERR); - nrf_spu_event_clear(NRF_SPU, NRF_SPU_EVENT_PERIPHACCERR); + bool is_pcd = false; + +#ifdef PM_PCD_SRAM_ADDRESS + is_pcd = is_pcd || spu_region_is_sram_region_in_address_range(region_id, PM_PCD_SRAM_ADDRESS, PM_PCD_SRAM_END_ADDRESS); +#endif + + return is_pcd; } #if defined(REGION_MCUBOOT_ADDRESS) || defined(REGION_B0_ADDRESS) || defined(REGION_S0_ADDRESS) || defined(REGION_S1_ADDRESS) @@ -81,15 +88,6 @@ static bool spu_region_is_flash_region_in_address_range(uint8_t region_id, uint3 } #endif -#if defined(REGION_PCD_SRAM_ADDRESS) -static bool spu_region_is_sram_region_in_address_range(uint8_t region_id, uint32_t start_address, uint32_t end_address) -{ - size_t start_id = (start_address - DEVICE_SRAM_BASE_ADDRESS) / SRAM_SECURE_ATTRIBUTION_REGION_SIZE; - size_t end_id = (end_address - DEVICE_SRAM_BASE_ADDRESS) / SRAM_SECURE_ATTRIBUTION_REGION_SIZE; - return region_id >= start_id && region_id <= end_id; -} -#endif - static bool spu_region_is_bootloader_region(NRF_SPU_Type * p_reg, uint8_t region_id) { bool is_bootloader = false; @@ -110,17 +108,98 @@ static bool spu_region_is_bootloader_region(NRF_SPU_Type * p_reg, uint8_t region return is_bootloader; } -static bool spu_region_is_pcd_region(NRF_SPU_Type * p_reg, uint8_t region_id) +#endif /* NRF_SPU_HAS_MEMORY */ + +void spu_enable_interrupts(void) { - bool is_pcd = false; + uint32_t mask = 0; -#ifdef PM_PCD_SRAM_ADDRESS - is_pcd = is_pcd || spu_region_is_sram_region_in_address_range(region_id, PM_PCD_SRAM_ADDRESS, PM_PCD_SRAM_END_ADDRESS); +#if NRF_SPU_HAS_MEMORY + mask |= NRF_SPU_INT_RAMACCERR_MASK; + mask |= NRF_SPU_INT_FLASHACCERR_MASK; #endif - return is_pcd; + mask |= NRF_SPU_INT_PERIPHACCERR_MASK; + + for(int i = 0; i < ARRAY_SIZE(spu_instances); i++) { + nrf_spu_int_enable(spu_instances[i], mask); + } } +uint32_t spu_events_get(void) +{ + uint32_t events = 0; + + for(int i = 0; i < ARRAY_SIZE(spu_instances); i++) { + if(nrf_spu_event_check(spu_instances[i], NRF_SPU_EVENT_PERIPHACCERR)){ + events |= SPU_EVENT_PERIPHACCERR; + } +#if NRF_SPU_HAS_MEMORY + if (nrf_spu_event_check(spu_instances[i], NRF_SPU_EVENT_RAMACCERR)) { + events |= SPU_EVENT_RAMACCERR; + } + if (nrf_spu_event_check(spu_instances[i], NRF_SPU_EVENT_FLASHACCERR)) { + events |= SPU_EVENT_FLASHACCERR; + } +#endif /* NRF_SPU_HAS_MEMORY */ + } + + return events; +} + +#ifdef MPC_PRESENT +void mpc_enable_interrupts(void) +{ + uint32_t mask = NRF_MPC_INT_MEMACCERR_MASK; + nrf_mpc_int_enable(NRF_MPC00, mask); +} + +uint32_t mpc_events_get(void) +{ + uint32_t events = 0; + + if (nrf_mpc_event_check(NRF_MPC00, NRF_MPC_EVENT_MEMACCERR)){ + events |= MPC_EVENT_MEMACCERR; + } + + return events; +} + +void mpc_clear_events() +{ + nrf_mpc_event_clear(NRF_MPC00, NRF_MPC_EVENT_MEMACCERR); +} +#endif /* MPC_PRESENT */ + +void spu_clear_events(void) +{ + for(int i = 0; i < ARRAY_SIZE(spu_instances); i++) { +#if NRF_SPU_HAS_MEMORY + nrf_spu_event_clear(spu_instances[i], NRF_SPU_EVENT_RAMACCERR); + nrf_spu_event_clear(spu_instances[i], NRF_SPU_EVENT_FLASHACCERR); +#endif + nrf_spu_event_clear(spu_instances[i], NRF_SPU_EVENT_PERIPHACCERR); + } +} + +#ifdef SPU_PERIPHACCERR_ADDRESS_ADDRESS_Msk +uint32_t spu_get_peri_addr(void) { + uint32_t addr = 0; + + for(int i = 0; i < ARRAY_SIZE(spu_instances); i++) { + if(spu_instances[i]->EVENTS_PERIPHACCERR){ + /* Only the lower 16 bits of the address are captured into the register. The upper + * 16 bits correspond to the upper 16 bits of the SPU's base address. + */ + addr = spu_instances[i]->PERIPHACCERR.ADDRESS | ((uint32_t)spu_instances[i] & 0xFFFF0000); + } + } + + return addr; +} +#endif + +#if NRF_SPU_HAS_MEMORY void spu_regions_reset_unlocked_secure(void) { for (size_t i = 0; i < NUM_FLASH_SECURE_ATTRIBUTION_REGIONS ; i++) { @@ -266,11 +345,13 @@ uint32_t spu_regions_sram_get_region_size(void) { return SRAM_SECURE_ATTRIBUTION_REGION_SIZE; } -void spu_peripheral_config_secure(uint32_t periph_base_addr, bool periph_lock) +#endif /* NRF_SPU_HAS_MEMORY */ + +void spu_peripheral_config_secure(const uint32_t periph_base_address, bool periph_lock) { - /* Determine peripheral ID */ - const uint8_t periph_id = NRFX_PERIPHERAL_ID_GET(periph_base_addr); + uint8_t periph_id = NRFX_PERIPHERAL_ID_GET(periph_base_address); +#if NRF_SPU_HAS_MEMORY /* ASSERT checking that this is not an explicit Non-Secure peripheral */ NRFX_ASSERT((NRF_SPU->PERIPHID[periph_id].PERM & SPU_PERIPHID_PERM_SECUREMAPPING_Msk) != @@ -281,13 +362,26 @@ void spu_peripheral_config_secure(uint32_t periph_base_addr, bool periph_lock) 1 /* Secure */, 1 /* Secure DMA */, periph_lock); + +#else + + NRF_SPU_Type * nrf_spu = spu_instance_from_peripheral_addr(periph_base_address); + + uint8_t spu_id = NRFX_PERIPHERAL_ID_GET(nrf_spu); + + uint8_t index = periph_id - spu_id; + + nrf_spu_periph_perm_secattr_set(nrf_spu, index, true /* Secure */); + nrf_spu_periph_perm_dmasec_set(nrf_spu, index, true /* Secure */); + nrf_spu_periph_perm_lock_enable(nrf_spu, index); +#endif } -void spu_peripheral_config_non_secure(uint32_t periph_base_addr, bool periph_lock) +void spu_peripheral_config_non_secure(const uint32_t periph_base_address, bool periph_lock) { - /* Determine peripheral ID */ - const uint8_t periph_id = NRFX_PERIPHERAL_ID_GET(periph_base_addr); + uint8_t periph_id = NRFX_PERIPHERAL_ID_GET(periph_base_address); +#if NRF_SPU_HAS_MEMORY /* ASSERT checking that this is not an explicit Secure peripheral */ NRFX_ASSERT((NRF_SPU->PERIPHID[periph_id].PERM & SPU_PERIPHID_PERM_SECUREMAPPING_Msk) != @@ -298,4 +392,15 @@ void spu_peripheral_config_non_secure(uint32_t periph_base_addr, bool periph_loc 0 /* Non-Secure */, 0 /* Non-Secure DMA */, periph_lock); +#else + NRF_SPU_Type * nrf_spu = spu_instance_from_peripheral_addr(periph_base_address); + + uint8_t spu_id = NRFX_PERIPHERAL_ID_GET(nrf_spu); + + uint8_t index = periph_id - spu_id; + + nrf_spu_periph_perm_secattr_set(nrf_spu, index, false /* Non-Secure */); + nrf_spu_periph_perm_dmasec_set(nrf_spu, index, false /* Non-Secure */); + nrf_spu_periph_perm_lock_enable(nrf_spu, index); +#endif } diff --git a/platform/ext/target/nordic_nrf/common/core/native_drivers/spu.h b/platform/ext/target/nordic_nrf/common/core/native_drivers/spu.h index 5e1bd4321..8c8856af2 100644 --- a/platform/ext/target/nordic_nrf/common/core/native_drivers/spu.h +++ b/platform/ext/target/nordic_nrf/common/core/native_drivers/spu.h @@ -20,14 +20,36 @@ #include #include #include +#include #include +#ifdef MPC_PRESENT +#include +#endif #define SPU_LOCK_CONF_LOCKED true #define SPU_LOCK_CONF_UNLOCKED false #define SPU_SECURE_ATTR_SECURE true #define SPU_SECURE_ATTR_NONSECURE false +__attribute__((unused)) static NRF_SPU_Type * spu_instances[] = { +#ifdef NRF_SPU + NRF_SPU, +#endif +#ifdef NRF_SPU00 + NRF_SPU00, +#endif +#ifdef NRF_SPU10 + NRF_SPU10, +#endif +#ifdef NRF_SPU20 + NRF_SPU20, +#endif +#ifdef NRF_SPU30 + NRF_SPU30, +#endif +}; + /** * \brief SPU interrupt enabling * @@ -36,6 +58,18 @@ */ void spu_enable_interrupts(void); +enum spu_events { + SPU_EVENT_RAMACCERR = 1 << 0, + SPU_EVENT_FLASHACCERR = 1 << 1, + SPU_EVENT_PERIPHACCERR= 1 << 2, + MPC_EVENT_MEMACCERR = 1 << 3 +}; + +/** + * \brief Retrieve bitmask of SPU events. + */ +uint32_t spu_events_get(void); + /** * \brief SPU event clearing * @@ -89,55 +123,44 @@ void spu_regions_flash_config_non_secure_callable(uint32_t start_addr, uint32_t * * Configure a device peripheral to be accessible from Secure domain only. * - * \param periph_base_addr peripheral base address - * (must correspond to a valid peripheral ID) + * \param periph_base_address Base address of a particular peripheral. * \param periph_lock Variable indicating whether to lock peripheral security * * \note * - peripheral shall not be a Non-Secure only peripheral * - DMA transactions are configured as Secure */ -void spu_peripheral_config_secure(uint32_t periph_base_addr, bool periph_lock); +void spu_peripheral_config_secure(const uint32_t periph_base_address, bool periph_lock); /** * Configure a device peripheral to be accessible from Non-Secure domain. * - * \param periph_base_addr peripheral base address - * (must correspond to a valid peripheral ID) + * \param periph_base_address Base address of a particular peripheral. * \param periph_lock Variable indicating whether to lock peripheral security * * \note * - peripheral shall not be a Secure-only peripheral * - DMA transactions are configured as Non-Secure */ -void spu_peripheral_config_non_secure(uint32_t periph_base_addr, bool periph_lock); +void spu_peripheral_config_non_secure(const uint32_t periph_base_address, bool periph_lock); /** - * Configure DPPI channels to be accessible from Non-Secure domain. - * - * \param channels_mask Bitmask with channels configuration. - * \param lock_conf Variable indicating whether to lock DPPI channel security + * /brief Retrieve the address of the transaction that triggered PERIPHACCERR. * - * \note all channels are configured as Non-Secure */ -static inline void spu_dppi_config_non_secure(uint32_t channels_mask, bool lock_conf) -{ - nrf_spu_dppi_config_set(NRF_SPU, 0, channels_mask, lock_conf); -} +uint32_t spu_get_peri_addr(void); /** - * Configure GPIO pins to be accessible from Non-Secure domain. - * - * \param port_number GPIO Port number - * \param gpio_mask Bitmask with gpio configuration. - * \param lock_conf Variable indicating whether to lock GPIO port security - * - * \note all pins are configured as Non-Secure + * Return the SPU instance that can be used to configure the + * peripheral at the given base address. */ -static inline void spu_gpio_config_non_secure(uint8_t port_number, uint32_t gpio_mask, - bool lock_conf) +static inline NRF_SPU_Type * spu_instance_from_peripheral_addr(uint32_t peripheral_addr) { - nrf_spu_gpio_config_set(NRF_SPU, port_number, gpio_mask, lock_conf); + /* See the SPU chapter in the IPS for how this is calculated */ + + uint32_t apb_bus_number = peripheral_addr & 0x00FC0000; + + return (NRF_SPU_Type *)(0x50000000 | apb_bus_number); } /** @@ -226,4 +249,24 @@ uint32_t spu_regions_sram_get_last_id(void); */ uint32_t spu_regions_sram_get_region_size(void); +/** + * \brief MPC interrupt enabling + * + * Enable security violations outside the Cortex-M33 + * to trigger SPU interrupts. + */ +void mpc_enable_interrupts(void); + +/** + * \brief Retrieve bitmask of MPC events. + */ +uint32_t mpc_events_get(void); + +/** + * \brief MPC event clearing + * + * Clear MPC event registers + */ +void mpc_clear_events(void); + #endif diff --git a/platform/ext/target/nordic_nrf/common/core/nrf_exception_info.c b/platform/ext/target/nordic_nrf/common/core/nrf_exception_info.c new file mode 100644 index 000000000..a5df17e8e --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/core/nrf_exception_info.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "nrf_exception_info.h" +#include "tfm_spm_log.h" +#include "spu.h" + +static struct nrf_exception_info nrf_exc_info; + +static void dump_exception_info(struct nrf_exception_info *ctx) +{ + SPMLOG_ERRMSG("Platform Exception:\r\n"); + + /* Report which type of violation occured */ + if (ctx->events & SPU_EVENT_RAMACCERR) { + SPMLOG_DBGMSG(" SPU.RAMACCERR\r\n"); + } + + if (ctx->events & SPU_EVENT_PERIPHACCERR) { + SPMLOG_DBGMSG(" SPU.PERIPHACCERR\r\n"); + SPMLOG_DBGMSGVAL(" Target addr: ", ctx->periphaccerr.address); + } + + if (ctx->events & SPU_EVENT_FLASHACCERR) { + SPMLOG_DBGMSG(" SPU.FLASHACCERR\r\n"); + } + +#if MPC_PRESENT + if (ctx->events & MPC_EVENT_MEMACCERR) { + SPMLOG_DBGMSG(" MPC.MEMACCERR\r\n"); + SPMLOG_DBGMSGVAL(" Target addr: ", ctx->memaccerr.address); + SPMLOG_DBGMSGVAL(" Access information: ", ctx->memaccerr.info); + SPMLOG_DBGMSGVAL(" Owner id: ", ctx->memaccerr.info & 0xf); + SPMLOG_DBGMSGVAL(" Masterport: ", (ctx->memaccerr.info & 0x1f0) >> 4); + SPMLOG_DBGMSGVAL(" Read: ", (ctx->memaccerr.info >> 12) & 1); + SPMLOG_DBGMSGVAL(" Write: ", (ctx->memaccerr.info >> 13) & 1); + SPMLOG_DBGMSGVAL(" Execute: ", (ctx->memaccerr.info >> 14) & 1); + SPMLOG_DBGMSGVAL(" Secure: ", (ctx->memaccerr.info >> 15) & 1); + SPMLOG_DBGMSGVAL(" Error source: ", (ctx->memaccerr.info >> 16) & 1); + } +#endif +} + +void nrf_exception_info_store_context(void) +{ + nrf_exc_info.events = spu_events_get(); + +#ifdef SPU_PERIPHACCERR_ADDRESS_ADDRESS_Msk + if (nrf_exc_info.events & SPU_EVENT_PERIPHACCERR){ + nrf_exc_info.periphaccerr.address = spu_get_peri_addr(); + } +#endif + +#ifdef MPC_PRESENT + nrf_exc_info.events |= mpc_events_get(); + if (nrf_exc_info.events & MPC_EVENT_MEMACCERR) + { + nrf_exc_info.memaccerr.address = NRF_MPC00->MEMACCERR.ADDRESS; + nrf_exc_info.memaccerr.info = NRF_MPC00->MEMACCERR.INFO; + } +#endif + + dump_exception_info(&nrf_exc_info); +} + +void nrf_exception_info_get_context(struct nrf_exception_info *ctx) +{ + memcpy(ctx, &nrf_exc_info, sizeof(struct nrf_exception_info)); +} diff --git a/platform/ext/target/nordic_nrf/common/core/nrf_exception_info.h b/platform/ext/target/nordic_nrf/common/core/nrf_exception_info.h new file mode 100644 index 000000000..04b2eb8ba --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/core/nrf_exception_info.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __NRF_EXCEPTION_INFO_H__ +#define __NRF_EXCEPTION_INFO_H__ + +#include + +struct nrf_exception_info { + uint32_t events; + union{ + struct { + uint32_t address; + } periphaccerr; + + struct { + uint32_t address; + uint32_t info; + } memaccerr; + }; +}; + +void nrf_exception_info_store_context(void); + +void nrf_exception_info_get_context(struct nrf_exception_info *ctx); + +#endif /* __NRF_EXCEPTION_INFO_H__ */ diff --git a/platform/ext/target/nordic_nrf/common/core/nrfx_config.h b/platform/ext/target/nordic_nrf/common/core/nrfx_config.h index e30baef60..f76e49cdd 100644 --- a/platform/ext/target/nordic_nrf/common/core/nrfx_config.h +++ b/platform/ext/target/nordic_nrf/common/core/nrfx_config.h @@ -35,10 +35,21 @@ #include #if RTE_FLASH0 + +#include + +#if defined(NRF_NVMC_S) #define NRFX_NVMC_ENABLED 1 +#elif defined(NRF_RRAMC_S) +#define NRFX_RRAMC_ENABLED 1 +#else +#error "Unrecognized platform" #endif -#if RTE_USART0 || RTE_USART1 || RTE_USART2 || RTE_USART3 +#endif /* RTE_FLASH0 */ + +#if RTE_USART0 || RTE_USART1 || RTE_USART2 || RTE_USART3 || \ + RTE_USART00 || RTE_USART20 || RTE_USART21 || RTE_USART22 || RTE_USART30 #define NRFX_UARTE_ENABLED 1 #endif #if RTE_USART0 @@ -54,6 +65,23 @@ #define NRFX_UARTE3_ENABLED 1 #endif +/* 54L15 has different UART instances */ +#if RTE_USART00 +#define NRFX_UARTE00_ENABLED 1 +#endif +#if RTE_USART20 +#define NRFX_UARTE20_ENABLED 1 +#endif +#if RTE_USART21 +#define NRFX_UARTE21_ENABLED 1 +#endif +#if RTE_USART22 +#define NRFX_UARTE22_ENABLED 1 +#endif +#if RTE_USART30 +#define NRFX_UARTE30_ENABLED 1 +#endif + /* * For chips with TrustZone support, MDK provides CMSIS-Core peripheral * accessing symbols in two flavors, with secure and non-secure base address @@ -72,6 +100,8 @@ #include #elif defined(NRF91_SERIES) #include +#elif defined(NRF54L15_ENGA_XXAA) + #include #else #error "Unknown device." #endif diff --git a/platform/ext/target/nordic_nrf/common/core/ns/CMakeLists.txt b/platform/ext/target/nordic_nrf/common/core/ns/CMakeLists.txt index 89c118e74..f2909dafe 100644 --- a/platform/ext/target/nordic_nrf/common/core/ns/CMakeLists.txt +++ b/platform/ext/target/nordic_nrf/common/core/ns/CMakeLists.txt @@ -19,6 +19,7 @@ target_compile_definitions(platform_region_defs target_sources(tfm_ns PRIVATE startup.c + $<$:${CMAKE_CURRENT_SOURCE_DIR}/startup_${target}.c> ) # Additional NS API sources @@ -55,3 +56,14 @@ target_compile_definitions(platform_ns NRF_TRUSTZONE_NONSECURE DOMAIN_NS=1 ) + +target_compile_definitions(platform_ns + PUBLIC + # We don't need to trim the device in the non-secure image because it + # is the secure image's responsiblity to do this. + NRF_DISABLE_FICR_TRIMCNF + # The glitch detector can only be configured from a secure image so + # we need to skip this configuration. + NRF_SKIP_GLITCHDETECTOR_DISABLE +) + diff --git a/platform/ext/target/nordic_nrf/common/core/plat_test.c b/platform/ext/target/nordic_nrf/common/core/plat_test.c index e9ea327e5..b653f3d03 100644 --- a/platform/ext/target/nordic_nrf/common/core/plat_test.c +++ b/platform/ext/target/nordic_nrf/common/core/plat_test.c @@ -30,6 +30,14 @@ #include "tfm_spm_log.h" #endif +#ifdef NRF_TIMER10 +#define SECURE_TIMER NRF_TIMER10 +#define NON_SECURE_TIMER NRF_TIMER20 +#else +#define SECURE_TIMER NRF_TIMER0 +#define NON_SECURE_TIMER NRF_TIMER1 +#endif + #define TIMER_RELOAD_VALUE (1*1000*1000) #define TIMER_FREQ_HZ (1000000) @@ -70,27 +78,27 @@ static void timer_event_clear(NRF_TIMER_Type *TIMER) void tfm_plat_test_secure_timer_start(void) { - timer_init(NRF_TIMER0, TIMER_RELOAD_VALUE); - timer_start(NRF_TIMER0); + timer_init(SECURE_TIMER, TIMER_RELOAD_VALUE); + timer_start(SECURE_TIMER); } void tfm_plat_test_secure_timer_clear_intr(void) { - timer_event_clear(NRF_TIMER0); + timer_event_clear(SECURE_TIMER); } void tfm_plat_test_secure_timer_stop(void) { - timer_stop(NRF_TIMER0); + timer_stop(SECURE_TIMER); } void tfm_plat_test_non_secure_timer_start(void) { - timer_init(NRF_TIMER1, TIMER_RELOAD_VALUE); - timer_start(NRF_TIMER1); + timer_init(NON_SECURE_TIMER, TIMER_RELOAD_VALUE); + timer_start(NON_SECURE_TIMER); } void tfm_plat_test_non_secure_timer_stop(void) { - timer_stop(NRF_TIMER1); + timer_stop(NON_SECURE_TIMER); } diff --git a/platform/ext/target/nordic_nrf/common/core/services/include/tfm_ioctl_core_api.h b/platform/ext/target/nordic_nrf/common/core/services/include/tfm_ioctl_core_api.h index df3c8d618..4c604642b 100644 --- a/platform/ext/target/nordic_nrf/common/core/services/include/tfm_ioctl_core_api.h +++ b/platform/ext/target/nordic_nrf/common/core/services/include/tfm_ioctl_core_api.h @@ -29,8 +29,8 @@ extern "C" { */ enum tfm_platform_ioctl_core_reqest_types_t { TFM_PLATFORM_IOCTL_READ_SERVICE, + TFM_PLATFORM_IOCTL_WRITE32_SERVICE, TFM_PLATFORM_IOCTL_GPIO_SERVICE, - /* Last core service, start platform specific from this value. */ TFM_PLATFORM_IOCTL_CORE_LAST }; @@ -50,6 +50,20 @@ struct tfm_read_service_out_t { uint32_t result; }; +/** @brief Argument list for each platform write32 service. + */ +struct tfm_write32_service_args_t { + uint32_t addr; + uint32_t value; + uint32_t mask; +}; +/** @brief Output list for each write32 platform service + */ + +struct tfm_write32_service_out_t { + uint32_t result; +}; + enum tfm_gpio_service_type { /** Select which MCU / Subsystem controls the pin */ TFM_GPIO_SERVICE_TYPE_PIN_MCU_SELECT = 0, @@ -88,6 +102,19 @@ struct tfm_gpio_service_out { enum tfm_platform_err_t tfm_platform_mem_read(void *destination, uint32_t addr, size_t len, uint32_t *result); +/** + * @brief Perform a write32 operation. + * + * @param[in] addr Address to write to + * @param[in] value 32 bit value to write + * @param[in] mask Mask applied to the write value + * @param[out] result An enum tfm_write32_service_result value + * + * @return Returns values as specified by the tfm_platform_err_t + */ +enum tfm_platform_err_t tfm_platform_mem_write32(uint32_t addr, uint32_t value, + uint32_t mask, uint32_t *result); + /** @brief Represents an accepted read range. */ struct tfm_read_service_range { @@ -95,6 +122,22 @@ struct tfm_read_service_range { size_t size; }; +/** @brief Represents the accepted addresses and masks for write32 service. + */ +struct tfm_write32_service_address { + uint32_t addr; + uint32_t mask; + const uint32_t *allowed_values; + const uint32_t allowed_values_array_size; +}; + +enum tfm_write32_service_result { + TFM_WRITE32_SERVICE_SUCCESS, + TFM_WRITE32_SERVICE_ERROR_INVALID_ADDRESS, + TFM_WRITE32_SERVICE_ERROR_INVALID_MASK, + TFM_WRITE32_SERVICE_ERROR_INVALID_VALUE, +}; + /** * @brief Perform a GPIO MCU select operation. * diff --git a/platform/ext/target/nordic_nrf/common/core/services/include/tfm_platform_hal_ioctl.h b/platform/ext/target/nordic_nrf/common/core/services/include/tfm_platform_hal_ioctl.h index abe940b66..ca540b552 100644 --- a/platform/ext/target/nordic_nrf/common/core/services/include/tfm_platform_hal_ioctl.h +++ b/platform/ext/target/nordic_nrf/common/core/services/include/tfm_platform_hal_ioctl.h @@ -26,6 +26,11 @@ tfm_platform_hal_read_service(const psa_invec *in_vec, enum tfm_platform_err_t tfm_platform_hal_gpio_service(const psa_invec *in_vec, const psa_outvec *out_vec); + +enum tfm_platform_err_t +tfm_platform_hal_write32_service(const psa_invec *in_vec, + const psa_outvec *out_vec); + #ifdef __cplusplus } #endif diff --git a/platform/ext/target/nordic_nrf/common/core/services/src/tfm_ioctl_core_ns_api.c b/platform/ext/target/nordic_nrf/common/core/services/src/tfm_ioctl_core_ns_api.c index 2370988e2..32f653a90 100644 --- a/platform/ext/target/nordic_nrf/common/core/services/src/tfm_ioctl_core_ns_api.c +++ b/platform/ext/target/nordic_nrf/common/core/services/src/tfm_ioctl_core_ns_api.c @@ -66,3 +66,31 @@ enum tfm_platform_err_t tfm_platform_gpio_pin_mcu_select(uint32_t pin_number, ui return TFM_PLATFORM_ERR_NOT_SUPPORTED; #endif } + +enum tfm_platform_err_t tfm_platform_mem_write32(uint32_t addr, uint32_t value, + uint32_t mask, uint32_t *result) +{ + enum tfm_platform_err_t ret; + psa_invec in_vec; + psa_outvec out_vec; + struct tfm_write32_service_args_t args; + struct tfm_write32_service_out_t out; + + in_vec.base = (const void *)&args; + in_vec.len = sizeof(args); + + out_vec.base = (void *)&out; + out_vec.len = sizeof(out); + + args.addr = addr; + args.value = value; + args.mask = mask; + /* Allowed values cannot be specified by the user */ + + ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_WRITE32_SERVICE, &in_vec, + &out_vec); + + *result = out.result; + + return ret; +} diff --git a/platform/ext/target/nordic_nrf/common/core/services/src/tfm_platform_hal_ioctl.c b/platform/ext/target/nordic_nrf/common/core/services/src/tfm_platform_hal_ioctl.c index c7a1bcc46..28c59e1a5 100644 --- a/platform/ext/target/nordic_nrf/common/core/services/src/tfm_platform_hal_ioctl.c +++ b/platform/ext/target/nordic_nrf/common/core/services/src/tfm_platform_hal_ioctl.c @@ -14,7 +14,7 @@ #include /* This contains the user provided allowed ranges */ -#include +#include #include @@ -76,10 +76,17 @@ tfm_platform_hal_read_service(const psa_invec *in_vec, static bool valid_mcu_select(uint32_t mcu) { switch (mcu) { +#if defined(NRF54L15_ENGA_XXAA) + case NRF_GPIO_PIN_SEL_GPIO: + case NRF_GPIO_PIN_SEL_VPR: + case NRF_GPIO_PIN_SEL_GRTC: + case NRF_GPIO_PIN_SEL_TND: +#else case NRF_GPIO_PIN_SEL_APP: case NRF_GPIO_PIN_SEL_NETWORK: case NRF_GPIO_PIN_SEL_PERIPHERAL: case NRF_GPIO_PIN_SEL_TND: +#endif return true; default: return false; @@ -126,3 +133,76 @@ tfm_platform_hal_gpio_service(const psa_invec *in_vec, const psa_outvec *out_ve } #endif /* NRF_GPIO_HAS_SEL */ +enum tfm_platform_err_t tfm_platform_hal_write32_service(const psa_invec *in_vec, + const psa_outvec *out_vec) +{ + uint32_t addr; + uint32_t mask; + uint32_t allowed_values_array_size; + + struct tfm_write32_service_args_t *args; + struct tfm_write32_service_out_t *out; + + enum tfm_platform_err_t err; + + if (in_vec->len != sizeof(struct tfm_write32_service_args_t) || + out_vec->len != sizeof(struct tfm_write32_service_out_t)) { + return TFM_PLATFORM_ERR_INVALID_PARAM; + } + + args = (struct tfm_write32_service_args_t *)in_vec->base; + out = (struct tfm_write32_service_out_t *)out_vec->base; + + /* Assume failure, in case we don't find a match */ + out->result = TFM_WRITE32_SERVICE_ERROR_INVALID_ADDRESS; + err = TFM_PLATFORM_ERR_INVALID_PARAM; + + for (size_t i = 0; i < ARRAY_SIZE(tfm_write32_service_addresses); i++) { + addr = tfm_write32_service_addresses[i].addr; + mask = tfm_write32_service_addresses[i].mask; + allowed_values_array_size = + tfm_write32_service_addresses[i].allowed_values_array_size; + + if (args->addr == addr) { + out->result = TFM_WRITE32_SERVICE_ERROR_INVALID_MASK; + + if (args->mask == mask) { + /* Check for allowed values if provided */ + if (allowed_values_array_size > 0 && + tfm_write32_service_addresses[i].allowed_values != NULL) { + bool is_value_allowed = false; + + for (int j = 0; j < allowed_values_array_size; j++) { + + const uint32_t allowed_value = + tfm_write32_service_addresses[i] + .allowed_values[j]; + + if (allowed_value == (args->value & args->mask)) { + is_value_allowed = true; + break; + } + } + + if (!is_value_allowed) { + out->result = + TFM_WRITE32_SERVICE_ERROR_INVALID_VALUE; + break; + } + } + + uint32_t new_value = *(uint32_t *)addr; + /* Invert the mask to convert the masked bits to 0 first */ + new_value &= ~args->mask; + new_value |= (args->value & args->mask); + *(uint32_t *)addr = new_value; + + out->result = TFM_WRITE32_SERVICE_SUCCESS; + err = TFM_PLATFORM_ERR_SUCCESS; + break; + } + } + } + + return err; +} diff --git a/platform/ext/target/nordic_nrf/common/core/startup.h b/platform/ext/target/nordic_nrf/common/core/startup.h index be6a6cb70..3906f138d 100644 --- a/platform/ext/target/nordic_nrf/common/core/startup.h +++ b/platform/ext/target/nordic_nrf/common/core/startup.h @@ -35,6 +35,15 @@ __NO_RETURN void SecureFault_Handler(void); void SPU_IRQHandler(void); +void SPU00_IRQHandler(void); +void SPU10_IRQHandler(void); +void SPU20_IRQHandler(void); +void SPU30_IRQHandler(void); + +void MPC00_IRQHandler(void); + +void CRACEN_IRQHandler(void); + /* * The default irq handler is used as a backup in case of * misconfiguration. diff --git a/platform/ext/target/nordic_nrf/common/nrf5340/gcc/startup_nrf5340.c b/platform/ext/target/nordic_nrf/common/core/startup_nrf5340.c similarity index 99% rename from platform/ext/target/nordic_nrf/common/nrf5340/gcc/startup_nrf5340.c rename to platform/ext/target/nordic_nrf/common/core/startup_nrf5340.c index c164a5912..ed60466e2 100644 --- a/platform/ext/target/nordic_nrf/common/nrf5340/gcc/startup_nrf5340.c +++ b/platform/ext/target/nordic_nrf/common/core/startup_nrf5340.c @@ -26,7 +26,7 @@ #include "exception_info.h" __NO_RETURN __attribute__((naked)) void default_tfm_IRQHandler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL default_irq_handler \n" diff --git a/platform/ext/target/nordic_nrf/common/core/startup_nrf54l15.c b/platform/ext/target/nordic_nrf/common/core/startup_nrf54l15.c new file mode 100644 index 000000000..59d3802b0 --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/core/startup_nrf54l15.c @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2022 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This file is derivative of CMSIS V5.9.0 startup_ARMCM33.c + * Git SHA: 2b7495b8535bdcb306dac29b9ded4cfb679d7e5c + */ + +// TODO: NCSDK-25033: Support interrupt handling in TF-M. The IRQs +// below correspond to nrf53, not nrf54L. + +/* + * Define __VECTOR_TABLE_ATTRIBUTE (which can be provided by cmsis.h) + * before including cmsis.h because TF-M's linker script + * tfm_common_s.ld assumes the vector table section is called .vectors + * while cmsis.h will sometimes (e.g. when cmsis is provided by nrfx) + * default to using the name .isr_vector. + */ +#define __VECTOR_TABLE_ATTRIBUTE __attribute__((used, section(".vectors"))) + +#include "cmsis.h" +#include "startup.h" +#include "exception_info.h" + +__NO_RETURN __attribute__((naked)) void default_tfm_IRQHandler(void) { + EXCEPTION_INFO(); + + __ASM volatile( + "BL default_irq_handler \n" + "B . \n" + ); +} + +DEFAULT_IRQ_HANDLER(NMI_Handler) +DEFAULT_IRQ_HANDLER(HardFault_Handler) +DEFAULT_IRQ_HANDLER(MemManage_Handler) +DEFAULT_IRQ_HANDLER(BusFault_Handler) +DEFAULT_IRQ_HANDLER(UsageFault_Handler) +DEFAULT_IRQ_HANDLER(SecureFault_Handler) +DEFAULT_IRQ_HANDLER(SVC_Handler) +DEFAULT_IRQ_HANDLER(DebugMon_Handler) +DEFAULT_IRQ_HANDLER(PendSV_Handler) +DEFAULT_IRQ_HANDLER(SysTick_Handler) + +DEFAULT_IRQ_HANDLER(SWI00_Handler) +DEFAULT_IRQ_HANDLER(SWI01_Handler) +DEFAULT_IRQ_HANDLER(SWI02_Handler) +DEFAULT_IRQ_HANDLER(SWI03_Handler) +DEFAULT_IRQ_HANDLER(MPC00_Handler) +DEFAULT_IRQ_HANDLER(AAR00_CCM00_Handler) +DEFAULT_IRQ_HANDLER(ECB00_Handler) +DEFAULT_IRQ_HANDLER(SERIAL00_Handler) +DEFAULT_IRQ_HANDLER(RRAMC_Handler) +DEFAULT_IRQ_HANDLER(VPR00_Handler) +DEFAULT_IRQ_HANDLER(CTRLAP_Handler) +DEFAULT_IRQ_HANDLER(CM33SS_Handler) +DEFAULT_IRQ_HANDLER(TIMER00_Handler) +DEFAULT_IRQ_HANDLER(TIMER10_Handler) +DEFAULT_IRQ_HANDLER(RTC10_Handler) +DEFAULT_IRQ_HANDLER(EGU10_Handler) +DEFAULT_IRQ_HANDLER(AAR10_CCM10_Handler) +DEFAULT_IRQ_HANDLER(ECB10_Handler) +DEFAULT_IRQ_HANDLER(RADIO_0_Handler) +DEFAULT_IRQ_HANDLER(RADIO_1_Handler) +DEFAULT_IRQ_HANDLER(SERIAL20_Handler) +DEFAULT_IRQ_HANDLER(SERIAL21_Handler) +DEFAULT_IRQ_HANDLER(SERIAL22_Handler) +DEFAULT_IRQ_HANDLER(EGU20_Handler) +DEFAULT_IRQ_HANDLER(TIMER20_Handler) +DEFAULT_IRQ_HANDLER(TIMER21_Handler) +DEFAULT_IRQ_HANDLER(TIMER22_Handler) +DEFAULT_IRQ_HANDLER(TIMER23_Handler) +DEFAULT_IRQ_HANDLER(TIMER24_Handler) +DEFAULT_IRQ_HANDLER(PWM20_Handler) +DEFAULT_IRQ_HANDLER(PWM21_Handler) +DEFAULT_IRQ_HANDLER(PWM22_Handler) +DEFAULT_IRQ_HANDLER(SAADC_Handler) +DEFAULT_IRQ_HANDLER(NFCT_Handler) +DEFAULT_IRQ_HANDLER(TEMP_Handler) +DEFAULT_IRQ_HANDLER(GPIOTE20_0_Handler) +DEFAULT_IRQ_HANDLER(GPIOTE20_1_Handler) +DEFAULT_IRQ_HANDLER(TAMPC_Handler) +DEFAULT_IRQ_HANDLER(I2S20_Handler) +DEFAULT_IRQ_HANDLER(QDEC20_Handler) +DEFAULT_IRQ_HANDLER(QDEC21_Handler) +DEFAULT_IRQ_HANDLER(GRTC_0_Handler) +DEFAULT_IRQ_HANDLER(GRTC_1_Handler) +DEFAULT_IRQ_HANDLER(GRTC_2_Handler) +DEFAULT_IRQ_HANDLER(GRTC_3_Handler) +DEFAULT_IRQ_HANDLER(SERIAL30_Handler) +DEFAULT_IRQ_HANDLER(RTC30_Handler) +DEFAULT_IRQ_HANDLER(COMP_LPCOMP_Handler) +DEFAULT_IRQ_HANDLER(WDT30_Handler) +DEFAULT_IRQ_HANDLER(WDT31_Handler) +DEFAULT_IRQ_HANDLER(GPIOTE30_0_Handler) +DEFAULT_IRQ_HANDLER(GPIOTE30_1_Handler) +DEFAULT_IRQ_HANDLER(CLOCK_POWER_Handler) + +#if defined(DOMAIN_NS) || defined(BL2) +DEFAULT_IRQ_HANDLER(MPC00_IRQHandler) +DEFAULT_IRQ_HANDLER(SPU00_IRQHandler) +DEFAULT_IRQ_HANDLER(SPU10_IRQHandler) +DEFAULT_IRQ_HANDLER(SPU20_IRQHandler) +DEFAULT_IRQ_HANDLER(SPU30_IRQHandler) +DEFAULT_IRQ_HANDLER(CRACEN_IRQHandler) +#else +// TODO: Move into the SPU error handling code +DEFAULT_IRQ_HANDLER(SPU00_IRQHandler) +DEFAULT_IRQ_HANDLER(SPU10_IRQHandler) +DEFAULT_IRQ_HANDLER(SPU20_IRQHandler) +DEFAULT_IRQ_HANDLER(SPU30_IRQHandler) +#endif + +#if defined ( __GNUC__ ) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#endif + +const VECTOR_TABLE_Type __VECTOR_TABLE[] __VECTOR_TABLE_ATTRIBUTE = { + (VECTOR_TABLE_Type)(&__INITIAL_SP), /* Initial Stack Pointer */ +/* Exceptions */ + Reset_Handler, + NMI_Handler, + HardFault_Handler, + MemManage_Handler, /* MPU Fault Handler */ + BusFault_Handler, + UsageFault_Handler, + SecureFault_Handler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + SVC_Handler, + DebugMon_Handler, + default_tfm_IRQHandler, + PendSV_Handler, + SysTick_Handler, +/* Device specific interrupt handlers */ + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + SWI00_Handler, + SWI01_Handler, + SWI02_Handler, + SWI03_Handler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + SPU00_IRQHandler, + MPC00_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + AAR00_CCM00_Handler, + ECB00_Handler, + CRACEN_IRQHandler, + default_tfm_IRQHandler, + SERIAL00_Handler, + RRAMC_Handler, + VPR00_Handler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + CTRLAP_Handler, + CM33SS_Handler, + default_tfm_IRQHandler, + TIMER00_Handler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + SPU10_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + TIMER10_Handler, + RTC10_Handler, + EGU10_Handler, + AAR10_CCM10_Handler, + ECB10_Handler, + RADIO_0_Handler, + RADIO_1_Handler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + SPU20_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + SERIAL20_Handler, + SERIAL21_Handler, + SERIAL22_Handler, + EGU20_Handler, + TIMER20_Handler, + TIMER21_Handler, + TIMER22_Handler, + TIMER23_Handler, + TIMER24_Handler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + PWM20_Handler, + PWM21_Handler, + PWM22_Handler, + SAADC_Handler, + NFCT_Handler, + TEMP_Handler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + GPIOTE20_0_Handler, + GPIOTE20_1_Handler, + TAMPC_Handler, + I2S20_Handler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + QDEC20_Handler, + QDEC21_Handler, + GRTC_0_Handler, + GRTC_1_Handler, + GRTC_2_Handler, + GRTC_3_Handler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + SPU30_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + SERIAL30_Handler, + RTC30_Handler, + COMP_LPCOMP_Handler, + default_tfm_IRQHandler, + WDT30_Handler, + WDT31_Handler, + default_tfm_IRQHandler, + default_tfm_IRQHandler, + GPIOTE30_0_Handler, + GPIOTE30_1_Handler, + CLOCK_POWER_Handler, +}; + +#if defined ( __GNUC__ ) +#pragma GCC diagnostic pop +#endif diff --git a/platform/ext/target/nordic_nrf/common/nrf91/gcc/startup_nrf91.c b/platform/ext/target/nordic_nrf/common/core/startup_nrf91.c similarity index 99% rename from platform/ext/target/nordic_nrf/common/nrf91/gcc/startup_nrf91.c rename to platform/ext/target/nordic_nrf/common/core/startup_nrf91.c index a171249e5..d82f6a642 100644 --- a/platform/ext/target/nordic_nrf/common/nrf91/gcc/startup_nrf91.c +++ b/platform/ext/target/nordic_nrf/common/core/startup_nrf91.c @@ -26,7 +26,7 @@ #include "exception_info.h" __NO_RETURN __attribute__((naked)) void default_tfm_IRQHandler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL default_irq_handler \n" diff --git a/platform/ext/target/nordic_nrf/common/core/target_cfg.c b/platform/ext/target/nordic_nrf/common/core/target_cfg.c index 7fd12130f..52c4fd2a3 100644 --- a/platform/ext/target/nordic_nrf/common/core/target_cfg.c +++ b/platform/ext/target/nordic_nrf/common/core/target_cfg.c @@ -17,25 +17,68 @@ */ #include "target_cfg.h" +#include "native_drivers/spu.h" +#include "nrf54l15_enga_global.h" #include "region_defs.h" #include "tfm_plat_defs.h" #include "tfm_peripherals_config.h" +#include "utilities.h" #include "region.h" +#include "array.h" + +#include #include #include -#include -#include + #include #include +#ifdef RRAMC_PRESENT +#include +#include + +#if CONFIG_NRF_RRAM_WRITE_BUFFER_SIZE > 0 +#define WRITE_BUFFER_SIZE CONFIG_NRF_RRAM_WRITE_BUFFER_SIZE +#else +#define WRITE_BUFFER_SIZE 0 +#endif + +#endif + +#define SPU_ADDRESS_REGION (0x50000000) +#define GET_SPU_SLAVE_INDEX(periph) ((periph.periph_start & 0x0003F000) >> 12) +#define GET_SPU_INSTANCE(periph) ((NRF_SPU_Type*)(SPU_ADDRESS_REGION | (periph.periph_start & 0x00FC0000))) + + +#ifdef CACHE_PRESENT +#include +#endif + +#ifdef NVMC_PRESENT +#include +#include +#endif + +#ifdef MPC_PRESENT +#include +#endif + +#ifdef NRF53_SERIES #define PIN_XL1 0 #define PIN_XL2 1 - -#if !(defined(NRF91_SERIES) || defined(NRF53_SERIES)) -#error "Invalid configuration" #endif +#ifdef NRF54L15_ENGA_XXAA +/* On nRF54L15 XL1 and XL2 are(P1.00) and XL2(P1.01) */ +#define PIN_XL1 32 +#define PIN_XL2 33 +/* During TF-M system initialization we invoke a function that comes + * from Zephyr. This function does not have a header file so we + * declare it's prototype here. + */ +int nordicsemi_nrf54l_init(void); +#endif #if TFM_PERIPHERAL_DCNF_SECURE struct platform_data_t tfm_peripheral_dcnf = { @@ -233,6 +276,41 @@ struct platform_data_t tfm_peripheral_uarte3 = { }; #endif +#if TFM_PERIPHERAL_UARTE00_SECURE +struct platform_data_t tfm_peripheral_uarte00 = { + NRF_UARTE00_S_BASE, + NRF_UARTE00_S_BASE + (sizeof(NRF_UARTE_Type) - 1), +}; +#endif + +#if TFM_PERIPHERAL_UARTE20_SECURE +struct platform_data_t tfm_peripheral_uarte20 = { + NRF_UARTE20_S_BASE, + NRF_UARTE20_S_BASE + (sizeof(NRF_UARTE_Type) - 1), +}; +#endif + +#if TFM_PERIPHERAL_UARTE21_SECURE +struct platform_data_t tfm_peripheral_uarte21 = { + NRF_UARTE21_S_BASE, + NRF_UARTE21_S_BASE + (sizeof(NRF_UARTE_Type) - 1), +}; +#endif + +#if TFM_PERIPHERAL_UARTE22_SECURE +struct platform_data_t tfm_peripheral_uarte22 = { + NRF_UARTE22_S_BASE, + NRF_UARTE22_S_BASE + (sizeof(NRF_UARTE_Type) - 1), +}; +#endif + +#if TFM_PERIPHERAL_UARTE30_SECURE +struct platform_data_t tfm_peripheral_uarte30 = { + NRF_UARTE30_S_BASE, + NRF_UARTE30_S_BASE + (sizeof(NRF_UARTE_Type) - 1), +}; +#endif + #if TFM_PERIPHERAL_SAADC_SECURE struct platform_data_t tfm_peripheral_saadc = { NRF_SAADC_S_BASE, @@ -605,7 +683,7 @@ enum tfm_plat_err_t system_reset_cfg(void) enum tfm_plat_err_t init_debug(void) { -#if defined(NRF91_SERIES) +#if defined(NRF91_SERIES) || defined(NRF54L15_ENGA_XXAA) #if !defined(DAUTH_CHIP_DEFAULT) #error "Debug access on this platform can only be configured by programming the corresponding registers in UICR." @@ -636,6 +714,9 @@ enum tfm_plat_err_t init_debug(void) NRF_CTRLAP->SECUREAPPROTECT.LOCK = CTRLAPPERI_SECUREAPPROTECT_LOCK_LOCK_Locked << CTRLAPPERI_SECUREAPPROTECT_LOCK_LOCK_Msk; +#else +#error "Unrecognized platform" + #endif return TFM_PLAT_ERR_SUCCESS; @@ -649,12 +730,29 @@ enum tfm_plat_err_t nvic_interrupt_target_state_cfg(void) NVIC->ITNS[i] = 0xFFFFFFFF; } - /* Make sure that the SPU is targeted to S state */ - NVIC_ClearTargetState(NRFX_IRQ_NUMBER_GET(NRF_SPU)); + /* Make sure that the SPU instance(s) are targeted to S state */ + for(int i = 0; i < ARRAY_SIZE(spu_instances); i++) { + NVIC_ClearTargetState(NRFX_IRQ_NUMBER_GET(spu_instances[i])); + } + +#ifdef NRF_CRACEN + NVIC_ClearTargetState(NRFX_IRQ_NUMBER_GET(NRF_CRACEN)); +#endif +#ifdef NRF_MPC00 + NVIC_ClearTargetState(MPC00_IRQn); +#endif #ifdef SECURE_UART1 +#if NRF_SECURE_UART_INSTANCE == 0 + /* UARTE0 is a secure peripheral, so its IRQ has to target S state */ + NVIC_ClearTargetState(NRFX_IRQ_NUMBER_GET(NRF_UARTE0)); +#elif NRF_SECURE_UART_INSTANCE == 1 /* UARTE1 is a secure peripheral, so its IRQ has to target S state */ NVIC_ClearTargetState(NRFX_IRQ_NUMBER_GET(NRF_UARTE1)); +#elif NRF_SECURE_UART_INSTANCE == 30 + /* UARTE30 is a secure peripheral, so its IRQ has to target S state */ + NVIC_ClearTargetState(NRFX_IRQ_NUMBER_GET(NRF_UARTE30)); +#endif #endif return TFM_PLAT_ERR_SUCCESS; @@ -666,8 +764,22 @@ enum tfm_plat_err_t nvic_interrupt_enable(void) /* SPU interrupt enabling */ spu_enable_interrupts(); - NVIC_ClearPendingIRQ(NRFX_IRQ_NUMBER_GET(NRF_SPU)); - NVIC_EnableIRQ(NRFX_IRQ_NUMBER_GET(NRF_SPU)); + for(int i = 0; i < ARRAY_SIZE(spu_instances); i++) { + NVIC_ClearPendingIRQ(NRFX_IRQ_NUMBER_GET(spu_instances[i])); + NVIC_EnableIRQ(NRFX_IRQ_NUMBER_GET(spu_instances[i])); + } + +#ifdef MPC_PRESENT + /* MPC interrupt enabling */ + mpc_enable_interrupts(); + + NVIC_ClearPendingIRQ(NRFX_IRQ_NUMBER_GET(NRF_MPC00)); + NVIC_EnableIRQ(NRFX_IRQ_NUMBER_GET(NRF_MPC00)); +#endif + + /* The CRACEN driver configures the NVIC for CRACEN and is + * therefore omitted here. + */ return TFM_PLAT_ERR_SUCCESS; } @@ -676,13 +788,61 @@ enum tfm_plat_err_t nvic_interrupt_enable(void) void sau_and_idau_cfg(void) { + /* + * SAU and IDAU configuration is very different between old + * (53/91) and new (54++) platforms. New platforms have a proper SAU + * and IDAU, whereas old platforms do not. + */ +#ifdef NRF54L15_ENGA_XXAA + /* + * This SAU configuration aligns with ARM's RSS implementation of + * sau_and_idau_cfg when possible. + */ + + /* Enables SAU */ + TZ_SAU_Enable(); + + /* Configures SAU regions to be non-secure */ + + /* Note that this SAU configuration assumes that there is only one + * secure NVM partition and one non-secure NVM partition. Meaning, + * memory_regions.non_secure_partition_limit is at the end of + * NVM. + */ + + /* Configure the end of NVM, and the FICR, to be non-secure using + a single region. Note that the FICR is placed after the + non-secure NVM and before the UICR.*/ + SAU->RNR = 0; + SAU->RBAR = (memory_regions.non_secure_partition_base + & SAU_RBAR_BADDR_Msk); + SAU->RLAR = (NRF_UICR_S_BASE & SAU_RLAR_LADDR_Msk) | SAU_RLAR_ENABLE_Msk; + + /* Leave SAU region 1 disabled until we find a use for it */ + + /* Configures veneers region to be non-secure callable */ + SAU->RNR = 2; + SAU->RBAR = (memory_regions.veneer_base & SAU_RBAR_BADDR_Msk); + SAU->RLAR = (memory_regions.veneer_limit & SAU_RLAR_LADDR_Msk) + | SAU_RLAR_ENABLE_Msk | SAU_RLAR_NSC_Msk; + + /* Configures SAU region 3 to cover both the end of SRAM and + * regions above it as shown in the "Example memory map" in the + * "Product Specification" */ + SAU->RNR = 3; + SAU->RBAR = (NS_DATA_START & SAU_RBAR_BADDR_Msk); + SAU->RLAR = (0xFFFFFFFFul & SAU_RLAR_LADDR_Msk) | SAU_RLAR_ENABLE_Msk; + +#else /* IDAU (SPU) is always enabled. SAU is non-existent. * Allow SPU to have precedence over (non-existing) ARMv8-M SAU. */ TZ_SAU_Disable(); SAU->CTRL |= SAU_CTRL_ALLNS_Msk; +#endif } +#if NRF_SPU_HAS_MEMORY enum tfm_plat_err_t spu_init_cfg(void) { /* @@ -761,30 +921,262 @@ enum tfm_plat_err_t spu_init_cfg(void) return TFM_PLAT_ERR_SUCCESS; } +#endif /* NRF_SPU_HAS_MEMORY */ + + +#ifdef MPC_PRESENT +struct mpc_region_override { + nrf_mpc_override_config_t config; + nrf_owner_t owner_id; + uintptr_t start_address; + size_t endaddr; + uint32_t perm; + uint32_t permmask; + size_t index; +}; + +static void mpc_configure_override(NRF_MPC_Type *mpc, struct mpc_region_override *override) +{ + nrf_mpc_override_startaddr_set(mpc, override->index, override->start_address); + nrf_mpc_override_endaddr_set(mpc, override->index, override->endaddr); + nrf_mpc_override_perm_set(mpc, override->index, override->perm); + nrf_mpc_override_permmask_set(mpc, override->index, override->permmask); + nrf_mpc_override_ownerid_set(mpc, override->index, override->owner_id); + nrf_mpc_override_config_set(mpc, override->index, &override->config); +} + +/* + * Configure the override struct with reasonable defaults. This includes: + * + * Use a slave number of 0 to avoid redirecting bus transactions from + * one slave to another. + * + * Lock the override to prevent the code that follows from tampering + * with the configuration. + * + * Enable the override so it takes effect. + * + * Indicate that secdom is not enabled as this driver is not used on + * platforms with secdom. + */ +static void init_mpc_region_override(struct mpc_region_override * override) +{ + *override = (struct mpc_region_override){ + .config = + (nrf_mpc_override_config_t){ + .slave_number = 0, + .lock = true, + .enable = true, + .secdom_enable = false, + .secure_mask = true, + }, + .perm = 0, /* 0 for non-secure */ + .owner_id = 0, + }; + + override->permmask = MPC_OVERRIDE_PERM_SECATTR_Msk; +} + +enum tfm_plat_err_t nrf_mpc_init_cfg(void) +{ + /* On 54l the NRF_MPC00->REGION[]'s are fixed in HW and the + * OVERRIDE indexes (that are useful to us) start at 0 and end + * (inclusive) at 4. + * + * Note that the MPC regions configure all volatile and non-volatile memory as secure, so we only + * need to explicitly OVERRIDE the non-secure addresses to permit non-secure access. + * + * Explicitly configuring memory as secure is not necessary. + * + * The last OVERRIDE in 54L is fixed in HW and exists to prevent + * other bus masters than the KMU from accessing CRACEN protected RAM. + * + * Note that we must take care not to configure an OVERRIDE that + * affects an active bus transaction. + * + * Note that we don't configure the NSC region to be NS because + * from the MPC's perspective it is secure. NSC is only configurable from the SAU. + * + * Note that OVERRIDE[n].MASTERPORT has a reasonable reset value + * so it is left unconfigured. + * + * Note that there are two owners in 54L. KMU with owner ID 1, and everything else with owner ID 0. + */ + + uint32_t index = 0; + /* + * Configure the non-secure partition of the non-volatile + * memory. This MPC region is intended to cover both the + * non-secure partition in the NVM and also the FICR. The FICR + * starts after the NVM and ends just before the UICR. + */ + { + struct mpc_region_override override; + + init_mpc_region_override(&override); + + override.start_address = memory_regions.non_secure_partition_base; + override.endaddr = NRF_UICR_S_BASE; + override.index = index++; + + mpc_configure_override(NRF_MPC00, &override); + } + + /* Configure the non-secure partition of the volatile memory */ + { + struct mpc_region_override override; + + init_mpc_region_override(&override); + + override.start_address = NS_DATA_START; + override.endaddr = 1 + NS_DATA_LIMIT; + override.index = index++; + + mpc_configure_override(NRF_MPC00, &override); + } + + if(index > 4) { + /* Used more overrides than are available */ + tfm_core_panic(); + } + + /* Lock and disable any unused MPC overrides to prevent malicious configuration */ + while(index <= 4) { + struct mpc_region_override override; + + init_mpc_region_override(&override); + + override.config.enable = false; + + override.index = index++; + + mpc_configure_override(NRF_MPC00, &override); + } + + return TFM_PLAT_ERR_SUCCESS; +} + +#endif /* MPC_PRESENT */ + +static void dppi_channel_configuration(void) +{ + /* The SPU HW and corresponding NRFX HAL API have two different + * API's for DPPI security configuration. The defines + * NRF_SPU_HAS_OWNERSHIP and NRF_SPU_HAS_MEMORY identify which of the two API's + * are present. + * + * TFM_PERIPHERAL_DPPI_CHANNEL_MASK_SECURE is configurable, but + * usually defaults to 0, which results in all DPPI channels being + * non-secure. + */ +#if NRF_SPU_HAS_MEMORY + /* There is only one dppi_id */ + uint8_t dppi_id = 0; + nrf_spu_dppi_config_set(NRF_SPU, dppi_id, TFM_PERIPHERAL_DPPI_CHANNEL_MASK_SECURE, + SPU_LOCK_CONF_LOCKED); +#else + /* TODO_NRF54L15: Use the nrf_spu_feature API to configure DPPI + channels according to a user-controllable config similar to + TFM_PERIPHERAL_DPPI_CHANNEL_MASK_SECURE. */ +#endif +} enum tfm_plat_err_t spu_periph_init_cfg(void) { /* Peripheral configuration */ +#ifdef NRF54L15_ENGA_XXAA + /* Configure features to be non-secure */ + + /* + * Due to MLT-7600, many SPU HW reset values are wrong. The docs + * generally features being non-secure when coming out of HW + * reset, but the HW has a good mix of both. + * + * When configuring NRF_SPU 0 will indicate non-secure and 1 will + * indicate secure. + * + * Most of the chip should be non-secure so to simplify and be + * consistent, we memset the entire memory map of each SPU + * peripheral to 0. + * + * Just after memsetting to 0 we explicitly configure the + * peripherals that should be secure back to secure again. + */ + // TODO: NCSDK-22597: Evaluate if it is safe to memset everything + // in NRF_SPU to 0. + memset(NRF_SPU00, 0, sizeof(NRF_SPU_Type)); + memset(NRF_SPU10, 0, sizeof(NRF_SPU_Type)); + memset(NRF_SPU20, 0, sizeof(NRF_SPU_Type)); + memset(NRF_SPU30, 0, sizeof(NRF_SPU_Type)); + + /* Configure TF-M's UART peripheral to be secure */ +#if NRF_SECURE_UART_INSTANCE == 00 + uint32_t uart_periph_start = tfm_peripheral_uarte00.periph_start; +#endif +#if NRF_SECURE_UART_INSTANCE == 20 + uint32_t uart_periph_start = tfm_peripheral_uarte20.periph_start; +#endif +#if NRF_SECURE_UART_INSTANCE == 21 + uint32_t uart_periph_start = tfm_peripheral_uarte21.periph_start; +#endif +#if NRF_SECURE_UART_INSTANCE == 22 + uint32_t uart_periph_start = tfm_peripheral_uarte22.periph_start; +#endif +#if NRF_SECURE_UART_INSTANCE == 30 + uint32_t uart_periph_start = tfm_peripheral_uarte30.periph_start; +#endif + spu_peripheral_config_secure(uart_periph_start, SPU_LOCK_CONF_LOCKED); + + /* Configure the CTRL-AP mailbox interface to be secure as it is used by the secure ADAC service */ + spu_peripheral_config_secure(NRF_CTRLAP_S_BASE, SPU_LOCK_CONF_LOCKED); + + /* Configure NRF_MEMCONF to be secure as it could otherwise be used to corrupt secure RAM. */ + spu_peripheral_config_secure(NRF_MEMCONF_S_BASE, SPU_LOCK_CONF_LOCKED); + /* Configure trace to be secure, as the security implications of non-secure trace are not understood */ + spu_peripheral_config_secure(NRF_TAD_S_BASE, SPU_LOCK_CONF_LOCKED); + + /* Configure these HW features, which are not in the MDK, to be + * secure, as the security implications of them being non-secure + * are not understood + */ + uint32_t base_addresses[4] = { + 0x50056000, + 0x5008C000, + 0x500E6000, + 0x5010F000 + }; + for(int i = 0; i < 4; i++) { + spu_peripheral_config_secure(base_addresses[i], SPU_LOCK_CONF_LOCKED); + } + + /* Configure NRF_REGULATORS, and NRF_OSCILLATORS to be secure as NRF_REGULATORS.POFCON is needed + * to prevent glitches when the power supply is attacked. + * + * NB: Note that NRF_OSCILLATORS and NRF_REGULATORS have the same base address and must therefore + * have the same security configuration. + */ + spu_peripheral_config_secure(NRF_REGULATORS_S_BASE, SPU_LOCK_CONF_LOCKED); +#else +static const uint32_t target_peripherals[] = { /* The following peripherals share ID: * - FPU (FPU cannot be configured in NRF91 series, it's always NS) * - DCNF (On 53, but not 91) */ #ifndef NRF91_SERIES - spu_peripheral_config_non_secure((uint32_t)NRF_FPU, false); + NRF_FPU_S_BASE, #endif - /* The following peripherals share ID: * - REGULATORS * - OSCILLATORS */ - spu_peripheral_config_non_secure((uint32_t)NRF_REGULATORS, false); + NRF_REGULATORS_S_BASE, /* The following peripherals share ID: * - CLOCK * - POWER * - RESET (On 53, but not 91) */ - spu_peripheral_config_non_secure((uint32_t)NRF_CLOCK, false); + NRF_CLOCK_S_BASE, /* The following peripherals share ID: (referred to as Serial-Box) * - SPIMx * - SPISx @@ -792,115 +1184,194 @@ enum tfm_plat_err_t spu_periph_init_cfg(void) * - TWISx * - UARTEx */ - spu_peripheral_config_non_secure((uint32_t)NRF_SPIM0, false); -#ifndef SECURE_UART1 - /* UART1 is a secure peripheral, so we need to leave Serial-Box 1 as Secure */ - spu_peripheral_config_non_secure((uint32_t)NRF_SPIM1, false); + + /* When UART0 is a secure peripheral we need to leave Serial-Box 0 as Secure. + * The UART Driver will configure it as non-secure when it uninitializes. + */ +#if defined(NRF54L15_ENGA_XXAA) + NRF_SPIM00_S_BASE, +#else +#if !(defined(SECURE_UART1) && NRF_SECURE_UART_INSTANCE == 0) + NRF_SPIM0_S_BASE, +#endif /* !(defined(SECURE_UART1) && NRF_SECURE_UART_INSTANCE == 0) */ +#endif /* NRF54L15_ENGA_XXAA */ + + /* When UART1 is a secure peripheral we need to leave Serial-Box 1 as Secure */ +#if !(defined(SECURE_UART1) && NRF_SECURE_UART_INSTANCE == 1) + NRF_SPIM1_S_BASE, +#endif + NRF_SPIM2_S_BASE, + NRF_SPIM3_S_BASE, + +/* For Moonlight if a UART instance is selected to be the secure instance leave it as secure */ +#if NRF_SECURE_UART_INSTANCE == 20 + NRF_SPIM20_S_BASE, +#endif +#if NRF_SECURE_UART_INSTANCE == 21 + NRF_SPIM21_S_BASE, +#endif +#if NRF_SECURE_UART_INSTANCE == 22 + NRF_SPIM22_S_BASE, +#endif +#if NRF_SECURE_UART_INSTANCE == 30 + NRF_SPIM30_S_BASE, #endif - spu_peripheral_config_non_secure((uint32_t)NRF_SPIM2, false); - spu_peripheral_config_non_secure((uint32_t)NRF_SPIM3, false); + #ifdef NRF_SPIM4 - spu_peripheral_config_non_secure((uint32_t)NRF_SPIM4, false); -#endif - spu_peripheral_config_non_secure((uint32_t)NRF_SAADC, false); - spu_peripheral_config_non_secure((uint32_t)NRF_TIMER0, false); - spu_peripheral_config_non_secure((uint32_t)NRF_TIMER1, false); - spu_peripheral_config_non_secure((uint32_t)NRF_TIMER2, false); - spu_peripheral_config_non_secure((uint32_t)NRF_RTC0, false); - spu_peripheral_config_non_secure((uint32_t)NRF_RTC1, false); - spu_peripheral_config_non_secure((uint32_t)NRF_DPPIC, false); + NRF_SPIM4_S_BASE, +#endif + NRF_SAADC_S_BASE, + NRF_TIMER0_S_BASE, + NRF_TIMER1_S_BASE, + NRF_TIMER2_S_BASE, + NRF_RTC0_S_BASE, + NRF_RTC1_S_BASE, + NRF_DPPIC_S_BASE, #ifndef PSA_API_TEST_IPC #ifdef NRF_WDT0 /* WDT0 is used as a secure peripheral in PSA FF tests */ - spu_peripheral_config_non_secure((uint32_t)NRF_WDT0, false); + NRF_WDT0_S_BASE, #endif #ifdef NRF_WDT - spu_peripheral_config_non_secure((uint32_t)NRF_WDT, false); + NRF_WDT_S_BASE, #endif #endif /* PSA_API_TEST_IPC */ #ifdef NRF_WDT1 - spu_peripheral_config_non_secure((uint32_t)NRF_WDT1, false); + NRF_WDT1_S_BASE, #endif /* The following peripherals share ID: * - COMP * - LPCOMP */ #ifdef NRF_COMP - spu_peripheral_config_non_secure((uint32_t)NRF_COMP, false); + NRF_COMP_S_BASE, #endif - spu_peripheral_config_non_secure((uint32_t)NRF_EGU0, false); - spu_peripheral_config_non_secure((uint32_t)NRF_EGU1, false); - spu_peripheral_config_non_secure((uint32_t)NRF_EGU2, false); - spu_peripheral_config_non_secure((uint32_t)NRF_EGU3, false); - spu_peripheral_config_non_secure((uint32_t)NRF_EGU4, false); + NRF_EGU0_S_BASE, + NRF_EGU1_S_BASE, + NRF_EGU2_S_BASE, + NRF_EGU3_S_BASE, + NRF_EGU4_S_BASE, #ifndef PSA_API_TEST_IPC /* EGU5 is used as a secure peripheral in PSA FF tests */ - spu_peripheral_config_non_secure((uint32_t)NRF_EGU5, false); + NRF_EGU5_S_BASE, #endif - spu_peripheral_config_non_secure((uint32_t)NRF_PWM0, false); - spu_peripheral_config_non_secure((uint32_t)NRF_PWM1, false); - spu_peripheral_config_non_secure((uint32_t)NRF_PWM2, false); - spu_peripheral_config_non_secure((uint32_t)NRF_PWM3, false); + NRF_PWM0_S_BASE, + NRF_PWM1_S_BASE, + NRF_PWM2_S_BASE, + NRF_PWM3_S_BASE, #ifdef NRF_PDM - spu_peripheral_config_non_secure((uint32_t)NRF_PDM, false); + NRF_PDM_S_BASE, #endif #ifdef NRF_PDM0 - spu_peripheral_config_non_secure((uint32_t)NRF_PDM0, false); + NRF_PDM0_S_BASE, #endif #ifdef NRF_I2S - spu_peripheral_config_non_secure((uint32_t)NRF_I2S, false); + NRF_I2S_S_BASE, #endif #ifdef NRF_I2S0 - spu_peripheral_config_non_secure((uint32_t)NRF_I2S0, false); + NRF_I2S0_S_BASE, #endif - spu_peripheral_config_non_secure((uint32_t)NRF_IPC, false); + NRF_IPC_S_BASE, #ifndef SECURE_QSPI #ifdef NRF_QSPI - spu_peripheral_config_non_secure((uint32_t)NRF_QSPI, false); + NRF_QSPI_S_BASE, #endif #endif #ifdef NRF_NFCT - spu_peripheral_config_non_secure((uint32_t)NRF_NFCT, false); + NRF_NFCT_S_BASE, #endif #ifdef NRF_MUTEX - spu_peripheral_config_non_secure((uint32_t)NRF_MUTEX, false); + NRF_MUTEX_S_BASE, #endif #ifdef NRF_QDEC0 - spu_peripheral_config_non_secure((uint32_t)NRF_QDEC0, false); + NRF_QDEC0_S_BASE, #endif #ifdef NRF_QDEC1 - spu_peripheral_config_non_secure((uint32_t)NRF_QDEC1, false); + NRF_QDEC1_S_BASE, #endif #ifdef NRF_USBD - spu_peripheral_config_non_secure((uint32_t)NRF_USBD, false); + NRF_USBD_S_BASE, #endif #ifdef NRF_USBREGULATOR - spu_peripheral_config_non_secure((uint32_t)NRF_USBREGULATOR, false); + NRF_USBREGULATOR_S_BASE, #endif - spu_peripheral_config_non_secure((uint32_t)NRF_NVMC, false); - spu_peripheral_config_non_secure((uint32_t)NRF_P0, false); + NRF_NVMC_S_BASE, + NRF_P0_S_BASE, #ifdef NRF_P1 - spu_peripheral_config_non_secure((uint32_t)NRF_P1, false); + NRF_P1_S_BASE, #endif - spu_peripheral_config_non_secure((uint32_t)NRF_VMC, false); +}; + + for (int i = 0; i < ARRAY_SIZE(target_peripherals); i++) { + spu_peripheral_config_non_secure(target_peripherals[i], SPU_LOCK_CONF_UNLOCKED); + } + +#endif /* Moonlight */ /* DPPI channel configuration */ - spu_dppi_config_non_secure(TFM_PERIPHERAL_DPPI_CHANNEL_MASK_SECURE, SPU_LOCK_CONF_LOCKED); + dppi_channel_configuration(); /* GPIO pin configuration */ - spu_gpio_config_non_secure(0, TFM_PERIPHERAL_GPIO0_PIN_MASK_SECURE, SPU_LOCK_CONF_LOCKED); + uint32_t secure_pins[] = { + TFM_PERIPHERAL_GPIO0_PIN_MASK_SECURE, #ifdef TFM_PERIPHERAL_GPIO1_PIN_MASK_SECURE - spu_gpio_config_non_secure(1, TFM_PERIPHERAL_GPIO1_PIN_MASK_SECURE, SPU_LOCK_CONF_LOCKED); + TFM_PERIPHERAL_GPIO1_PIN_MASK_SECURE, +#endif +#ifdef TFM_PERIPHERAL_GPIO2_PIN_MASK_SECURE + TFM_PERIPHERAL_GPIO2_PIN_MASK_SECURE, +#endif + }; + + /* Note that there are two different API's for SPU configuration */ +#if NRF_SPU_HAS_MEMORY + + for(int port = 0; port < ARRAY_SIZE(secure_pins); port++){ + nrf_spu_gpio_config_set(NRF_SPU, port, secure_pins[port], SPU_LOCK_CONF_LOCKED); + } + +#elif NRF_SPU_HAS_PERIPHERAL_ACCESS + + for(int port = 0; port < ARRAY_SIZE(secure_pins); port++) { + for (int pin = 0; pin < 32; pin++) { + if (secure_pins[port] & (1 << pin)) { + bool enable = true; // secure + + /* + * Unfortunately, NRF_P0 is not configured by NRF_SPU00, etc. + * so it is a bit convoluted to find the SPU instance for port x. + */ + uint32_t gpio_port_addr[2] = { + NRF_P0_S_BASE, + NRF_P1_S_BASE, + }; + + NRF_SPU_Type * spu_instance = spu_instance_from_peripheral_addr(gpio_port_addr[port]); + + nrf_spu_feature_secattr_set(spu_instance, NRF_SPU_FEATURE_GPIO_PIN, port, pin, enable); + nrf_spu_feature_lock_enable(spu_instance, NRF_SPU_FEATURE_GPIO_PIN, port, pin); + } + } + } +#else +#error "Expected either NRF_SPU_HAS_MEMORY or NRF_SPU_HAS_PERIPHERAL_ACCESS to be true" #endif -#ifdef NRF53_SERIES /* Configure properly the XL1 and XL2 pins so that the low-frequency crystal * oscillator (LFXO) can be used. * This configuration can be done only from secure code, as otherwise those * register fields are not accessible. That's why it is placed here. */ +#ifdef NRF53_SERIES +#if defined(CONFIG_SOC_ENABLE_LFXO) && CONFIG_SOC_ENABLE_LFXO == 1 +/* CONFIG_SOC_ENABLE_LFXO doesn't exist for 54L15 target, might be changed in future */ nrf_gpio_pin_control_select(PIN_XL1, NRF_GPIO_PIN_SEL_PERIPHERAL); nrf_gpio_pin_control_select(PIN_XL2, NRF_GPIO_PIN_SEL_PERIPHERAL); +#endif /* CONFIG_SOC_ENABLE_LFXO */ +#endif +#ifdef NRF54L15_ENGA_XXAA + /* NRF54L has a different define */ + nrf_gpio_pin_control_select(PIN_XL1, NRF_GPIO_PIN_SEL_GPIO); + nrf_gpio_pin_control_select(PIN_XL2, NRF_GPIO_PIN_SEL_GPIO); #endif /* @@ -916,9 +1387,52 @@ enum tfm_plat_err_t spu_periph_init_cfg(void) #if defined(NVMC_FEATURE_CACHE_PRESENT) // From MDK nrfx_nvmc_icache_enable(); #elif defined(CACHE_PRESENT) // From MDK - NRF_CACHE->ENABLE = CACHE_ENABLE_ENABLE_Enabled; + +#ifdef NRF_CACHE + nrf_cache_enable(NRF_CACHE); +#endif +#ifdef NRF_ICACHE + nrf_cache_enable(NRF_ICACHE); +#endif +#ifdef NRF_DCACHE + nrf_cache_enable(NRF_DCACHE); +#endif + +#endif + +#ifdef RRAMC_PRESENT + nrfx_rramc_config_t config = NRFX_RRAMC_DEFAULT_CONFIG(WRITE_BUFFER_SIZE); + + config.mode_write = true; + +#if CONFIG_NRF_RRAM_READYNEXT_TIMEOUT_VALUE > 0 + config.preload_timeout_enable = true; + config.preload_timeout = CONFIG_NRF_RRAM_READYNEXT_TIMEOUT_VALUE; +#else + config.preload_timeout_enable = false; + config.preload_timeout = 0; +#endif + + /* Don't use an event handler until it's understood whether we + * want it or not + */ + nrfx_rramc_evt_handler_t handler = NULL; + + nrfx_err_t err = nrfx_rramc_init(&config, handler); + if(err != NRFX_SUCCESS && err != NRFX_ERROR_ALREADY) { + return err; + } +#endif /* RRAMC_PRESENT */ + +#ifdef NRF54L15_ENGA_XXAA + /* SOC configuration from Zephyr's soc.c. */ + int soc_err = nordicsemi_nrf54l_init(); + if(soc_err) { + return soc_err; + } #endif +#if NRF_SPU_HAS_MEMORY /* Enforce that the nRF5340 Network MCU is in the Non-Secure * domain. Non-secure is the HW reset value for the network core * so configuring this should not be necessary, but we want to @@ -927,16 +1441,7 @@ enum tfm_plat_err_t spu_periph_init_cfg(void) * it doesn't get changed by accident. */ nrf_spu_extdomain_set(NRF_SPU, 0, false, true); +#endif return TFM_PLAT_ERR_SUCCESS; } - -void spu_periph_configure_to_secure(uint32_t periph_num) -{ - spu_peripheral_config_secure(periph_num, true); -} - -void spu_periph_configure_to_non_secure(uint32_t periph_num) -{ - spu_peripheral_config_non_secure(periph_num, true); -} diff --git a/platform/ext/target/nordic_nrf/common/nrf5340/target_cfg.h b/platform/ext/target/nordic_nrf/common/core/target_cfg.h similarity index 76% rename from platform/ext/target/nordic_nrf/common/nrf5340/target_cfg.h rename to platform/ext/target/nordic_nrf/common/core/target_cfg.h index 5425b6f9e..aea09bece 100644 --- a/platform/ext/target/nordic_nrf/common/nrf5340/target_cfg.h +++ b/platform/ext/target/nordic_nrf/common/core/target_cfg.h @@ -20,11 +20,11 @@ /** * \file target_cfg.h - * \brief nRF5340 target configuration header + * \brief Target configuration header * * This file contains the platform specific functions to configure - * the Cortex-M33 core, memory permissions and security attribution - * on the nRF5340 platform. + * the Cortex-M33 core, memory permissions and security attribution. + * on the nordic_nrf platform. * * Memory permissions and security attribution are configured via * the System Protection Unit (SPU) which is the nRF specific Implementation @@ -35,8 +35,34 @@ #include "tfm_plat_defs.h" #include "region_defs.h" +#if NRF_SECURE_UART_INSTANCE == 0 +#define TFM_DRIVER_STDIO Driver_USART0 +#elif NRF_SECURE_UART_INSTANCE == 1 #define TFM_DRIVER_STDIO Driver_USART1 +#elif NRF_SECURE_UART_INSTANCE == 00 +#define TFM_DRIVER_STDIO Driver_USART00 +#elif NRF_SECURE_UART_INSTANCE == 20 +#define TFM_DRIVER_STDIO Driver_USART20 +#elif NRF_SECURE_UART_INSTANCE == 21 +#define TFM_DRIVER_STDIO Driver_USART21 +#elif NRF_SECURE_UART_INSTANCE == 22 +#define TFM_DRIVER_STDIO Driver_USART22 +#elif NRF_SECURE_UART_INSTANCE == 30 +#define TFM_DRIVER_STDIO Driver_USART30 +#endif + +/* Only UART20 and UART30 are supported for TF-M tests, which are the + * Non-secure applications build via the TF-M build system + */ +#ifdef NRF54L15_ENGA_XXAA +#if NRF_SECURE_UART_INSTANCE == 20 +#define NS_DRIVER_STDIO Driver_USART30 +#else +#define NS_DRIVER_STDIO Driver_USART20 +#endif +#else #define NS_DRIVER_STDIO Driver_USART0 +#endif /** * \brief Store the addresses of memory regions @@ -80,26 +106,19 @@ enum tfm_plat_err_t spu_init_cfg(void); * - grants Non-Secure access to nRF peripherals that are not Secure-only * - grants Non-Secure access to DDPI channels * - grants Non-Secure access to GPIO pins - * - enforces that the external domain is still at the HW reset value of non-secure and locking it + * - On nrf5340 enforces that the external domain is still at the HW reset value + * of non-secure and locking it * * \return Returns values as specified by the \ref tfm_plat_err_t */ enum tfm_plat_err_t spu_periph_init_cfg(void); /** - * \brief Restrict access to peripheral to secure - */ -void spu_periph_configure_to_secure(uint32_t periph_num); - -/** - * \brief Allow non-secure access to peripheral - */ -void spu_periph_configure_to_non_secure(uint32_t periph_num); - -/** - * \brief Clears SPU interrupt. + * \brief Configures memory permissions via the MPC. + * + * \return Returns values as specified by the \ref tfm_plat_err_t */ -void spu_clear_irq(void); +enum tfm_plat_err_t nrf_mpc_init_cfg(void); /** * \brief Configures SAU and IDAU. diff --git a/platform/ext/target/nordic_nrf/common/core/tfm_hal_isolation.c b/platform/ext/target/nordic_nrf/common/core/tfm_hal_isolation.c index 6c9633b3e..f35ef8825 100644 --- a/platform/ext/target/nordic_nrf/common/core/tfm_hal_isolation.c +++ b/platform/ext/target/nordic_nrf/common/core/tfm_hal_isolation.c @@ -50,9 +50,16 @@ enum tfm_hal_status_t tfm_hal_set_up_static_boundaries( /* Set up isolation boundaries between SPE and NSPE */ sau_and_idau_cfg(); +#if NRF_SPU_HAS_MEMORY if (spu_init_cfg() != TFM_PLAT_ERR_SUCCESS) { return TFM_HAL_ERROR_GENERIC; } +#else + /* If the SPU doesn't configure MEMORY on this platform then the NRF_MPC does */ + if (nrf_mpc_init_cfg() != TFM_PLAT_ERR_SUCCESS) { + return TFM_HAL_ERROR_GENERIC; + } +#endif if (spu_periph_init_cfg() != TFM_PLAT_ERR_SUCCESS) { return TFM_HAL_ERROR_GENERIC; @@ -124,7 +131,12 @@ tfm_hal_bind_boundary(const struct partition_load_info_t *p_ldinf, continue; } - spu_periph_configure_to_secure(plat_data_ptr->periph_start); +#ifdef NRF_SPU + spu_peripheral_config_secure(plat_data_ptr->periph_start, + SPU_LOCK_CONF_LOCKED); +#else + // TODO: NCSDK-22597: Support configuring peripherals as secure +#endif /* * Static boundaries are set. Set up MPU region for MMIO. diff --git a/platform/ext/target/nordic_nrf/common/core/tfm_hal_its_encryption_cracen.c b/platform/ext/target/nordic_nrf/common/core/tfm_hal_its_encryption_cracen.c new file mode 100644 index 000000000..074e3ad92 --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/core/tfm_hal_its_encryption_cracen.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "config_tfm.h" +#include "platform/include/tfm_hal_its_encryption.h" +#include "platform/include/tfm_hal_its.h" + +typedef uint64_t psa_drv_slot_number_t; +#include +#include + + +#define CHACHA20_KEY_SIZE 32 +#define TFM_ITS_AEAD_ALG PSA_ALG_CHACHA20_POLY1305 + + +/* Global encryption counter which resets per boot. The counter ensures that + * the nonce will not be identical for consecutive file writes during the same + * boot. + */ +static uint32_t g_enc_counter; + +/* The global nonce seed which is fetched once in every boot. The seed is used + * as part of the nonce and allows the platforms to diversify their nonces + * across resets. Note that the way that this seed is generated is platform + * specific, so the diversification is optional. + */ +static uint8_t g_enc_nonce_seed[TFM_ITS_ENC_NONCE_LENGTH - + sizeof(g_enc_counter)]; + +/* TFM_ITS_ENC_NONCE_LENGTH is configurable but this implementation expects + * the seed to be 8 bytes and the nonce length to be 12. + */ +#if TFM_ITS_ENC_NONCE_LENGTH != 12 +#error "This implementation only supports a ITS nonce of size 12" +#endif + +/* + * This implementation doesn't use monotonic counters, but therfore a 64 bit + * seed combined with a counter, that gets reset on each reboot. + * This still has the risk of getting a collision on the seed resulting in + * nonce's beeing the same after a reboot. + * It would still need 3.3x10^9 resets to get a collision with a probability of + * 0.25. + */ +enum tfm_hal_status_t tfm_hal_its_aead_generate_nonce(uint8_t *nonce, + const size_t nonce_size) +{ + if(nonce == NULL){ + return TFM_HAL_ERROR_INVALID_INPUT; + } + + if(nonce_size < sizeof(g_enc_nonce_seed) + sizeof(g_enc_counter)){ + return TFM_HAL_ERROR_INVALID_INPUT; + } + + /* To avoid wrap-around of the g_enc_counter and subsequent re-use of the + * nonce we check the counter value for its max value + */ + if(g_enc_counter == UINT32_MAX) { + return TFM_HAL_ERROR_GENERIC; + } + + if (g_enc_counter == 0) { + psa_status_t status = cracen_get_random(NULL, g_enc_nonce_seed, sizeof(g_enc_nonce_seed)); + if (status != PSA_SUCCESS) { + return TFM_HAL_ERROR_GENERIC; + } + } + + memcpy(nonce, g_enc_nonce_seed, sizeof(g_enc_nonce_seed)); + memcpy(nonce + sizeof(g_enc_nonce_seed), + &g_enc_counter, + sizeof(g_enc_counter)); + + g_enc_counter++; + + return TFM_HAL_SUCCESS; +} + +static bool ctx_is_valid(struct tfm_hal_its_auth_crypt_ctx *ctx) +{ + bool ret; + + if (ctx == NULL) { + return false; + } + + ret = (ctx->deriv_label == NULL && ctx->deriv_label_size != 0) || + (ctx->aad == NULL && ctx->add_size != 0) || + (ctx->nonce == NULL && ctx->nonce_size != 0); + + return !ret; +} + +psa_status_t tfm_hal_its_get_aead(struct tfm_hal_its_auth_crypt_ctx *ctx, + const uint8_t *input, + const size_t input_size, + uint8_t *output, + const size_t output_size, + uint8_t *tag, + const size_t tag_size, + bool encrypt) +{ + psa_status_t status; + uint8_t key_out[CHACHA20_KEY_SIZE]; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + cracen_aead_operation_t operation = {0}; + size_t out_length; + size_t tag_length = PSA_AEAD_TAG_LENGTH(PSA_KEY_TYPE_CHACHA20, + PSA_BYTES_TO_BITS(CHACHA20_KEY_SIZE), + TFM_ITS_AEAD_ALG); + + if (!ctx_is_valid(ctx) || tag == NULL) { + return TFM_HAL_ERROR_INVALID_INPUT; + } + + if(tag_size < tag_length){ + return TFM_HAL_ERROR_INVALID_INPUT; + } + + if (encrypt && (output_size < PSA_AEAD_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_CHACHA20, + TFM_ITS_AEAD_ALG, + input_size))){ + return TFM_HAL_ERROR_INVALID_INPUT; + } + + status = hw_unique_key_derive_key(HUK_KEYSLOT_MKEK, NULL, 0, ctx->deriv_label, ctx->deriv_label_size, key_out, sizeof(key_out)); + if (status != HW_UNIQUE_KEY_SUCCESS) { + return TFM_HAL_ERROR_GENERIC; + } + + psa_set_key_usage_flags(&attributes, (PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT)); + psa_set_key_algorithm(&attributes, TFM_ITS_AEAD_ALG); + psa_set_key_type(&attributes, PSA_KEY_TYPE_CHACHA20); + psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(CHACHA20_KEY_SIZE)); + + if (encrypt) { + status = cracen_aead_encrypt_setup(&operation, &attributes, key_out, sizeof(key_out), TFM_ITS_AEAD_ALG); + } else { + status = cracen_aead_decrypt_setup(&operation, &attributes, key_out, sizeof(key_out), TFM_ITS_AEAD_ALG); + } + + if (status != PSA_SUCCESS) { + return status; + } + + status = cracen_aead_set_nonce(&operation, ctx->nonce, ctx->nonce_size); + if (status != PSA_SUCCESS) { + return status; + } + + status = cracen_aead_update_ad(&operation, ctx->aad, ctx->add_size); + if (status != PSA_SUCCESS) { + return status; + } + + status = cracen_aead_update(&operation, input, input_size, output, output_size, &out_length); + if (status != PSA_SUCCESS) { + return status; + } + + if (encrypt) { + status = cracen_aead_finish(&operation, output + out_length, output_size - out_length, &out_length, tag, tag_size, &tag_length); + } else { + status = cracen_aead_verify(&operation, output + out_length, output_size - out_length, &out_length , tag, tag_size); + } + + return status; +} + +enum tfm_hal_status_t tfm_hal_its_aead_encrypt(struct tfm_hal_its_auth_crypt_ctx *ctx, + const uint8_t *plaintext, + const size_t plaintext_size, + uint8_t *ciphertext, + const size_t ciphertext_size, + uint8_t *tag, + const size_t tag_size) +{ + psa_status_t status = tfm_hal_its_get_aead(ctx, + plaintext, + plaintext_size, + ciphertext, + ciphertext_size, + tag, + tag_size, + true); + if (status != PSA_SUCCESS) { + return TFM_HAL_ERROR_GENERIC; + } + + return TFM_HAL_SUCCESS; +} + +enum tfm_hal_status_t tfm_hal_its_aead_decrypt(struct tfm_hal_its_auth_crypt_ctx *ctx, + const uint8_t *ciphertext, + const size_t ciphertext_size, + uint8_t *tag, + const size_t tag_size, + uint8_t *plaintext, + const size_t plaintext_size) +{ + psa_status_t status = tfm_hal_its_get_aead(ctx, + ciphertext, + ciphertext_size, + plaintext, + plaintext_size, + tag, + tag_size, + false); + + if (status != PSA_SUCCESS) { + return TFM_HAL_ERROR_GENERIC; + } + + return TFM_HAL_SUCCESS; +} diff --git a/platform/ext/target/nordic_nrf/common/core/tfm_hal_platform_common.c b/platform/ext/target/nordic_nrf/common/core/tfm_hal_platform_common.c index 51026e3e2..423602fbc 100644 --- a/platform/ext/target/nordic_nrf/common/core/tfm_hal_platform_common.c +++ b/platform/ext/target/nordic_nrf/common/core/tfm_hal_platform_common.c @@ -11,6 +11,8 @@ #include "tfm_plat_defs.h" #include "uart_stdout.h" +int init_tampc(void); + extern const struct memory_region_limits memory_regions; enum tfm_hal_status_t tfm_hal_platform_common_init(void) { @@ -46,6 +48,12 @@ enum tfm_hal_status_t tfm_hal_platform_common_init(void) return TFM_HAL_ERROR_GENERIC; } + /***/ + plat_err = init_tampc(); + if (plat_err != TFM_PLAT_ERR_SUCCESS) { + return TFM_HAL_ERROR_GENERIC; + } + return TFM_HAL_SUCCESS; } diff --git a/platform/ext/target/nordic_nrf/common/nrf5340/CMakeLists.txt b/platform/ext/target/nordic_nrf/common/nrf5340/CMakeLists.txt index 6cfcf87c6..b15178ec6 100644 --- a/platform/ext/target/nordic_nrf/common/nrf5340/CMakeLists.txt +++ b/platform/ext/target/nordic_nrf/common/nrf5340/CMakeLists.txt @@ -9,23 +9,9 @@ cmake_policy(SET CMP0076 NEW) set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(target nrf5340) add_subdirectory(../core nrf_common) -#========================= Platform common defs ===============================# - -# Specify the location of platform specific build dependencies. -target_sources(tfm_s - PRIVATE - $<$:${CMAKE_CURRENT_SOURCE_DIR}/gcc/startup_nrf5340.c> -) - -if(BL2) - target_sources(bl2 - PRIVATE - $<$:${CMAKE_CURRENT_SOURCE_DIR}/gcc/startup_nrf5340.c> - ) -endif() - #========================= Platform Secure ====================================# target_include_directories(platform_s @@ -70,7 +56,6 @@ target_sources(tfm_spm #========================= Files for building NS side platform ================# install(FILES nrfx_config_nrf5340_application.h - target_cfg.h ns/CMakeLists.txt config.cmake cpuarch.cmake @@ -78,7 +63,6 @@ install(FILES nrfx_config_nrf5340_application.h ) install(DIRECTORY partition - gcc tests DESTINATION ${INSTALL_PLATFORM_NS_DIR}/common/nrf5340 ) diff --git a/platform/ext/target/nordic_nrf/common/nrf5340/ns/CMakeLists.txt b/platform/ext/target/nordic_nrf/common/nrf5340/ns/CMakeLists.txt index 8b8603d35..52593d125 100644 --- a/platform/ext/target/nordic_nrf/common/nrf5340/ns/CMakeLists.txt +++ b/platform/ext/target/nordic_nrf/common/nrf5340/ns/CMakeLists.txt @@ -8,13 +8,9 @@ cmake_policy(SET CMP0076 NEW) set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(target nrf5340) add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../core nrf_common) -target_sources(tfm_ns - PRIVATE - $<$:${CMAKE_CURRENT_LIST_DIR}/gcc/startup_nrf5340.c> -) - target_include_directories(platform_ns PUBLIC ${CMAKE_CURRENT_LIST_DIR} diff --git a/platform/ext/target/nordic_nrf/common/nrf54l15/CMakeLists.txt b/platform/ext/target/nordic_nrf/common/nrf54l15/CMakeLists.txt new file mode 100644 index 000000000..7eb27b019 --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/nrf54l15/CMakeLists.txt @@ -0,0 +1,52 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2020-2022, Arm Limited. All rights reserved. +# Copyright (c) 2020, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +cmake_policy(SET CMP0076 NEW) +set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}) + +set(target nrf54l15) +add_subdirectory(../core nrf_common) + +#========================= Platform Secure ====================================# + +target_include_directories(platform_s + PUBLIC + . +) + +target_sources(platform_s + PRIVATE + ${HAL_NORDIC_PATH}/nrfx/mdk/system_nrf54l.c + tampc.c +) + +target_compile_definitions(platform_s + PUBLIC + NRF_SKIP_FICR_NS_COPY_TO_RAM +) + +#========================= tfm_spm ============================================# + +target_sources(tfm_spm + PRIVATE + $<$,$>:${CMAKE_CURRENT_SOURCE_DIR}/tfm_interrupts.c> +) + +#========================= Files for building NS side platform ================# + +install(FILES nrfx_config_nrf54l15_application.h + ns/CMakeLists.txt + config.cmake + cpuarch.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR}/common/nrf54l15 +) + +install(DIRECTORY partition + tests + DESTINATION ${INSTALL_PLATFORM_NS_DIR}/common/nrf54l15 +) diff --git a/platform/ext/target/nordic_nrf/common/nrf54l15/config.cmake b/platform/ext/target/nordic_nrf/common/nrf54l15/config.cmake new file mode 100644 index 000000000..01426be79 --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/nrf54l15/config.cmake @@ -0,0 +1,14 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2020, Nordic Semiconductor ASA. +# Copyright (c) 2020-2023, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +include(${PLATFORM_PATH}/common/core/config.cmake) + +set(SECURE_UART1 ON CACHE BOOL "Enable secure UART1") +set(NRF_NS_STORAGE OFF CACHE BOOL "Enable non-secure storage partition") +set(BL2 OFF CACHE BOOL "Whether to build BL2") +set(NRF_NS_SECONDARY OFF CACHE BOOL "Enable non-secure secondary partition") diff --git a/platform/ext/target/nordic_nrf/common/nrf54l15/cpuarch.cmake b/platform/ext/target/nordic_nrf/common/nrf54l15/cpuarch.cmake new file mode 100644 index 000000000..18c7fa920 --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/nrf54l15/cpuarch.cmake @@ -0,0 +1,23 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# cpuarch.cmake is used to set things that related to the platform that are both +# immutable and global, which is to say they should apply to any kind of project +# that uses this platform. In practice this is normally compiler definitions and +# variables related to hardware. + +# Set architecture and CPU +set(TFM_SYSTEM_PROCESSOR cortex-m33) +set(TFM_SYSTEM_ARCHITECTURE armv8-m.main) +set(CONFIG_TFM_FP_ARCH "fpv5-sp-d16") + +add_compile_definitions( + NRF54L15_ENGA_XXAA # Required by nrf.h + NRF_APPLICATION + # SKIP configuring the SAU from the MDK as it does not fit TF-M's needs + NRF_SKIP_SAU_CONFIGURATION + NRF_SKIP_FICR_NS_COPY_TO_RAM +) diff --git a/platform/ext/target/nordic_nrf/common/nrf54l15/mmio_defs.h b/platform/ext/target/nordic_nrf/common/nrf54l15/mmio_defs.h new file mode 100644 index 000000000..f45682cc2 --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/nrf54l15/mmio_defs.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + * + */ + +#ifndef __MMIO_DEFS_H__ +#define __MMIO_DEFS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "tfm_peripherals_def.h" +#include "tfm_peripherals_config.h" +#include "handle_attr.h" + +/* Allowed named MMIO of this platform */ +const uintptr_t partition_named_mmio_list[] = { + /* TODO: NCSDK-22597: Populate this list */ +#if TFM_PERIPHERAL_TIMER00_SECURE + (uintptr_t)TFM_PERIPHERAL_TIMER00, +#endif +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __MMIO_DEFS_H__ */ diff --git a/platform/ext/target/nordic_nrf/common/nrf54l15/nrfx_config_nrf54l15_application.h b/platform/ext/target/nordic_nrf/common/nrf54l15/nrfx_config_nrf54l15_application.h new file mode 100644 index 000000000..814f022b4 --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/nrf54l15/nrfx_config_nrf54l15_application.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef NRFX_CONFIG_NRF54L15_APPLICATION_H__ +#define NRFX_CONFIG_NRF54L15_APPLICATION_H__ + +#ifndef NRFX_CONFIG_H__ +#error "This file should not be included directly. Include nrfx_config.h instead." +#endif + +/** + * @brief NRFX_DEFAULT_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_DEFAULT_IRQ_PRIORITY +#define NRFX_DEFAULT_IRQ_PRIORITY 7 +#endif + +/** + * @brief NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_RRAMC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RRAMC_ENABLED +#define NRFX_RRAMC_ENABLED 0 +#endif + +/** + * @brief NRFX_RRAMC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_RRAMC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_RRAMC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_RRAMC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RRAMC_CONFIG_LOG_ENABLED +#define NRFX_RRAMC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_RRAMC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_RRAMC_CONFIG_LOG_LEVEL +#define NRFX_RRAMC_CONFIG_LOG_LEVEL 3 +#endif + +#endif // NRFX_CONFIG_NRF54L15_APPLICATION_H__ diff --git a/platform/ext/target/nordic_nrf/common/nrf54l15/ns/CMakeLists.txt b/platform/ext/target/nordic_nrf/common/nrf54l15/ns/CMakeLists.txt new file mode 100644 index 000000000..541b039f7 --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/nrf54l15/ns/CMakeLists.txt @@ -0,0 +1,28 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2023, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +cmake_policy(SET CMP0076 NEW) +set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}) + +set(target nrf54l15) +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../core nrf_common) + +target_include_directories(platform_ns + PUBLIC + ${CMAKE_CURRENT_LIST_DIR} +) + +target_sources(platform_ns + PRIVATE + ${HAL_NORDIC_PATH}/nrfx/mdk/system_nrf54l.c +) + +target_compile_definitions(platform_ns + PUBLIC + NRF_TRUSTZONE_NONSECURE + DOMAIN_NS=1 +) diff --git a/platform/ext/target/nordic_nrf/common/nrf54l15/partition/flash_layout.h b/platform/ext/target/nordic_nrf/common/nrf54l15/partition/flash_layout.h new file mode 100644 index 000000000..08b90647e --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/nrf54l15/partition/flash_layout.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018-2022 Arm Limited. All rights reserved. + * Copyright (c) 2020 Nordic Semiconductor ASA. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __FLASH_LAYOUT_H__ +#define __FLASH_LAYOUT_H__ + +#error "not supported yet" + +#endif /* __FLASH_LAYOUT_H__ */ diff --git a/platform/ext/target/nordic_nrf/common/nrf54l15/partition/region_defs.h b/platform/ext/target/nordic_nrf/common/nrf54l15/partition/region_defs.h new file mode 100755 index 000000000..212106c96 --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/nrf54l15/partition/region_defs.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2017-2022 Arm Limited. All rights reserved. + * Copyright (c) 2020 Nordic Semiconductor ASA. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __REGION_DEFS_H__ +#define __REGION_DEFS_H__ + +#include "flash_layout.h" + +#endif /* __REGION_DEFS_H__ */ diff --git a/platform/ext/target/nordic_nrf/common/nrf54l15/tampc.c b/platform/ext/target/nordic_nrf/common/nrf54l15/tampc.c new file mode 100644 index 000000000..d5337c8ba --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/nrf54l15/tampc.c @@ -0,0 +1,77 @@ + +/*** + + +*/ + +#include "nrf54l15_enga_application.h" +#include "nrf54l15_enga_global.h" +#include "nrf54l15_enga_types.h" +#include "tfm_hal_platform.h" +#include "tfm_plat_defs.h" +#include +#include + +bool boot_reason_sectamper; + +#define RESET_BY_PERIPHERAL false +#define TAMPER_EVENT_HANDLER tfm_core_panic + +#define TAMPC_REASON (((volatile uint32_t *)0x4010E600)[0]) +void tampc_enable(void); +void tampc_disable(void); + +int init_tampc(void) { + + if (TAMPC_REASON & NRFX_RESET_REASON_SECTAMPER_MASK) { + TAMPC_REASON = NRFX_RESET_REASON_SECTAMPER_MASK; + boot_reason_sectamper = true; + } + + nrf_tampc_event_clear(NRF_TAMPC, NRF_TAMPC_EVENT_TAMPER); + nrf_tampc_event_clear(NRF_TAMPC, NRF_TAMPC_EVENT_WRITE_ERROR); + + tampc_enable(); + nrf_tampc_int_enable(NRF_TAMPC, NRF_TAMPC_ALL_INTS_MASK); + + nrf_tampc_protector_ctrl_value_set(NRF_TAMPC, NRF_TAMPC_PROTECT_RESETEN_INT, + RESET_BY_PERIPHERAL); + + NVIC_ClearPendingIRQ(TAMPC_IRQn); + NVIC_ClearTargetState(TAMPC_IRQn); + NVIC_EnableIRQ(TAMPC_IRQn); + + return TFM_PLAT_ERR_SUCCESS; +} + +void tampc_enable(void) { + nrf_tampc_protector_ctrl_value_set( + NRF_TAMPC, NRF_TAMPC_PROTECT_GLITCH_DOMAIN_FAST, true); + nrf_tampc_protector_ctrl_value_set( + NRF_TAMPC, NRF_TAMPC_PROTECT_GLITCH_DOMAIN_SLOW, true); +} + +void tampc_disable(void) { + nrf_tampc_protector_ctrl_value_set( + NRF_TAMPC, NRF_TAMPC_PROTECT_GLITCH_DOMAIN_FAST, false); + nrf_tampc_protector_ctrl_value_set( + NRF_TAMPC, NRF_TAMPC_PROTECT_GLITCH_DOMAIN_SLOW, false); +} + +void TAMPC_Handler(void) { + SPMLOG_ERRMSG("TAMPC Exception:\r\n"); + + if (nrf_tampc_event_check(NRF_TAMPC, NRF_TAMPC_EVENT_WRITE_ERROR)) { + SPMLOG_ERRMSG("\tWrite error.\r\n"); + nrf_tampc_event_clear(NRF_TAMPC, NRF_TAMPC_EVENT_WRITE_ERROR); + NVIC_ClearPendingIRQ(TAMPC_IRQn); + tfm_core_panic(); + } + + if (nrf_tampc_event_check(NRF_TAMPC, NRF_TAMPC_EVENT_TAMPER)) { + SPMLOG_ERRMSG("\tTamper event.\r\n"); + nrf_tampc_event_clear(NRF_TAMPC, NRF_TAMPC_EVENT_TAMPER); + NVIC_ClearPendingIRQ(TAMPC_IRQn); + TAMPER_EVENT_HANDLER(); + } +} diff --git a/platform/ext/target/nordic_nrf/common/nrf54l15/tests/psa_arch_tests_config.cmake b/platform/ext/target/nordic_nrf/common/nrf54l15/tests/psa_arch_tests_config.cmake new file mode 100644 index 000000000..88586c115 --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/nrf54l15/tests/psa_arch_tests_config.cmake @@ -0,0 +1,9 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2023, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +# Platform-specific configurations +set(PSA_API_TEST_TARGET "nrf54l15") diff --git a/platform/ext/target/nordic_nrf/common/nrf54l15/tfm_peripherals_def.h b/platform/ext/target/nordic_nrf/common/nrf54l15/tfm_peripherals_def.h new file mode 100644 index 000000000..42bdb35bd --- /dev/null +++ b/platform/ext/target/nordic_nrf/common/nrf54l15/tfm_peripherals_def.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + * + */ + +#ifndef __TFM_PERIPHERALS_DEF_H__ +#define __TFM_PERIPHERALS_DEF_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + /* TODO: NCSDK-22597: Define peripherals */ + +#include + +#define TFM_TIMER0_IRQ (NRFX_IRQ_NUMBER_GET(NRF_TIMER0)) + +extern struct platform_data_t tfm_peripheral_timer0; + +#define TFM_PERIPHERAL_TIMER0 (&tfm_peripheral_timer0) + +/* + * Quantized default IRQ priority, the value is: + * (Number of configurable priority) / 4: (1UL << __NVIC_PRIO_BITS) / 4 + */ +#define DEFAULT_IRQ_PRIORITY (1UL << (__NVIC_PRIO_BITS - 2)) + +#define TFM_PERIPHERAL_STD_UART TFM_PERIPHERAL_UARTE1 + +#ifdef PSA_API_TEST_IPC +/* see other platforms when supporting this */ +#error "Not supported yet" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_PERIPHERALS_DEF_H__ */ diff --git a/platform/ext/target/nordic_nrf/common/nrf91/CMakeLists.txt b/platform/ext/target/nordic_nrf/common/nrf91/CMakeLists.txt index 3fffd49f7..31898e64c 100644 --- a/platform/ext/target/nordic_nrf/common/nrf91/CMakeLists.txt +++ b/platform/ext/target/nordic_nrf/common/nrf91/CMakeLists.txt @@ -9,23 +9,9 @@ cmake_policy(SET CMP0076 NEW) set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(target nrf91) add_subdirectory(../core nrf_common) -#========================= Platform common defs ===============================# - -# Specify the location of platform specific build dependencies. -target_sources(tfm_s - PRIVATE - $<$:${CMAKE_CURRENT_SOURCE_DIR}/gcc/startup_nrf91.c> -) - -if(BL2) - target_sources(bl2 - PRIVATE - $<$:${CMAKE_CURRENT_SOURCE_DIR}/gcc/startup_nrf91.c> - ) -endif() - #========================= Platform Secure ====================================# target_include_directories(platform_s @@ -72,14 +58,12 @@ target_sources(tfm_spm #========================= Files for building NS side platform ================# install(FILES nrfx_config_nrf91.h - target_cfg.h ns/CMakeLists.txt config.cmake DESTINATION ${INSTALL_PLATFORM_NS_DIR}/common/nrf91 ) install(DIRECTORY partition - gcc tests DESTINATION ${INSTALL_PLATFORM_NS_DIR}/common/nrf91 ) diff --git a/platform/ext/target/nordic_nrf/common/nrf91/nrfx_config_nrf91.h b/platform/ext/target/nordic_nrf/common/nrf91/nrfx_config_nrf91.h index 8519278be..e95f3920a 100644 --- a/platform/ext/target/nordic_nrf/common/nrf91/nrfx_config_nrf91.h +++ b/platform/ext/target/nordic_nrf/common/nrf91/nrfx_config_nrf91.h @@ -36,6 +36,17 @@ #error "This file should not be included directly. Include nrfx_config.h instead." #endif +/* + * The MDK for nRF9120 used in the nRF9161 target doesn't define the Secure FPU + * as it doesn't exist, but for other platforms like the 9160 it has a dummy + * define. + * Therefore we define it here manually until it is fixed in the MDK. + * See: NCSDK-23046 + */ +#ifdef NRF9120_XXAA +#define NRF_FPU_S 1 +#endif + #define NRF_CLOCK NRF_PERIPH(NRF_CLOCK) #define NRF_DPPIC NRF_PERIPH(NRF_DPPIC) #define NRF_EGU0 NRF_PERIPH(NRF_EGU0) diff --git a/platform/ext/target/nordic_nrf/common/nrf91/ns/CMakeLists.txt b/platform/ext/target/nordic_nrf/common/nrf91/ns/CMakeLists.txt index 5a430489c..290d7f4c5 100644 --- a/platform/ext/target/nordic_nrf/common/nrf91/ns/CMakeLists.txt +++ b/platform/ext/target/nordic_nrf/common/nrf91/ns/CMakeLists.txt @@ -9,15 +9,9 @@ cmake_policy(SET CMP0076 NEW) set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(target nrf91) add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../core nrf_common) -#========================= Platform common defs ===============================# - -target_sources(tfm_ns - PRIVATE - $<$:${CMAKE_CURRENT_SOURCE_DIR}/gcc/startup_nrf91.c> -) - #========================= Platform Non-Secure ================================# target_include_directories(platform_ns diff --git a/platform/ext/target/nordic_nrf/common/nrf91/target_cfg.h b/platform/ext/target/nordic_nrf/common/nrf91/target_cfg.h deleted file mode 100644 index 07383324f..000000000 --- a/platform/ext/target/nordic_nrf/common/nrf91/target_cfg.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2017-2019 Arm Limited - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __TARGET_CFG_H__ -#define __TARGET_CFG_H__ - -/** - * \file target_cfg.h - * \brief nRF9160 target configuration header - * - * This file contains the platform specific functions to configure - * the Cortex-M33 core, memory permissions and security attribution - * on the nRF9160 platform. - * - * Memory permissions and security attribution are configured via - * the System Protection Unit (SPU) which is the nRF specific Implementation - * Defined Attribution Unit (IDAU). - */ - -#include "tfm_plat_defs.h" -#include "region_defs.h" - -#define TFM_DRIVER_STDIO Driver_USART1 -#define NS_DRIVER_STDIO Driver_USART0 - -/** - * \brief Store the addresses of memory regions - */ -struct memory_region_limits { - uint32_t non_secure_code_start; - uint32_t non_secure_partition_base; - uint32_t non_secure_partition_limit; - uint32_t veneer_base; - uint32_t veneer_limit; -#ifdef NRF_NS_SECONDARY - uint32_t secondary_partition_base; - uint32_t secondary_partition_limit; -#endif /* NRF_NS_SECONDARY */ -#ifdef NRF_NS_STORAGE_PARTITION_START - uint32_t non_secure_storage_partition_base; - uint32_t non_secure_storage_partition_limit; -#endif /* NRF_NS_STORAGE_PARTITION_START */ -}; - -/** - * \brief Holds the data necessary to do isolation for a specific peripheral. - */ -struct platform_data_t -{ - uint32_t periph_start; - uint32_t periph_limit; -}; - -/** - * \brief Configures memory permissions via the System Protection Unit. - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t spu_init_cfg(void); - -/** - * \brief Configures peripheral permissions via the System Protection Unit. - * - * The function does the following: - * - grants Non-Secure access to nRF peripherals that are not Secure-only - * - grants Non-Secure access to DDPI channels - * - grants Non-Secure access to GPIO pins - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t spu_periph_init_cfg(void); - -/** - * \brief Restrict access to peripheral to secure - */ -void spu_periph_configure_to_secure(uint32_t periph_num); - -/** - * \brief Allow non-secure access to peripheral - */ -void spu_periph_configure_to_non_secure(uint32_t periph_num); - -/** - * \brief Clears SPU interrupt. - */ -void spu_clear_irq(void); - -/** - * \brief Configures SAU and IDAU. - */ -void sau_and_idau_cfg(void); - -/** - * \brief Enables the fault handlers and sets priorities. - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t enable_fault_handlers(void); - -/** - * \brief Configures the system reset request properties - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t system_reset_cfg(void); - -/** - * \brief Configures the system debug properties. - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t init_debug(void); - -/** - * \brief Configures all external interrupts to target the - * NS state, apart for the ones associated to secure - * peripherals (plus SPU) - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t nvic_interrupt_target_state_cfg(void); - -/** - * \brief This function enable the interrupts associated - * to the secure peripherals (plus the isolation boundary violation - * interrupts) - * - * \return Returns values as specified by the \ref tfm_plat_err_t - */ -enum tfm_plat_err_t nvic_interrupt_enable(void); - -#endif /* __TARGET_CFG_H__ */ diff --git a/platform/ext/target/nordic_nrf/nrf5340dk_nrf5340_cpuapp/services/include/tfm_read_ranges.h b/platform/ext/target/nordic_nrf/nrf5340dk_nrf5340_cpuapp/services/include/tfm_platform_user_memory_ranges.h similarity index 72% rename from platform/ext/target/nordic_nrf/nrf5340dk_nrf5340_cpuapp/services/include/tfm_read_ranges.h rename to platform/ext/target/nordic_nrf/nrf5340dk_nrf5340_cpuapp/services/include/tfm_platform_user_memory_ranges.h index 83cb01431..be9c72f3b 100644 --- a/platform/ext/target/nordic_nrf/nrf5340dk_nrf5340_cpuapp/services/include/tfm_read_ranges.h +++ b/platform/ext/target/nordic_nrf/nrf5340dk_nrf5340_cpuapp/services/include/tfm_platform_user_memory_ranges.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef TFM_READ_RANGES_H__ -#define TFM_READ_RANGES_H__ +#ifndef TFM_PLATFORM_USER_MEMORY_RANGES_H__ +#define TFM_PLATFORM_USER_MEMORY_RANGES_H__ #include @@ -33,4 +33,9 @@ static const struct tfm_read_service_range ranges[] = { { .start = FICR_XOSC32MTRIM_ADDR, .size = FICR_XOSC32MTRIM_SIZE }, }; -#endif /* TFM_READ_RANGES_H__ */ +static const struct tfm_write32_service_address tfm_write32_service_addresses[] = { + /* This is a dummy value because this table cannot be empty */ + {.addr = 0xFFFFFFFF, .mask = 0x0, .allowed_values = NULL, .allowed_values_array_size = 0}, +}; + +#endif /* TFM_PLATFORM_USER_MEMORY_RANGES_H__ */ diff --git a/platform/ext/target/nordic_nrf/nrf5340dk_nrf5340_cpuapp/tfm_peripherals_config.h b/platform/ext/target/nordic_nrf/nrf5340dk_nrf5340_cpuapp/tfm_peripherals_config.h index 7a8885712..18a044094 100644 --- a/platform/ext/target/nordic_nrf/nrf5340dk_nrf5340_cpuapp/tfm_peripherals_config.h +++ b/platform/ext/target/nordic_nrf/nrf5340dk_nrf5340_cpuapp/tfm_peripherals_config.h @@ -13,8 +13,12 @@ extern "C" { #endif #ifdef SECURE_UART1 +#if NRF_SECURE_UART_INSTANCE == 0 +#define TFM_PERIPHERAL_UARTE0_SECURE 1 +#elif NRF_SECURE_UART_INSTANCE == 1 #define TFM_PERIPHERAL_UARTE1_SECURE 1 #endif +#endif #if TFM_PARTITION_SLIH_TEST || TFM_PARTITION_FLIH_TEST #define TFM_PERIPHERAL_TIMER0_SECURE 1 diff --git a/platform/ext/target/nordic_nrf/nrf54l15dk_nrf54l15_cpuapp/ns/CMakeLists.txt b/platform/ext/target/nordic_nrf/nrf54l15dk_nrf54l15_cpuapp/ns/CMakeLists.txt new file mode 100644 index 000000000..5cd4273e4 --- /dev/null +++ b/platform/ext/target/nordic_nrf/nrf54l15dk_nrf54l15_cpuapp/ns/CMakeLists.txt @@ -0,0 +1,31 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2023, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +cmake_policy(SET CMP0076 NEW) +set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(NRF_BOARD_SELECTED True) + +add_library(platform_ns STATIC) + +# Get the value of HAL_NORDIC_PATH +include(${CMAKE_CURRENT_LIST_DIR}/common/core/config_nordic_nrf_spe.cmake) +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/common/nrf54l15 nrf54l15) + +target_include_directories(platform_ns + PUBLIC + ${CMAKE_CURRENT_LIST_DIR} +) + +target_link_libraries(platform_ns + PUBLIC + platform_region_defs +) + +target_include_directories(platform_region_defs + INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/common/nrf54l15/partition +) diff --git a/platform/ext/target/nordic_nrf/nrf54l15dk_nrf54l15_cpuapp/ns/cpuarch_ns.cmake b/platform/ext/target/nordic_nrf/nrf54l15dk_nrf54l15_cpuapp/ns/cpuarch_ns.cmake new file mode 100644 index 000000000..25f91fb54 --- /dev/null +++ b/platform/ext/target/nordic_nrf/nrf54l15dk_nrf54l15_cpuapp/ns/cpuarch_ns.cmake @@ -0,0 +1,10 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: BSD-3-Clause +#------------------------------------------------------------------------------- + +set(PLATFORM_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(PLATFORM_PATH ${CMAKE_CURRENT_LIST_DIR}) + +include(${CMAKE_CURRENT_LIST_DIR}/common/nrf54l15/cpuarch.cmake) diff --git a/platform/ext/target/nordic_nrf/nrf54l15dk_nrf54l15_cpuapp/tests/psa_arch_tests_config.cmake b/platform/ext/target/nordic_nrf/nrf54l15dk_nrf54l15_cpuapp/tests/psa_arch_tests_config.cmake new file mode 100644 index 000000000..327e36c66 --- /dev/null +++ b/platform/ext/target/nordic_nrf/nrf54l15dk_nrf54l15_cpuapp/tests/psa_arch_tests_config.cmake @@ -0,0 +1,8 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2023, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +include(${PLATFORM_PATH}/common/nrf54l15/tests/psa_arch_tests_config.cmake) diff --git a/platform/ext/target/nordic_nrf/nrf54l15dk_nrf54l15_cpuapp/tests/tfm_tests_config.cmake b/platform/ext/target/nordic_nrf/nrf54l15dk_nrf54l15_cpuapp/tests/tfm_tests_config.cmake new file mode 100644 index 000000000..619f1f92c --- /dev/null +++ b/platform/ext/target/nordic_nrf/nrf54l15dk_nrf54l15_cpuapp/tests/tfm_tests_config.cmake @@ -0,0 +1,8 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2023, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +include(${PLATFORM_PATH}/common/core/tests/tfm_tests_config.cmake) diff --git a/platform/ext/target/nordic_nrf/nrf9160dk_nrf9160/services/include/tfm_read_ranges.h b/platform/ext/target/nordic_nrf/nrf9160dk_nrf9160/services/include/tfm_platform_user_memory_ranges.h similarity index 62% rename from platform/ext/target/nordic_nrf/nrf9160dk_nrf9160/services/include/tfm_read_ranges.h rename to platform/ext/target/nordic_nrf/nrf9160dk_nrf9160/services/include/tfm_platform_user_memory_ranges.h index c5e1b09e6..f1419bd6a 100644 --- a/platform/ext/target/nordic_nrf/nrf9160dk_nrf9160/services/include/tfm_read_ranges.h +++ b/platform/ext/target/nordic_nrf/nrf9160dk_nrf9160/services/include/tfm_platform_user_memory_ranges.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef TFM_READ_RANGES_H__ -#define TFM_READ_RANGES_H__ +#ifndef TFM_PLATFORM_USER_MEMORY_RANGES_H__ +#define TFM_PLATFORM_USER_MEMORY_RANGES_H__ #include @@ -25,4 +25,9 @@ static const struct tfm_read_service_range ranges[] = { { .start = FICR_RESTRICTED_ADDR, .size = FICR_RESTRICTED_SIZE }, }; -#endif /* TFM_READ_RANGES_H__ */ +static const struct tfm_write32_service_address tfm_write32_service_addresses[] = { + /* This is a dummy value because this table cannot be empty */ + {.addr = 0xFFFFFFFF, .mask = 0x0, .allowed_values = NULL, .allowed_values_array_size = 0}, +}; + +#endif /* TFM_PLATFORM_USER_MEMORY_RANGES_H__ */ diff --git a/platform/ext/target/nordic_nrf/nrf9160dk_nrf9160/tfm_peripherals_config.h b/platform/ext/target/nordic_nrf/nrf9160dk_nrf9160/tfm_peripherals_config.h index 80f8540c5..cc980516e 100644 --- a/platform/ext/target/nordic_nrf/nrf9160dk_nrf9160/tfm_peripherals_config.h +++ b/platform/ext/target/nordic_nrf/nrf9160dk_nrf9160/tfm_peripherals_config.h @@ -13,8 +13,12 @@ extern "C" { #endif #ifdef SECURE_UART1 +#if NRF_SECURE_UART_INSTANCE == 0 +#define TFM_PERIPHERAL_UARTE0_SECURE 1 +#elif NRF_SECURE_UART_INSTANCE == 1 #define TFM_PERIPHERAL_UARTE1_SECURE 1 #endif +#endif #if TFM_PARTITION_SLIH_TEST || TFM_PARTITION_FLIH_TEST #define TFM_PERIPHERAL_TIMER0_SECURE 1 diff --git a/platform/ext/target/nordic_nrf/nrf9161dk_nrf9161/services/include/tfm_read_ranges.h b/platform/ext/target/nordic_nrf/nrf9161dk_nrf9161/services/include/tfm_platform_user_memory_ranges.h similarity index 62% rename from platform/ext/target/nordic_nrf/nrf9161dk_nrf9161/services/include/tfm_read_ranges.h rename to platform/ext/target/nordic_nrf/nrf9161dk_nrf9161/services/include/tfm_platform_user_memory_ranges.h index 2b159f721..61c8fd0e2 100644 --- a/platform/ext/target/nordic_nrf/nrf9161dk_nrf9161/services/include/tfm_read_ranges.h +++ b/platform/ext/target/nordic_nrf/nrf9161dk_nrf9161/services/include/tfm_platform_user_memory_ranges.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef TFM_READ_RANGES_H__ -#define TFM_READ_RANGES_H__ +#ifndef TFM_PLATFORM_USER_MEMORY_RANGES_H__ +#define TFM_PLATFORM_USER_MEMORY_RANGES_H__ #include @@ -25,4 +25,9 @@ static const struct tfm_read_service_range ranges[] = { { .start = FICR_RESTRICTED_ADDR, .size = FICR_RESTRICTED_SIZE }, }; -#endif /* TFM_READ_RANGES_H__ */ +static const struct tfm_write32_service_address tfm_write32_service_addresses[] = { + /* This is a dummy value because this table cannot be empty */ + {.addr = 0xFFFFFFFF, .mask = 0x0, .allowed_values = NULL, .allowed_values_array_size = 0}, +}; + +#endif /* TFM_PLATFORM_USER_MEMORY_RANGES_H__ */ diff --git a/platform/ext/target/nuvoton/common/faults.c b/platform/ext/target/nuvoton/common/faults.c index d243e555f..a05133406 100644 --- a/platform/ext/target/nuvoton/common/faults.c +++ b/platform/ext/target/nuvoton/common/faults.c @@ -21,7 +21,7 @@ void C_SCU_Handler(void) __attribute__((naked)) void SCU_IRQHandler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_SCU_Handler \n" @@ -39,7 +39,7 @@ void C_MPC_Handler(void) __attribute__((naked)) void MPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_MPC_Handler \n" @@ -57,7 +57,7 @@ void C_PPC_Handler(void) __attribute__((naked)) void PPC_Handler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_PPC_Handler \n" diff --git a/platform/ext/target/nxp/common/mpc_ppc_faults.c b/platform/ext/target/nxp/common/mpc_ppc_faults.c index e118f8f7b..a14ea86c7 100644 --- a/platform/ext/target/nxp/common/mpc_ppc_faults.c +++ b/platform/ext/target/nxp/common/mpc_ppc_faults.c @@ -25,7 +25,7 @@ void C_SEC_VIO_IRQHandler(void) __attribute__((naked)) void SEC_VIO_IRQHandler(void) { - EXCEPTION_INFO(EXCEPTION_TYPE_PLATFORM); + EXCEPTION_INFO(); __ASM volatile( "BL C_SEC_VIO_IRQHandler \n" diff --git a/platform/include/exception_info.h b/platform/include/exception_info.h index 51bf0a708..9502008e0 100644 --- a/platform/include/exception_info.h +++ b/platform/include/exception_info.h @@ -19,20 +19,12 @@ #define FAULT_STATUS_PRESENT #endif -/* Arguments to EXCEPTION_INFO() */ -#define EXCEPTION_TYPE_SECUREFAULT 0 -#define EXCEPTION_TYPE_HARDFAULT 1 -#define EXCEPTION_TYPE_MEMFAULT 2 -#define EXCEPTION_TYPE_BUSFAULT 3 -#define EXCEPTION_TYPE_USAGEFAULT 4 -#define EXCEPTION_TYPE_PLATFORM 5 - -#ifndef __STRINGIFY -/* This level of indirection is needed to fully resolve exception info when it's - * a macro - */ -#define __STRINGIFY(exception_info) #exception_info -#endif +/* Exception type number (subtract 16 for IRQn) */ +#define EXCEPTION_TYPE_HARDFAULT 3 +#define EXCEPTION_TYPE_MEMMANAGEFAULT 4 +#define EXCEPTION_TYPE_BUSFAULT 5 +#define EXCEPTION_TYPE_USAGEFAULT 6 +#define EXCEPTION_TYPE_SECUREFAULT 7 /* Store context for an exception, and print an error message with the context. * @@ -41,28 +33,93 @@ */ #ifdef TFM_EXCEPTION_INFO_DUMP +struct exception_info_t { + uint32_t VECTACTIVE; /* Active exception number. */ + uint32_t EXC_RETURN; /* EXC_RETURN value in LR. */ + uint32_t MSP; /* (Secure) MSP. */ + uint32_t PSP; /* (Secure) PSP. */ + uint32_t *EXC_FRAME; /* Exception frame on stack. */ + uint32_t EXC_FRAME_COPY[8]; /* Copy of the basic exception frame. */ + uint32_t CALLEE_SAVED_COPY[8]; /* Copy of the callee saved registers. */ + uint32_t xPSR; /* Program Status Registers. */ + +#ifdef FAULT_STATUS_PRESENT + uint32_t CFSR; /* Configurable Fault Status Register. */ + uint32_t HFSR; /* Hard Fault Status Register. */ + uint32_t BFAR; /* Bus Fault address register. */ + uint32_t BFARVALID; /* Whether BFAR contains a valid address. */ + uint32_t MMFAR; /* MemManage Fault address register. */ + uint32_t MMARVALID; /* Whether MMFAR contains a valid address. */ +#ifdef TRUSTZONE_PRESENT + uint32_t SFSR; /* SecureFault Status Register. */ + uint32_t SFAR; /* SecureFault Address Register. */ + uint32_t SFARVALID; /* Whether SFAR contains a valid address. */ +#endif +#endif +}; + +/** + * \brief Get a pointer to the current exception_info_t context + * + * \return A pointer to the exception_info_t context or NULL if no context + * has been stored + */ +void tfm_exception_info_get_context(struct exception_info_t *ctx); + /* Store context for an exception, then print the info. * Call EXCEPTION_INFO() instead of calling this directly. */ -void store_and_dump_context(uint32_t LR_in, uint32_t MSP_in, uint32_t PSP_in, - uint32_t exception_type); +void store_and_dump_context(uint32_t MSP_in, uint32_t PSP_in, uint32_t LR_in, + uint32_t *callee_saved); /* IAR Specific */ #if defined(__ICCARM__) #pragma required = store_and_dump_context #endif -#define EXCEPTION_INFO(exception_type) \ - __ASM volatile( \ - "MOV r0, lr\n" \ - "MRS r1, MSP\n" \ - "MRS r2, PSP\n" \ - "MOVS r3, #" __STRINGIFY(exception_type) "\n"\ - "BL store_and_dump_context\n" \ +#if defined(__ARM_ARCH_8M_BASE__) || defined(__ARCM_ARCH_V6_M__) +#define EXCEPTION_INFO() \ + __ASM volatile( \ + "MRS R0, MSP\n" \ + "MRS R1, PSP\n" \ + "MOV R2, R11\n" \ + "MOV R3, R10\n" \ + "PUSH {R2, R3}\n" \ + "MOV R2, R9\n" \ + "MOV R3, R8\n" \ + "PUSH {R2, R3}\n" \ + "PUSH {R4-R7}\n" \ + "MOV R3, SP\n" \ + "MOV R2, LR\n" \ + "BL store_and_dump_context\n" \ + "ADD SP, #32\n" \ ) +#elif defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__) || \ + defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) +#define EXCEPTION_INFO() \ + __ASM volatile( \ + "MRS R0, MSP\n" \ + "MRS R1, PSP\n" \ + "PUSH {R4-R11}\n" \ + "MOV R3, SP\n" \ + "MOV R2, LR\n" \ + "BL store_and_dump_context\n" \ + "ADD SP, #32\n" \ + ) +#else +/* Unhandled arch, call store_and_dump_context with callee_saved = NULL */ +#define EXCEPTION_INFO() \ + __ASM volatile( \ + "MRS R0, MSP\n" \ + "MRS R1, PSP\n" \ + "MOV R2, LR\n" \ + "MOV R3, #0\n" \ + "BL store_and_dump_context\n" \ + ) +#endif #else /* TFM_EXCEPTION_INFO_DUMP */ -#define EXCEPTION_INFO(exception_type) +#define EXCEPTION_INFO() #endif /* TFM_EXCEPTION_INFO_DUMP */ #endif /* __EXCEPTION_INFO_H__ */ diff --git a/secure_fw/partitions/crypto/CMakeLists.txt b/secure_fw/partitions/crypto/CMakeLists.txt index 546930856..db92779f6 100644 --- a/secure_fw/partitions/crypto/CMakeLists.txt +++ b/secure_fw/partitions/crypto/CMakeLists.txt @@ -31,6 +31,7 @@ target_sources(tfm_psa_rot_partition_crypto crypto_key_management.c crypto_rng.c crypto_library.c + crypto_pake.c $<$:psa_driver_api/tfm_builtin_key_loader.c> ) @@ -91,10 +92,10 @@ target_link_libraries(tfm_config ############################### PSA CRYPTO CONFIG ############################## add_library(psa_crypto_config INTERFACE) -target_compile_definitions(psa_crypto_config - INTERFACE - MBEDTLS_PSA_CRYPTO_CONFIG_FILE="${TFM_MBEDCRYPTO_PSA_CRYPTO_CONFIG_PATH}" -) +# target_compile_definitions(psa_crypto_config +# INTERFACE +# MBEDTLS_PSA_CRYPTO_CONFIG_FILE="${TFM_MBEDCRYPTO_PSA_CRYPTO_CONFIG_PATH}" +# ) ############################### MBEDCRYPTO ##################################### @@ -138,20 +139,8 @@ set(MBEDTLS_TARGET_PREFIX crypto_service_) #set(MBEDTLS_PSA_CRYPTO_CONFIG_FILE "${TFM_MBEDCRYPTO_PSA_CRYPTO_CONFIG_PATH}") #set(MBEDTLS_CONFIG_FILE "${TFM_MBEDCRYPTO_CONFIG_PATH}") -# Check if the p256m driver is enabled in the config file, as that will require a -# dedicated target to be linked in. Note that 0 means SUCCESS here, 1 means FAILURE -set(MBEDTLS_P256M_NOT_FOUND 1) -execute_process(COMMAND - ${Python3_EXECUTABLE} - ${MBEDCRYPTO_PATH}/scripts/config.py -f "${TFM_MBEDCRYPTO_CONFIG_PATH}" get MBEDTLS_PSA_P256M_DRIVER_ENABLED - RESULT_VARIABLE MBEDTLS_P256M_NOT_FOUND) - -if (${MBEDTLS_P256M_NOT_FOUND} EQUAL 0) - message(STATUS "[Crypto service] Using P256M software driver in PSA Crypto backend") - set(MBEDTLS_P256M_ENABLED true) -else() - set(MBEDTLS_P256M_ENABLED false) -endif() +# We use hardware acceleration or ocrypto so disable the P256M module by default +set(MBEDTLS_P256M_ENABLED false) # Mbedcrypto is quite a large lib, and it uses too much memory for it to be # reasonable to build it in debug info. As a compromise, if `debug` build type @@ -194,19 +183,21 @@ target_compile_definitions(${MBEDTLS_TARGET_PREFIX}mbedcrypto MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER ) -# FixMe: The p256m CmakeLists.txt in version 3.5.0 has an issue with target -# names and for this reason we need to force those defines at this stage -target_compile_definitions(${MBEDTLS_TARGET_PREFIX}p256m - PRIVATE - MBEDTLS_PSA_P256M_DRIVER_ENABLED - MBEDTLS_PSA_CRYPTO_SPM -) - -# The crypto_spe.h to be passed to p256m is here -target_include_directories(${MBEDTLS_TARGET_PREFIX}p256m - PRIVATE - . -) +if(MBEDTLS_P256M_ENABLED) + # FixMe: The p256m CmakeLists.txt in version 3.5.0 has an issue with target + # names and for this reason we need to force those defines at this stage + target_compile_definitions(${MBEDTLS_TARGET_PREFIX}p256m + PRIVATE + MBEDTLS_PSA_P256M_DRIVER_ENABLED + MBEDTLS_PSA_CRYPTO_SPM + ) + + # The crypto_spe.h to be passed to p256m is here + target_include_directories(${MBEDTLS_TARGET_PREFIX}p256m + PRIVATE + . + ) +endif() target_link_libraries(${MBEDTLS_TARGET_PREFIX}mbedcrypto PRIVATE diff --git a/secure_fw/partitions/crypto/Kconfig.comp b/secure_fw/partitions/crypto/Kconfig.comp index e5bf08780..f8ef7658c 100644 --- a/secure_fw/partitions/crypto/Kconfig.comp +++ b/secure_fw/partitions/crypto/Kconfig.comp @@ -71,6 +71,10 @@ config CRYPTO_KEY_DERIVATION_MODULE_ENABLED bool "PSA Crypto key derivation module" default y +config CRYPTO_PAKE_MODULE_ENABLED + bool "PSA Crypto PAKE module" + default y + config CRYPTO_NV_SEED bool default n if CRYPTO_HW_ACCELERATOR diff --git a/secure_fw/partitions/crypto/config_crypto_check.h b/secure_fw/partitions/crypto/config_crypto_check.h index 9dbcd3458..f1cfbc155 100644 --- a/secure_fw/partitions/crypto/config_crypto_check.h +++ b/secure_fw/partitions/crypto/config_crypto_check.h @@ -12,7 +12,7 @@ /* Check invalid configs. */ #if CRYPTO_NV_SEED && defined(CRYPTO_HW_ACCELERATOR) -#error "Invalid config: CRYPTO_NV_SEED AND CRYPTO_HW_ACCELERATOR!" +// #error "Invalid config: CRYPTO_NV_SEED AND CRYPTO_HW_ACCELERATOR!" #endif #if (!CRYPTO_NV_SEED) && (!defined(CRYPTO_HW_ACCELERATOR)) diff --git a/secure_fw/partitions/crypto/crypto_check_config.h b/secure_fw/partitions/crypto/crypto_check_config.h index c06b46c6e..19d04b77b 100644 --- a/secure_fw/partitions/crypto/crypto_check_config.h +++ b/secure_fw/partitions/crypto/crypto_check_config.h @@ -9,62 +9,123 @@ #include "config_tfm.h" -#if CRYPTO_RNG_MODULE_ENABLED && \ - (!defined(MBEDTLS_CTR_DRBG_C) && \ - !defined(MBEDTLS_HMAC_DRBG_C) && \ - !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)) -#error "CRYPTO_RNG_MODULE_ENABLED enables, but not all prerequisites (missing RNG)!" +/* RNG module config can't be adjusted on PSA_WANT_* requirements. */ + +#if CRYPTO_KEY_MODULE_ENABLED && \ + (!defined(PSA_WANT_KEY_TYPE_DERIVE) && \ + !defined(PSA_WANT_KEY_TYPE_HMAC) && \ + !defined(PSA_WANT_KEY_TYPE_RAW_DATA) && \ + !defined(PSA_WANT_KEY_TYPE_PASSWORD) && \ + !defined(PSA_WANT_KEY_TYPE_PASSWORD_HASH) && \ + !defined(PSA_WANT_KEY_TYPE_PEPPER) && \ + !defined(PSA_WANT_KEY_TYPE_AES) && \ + !defined(PSA_WANT_KEY_TYPE_ARIA) && \ + !defined(PSA_WANT_KEY_TYPE_DES) && \ + !defined(PSA_WANT_KEY_TYPE_CAMELLIA) && \ + !defined(PSA_WANT_KEY_TYPE_SM4) && \ + !defined(PSA_WANT_KEY_TYPE_ARC4) && \ + !defined(PSA_WANT_KEY_TYPE_CHACHA20) && \ + !defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR) && \ + !defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) && \ + !defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR) && \ + !defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) && \ + !defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR) && \ + !defined(PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY)) +#error "CRYPTO_KEY_MODULE enabled, but not all prerequisites (missing key types)!" #endif -#if CRYPTO_AEAD_MODULE_ENABLED && \ - (!defined(PSA_WANT_ALG_CCM) && !defined(PSA_WANT_ALG_GCM) && \ +#if CRYPTO_AEAD_MODULE_ENABLED && \ + (!defined(PSA_WANT_ALG_CCM) && \ + !defined(PSA_WANT_ALG_GCM) && \ !defined(PSA_WANT_ALG_CHACHA20_POLY1305)) -#error "CRYPTO_AEAD_MODULE_ENABLED enables, but not all prerequisites (missing AEAD algorithms)!" +#error "CRYPTO_AEAD_MODULE_ENABLED enabled, but not all prerequisites (missing AEAD algorithms)!" #endif #if CRYPTO_MAC_MODULE_ENABLED && \ - (!defined(PSA_WANT_ALG_CMAC) && !defined(PSA_WANT_ALG_HMAC)) -#error "CRYPTO_MAC_MODULE_ENABLED enables, but not all prerequisites (missing MAC algorithms)!" + (!defined(PSA_WANT_ALG_CMAC) && \ + !defined(PSA_WANT_ALG_HMAC) && \ + !defined(PSA_WANT_ALG_CBC_MAC)) +#error "CRYPTO_MAC_MODULE_ENABLED enabled, but not all prerequisites (missing MAC algorithms)!" #endif #if CRYPTO_CIPHER_MODULE_ENABLED && \ - (!defined(PSA_WANT_KEY_TYPE_AES) && \ - !defined(PSA_WANT_KEY_TYPE_CHACHA20) && \ - !defined(PSA_WANT_ALG_CBC_NO_PADDING) && \ - !defined(PSA_WANT_ALG_CBC_PKCS7) && \ - !defined(PSA_WANT_ALG_CCM) && \ - !defined(PSA_WANT_ALG_GCM)) -#error "CRYPTO_CIPHER_MODULE_ENABLED enables, but not all prerequisites (missing CIPHER algorithms)!" + (!defined(PSA_WANT_ALG_ECB_NO_PADDING) && \ + !defined(PSA_WANT_ALG_CBC_NO_PADDING) && \ + !defined(PSA_WANT_ALG_CBC_PKCS7) && \ + !defined(PSA_WANT_ALG_CCM_STAR_NO_TAG) && \ + !defined(PSA_WANT_ALG_CFB) && \ + !defined(PSA_WANT_ALG_CTR) && \ + !defined(PSA_WANT_ALG_OFB) && \ + !defined(PSA_WANT_ALG_XTS) && \ + !defined(PSA_WANT_ALG_STREAM_CIPHER)) +#error "CRYPTO_CIPHER_MODULE_ENABLED enabled, but not all prerequisites (missing CIPHER algorithms)!" #endif #if CRYPTO_HASH_MODULE_ENABLED && \ - (!defined(PSA_WANT_ALG_RIPEMD160) && \ - !defined(PSA_WANT_ALG_SHA_224) && \ - !defined(PSA_WANT_ALG_SHA_256) && \ - !defined(PSA_WANT_ALG_SHA_384) && \ - !defined(PSA_WANT_ALG_SHA_512)) -#error "CRYPTO_HASH_MODULE_ENABLED enables, but not all prerequisites (missing HASH algorithms)!" + (!defined(PSA_WANT_ALG_MD2) && \ + !defined(PSA_WANT_ALG_MD4) && \ + !defined(PSA_WANT_ALG_MD5) && \ + !defined(PSA_WANT_ALG_RIPEMD160) && \ + !defined(PSA_WANT_ALG_SHA_1) && \ + !defined(PSA_WANT_ALG_SHA_224) && \ + !defined(PSA_WANT_ALG_SHA_256) && \ + !defined(PSA_WANT_ALG_SHA_384) && \ + !defined(PSA_WANT_ALG_SHA_512) && \ + !defined(PSA_WANT_ALG_SHA_512_224) && \ + !defined(PSA_WANT_ALG_SHA_512_256) && \ + !defined(PSA_WANT_ALG_SHA3_224) && \ + !defined(PSA_WANT_ALG_SHA3_256) && \ + !defined(PSA_WANT_ALG_SHA3_384) && \ + !defined(PSA_WANT_ALG_SHA3_512) && \ + !defined(PSA_WANT_ALG_SM3) && \ + !defined(PSA_WANT_ALG_SHAKE256_512)) +#error "CRYPTO_HASH_MODULE_ENABLED enabled, but not all prerequisites (missing HASH algorithms)!" #endif #if CRYPTO_ASYM_SIGN_MODULE_ENABLED && \ (!defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN) && \ + !defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN_RAW) && \ !defined(PSA_WANT_ALG_RSA_PSS) && \ + !defined(PSA_WANT_ALG_RSA_PSS_ANY_SALT) && \ !defined(PSA_WANT_ALG_ECDSA) && \ - !defined(PSA_WANT_ALG_DETERMINISTIC_ECDSA)) -#error "CRYPTO_ASYM_SIGN_MODULE_ENABLED enables, but not all prerequisites (missing asymmetric sign algorithms)!" + !defined(PSA_WANT_ALG_ECDSA_ANY) && \ + !defined(PSA_WANT_ALG_DETERMINISTIC_ECDSA) && \ + !defined(PSA_WANT_ALG_PURE_EDDSA) && \ + !defined(PSA_WANT_ALG_ED25519PH) && \ + !defined(PSA_WANT_ALG_ED448PH)) +#error "CRYPTO_ASYM_SIGN_MODULE_ENABLED enabled, but not all prerequisites (missing asymmetric sign algorithms)!" #endif #if CRYPTO_ASYM_ENCRYPT_MODULE_ENABLED && \ (!defined(PSA_WANT_ALG_RSA_PKCS1V15_CRYPT) && \ !defined(PSA_WANT_ALG_RSA_OAEP)) -#error "CRYPTO_ASYM_ENCRYPT_MODULE_ENABLED enables, but not all prerequisites (missing asymmetric encryption algorithms)!" +#error "CRYPTO_ASYM_ENCRYPT_MODULE_ENABLED enabled, but not all prerequisites (missing asymmetric encryption algorithms)!" #endif #if CRYPTO_KEY_DERIVATION_MODULE_ENABLED && \ - (!defined(PSA_WANT_ALG_HKDF) && \ + (/* Key agreement */ \ + !defined(PSA_WANT_ALG_ECDH) && \ + !defined(PSA_WANT_ALG_FFDH) && \ + /* Key derivation */ \ + !defined(PSA_WANT_ALG_HKDF) && \ + !defined(PSA_WANT_ALG_HKDF_EXPAND) /* Not official PSA but exists in mbedtls */ && \ + !defined(PSA_WANT_ALG_HKDF_EXTRACT) /* Not official PSA but exists in mbedtls */ && \ + !defined(PSA_WANT_ALG_PBKDF2_HMAC) && \ + !defined(PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128) && \ !defined(PSA_WANT_ALG_TLS12_PRF) && \ - !defined(PSA_WANT_ALG_TLS12_PSK_TO_MS)) -#error "CRYPTO_KEY_DERIVATION_MODULE_ENABLED enables, but not all prerequisites (missing key derivation algorithms)!" + !defined(PSA_WANT_ALG_TLS12_PSK_TO_MS) && \ + !defined(PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS) /* Not official PSA but exists in mbedtls */) +#error "CRYPTO_KEY_DERIVATION_MODULE_ENABLED enabled, but not all prerequisites (missing key derivation algorithms)!" +#endif + +#if CRYPTO_PAKE_MODULE_ENABLED && \ + (!defined(PSA_WANT_ALG_JPAKE) && \ + !defined(PSA_WANT_ALG_SPAKE2P_HMAC) && \ + !defined(PSA_WANT_ALG_SPAKE2P_CMAC) && \ + !defined(PSA_WANT_ALG_SPAKE2P_MATTER) && \ + !defined(PSA_WANT_ALG_SRP_6) && \ + !defined(PSA_WANT_ALG_SRP_PASSWORD_HASH)) +#error "CRYPTO_PAKE_MODULE_ENABLED enabled, but not all prerequisites (missing PAKE algorithms)!" #endif #endif /* __CRYPTO_CHECK_CONFIG_H__ */ diff --git a/secure_fw/partitions/crypto/crypto_init.c b/secure_fw/partitions/crypto/crypto_init.c index da20896d4..6067ea07d 100644 --- a/secure_fw/partitions/crypto/crypto_init.c +++ b/secure_fw/partitions/crypto/crypto_init.c @@ -388,6 +388,8 @@ psa_status_t tfm_crypto_api_dispatcher(psa_invec in_vec[], &encoded_key); case TFM_CRYPTO_GROUP_ID_RANDOM: return tfm_crypto_random_interface(in_vec, out_vec); + case TFM_CRYPTO_GROUP_ID_PAKE: + return tfm_crypto_pake_interface(in_vec, out_vec, &encoded_key); default: LOG_ERRFMT("[ERR][Crypto] Unsupported request!\r\n"); return PSA_ERROR_NOT_SUPPORTED; diff --git a/secure_fw/partitions/crypto/crypto_key_derivation.c b/secure_fw/partitions/crypto/crypto_key_derivation.c index f9fb1dafb..d642bdf10 100644 --- a/secure_fw/partitions/crypto/crypto_key_derivation.c +++ b/secure_fw/partitions/crypto/crypto_key_derivation.c @@ -94,6 +94,10 @@ psa_status_t tfm_crypto_key_derivation_interface(psa_invec in_vec[], return psa_key_derivation_input_bytes(operation, iov->step, data, data_length); } + case TFM_CRYPTO_KEY_DERIVATION_INPUT_INTEGER_SID: + { + return psa_key_derivation_input_integer(operation, iov->step, iov->value); + } case TFM_CRYPTO_KEY_DERIVATION_OUTPUT_BYTES_SID: { uint8_t *output = out_vec[0].base; diff --git a/secure_fw/partitions/crypto/crypto_library.c b/secure_fw/partitions/crypto/crypto_library.c index f65e366be..1f1688123 100644 --- a/secure_fw/partitions/crypto/crypto_library.c +++ b/secure_fw/partitions/crypto/crypto_library.c @@ -153,6 +153,7 @@ psa_status_t tfm_crypto_core_library_key_attributes_to_client( return PSA_SUCCESS; } +#ifdef PSA_CRYPTO_DRIVER_TFM_BUILTIN_KEY_LOADER /** * \brief This function is required by mbed TLS to enable support for * platform builtin keys in the PSA Crypto core layer implemented @@ -181,4 +182,5 @@ psa_status_t mbedtls_psa_platform_get_builtin_key( return PSA_ERROR_DOES_NOT_EXIST; } +#endif /*!@}*/ diff --git a/secure_fw/partitions/crypto/crypto_pake.c b/secure_fw/partitions/crypto/crypto_pake.c new file mode 100644 index 000000000..c19791fe8 --- /dev/null +++ b/secure_fw/partitions/crypto/crypto_pake.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "config_tfm.h" +#include "tfm_mbedcrypto_include.h" + +#include "tfm_crypto_api.h" +#include "tfm_crypto_key.h" +#include "tfm_crypto_defs.h" + +#include "crypto_library.h" + +/*! + * \addtogroup tfm_crypto_api_shim_layer + * + */ + +/*!@{*/ +#if CRYPTO_PAKE_MODULE_ENABLED +psa_status_t tfm_crypto_pake_interface(psa_invec in_vec[], + psa_outvec out_vec[], + struct tfm_crypto_key_id_s *encoded_key) +{ + const struct tfm_crypto_pack_iovec *iov = in_vec[0].base; + psa_status_t status = PSA_ERROR_NOT_SUPPORTED; + psa_pake_operation_t *operation = NULL; + uint32_t *p_handle = NULL; + uint16_t sid = iov->function_id; + + tfm_crypto_library_key_id_t library_key = tfm_crypto_library_key_id_init( + encoded_key->owner, encoded_key->key_id); + if(sid == TFM_CRYPTO_PAKE_SETUP_SID) { + p_handle = out_vec[0].base; + *p_handle = iov->op_handle; + status = tfm_crypto_operation_alloc(TFM_CRYPTO_PAKE_OPERATION, + out_vec[0].base, + (void **)&operation); + } else { + status = tfm_crypto_operation_lookup(TFM_CRYPTO_PAKE_OPERATION, + iov->op_handle, + (void **)&operation); + if ((sid == TFM_CRYPTO_PAKE_ABORT_SID) || sid == TFM_CRYPTO_PAKE_GET_SHARED_KEY_SID){ + /* + * finish()/abort() interface put handle in out_vec[0]. + * Therefore, out_vec[0] shall be specially set to original handle + * value. Otherwise, the garbage data in message out_vec[0] may + * override the original handle value in client, after lookup fails. + */ + p_handle = out_vec[0].base; + *p_handle = iov->op_handle; + } + } + if (status != PSA_SUCCESS) { + if (sid == TFM_CRYPTO_PAKE_ABORT_SID) { + /* + * Mbed TLS psa_pake_abort() will return a misleading error code + * if it is called with invalid operation content, since it + * doesn't validate the operation handle. + * It is neither necessary to call tfm_crypto_operation_release() + * with an invalid handle. + * Therefore return PSA_SUCCESS directly as psa_cipher_abort() can + * be called multiple times. + */ + return PSA_SUCCESS; + } + return status; + } + + switch (sid) + { + case TFM_CRYPTO_PAKE_SETUP_SID: + { + status = psa_pake_setup(operation, library_key, in_vec[1].base); + if (status != PSA_SUCCESS) { + goto release_operation_and_return; + } + } + break; + case TFM_CRYPTO_PAKE_SET_ROLE_SID: + { + status = psa_pake_set_role(operation, iov->role); + } + break; + case TFM_CRYPTO_PAKE_SET_USER_SID: + { + status = psa_pake_set_user(operation, in_vec[1].base, in_vec[1].len); + } + break; + case TFM_CRYPTO_PAKE_SET_PEER_SID: + { + status = psa_pake_set_peer(operation, in_vec[1].base, in_vec[1].len); + } + break; + case TFM_CRYPTO_PAKE_SET_CONTEXT_SID: + { + status = psa_pake_set_context(operation, in_vec[1].base, in_vec[1].len); + } + break; + case TFM_CRYPTO_PAKE_OUTPUT_SID: + { + psa_pake_step_t step = (psa_pake_step_t)iov->step; + uint8_t *output = (uint8_t *)out_vec[0].base; + size_t output_size = out_vec[0].len; + size_t *output_length = &out_vec[0].len; + status = psa_pake_output(operation, step, output, output_size, output_length); + if (status != PSA_SUCCESS) { + out_vec[0].len = 0; + } + } + break; + case TFM_CRYPTO_PAKE_INPUT_SID: + { + status = psa_pake_input(operation, (psa_pake_step_t)iov->step, in_vec[1].base, in_vec[1].len); + } + break; + case TFM_CRYPTO_PAKE_GET_SHARED_KEY_SID: + { + psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; + const struct psa_client_key_attributes_s *client_key_attr = + in_vec[1].base; + psa_key_id_t *key_handle = out_vec[1].base; + + status = tfm_crypto_core_library_key_attributes_from_client( + client_key_attr, + encoded_key->owner, + &key_attributes); + + if (status != PSA_SUCCESS) { + break; + } + + status = psa_pake_get_shared_key(operation, &key_attributes, &library_key); + if (status == PSA_SUCCESS) { + *key_handle = CRYPTO_LIBRARY_GET_KEY_ID(library_key); + /* In case of success automatically release the operation */ + goto release_operation_and_return; + } + } + break; + case TFM_CRYPTO_PAKE_ABORT_SID: + { + status = psa_pake_abort(operation); + goto release_operation_and_return; + } + default: + return PSA_ERROR_NOT_SUPPORTED; + } + + return status; + +release_operation_and_return: + /* Release the operation context, ignore if the operation fails. */ + (void)tfm_crypto_operation_release(p_handle); + return status; +} +#else /* CRYPTO_PAKE_MODULE_ENABLED */ +psa_status_t tfm_crypto_pake_interface(psa_invec in_vec[], + psa_outvec out_vec[], + struct tfm_crypto_key_id_s *encoded_key) +{ + (void)in_vec; + (void)out_vec; + (void)encoded_key; + + return PSA_ERROR_NOT_SUPPORTED; +} +#endif /* CRYPTO_PAKE_MODULE_ENABLED */ +/*!@}*/ diff --git a/secure_fw/partitions/crypto/crypto_spe.h b/secure_fw/partitions/crypto/crypto_spe.h index b4d21fa0c..091b894a5 100644 --- a/secure_fw/partitions/crypto/crypto_spe.h +++ b/secure_fw/partitions/crypto/crypto_spe.h @@ -30,8 +30,14 @@ PSA_FUNCTION_NAME(psa_key_derivation_set_capacity) #define psa_key_derivation_input_bytes \ PSA_FUNCTION_NAME(psa_key_derivation_input_bytes) +#define psa_key_derivation_input_integer \ + PSA_FUNCTION_NAME(psa_key_derivation_input_integer) +#define psa_key_derivation_verify_key \ + PSA_FUNCTION_NAME(psa_key_derivation_verify_key) #define psa_key_derivation_output_bytes \ PSA_FUNCTION_NAME(psa_key_derivation_output_bytes) +#define psa_key_derivation_verify_bytes \ + PSA_FUNCTION_NAME(psa_key_derivation_verify_bytes) #define psa_key_derivation_input_key \ PSA_FUNCTION_NAME(psa_key_derivation_input_key) #define psa_key_derivation_output_key \ @@ -160,5 +166,23 @@ PSA_FUNCTION_NAME(psa_asymmetric_decrypt) #define psa_generate_key \ PSA_FUNCTION_NAME(psa_generate_key) +#define psa_pake_setup \ + PSA_FUNCTION_NAME(psa_pake_setup) +#define psa_pake_set_role \ + PSA_FUNCTION_NAME(psa_pake_set_role) +#define psa_pake_set_user \ + PSA_FUNCTION_NAME(psa_pake_set_user) +#define psa_pake_set_peer \ + PSA_FUNCTION_NAME(psa_pake_set_peer) +#define psa_pake_set_context \ + PSA_FUNCTION_NAME(psa_pake_set_context) +#define psa_pake_output \ + PSA_FUNCTION_NAME(psa_pake_output) +#define psa_pake_input \ + PSA_FUNCTION_NAME(psa_pake_input) +#define psa_pake_get_shared_key \ + PSA_FUNCTION_NAME(psa_pake_get_shared_key) +#define psa_pake_abort \ + PSA_FUNCTION_NAME(psa_pake_abort) #endif /* CRYPTO_SPE_H */ diff --git a/secure_fw/partitions/crypto/psa_driver_api/tfm_builtin_key_loader.c b/secure_fw/partitions/crypto/psa_driver_api/tfm_builtin_key_loader.c index 2af9130d5..3d129782f 100644 --- a/secure_fw/partitions/crypto/psa_driver_api/tfm_builtin_key_loader.c +++ b/secure_fw/partitions/crypto/psa_driver_api/tfm_builtin_key_loader.c @@ -197,8 +197,6 @@ static psa_status_t derive_subkey_into_buffer( struct tfm_builtin_key_t *key_slot, int32_t user, uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length) { - int mbedtls_err; - #ifdef TFM_PARTITION_TEST_PS /* Hack to allow the PS tests to work, since they directly call * ps_system_prepare from the test partition which would otherwise derive a @@ -209,22 +207,54 @@ static psa_status_t derive_subkey_into_buffer( } #endif /* TFM_PARTITION_TEST_PS */ - /* FIXME this should be moved to using the PSA APIs once key derivation is - * implemented in the PSA driver wrapper. Using the external PSA apis - * directly creates a keyslot and we'd need to read the data from it and - * then destroy it, so isn't ideal. In order to avoid infinite recursion, - * it'll be necessary to add a special case (probably if owner == 0) to make - * sure the new PSA derivation request doesn't end up back here. - */ - mbedtls_err = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), - NULL, 0, key_slot->key, key_slot->key_len, - (uint8_t *)&user, sizeof(user), key_buffer, - key_buffer_size); - if (mbedtls_err) { - return PSA_ERROR_GENERIC_ERROR; + psa_status_t status; + mbedtls_svc_key_id_t output_key_id_local = MBEDTLS_SVC_KEY_ID_INIT; + mbedtls_svc_key_id_t builtin_key = psa_get_key_id(&key_slot->attr); + mbedtls_svc_key_id_t input_key_id_local = mbedtls_svc_key_id_make( + TFM_SP_CRYPTO, MBEDTLS_SVC_KEY_ID_GET_KEY_ID(builtin_key)); + psa_key_derivation_operation_t deriv_ops = psa_key_derivation_operation_init(); + psa_key_attributes_t output_key_attr = PSA_KEY_ATTRIBUTES_INIT; + psa_key_attributes_t input_key_attr = PSA_KEY_ATTRIBUTES_INIT; + /* Set properties for the output key */ + psa_set_key_type(&output_key_attr, PSA_KEY_TYPE_RAW_DATA); + psa_set_key_bits(&output_key_attr, PSA_BYTES_TO_BITS(key_buffer_size)); + psa_set_key_usage_flags(&output_key_attr, PSA_KEY_USAGE_EXPORT); + /* Import the key material as a volatile key */ + psa_set_key_usage_flags(&input_key_attr, PSA_KEY_USAGE_DERIVE); + psa_set_key_algorithm(&input_key_attr, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + psa_set_key_type(&input_key_attr, PSA_KEY_TYPE_DERIVE); + status = psa_import_key(&input_key_attr, key_slot->key, key_slot->key_len, &input_key_id_local); + if (status != PSA_SUCCESS) { + goto wrap_up; } - - *key_buffer_length = key_buffer_size; + status = psa_key_derivation_setup(&deriv_ops, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + if (status != PSA_SUCCESS) { + goto wrap_up; + } + /* No salt is being used for the derivation */ + status = psa_key_derivation_input_key( + &deriv_ops, PSA_KEY_DERIVATION_INPUT_SECRET, input_key_id_local); + if (status != PSA_SUCCESS) { + goto wrap_up; + } + status = psa_key_derivation_input_bytes( + &deriv_ops, PSA_KEY_DERIVATION_INPUT_INFO, (uint8_t *)&user, sizeof(user)); + if (status != PSA_SUCCESS) { + goto wrap_up; + } + status = psa_key_derivation_output_key(&output_key_attr, &deriv_ops, + &output_key_id_local); + if (status != PSA_SUCCESS) { + goto wrap_up; + } + status = psa_export_key(output_key_id_local, key_buffer, key_buffer_size, key_buffer_length); + if (status != PSA_SUCCESS) { + goto wrap_up; + } +wrap_up: + (void)psa_key_derivation_abort(&deriv_ops); + (void)psa_destroy_key(input_key_id_local); + (void)psa_destroy_key(output_key_id_local); return PSA_SUCCESS; } diff --git a/secure_fw/partitions/crypto/tfm_crypto_api.h b/secure_fw/partitions/crypto/tfm_crypto_api.h index 8fff29dce..2dc8473fd 100644 --- a/secure_fw/partitions/crypto/tfm_crypto_api.h +++ b/secure_fw/partitions/crypto/tfm_crypto_api.h @@ -31,6 +31,7 @@ enum tfm_crypto_operation_type { TFM_CRYPTO_HASH_OPERATION = 3, TFM_CRYPTO_KEY_DERIVATION_OPERATION = 4, TFM_CRYPTO_AEAD_OPERATION = 5, + TFM_CRYPTO_PAKE_OPERATION = 6, /* Used to force the enum size */ TFM_CRYPTO_OPERATION_TYPE_MAX = INT_MAX @@ -217,6 +218,19 @@ psa_status_t tfm_crypto_random_interface(psa_invec in_vec[], psa_status_t tfm_crypto_hash_interface(psa_invec in_vec[], psa_outvec out_vec[]); +/** + * \brief This function acts as interface for the PAKE module + * + * \param[in] in_vec Array of invec parameters + * \param[out] out_vec Array of outvec parameters + * \param[in] encoded_key Key encoded with partition_id and key_id + * + * \return Return values as described in \ref psa_status_t + */ +psa_status_t tfm_crypto_pake_interface(psa_invec in_vec[], + psa_outvec out_vec[], + struct tfm_crypto_key_id_s *encoded_key); + #ifdef __cplusplus } #endif diff --git a/secure_fw/partitions/internal_trusted_storage/CMakeLists.txt b/secure_fw/partitions/internal_trusted_storage/CMakeLists.txt index 94aa82236..f4c960c2e 100644 --- a/secure_fw/partitions/internal_trusted_storage/CMakeLists.txt +++ b/secure_fw/partitions/internal_trusted_storage/CMakeLists.txt @@ -64,6 +64,7 @@ target_link_libraries(tfm_psa_rot_partition_its target_compile_definitions(tfm_psa_rot_partition_its PUBLIC PS_CRYPTO_AEAD_ALG=${PS_CRYPTO_AEAD_ALG} + PS_CRYPTO_KDF_ALG=${PS_CRYPTO_KDF_ALG} ) ################ Display the configuration being applied ####################### diff --git a/secure_fw/partitions/protected_storage/crypto/ps_crypto_interface.c b/secure_fw/partitions/protected_storage/crypto/ps_crypto_interface.c index 20e9adfed..5b12275d0 100644 --- a/secure_fw/partitions/protected_storage/crypto/ps_crypto_interface.c +++ b/secure_fw/partitions/protected_storage/crypto/ps_crypto_interface.c @@ -18,6 +18,10 @@ #define PS_CRYPTO_AEAD_ALG PSA_ALG_GCM #endif +#if !defined(PS_CRYPTO_KDF_ALG) +#define PS_CRYPTO_KDF_ALG PSA_ALG_HKDF(PSA_ALG_SHA_256) +#endif + /* The PSA key type used by this implementation */ #define PS_KEY_TYPE PSA_KEY_TYPE_AES /* The PSA key usage required by this implementation */ @@ -73,7 +77,7 @@ psa_status_t ps_crypto_setkey(const uint8_t *key_label, size_t key_label_len) psa_set_key_type(&attributes, PS_KEY_TYPE); psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(PS_KEY_LEN_BYTES)); - status = psa_key_derivation_setup(&op, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + status = psa_key_derivation_setup(&op, PS_CRYPTO_KDF_ALG); if (status != PSA_SUCCESS) { return status; } @@ -86,7 +90,8 @@ psa_status_t ps_crypto_setkey(const uint8_t *key_label, size_t key_label_len) } /* Supply the PS key label as an input to the key derivation */ - status = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_INFO, + status = psa_key_derivation_input_bytes(&op, PS_CRYPTO_KDF_ALG == PSA_ALG_SP800_108_COUNTER_CMAC ? + PSA_KEY_DERIVATION_INPUT_LABEL : PSA_KEY_DERIVATION_INPUT_INFO, key_label, key_label_len); if (status != PSA_SUCCESS) { diff --git a/secure_fw/partitions/protected_storage/ps_object_defs.h b/secure_fw/partitions/protected_storage/ps_object_defs.h index 7b0265443..ca66d0c77 100644 --- a/secure_fw/partitions/protected_storage/ps_object_defs.h +++ b/secure_fw/partitions/protected_storage/ps_object_defs.h @@ -45,8 +45,11 @@ struct ps_obj_header_t { #define PS_MAX_OBJECT_DATA_SIZE PS_MAX_ASSET_SIZE + +#ifdef PS_ENCRYPTION #define PS_TAG_IV_LEN_MAX ((PS_TAG_LEN_BYTES > PS_IV_LEN_BYTES) ? \ PS_TAG_LEN_BYTES : PS_IV_LEN_BYTES) +#endif /*! * \struct ps_object_t @@ -57,7 +60,9 @@ struct ps_obj_header_t { struct ps_object_t { struct ps_obj_header_t header; /*!< Object header */ uint8_t data[PS_MAX_OBJECT_DATA_SIZE]; /*!< Object data */ +#ifdef PS_ENCRYPTION uint8_t tag_iv[PS_TAG_IV_LEN_MAX]; +#endif }; diff --git a/secure_fw/spm/core/tfm_svcalls.c b/secure_fw/spm/core/tfm_svcalls.c index ee0447def..3ab48c7ba 100644 --- a/secure_fw/spm/core/tfm_svcalls.c +++ b/secure_fw/spm/core/tfm_svcalls.c @@ -27,6 +27,7 @@ #include "load/spm_load_api.h" #include "load/partition_defs.h" #include "psa/client.h" +#include "uart_stdout.h" #ifdef PLATFORM_SVC_HANDLERS extern int32_t platform_svc_handlers(uint8_t svc_number, @@ -168,10 +169,19 @@ static int32_t prepare_to_thread_mode_spm(uint8_t svc_number, uint32_t *ctx, uin static uint32_t handle_spm_svc_requests(uint32_t svc_number, uint32_t exc_return, uint32_t *svc_args, uint32_t *msp) { +#if TFM_SP_LOG_RAW_ENABLED + struct partition_t *curr_partition; + fih_int fih_rc = FIH_FAILURE; +#endif + switch (svc_number) { case TFM_SVC_SPM_INIT: exc_return = tfm_spm_init(); tfm_arch_check_msp_sealing(); + +#if defined(CONFIG_TFM_LOG_SHARE_UART) + stdio_uninit(); +#endif /* The following call does not return */ tfm_arch_free_msp_and_exc_ret(SPM_BOOT_STACK_BOTTOM, exc_return); break; @@ -189,7 +199,17 @@ static uint32_t handle_spm_svc_requests(uint32_t svc_number, uint32_t exc_return #endif #if TFM_SP_LOG_RAW_ENABLED case TFM_SVC_OUTPUT_UNPRIV_STRING: - svc_args[0] = tfm_hal_output_spm_log((const char *)svc_args[0], svc_args[1]); + /* Protect PRoT data from unauthorised access from ARoT partition. + * This fixes the TFMV-7 vulnerability + */ + curr_partition = GET_CURRENT_COMPONENT(); + FIH_CALL(tfm_hal_memory_check, fih_rc, curr_partition->boundary, (uintptr_t)svc_args[0], + svc_args[1], TFM_HAL_ACCESS_READABLE); + if (fih_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) { + svc_args[0] = tfm_hal_output_spm_log((const char *)svc_args[0], svc_args[1]); + } else { + tfm_core_panic(); + } break; #endif #if TFM_ISOLATION_LEVEL > 1 diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 8389b85f5..e34469fe7 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -159,12 +159,17 @@ set(MANIFEST_COMMAND -o ${CMAKE_BINARY_DIR}/generated ${PARSE_MANIFEST_QUIET_FLAG}) +set(NO_BUILD_CMD_FOR_MANIFEST 1) + +if(NO_BUILD_CMD_FOR_MANIFEST) +else() add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/generated COMMAND ${MANIFEST_COMMAND} DEPENDS ${MANIFEST_LISTS} ${GENERATED_FILE_LISTS} ${MANIFEST_FILES} ${TEMPLATE_FILES} ) +endif() add_custom_target( manifest_tool