Merge pull request #4726 from athoelke/at-pbkdf2-doc-fixes

Fixes for PBKDF2 documentation
diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt
index 18945e5..fbd0470 100644
--- a/3rdparty/CMakeLists.txt
+++ b/3rdparty/CMakeLists.txt
@@ -1,17 +1,5 @@
-list (APPEND thirdparty_src)
-list (APPEND thirdparty_lib)
-list (APPEND thirdparty_inc_public)
-list (APPEND thirdparty_inc)
-list (APPEND thirdparty_def)
-
 execute_process(COMMAND ${MBEDTLS_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/config.py -f ${CMAKE_CURRENT_SOURCE_DIR}/../include/mbedtls/config.h get MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED RESULT_VARIABLE result)
 
 if(${result} EQUAL 0)
     add_subdirectory(everest)
 endif()
-
-set(thirdparty_src ${thirdparty_src} PARENT_SCOPE)
-set(thirdparty_lib ${thirdparty_lib} PARENT_SCOPE)
-set(thirdparty_inc_public ${thirdparty_inc_public} PARENT_SCOPE)
-set(thirdparty_inc ${thirdparty_inc} PARENT_SCOPE)
-set(thirdparty_def ${thirdparty_def} PARENT_SCOPE)
diff --git a/3rdparty/everest/CMakeLists.txt b/3rdparty/everest/CMakeLists.txt
index d81d995..ff9da7a 100644
--- a/3rdparty/everest/CMakeLists.txt
+++ b/3rdparty/everest/CMakeLists.txt
@@ -1,16 +1,15 @@
-list (APPEND everest_src)
-list (APPEND everest_inc_public)
-list (APPEND everest_inc)
-list (APPEND everest_def)
+add_library(everest
+  library/everest.c
+  library/x25519.c
+  library/Hacl_Curve25519_joined.c)
 
-set(everest_src
-  ${CMAKE_CURRENT_SOURCE_DIR}/library/everest.c
-  ${CMAKE_CURRENT_SOURCE_DIR}/library/x25519.c
-  ${CMAKE_CURRENT_SOURCE_DIR}/library/Hacl_Curve25519_joined.c
-)
-
-list(APPEND everest_inc_public ${CMAKE_CURRENT_SOURCE_DIR}/include)
-list(APPEND everest_inc ${CMAKE_CURRENT_SOURCE_DIR}/include/everest ${CMAKE_CURRENT_SOURCE_DIR}/include/everest/kremlib)
+target_include_directories(everest
+  PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+         $<BUILD_INTERFACE:${MBEDTLS_DIR}/include>
+         $<INSTALL_INTERFACE:include>
+  PRIVATE include/everest
+          include/everest/kremlib
+          ${MBEDTLS_DIR}/library/)
 
 if(INSTALL_MBEDTLS_HEADERS)
 
@@ -22,7 +21,7 @@
 
 endif(INSTALL_MBEDTLS_HEADERS)
 
-set(thirdparty_src ${thirdparty_src} ${everest_src} PARENT_SCOPE)
-set(thirdparty_inc_public ${thirdparty_inc_public} ${everest_inc_public} PARENT_SCOPE)
-set(thirdparty_inc ${thirdparty_inc} ${everest_inc} PARENT_SCOPE)
-set(thirdparty_def ${thirdparty_def} ${everest_def} PARENT_SCOPE)
+install(TARGETS everest
+  EXPORT MbedTLSTargets
+  DESTINATION ${LIB_INSTALL_DIR}
+  PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index efe3cab..f126f8d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,6 +20,8 @@
 # until our infrastructure catches up.
 cmake_minimum_required(VERSION 3.5.1)
 
+include(CMakePackageConfigHelpers)
+
 # https://cmake.org/cmake/help/latest/policy/CMP0011.html
 # Setting this policy is required in CMake >= 3.18.0, otherwise a warning is generated. The OLD
 # policy setting is deprecated, and will be removed in future versions.
@@ -223,7 +225,6 @@
 add_subdirectory(include)
 
 add_subdirectory(3rdparty)
-list(APPEND libs ${thirdparty_lib})
 
 add_subdirectory(library)
 
@@ -302,3 +303,37 @@
                     ${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl COPYONLY)
     endif()
 endif()
+
+configure_package_config_file(
+    "cmake/MbedTLSConfig.cmake.in"
+    "cmake/MbedTLSConfig.cmake"
+        INSTALL_DESTINATION "cmake")
+
+write_basic_package_version_file(
+    "cmake/MbedTLSConfigVersion.cmake"
+        COMPATIBILITY SameMajorVersion
+        VERSION 2.26.0)
+
+install(
+    FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfig.cmake"
+          "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfigVersion.cmake"
+    DESTINATION "cmake")
+
+export(
+    EXPORT MbedTLSTargets
+    NAMESPACE MbedTLS::
+    FILE "cmake/MbedTLSTargets.cmake")
+
+install(
+    EXPORT MbedTLSTargets
+    NAMESPACE MbedTLS::
+    DESTINATION "cmake"
+    FILE "MbedTLSTargets.cmake")
+
+if(CMAKE_VERSION VERSION_GREATER 3.14)
+    # Do not export the package by default
+    cmake_policy(SET CMP0090 NEW)
+
+    # Make this package visible to the system
+    export(PACKAGE MbedTLS)
+endif()
diff --git a/ChangeLog.d/add-cmake-package-config.txt b/ChangeLog.d/add-cmake-package-config.txt
new file mode 100644
index 0000000..3b73816
--- /dev/null
+++ b/ChangeLog.d/add-cmake-package-config.txt
@@ -0,0 +1,2 @@
+Changes
+   * Add CMake package config generation for CMake projects consuming Mbed TLS.
diff --git a/ChangeLog.d/spm_build.txt b/ChangeLog.d/spm_build.txt
new file mode 100644
index 0000000..6016d84
--- /dev/null
+++ b/ChangeLog.d/spm_build.txt
@@ -0,0 +1,4 @@
+Bugfix
+   * When MBEDTLS_PSA_CRYPTO_SPM is enabled, crypto_spe.h was not included
+     in all the right places. Include it from crypto_platform.h, which is
+     the natural place. Fixes #4649.
diff --git a/README.md b/README.md
index 78d3c30..4c3c938 100644
--- a/README.md
+++ b/README.md
@@ -184,6 +184,33 @@
 your value of CFLAGS doesn't override the content provided by cmake (depending
 on the build mode as seen above), it's merely prepended to it.
 
+#### Consuming Mbed TLS
+
+Mbed TLS provides a package config file for consumption as a dependency in other
+CMake projects. You can include Mbed TLS's CMake targets yourself with:
+
+    find_package(MbedTLS)
+
+If prompted, set `MbedTLS_DIR` to `${YOUR_MBEDTLS_INSTALL_DIR}/cmake`. This
+creates the following targets:
+
+- `MbedTLS::mbedcrypto` (Crypto library)
+- `MbedTLS::mbedtls` (TLS library)
+- `MbedTLS::mbedx509` (X509 library)
+
+You can then use these directly through `target_link_libraries()`:
+
+    add_executable(xyz)
+
+    target_link_libraries(xyz
+        PUBLIC MbedTLS::mbedtls
+               MbedTLS::mbedcrypto
+               MbedTLS::mbedx509)
+
+This will link the Mbed TLS libraries to your library or application, and add
+its include directories to your target (transitively, in the case of `PUBLIC` or
+`INTERFACE` link libraries).
+
 #### Mbed TLS as a subproject
 
 Mbed TLS supports being built as a CMake subproject. One can
diff --git a/cmake/MbedTLSConfig.cmake.in b/cmake/MbedTLSConfig.cmake.in
new file mode 100644
index 0000000..b65bbab
--- /dev/null
+++ b/cmake/MbedTLSConfig.cmake.in
@@ -0,0 +1,3 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/MbedTLSTargets.cmake")
diff --git a/include/mbedtls/gcm.h b/include/mbedtls/gcm.h
index f3c3035..06b06b4 100644
--- a/include/mbedtls/gcm.h
+++ b/include/mbedtls/gcm.h
@@ -339,6 +339,10 @@
  *                    then mbedtls_gcm_finish() never produces any output,
  *                    so \p output_size can be \c 0.
  *                  - \p output_size never needs to be more than \c 15.
+ * \param output_length On success, \p *output_length contains the actual
+ *                      length of the output written in \p output.
+ *                      On failure, the content of \p *output_length is
+ *                      unspecified.
  *
  * \return          \c 0 on success.
  * \return          #MBEDTLS_ERR_GCM_BAD_INPUT on failure:
@@ -347,6 +351,7 @@
  */
 int mbedtls_gcm_finish( mbedtls_gcm_context *ctx,
                         unsigned char *output, size_t output_size,
+                        size_t *output_length,
                         unsigned char *tag, size_t tag_len );
 
 /**
diff --git a/include/psa/crypto_platform.h b/include/psa/crypto_platform.h
index d60b773..edf7210 100644
--- a/include/psa/crypto_platform.h
+++ b/include/psa/crypto_platform.h
@@ -82,6 +82,18 @@
 
 #endif /* MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER */
 
+/*
+ * 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)
+#define PSA_CRYPTO_SECURE 1
+#include "crypto_spe.h"
+#endif // MBEDTLS_PSA_CRYPTO_SPM
+
 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
 /** The type of the context passed to mbedtls_psa_external_get_random().
  *
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index d6ecba5..14fecff 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -82,8 +82,6 @@
     version_features.c
 )
 
-list(APPEND src_crypto ${thirdparty_src})
-
 set(src_x509
     x509.c
     x509_create.c
@@ -175,6 +173,10 @@
     set_target_properties(${mbedcrypto_static_target} PROPERTIES OUTPUT_NAME mbedcrypto)
     target_link_libraries(${mbedcrypto_static_target} PUBLIC ${libs})
 
+    if(TARGET everest)
+        target_link_libraries(${mbedcrypto_static_target} PUBLIC everest)
+    endif()
+
     add_library(${mbedx509_static_target} STATIC ${src_x509})
     set_target_properties(${mbedx509_static_target} PROPERTIES OUTPUT_NAME mbedx509)
     target_link_libraries(${mbedx509_static_target} PUBLIC ${libs} ${mbedcrypto_static_target})
@@ -189,6 +191,10 @@
     set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 2.26.0 SOVERSION 6)
     target_link_libraries(${mbedcrypto_target} PUBLIC ${libs})
 
+    if(TARGET everest)
+        target_link_libraries(${mbedcrypto_target} PUBLIC everest)
+    endif()
+
     add_library(${mbedx509_target} SHARED ${src_x509})
     set_target_properties(${mbedx509_target} PROPERTIES VERSION 2.26.0 SOVERSION 1)
     target_link_libraries(${mbedx509_target} PUBLIC ${libs} ${mbedcrypto_target})
@@ -205,15 +211,14 @@
     # /library needs to be listed explicitly when building .c files outside
     # of /library (which currently means: under /3rdparty).
     target_include_directories(${target}
-        PUBLIC ${MBEDTLS_DIR}/include/
-        PUBLIC ${thirdparty_inc_public}
-        PRIVATE ${MBEDTLS_DIR}/library/
-        PRIVATE ${thirdparty_inc})
-    target_compile_definitions(${target}
-        PRIVATE ${thirdparty_def})
-    install(TARGETS ${target}
-            DESTINATION ${LIB_INSTALL_DIR}
-            PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+        PUBLIC $<BUILD_INTERFACE:${MBEDTLS_DIR}/include/>
+               $<INSTALL_INTERFACE:include/>
+        PRIVATE ${MBEDTLS_DIR}/library/)
+    install(
+        TARGETS ${target}
+        EXPORT MbedTLSTargets
+        DESTINATION ${LIB_INSTALL_DIR}
+        PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
 endforeach(target)
 
 set(lib_target "${MBEDTLS_TARGET_PREFIX}lib")
diff --git a/library/cipher.c b/library/cipher.c
index 4f56b52..546cace 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -1109,9 +1109,14 @@
 
 #if defined(MBEDTLS_GCM_C)
     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
+    {
+        size_t output_length;
+        /* The code here doesn't yet support alternative implementations
+         * that can delay up to a block of output. */
         return( mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx,
-                                    NULL, 0,
+                                    NULL, 0, &output_length,
                                     tag, tag_len ) );
+    }
 #endif
 
 #if defined(MBEDTLS_CHACHAPOLY_C)
@@ -1158,12 +1163,16 @@
 #if defined(MBEDTLS_GCM_C)
     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
     {
+        size_t output_length;
+        /* The code here doesn't yet support alternative implementations
+         * that can delay up to a block of output. */
+
         if( tag_len > sizeof( check_tag ) )
             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
 
         if( 0 != ( ret = mbedtls_gcm_finish(
                        (mbedtls_gcm_context *) ctx->cipher_ctx,
-                       NULL, 0,
+                       NULL, 0, &output_length,
                        check_tag, tag_len ) ) )
         {
             return( ret );
diff --git a/library/gcm.c b/library/gcm.c
index 8fa4ee7..835b1b2 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -532,6 +532,7 @@
 
 int mbedtls_gcm_finish( mbedtls_gcm_context *ctx,
                         unsigned char *output, size_t output_size,
+                        size_t *output_length,
                         unsigned char *tag, size_t tag_len )
 {
     unsigned char work_buf[16];
@@ -546,6 +547,7 @@
      * for the sake of alternative implementations. */
     (void) output;
     (void) output_size;
+    *output_length = 0;
 
     orig_len = ctx->len * 8;
     orig_add_len = ctx->add_len * 8;
@@ -616,7 +618,7 @@
                                     output, length, &olen ) ) != 0 )
         return( ret );
 
-    if( ( ret = mbedtls_gcm_finish( ctx, NULL, 0, tag, tag_len ) ) != 0 )
+    if( ( ret = mbedtls_gcm_finish( ctx, NULL, 0, &olen, tag, tag_len ) ) != 0 )
         return( ret );
 
     return( 0 );
@@ -1068,7 +1070,7 @@
                     goto exit;
             }
 
-            ret = mbedtls_gcm_finish( &ctx, NULL, 0, tag_buf, 16 );
+            ret = mbedtls_gcm_finish( &ctx, NULL, 0, &olen, tag_buf, 16 );
             if( ret != 0 )
                 goto exit;
 
@@ -1140,7 +1142,7 @@
                     goto exit;
             }
 
-            ret = mbedtls_gcm_finish( &ctx, NULL, 0, tag_buf, 16 );
+            ret = mbedtls_gcm_finish( &ctx, NULL, 0, &olen, tag_buf, 16 );
             if( ret != 0 )
                 goto exit;
 
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 4f932c6..5884bc7 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -26,7 +26,6 @@
 #include "check_crypto_config.h"
 #endif
 
-#include "psa_crypto_service_integration.h"
 #include "psa/crypto.h"
 
 #include "psa_crypto_cipher.h"
@@ -2089,34 +2088,54 @@
 psa_status_t psa_hash_setup( psa_hash_operation_t *operation,
                              psa_algorithm_t alg )
 {
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
     /* A context must be freshly initialized before it can be set up. */
     if( operation->id != 0 )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
 
     if( !PSA_ALG_IS_HASH( alg ) )
-        return( PSA_ERROR_INVALID_ARGUMENT );
+    {
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto exit;
+    }
 
     /* Ensure all of the context is zeroized, since PSA_HASH_OPERATION_INIT only
      * directly zeroes the int-sized dummy member of the context union. */
     memset( &operation->ctx, 0, sizeof( operation->ctx ) );
 
-    return( psa_driver_wrapper_hash_setup( operation, alg ) );
+    status = psa_driver_wrapper_hash_setup( operation, alg );
+
+exit:
+    if( status != PSA_SUCCESS )
+        psa_hash_abort( operation );
+
+    return status;
 }
 
 psa_status_t psa_hash_update( psa_hash_operation_t *operation,
                               const uint8_t *input,
                               size_t input_length )
 {
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
     if( operation->id == 0 )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
 
     /* Don't require hash implementations to behave correctly on a
      * zero-length input, which may have an invalid pointer. */
     if( input_length == 0 )
         return( PSA_SUCCESS );
 
-    psa_status_t status = psa_driver_wrapper_hash_update( operation,
-                                                          input, input_length );
+    status = psa_driver_wrapper_hash_update( operation, input, input_length );
+
+exit:
     if( status != PSA_SUCCESS )
         psa_hash_abort( operation );
 
@@ -2148,13 +2167,24 @@
                             operation,
                             actual_hash, sizeof( actual_hash ),
                             &actual_hash_length );
+
     if( status != PSA_SUCCESS )
-        return( status );
+        goto exit;
+
     if( actual_hash_length != hash_length )
-        return( PSA_ERROR_INVALID_SIGNATURE );
+    {
+        status = PSA_ERROR_INVALID_SIGNATURE;
+        goto exit;
+    }
+
     if( mbedtls_psa_safer_memcmp( hash, actual_hash, actual_hash_length ) != 0 )
-        return( PSA_ERROR_INVALID_SIGNATURE );
-    return( PSA_SUCCESS );
+        status = PSA_ERROR_INVALID_SIGNATURE;
+
+exit:
+    if( status != PSA_SUCCESS )
+        psa_hash_abort(operation);
+
+    return( status );
 }
 
 psa_status_t psa_hash_compute( psa_algorithm_t alg,
@@ -2276,11 +2306,14 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_key_slot_t *slot;
+    psa_key_slot_t *slot = NULL;
 
     /* A context must be freshly initialized before it can be set up. */
     if( operation->id != 0 )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
 
     status = psa_get_and_lock_key_slot_with_policy(
                  key,
@@ -2288,7 +2321,7 @@
                  is_sign ? PSA_KEY_USAGE_SIGN_HASH : PSA_KEY_USAGE_VERIFY_HASH,
                  alg );
     if( status != PSA_SUCCESS )
-        return( status );
+        goto exit;
 
     psa_key_attributes_t attributes = {
         .core = slot->attr
@@ -2369,29 +2402,37 @@
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t abort_status = PSA_ERROR_CORRUPTION_DETECTED;
 
-    /* Set the output length and content to a safe default, such that in
-     * case the caller misses an error check, the output would be an
-     * unachievable MAC. */
-    *mac_length = mac_size;
-
     if( operation->id == 0 )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
 
     if( ! operation->is_sign )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
 
     /* Sanity check. This will guarantee that mac_size != 0 (and so mac != NULL)
      * once all the error checks are done. */
     if( operation->mac_size == 0 )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
 
     if( mac_size < operation->mac_size )
-        return( PSA_ERROR_BUFFER_TOO_SMALL );
+    {
+        status = PSA_ERROR_BUFFER_TOO_SMALL;
+        goto exit;
+    }
 
     status = psa_driver_wrapper_mac_sign_finish( operation,
                                                  mac, operation->mac_size,
                                                  mac_length );
 
+exit:
     /* In case of success, set the potential excess room in the output buffer
      * to an invalid value, to avoid potentially leaking a longer MAC.
      * In case of error, set the output length and content to a safe default,
@@ -2421,21 +2462,27 @@
     psa_status_t abort_status = PSA_ERROR_CORRUPTION_DETECTED;
 
     if( operation->id == 0 )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
 
     if( operation->is_sign )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
 
     if( operation->mac_size != mac_length )
     {
         status = PSA_ERROR_INVALID_SIGNATURE;
-        goto cleanup;
+        goto exit;
     }
 
     status = psa_driver_wrapper_mac_verify_finish( operation,
                                                    mac, mac_length );
 
-cleanup:
+exit:
     abort_status = psa_mac_abort( operation );
 
     return( status == PSA_SUCCESS ? abort_status : status );
@@ -3185,18 +3232,24 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_key_slot_t *slot;
+    psa_key_slot_t *slot = NULL;
     psa_key_usage_t usage = ( cipher_operation == MBEDTLS_ENCRYPT ?
                               PSA_KEY_USAGE_ENCRYPT :
                               PSA_KEY_USAGE_DECRYPT );
 
     /* A context must be freshly initialized before it can be set up. */
     if( operation->id != 0 )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
 
     /* The requested algorithm must be one that can be processed by cipher. */
     if( ! PSA_ALG_IS_CIPHER( alg ) )
-        return( PSA_ERROR_INVALID_ARGUMENT );
+    {
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto exit;
+    }
 
     /* Fetch key material from key storage. */
     status = psa_get_and_lock_key_slot_with_policy( key, &slot, usage, alg );
@@ -3266,12 +3319,14 @@
 
     if( operation->id == 0 )
     {
-        return( PSA_ERROR_BAD_STATE );
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
     }
 
     if( operation->iv_set || ! operation->iv_required )
     {
-        return( PSA_ERROR_BAD_STATE );
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
     }
 
     if( iv_size < operation->default_iv_length )
@@ -3307,18 +3362,28 @@
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 
     if( operation->id == 0 )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
 
     if( operation->iv_set || ! operation->iv_required )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
+    }
 
     if( iv_length > PSA_CIPHER_IV_MAX_SIZE )
-        return( PSA_ERROR_INVALID_ARGUMENT );
+    {
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto exit;
+    }
 
     status = psa_driver_wrapper_cipher_set_iv( operation,
                                                iv,
                                                iv_length );
 
+exit:
     if( status == PSA_SUCCESS )
         operation->iv_set = 1;
     else
@@ -3337,11 +3402,14 @@
 
     if( operation->id == 0 )
     {
-        return( PSA_ERROR_BAD_STATE );
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
     }
+
     if( operation->iv_required && ! operation->iv_set )
     {
-        return( PSA_ERROR_BAD_STATE );
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
     }
 
     status = psa_driver_wrapper_cipher_update( operation,
@@ -3350,6 +3418,8 @@
                                                output,
                                                output_size,
                                                output_length );
+
+exit:
     if( status != PSA_SUCCESS )
         psa_cipher_abort( operation );
 
@@ -3365,17 +3435,22 @@
 
     if( operation->id == 0 )
     {
-        return( PSA_ERROR_BAD_STATE );
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
     }
+
     if( operation->iv_required && ! operation->iv_set )
     {
-        return( PSA_ERROR_BAD_STATE );
+        status = PSA_ERROR_BAD_STATE;
+        goto exit;
     }
 
     status = psa_driver_wrapper_cipher_finish( operation,
                                                output,
                                                output_size,
                                                output_length );
+
+exit:
     if( status == PSA_SUCCESS )
         return( psa_cipher_abort( operation ) );
     else
diff --git a/library/psa_crypto_client.c b/library/psa_crypto_client.c
index e84cf30..629feb7 100644
--- a/library/psa_crypto_client.c
+++ b/library/psa_crypto_client.c
@@ -19,7 +19,6 @@
  */
 
 #include "common.h"
-#include "psa_crypto_service_integration.h"
 #include "psa/crypto.h"
 
 #if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
diff --git a/library/psa_crypto_service_integration.h b/library/psa_crypto_service_integration.h
deleted file mode 100644
index 87889af..0000000
--- a/library/psa_crypto_service_integration.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0
- *
- *  Licensed under the Apache License, Version 2.0 (the "License"); you may
- *  not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#ifndef PSA_CRYPTO_SERVICE_INTEGRATION_H
-#define PSA_CRYPTO_SERVICE_INTEGRATION_H
-
-/*
- * 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 the file which included this file is being
- * compiled for SPE. The files crypto_structs.h and crypto_types.h have
- * different implementations for NSPE and SPE and are compiled according to this
- * flag.
- */
-#define PSA_CRYPTO_SECURE 1
-#include "crypto_spe.h"
-#endif // MBEDTLS_PSA_CRYPTO_SPM
-
-#endif // PSA_CRYPTO_SERVICE_INTEGRATION_H
diff --git a/library/psa_crypto_slot_management.c b/library/psa_crypto_slot_management.c
index a95b4b3..925d684 100644
--- a/library/psa_crypto_slot_management.c
+++ b/library/psa_crypto_slot_management.c
@@ -22,7 +22,6 @@
 
 #if defined(MBEDTLS_PSA_CRYPTO_C)
 
-#include "psa_crypto_service_integration.h"
 #include "psa/crypto.h"
 
 #include "psa_crypto_core.h"
diff --git a/library/psa_crypto_storage.c b/library/psa_crypto_storage.c
index 575e992..09cbab4 100644
--- a/library/psa_crypto_storage.c
+++ b/library/psa_crypto_storage.c
@@ -25,7 +25,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "psa_crypto_service_integration.h"
 #include "psa/crypto.h"
 #include "psa_crypto_storage.h"
 #include "mbedtls/platform_util.h"
diff --git a/programs/test/cmake_package/.gitignore b/programs/test/cmake_package/.gitignore
new file mode 100644
index 0000000..9ae6b59
--- /dev/null
+++ b/programs/test/cmake_package/.gitignore
@@ -0,0 +1,3 @@
+build
+Makefile
+cmake_package
diff --git a/programs/test/cmake_package/CMakeLists.txt b/programs/test/cmake_package/CMakeLists.txt
new file mode 100644
index 0000000..518d2e9
--- /dev/null
+++ b/programs/test/cmake_package/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+#
+# Simulate configuring and building Mbed TLS as the user might do it. We'll
+# skip installing it, and use the build directory directly instead.
+#
+
+set(MbedTLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../..")
+set(MbedTLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/mbedtls")
+
+execute_process(
+    COMMAND "${CMAKE_COMMAND}"
+        "-H${MbedTLS_SOURCE_DIR}"
+        "-B${MbedTLS_BINARY_DIR}"
+        "-DENABLE_PROGRAMS=NO"
+        "-DENABLE_TESTING=NO")
+
+execute_process(
+    COMMAND "${CMAKE_COMMAND}"
+        --build "${MbedTLS_BINARY_DIR}")
+
+#
+# Locate the package.
+#
+
+set(MbedTLS_DIR "${MbedTLS_BINARY_DIR}/cmake")
+find_package(MbedTLS REQUIRED)
+
+#
+# At this point, the Mbed TLS targets should have been imported, and we can now
+# link to them from our own program.
+#
+
+add_executable(cmake_package cmake_package.c)
+target_link_libraries(cmake_package
+    MbedTLS::mbedcrypto MbedTLS::mbedtls MbedTLS::mbedx509)
diff --git a/programs/test/cmake_package/cmake_package.c b/programs/test/cmake_package/cmake_package.c
new file mode 100644
index 0000000..3f993a0
--- /dev/null
+++ b/programs/test/cmake_package/cmake_package.c
@@ -0,0 +1,53 @@
+/*
+ *  Simple program to test that Mbed TLS builds correctly as a CMake package.
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_fprintf         fprintf
+#define mbedtls_printf          printf
+#define mbedtls_exit            exit
+#define MBEDTLS_EXIT_SUCCESS    EXIT_SUCCESS
+#define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE
+#endif /* MBEDTLS_PLATFORM_C */
+
+#include "mbedtls/version.h"
+
+/* The main reason to build this is for testing the CMake build, so the program
+ * doesn't need to do very much. It calls a single library function to ensure
+ * linkage works, but that is all. */
+int main()
+{
+    /* This version string is 18 bytes long, as advised by version.h. */
+    char version[18];
+
+    mbedtls_version_get_string_full( version );
+
+    mbedtls_printf( "Built against %s\n", version );
+
+    return( 0 );
+}
diff --git a/programs/test/cmake_package_install/.gitignore b/programs/test/cmake_package_install/.gitignore
new file mode 100644
index 0000000..b9b8282
--- /dev/null
+++ b/programs/test/cmake_package_install/.gitignore
@@ -0,0 +1,3 @@
+build
+Makefile
+cmake_package_install
diff --git a/programs/test/cmake_package_install/CMakeLists.txt b/programs/test/cmake_package_install/CMakeLists.txt
new file mode 100644
index 0000000..711a1e5
--- /dev/null
+++ b/programs/test/cmake_package_install/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+#
+# Simulate configuring and building Mbed TLS as the user might do it. We'll
+# install into a directory inside our own build directory.
+#
+
+set(MbedTLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../..")
+set(MbedTLS_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/mbedtls")
+set(MbedTLS_BINARY_DIR "${MbedTLS_INSTALL_DIR}${CMAKE_FILES_DIRECTORY}")
+
+execute_process(
+    COMMAND "${CMAKE_COMMAND}"
+        "-H${MbedTLS_SOURCE_DIR}"
+        "-B${MbedTLS_BINARY_DIR}"
+        "-DENABLE_PROGRAMS=NO"
+        "-DENABLE_TESTING=NO"
+        "-DCMAKE_INSTALL_PREFIX=${MbedTLS_INSTALL_DIR}")
+
+execute_process(
+    COMMAND "${CMAKE_COMMAND}"
+        --build "${MbedTLS_BINARY_DIR}"
+        --target install)
+
+#
+# Locate the package.
+#
+
+set(MbedTLS_DIR "${MbedTLS_INSTALL_DIR}/cmake")
+find_package(MbedTLS REQUIRED)
+
+#
+# At this point, the Mbed TLS targets should have been imported, and we can now
+# link to them from our own program.
+#
+
+add_executable(cmake_package_install cmake_package_install.c)
+target_link_libraries(cmake_package_install
+    MbedTLS::mbedcrypto MbedTLS::mbedtls MbedTLS::mbedx509)
diff --git a/programs/test/cmake_package_install/cmake_package_install.c b/programs/test/cmake_package_install/cmake_package_install.c
new file mode 100644
index 0000000..1ae0b84
--- /dev/null
+++ b/programs/test/cmake_package_install/cmake_package_install.c
@@ -0,0 +1,54 @@
+/*
+ * Simple program to test that Mbed TLS builds correctly as an installable CMake
+ * package.
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_fprintf         fprintf
+#define mbedtls_printf          printf
+#define mbedtls_exit            exit
+#define MBEDTLS_EXIT_SUCCESS    EXIT_SUCCESS
+#define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE
+#endif /* MBEDTLS_PLATFORM_C */
+
+#include "mbedtls/version.h"
+
+/* The main reason to build this is for testing the CMake build, so the program
+ * doesn't need to do very much. It calls a single library function to ensure
+ * linkage works, but that is all. */
+int main()
+{
+    /* This version string is 18 bytes long, as advised by version.h. */
+    char version[18];
+
+    mbedtls_version_get_string_full( version );
+
+    mbedtls_printf( "Built against %s\n", version );
+
+    return( 0 );
+}
diff --git a/tests/include/spe/crypto_spe.h b/tests/include/spe/crypto_spe.h
new file mode 100644
index 0000000..f80fd86
--- /dev/null
+++ b/tests/include/spe/crypto_spe.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/**
+ * \file crypto_spe.h
+ *
+ * \brief When Mbed Crypto is built with the MBEDTLS_PSA_CRYPTO_SPM option
+ *        enabled, this header is included by all .c files in Mbed Crypto that
+ *        use PSA Crypto function names. This avoids duplication of symbols
+ *        between TF-M and Mbed Crypto.
+ *
+ * \note  This file should be included before including any PSA Crypto headers
+ *        from Mbed Crypto.
+ */
+
+#ifndef CRYPTO_SPE_H
+#define CRYPTO_SPE_H
+
+#define PSA_FUNCTION_NAME(x) mbedcrypto__ ## x
+
+#define psa_crypto_init \
+        PSA_FUNCTION_NAME(psa_crypto_init)
+#define psa_key_derivation_get_capacity \
+        PSA_FUNCTION_NAME(psa_key_derivation_get_capacity)
+#define psa_key_derivation_set_capacity \
+        PSA_FUNCTION_NAME(psa_key_derivation_set_capacity)
+#define psa_key_derivation_input_bytes \
+        PSA_FUNCTION_NAME(psa_key_derivation_input_bytes)
+#define psa_key_derivation_output_bytes \
+        PSA_FUNCTION_NAME(psa_key_derivation_output_bytes)
+#define psa_key_derivation_input_key \
+        PSA_FUNCTION_NAME(psa_key_derivation_input_key)
+#define psa_key_derivation_output_key \
+        PSA_FUNCTION_NAME(psa_key_derivation_output_key)
+#define psa_key_derivation_setup \
+        PSA_FUNCTION_NAME(psa_key_derivation_setup)
+#define psa_key_derivation_abort \
+        PSA_FUNCTION_NAME(psa_key_derivation_abort)
+#define psa_key_derivation_key_agreement \
+        PSA_FUNCTION_NAME(psa_key_derivation_key_agreement)
+#define psa_raw_key_agreement \
+        PSA_FUNCTION_NAME(psa_raw_key_agreement)
+#define psa_generate_random \
+        PSA_FUNCTION_NAME(psa_generate_random)
+#define psa_aead_encrypt \
+        PSA_FUNCTION_NAME(psa_aead_encrypt)
+#define psa_aead_decrypt \
+        PSA_FUNCTION_NAME(psa_aead_decrypt)
+#define psa_open_key \
+        PSA_FUNCTION_NAME(psa_open_key)
+#define psa_close_key \
+        PSA_FUNCTION_NAME(psa_close_key)
+#define psa_import_key \
+        PSA_FUNCTION_NAME(psa_import_key)
+#define psa_destroy_key \
+        PSA_FUNCTION_NAME(psa_destroy_key)
+#define psa_get_key_attributes \
+        PSA_FUNCTION_NAME(psa_get_key_attributes)
+#define psa_reset_key_attributes \
+        PSA_FUNCTION_NAME(psa_reset_key_attributes)
+#define psa_export_key \
+        PSA_FUNCTION_NAME(psa_export_key)
+#define psa_export_public_key \
+        PSA_FUNCTION_NAME(psa_export_public_key)
+#define psa_purge_key \
+        PSA_FUNCTION_NAME(psa_purge_key)
+#define psa_copy_key \
+        PSA_FUNCTION_NAME(psa_copy_key)
+#define psa_cipher_operation_init \
+        PSA_FUNCTION_NAME(psa_cipher_operation_init)
+#define psa_cipher_generate_iv \
+        PSA_FUNCTION_NAME(psa_cipher_generate_iv)
+#define psa_cipher_set_iv \
+        PSA_FUNCTION_NAME(psa_cipher_set_iv)
+#define psa_cipher_encrypt_setup \
+        PSA_FUNCTION_NAME(psa_cipher_encrypt_setup)
+#define psa_cipher_decrypt_setup \
+        PSA_FUNCTION_NAME(psa_cipher_decrypt_setup)
+#define psa_cipher_update \
+        PSA_FUNCTION_NAME(psa_cipher_update)
+#define psa_cipher_finish \
+        PSA_FUNCTION_NAME(psa_cipher_finish)
+#define psa_cipher_abort \
+        PSA_FUNCTION_NAME(psa_cipher_abort)
+#define psa_hash_operation_init \
+        PSA_FUNCTION_NAME(psa_hash_operation_init)
+#define psa_hash_setup \
+        PSA_FUNCTION_NAME(psa_hash_setup)
+#define psa_hash_update \
+        PSA_FUNCTION_NAME(psa_hash_update)
+#define psa_hash_finish \
+        PSA_FUNCTION_NAME(psa_hash_finish)
+#define psa_hash_verify \
+        PSA_FUNCTION_NAME(psa_hash_verify)
+#define psa_hash_abort \
+        PSA_FUNCTION_NAME(psa_hash_abort)
+#define psa_hash_clone \
+        PSA_FUNCTION_NAME(psa_hash_clone)
+#define psa_hash_compute \
+        PSA_FUNCTION_NAME(psa_hash_compute)
+#define psa_hash_compare \
+        PSA_FUNCTION_NAME(psa_hash_compare)
+#define psa_mac_operation_init \
+        PSA_FUNCTION_NAME(psa_mac_operation_init)
+#define psa_mac_sign_setup \
+        PSA_FUNCTION_NAME(psa_mac_sign_setup)
+#define psa_mac_verify_setup \
+        PSA_FUNCTION_NAME(psa_mac_verify_setup)
+#define psa_mac_update \
+        PSA_FUNCTION_NAME(psa_mac_update)
+#define psa_mac_sign_finish \
+        PSA_FUNCTION_NAME(psa_mac_sign_finish)
+#define psa_mac_verify_finish \
+        PSA_FUNCTION_NAME(psa_mac_verify_finish)
+#define psa_mac_abort \
+        PSA_FUNCTION_NAME(psa_mac_abort)
+#define psa_sign_hash \
+        PSA_FUNCTION_NAME(psa_sign_hash)
+#define psa_verify_hash \
+        PSA_FUNCTION_NAME(psa_verify_hash)
+#define psa_asymmetric_encrypt \
+        PSA_FUNCTION_NAME(psa_asymmetric_encrypt)
+#define psa_asymmetric_decrypt \
+        PSA_FUNCTION_NAME(psa_asymmetric_decrypt)
+#define psa_generate_key \
+        PSA_FUNCTION_NAME(psa_generate_key)
+
+#endif /* CRYPTO_SPE_H */
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index fe53669..c0771f0 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -273,7 +273,7 @@
            -iname CMakeFiles -exec rm -rf {} \+ -o \
            \( -iname cmake_install.cmake -o \
               -iname CTestTestfile.cmake -o \
-              -iname CMakeCache.txt \) -exec rm {} \+
+              -iname CMakeCache.txt \) -exec rm -f {} \+
     # Recover files overwritten by in-tree CMake builds
     rm -f include/Makefile include/mbedtls/Makefile programs/*/Makefile
     git update-index --no-skip-worktree Makefile library/Makefile programs/Makefile tests/Makefile programs/fuzz/Makefile
@@ -284,6 +284,16 @@
     rm -f programs/test/cmake_subproject/Makefile
     rm -f programs/test/cmake_subproject/cmake_subproject
 
+    # Remove any artifacts from the component_test_cmake_as_package test.
+    rm -rf programs/test/cmake_package/build
+    rm -f programs/test/cmake_package/Makefile
+    rm -f programs/test/cmake_package/cmake_package
+
+    # Remove any artifacts from the component_test_cmake_as_installed_package test.
+    rm -rf programs/test/cmake_package_install/build
+    rm -f programs/test/cmake_package_install/Makefile
+    rm -f programs/test/cmake_package_install/cmake_package_install
+
     if [ -f "$CONFIG_BAK" ]; then
         mv "$CONFIG_BAK" "$CONFIG_H"
     fi
@@ -820,6 +830,32 @@
     make test
 }
 
+# check_renamed_symbols HEADER LIB
+# Check that if HEADER contains '#define MACRO ...' then MACRO is not a symbol
+# name is LIB.
+check_renamed_symbols () {
+    ! nm "$2" | sed 's/.* //' |
+      grep -x -F "$(sed -n 's/^ *# *define  *\([A-Z_a-z][0-9A-Z_a-z]*\)..*/\1/p' "$1")"
+}
+
+component_build_psa_crypto_spm () {
+    msg "build: full config - USE_PSA_CRYPTO + PSA_CRYPTO_KEY_ID_ENCODES_OWNER + PSA_CRYPTO_SPM, make, gcc"
+    scripts/config.py full
+    scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
+    scripts/config.py unset MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_SPM
+    # We can only compile, not link, since our test and sample programs
+    # aren't equipped for the modified names used when MBEDTLS_PSA_CRYPTO_SPM
+    # is active.
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -I../tests/include/spe' lib
+
+    # Check that if a symbol is renamed by crypto_spe.h, the non-renamed
+    # version is not present.
+    echo "Checking for renamed symbols in the library"
+    if_build_succeeded check_renamed_symbols tests/include/spe/crypto_spe.h library/libmbedcrypto.a
+}
+
 component_test_psa_crypto_client () {
     msg "build: default config - PSA_CRYPTO_C + PSA_CRYPTO_CLIENT, make"
     scripts/config.py unset MBEDTLS_PSA_CRYPTO_C
@@ -2514,6 +2550,32 @@
     unset MBEDTLS_ROOT_DIR
 }
 
+component_test_cmake_as_package () {
+    msg "build: cmake 'as-package' build"
+    MBEDTLS_ROOT_DIR="$PWD"
+
+    cd programs/test/cmake_package
+    cmake .
+    make
+    if_build_succeeded ./cmake_package
+
+    cd "$MBEDTLS_ROOT_DIR"
+    unset MBEDTLS_ROOT_DIR
+}
+
+component_test_cmake_as_package_install () {
+    msg "build: cmake 'as-installed-package' build"
+    MBEDTLS_ROOT_DIR="$PWD"
+
+    cd programs/test/cmake_package_install
+    cmake .
+    make
+    if_build_succeeded ./cmake_package_install
+
+    cd "$MBEDTLS_ROOT_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
diff --git a/tests/suites/test_suite_gcm.function b/tests/suites/test_suite_gcm.function
index 49859dd..c530e6b 100644
--- a/tests/suites/test_suite_gcm.function
+++ b/tests/suites/test_suite_gcm.function
@@ -50,7 +50,8 @@
     output = NULL;
 
     ASSERT_ALLOC( output, tag->len );
-    TEST_EQUAL( 0, mbedtls_gcm_finish( ctx, NULL, 0, output, tag->len ) );
+    TEST_EQUAL( 0, mbedtls_gcm_finish( ctx, NULL, 0, &olen, output, tag->len ) );
+    TEST_EQUAL( 0, olen );
     ASSERT_COMPARE( output, tag->len, tag->x, tag->len );
     mbedtls_free( output );
     output = NULL;
@@ -96,7 +97,8 @@
     output = NULL;
 
     ASSERT_ALLOC( output, tag->len );
-    TEST_EQUAL( 0, mbedtls_gcm_finish( ctx, NULL, 0, output, tag->len ) );
+    TEST_EQUAL( 0, mbedtls_gcm_finish( ctx, NULL, 0, &olen, output, tag->len ) );
+    TEST_EQUAL( 0, olen );
     ASSERT_COMPARE( output, tag->len, tag->x, tag->len );
 
 exit:
@@ -125,7 +127,9 @@
     }
 
     ASSERT_ALLOC( output_tag, tag->len );
-    TEST_EQUAL( 0, mbedtls_gcm_finish( ctx, NULL, 0, output_tag, tag->len ) );
+    TEST_EQUAL( 0, mbedtls_gcm_finish( ctx, NULL, 0, &olen,
+                                       output_tag, tag->len ) );
+    TEST_EQUAL( 0, olen );
     ASSERT_COMPARE( output_tag, tag->len, tag->x, tag->len );
 
 exit:
@@ -138,11 +142,13 @@
                                    const data_t *tag )
 {
     uint8_t *output = NULL;
+    size_t olen = 0;
 
     TEST_EQUAL( 0, mbedtls_gcm_starts( ctx, mode,
                                        iv->x, iv->len ) );
     ASSERT_ALLOC( output, tag->len );
-    TEST_EQUAL( 0, mbedtls_gcm_finish( ctx, NULL, 0, output, tag->len ) );
+    TEST_EQUAL( 0, mbedtls_gcm_finish( ctx, NULL, 0, &olen, output, tag->len ) );
+    TEST_EQUAL( 0, olen );
     ASSERT_COMPARE( output, tag->len, tag->x, tag->len );
 
 exit:
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 33e7c95..41e2972 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -19,6 +19,11 @@
 /* If this comes up, it's a bug in the test code or in the test data. */
 #define UNUSED 0xdeadbeef
 
+/* Assert that an operation is (not) active.
+ * This serves as a proxy for checking if the operation is aborted. */
+#define ASSERT_OPERATION_IS_ACTIVE(   operation ) TEST_ASSERT( operation.id != 0 )
+#define ASSERT_OPERATION_IS_INACTIVE( operation ) TEST_ASSERT( operation.id == 0 )
+
 /** An invalid export length that will never be set by psa_export_key(). */
 static const size_t INVALID_EXPORT_LENGTH = ~0U;
 
@@ -1540,15 +1545,28 @@
 
     /* Call setup twice in a row. */
     PSA_ASSERT( psa_hash_setup( &operation, alg ) );
+    ASSERT_OPERATION_IS_ACTIVE( operation );
     TEST_EQUAL( psa_hash_setup( &operation, alg ),
                 PSA_ERROR_BAD_STATE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
     PSA_ASSERT( psa_hash_abort( &operation ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
 
     /* Call update without calling setup beforehand. */
     TEST_EQUAL( psa_hash_update( &operation, input, sizeof( input ) ),
                 PSA_ERROR_BAD_STATE );
     PSA_ASSERT( psa_hash_abort( &operation ) );
 
+    /* Check that update calls abort on error. */
+    PSA_ASSERT( psa_hash_setup( &operation, alg ) );
+    operation.id = UINT_MAX;
+    ASSERT_OPERATION_IS_ACTIVE( operation );
+    TEST_EQUAL( psa_hash_update( &operation, input, sizeof( input ) ),
+                PSA_ERROR_BAD_STATE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
+    PSA_ASSERT( psa_hash_abort( &operation ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
+
     /* Call update after finish. */
     PSA_ASSERT( psa_hash_setup( &operation, alg ) );
     PSA_ASSERT( psa_hash_finish( &operation,
@@ -1574,11 +1592,14 @@
 
     /* Call verify twice in a row. */
     PSA_ASSERT( psa_hash_setup( &operation, alg ) );
+    ASSERT_OPERATION_IS_ACTIVE( operation );
     PSA_ASSERT( psa_hash_verify( &operation,
                                  valid_hash, sizeof( valid_hash ) ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
     TEST_EQUAL( psa_hash_verify( &operation,
                                  valid_hash, sizeof( valid_hash ) ),
                 PSA_ERROR_BAD_STATE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
     PSA_ASSERT( psa_hash_abort( &operation ) );
 
     /* Call finish without calling setup beforehand. */
@@ -1627,8 +1648,12 @@
 
     /* psa_hash_verify with a smaller hash than expected */
     PSA_ASSERT( psa_hash_setup( &operation, alg ) );
+    ASSERT_OPERATION_IS_ACTIVE( operation );
     TEST_EQUAL( psa_hash_verify( &operation, hash, expected_size - 1 ),
                 PSA_ERROR_INVALID_SIGNATURE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
+    PSA_ASSERT( psa_hash_abort( &operation ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
 
     /* psa_hash_verify with a non-matching hash */
     PSA_ASSERT( psa_hash_setup( &operation, alg ) );
@@ -1871,9 +1896,12 @@
 
     /* Call setup twice in a row. */
     PSA_ASSERT( psa_mac_sign_setup( &operation, key, alg ) );
+    ASSERT_OPERATION_IS_ACTIVE( operation );
     TEST_EQUAL( psa_mac_sign_setup( &operation, key, alg ),
                 PSA_ERROR_BAD_STATE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
     PSA_ASSERT( psa_mac_abort( &operation ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
 
     /* Call update after sign finish. */
     PSA_ASSERT( psa_mac_sign_setup( &operation, key, alg ) );
@@ -1919,19 +1947,25 @@
     /* Setup sign but try verify. */
     PSA_ASSERT( psa_mac_sign_setup( &operation, key, alg ) );
     PSA_ASSERT( psa_mac_update( &operation, input, sizeof( input ) ) );
+    ASSERT_OPERATION_IS_ACTIVE( operation );
     TEST_EQUAL( psa_mac_verify_finish( &operation,
                                        verify_mac, sizeof( verify_mac ) ),
                 PSA_ERROR_BAD_STATE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
     PSA_ASSERT( psa_mac_abort( &operation ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
 
     /* Setup verify but try sign. */
     PSA_ASSERT( psa_mac_verify_setup( &operation, key, alg ) );
     PSA_ASSERT( psa_mac_update( &operation, input, sizeof( input ) ) );
+    ASSERT_OPERATION_IS_ACTIVE( operation );
     TEST_EQUAL( psa_mac_sign_finish( &operation,
                                      sign_mac, sizeof( sign_mac ),
                                      &sign_mac_length ),
                 PSA_ERROR_BAD_STATE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
     PSA_ASSERT( psa_mac_abort( &operation ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
 
     PSA_ASSERT( psa_destroy_key( key ) );
 
@@ -2233,15 +2267,21 @@
 
     /* Call encrypt setup twice in a row. */
     PSA_ASSERT( psa_cipher_encrypt_setup( &operation, key, alg ) );
+    ASSERT_OPERATION_IS_ACTIVE( operation );
     TEST_EQUAL( psa_cipher_encrypt_setup( &operation, key, alg ),
                 PSA_ERROR_BAD_STATE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
     PSA_ASSERT( psa_cipher_abort( &operation ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
 
     /* Call decrypt setup twice in a row. */
     PSA_ASSERT( psa_cipher_decrypt_setup( &operation, key, alg ) );
+    ASSERT_OPERATION_IS_ACTIVE( operation );
     TEST_EQUAL( psa_cipher_decrypt_setup( &operation, key, alg ),
                 PSA_ERROR_BAD_STATE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
     PSA_ASSERT( psa_cipher_abort( &operation ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
 
     /* Generate an IV without calling setup beforehand. */
     TEST_EQUAL( psa_cipher_generate_iv( &operation,
@@ -2255,11 +2295,14 @@
     PSA_ASSERT( psa_cipher_generate_iv( &operation,
                                         buffer, sizeof( buffer ),
                                         &length ) );
+    ASSERT_OPERATION_IS_ACTIVE( operation );
     TEST_EQUAL( psa_cipher_generate_iv( &operation,
                                         buffer, sizeof( buffer ),
                                         &length ),
                 PSA_ERROR_BAD_STATE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
     PSA_ASSERT( psa_cipher_abort( &operation ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
 
     /* Generate an IV after it's already set. */
     PSA_ASSERT( psa_cipher_encrypt_setup( &operation, key, alg ) );
@@ -2281,10 +2324,13 @@
     PSA_ASSERT( psa_cipher_encrypt_setup( &operation, key, alg ) );
     PSA_ASSERT( psa_cipher_set_iv( &operation,
                                    iv, sizeof( iv ) ) );
+    ASSERT_OPERATION_IS_ACTIVE( operation );
     TEST_EQUAL( psa_cipher_set_iv( &operation,
                                    iv, sizeof( iv ) ),
                 PSA_ERROR_BAD_STATE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
     PSA_ASSERT( psa_cipher_abort( &operation ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
 
     /* Set an IV after it's already generated. */
     PSA_ASSERT( psa_cipher_encrypt_setup( &operation, key, alg ) );
@@ -2305,12 +2351,16 @@
     PSA_ASSERT( psa_cipher_abort( &operation ) );
 
     /* Call update without an IV where an IV is required. */
+    PSA_ASSERT( psa_cipher_encrypt_setup( &operation, key, alg ) );
+    ASSERT_OPERATION_IS_ACTIVE( operation );
     TEST_EQUAL( psa_cipher_update( &operation,
                                    text, sizeof( text ),
                                    buffer, sizeof( buffer ),
                                    &length ),
                 PSA_ERROR_BAD_STATE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
     PSA_ASSERT( psa_cipher_abort( &operation ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
 
     /* Call update after finish. */
     PSA_ASSERT( psa_cipher_encrypt_setup( &operation, key, alg ) );
@@ -2335,10 +2385,13 @@
     PSA_ASSERT( psa_cipher_encrypt_setup( &operation, key, alg ) );
     /* Not calling update means we are encrypting an empty buffer, which is OK
      * for cipher modes with padding. */
+    ASSERT_OPERATION_IS_ACTIVE( operation );
     TEST_EQUAL( psa_cipher_finish( &operation,
                                    buffer, sizeof( buffer ), &length ),
                 PSA_ERROR_BAD_STATE );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
     PSA_ASSERT( psa_cipher_abort( &operation ) );
+    ASSERT_OPERATION_IS_INACTIVE( operation );
 
     /* Call finish twice in a row. */
     PSA_ASSERT( psa_cipher_encrypt_setup( &operation, key, alg ) );
diff --git a/tests/suites/test_suite_rsa.function b/tests/suites/test_suite_rsa.function
index f5f4aac..f5f5159 100644
--- a/tests/suites/test_suite_rsa.function
+++ b/tests/suites/test_suite_rsa.function
@@ -179,11 +179,12 @@
     mbedtls_test_rnd_pseudo_info rnd_info;
 
     mbedtls_rsa_init( &ctx );
-    TEST_ASSERT( mbedtls_rsa_set_padding( &ctx, padding_mode,
-                                          MBEDTLS_MD_NONE ) == 0 );
     mbedtls_mpi_init( &N ); mbedtls_mpi_init( &P );
     mbedtls_mpi_init( &Q ); mbedtls_mpi_init( &E );
 
+    TEST_ASSERT( mbedtls_rsa_set_padding( &ctx, padding_mode,
+                                          MBEDTLS_MD_NONE ) == 0 );
+
     memset( output, 0x00, sizeof( output ) );
     memset( &rnd_info, 0, sizeof( mbedtls_test_rnd_pseudo_info ) );