Merge pull request #13 from Patater/pubkey-format

Simplify RSA and EC public key formats
diff --git a/include/mbedtls/cipher_internal.h b/include/mbedtls/cipher_internal.h
index 6687b36..d711339 100644
--- a/include/mbedtls/cipher_internal.h
+++ b/include/mbedtls/cipher_internal.h
@@ -137,7 +137,7 @@
 typedef struct
 {
     psa_algorithm_t alg;
-    psa_key_slot_t slot;
+    psa_key_handle_t slot;
     mbedtls_cipher_psa_key_ownership slot_state;
 } mbedtls_cipher_context_psa;
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h
index 862065e..4f1b06f 100644
--- a/include/mbedtls/pk.h
+++ b/include/mbedtls/pk.h
@@ -273,7 +273,7 @@
  *                  ECC key pair.
  * \return          #MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure.
  */
-int mbedtls_pk_setup_opaque( mbedtls_pk_context *ctx, const psa_key_slot_t key );
+int mbedtls_pk_setup_opaque( mbedtls_pk_context *ctx, const psa_key_handle_t key );
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
 #if defined(MBEDTLS_PK_RSA_ALT_SUPPORT)
@@ -761,7 +761,7 @@
  * \return          An Mbed TLS error code otherwise.
  */
 int mbedtls_pk_wrap_as_opaque( mbedtls_pk_context *pk,
-                               psa_key_slot_t *slot,
+                               psa_key_handle_t *slot,
                                psa_algorithm_t hash_alg );
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
diff --git a/include/mbedtls/psa_util.h b/include/mbedtls/psa_util.h
index 5766133..a78c1a9 100644
--- a/include/mbedtls/psa_util.h
+++ b/include/mbedtls/psa_util.h
@@ -42,21 +42,6 @@
 #include "md.h"
 #include "pk.h"
 
-/* Slot allocation */
-
-static inline psa_status_t mbedtls_psa_get_free_key_slot( psa_key_slot_t *key )
-{
-    for( psa_key_slot_t slot = 1; slot <= 32; slot++ )
-    {
-        if( psa_get_key_information( slot, NULL, NULL ) == PSA_ERROR_EMPTY_SLOT )
-        {
-            *key = slot;
-            return( PSA_SUCCESS );
-        }
-    }
-    return( PSA_ERROR_INSUFFICIENT_MEMORY );
-}
-
 /* Translations for symmetric crypto. */
 
 static inline psa_key_type_t mbedtls_psa_translate_cipher_type(
@@ -231,6 +216,23 @@
     }
 }
 
+#define MBEDTLS_PSA_ECC_KEY_BITS_OF_CURVE( curve )                \
+    ( curve == PSA_ECC_CURVE_SECP192R1        ? 192 :             \
+      curve == PSA_ECC_CURVE_SECP224R1        ? 224 :             \
+      curve == PSA_ECC_CURVE_SECP256R1        ? 256 :             \
+      curve == PSA_ECC_CURVE_SECP384R1        ? 384 :             \
+      curve == PSA_ECC_CURVE_SECP521R1        ? 521 :             \
+      curve == PSA_ECC_CURVE_SECP192K1        ? 192 :             \
+      curve == PSA_ECC_CURVE_SECP224K1        ? 224 :             \
+      curve == PSA_ECC_CURVE_SECP256K1        ? 256 :             \
+      curve == PSA_ECC_CURVE_BRAINPOOL_P256R1 ? 256 :             \
+      curve == PSA_ECC_CURVE_BRAINPOOL_P384R1 ? 384 :             \
+      curve == PSA_ECC_CURVE_BRAINPOOL_P512R1 ? 512 :             \
+      0 )
+
+#define MBEDTLS_PSA_ECC_KEY_BYTES_OF_CURVE( curve )                \
+    ( ( MBEDTLS_PSA_ECC_KEY_BITS_OF_CURVE( curve ) + 7 ) / 8 )
+
 /* Translations for PK layer */
 
 static inline int mbedtls_psa_err_translate_pk( psa_status_t status )
@@ -259,6 +261,19 @@
     }
 }
 
+/* Translations for ECC */
+
+/* This function transforms an ECC group identifier from
+ * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
+ * into a PSA ECC group identifier. */
+static inline psa_ecc_curve_t mbedtls_psa_parse_tls_ecc_group(
+    uint16_t tls_ecc_grp_reg_id )
+{
+    /* The PSA identifiers are currently aligned with those from
+     * the TLS Supported Groups registry, so no conversion is necessary. */
+    return( (psa_ecc_curve_t) tls_ecc_grp_reg_id );
+}
+
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
 #endif /* MBEDTLS_PSA_UTIL_H */
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index f7c9d93..3e38f15 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -929,11 +929,11 @@
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
-    psa_key_slot_t psk_opaque; /*!< PSA key slot holding opaque PSK.
-                                *   This field should only be set via
-                                *   mbedtls_ssl_conf_psk_opaque().
-                                *   If either no PSK or a raw PSK have
-                                *   been configured, this has value \c 0. */
+    psa_key_handle_t psk_opaque; /*!< PSA key slot holding opaque PSK.
+                                  *   This field should only be set via
+                                  *   mbedtls_ssl_conf_psk_opaque().
+                                  *   If either no PSK or a raw PSK have
+                                  *   been configured, this has value \c 0. */
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
     unsigned char *psk;      /*!< The raw pre-shared key. This field should
@@ -2129,7 +2129,7 @@
  * \param psk      The identifier of the key slot holding the PSK.
  *                 Until \p conf is destroyed or this function is successfully
  *                 called again, the key slot \p psk must be populated with a
- *                 key of type #PSA_ALG_CATEGORY_KEY_DERIVATION whose policy
+ *                 key of type PSA_ALG_CATEGORY_KEY_DERIVATION whose policy
  *                 allows its use for the key derivation algorithm applied
  *                 in the handshake.
  * \param psk_identity      The pointer to the pre-shared key identity.
@@ -2144,7 +2144,7 @@
  * \return         An \c MBEDTLS_ERR_SSL_XXX error code on failure.
  */
 int mbedtls_ssl_conf_psk_opaque( mbedtls_ssl_config *conf,
-                                 psa_key_slot_t psk,
+                                 psa_key_handle_t psk,
                                  const unsigned char *psk_identity,
                                  size_t psk_identity_len );
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
@@ -2176,7 +2176,7 @@
  * \param psk      The identifier of the key slot holding the PSK.
  *                 For the duration of the current handshake, the key slot
  *                 must be populated with a key of type
- *                 #PSA_ALG_CATEGORY_KEY_DERIVATION whose policy allows its
+ *                 PSA_ALG_CATEGORY_KEY_DERIVATION whose policy allows its
  *                 use for the key derivation algorithm
  *                 applied in the handshake.
   *
@@ -2184,7 +2184,7 @@
  * \return         An \c MBEDTLS_ERR_SSL_XXX error code on failure.
  */
 int mbedtls_ssl_set_hs_psk_opaque( mbedtls_ssl_context *ssl,
-                                   psa_key_slot_t psk );
+                                   psa_key_handle_t psk );
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
 /**
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index 318d13f..fced2cb 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -284,7 +284,7 @@
 #endif
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
-    psa_key_slot_t psk_opaque;          /*!< Opaque PSK from the callback   */
+    psa_key_handle_t psk_opaque;        /*!< Opaque PSK from the callback   */
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
     unsigned char *psk;                 /*!<  PSK from the callback         */
     size_t psk_len;                     /*!<  Length of PSK from callback   */
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index d61c866..06f9eb8 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -124,14 +124,6 @@
  * application calls psa_close_key() or psa_destroy_key() or until the
  * application terminates.
  *
- * This function takes a key type and maximum size as arguments so that
- * the implementation can reserve a corresponding amount of memory.
- * Implementations are not required to enforce this limit: if the application
- * later tries to create a larger key or a key of a different type, it
- * is implementation-defined whether this may succeed.
- *
- * \param type          The type of key that the slot will contain.
- * \param max_bits      The maximum key size that the slot will contain.
  * \param[out] handle   On success, a handle to a volatile key slot.
  *
  * \retval #PSA_SUCCESS
@@ -140,13 +132,8 @@
  * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
  *         There was not enough memory, or the maximum number of key slots
  *         has been reached.
- * \retval #PSA_ERROR_INVALID_ARGUMENT
- *         This implementation does not support this key type.
  */
-
-psa_status_t psa_allocate_key(psa_key_type_t type,
-                              size_t max_bits,
-                              psa_key_handle_t *handle);
+psa_status_t psa_allocate_key(psa_key_handle_t *handle);
 
 /** Open a handle to an existing persistent key.
  *
@@ -192,8 +179,6 @@
  *                      area where the key material is stored. This must not
  *                      be #PSA_KEY_LIFETIME_VOLATILE.
  * \param id            The persistent identifier of the key.
- * \param type          The type of key that the slot will contain.
- * \param max_bits      The maximum key size that the slot will contain.
  * \param[out] handle   On success, a handle to the newly created key slot.
  *                      When key material is later created in this key slot,
  *                      it will be saved to the specified persistent location.
@@ -218,8 +203,6 @@
  */
 psa_status_t psa_create_key(psa_key_lifetime_t lifetime,
                             psa_key_id_t id,
-                            psa_key_type_t type,
-                            size_t max_bits,
                             psa_key_handle_t *handle);
 
 /** Close a key handle.
@@ -261,11 +244,9 @@
  * according to a different format.
  *
  * \param handle      Handle to the slot where the key will be stored.
- *                    This must be a valid slot for a key of the chosen
- *                    type: it must have been obtained by calling
- *                    psa_allocate_key() or psa_create_key() with the
- *                    correct \p type and with a maximum size that is
- *                    compatible with \p data.
+ *                    It must have been obtained by calling
+ *                    psa_allocate_key() or psa_create_key() and must
+ *                    not contain key material yet.
  * \param type        Key type (a \c PSA_KEY_TYPE_XXX value). On a successful
  *                    import, the key slot will contain a key of this type.
  * \param[in] data    Buffer containing the key data. The content of this
@@ -906,6 +887,33 @@
  */
 psa_status_t psa_hash_abort(psa_hash_operation_t *operation);
 
+/** Clone a hash operation.
+ *
+ * This function copies the state of an ongoing hash operation to
+ * a new operation object. In other words, this function is equivalent
+ * to calling psa_hash_setup() on \p target_operation with the same
+ * algorithm that \p source_operation was set up for, then
+ * psa_hash_update() on \p target_operation with the same input that
+ * that was passed to \p source_operation. After this function returns, the
+ * two objects are independent, i.e. subsequent calls involving one of
+ * the objects do not affect the other object.
+ *
+ * \param[in] source_operation      The active hash operation to clone.
+ * \param[in,out] target_operation  The operation object to set up.
+ *                                  It must be initialized but not active.
+ *
+ * \retval #PSA_SUCCESS
+ * \retval #PSA_ERROR_BAD_STATE
+ *         \p source_operation is not an active hash operation.
+ * \retval #PSA_ERROR_BAD_STATE
+ *         \p target_operation is active.
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE
+ * \retval #PSA_ERROR_HARDWARE_FAILURE
+ * \retval #PSA_ERROR_TAMPERING_DETECTED
+ */
+psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation,
+                            psa_hash_operation_t *target_operation);
+
 /**@}*/
 
 /** \defgroup MAC Message authentication codes
@@ -1990,12 +1998,9 @@
  * the key material is not exposed outside the isolation boundary.
  *
  * \param handle            Handle to the slot where the key will be stored.
- *                          This must be a valid slot for a key of the chosen
- *                          type: it must have been obtained by calling
- *                          psa_allocate_key() or psa_create_key() with the
- *                          correct \p type and with a maximum size that is
- *                          compatible with \p bits.
- *                          It must not contain any key material yet.
+ *                          It must have been obtained by calling
+ *                          psa_allocate_key() or psa_create_key() and must
+ *                          not contain key material yet.
  * \param type              Key type (a \c PSA_KEY_TYPE_XXX value).
  *                          This must be a symmetric key type.
  * \param bits              Key size in bits.
@@ -2226,12 +2231,9 @@
  * \brief Generate a key or key pair.
  *
  * \param handle            Handle to the slot where the key will be stored.
- *                          This must be a valid slot for a key of the chosen
- *                          type: it must have been obtained by calling
- *                          psa_allocate_key() or psa_create_key() with the
- *                          correct \p type and with a maximum size that is
- *                          compatible with \p bits.
- *                          It must not contain any key material yet.
+ *                          It must have been obtained by calling
+ *                          psa_allocate_key() or psa_create_key() and must
+ *                          not contain key material yet.
  * \param type              Key type (a \c PSA_KEY_TYPE_XXX value).
  * \param bits              Key size in bits.
  * \param[in] extra         Extra parameters for key generation. The
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 3a3f61b..3b56c44 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -103,6 +103,12 @@
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-declarations -Wmissing-prototypes -Wdocumentation -Wno-documentation-deprecated-sync -Wunreachable-code")
 endif(CMAKE_COMPILER_IS_CLANG)
 
+if(UNSAFE_BUILD)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error")
+    set(CMAKE_C_FLAGS_ASAN "${CMAKE_C_FLAGS_ASAN} -Wno-error")
+    set(CMAKE_C_FLAGS_ASANDBG "${CMAKE_C_FLAGS_ASANDBG} -Wno-error")
+endif(UNSAFE_BUILD)
+
 if(WIN32)
     set(libs ${libs} ws2_32)
 endif(WIN32)
diff --git a/library/cipher.c b/library/cipher.c
index 1cc0beb..03c0e06 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -302,12 +302,18 @@
         if( cipher_psa->slot_state != MBEDTLS_CIPHER_PSA_KEY_UNSET )
             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
 
-        /* Find a fresh key slot to use. */
-        status = mbedtls_psa_get_free_key_slot( &cipher_psa->slot );
+        key_type = mbedtls_psa_translate_cipher_type(
+            ctx->cipher_info->type );
+        if( key_type == 0 )
+            return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
+
+        /* Allocate a key slot to use. */
+        status = psa_allocate_key( key_type, key_bitlen, &cipher_psa->slot );
         if( status != PSA_SUCCESS )
             return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED );
-         /* Indicate that we own the key slot and need to
-          * destroy it in mbedtls_cipher_free(). */
+
+        /* Indicate that we own the key slot and need to
+         * destroy it in mbedtls_cipher_free(). */
         cipher_psa->slot_state = MBEDTLS_CIPHER_PSA_KEY_OWNED;
 
         /* From that point on, the responsibility for destroying the
@@ -330,10 +336,6 @@
             return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED );
 
         /* Populate new key slot. */
-        key_type = mbedtls_psa_translate_cipher_type(
-            ctx->cipher_info->type );
-        if( key_type == 0 )
-            return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
         status = psa_import_key( cipher_psa->slot,
                                  key_type, key, key_bytelen );
         if( status != PSA_SUCCESS )
diff --git a/library/pk.c b/library/pk.c
index 989ed09..024dcdc 100644
--- a/library/pk.c
+++ b/library/pk.c
@@ -147,10 +147,10 @@
 /*
  * Initialise a PSA-wrapping context
  */
-int mbedtls_pk_setup_opaque( mbedtls_pk_context *ctx, const psa_key_slot_t key )
+int mbedtls_pk_setup_opaque( mbedtls_pk_context *ctx, const psa_key_handle_t key )
 {
     const mbedtls_pk_info_t * const info = &mbedtls_pk_opaque_info;
-    psa_key_slot_t *pk_ctx;
+    psa_key_handle_t *pk_ctx;
     psa_key_type_t type;
 
     if( ctx == NULL || ctx->pk_info != NULL )
@@ -168,7 +168,7 @@
 
     ctx->pk_info = info;
 
-    pk_ctx = (psa_key_slot_t *) ctx->pk_ctx;
+    pk_ctx = (psa_key_handle_t *) ctx->pk_ctx;
     *pk_ctx = key;
 
     return( 0 );
@@ -547,13 +547,13 @@
  * Currently only works for EC private keys.
  */
 int mbedtls_pk_wrap_as_opaque( mbedtls_pk_context *pk,
-                               psa_key_slot_t *slot,
+                               psa_key_handle_t *slot,
                                psa_algorithm_t hash_alg )
 {
 #if !defined(MBEDTLS_ECP_C)
     return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
 #else
-    psa_key_slot_t key;
+    psa_key_handle_t key;
     const mbedtls_ecp_keypair *ec;
     unsigned char d[MBEDTLS_ECP_MAX_BYTES];
     size_t d_len;
@@ -572,9 +572,11 @@
         return( ret );
 
     curve_id = mbedtls_ecp_curve_info_from_grp_id( ec->grp.id )->tls_id;
+    key_type = PSA_KEY_TYPE_ECC_KEYPAIR(
+                                 mbedtls_psa_parse_tls_ecc_group ( curve_id ) );
 
-    /* find a free key slot */
-    if( PSA_SUCCESS != mbedtls_psa_get_free_key_slot( &key ) )
+    /* allocate a key slot */
+    if( PSA_SUCCESS != psa_allocate_key( key_type, d_len * 8, &key ) )
         return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED );
 
     /* set policy */
@@ -585,7 +587,6 @@
         return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED );
 
     /* import private key in slot */
-    key_type = PSA_KEY_TYPE_ECC_KEYPAIR(curve_id);
     if( PSA_SUCCESS != psa_import_key( key, key_type, d, d_len ) )
         return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED );
 
diff --git a/library/pk_wrap.c b/library/pk_wrap.c
index 6aacba8..08550d4 100644
--- a/library/pk_wrap.c
+++ b/library/pk_wrap.c
@@ -546,7 +546,7 @@
                        const unsigned char *sig, size_t sig_len )
 {
     int ret;
-    psa_key_slot_t key_slot;
+    psa_key_handle_t key_slot;
     psa_key_policy_t policy;
     psa_key_type_t psa_type;
     mbedtls_pk_context key;
@@ -571,15 +571,17 @@
     if( key_len <= 0 )
         return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
 
-    if( ( ret = mbedtls_psa_get_free_key_slot( &key_slot ) ) != PSA_SUCCESS )
-        return( mbedtls_psa_err_translate_pk( ret ) );
-
     psa_md = mbedtls_psa_translate_md( md_alg );
     if( psa_md == 0 )
         return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
     psa_sig_md = PSA_ALG_ECDSA( psa_md );
     psa_type = PSA_KEY_TYPE_ECC_PUBLIC_KEY( curve );
 
+    if( ( ret = psa_allocate_key( psa_type,
+                                  MBEDTLS_PSA_ECC_KEY_BITS_OF_CURVE(curve),
+                                  &key_slot ) ) != PSA_SUCCESS )
+          return( mbedtls_psa_err_translate_pk( ret ) );
+
     psa_key_policy_init( &policy );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_VERIFY, psa_sig_md );
     if( ( ret = psa_set_key_policy( key_slot, &policy ) ) != PSA_SUCCESS )
@@ -879,7 +881,7 @@
 
 static void *pk_opaque_alloc_wrap( void )
 {
-    void *ctx = mbedtls_calloc( 1, sizeof( psa_key_slot_t ) );
+    void *ctx = mbedtls_calloc( 1, sizeof( psa_key_handle_t ) );
 
     /* no _init() function to call, an calloc() already zeroized */
 
@@ -888,13 +890,13 @@
 
 static void pk_opaque_free_wrap( void *ctx )
 {
-    mbedtls_platform_zeroize( ctx, sizeof( psa_key_slot_t ) );
+    mbedtls_platform_zeroize( ctx, sizeof( psa_key_handle_t ) );
     mbedtls_free( ctx );
 }
 
 static size_t pk_opaque_get_bitlen( const void *ctx )
 {
-    const psa_key_slot_t *key = (const psa_key_slot_t *) ctx;
+    const psa_key_handle_t *key = (const psa_key_handle_t *) ctx;
     size_t bits;
 
     if( PSA_SUCCESS != psa_get_key_information( *key, NULL, &bits ) )
@@ -999,7 +1001,7 @@
                    unsigned char *sig, size_t *sig_len,
                    int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
 {
-    const psa_key_slot_t *key = (const psa_key_slot_t *) ctx;
+    const psa_key_handle_t *key = (const psa_key_handle_t *) ctx;
     psa_algorithm_t alg = PSA_ALG_ECDSA( mbedtls_psa_translate_md( md_alg ) );
     size_t bits, buf_len;
     psa_status_t status;
diff --git a/library/pkwrite.c b/library/pkwrite.c
index d34714b..11a2a61 100644
--- a/library/pkwrite.c
+++ b/library/pkwrite.c
@@ -168,7 +168,7 @@
     if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_OPAQUE )
     {
         size_t buffer_size;
-        psa_key_slot_t* key_slot = (psa_key_slot_t*) key->pk_ctx;
+        psa_key_handle_t* key_slot = (psa_key_handle_t*) key->pk_ctx;
 
         if ( *p < start )
             return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index bb53f81..58e82fa 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -27,15 +27,16 @@
 
 #if defined(MBEDTLS_PSA_CRYPTO_C)
 /*
- * In case MBEDTLS_PSA_CRYPTO_SPM is defined the code is built for SPM (Secure
- * Partition Manager) integration which separate the code into two parts
- * NSPE (Non-Secure Process Environment) and SPE (Secure Process Environment).
- * In this mode an additional header file should be included.
+ * When MBEDTLS_PSA_CRYPTO_SPM is defined, the code is being built for SPM
+ * (Secure Partition Manager) integration which separates the code into two
+ * parts: NSPE (Non-Secure Processing Environment) and SPE (Secure Processing
+ * Environment). When building for the SPE, an additional header file should be
+ * included.
  */
 #if defined(MBEDTLS_PSA_CRYPTO_SPM)
 /*
- * PSA_CRYPTO_SECURE means that this file is compiled to the SPE side.
- * some headers will be affected by this flag.
+ * PSA_CRYPTO_SECURE means that this file is compiled for the SPE.
+ * Some headers will be affected by this flag.
  */
 #define PSA_CRYPTO_SECURE 1
 #include "crypto_spe.h"
@@ -1475,6 +1476,67 @@
     return( PSA_SUCCESS );
 }
 
+psa_status_t psa_hash_clone( const psa_hash_operation_t *source_operation,
+                             psa_hash_operation_t *target_operation )
+{
+    if( target_operation->alg != 0 )
+        return( PSA_ERROR_BAD_STATE );
+
+    switch( source_operation->alg )
+    {
+        case 0:
+            return( PSA_ERROR_BAD_STATE );
+#if defined(MBEDTLS_MD2_C)
+        case PSA_ALG_MD2:
+            mbedtls_md2_clone( &target_operation->ctx.md2,
+                               &source_operation->ctx.md2 );
+            break;
+#endif
+#if defined(MBEDTLS_MD4_C)
+        case PSA_ALG_MD4:
+            mbedtls_md4_clone( &target_operation->ctx.md4,
+                               &source_operation->ctx.md4 );
+            break;
+#endif
+#if defined(MBEDTLS_MD5_C)
+        case PSA_ALG_MD5:
+            mbedtls_md5_clone( &target_operation->ctx.md5,
+                               &source_operation->ctx.md5 );
+            break;
+#endif
+#if defined(MBEDTLS_RIPEMD160_C)
+        case PSA_ALG_RIPEMD160:
+            mbedtls_ripemd160_clone( &target_operation->ctx.ripemd160,
+                                     &source_operation->ctx.ripemd160 );
+            break;
+#endif
+#if defined(MBEDTLS_SHA1_C)
+        case PSA_ALG_SHA_1:
+            mbedtls_sha1_clone( &target_operation->ctx.sha1,
+                                &source_operation->ctx.sha1 );
+            break;
+#endif
+#if defined(MBEDTLS_SHA256_C)
+        case PSA_ALG_SHA_224:
+        case PSA_ALG_SHA_256:
+            mbedtls_sha256_clone( &target_operation->ctx.sha256,
+                                  &source_operation->ctx.sha256 );
+            break;
+#endif
+#if defined(MBEDTLS_SHA512_C)
+        case PSA_ALG_SHA_384:
+        case PSA_ALG_SHA_512:
+            mbedtls_sha512_clone( &target_operation->ctx.sha512,
+                                  &source_operation->ctx.sha512 );
+            break;
+#endif
+        default:
+            return( PSA_ERROR_NOT_SUPPORTED );
+    }
+
+    target_operation->alg = source_operation->alg;
+    return( PSA_SUCCESS );
+}
 
 
 /****************************************************************/
diff --git a/library/psa_crypto_slot_management.c b/library/psa_crypto_slot_management.c
index 0b4399f..c151c5e 100644
--- a/library/psa_crypto_slot_management.c
+++ b/library/psa_crypto_slot_management.c
@@ -26,6 +26,21 @@
 #endif
 
 #if defined(MBEDTLS_PSA_CRYPTO_C)
+/*
+ * When MBEDTLS_PSA_CRYPTO_SPM is defined, the code is being built for SPM
+ * (Secure Partition Manager) integration which separates the code into two
+ * parts: NSPE (Non-Secure Processing Environment) and SPE (Secure Processing
+ * Environment). When building for the SPE, an additional header file should be
+ * included.
+ */
+#if defined(MBEDTLS_PSA_CRYPTO_SPM)
+/*
+ * PSA_CRYPTO_SECURE means that this file is compiled for the SPE.
+ * Some headers will be affected by this flag.
+ */
+#define PSA_CRYPTO_SECURE 1
+#include "crypto_spe.h"
+#endif
 
 #include "psa/crypto.h"
 
@@ -142,13 +157,8 @@
     return( psa_wipe_key_slot( slot ) );
 }
 
-psa_status_t psa_allocate_key( psa_key_type_t type,
-                               size_t max_bits,
-                               psa_key_handle_t *handle )
+psa_status_t psa_allocate_key( psa_key_handle_t *handle )
 {
-    /* This implementation doesn't reserve memory for the keys. */
-    (void) type;
-    (void) max_bits;
     *handle = 0;
     return( psa_internal_allocate_key_slot( handle ) );
 }
@@ -259,16 +269,10 @@
 
 psa_status_t psa_create_key( psa_key_lifetime_t lifetime,
                              psa_key_id_t id,
-                             psa_key_type_t type,
-                             size_t max_bits,
                              psa_key_handle_t *handle )
 {
     psa_status_t status;
 
-    /* This implementation doesn't reserve memory for the keys. */
-    (void) type;
-    (void) max_bits;
-
     status = persistent_key_setup( lifetime, id, handle,
                                    PSA_ERROR_EMPTY_SLOT );
     switch( status )
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index d14434a..8fe9314 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -798,7 +798,7 @@
             psa_status_t status;
             psa_algorithm_t alg;
             psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT;
-            psa_key_slot_t psk;
+            psa_key_handle_t psk;
 
             MBEDTLS_SSL_DEBUG_MSG( 2, ( "perform PSA-based PSK-to-MS expansion" ) );
 
@@ -7617,7 +7617,7 @@
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
 int mbedtls_ssl_conf_psk_opaque( mbedtls_ssl_config *conf,
-                                 psa_key_slot_t psk_slot,
+                                 psa_key_handle_t psk_slot,
                                  const unsigned char *psk_identity,
                                  size_t psk_identity_len )
 {
@@ -7640,7 +7640,7 @@
 }
 
 int mbedtls_ssl_set_hs_psk_opaque( mbedtls_ssl_context *ssl,
-                                   psa_key_slot_t psk_slot )
+                                   psa_key_handle_t psk_slot )
 {
     if( psk_slot == 0 || ssl->handshake == NULL )
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
diff --git a/programs/psa/crypto_examples.c b/programs/psa/crypto_examples.c
index db85468..7291c34 100644
--- a/programs/psa/crypto_examples.c
+++ b/programs/psa/crypto_examples.c
@@ -176,7 +176,7 @@
     status = psa_generate_random( input, sizeof( input ) );
     ASSERT_STATUS( status, PSA_SUCCESS );
 
-    status = psa_allocate_key( PSA_KEY_TYPE_AES, key_bits, &key_handle );
+    status = psa_allocate_key( &key_handle );
     ASSERT_STATUS( status, PSA_SUCCESS );
 
     status = set_key_policy( key_handle,
@@ -226,7 +226,7 @@
     status = psa_generate_random( input, sizeof( input ) );
     ASSERT_STATUS( status, PSA_SUCCESS );
 
-    status = psa_allocate_key( PSA_KEY_TYPE_AES, key_bits, &key_handle );
+    status = psa_allocate_key( &key_handle );
     ASSERT_STATUS( status, PSA_SUCCESS );
 
     status = set_key_policy( key_handle,
@@ -275,7 +275,7 @@
     status = psa_generate_random( input, sizeof( input ) );
     ASSERT_STATUS( status, PSA_SUCCESS );
 
-    status = psa_allocate_key( PSA_KEY_TYPE_AES, key_bits, &key_handle );
+    status = psa_allocate_key( &key_handle );
     ASSERT_STATUS( status, PSA_SUCCESS );
     status = set_key_policy( key_handle,
                              PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT,
diff --git a/programs/psa/key_ladder_demo.c b/programs/psa/key_ladder_demo.c
index 66f66fc..45a9b6f 100644
--- a/programs/psa/key_ladder_demo.c
+++ b/programs/psa/key_ladder_demo.c
@@ -211,9 +211,7 @@
     psa_key_handle_t key_handle = 0;
     psa_key_policy_t policy = PSA_KEY_POLICY_INIT;
 
-    PSA_CHECK( psa_allocate_key( PSA_KEY_TYPE_DERIVE,
-                                 PSA_BYTES_TO_BITS( KEY_SIZE_BYTES ),
-                                 &key_handle ) );
+    PSA_CHECK( psa_allocate_key( &key_handle ) );
     psa_key_policy_set_usage( &policy,
                               PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT,
                               KDF_ALG );
@@ -263,9 +261,7 @@
     SYS_CHECK( fclose( key_file ) == 0 );
     key_file = NULL;
 
-    PSA_CHECK( psa_allocate_key( PSA_KEY_TYPE_DERIVE,
-                                 PSA_BYTES_TO_BITS( key_size ),
-                                 master_key_handle ) );
+    PSA_CHECK( psa_allocate_key( master_key_handle ) );
     psa_key_policy_set_usage( &policy, usage, alg );
     PSA_CHECK( psa_set_key_policy( *master_key_handle, &policy ) );
     PSA_CHECK( psa_import_key( *master_key_handle,
@@ -318,9 +314,7 @@
          * since it is no longer needed. */
         PSA_CHECK( psa_close_key( *key_handle ) );
         *key_handle = 0;
-        PSA_CHECK( psa_allocate_key( PSA_KEY_TYPE_DERIVE,
-                                     PSA_BYTES_TO_BITS( KEY_SIZE_BYTES ),
-                                     key_handle ) );
+        PSA_CHECK( psa_allocate_key( key_handle ) );
         PSA_CHECK( psa_set_key_policy( *key_handle, &policy ) );
         /* Use the generator obtained from the parent key to create
          * the next intermediate key. */
@@ -352,8 +346,7 @@
     psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT;
 
     *wrapping_key_handle = 0;
-    PSA_CHECK( psa_allocate_key( PSA_KEY_TYPE_AES, WRAPPING_KEY_BITS,
-                                 wrapping_key_handle ) );
+    PSA_CHECK( psa_allocate_key( wrapping_key_handle ) );
     psa_key_policy_set_usage( &policy, usage, WRAPPING_ALG );
     PSA_CHECK( psa_set_key_policy( *wrapping_key_handle, &policy ) );
 
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index a98a3a2..a8c16dc 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -571,7 +571,7 @@
     const char *pers = "ssl_client2";
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
-    psa_key_slot_t slot = 0;
+    psa_key_handle_t slot = 0;
     psa_algorithm_t alg = 0;
     psa_key_policy_t policy;
     psa_status_t status;
@@ -594,7 +594,7 @@
     mbedtls_x509_crt clicert;
     mbedtls_pk_context pkey;
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
-    psa_key_slot_t key_slot = 0; /* invalid key slot */
+    psa_key_handle_t key_slot = 0; /* invalid key slot */
 #endif
 #endif
     char *p, *q;
@@ -1594,7 +1594,7 @@
     if( opt.psk_opaque != 0 )
     {
         /* The algorithm has already been determined earlier. */
-        status = mbedtls_psa_get_free_key_slot( &slot );
+        status = psa_allocate_key( PSA_KEY_TYPE_DERIVE, psk_len * 8, &slot );
         if( status != PSA_SUCCESS )
         {
             ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 534a3f3..8b3b9cd 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -806,7 +806,7 @@
     size_t key_len;
     unsigned char key[MBEDTLS_PSK_MAX_LEN];
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
-    psa_key_slot_t slot;
+    psa_key_handle_t slot;
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
     psk_entry *next;
 };
@@ -822,7 +822,7 @@
     {
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
         psa_status_t status;
-        psa_key_slot_t const slot = head->slot;
+        psa_key_handle_t const slot = head->slot;
 
         if( slot != 0 )
         {
@@ -1231,7 +1231,7 @@
 }
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
-static psa_status_t psa_setup_psk_key_slot( psa_key_slot_t slot,
+static psa_status_t psa_setup_psk_key_slot( psa_key_handle_t slot,
                                             psa_algorithm_t alg,
                                             unsigned char *psk,
                                             size_t psk_len )
@@ -1268,7 +1268,7 @@
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     psa_algorithm_t alg = 0;
-    psa_key_slot_t psk_slot = 0;
+    psa_key_handle_t psk_slot = 0;
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
     unsigned char psk[MBEDTLS_PSK_MAX_LEN];
     size_t psk_len = 0;
@@ -2667,7 +2667,7 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
         if( opt.psk_opaque != 0 )
         {
-            status = mbedtls_psa_get_free_key_slot( &psk_slot );
+            status = psa_allocate_key( PSA_KEY_TYPE_DERIVE, psk_len * 8, &psk_slot );
             if( status != PSA_SUCCESS )
             {
                 fprintf( stderr, "ALLOC FAIL\n" );
@@ -2711,7 +2711,7 @@
             psk_entry *cur_psk;
             for( cur_psk = psk_info; cur_psk != NULL; cur_psk = cur_psk->next )
             {
-                status = mbedtls_psa_get_free_key_slot( &cur_psk->slot );
+                status = psa_allocate_key( PSA_KEY_TYPE_DERIVE, cur_psk->key_len * 8, &cur_psk->slot );
                 if( status != PSA_SUCCESS )
                 {
                     ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 43f1db6..11d10a3 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -55,21 +55,46 @@
 # Notes for maintainers
 # ---------------------
 #
+# The bulk of the code is organized into functions that follow one of the
+# following naming conventions:
+#  * pre_XXX: things to do before running the tests, in order.
+#  * component_XXX: independent components. They can be run in any order.
+#      * component_check_XXX: quick tests that aren't worth parallelizing.
+#      * component_build_XXX: build things but don't run them.
+#      * component_test_XXX: build and test.
+#  * support_XXX: if support_XXX exists and returns false then
+#    component_XXX is not run by default.
+#  * post_XXX: things to do after running the tests.
+#  * other: miscellaneous support functions.
+#
+# Each component must start by invoking `msg` with a short informative message.
+#
+# The framework performs some cleanup tasks after each component. This
+# means that components can assume that the working directory is in a
+# cleaned-up state, and don't need to perform the cleanup themselves.
+# * Run `make clean`.
+# * Restore `include/mbedtks/config.h` from a backup made before running
+#   the component.
+# * Check out `Makefile`, `library/Makefile`, `programs/Makefile` and
+#   `tests/Makefile` from git. This cleans up after an in-tree use of
+#   CMake.
+#
+# Any command that is expected to fail must be protected so that the
+# script keeps running in --keep-going mode despite `set -e`. In keep-going
+# mode, if a protected command fails, this is logged as a failure and the
+# script will exit with a failure status once it has run all components.
+# Commands can be protected in any of the following ways:
+# * `make` is a function which runs the `make` command with protection.
+#   Note that you must write `make VAR=value`, not `VAR=value make`,
+#   because the `VAR=value make` syntax doesn't work with functions.
+# * Put `report_status` before the command to protect it.
+# * Put `if_build_successful` before a command. This protects it, and
+#   additionally skips it if a prior invocation of `make` in the same
+#   component failed.
+#
 # The tests are roughly in order from fastest to slowest. This doesn't
 # have to be exact, but in general you should add slower tests towards
 # the end and fast checks near the beginning.
-#
-# Sanity checks have the following form:
-#   1. msg "short description of what is about to be done"
-#   2. run sanity check (failure stops the script)
-#
-# Build or build-and-test steps have the following form:
-#   1. msg "short description of what is about to be done"
-#   2. cleanup
-#   3. preparation (config.pl, cmake, ...) (failure stops the script)
-#   4. make
-#   5. Run tests if relevant. All tests must be prefixed with
-#      if_build_successful for the sake of --keep-going.
 
 
 
@@ -80,50 +105,93 @@
 # Abort on errors (and uninitialised variables)
 set -eu
 
-if [ "$( uname )" != "Linux" ]; then
-    echo "This script only works in Linux" >&2
-    exit 1
-elif [ -d library -a -d include -a -d tests ]; then :; else
-    echo "Must be run from mbed TLS root" >&2
-    exit 1
-fi
+pre_check_environment () {
+    if [ -d library -a -d include -a -d tests ]; then :; else
+        echo "Must be run from mbed TLS root" >&2
+        exit 1
+    fi
+}
 
-CONFIG_H='include/mbedtls/config.h'
-CONFIG_BAK="$CONFIG_H.bak"
+pre_initialize_variables () {
+    CONFIG_H='include/mbedtls/config.h'
+    CONFIG_BAK="$CONFIG_H.bak"
 
-MEMORY=0
-FORCE=0
-KEEP_GOING=0
-RUN_ARMCC=1
+    MEMORY=0
+    FORCE=0
+    KEEP_GOING=0
 
-# Default commands, can be overriden by the environment
-: ${OPENSSL:="openssl"}
-: ${OPENSSL_LEGACY:="$OPENSSL"}
-: ${OPENSSL_NEXT:="$OPENSSL"}
-: ${GNUTLS_CLI:="gnutls-cli"}
-: ${GNUTLS_SERV:="gnutls-serv"}
-: ${GNUTLS_LEGACY_CLI:="$GNUTLS_CLI"}
-: ${GNUTLS_LEGACY_SERV:="$GNUTLS_SERV"}
-: ${OUT_OF_SOURCE_DIR:=./mbedtls_out_of_source_build}
-: ${ARMC5_BIN_DIR:=/usr/bin}
-: ${ARMC6_BIN_DIR:=/usr/bin}
+    # Default commands, can be overriden by the environment
+    : ${OPENSSL:="openssl"}
+    : ${OPENSSL_LEGACY:="$OPENSSL"}
+    : ${OPENSSL_NEXT:="$OPENSSL"}
+    : ${GNUTLS_CLI:="gnutls-cli"}
+    : ${GNUTLS_SERV:="gnutls-serv"}
+    : ${GNUTLS_LEGACY_CLI:="$GNUTLS_CLI"}
+    : ${GNUTLS_LEGACY_SERV:="$GNUTLS_SERV"}
+    : ${OUT_OF_SOURCE_DIR:=./mbedtls_out_of_source_build}
+    : ${ARMC5_BIN_DIR:=/usr/bin}
+    : ${ARMC6_BIN_DIR:=/usr/bin}
 
-# if MAKEFLAGS is not set add the -j option to speed up invocations of make
-if [ -n "${MAKEFLAGS+set}" ]; then
-    export MAKEFLAGS="-j"
-fi
+    # if MAKEFLAGS is not set add the -j option to speed up invocations of make
+    if [ -z "${MAKEFLAGS+set}" ]; then
+        export MAKEFLAGS="-j"
+    fi
+
+    # Gather the list of available components. These are the functions
+    # defined in this script whose name starts with "component_".
+    # Parse the script with sed, because in sh there is no way to list
+    # defined functions.
+    ALL_COMPONENTS=$(sed -n 's/^ *component_\([0-9A-Z_a-z]*\) *().*/\1/p' <"$0")
+
+    # Exclude components that are not supported on this platform.
+    SUPPORTED_COMPONENTS=
+    for component in $ALL_COMPONENTS; do
+        case $(type "support_$component" 2>&1) in
+            *' function'*)
+                if ! support_$component; then continue; fi;;
+        esac
+        SUPPORTED_COMPONENTS="$SUPPORTED_COMPONENTS $component"
+    done
+}
+
+# Test whether the component $1 is included in the command line patterns.
+is_component_included()
+{
+    set -f
+    for pattern in $COMMAND_LINE_COMPONENTS; do
+        set +f
+        case ${1#component_} in $pattern) return 0;; esac
+    done
+    set +f
+    return 1
+}
 
 usage()
 {
     cat <<EOF
-Usage: $0 [OPTION]...
-  -h|--help             Print this help.
+Usage: $0 [OPTION]... [COMPONENT]...
+Run mbedtls release validation tests.
+By default, run all tests. With one or more COMPONENT, run only those.
+COMPONENT can be the name of a component or a shell wildcard pattern.
+
+Examples:
+  $0 "check_*"
+    Run all sanity checks.
+  $0 --no-armcc --except test_memsan
+    Run everything except builds that require armcc and MemSan.
+
+Special options:
+  -h|--help             Print this help and exit.
+  --list-all-components List all available test components and exit.
+  --list-components     List components supported on this platform and exit.
 
 General options:
   -f|--force            Force the tests to overwrite any modified files.
   -k|--keep-going       Run all tests and report errors at the end.
   -m|--memory           Additional optional memory tests.
      --armcc            Run ARM Compiler builds (on by default).
+     --except           Exclude the COMPONENTs listed on the command line,
+                        instead of running only those.
      --no-armcc         Skip ARM Compiler builds.
      --no-force         Refuse to overwrite modified files (default).
      --no-keep-going    Stop at the first error (default).
@@ -189,25 +257,27 @@
 
 msg()
 {
+    if [ -n "${current_component:-}" ]; then
+        current_section="${current_component#component_}: $1"
+    else
+        current_section="$1"
+    fi
     echo ""
     echo "******************************************************************"
-    echo "* $1 "
+    echo "* $current_section "
     printf "* "; date
     echo "******************************************************************"
-    current_section=$1
 }
 
-if [ $RUN_ARMCC -ne 0 ]; then
-    armc6_build_test()
-    {
-        FLAGS="$1"
+armc6_build_test()
+{
+    FLAGS="$1"
 
-        msg "build: ARM Compiler 6 ($FLAGS), make"
-        ARM_TOOL_VARIANT="ult" CC="$ARMC6_CC" AR="$ARMC6_AR" CFLAGS="$FLAGS" \
-                        WARNING_CFLAGS='-xc -std=c99' make lib
-        make clean
-    }
-fi
+    msg "build: ARM Compiler 6 ($FLAGS), make"
+    ARM_TOOL_VARIANT="ult" CC="$ARMC6_CC" AR="$ARMC6_AR" CFLAGS="$FLAGS" \
+                    WARNING_CFLAGS='-xc -std=c99' make lib
+    make clean
+}
 
 err_msg()
 {
@@ -232,61 +302,95 @@
     rm headers.txt
 }
 
-while [ $# -gt 0 ]; do
-    case "$1" in
-        --armcc) RUN_ARMCC=1;;
-        --armc5-bin-dir) shift; ARMC5_BIN_DIR="$1";;
-        --armc6-bin-dir) shift; ARMC6_BIN_DIR="$1";;
-        --force|-f) FORCE=1;;
-        --gnutls-cli) shift; GNUTLS_CLI="$1";;
-        --gnutls-legacy-cli) shift; GNUTLS_LEGACY_CLI="$1";;
-        --gnutls-legacy-serv) shift; GNUTLS_LEGACY_SERV="$1";;
-        --gnutls-serv) shift; GNUTLS_SERV="$1";;
-        --help|-h) usage; exit;;
-        --keep-going|-k) KEEP_GOING=1;;
-        --memory|-m) MEMORY=1;;
-        --no-armcc) RUN_ARMCC=0;;
-        --no-force) FORCE=0;;
-        --no-keep-going) KEEP_GOING=0;;
-        --no-memory) MEMORY=0;;
-        --openssl) shift; OPENSSL="$1";;
-        --openssl-legacy) shift; OPENSSL_LEGACY="$1";;
-        --openssl-next) shift; OPENSSL_NEXT="$1";;
-        --out-of-source-dir) shift; OUT_OF_SOURCE_DIR="$1";;
-        --random-seed) unset SEED;;
-        --release-test|-r) SEED=1;;
-        --seed|-s) shift; SEED="$1";;
-        *)
-            echo >&2 "Unknown option: $1"
-            echo >&2 "Run $0 --help for usage."
-            exit 120
-            ;;
-    esac
-    shift
-done
+pre_parse_command_line () {
+    COMMAND_LINE_COMPONENTS=
+    all_except=0
+    no_armcc=
 
-if [ $FORCE -eq 1 ]; then
-    git checkout-index -f -q $CONFIG_H
-    cleanup
-else
+    while [ $# -gt 0 ]; do
+        case "$1" in
+            --armcc) no_armcc=;;
+            --armc5-bin-dir) shift; ARMC5_BIN_DIR="$1";;
+            --armc6-bin-dir) shift; ARMC6_BIN_DIR="$1";;
+            --except) all_except=1;;
+            --force|-f) FORCE=1;;
+            --gnutls-cli) shift; GNUTLS_CLI="$1";;
+            --gnutls-legacy-cli) shift; GNUTLS_LEGACY_CLI="$1";;
+            --gnutls-legacy-serv) shift; GNUTLS_LEGACY_SERV="$1";;
+            --gnutls-serv) shift; GNUTLS_SERV="$1";;
+            --help|-h) usage; exit;;
+            --keep-going|-k) KEEP_GOING=1;;
+            --list-all-components) printf '%s\n' $ALL_COMPONENTS; exit;;
+            --list-components) printf '%s\n' $SUPPORTED_COMPONENTS; exit;;
+            --memory|-m) MEMORY=1;;
+            --no-armcc) no_armcc=1;;
+            --no-force) FORCE=0;;
+            --no-keep-going) KEEP_GOING=0;;
+            --no-memory) MEMORY=0;;
+            --openssl) shift; OPENSSL="$1";;
+            --openssl-legacy) shift; OPENSSL_LEGACY="$1";;
+            --openssl-next) shift; OPENSSL_NEXT="$1";;
+            --out-of-source-dir) shift; OUT_OF_SOURCE_DIR="$1";;
+            --random-seed) unset SEED;;
+            --release-test|-r) SEED=1;;
+            --seed|-s) shift; SEED="$1";;
+            -*)
+                echo >&2 "Unknown option: $1"
+                echo >&2 "Run $0 --help for usage."
+                exit 120
+                ;;
+            *) COMMAND_LINE_COMPONENTS="$COMMAND_LINE_COMPONENTS $1";;
+        esac
+        shift
+    done
 
-    if [ -d "$OUT_OF_SOURCE_DIR" ]; then
-        echo "Warning - there is an existing directory at '$OUT_OF_SOURCE_DIR'" >&2
-        echo "You can either delete this directory manually, or force the test by rerunning"
-        echo "the script as: $0 --force --out-of-source-dir $OUT_OF_SOURCE_DIR"
-        exit 1
+    # With no list of components, run everything.
+    if [ -z "$COMMAND_LINE_COMPONENTS" ]; then
+        all_except=1
     fi
 
-    if ! git diff-files --quiet include/mbedtls/config.h; then
-        err_msg "Warning - the configuration file 'include/mbedtls/config.h' has been edited. "
-        echo "You can either delete or preserve your work, or force the test by rerunning the"
-        echo "script as: $0 --force"
-        exit 1
+    # --no-armcc is a legacy option. The modern way is --except '*_armcc*'.
+    # Ignore it if components are listed explicitly on the command line.
+    if [ -n "$no_armcc" ] && [ $all_except -eq 1 ]; then
+        COMMAND_LINE_COMPONENTS="$COMMAND_LINE_COMPONENTS *_armcc*"
     fi
-fi
 
-build_status=0
-if [ $KEEP_GOING -eq 1 ]; then
+    # Build the list of components to run.
+    RUN_COMPONENTS=
+    for component in $SUPPORTED_COMPONENTS; do
+        if is_component_included "$component"; [ $? -eq $all_except ]; then
+            RUN_COMPONENTS="$RUN_COMPONENTS $component"
+        fi
+    done
+
+    unset all_except
+    unset no_armcc
+}
+
+pre_check_git () {
+    if [ $FORCE -eq 1 ]; then
+        rm -rf "$OUT_OF_SOURCE_DIR"
+        git checkout-index -f -q $CONFIG_H
+        cleanup
+    else
+
+        if [ -d "$OUT_OF_SOURCE_DIR" ]; then
+            echo "Warning - there is an existing directory at '$OUT_OF_SOURCE_DIR'" >&2
+            echo "You can either delete this directory manually, or force the test by rerunning"
+            echo "the script as: $0 --force --out-of-source-dir $OUT_OF_SOURCE_DIR"
+            exit 1
+        fi
+
+        if ! git diff --quiet include/mbedtls/config.h; then
+            err_msg "Warning - the configuration file 'include/mbedtls/config.h' has been edited. "
+            echo "You can either delete or preserve your work, or force the test by rerunning the"
+            echo "script as: $0 --force"
+            exit 1
+        fi
+    fi
+}
+
+pre_setup_keep_going () {
     failure_summary=
     failure_count=0
     start_red=
@@ -340,11 +444,8 @@
             echo "Killed by SIG$1."
         fi
     }
-else
-    record_status () {
-        "$@"
-    }
-fi
+}
+
 if_build_succeeded () {
     if [ $build_status -eq 0 ]; then
         record_status "$@"
@@ -357,44 +458,84 @@
     ! "$@"
 }
 
-msg "info: $0 configuration"
-echo "MEMORY: $MEMORY"
-echo "FORCE: $FORCE"
-echo "SEED: ${SEED-"UNSET"}"
-echo "OPENSSL: $OPENSSL"
-echo "OPENSSL_LEGACY: $OPENSSL_LEGACY"
-echo "OPENSSL_NEXT: $OPENSSL_NEXT"
-echo "GNUTLS_CLI: $GNUTLS_CLI"
-echo "GNUTLS_SERV: $GNUTLS_SERV"
-echo "GNUTLS_LEGACY_CLI: $GNUTLS_LEGACY_CLI"
-echo "GNUTLS_LEGACY_SERV: $GNUTLS_LEGACY_SERV"
-echo "ARMC5_BIN_DIR: $ARMC5_BIN_DIR"
-echo "ARMC6_BIN_DIR: $ARMC6_BIN_DIR"
-
-ARMC5_CC="$ARMC5_BIN_DIR/armcc"
-ARMC5_AR="$ARMC5_BIN_DIR/armar"
-ARMC6_CC="$ARMC6_BIN_DIR/armclang"
-ARMC6_AR="$ARMC6_BIN_DIR/armar"
-
-# To avoid setting OpenSSL and GnuTLS for each call to compat.sh and ssl-opt.sh
-# we just export the variables they require
-export OPENSSL_CMD="$OPENSSL"
-export GNUTLS_CLI="$GNUTLS_CLI"
-export GNUTLS_SERV="$GNUTLS_SERV"
-
-# Avoid passing --seed flag in every call to ssl-opt.sh
-if [ -n "${SEED-}" ]; then
-  export SEED
-fi
+pre_print_configuration () {
+    msg "info: $0 configuration"
+    echo "MEMORY: $MEMORY"
+    echo "FORCE: $FORCE"
+    echo "SEED: ${SEED-"UNSET"}"
+    echo "OPENSSL: $OPENSSL"
+    echo "OPENSSL_LEGACY: $OPENSSL_LEGACY"
+    echo "OPENSSL_NEXT: $OPENSSL_NEXT"
+    echo "GNUTLS_CLI: $GNUTLS_CLI"
+    echo "GNUTLS_SERV: $GNUTLS_SERV"
+    echo "GNUTLS_LEGACY_CLI: $GNUTLS_LEGACY_CLI"
+    echo "GNUTLS_LEGACY_SERV: $GNUTLS_LEGACY_SERV"
+    echo "ARMC5_BIN_DIR: $ARMC5_BIN_DIR"
+    echo "ARMC6_BIN_DIR: $ARMC6_BIN_DIR"
+}
 
 # Make sure the tools we need are available.
-check_tools "$OPENSSL" "$OPENSSL_LEGACY" "$OPENSSL_NEXT" \
-            "$GNUTLS_CLI" "$GNUTLS_SERV" \
-            "$GNUTLS_LEGACY_CLI" "$GNUTLS_LEGACY_SERV" "doxygen" "dot" \
-            "arm-none-eabi-gcc" "i686-w64-mingw32-gcc" "gdb"
-if [ $RUN_ARMCC -ne 0 ]; then
-    check_tools "$ARMC5_CC" "$ARMC5_AR" "$ARMC6_CC" "$ARMC6_AR"
-fi
+pre_check_tools () {
+    # Build the list of variables to pass to output_env.sh.
+    set env
+
+    case " $RUN_COMPONENTS " in
+        # Require OpenSSL and GnuTLS if running any tests (as opposed to
+        # only doing builds). Not all tests run OpenSSL and GnuTLS, but this
+        # is a good enough approximation in practice.
+        *" test_"*)
+            # To avoid setting OpenSSL and GnuTLS for each call to compat.sh
+            # and ssl-opt.sh, we just export the variables they require.
+            export OPENSSL_CMD="$OPENSSL"
+            export GNUTLS_CLI="$GNUTLS_CLI"
+            export GNUTLS_SERV="$GNUTLS_SERV"
+            # Avoid passing --seed flag in every call to ssl-opt.sh
+            if [ -n "${SEED-}" ]; then
+                export SEED
+            fi
+            set "$@" OPENSSL="$OPENSSL" OPENSSL_LEGACY="$OPENSSL_LEGACY"
+            set "$@" GNUTLS_CLI="$GNUTLS_CLI" GNUTLS_SERV="$GNUTLS_SERV"
+            set "$@" GNUTLS_LEGACY_CLI="$GNUTLS_LEGACY_CLI"
+            set "$@" GNUTLS_LEGACY_SERV="$GNUTLS_LEGACY_SERV"
+            check_tools "$OPENSSL" "$OPENSSL_LEGACY" "$OPENSSL_NEXT" \
+                        "$GNUTLS_CLI" "$GNUTLS_SERV" \
+                        "$GNUTLS_LEGACY_CLI" "$GNUTLS_LEGACY_SERV"
+            ;;
+    esac
+
+    case " $RUN_COMPONENTS " in
+        *_doxygen[_\ ]*) check_tools "doxygen" "dot";;
+    esac
+
+    case " $RUN_COMPONENTS " in
+        *_arm_none_eabi_gcc[_\ ]*) check_tools "arm-none-eabi-gcc";;
+    esac
+
+    case " $RUN_COMPONENTS " in
+        *_mingw[_\ ]*) check_tools "i686-w64-mingw32-gcc";;
+    esac
+
+    case " $RUN_COMPONENTS " in
+        *" test_zeroize "*) check_tools "gdb";;
+    esac
+
+    case " $RUN_COMPONENTS " in
+        *_armcc*)
+            ARMC5_CC="$ARMC5_BIN_DIR/armcc"
+            ARMC5_AR="$ARMC5_BIN_DIR/armar"
+            ARMC6_CC="$ARMC6_BIN_DIR/armclang"
+            ARMC6_AR="$ARMC6_BIN_DIR/armar"
+            check_tools "$ARMC5_CC" "$ARMC5_AR" "$ARMC6_CC" "$ARMC6_AR";;
+    esac
+
+    msg "info: output_env.sh"
+    case $RUN_COMPONENTS in
+        *_armcc*)
+            set "$@" ARMC5_CC="$ARMC5_CC" ARMC6_CC="$ARMC6_CC" RUN_ARMCC=1;;
+        *) set "$@" RUN_ARMCC=0;;
+    esac
+    "$@" scripts/output_env.sh
+}
 
 
 
@@ -413,516 +554,533 @@
 #
 # Indicative running times are given for reference.
 
-msg "info: output_env.sh"
-OPENSSL="$OPENSSL" OPENSSL_LEGACY="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_CLI" \
-    GNUTLS_SERV="$GNUTLS_SERV" GNUTLS_LEGACY_CLI="$GNUTLS_LEGACY_CLI" \
-    GNUTLS_LEGACY_SERV="$GNUTLS_LEGACY_SERV" ARMC5_CC="$ARMC5_CC" \
-    ARMC6_CC="$ARMC6_CC" RUN_ARMCC="$RUN_ARMCC" scripts/output_env.sh
+component_check_recursion () {
+    msg "test: recursion.pl" # < 1s
+    record_status tests/scripts/recursion.pl library/*.c
+}
 
-msg "test: recursion.pl" # < 1s
-record_status tests/scripts/recursion.pl library/*.c
+component_check_generated_files () {
+    msg "test: freshness of generated source files" # < 1s
+    record_status tests/scripts/check-generated-files.sh
+}
 
-msg "test: freshness of generated source files" # < 1s
-record_status tests/scripts/check-generated-files.sh
+component_check_doxy_blocks () {
+    msg "test: doxygen markup outside doxygen blocks" # < 1s
+    record_status tests/scripts/check-doxy-blocks.pl
+}
 
-msg "test: doxygen markup outside doxygen blocks" # < 1s
-record_status tests/scripts/check-doxy-blocks.pl
+component_check_files () {
+    msg "test: check-files.py" # < 1s
+    record_status tests/scripts/check-files.py
+}
 
-msg "test: check-files.py" # < 1s
-cleanup
-record_status tests/scripts/check-files.py
+component_check_names () {
+    msg "test/build: declared and exported names" # < 3s
+    record_status tests/scripts/check-names.sh
+}
 
-msg "test/build: declared and exported names" # < 3s
-cleanup
-record_status tests/scripts/check-names.sh
-
-msg "test: doxygen warnings" # ~ 3s
-cleanup
-record_status tests/scripts/doxygen.sh
+component_check_doxygen_warnings () {
+    msg "test: doxygen warnings" # ~ 3s
+    record_status tests/scripts/doxygen.sh
+}
 
 
 ################################################################
 #### Build and test many configurations and targets
 ################################################################
 
-msg "build: cmake, gcc, ASan" # ~ 1 min 50s
-cleanup
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+component_test_default_cmake_gcc_asan () {
+    msg "build: cmake, gcc, ASan" # ~ 1 min 50s
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "test: main suites (inc. selftests) (ASan build)" # ~ 50s
-make test
+    msg "test: main suites (inc. selftests) (ASan build)" # ~ 50s
+    make test
 
-msg "test: ssl-opt.sh (ASan build)" # ~ 1 min
-if_build_succeeded tests/ssl-opt.sh
+    msg "test: ssl-opt.sh (ASan build)" # ~ 1 min
+    if_build_succeeded tests/ssl-opt.sh
 
-msg "test/build: ref-configs (ASan build)" # ~ 6 min 20s
-record_status tests/scripts/test-ref-configs.pl
+    msg "test: compat.sh (ASan build)" # ~ 6 min
+    if_build_succeeded tests/compat.sh
+}
 
-msg "build: with ASan (rebuild after ref-configs)" # ~ 1 min
-make
+component_test_ref_configs () {
+    msg "test/build: ref-configs (ASan build)" # ~ 6 min 20s
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    record_status tests/scripts/test-ref-configs.pl
+}
 
-msg "test: compat.sh (ASan build)" # ~ 6 min
-if_build_succeeded tests/compat.sh
+component_test_sslv3 () {
+    msg "build: Default + SSLv3 (ASan build)" # ~ 6 min
+    scripts/config.pl set MBEDTLS_SSL_PROTO_SSL3
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: Default + SSLv3 (ASan build)" # ~ 6 min
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_SSL_PROTO_SSL3
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: SSLv3 - main suites (inc. selftests) (ASan build)" # ~ 50s
+    make test
 
-msg "test: SSLv3 - main suites (inc. selftests) (ASan build)" # ~ 50s
-make test
+    msg "build: SSLv3 - compat.sh (ASan build)" # ~ 6 min
+    if_build_succeeded tests/compat.sh -m 'tls1 tls1_1 tls1_2 dtls1 dtls1_2'
+    if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" tests/compat.sh -m 'ssl3'
 
-msg "build: SSLv3 - compat.sh (ASan build)" # ~ 6 min
-if_build_succeeded tests/compat.sh -m 'tls1 tls1_1 tls1_2 dtls1 dtls1_2'
-if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" tests/compat.sh -m 'ssl3'
+    msg "build: SSLv3 - ssl-opt.sh (ASan build)" # ~ 6 min
+    if_build_succeeded tests/ssl-opt.sh
+}
 
-msg "build: SSLv3 - ssl-opt.sh (ASan build)" # ~ 6 min
-if_build_succeeded tests/ssl-opt.sh
+component_test_no_renegotiation () {
+    msg "build: Default + !MBEDTLS_SSL_RENEGOTIATION (ASan build)" # ~ 6 min
+    scripts/config.pl unset MBEDTLS_SSL_RENEGOTIATION
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: Default + !MBEDTLS_SSL_RENEGOTIATION (ASan build)" # ~ 6 min
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_SSL_RENEGOTIATION
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: !MBEDTLS_SSL_RENEGOTIATION - main suites (inc. selftests) (ASan build)" # ~ 50s
+    make test
 
-msg "test: !MBEDTLS_SSL_RENEGOTIATION - main suites (inc. selftests) (ASan build)" # ~ 50s
-make test
+    msg "test: !MBEDTLS_SSL_RENEGOTIATION - ssl-opt.sh (ASan build)" # ~ 6 min
+    if_build_succeeded tests/ssl-opt.sh
+}
 
-msg "test: !MBEDTLS_SSL_RENEGOTIATION - ssl-opt.sh (ASan build)" # ~ 6 min
-if_build_succeeded tests/ssl-opt.sh
+component_test_rsa_no_crt () {
+    msg "build: Default + RSA_NO_CRT (ASan build)" # ~ 6 min
+    scripts/config.pl set MBEDTLS_RSA_NO_CRT
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: Default + RSA_NO_CRT (ASan build)" # ~ 6 min
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_RSA_NO_CRT
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: RSA_NO_CRT - main suites (inc. selftests) (ASan build)" # ~ 50s
+    make test
 
-msg "test: RSA_NO_CRT - main suites (inc. selftests) (ASan build)" # ~ 50s
-make test
+    msg "test: RSA_NO_CRT - RSA-related part of ssl-opt.sh (ASan build)" # ~ 5s
+    if_build_succeeded tests/ssl-opt.sh -f RSA
 
-msg "test: RSA_NO_CRT - RSA-related part of ssl-opt.sh (ASan build)" # ~ 5s
-if_build_succeeded tests/ssl-opt.sh -f RSA
+    msg "test: RSA_NO_CRT - RSA-related part of compat.sh (ASan build)" # ~ 3 min
+    if_build_succeeded tests/compat.sh -t RSA
+}
 
-msg "test: RSA_NO_CRT - RSA-related part of compat.sh (ASan build)" # ~ 3 min
-if_build_succeeded tests/compat.sh -t RSA
+component_test_small_ssl_out_content_len () {
+    msg "build: small SSL_OUT_CONTENT_LEN (ASan build)"
+    scripts/config.pl set MBEDTLS_SSL_IN_CONTENT_LEN 16384
+    scripts/config.pl set MBEDTLS_SSL_OUT_CONTENT_LEN 4096
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: small SSL_OUT_CONTENT_LEN (ASan build)"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_SSL_IN_CONTENT_LEN 16384
-scripts/config.pl set MBEDTLS_SSL_OUT_CONTENT_LEN 4096
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: small SSL_OUT_CONTENT_LEN - ssl-opt.sh MFL and large packet tests"
+    if_build_succeeded tests/ssl-opt.sh -f "Max fragment\|Large packet"
+}
 
-msg "test: small SSL_OUT_CONTENT_LEN - ssl-opt.sh MFL and large packet tests"
-if_build_succeeded tests/ssl-opt.sh -f "Max fragment\|Large packet"
+component_test_small_ssl_in_content_len () {
+    msg "build: small SSL_IN_CONTENT_LEN (ASan build)"
+    scripts/config.pl set MBEDTLS_SSL_IN_CONTENT_LEN 4096
+    scripts/config.pl set MBEDTLS_SSL_OUT_CONTENT_LEN 16384
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: small SSL_IN_CONTENT_LEN (ASan build)"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_SSL_IN_CONTENT_LEN 4096
-scripts/config.pl set MBEDTLS_SSL_OUT_CONTENT_LEN 16384
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: small SSL_IN_CONTENT_LEN - ssl-opt.sh MFL tests"
+    if_build_succeeded tests/ssl-opt.sh -f "Max fragment"
+}
 
-msg "test: small SSL_IN_CONTENT_LEN - ssl-opt.sh MFL tests"
-if_build_succeeded tests/ssl-opt.sh -f "Max fragment"
+component_test_small_ssl_dtls_max_buffering () {
+    msg "build: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #0"
+    scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 1000
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #0"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 1000
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #0 - ssl-opt.sh specific reordering test"
+    if_build_succeeded tests/ssl-opt.sh -f "DTLS reordering: Buffer out-of-order hs msg before reassembling next, free buffered msg"
+}
 
-msg "test: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #0 - ssl-opt.sh specific reordering test"
-if_build_succeeded tests/ssl-opt.sh -f "DTLS reordering: Buffer out-of-order hs msg before reassembling next, free buffered msg"
+component_test_small_mbedtls_ssl_dtls_max_buffering () {
+    msg "build: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #1"
+    scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 240
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #1"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 240
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #1 - ssl-opt.sh specific reordering test"
+    if_build_succeeded tests/ssl-opt.sh -f "DTLS reordering: Buffer encrypted Finished message, drop for fragmented NewSessionTicket"
+}
 
-msg "test: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #1 - ssl-opt.sh specific reordering test"
-if_build_succeeded tests/ssl-opt.sh -f "DTLS reordering: Buffer encrypted Finished message, drop for fragmented NewSessionTicket"
+component_test_full_cmake_clang () {
+    msg "build: cmake, full config, clang" # ~ 50s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
+    CC=clang cmake -D CMAKE_BUILD_TYPE:String=Check -D ENABLE_TESTING=On .
+    make
 
-msg "build: cmake, full config, clang" # ~ 50s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
-CC=clang cmake -D CMAKE_BUILD_TYPE:String=Check -D ENABLE_TESTING=On .
-make
+    msg "test: main suites (full config)" # ~ 5s
+    make test
 
-msg "test: main suites (full config)" # ~ 5s
-make test
+    msg "test: ssl-opt.sh default, ECJPAKE, SSL async (full config)" # ~ 1s
+    if_build_succeeded tests/ssl-opt.sh -f 'Default\|ECJPAKE\|SSL async private'
 
-msg "test: ssl-opt.sh default, ECJPAKE, SSL async (full config)" # ~ 1s
-if_build_succeeded tests/ssl-opt.sh -f 'Default\|ECJPAKE\|SSL async private'
+    msg "test: compat.sh RC4, DES & NULL (full config)" # ~ 2 min
+    if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR'
 
-msg "test: compat.sh RC4, DES & NULL (full config)" # ~ 2 min
-if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR'
+    msg "test: compat.sh ARIA + ChachaPoly"
+    if_build_succeeded env OPENSSL_CMD="$OPENSSL_NEXT" tests/compat.sh -e '^$' -f 'ARIA\|CHACHA'
+}
 
-msg "test: compat.sh ARIA + ChachaPoly"
-if_build_succeeded env OPENSSL_CMD="$OPENSSL_NEXT" tests/compat.sh -e '^$' -f 'ARIA\|CHACHA'
+component_build_deprecated () {
+    msg "build: make, full config + DEPRECATED_WARNING, gcc -O" # ~ 30s
+    scripts/config.pl full
+    scripts/config.pl set MBEDTLS_DEPRECATED_WARNING
+    # Build with -O -Wextra to catch a maximum of issues.
+    make CC=gcc CFLAGS='-O -Werror -Wall -Wextra' lib programs
+    make CC=gcc CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests
 
-msg "build: make, full config + DEPRECATED_WARNING, gcc -O" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl set MBEDTLS_DEPRECATED_WARNING
-# Build with -O -Wextra to catch a maximum of issues.
-make CC=gcc CFLAGS='-O -Werror -Wall -Wextra' lib programs
-make CC=gcc CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests
+    msg "build: make, full config + DEPRECATED_REMOVED, clang -O" # ~ 30s
+    # No cleanup, just tweak the configuration and rebuild
+    make clean
+    scripts/config.pl unset MBEDTLS_DEPRECATED_WARNING
+    scripts/config.pl set MBEDTLS_DEPRECATED_REMOVED
+    # Build with -O -Wextra to catch a maximum of issues.
+    make CC=clang CFLAGS='-O -Werror -Wall -Wextra' lib programs
+    make CC=clang CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests
+}
 
-msg "build: make, full config + DEPRECATED_REMOVED, clang -O" # ~ 30s
-# No cleanup, just tweak the configuration and rebuild
-make clean
-scripts/config.pl unset MBEDTLS_DEPRECATED_WARNING
-scripts/config.pl set MBEDTLS_DEPRECATED_REMOVED
-# Build with -O -Wextra to catch a maximum of issues.
-make CC=clang CFLAGS='-O -Werror -Wall -Wextra' lib programs
-make CC=clang CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests
 
-msg "test/build: curves.pl (gcc)" # ~ 4 min
-cleanup
-record_status tests/scripts/curves.pl
+component_test_depends_curves () {
+    msg "test/build: curves.pl (gcc)" # ~ 4 min
+    record_status tests/scripts/curves.pl
+}
 
-msg "test/build: depends-hashes.pl (gcc)" # ~ 2 min
-cleanup
-record_status tests/scripts/depends-hashes.pl
+component_test_depends_hashes () {
+    msg "test/build: depends-hashes.pl (gcc)" # ~ 2 min
+    record_status tests/scripts/depends-hashes.pl
+}
 
-msg "test/build: depends-pkalgs.pl (gcc)" # ~ 2 min
-cleanup
-record_status tests/scripts/depends-pkalgs.pl
+component_test_depends_pkalgs () {
+    msg "test/build: depends-pkalgs.pl (gcc)" # ~ 2 min
+    record_status tests/scripts/depends-pkalgs.pl
+}
 
-msg "test/build: key-exchanges (gcc)" # ~ 1 min
-cleanup
-record_status tests/scripts/key-exchanges.pl
+component_build_key_exchanges () {
+    msg "test/build: key-exchanges (gcc)" # ~ 1 min
+    record_status tests/scripts/key-exchanges.pl
+}
 
-msg "build: Unix make, -Os (gcc)" # ~ 30s
-cleanup
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -Os'
+component_build_default_make_gcc_and_cxx () {
+    msg "build: Unix make, -Os (gcc)" # ~ 30s
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -Os'
 
-msg "test: verify header list in cpp_dummy_build.cpp"
-record_status check_headers_in_cpp
+    msg "test: verify header list in cpp_dummy_build.cpp"
+    record_status check_headers_in_cpp
 
-msg "build: Unix make, incremental g++"
-make TEST_CPP=1
+    msg "build: Unix make, incremental g++"
+    make TEST_CPP=1
+}
 
-# Full configuration build, without platform support, file IO and net sockets.
-# This should catch missing mbedtls_printf definitions, and by disabling file
-# IO, it should catch missing '#include <stdio.h>'
-msg "build: full config except platform/fsio/net, make, gcc, C99" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_PLATFORM_C
-scripts/config.pl unset MBEDTLS_NET_C
-scripts/config.pl unset MBEDTLS_PLATFORM_MEMORY
-scripts/config.pl unset MBEDTLS_PLATFORM_PRINTF_ALT
-scripts/config.pl unset MBEDTLS_PLATFORM_FPRINTF_ALT
-scripts/config.pl unset MBEDTLS_PLATFORM_SNPRINTF_ALT
-scripts/config.pl unset MBEDTLS_PLATFORM_TIME_ALT
-scripts/config.pl unset MBEDTLS_PLATFORM_EXIT_ALT
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
-scripts/config.pl unset MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
-scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_C
-# Note, _DEFAULT_SOURCE needs to be defined for platforms using glibc version >2.19,
-# to re-enable platform integration features otherwise disabled in C99 builds
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic -O0 -D_DEFAULT_SOURCE' lib programs
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' test
+component_test_no_platform () {
+    # Full configuration build, without platform support, file IO and net sockets.
+    # This should catch missing mbedtls_printf definitions, and by disabling file
+    # IO, it should catch missing '#include <stdio.h>'
+    msg "build: full config except platform/fsio/net, make, gcc, C99" # ~ 30s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_PLATFORM_C
+    scripts/config.pl unset MBEDTLS_NET_C
+    scripts/config.pl unset MBEDTLS_PLATFORM_MEMORY
+    scripts/config.pl unset MBEDTLS_PLATFORM_PRINTF_ALT
+    scripts/config.pl unset MBEDTLS_PLATFORM_FPRINTF_ALT
+    scripts/config.pl unset MBEDTLS_PLATFORM_SNPRINTF_ALT
+    scripts/config.pl unset MBEDTLS_PLATFORM_TIME_ALT
+    scripts/config.pl unset MBEDTLS_PLATFORM_EXIT_ALT
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
+    scripts/config.pl unset MBEDTLS_FS_IO
+    scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
+    scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_C
+    # Note, _DEFAULT_SOURCE needs to be defined for platforms using glibc version >2.19,
+    # to re-enable platform integration features otherwise disabled in C99 builds
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic -O0 -D_DEFAULT_SOURCE' lib programs
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' test
+}
 
-# catch compile bugs in _uninit functions
-msg "build: full config with NO_STD_FUNCTION, make, gcc" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl set MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
+component_build_no_std_function () {
+    # catch compile bugs in _uninit functions
+    msg "build: full config with NO_STD_FUNCTION, make, gcc" # ~ 30s
+    scripts/config.pl full
+    scripts/config.pl set MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
+}
 
-msg "build: full config except ssl_srv.c, make, gcc" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_SSL_SRV_C
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
+component_build_no_ssl_srv () {
+    msg "build: full config except ssl_srv.c, make, gcc" # ~ 30s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_SSL_SRV_C
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
+}
 
-msg "build: full config except ssl_cli.c, make, gcc" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_SSL_CLI_C
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
+component_build_no_ssl_cli () {
+    msg "build: full config except ssl_cli.c, make, gcc" # ~ 30s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_SSL_CLI_C
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
+}
 
-# Note, C99 compliance can also be tested with the sockets support disabled,
-# as that requires a POSIX platform (which isn't the same as C99).
-msg "build: full config except net_sockets.c, make, gcc -std=c99 -pedantic" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_NET_C # getaddrinfo() undeclared, etc.
-scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY # uses syscall() on GNU/Linux
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0 -std=c99 -pedantic' lib
+component_build_no_sockets () {
+    # Note, C99 compliance can also be tested with the sockets support disabled,
+    # as that requires a POSIX platform (which isn't the same as C99).
+    msg "build: full config except net_sockets.c, make, gcc -std=c99 -pedantic" # ~ 30s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_NET_C # getaddrinfo() undeclared, etc.
+    scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY # uses syscall() on GNU/Linux
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0 -std=c99 -pedantic' lib
+}
 
-# Run max fragment length tests with MFL disabled
-msg "build: default config except MFL extension (ASan build)" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+component_test_no_max_fragment_length () {
+    # Run max fragment length tests with MFL disabled
+    msg "build: default config except MFL extension (ASan build)" # ~ 30s
+    scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "test: ssl-opt.sh, MFL-related tests"
-if_build_succeeded tests/ssl-opt.sh -f "Max fragment length"
+    msg "test: ssl-opt.sh, MFL-related tests"
+    if_build_succeeded tests/ssl-opt.sh -f "Max fragment length"
+}
 
-msg "build: no MFL extension, small SSL_OUT_CONTENT_LEN (ASan build)"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
-scripts/config.pl set MBEDTLS_SSL_IN_CONTENT_LEN 16384
-scripts/config.pl set MBEDTLS_SSL_OUT_CONTENT_LEN 4096
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+component_test_no_max_fragment_length_small_ssl_out_content_len () {
+    msg "build: no MFL extension, small SSL_OUT_CONTENT_LEN (ASan build)"
+    scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+    scripts/config.pl set MBEDTLS_SSL_IN_CONTENT_LEN 16384
+    scripts/config.pl set MBEDTLS_SSL_OUT_CONTENT_LEN 4096
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "test: MFL tests (disabled MFL extension case) & large packet tests"
-if_build_succeeded tests/ssl-opt.sh -f "Max fragment length\|Large buffer"
+    msg "test: MFL tests (disabled MFL extension case) & large packet tests"
+    if_build_succeeded tests/ssl-opt.sh -f "Max fragment length\|Large buffer"
+}
 
-msg "build: default config with  MBEDTLS_TEST_NULL_ENTROPY (ASan build)"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_TEST_NULL_ENTROPY
-scripts/config.pl set MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
-scripts/config.pl set MBEDTLS_ENTROPY_C
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl unset MBEDTLS_ENTROPY_HARDWARE_ALT
-scripts/config.pl unset MBEDTLS_HAVEGE_C
-CC=gcc cmake  -D UNSAFE_BUILD=ON -D CMAKE_C_FLAGS:String="-fsanitize=address -fno-common -O3" .
-make
+component_test_null_entropy () {
+    msg "build: default config with  MBEDTLS_TEST_NULL_ENTROPY (ASan build)"
+    scripts/config.pl set MBEDTLS_TEST_NULL_ENTROPY
+    scripts/config.pl set MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+    scripts/config.pl set MBEDTLS_ENTROPY_C
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl unset MBEDTLS_ENTROPY_HARDWARE_ALT
+    scripts/config.pl unset MBEDTLS_HAVEGE_C
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan -D UNSAFE_BUILD=ON .
+    make
 
-msg "test: MBEDTLS_TEST_NULL_ENTROPY - main suites (inc. selftests) (ASan build)"
-make test
+    msg "test: MBEDTLS_TEST_NULL_ENTROPY - main suites (inc. selftests) (ASan build)"
+    make test
+}
 
-msg "build: MBEDTLS_PLATFORM_{CALLOC/FREE}_MACRO enabled (ASan build)"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_PLATFORM_MEMORY
-scripts/config.pl set MBEDTLS_PLATFORM_CALLOC_MACRO calloc
-scripts/config.pl set MBEDTLS_PLATFORM_FREE_MACRO   free
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+component_test_platform_calloc_macro () {
+    msg "build: MBEDTLS_PLATFORM_{CALLOC/FREE}_MACRO enabled (ASan build)"
+    scripts/config.pl set MBEDTLS_PLATFORM_MEMORY
+    scripts/config.pl set MBEDTLS_PLATFORM_CALLOC_MACRO calloc
+    scripts/config.pl set MBEDTLS_PLATFORM_FREE_MACRO   free
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "test: MBEDTLS_PLATFORM_{CALLOC/FREE}_MACRO enabled (ASan build)"
-make test
+    msg "test: MBEDTLS_PLATFORM_{CALLOC/FREE}_MACRO enabled (ASan build)"
+    make test
+}
 
-msg "build: default config with AES_FEWER_TABLES enabled"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_AES_FEWER_TABLES
-make CC=gcc CFLAGS='-Werror -Wall -Wextra'
+component_test_aes_fewer_tables () {
+    msg "build: default config with AES_FEWER_TABLES enabled"
+    scripts/config.pl set MBEDTLS_AES_FEWER_TABLES
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra'
 
-msg "test: AES_FEWER_TABLES"
-make test
+    msg "test: AES_FEWER_TABLES"
+    make test
+}
 
-msg "build: default config with AES_ROM_TABLES enabled"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_AES_ROM_TABLES
-make CC=gcc CFLAGS='-Werror -Wall -Wextra'
+component_test_aes_rom_tables () {
+    msg "build: default config with AES_ROM_TABLES enabled"
+    scripts/config.pl set MBEDTLS_AES_ROM_TABLES
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra'
 
-msg "test: AES_ROM_TABLES"
-make test
+    msg "test: AES_ROM_TABLES"
+    make test
+}
 
-msg "build: default config with AES_ROM_TABLES and AES_FEWER_TABLES enabled"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_AES_FEWER_TABLES
-scripts/config.pl set MBEDTLS_AES_ROM_TABLES
-make CC=gcc CFLAGS='-Werror -Wall -Wextra'
+component_test_aes_fewer_tables_and_rom_tables () {
+    msg "build: default config with AES_ROM_TABLES and AES_FEWER_TABLES enabled"
+    scripts/config.pl set MBEDTLS_AES_FEWER_TABLES
+    scripts/config.pl set MBEDTLS_AES_ROM_TABLES
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra'
 
-msg "test: AES_FEWER_TABLES + AES_ROM_TABLES"
-make test
+    msg "test: AES_FEWER_TABLES + AES_ROM_TABLES"
+    make test
+}
 
-if uname -a | grep -F Linux >/dev/null; then
+component_test_make_shared () {
     msg "build/test: make shared" # ~ 40s
-    cleanup
     make SHARED=1 all check
-fi
+}
 
-if uname -a | grep -F x86_64 >/dev/null; then
+component_test_m32_o0 () {
     # Build once with -O0, to compile out the i386 specific inline assembly
     msg "build: i386, make, gcc -O0 (ASan build)" # ~ 30s
-    cleanup
-    cp "$CONFIG_H" "$CONFIG_BAK"
     scripts/config.pl full
     make CC=gcc CFLAGS='-O0 -Werror -Wall -Wextra -m32 -fsanitize=address'
 
     msg "test: i386, make, gcc -O0 (ASan build)"
     make test
+}
+support_test_m32_o0 () {
+    case $(uname -m) in
+        *64*) true;;
+        *) false;;
+    esac
+}
 
+component_test_m32_o1 () {
     # Build again with -O1, to compile in the i386 specific inline assembly
     msg "build: i386, make, gcc -O1 (ASan build)" # ~ 30s
-    cleanup
-    cp "$CONFIG_H" "$CONFIG_BAK"
     scripts/config.pl full
     make CC=gcc CFLAGS='-O1 -Werror -Wall -Wextra -m32 -fsanitize=address'
 
     msg "test: i386, make, gcc -O1 (ASan build)"
     make test
+}
+support_test_m32_o1 () {
+    support_test_m32_o0 "$@"
+}
 
+component_test_mx32 () {
     msg "build: 64-bit ILP32, make, gcc" # ~ 30s
-    cleanup
-    cp "$CONFIG_H" "$CONFIG_BAK"
     scripts/config.pl full
     make CC=gcc CFLAGS='-Werror -Wall -Wextra -mx32'
 
     msg "test: 64-bit ILP32, make, gcc"
     make test
-fi # x86_64
+}
+support_test_mx32 () {
+    case $(uname -m) in
+        amd64|x86_64) true;;
+        *) false;;
+    esac
+}
 
-msg "build: gcc, force 32-bit bignum limbs"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_HAVE_ASM
-scripts/config.pl unset MBEDTLS_AESNI_C
-scripts/config.pl unset MBEDTLS_PADLOCK_C
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT32'
+component_test_have_int32 () {
+    msg "build: gcc, force 32-bit bignum limbs"
+    scripts/config.pl unset MBEDTLS_HAVE_ASM
+    scripts/config.pl unset MBEDTLS_AESNI_C
+    scripts/config.pl unset MBEDTLS_PADLOCK_C
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT32'
 
-msg "test: gcc, force 32-bit bignum limbs"
-make test
+    msg "test: gcc, force 32-bit bignum limbs"
+    make test
+}
 
-msg "build: gcc, force 64-bit bignum limbs"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_HAVE_ASM
-scripts/config.pl unset MBEDTLS_AESNI_C
-scripts/config.pl unset MBEDTLS_PADLOCK_C
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT64'
+component_test_have_int64 () {
+    msg "build: gcc, force 64-bit bignum limbs"
+    scripts/config.pl unset MBEDTLS_HAVE_ASM
+    scripts/config.pl unset MBEDTLS_AESNI_C
+    scripts/config.pl unset MBEDTLS_PADLOCK_C
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT64'
 
-msg "test: gcc, force 64-bit bignum limbs"
-make test
+    msg "test: gcc, force 64-bit bignum limbs"
+    make test
+}
 
+component_test_no_udbl_division () {
+    msg "build: MBEDTLS_NO_UDBL_DIVISION native" # ~ 10s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
+    scripts/config.pl set MBEDTLS_NO_UDBL_DIVISION
+    make CFLAGS='-Werror -O1'
 
-msg "build: MBEDTLS_NO_UDBL_DIVISION native" # ~ 10s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
-scripts/config.pl set MBEDTLS_NO_UDBL_DIVISION
-make CFLAGS='-Werror -O1'
+    msg "test: MBEDTLS_NO_UDBL_DIVISION native" # ~ 10s
+    make test
+}
 
-msg "test: MBEDTLS_NO_UDBL_DIVISION native" # ~ 10s
-make test
+component_test_no_64bit_multiplication () {
+    msg "build: MBEDTLS_NO_64BIT_MULTIPLICATION native" # ~ 10s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
+    scripts/config.pl set MBEDTLS_NO_64BIT_MULTIPLICATION
+    make CFLAGS='-Werror -O1'
 
+    msg "test: MBEDTLS_NO_64BIT_MULTIPLICATION native" # ~ 10s
+    make test
+}
 
-msg "build: MBEDTLS_NO_64BIT_MULTIPLICATION native" # ~ 10s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
-scripts/config.pl set MBEDTLS_NO_64BIT_MULTIPLICATION
-make CFLAGS='-Werror -O1'
+component_build_arm_none_eabi_gcc () {
+    msg "build: arm-none-eabi-gcc, make" # ~ 10s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_NET_C
+    scripts/config.pl unset MBEDTLS_TIMING_C
+    scripts/config.pl unset MBEDTLS_FS_IO
+    scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
+    scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_C
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
+    # following things are not in the default config
+    scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
+    scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
+    scripts/config.pl unset MBEDTLS_THREADING_C
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
+    make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -Wall -Wextra' lib
+}
 
-msg "test: MBEDTLS_NO_64BIT_MULTIPLICATION native" # ~ 10s
-make test
+component_build_arm_none_eabi_gcc_no_udbl_division () {
+    msg "build: arm-none-eabi-gcc -DMBEDTLS_NO_UDBL_DIVISION, make" # ~ 10s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_NET_C
+    scripts/config.pl unset MBEDTLS_TIMING_C
+    scripts/config.pl unset MBEDTLS_FS_IO
+    scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
+    scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_C
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
+    # following things are not in the default config
+    scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
+    scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
+    scripts/config.pl unset MBEDTLS_THREADING_C
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
+    scripts/config.pl set MBEDTLS_NO_UDBL_DIVISION
+    make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -Wall -Wextra' lib
+    echo "Checking that software 64-bit division is not required"
+    if_build_succeeded not grep __aeabi_uldiv library/*.o
+}
 
+component_build_arm_none_eabi_gcc_no_64bit_multiplication () {
+    msg "build: arm-none-eabi-gcc MBEDTLS_NO_64BIT_MULTIPLICATION, make" # ~ 10s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_NET_C
+    scripts/config.pl unset MBEDTLS_TIMING_C
+    scripts/config.pl unset MBEDTLS_FS_IO
+    scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
+    scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_C
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
+    # following things are not in the default config
+    scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
+    scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
+    scripts/config.pl unset MBEDTLS_THREADING_C
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
+    scripts/config.pl set MBEDTLS_NO_64BIT_MULTIPLICATION
+    make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -O1 -march=armv6-m -mthumb' lib
+    echo "Checking that software 64-bit multiplication is not required"
+    if_build_succeeded not grep __aeabi_lmul library/*.o
+}
 
-msg "build: arm-none-eabi-gcc, make" # ~ 10s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_NET_C
-scripts/config.pl unset MBEDTLS_TIMING_C
-scripts/config.pl unset MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
-# following things are not in the default config
-scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
-scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
-scripts/config.pl unset MBEDTLS_THREADING_C
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
-scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
-scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C # depends on MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_C # depends on MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
-make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -Wall -Wextra' lib
+component_build_armcc () {
+    msg "build: ARM Compiler 5, make"
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_NET_C
+    scripts/config.pl unset MBEDTLS_TIMING_C
+    scripts/config.pl unset MBEDTLS_FS_IO
+    scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
+    scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_C
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl unset MBEDTLS_HAVE_TIME
+    scripts/config.pl unset MBEDTLS_HAVE_TIME_DATE
+    scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
+    # following things are not in the default config
+    scripts/config.pl unset MBEDTLS_DEPRECATED_WARNING
+    scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
+    scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
+    scripts/config.pl unset MBEDTLS_THREADING_C
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
+    scripts/config.pl unset MBEDTLS_PLATFORM_TIME_ALT # depends on MBEDTLS_HAVE_TIME
 
-msg "build: arm-none-eabi-gcc -DMBEDTLS_NO_UDBL_DIVISION, make" # ~ 10s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_NET_C
-scripts/config.pl unset MBEDTLS_TIMING_C
-scripts/config.pl unset MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
-# following things are not in the default config
-scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
-scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
-scripts/config.pl unset MBEDTLS_THREADING_C
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
-scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
-scripts/config.pl set MBEDTLS_NO_UDBL_DIVISION
-scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C # depends on MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_C # depends on MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
-make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -Wall -Wextra' lib
-echo "Checking that software 64-bit division is not required"
-if_build_succeeded not grep __aeabi_uldiv library/*.o
-
-msg "build: arm-none-eabi-gcc MBEDTLS_NO_64BIT_MULTIPLICATION, make" # ~ 10s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_NET_C
-scripts/config.pl unset MBEDTLS_TIMING_C
-scripts/config.pl unset MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
-# following things are not in the default config
-scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
-scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
-scripts/config.pl unset MBEDTLS_THREADING_C
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
-scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
-scripts/config.pl set MBEDTLS_NO_64BIT_MULTIPLICATION
-scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C # depends on MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_C # depends on MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
-make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -O1 -march=armv6-m -mthumb' lib
-echo "Checking that software 64-bit multiplication is not required"
-if_build_succeeded not grep __aeabi_lmul library/*.o
-
-msg "build: ARM Compiler 5, make"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_NET_C
-scripts/config.pl unset MBEDTLS_TIMING_C
-scripts/config.pl unset MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl unset MBEDTLS_HAVE_TIME
-scripts/config.pl unset MBEDTLS_HAVE_TIME_DATE
-scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
-# following things are not in the default config
-scripts/config.pl unset MBEDTLS_DEPRECATED_WARNING
-scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
-scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
-scripts/config.pl unset MBEDTLS_THREADING_C
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
-scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
-scripts/config.pl unset MBEDTLS_PLATFORM_TIME_ALT # depends on MBEDTLS_HAVE_TIME
-scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C # depends on MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_PSA_CRYPTO_STORAGE_C # depends on MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
-
-if [ $RUN_ARMCC -ne 0 ]; then
     make CC="$ARMC5_CC" AR="$ARMC5_AR" WARNING_CFLAGS='--strict --c99' lib
     make clean
 
@@ -940,46 +1098,33 @@
 
     # ARM Compiler 6 - Target ARMv8-A - AArch64
     armc6_build_test "--target=aarch64-arm-none-eabi -march=armv8.2-a"
-fi
+}
 
-msg "build: allow SHA1 in certificates by default"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES
-make CFLAGS='-Werror -Wall -Wextra'
-msg "test: allow SHA1 in certificates by default"
-make test
-if_build_succeeded tests/ssl-opt.sh -f SHA-1
+component_test_allow_sha1 () {
+    msg "build: allow SHA1 in certificates by default"
+    scripts/config.pl set MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES
+    make CFLAGS='-Werror -Wall -Wextra'
+    msg "test: allow SHA1 in certificates by default"
+    make test
+    if_build_succeeded tests/ssl-opt.sh -f SHA-1
+}
 
-msg "build: Default + MBEDTLS_RSA_NO_CRT (ASan build)" # ~ 6 min
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_RSA_NO_CRT
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+component_build_mingw () {
+    msg "build: Windows cross build - mingw64, make (Link Library)" # ~ 30s
+    make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 lib programs
 
-msg "test: MBEDTLS_RSA_NO_CRT - main suites (inc. selftests) (ASan build)"
-make test
+    # note Make tests only builds the tests, but doesn't run them
+    make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror' WINDOWS_BUILD=1 tests
+    make WINDOWS_BUILD=1 clean
 
-msg "build: Windows cross build - mingw64, make (Link Library)" # ~ 30s
-cleanup
-make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 lib programs
+    msg "build: Windows cross build - mingw64, make (DLL)" # ~ 30s
+    make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 lib programs
+    make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 tests
+    make WINDOWS_BUILD=1 clean
+}
 
-# note Make tests only builds the tests, but doesn't run them
-make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror' WINDOWS_BUILD=1 tests
-make WINDOWS_BUILD=1 clean
-
-msg "build: Windows cross build - mingw64, make (DLL)" # ~ 30s
-make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 lib programs
-make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 tests
-make WINDOWS_BUILD=1 clean
-
-# MemSan currently only available on Linux 64 bits
-if uname -a | grep 'Linux.*x86_64' >/dev/null; then
-
+component_test_memsan () {
     msg "build: MSan (clang)" # ~ 1 min 20s
-    cleanup
-    cp "$CONFIG_H" "$CONFIG_BAK"
     scripts/config.pl unset MBEDTLS_AESNI_C # memsan doesn't grok asm
     CC=clang cmake -D CMAKE_BUILD_TYPE:String=MemSan .
     make
@@ -996,11 +1141,10 @@
         msg "test: compat.sh (MSan)" # ~ 6 min 20s
         if_build_succeeded tests/compat.sh
     fi
+}
 
-else # no MemSan
-
+component_test_valgrind () {
     msg "build: Release (clang)"
-    cleanup
     CC=clang cmake -D CMAKE_BUILD_TYPE:String=Release .
     make
 
@@ -1020,63 +1164,123 @@
         msg "test: compat.sh --memcheck (Release)"
         if_build_succeeded tests/compat.sh --memcheck
     fi
+}
 
-fi # MemSan
+component_test_cmake_out_of_source () {
+    msg "build: cmake 'out-of-source' build"
+    MBEDTLS_ROOT_DIR="$PWD"
+    mkdir "$OUT_OF_SOURCE_DIR"
+    cd "$OUT_OF_SOURCE_DIR"
+    cmake "$MBEDTLS_ROOT_DIR"
+    make
 
-msg "build: cmake 'out-of-source' build"
-cleanup
-MBEDTLS_ROOT_DIR="$PWD"
-mkdir "$OUT_OF_SOURCE_DIR"
-cd "$OUT_OF_SOURCE_DIR"
-cmake "$MBEDTLS_ROOT_DIR"
-make
+    msg "test: cmake 'out-of-source' build"
+    make test
+    # Test an SSL option that requires an auxiliary script in test/scripts/.
+    # Also ensure that there are no error messages such as
+    # "No such file or directory", which would indicate that some required
+    # file is missing (ssl-opt.sh tolerates the absence of some files so
+    # may exit with status 0 but emit errors).
+    if_build_succeeded ./tests/ssl-opt.sh -f 'Fallback SCSV: beginning of list' 2>ssl-opt.err
+    if [ -s ssl-opt.err ]; then
+        cat ssl-opt.err >&2
+        record_status [ ! -s ssl-opt.err ]
+        rm ssl-opt.err
+    fi
+    cd "$MBEDTLS_ROOT_DIR"
+    rm -rf "$OUT_OF_SOURCE_DIR"
+    unset MBEDTLS_ROOT_DIR
+}
 
-msg "test: cmake 'out-of-source' build"
-make test
-# Test an SSL option that requires an auxiliary script in test/scripts/.
-# Also ensure that there are no error messages such as
-# "No such file or directory", which would indicate that some required
-# file is missing (ssl-opt.sh tolerates the absence of some files so
-# may exit with status 0 but emit errors).
-if_build_succeeded ./tests/ssl-opt.sh -f 'Fallback SCSV: beginning of list' 2>ssl-opt.err
-if [ -s ssl-opt.err ]; then
-  cat ssl-opt.err >&2
-  record_status [ ! -s ssl-opt.err ]
-  rm ssl-opt.err
-fi
-cd "$MBEDTLS_ROOT_DIR"
-rm -rf "$OUT_OF_SOURCE_DIR"
-unset MBEDTLS_ROOT_DIR
+component_test_zeroize () {
+    # Test that the function mbedtls_platform_zeroize() is not optimized away by
+    # different combinations of compilers and optimization flags by using an
+    # auxiliary GDB script. Unfortunately, GDB does not return error values to the
+    # system in all cases that the script fails, so we must manually search the
+    # output to check whether the pass string is present and no failure strings
+    # were printed.
 
-# Test that the function mbedtls_platform_zeroize() is not optimized away by
-# different combinations of compilers and optimization flags by using an
-# auxiliary GDB script. Unfortunately, GDB does not return error values to the
-# system in all cases that the script fails, so we must manually search the
-# output to check whether the pass string is present and no failure strings
-# were printed.
-for optimization_flag in -O2 -O3 -Ofast -Os; do
-    for compiler in clang gcc; do
-        msg "test: $compiler $optimization_flag, mbedtls_platform_zeroize()"
-        cleanup
-        make programs CC="$compiler" DEBUG=1 CFLAGS="$optimization_flag"
-        if_build_succeeded gdb -x tests/scripts/test_zeroize.gdb -nw -batch -nx 2>&1 | tee test_zeroize.log
-        if_build_succeeded grep "The buffer was correctly zeroized" test_zeroize.log
-        if_build_succeeded not grep -i "error" test_zeroize.log
-        rm -f test_zeroize.log
+    # Don't try to disable ASLR. We don't care about ASLR here. We do care
+    # about a spurious message if Gdb tries and fails, so suppress that.
+    gdb_disable_aslr=
+    if [ -z "$(gdb -batch -nw -ex 'set disable-randomization off' 2>&1)" ]; then
+        gdb_disable_aslr='set disable-randomization off'
+    fi
+
+    for optimization_flag in -O2 -O3 -Ofast -Os; do
+        for compiler in clang gcc; do
+            msg "test: $compiler $optimization_flag, mbedtls_platform_zeroize()"
+            make programs CC="$compiler" DEBUG=1 CFLAGS="$optimization_flag"
+            if_build_succeeded gdb -ex "$gdb_disable_aslr" -x tests/scripts/test_zeroize.gdb -nw -batch -nx 2>&1 | tee test_zeroize.log
+            if_build_succeeded grep "The buffer was correctly zeroized" test_zeroize.log
+            if_build_succeeded not grep -i "error" test_zeroize.log
+            rm -f test_zeroize.log
+            make clean
+        done
     done
-done
 
-msg "Lint: Python scripts"
-record_status tests/scripts/check-python-files.sh
+    unset gdb_disable_aslr
+}
 
-msg "uint test: generate_test_code.py"
-record_status ./tests/scripts/test_generate_test_code.py
+component_check_python_files () {
+    msg "Lint: Python scripts"
+    record_status tests/scripts/check-python-files.sh
+}
+
+component_check_generate_test_code () {
+    msg "uint test: generate_test_code.py"
+    record_status ./tests/scripts/test_generate_test_code.py
+}
 
 ################################################################
 #### Termination
 ################################################################
 
-msg "Done, cleaning up"
+post_report () {
+    msg "Done, cleaning up"
+    cleanup
+
+    final_report
+}
+
+
+
+################################################################
+#### Run all the things
+################################################################
+
+# Run one component and clean up afterwards.
+run_component () {
+    # Back up the configuration in case the component modifies it.
+    # The cleanup function will restore it.
+    cp -p "$CONFIG_H" "$CONFIG_BAK"
+    current_component="$1"
+    "$@"
+    cleanup
+}
+
+# Preliminary setup
+pre_check_environment
+pre_initialize_variables
+pre_parse_command_line "$@"
+
+pre_check_git
+build_status=0
+if [ $KEEP_GOING -eq 1 ]; then
+    pre_setup_keep_going
+else
+    record_status () {
+        "$@"
+    }
+fi
+pre_print_configuration
+pre_check_tools
 cleanup
 
-final_report
+# Run the requested tests.
+for component in $RUN_COMPONENTS; do
+    run_component "component_$component"
+done
+
+# We're done.
+post_report
diff --git a/tests/scripts/check-names.sh b/tests/scripts/check-names.sh
index addcc05..925037c 100755
--- a/tests/scripts/check-names.sh
+++ b/tests/scripts/check-names.sh
@@ -40,7 +40,7 @@
 for THING in actual-macros enum-consts; do
     printf "Names of $THING: "
     test -r $THING
-    BAD=$( grep -v '^MBEDTLS_[0-9A-Z_]*[0-9A-Z]$' $THING || true )
+    BAD=$( grep -E -v '^(MBEDTLS|PSA)_[0-9A-Z_]*[0-9A-Z]$' $THING || true )
     if [ "x$BAD" = "x" ]; then
         echo "PASS"
     else
@@ -65,7 +65,7 @@
 
 printf "Likely typos: "
 sort -u actual-macros enum-consts > _caps
-HEADERS=$( ls include/mbedtls/*.h | egrep -v 'compat-1\.3\.h' )
+HEADERS=$( ls include/mbedtls/*.h include/psa/*.h | egrep -v 'compat-1\.3\.h' )
 NL='
 '
 sed -n 's/MBED..._[A-Z0-9_]*/\'"$NL"'&\'"$NL"/gp \
diff --git a/tests/scripts/list-macros.sh b/tests/scripts/list-macros.sh
index 3c84adb..5982bb7 100755
--- a/tests/scripts/list-macros.sh
+++ b/tests/scripts/list-macros.sh
@@ -7,7 +7,7 @@
     exit 1
 fi
 
-HEADERS=$( ls include/mbedtls/*.h | egrep -v 'compat-1\.3\.h' )
+HEADERS=$( ls include/mbedtls/*.h include/psa/*.h | egrep -v 'compat-1\.3\.h' )
 
 sed -n -e 's/.*#define \([a-zA-Z0-9_]*\).*/\1/p' $HEADERS \
     | egrep -v '^(asm|inline|EMIT|_CRT_SECURE_NO_DEPRECATE)$|^MULADDC_' \
diff --git a/tests/scripts/test_zeroize.gdb b/tests/scripts/test_zeroize.gdb
index 77c812a..2f995d2 100644
--- a/tests/scripts/test_zeroize.gdb
+++ b/tests/scripts/test_zeroize.gdb
@@ -41,8 +41,6 @@
 # number does not need to be updated often.
 
 set confirm off
-# We don't need to turn off ASLR, so don't try.
-set disable-randomization off
 
 file ./programs/test/zeroize
 break zeroize.c:100
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 2ccecc4..26830fe 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -167,7 +167,7 @@
 get_config_value_or_default() {
     NAME="$1"
     DEF_VAL=$( grep ".*#define.*${NAME}" ../include/mbedtls/config.h |
-               sed 's/^.*\s\([0-9]*\)$/\1/' )
+               sed 's/^.* \([0-9]*\)$/\1/' )
     ../scripts/config.pl get $NAME || echo "$DEF_VAL"
 }
 
diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function
index 9168b1d..47d72d0 100644
--- a/tests/suites/test_suite_pk.function
+++ b/tests/suites/test_suite_pk.function
@@ -74,17 +74,17 @@
  * or PK_PSA_INVALID_SLOT if no slot was available.
  * The key uses NIST P-256 and is usable for signing with SHA-256.
  */
-psa_key_slot_t pk_psa_genkey( void )
+psa_key_handle_t pk_psa_genkey( void )
 {
-    psa_key_slot_t key;
+    psa_key_handle_t key;
 
     const int curve = PSA_ECC_CURVE_SECP256R1;
     const psa_key_type_t type = PSA_KEY_TYPE_ECC_KEYPAIR(curve);
     const size_t bits = 256;
     psa_key_policy_t policy;
 
-    /* find a free key slot */
-    if( PSA_SUCCESS != mbedtls_psa_get_free_key_slot( &key ) )
+    /* Allocate a key slot */
+    if( PSA_SUCCESS != psa_allocate_key( type, bits, &key ) )
         return( PK_PSA_INVALID_SLOT );
 
     /* set up policy on key slot */
@@ -112,7 +112,7 @@
 void pk_psa_utils(  )
 {
     mbedtls_pk_context pk, pk2;
-    psa_key_slot_t key;
+    psa_key_handle_t key;
 
     const char * const name = "Opaque";
     const size_t bitlen = 256; /* harcoded in genkey() */
@@ -778,7 +778,7 @@
 void pk_psa_sign(  )
 {
     mbedtls_pk_context pk;
-    psa_key_slot_t key;
+    psa_key_handle_t key;
     unsigned char hash[50], sig[100], pkey[100];
     size_t sig_len, klen = 0;
 
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index f50773f..fab66cb 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -520,6 +520,12 @@
 PSA hash finish: bad arguments
 hash_finish_bad_args:
 
+PSA hash clone: source state
+hash_clone_source_state:
+
+PSA hash clone: target state
+hash_clone_target_state:
+
 MAC operation object initializers zero properly
 mac_operation_init:
 
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index ea1e545..2e19e1e 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -853,8 +853,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( type, KEY_BITS_FROM_DATA( type, data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     status = psa_import_key( handle, type, data->x, data->len );
     TEST_EQUAL( status, expected_status );
     if( status == PSA_SUCCESS )
@@ -884,10 +883,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( type1,
-                                  MAX( KEY_BITS_FROM_DATA( type1, data1 ),
-                                       KEY_BITS_FROM_DATA( type2, data2 ) ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, usage, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -931,7 +927,7 @@
     length = ret;
 
     /* Try importing the key */
-    PSA_ASSERT( psa_allocate_key( type, bits, &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     status = psa_import_key( handle, type, p, length );
     TEST_EQUAL( status, expected_status );
     if( status == PSA_SUCCESS )
@@ -973,7 +969,7 @@
         ASSERT_ALLOC( reexported, export_size );
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( type, expected_bits, &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, usage_arg, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -1019,7 +1015,7 @@
     else
     {
         psa_key_handle_t handle2;
-        PSA_ASSERT( psa_allocate_key( type, expected_bits, &handle2 ) );
+        PSA_ASSERT( psa_allocate_key( &handle2 ) );
         PSA_ASSERT( psa_set_key_policy( handle2, &policy ) );
 
         PSA_ASSERT( psa_import_key( handle2, type,
@@ -1057,8 +1053,7 @@
     const uint8_t data[] = { 0x1, 0x2, 0x3, 0x4, 0x5 };
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( type, PSA_BYTES_TO_BITS( sizeof( data ) ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
 
     /* Import the key */
     PSA_ASSERT( psa_import_key( handle, type,
@@ -1108,8 +1103,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( PSA_KEY_TYPE_RAW_DATA, 0,
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_EXPORT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -1135,8 +1129,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( PSA_KEY_TYPE_RAW_DATA, 0,
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_ENCRYPT, exercise_alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -1163,8 +1156,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( type, KEY_BITS_FROM_DATA( type, data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
 
     /* Import the key - expect failure */
     status = psa_import_key( handle, type,
@@ -1195,8 +1187,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( type, KEY_BITS_FROM_DATA( type, data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
 
     /* Import the key - expect failure */
     status = psa_import_key( handle, type,
@@ -1226,8 +1217,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( type, KEY_BITS_FROM_DATA( type, data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_EXPORT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
     export_size = (ptrdiff_t) data->len;
@@ -1274,8 +1264,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( type, KEY_BITS_FROM_DATA( type, data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_EXPORT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -1325,8 +1314,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( type, KEY_BITS_FROM_DATA( type, data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, usage, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -1366,8 +1354,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( sizeof( key ) ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy_set, usage, alg );
 
     TEST_EQUAL( psa_key_policy_get_usage( &policy_set ), usage );
@@ -1428,9 +1415,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, policy_usage, policy_alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -1474,9 +1459,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, policy_usage, policy_alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -1528,9 +1511,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, policy_usage, policy_alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -1585,9 +1566,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, policy_usage, policy_alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -1649,9 +1628,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, policy_usage, policy_alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -1698,9 +1675,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, policy_usage, policy_alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -1740,9 +1715,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, policy_usage, policy_alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -1901,6 +1874,92 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE depends_on:MBEDTLS_SHA256_C */
+void hash_clone_source_state( )
+{
+    psa_algorithm_t alg = PSA_ALG_SHA_256;
+    unsigned char hash[PSA_HASH_MAX_SIZE];
+    psa_hash_operation_t op_source = PSA_HASH_OPERATION_INIT;
+    psa_hash_operation_t op_init = PSA_HASH_OPERATION_INIT;
+    psa_hash_operation_t op_setup = PSA_HASH_OPERATION_INIT;
+    psa_hash_operation_t op_finished = PSA_HASH_OPERATION_INIT;
+    psa_hash_operation_t op_aborted = PSA_HASH_OPERATION_INIT;
+    size_t hash_len;
+
+    PSA_ASSERT( psa_crypto_init( ) );
+    PSA_ASSERT( psa_hash_setup( &op_source, alg ) );
+
+    PSA_ASSERT( psa_hash_setup( &op_setup, alg ) );
+    PSA_ASSERT( psa_hash_setup( &op_finished, alg ) );
+    PSA_ASSERT( psa_hash_finish( &op_finished,
+                                 hash, sizeof( hash ), &hash_len ) );
+    PSA_ASSERT( psa_hash_setup( &op_aborted, alg ) );
+    PSA_ASSERT( psa_hash_abort( &op_aborted ) );
+
+    TEST_EQUAL( psa_hash_clone( &op_source, &op_setup ),
+                PSA_ERROR_BAD_STATE );
+
+    PSA_ASSERT( psa_hash_clone( &op_source, &op_init ) );
+    PSA_ASSERT( psa_hash_finish( &op_init,
+                                 hash, sizeof( hash ), &hash_len ) );
+    PSA_ASSERT( psa_hash_clone( &op_source, &op_finished ) );
+    PSA_ASSERT( psa_hash_finish( &op_finished,
+                                 hash, sizeof( hash ), &hash_len ) );
+    PSA_ASSERT( psa_hash_clone( &op_source, &op_aborted ) );
+    PSA_ASSERT( psa_hash_finish( &op_aborted,
+                                 hash, sizeof( hash ), &hash_len ) );
+
+exit:
+    psa_hash_abort( &op_source );
+    psa_hash_abort( &op_init );
+    psa_hash_abort( &op_setup );
+    psa_hash_abort( &op_finished );
+    psa_hash_abort( &op_aborted );
+    mbedtls_psa_crypto_free( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_SHA256_C */
+void hash_clone_target_state( )
+{
+    psa_algorithm_t alg = PSA_ALG_SHA_256;
+    unsigned char hash[PSA_HASH_MAX_SIZE];
+    psa_hash_operation_t op_init = PSA_HASH_OPERATION_INIT;
+    psa_hash_operation_t op_setup = PSA_HASH_OPERATION_INIT;
+    psa_hash_operation_t op_finished = PSA_HASH_OPERATION_INIT;
+    psa_hash_operation_t op_aborted = PSA_HASH_OPERATION_INIT;
+    psa_hash_operation_t op_target = PSA_HASH_OPERATION_INIT;
+    size_t hash_len;
+
+    PSA_ASSERT( psa_crypto_init( ) );
+
+    PSA_ASSERT( psa_hash_setup( &op_setup, alg ) );
+    PSA_ASSERT( psa_hash_setup( &op_finished, alg ) );
+    PSA_ASSERT( psa_hash_finish( &op_finished,
+                                 hash, sizeof( hash ), &hash_len ) );
+    PSA_ASSERT( psa_hash_setup( &op_aborted, alg ) );
+    PSA_ASSERT( psa_hash_abort( &op_aborted ) );
+
+    PSA_ASSERT( psa_hash_clone( &op_setup, &op_target ) );
+    PSA_ASSERT( psa_hash_finish( &op_target,
+                                 hash, sizeof( hash ), &hash_len ) );
+
+    TEST_EQUAL( psa_hash_clone( &op_init, &op_target ), PSA_ERROR_BAD_STATE );
+    TEST_EQUAL( psa_hash_clone( &op_finished, &op_target ),
+                PSA_ERROR_BAD_STATE );
+    TEST_EQUAL( psa_hash_clone( &op_aborted, &op_target ),
+                PSA_ERROR_BAD_STATE );
+
+exit:
+    psa_hash_abort( &op_target );
+    psa_hash_abort( &op_init );
+    psa_hash_abort( &op_setup );
+    psa_hash_abort( &op_finished );
+    psa_hash_abort( &op_aborted );
+    mbedtls_psa_crypto_free( );
+}
+/* END_CASE */
+
 /* BEGIN_CASE */
 void mac_operation_init( )
 {
@@ -1942,8 +2001,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy,
                               PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY,
                               alg );
@@ -1988,8 +2046,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_SIGN, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2036,8 +2093,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_VERIFY, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2100,8 +2156,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_ENCRYPT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2143,8 +2198,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_ENCRYPT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2210,8 +2264,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_ENCRYPT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2280,8 +2333,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DECRYPT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2352,8 +2404,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DECRYPT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2420,8 +2471,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2505,8 +2555,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2608,8 +2657,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key_data->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy,
                               PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT,
                               alg );
@@ -2674,8 +2722,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key_data->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_ENCRYPT , alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2724,8 +2771,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key_data->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DECRYPT , alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2784,9 +2830,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_SIGN, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2840,9 +2884,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_SIGN, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2883,9 +2925,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy,
                               PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY,
                               alg );
@@ -2954,9 +2994,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_VERIFY, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -2989,9 +3027,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_VERIFY, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -3036,9 +3072,7 @@
     PSA_ASSERT( psa_crypto_init( ) );
 
     /* Import the key */
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_ENCRYPT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
     PSA_ASSERT( psa_import_key( handle, key_type,
@@ -3105,9 +3139,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy,
                               PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT,
                               alg );
@@ -3175,9 +3207,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DECRYPT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -3241,9 +3271,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  KEY_BITS_FROM_DATA( key_type, key_data ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DECRYPT, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -3326,8 +3354,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type, PSA_BYTES_TO_BITS( key_data->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DERIVE, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -3364,9 +3391,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( key_type,
-                                  PSA_BYTES_TO_BITS( sizeof( key_data ) ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DERIVE, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -3461,9 +3486,7 @@
     ASSERT_ALLOC( output_buffer, output_buffer_size );
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( PSA_KEY_TYPE_DERIVE,
-                                  PSA_BYTES_TO_BITS( key_data->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DERIVE, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -3541,9 +3564,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( PSA_KEY_TYPE_DERIVE,
-                                  PSA_BYTES_TO_BITS( key_data->len ),
-                                  &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DERIVE, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -3613,9 +3634,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( PSA_KEY_TYPE_DERIVE,
-                                  PSA_BYTES_TO_BITS( key_data->len ),
-                                  &base_handle ) );
+    PSA_ASSERT( psa_allocate_key( &base_handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DERIVE, alg );
     PSA_ASSERT( psa_set_key_policy( base_handle, &policy ) );
     PSA_ASSERT( psa_import_key( base_handle, PSA_KEY_TYPE_DERIVE,
@@ -3627,8 +3646,7 @@
                                     salt->x, salt->len,
                                     label->x, label->len,
                                     capacity ) );
-    PSA_ASSERT( psa_allocate_key( derived_type, derived_bits,
-                                  &derived_handle ) );
+    PSA_ASSERT( psa_allocate_key( &derived_handle ) );
     psa_key_policy_set_usage( &policy, derived_usage, derived_alg );
     PSA_ASSERT( psa_set_key_policy( derived_handle, &policy ) );
     PSA_ASSERT( psa_generator_import_key( derived_handle,
@@ -3680,9 +3698,7 @@
     ASSERT_ALLOC( export_buffer, capacity );
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( PSA_KEY_TYPE_DERIVE,
-                                  PSA_BYTES_TO_BITS( key_data->len ),
-                                  &base_handle ) );
+    PSA_ASSERT( psa_allocate_key( &base_handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DERIVE, alg );
     PSA_ASSERT( psa_set_key_policy( base_handle, &policy ) );
     PSA_ASSERT( psa_import_key( base_handle, PSA_KEY_TYPE_DERIVE,
@@ -3704,8 +3720,7 @@
                                     salt->x, salt->len,
                                     label->x, label->len,
                                     capacity ) );
-    PSA_ASSERT( psa_allocate_key( PSA_KEY_TYPE_RAW_DATA, derived_bits,
-                                  &derived_handle ) );
+    PSA_ASSERT( psa_allocate_key( &derived_handle ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_EXPORT, 0 );
     PSA_ASSERT( psa_set_key_policy( derived_handle, &policy ) );
     PSA_ASSERT( psa_generator_import_key( derived_handle,
@@ -3717,9 +3732,7 @@
                                 &length ) );
     TEST_EQUAL( length, bytes1 );
     PSA_ASSERT( psa_destroy_key( derived_handle ) );
-    PSA_ASSERT( psa_allocate_key( PSA_KEY_TYPE_RAW_DATA,
-                                  PSA_BYTES_TO_BITS( bytes2 ),
-                                  &derived_handle ) );
+    PSA_ASSERT( psa_allocate_key( &derived_handle ) );
     PSA_ASSERT( psa_set_key_policy( derived_handle, &policy ) );
     PSA_ASSERT( psa_generator_import_key( derived_handle,
                                           PSA_KEY_TYPE_RAW_DATA,
@@ -3758,10 +3771,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( our_key_type,
-                                  KEY_BITS_FROM_DATA( our_key_type,
-                                                      our_key_data ),
-                                  &our_key ) );
+    PSA_ASSERT( psa_allocate_key( &our_key ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DERIVE, alg );
     PSA_ASSERT( psa_set_key_policy( our_key, &policy ) );
     PSA_ASSERT( psa_import_key( our_key, our_key_type,
@@ -3797,10 +3807,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( our_key_type,
-                                  KEY_BITS_FROM_DATA( our_key_type,
-                                                      our_key_data ),
-                                  &our_key ) );
+    PSA_ASSERT( psa_allocate_key( &our_key ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DERIVE, alg );
     PSA_ASSERT( psa_set_key_policy( our_key, &policy ) );
     PSA_ASSERT( psa_import_key( our_key, our_key_type,
@@ -3854,10 +3861,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( our_key_type,
-                                  KEY_BITS_FROM_DATA( our_key_type,
-                                                      our_key_data ),
-                                  &our_key ) );
+    PSA_ASSERT( psa_allocate_key( &our_key ) );
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_DERIVE, alg );
     PSA_ASSERT( psa_set_key_policy( our_key, &policy ) );
     PSA_ASSERT( psa_import_key( our_key, our_key_type,
@@ -3963,7 +3967,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    PSA_ASSERT( psa_allocate_key( type, bits, &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     psa_key_policy_set_usage( &policy, usage, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
 
@@ -4019,7 +4023,6 @@
     PSA_ASSERT( psa_crypto_init() );
 
     PSA_ASSERT( psa_create_key( PSA_KEY_LIFETIME_PERSISTENT, 1,
-                                type, bits,
                                 &handle ) );
     psa_key_policy_set_usage( &policy_set, policy_usage,
                               policy_alg );
@@ -4041,9 +4044,7 @@
 
         case DERIVE_KEY:
             /* Create base key */
-            PSA_ASSERT( psa_allocate_key( PSA_KEY_TYPE_DERIVE,
-                                          PSA_BYTES_TO_BITS( data->len ),
-                                          &base_key ) );
+            PSA_ASSERT( psa_allocate_key( &base_key ) );
             psa_key_policy_set_usage( &base_policy_set, PSA_KEY_USAGE_DERIVE,
                                       base_policy_alg );
             PSA_ASSERT( psa_set_key_policy(
diff --git a/tests/suites/test_suite_psa_crypto_hash.function b/tests/suites/test_suite_psa_crypto_hash.function
index bdb2f98..8abd4e2 100644
--- a/tests/suites/test_suite_psa_crypto_hash.function
+++ b/tests/suites/test_suite_psa_crypto_hash.function
@@ -67,6 +67,7 @@
     unsigned char actual_hash[PSA_HASH_MAX_SIZE];
     size_t actual_hash_length;
     psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
+    psa_hash_operation_t operation2 = PSA_HASH_OPERATION_INIT;
     uint32_t len = 0;
 
     PSA_ASSERT( psa_crypto_init( ) );
@@ -78,16 +79,23 @@
 
         PSA_ASSERT( psa_hash_update( &operation,
                                      input->x, len ) );
+        PSA_ASSERT( psa_hash_clone( &operation, &operation2 ) );
         PSA_ASSERT( psa_hash_update( &operation,
                                      input->x + len, input->len - len ) );
+        PSA_ASSERT( psa_hash_update( &operation2,
+                                     input->x + len, input->len - len ) );
 
         PSA_ASSERT( psa_hash_finish( &operation,
                                      actual_hash, sizeof( actual_hash ),
                                      &actual_hash_length ) );
-
         ASSERT_COMPARE( expected_hash->x, expected_hash->len,
                         actual_hash, actual_hash_length );
 
+        PSA_ASSERT( psa_hash_finish( &operation2,
+                                     actual_hash, sizeof( actual_hash ),
+                                     &actual_hash_length ) );
+        ASSERT_COMPARE( expected_hash->x, expected_hash->len,
+                        actual_hash, actual_hash_length );
     } while( len++ != input->len );
 
 exit:
diff --git a/tests/suites/test_suite_psa_crypto_persistent_key.function b/tests/suites/test_suite_psa_crypto_persistent_key.function
index 939a37b..e19ef2b 100644
--- a/tests/suites/test_suite_psa_crypto_persistent_key.function
+++ b/tests/suites/test_suite_psa_crypto_persistent_key.function
@@ -97,8 +97,6 @@
     PSA_ASSERT( psa_crypto_init() );
 
     PSA_ASSERT( psa_create_key( PSA_KEY_LIFETIME_PERSISTENT, key_id,
-                                PSA_KEY_TYPE_RAW_DATA,
-                                PSA_BYTES_TO_BITS( data_length ),
                                 &handle ) );
 
     TEST_EQUAL( psa_import_key( handle, PSA_KEY_TYPE_RAW_DATA,
@@ -125,8 +123,6 @@
     PSA_ASSERT( psa_crypto_init() );
 
     PSA_ASSERT( psa_create_key( PSA_KEY_LIFETIME_PERSISTENT, key_id,
-                                first_type,
-                                PSA_BYTES_TO_BITS( first_data->len ),
                                 &handle ) );
 
     if( should_store == 1 )
@@ -151,8 +147,6 @@
 
     /* Create another key in the same slot */
     PSA_ASSERT( psa_create_key( PSA_KEY_LIFETIME_PERSISTENT, key_id,
-                                second_type,
-                                PSA_BYTES_TO_BITS( second_data->len ),
                                 &handle ) );
     PSA_ASSERT( psa_import_key(
                     handle, second_type,
@@ -176,8 +170,6 @@
     PSA_ASSERT( psa_crypto_init() );
 
     PSA_ASSERT( psa_create_key( PSA_KEY_LIFETIME_PERSISTENT, key_id,
-                                type,
-                                PSA_BYTES_TO_BITS( data->len ),
                                 &handle ) );
     TEST_EQUAL( psa_import_key( handle, type, data->x, data->len ),
                 expected_status );
@@ -217,8 +209,6 @@
     PSA_ASSERT( psa_crypto_init( ) );
 
     PSA_ASSERT( psa_create_key( PSA_KEY_LIFETIME_PERSISTENT, key_id,
-                                type,
-                                PSA_BYTES_TO_BITS( data->len ),
                                 &handle ) );
 
     psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_EXPORT,
diff --git a/tests/suites/test_suite_psa_crypto_slot_management.data b/tests/suites/test_suite_psa_crypto_slot_management.data
index 39661b9..e8ec40c 100644
--- a/tests/suites/test_suite_psa_crypto_slot_management.data
+++ b/tests/suites/test_suite_psa_crypto_slot_management.data
@@ -1,41 +1,29 @@
 Transient slot, check after closing
-transient_slot_lifecycle:PSA_KEY_TYPE_RAW_DATA:128:0:0:"0123456789abcdef0123456789abcdef":CLOSE_BY_CLOSE
+transient_slot_lifecycle:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_CLOSE
 
 Transient slot, check after destroying
-transient_slot_lifecycle:PSA_KEY_TYPE_RAW_DATA:128:0:0:"0123456789abcdef0123456789abcdef":CLOSE_BY_DESTROY
+transient_slot_lifecycle:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_DESTROY
 
 Transient slot, check after restart
-transient_slot_lifecycle:PSA_KEY_TYPE_RAW_DATA:128:0:0:"0123456789abcdef0123456789abcdef":CLOSE_BY_SHUTDOWN
+transient_slot_lifecycle:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_SHUTDOWN
 
 Persistent slot, check after closing
-persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_TYPE_RAW_DATA:128:0:0:"0123456789abcdef0123456789abcdef":CLOSE_BY_CLOSE
+persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:1:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_CLOSE
 
 Persistent slot, check after destroying
-persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_TYPE_RAW_DATA:128:0:0:"0123456789abcdef0123456789abcdef":CLOSE_BY_DESTROY
+persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:1:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_DESTROY
 
 Persistent slot, check after restart
-persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_TYPE_RAW_DATA:128:0:0:"0123456789abcdef0123456789abcdef":CLOSE_BY_SHUTDOWN
+persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:1:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_SHUTDOWN
 
-Attempt to overwrite: close before, same type
-create_existent:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_TYPE_RAW_DATA:CLOSE_BEFORE
+Attempt to overwrite: close before
+create_existent:PSA_KEY_LIFETIME_PERSISTENT:1:CLOSE_BEFORE
 
-Attempt to overwrite: close before, different type
-depends_on:MBEDTLS_AES_C
-create_existent:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_TYPE_AES:CLOSE_BEFORE
+Attempt to overwrite: close after
+create_existent:PSA_KEY_LIFETIME_PERSISTENT:1:CLOSE_AFTER
 
-Attempt to overwrite: close after, same type
-create_existent:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_TYPE_RAW_DATA:CLOSE_AFTER
-
-Attempt to overwrite: close after, different type
-depends_on:MBEDTLS_AES_C
-create_existent:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_TYPE_AES:CLOSE_AFTER
-
-Attempt to overwrite: keep open, same type
-create_existent:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_TYPE_RAW_DATA:KEEP_OPEN
-
-Attempt to overwrite: keep open, different type
-depends_on:MBEDTLS_AES_C
-create_existent:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_TYPE_AES:KEEP_OPEN
+Attempt to overwrite: keep open
+create_existent:PSA_KEY_LIFETIME_PERSISTENT:1:KEEP_OPEN
 
 Open failure: invalid identifier (0)
 depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C
@@ -56,18 +44,18 @@
 open_fail:0x7fffffff:0:PSA_ERROR_INVALID_ARGUMENT
 
 Create failure: volatile lifetime
-create_fail:PSA_KEY_LIFETIME_VOLATILE:1:PSA_KEY_TYPE_RAW_DATA:8:PSA_ERROR_INVALID_ARGUMENT
+create_fail:PSA_KEY_LIFETIME_VOLATILE:1:PSA_ERROR_INVALID_ARGUMENT
 
 Create failure: invalid lifetime
-create_fail:0x7fffffff:0:PSA_KEY_TYPE_RAW_DATA:8:PSA_ERROR_INVALID_ARGUMENT
+create_fail:0x7fffffff:0:PSA_ERROR_INVALID_ARGUMENT
 
 Create failure: invalid key id (0)
 depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C
-create_fail:PSA_KEY_LIFETIME_PERSISTENT:0:PSA_KEY_TYPE_RAW_DATA:8:PSA_ERROR_INVALID_ARGUMENT
+create_fail:PSA_KEY_LIFETIME_PERSISTENT:0:PSA_ERROR_INVALID_ARGUMENT
 
 Create failure: invalid key id (random seed UID)
 depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C
-create_fail:PSA_KEY_LIFETIME_PERSISTENT:PSA_CRYPTO_ITS_RANDOM_SEED_UID:PSA_KEY_TYPE_RAW_DATA:8:PSA_ERROR_INVALID_ARGUMENT
+create_fail:PSA_KEY_LIFETIME_PERSISTENT:PSA_CRYPTO_ITS_RANDOM_SEED_UID:PSA_ERROR_INVALID_ARGUMENT
 
 Open not supported
 depends_on:!MBEDTLS_PSA_CRYPTO_STORAGE_C
@@ -75,7 +63,7 @@
 
 Create not supported
 depends_on:!MBEDTLS_PSA_CRYPTO_STORAGE_C
-create_fail:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_TYPE_RAW_DATA:8:PSA_ERROR_NOT_SUPPORTED
+create_fail:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_ERROR_NOT_SUPPORTED
 
 Close/destroy invalid handle
 invalid_handle:
diff --git a/tests/suites/test_suite_psa_crypto_slot_management.function b/tests/suites/test_suite_psa_crypto_slot_management.function
index 670c740..46fafcc 100644
--- a/tests/suites/test_suite_psa_crypto_slot_management.function
+++ b/tests/suites/test_suite_psa_crypto_slot_management.function
@@ -65,15 +65,13 @@
  */
 
 /* BEGIN_CASE */
-void transient_slot_lifecycle( int type_arg, int max_bits_arg,
-                               int alg_arg, int usage_arg,
-                               data_t *key_data,
+void transient_slot_lifecycle( int alg_arg, int usage_arg,
+                               int type_arg, data_t *key_data,
                                int close_method_arg )
 {
-    psa_key_type_t type = type_arg;
-    size_t max_bits = max_bits_arg;
     psa_algorithm_t alg = alg_arg;
     psa_key_usage_t usage_flags = usage_arg;
+    psa_key_type_t type = type_arg;
     close_method_t close_method = close_method_arg;
     psa_key_type_t read_type;
     psa_key_handle_t handle = 0;
@@ -82,7 +80,7 @@
     PSA_ASSERT( psa_crypto_init( ) );
 
     /* Get a handle and import a key. */
-    PSA_ASSERT( psa_allocate_key( type, max_bits, &handle ) );
+    PSA_ASSERT( psa_allocate_key( &handle ) );
     TEST_ASSERT( handle != 0 );
     psa_key_policy_set_usage( &policy, usage_flags, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
@@ -116,17 +114,15 @@
 
 /* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C */
 void persistent_slot_lifecycle( int lifetime_arg, int id_arg,
-                                int type_arg, int max_bits_arg,
                                 int alg_arg, int usage_arg,
-                                data_t *key_data,
+                                int type_arg, data_t *key_data,
                                 int close_method_arg )
 {
     psa_key_lifetime_t lifetime = lifetime_arg;
     psa_key_id_t id = id_arg;
-    psa_key_type_t type = type_arg;
-    size_t max_bits = max_bits_arg;
     psa_algorithm_t alg = alg_arg;
     psa_key_usage_t usage_flags = usage_arg;
+    psa_key_type_t type = type_arg;
     close_method_t close_method = close_method_arg;
     psa_key_type_t read_type;
     psa_key_handle_t handle = 0;
@@ -137,7 +133,7 @@
     PSA_ASSERT( psa_crypto_init( ) );
 
     /* Get a handle and import a key. */
-    PSA_ASSERT( psa_create_key( lifetime, id, type, max_bits, &handle ) );
+    PSA_ASSERT( psa_create_key( lifetime, id, &handle ) );
     TEST_ASSERT( handle != 0 );
     psa_key_policy_set_usage( &policy, usage_flags, alg );
     PSA_ASSERT( psa_set_key_policy( handle, &policy ) );
@@ -194,7 +190,6 @@
 
 /* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C */
 void create_existent( int lifetime_arg, int id_arg,
-                      int new_type_arg,
                       int reopen_policy_arg )
 {
     psa_key_lifetime_t lifetime = lifetime_arg;
@@ -203,7 +198,6 @@
     psa_key_policy_t policy1 = PSA_KEY_POLICY_INIT;
     psa_key_policy_t read_policy = PSA_KEY_POLICY_INIT;
     psa_key_type_t type1 = PSA_KEY_TYPE_RAW_DATA;
-    psa_key_type_t type2 = new_type_arg;
     psa_key_type_t read_type;
     const uint8_t material1[16] = "test material #1";
     size_t bits1 = PSA_BYTES_TO_BITS( sizeof( material1 ) );
@@ -217,7 +211,7 @@
     PSA_ASSERT( psa_crypto_init( ) );
 
     /* Create a key. */
-    PSA_ASSERT( psa_create_key( lifetime, id, type1, bits1, &handle1 ) );
+    PSA_ASSERT( psa_create_key( lifetime, id, &handle1 ) );
     TEST_ASSERT( handle1 != 0 );
     psa_key_policy_set_usage( &policy1, PSA_KEY_USAGE_EXPORT, 0 );
     PSA_ASSERT( psa_set_key_policy( handle1, &policy1 ) );
@@ -228,7 +222,7 @@
         PSA_ASSERT( psa_close_key( handle1 ) );
 
     /* Attempt to create a new key in the same slot. */
-    TEST_EQUAL( psa_create_key( lifetime, id, type2, bits1, &handle2 ),
+    TEST_EQUAL( psa_create_key( lifetime, id, &handle2 ),
                 PSA_ERROR_OCCUPIED_SLOT );
     TEST_EQUAL( handle2, 0 );
 
@@ -276,13 +270,10 @@
 
 /* BEGIN_CASE */
 void create_fail( int lifetime_arg, int id_arg,
-                  int type_arg, int max_bits_arg,
                   int expected_status_arg )
 {
     psa_key_lifetime_t lifetime = lifetime_arg;
     psa_key_id_t id = id_arg;
-    psa_key_type_t type = type_arg;
-    size_t max_bits = max_bits_arg;
     psa_status_t expected_status = expected_status_arg;
     psa_key_handle_t handle = 0xdead;
 
@@ -290,7 +281,7 @@
 
     PSA_ASSERT( psa_crypto_init( ) );
 
-    TEST_EQUAL( psa_create_key( lifetime, id, type, max_bits, &handle ),
+    TEST_EQUAL( psa_create_key( lifetime, id, &handle ),
                 expected_status );
     TEST_EQUAL( handle, 0 );
 
@@ -314,7 +305,7 @@
     PSA_ASSERT( psa_crypto_init( ) );
 
     /* Allocate a handle and store a key in it. */
-    PSA_ASSERT( psa_allocate_key( PSA_KEY_TYPE_RAW_DATA, 1, &handle1 ) );
+    PSA_ASSERT( psa_allocate_key( &handle1 ) );
     TEST_ASSERT( handle1 != 0 );
     psa_key_policy_set_usage( &policy, 0, 0 );
     PSA_ASSERT( psa_set_key_policy( handle1, &policy ) );
@@ -350,7 +341,6 @@
     psa_key_policy_t policy = PSA_KEY_POLICY_INIT;
     uint8_t exported[sizeof( size_t )];
     size_t exported_length;
-    size_t max_bits = PSA_BITS_TO_BYTES( sizeof( exported ) );
 
     ASSERT_ALLOC( handles, max_handles );
     PSA_ASSERT( psa_crypto_init( ) );
@@ -358,8 +348,7 @@
 
     for( i = 0; i < max_handles; i++ )
     {
-        status = psa_allocate_key( PSA_KEY_TYPE_RAW_DATA, max_bits,
-                                   &handles[i] );
+        status = psa_allocate_key( &handles[i] );
         if( status == PSA_ERROR_INSUFFICIENT_MEMORY )
             break;
         PSA_ASSERT( status );
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index bf43a80..268b4bb 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -133,7 +133,7 @@
                                  int cert_type )
 {
     mbedtls_pk_context key;
-    psa_key_slot_t slot;
+    psa_key_handle_t slot;
     psa_algorithm_t md_alg_psa;
     mbedtls_x509write_csr req;
     unsigned char buf[4096];