Merge pull request #9258 from tom-daubney-arm/drop_padlock_support

Drop support for VIA Padlock
diff --git a/.gitignore b/.gitignore
index 12c775d..6068cbc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,9 @@
 seedfile
 # MBEDTLS_PSA_INJECT_ENTROPY seed file created by the test framework
 00000000ffffff52.psa_its
+# Log files created by all.sh to reduce the logs in case a component runs
+# successfully
+quiet-make.*
 
 # CMake build artifacts:
 CMakeCache.txt
diff --git a/3rdparty/everest/CMakeLists.txt b/3rdparty/everest/CMakeLists.txt
index e0e5ade..8c8e8db 100644
--- a/3rdparty/everest/CMakeLists.txt
+++ b/3rdparty/everest/CMakeLists.txt
@@ -8,6 +8,7 @@
 target_include_directories(${everest_target}
   PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
          $<BUILD_INTERFACE:${MBEDTLS_DIR}/include>
+         $<BUILD_INTERFACE:${MBEDTLS_DIR}/tf-psa-crypto/include>
          $<INSTALL_INTERFACE:include>
   PRIVATE include/everest
           include/everest/kremlib
diff --git a/3rdparty/p256-m/.gitignore b/3rdparty/p256-m/.gitignore
new file mode 100644
index 0000000..f3c7a7c
--- /dev/null
+++ b/3rdparty/p256-m/.gitignore
@@ -0,0 +1 @@
+Makefile
diff --git a/3rdparty/p256-m/CMakeLists.txt b/3rdparty/p256-m/CMakeLists.txt
index 2ef0d48..bd302a7 100644
--- a/3rdparty/p256-m/CMakeLists.txt
+++ b/3rdparty/p256-m/CMakeLists.txt
@@ -8,6 +8,7 @@
   PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
          $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/p256-m>
          $<BUILD_INTERFACE:${MBEDTLS_DIR}/include>
+         $<BUILD_INTERFACE:${MBEDTLS_DIR}/tf-psa-crypto/include>
          $<INSTALL_INTERFACE:include>
   PRIVATE ${MBEDTLS_DIR}/library/)
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e476675..35b8d48 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -73,10 +73,16 @@
 
 option(DISABLE_PACKAGE_CONFIG_AND_INSTALL "Disable package configuration, target export and installation" ${MBEDTLS_AS_SUBPROJECT})
 
-string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${CMAKE_C_COMPILER_ID}")
-string(REGEX MATCH "GNU" CMAKE_COMPILER_IS_GNU "${CMAKE_C_COMPILER_ID}")
-string(REGEX MATCH "IAR" CMAKE_COMPILER_IS_IAR "${CMAKE_C_COMPILER_ID}")
-string(REGEX MATCH "MSVC" CMAKE_COMPILER_IS_MSVC "${CMAKE_C_COMPILER_ID}")
+if (CMAKE_C_SIMULATE_ID)
+    set(COMPILER_ID ${CMAKE_C_SIMULATE_ID})
+else()
+    set(COMPILER_ID ${CMAKE_C_COMPILER_ID})
+endif(CMAKE_C_SIMULATE_ID)
+
+string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${COMPILER_ID}")
+string(REGEX MATCH "GNU" CMAKE_COMPILER_IS_GNU "${COMPILER_ID}")
+string(REGEX MATCH "IAR" CMAKE_COMPILER_IS_IAR "${COMPILER_ID}")
+string(REGEX MATCH "MSVC" CMAKE_COMPILER_IS_MSVC "${COMPILER_ID}")
 
 # the test suites currently have compile errors with MSVC
 if(CMAKE_COMPILER_IS_MSVC)
@@ -184,8 +190,6 @@
     set(${dest_var} ${no_ext_name} PARENT_SCOPE)
 endfunction(get_name_without_last_ext)
 
-string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${CMAKE_C_COMPILER_ID}")
-
 include(CheckCCompilerFlag)
 
 set(CMAKE_C_EXTENSIONS OFF)
@@ -294,6 +298,8 @@
 
 add_subdirectory(library)
 
+add_subdirectory(tf-psa-crypto)
+
 add_subdirectory(pkgconfig)
 
 #
@@ -349,6 +355,7 @@
     target_include_directories(mbedtls_test
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests/include
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+        PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tf-psa-crypto/include
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/library)
     # Request C11, needed for memory poisoning tests
     set_target_properties(mbedtls_test PROPERTIES C_STANDARD 11)
@@ -359,6 +366,7 @@
     target_include_directories(mbedtls_test_helpers
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests/include
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+        PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tf-psa-crypto/include
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/library
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/everest/include)
 
diff --git a/ChangeLog.d/9126.txt b/ChangeLog.d/9126.txt
new file mode 100644
index 0000000..22939df
--- /dev/null
+++ b/ChangeLog.d/9126.txt
@@ -0,0 +1,5 @@
+Default behavior changes
+   * In a PSA-client-only build (i.e. MBEDTLS_PSA_CRYPTO_CLIENT &&
+     !MBEDTLS_PSA_CRYPTO_C), do not automatically enable local crypto when the
+     corresponding PSA mechanism is enabled, since the server provides the
+     crypto. Fixes #9126.
diff --git a/ChangeLog.d/fix-test-suite-pk-warnings.txt b/ChangeLog.d/fix-test-suite-pk-warnings.txt
new file mode 100644
index 0000000..2604219
--- /dev/null
+++ b/ChangeLog.d/fix-test-suite-pk-warnings.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * Fix redefinition warnings when SECP192R1 and/or SECP192K1 are disabled.
+     Fixes #9029.
diff --git a/Makefile b/Makefile
index fb80529..0f1f3da 100644
--- a/Makefile
+++ b/Makefile
@@ -96,7 +96,7 @@
 	mkdir -p $(DESTDIR)/include/mbedtls
 	cp -rp include/mbedtls $(DESTDIR)/include
 	mkdir -p $(DESTDIR)/include/psa
-	cp -rp include/psa $(DESTDIR)/include
+	cp -rp tf-psa-crypto/include/psa $(DESTDIR)/include
 
 	mkdir -p $(DESTDIR)/lib
 	cp -RP library/libmbedtls.*    $(DESTDIR)/lib
@@ -197,6 +197,7 @@
 	3rdparty/*/*.c 3rdparty/*/*/*.c 3rdparty/*/*/*/*.c 3rdparty/*/*/*/*/*.c \
 	include/*/*.h \
 	library/*.[hc] \
+	tf-psa-crypto/include/*/*.h \
 	programs/*/*.[hc] \
 	tests/include/*/*.h tests/include/*/*/*.h \
 	tests/src/*.c tests/src/*/*.c \
@@ -213,5 +214,5 @@
 	ls $(C_SOURCE_FILES) | gtags -f - --gtagsconf .globalrc
 cscope: cscope.in.out cscope.po.out cscope.out
 cscope.in.out cscope.po.out cscope.out: $(C_SOURCE_FILES)
-	cscope -bq -u -Iinclude -Ilibrary $(patsubst %,-I%,$(wildcard 3rdparty/*/include)) -Itests/include $(C_SOURCE_FILES)
+	cscope -bq -u -Iinclude -Ilibrary -Itf-psa-crypto/include $(patsubst %,-I%,$(wildcard 3rdparty/*/include)) -Itests/include $(C_SOURCE_FILES)
 .PHONY: cscope global
diff --git a/configs/config-no-entropy.h b/configs/config-no-entropy.h
deleted file mode 100644
index ddb00b4..0000000
--- a/configs/config-no-entropy.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * \file config-no-entropy.h
- *
- * \brief Minimal configuration of features that do not require an entropy source
- */
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-/*
- * Minimal configuration of features that do not require an entropy source
- * Distinguishing features:
- * - no entropy module
- * - no TLS protocol implementation available due to absence of an entropy
- *   source
- *
- * See README.txt for usage instructions.
- */
-
-/* System support */
-#define MBEDTLS_HAVE_ASM
-#define MBEDTLS_HAVE_TIME
-
-/* Mbed TLS feature support */
-#define MBEDTLS_CIPHER_MODE_CBC
-#define MBEDTLS_CIPHER_PADDING_PKCS7
-#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
-#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
-#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
-#define MBEDTLS_ECP_NIST_OPTIM
-#define MBEDTLS_ECDSA_DETERMINISTIC
-#define MBEDTLS_PK_RSA_ALT_SUPPORT
-#define MBEDTLS_PKCS1_V15
-#define MBEDTLS_PKCS1_V21
-#define MBEDTLS_SELF_TEST
-#define MBEDTLS_VERSION_FEATURES
-
-/* Mbed TLS modules */
-#define MBEDTLS_AES_C
-#define MBEDTLS_ASN1_PARSE_C
-#define MBEDTLS_ASN1_WRITE_C
-#define MBEDTLS_BASE64_C
-#define MBEDTLS_BIGNUM_C
-#define MBEDTLS_CCM_C
-#define MBEDTLS_CIPHER_C
-#define MBEDTLS_ECDSA_C
-#define MBEDTLS_ECP_C
-#define MBEDTLS_ERROR_C
-#define MBEDTLS_GCM_C
-#define MBEDTLS_HMAC_DRBG_C
-#define MBEDTLS_MD_C
-#define MBEDTLS_OID_C
-#define MBEDTLS_PEM_PARSE_C
-#define MBEDTLS_PK_C
-#define MBEDTLS_PK_PARSE_C
-#define MBEDTLS_PK_WRITE_C
-#define MBEDTLS_PLATFORM_C
-#define MBEDTLS_RSA_C
-/* The library does not currently support enabling SHA-224 without SHA-256.
- * A future version of the library will have this option disabled
- * by default. */
-#define MBEDTLS_SHA224_C
-#define MBEDTLS_SHA256_C
-#define MBEDTLS_SHA384_C
-#define MBEDTLS_SHA512_C
-#define MBEDTLS_VERSION_C
-#define MBEDTLS_X509_USE_C
-#define MBEDTLS_X509_CRT_PARSE_C
-#define MBEDTLS_X509_CRL_PARSE_C
-//#define MBEDTLS_CMAC_C
-
-/* Miscellaneous options */
-#define MBEDTLS_AES_ROM_TABLES
diff --git a/docs/architecture/psa-migration/outcome-analysis.sh b/docs/architecture/psa-migration/outcome-analysis.sh
index 1805a3c..bbcdffd 100755
--- a/docs/architecture/psa-migration/outcome-analysis.sh
+++ b/docs/architecture/psa-migration/outcome-analysis.sh
@@ -27,7 +27,7 @@
 
 cleanup() {
     make clean
-    git checkout -- include/mbedtls/mbedtls_config.h include/psa/crypto_config.h
+    git checkout -- include/mbedtls/mbedtls_config.h tf-psa-crypto/include/psa/crypto_config.h
 }
 
 record() {
diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile
index c4505ac..847deb0 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -6,7 +6,7 @@
 EXTRACT_PRIVATE        = YES
 EXTRACT_STATIC         = YES
 CASE_SENSE_NAMES       = NO
-INPUT                  = ../include input ../tests/include/alt-dummy
+INPUT                  = ../include ../tf-psa-crypto/include input ../tests/include/alt-dummy
 FILE_PATTERNS          = *.h
 RECURSIVE              = YES
 EXCLUDE_SYMLINKS       = YES
@@ -21,7 +21,7 @@
 GENERATE_XML           = YES
 MACRO_EXPANSION        = YES
 EXPAND_ONLY_PREDEF     = YES
-INCLUDE_PATH           = ../include
+INCLUDE_PATH           = ../include ../tf-psa-crypto/include
 EXPAND_AS_DEFINED      = MBEDTLS_PRIVATE
 CLASS_DIAGRAMS         = NO
 HAVE_DOT               = YES
diff --git a/framework b/framework
index 623c1b4..0484721 160000
--- a/framework
+++ b/framework
@@ -1 +1 @@
-Subproject commit 623c1b4532e8de64a5d82ea84a7496e64c370d15
+Subproject commit 04847216ab964b9bdce41f1e61ccc6d8f5d2a139
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index e11e271..755efed 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -3,20 +3,13 @@
 if(INSTALL_MBEDTLS_HEADERS)
 
     file(GLOB headers "mbedtls/*.h")
-    file(GLOB psa_headers "psa/*.h")
 
     install(FILES ${headers}
         DESTINATION include/mbedtls
         PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
-
-    install(FILES ${psa_headers}
-        DESTINATION include/psa
-        PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
-
 endif(INSTALL_MBEDTLS_HEADERS)
 
 # Make mbedtls_config.h available in an out-of-source build. ssl-opt.sh requires it.
 if (ENABLE_TESTING AND NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
     link_to_source(mbedtls)
-    link_to_source(psa)
 endif()
diff --git a/include/mbedtls/config_psa.h b/include/mbedtls/config_psa.h
index de961ec..5f3d0f3 100644
--- a/include/mbedtls/config_psa.h
+++ b/include/mbedtls/config_psa.h
@@ -34,7 +34,11 @@
  * before we deduce what built-ins are required. */
 #include "psa/crypto_adjust_config_key_pair_types.h"
 
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+/* If we are implementing PSA crypto ourselves, then we want to enable the
+ * required built-ins. Otherwise, PSA features will be provided by the server. */
 #include "mbedtls/config_adjust_legacy_from_psa.h"
+#endif
 
 #else /* MBEDTLS_PSA_CRYPTO_CONFIG */
 
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index ca130a3..4b59e78 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -2364,7 +2364,7 @@
  */
 int mbedtls_ssl_get_own_cid(mbedtls_ssl_context *ssl,
                             int *enabled,
-                            unsigned char own_cid[MBEDTLS_SSL_CID_OUT_LEN_MAX],
+                            unsigned char own_cid[MBEDTLS_SSL_CID_IN_LEN_MAX],
                             size_t *own_cid_len);
 
 /**
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 493af30..9b26b6b 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -328,6 +328,7 @@
     # of /library (which currently means: under /3rdparty).
     target_include_directories(${target}
         PUBLIC $<BUILD_INTERFACE:${MBEDTLS_DIR}/include/>
+               $<BUILD_INTERFACE:${MBEDTLS_DIR}/tf-psa-crypto/include/>
                $<INSTALL_INTERFACE:include/>
         PRIVATE ${MBEDTLS_DIR}/library/
                 # Needed to include psa_crypto_driver_wrappers.h
diff --git a/library/Makefile b/library/Makefile
index e0eefd8..014e0ca 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -28,11 +28,11 @@
 WARNING_CFLAGS ?=  -Wall -Wextra -Wformat=2 -Wno-format-nonliteral
 LDFLAGS ?=
 
-# Include ../include for public headers and . for private headers.
-# Note that . needs to be included explicitly for the sake of library
-# files that are not in the /library directory (which currently means
+# Include ../include, ../tf-psa-crypto/include for public headers and . for
+# private headers. Note that . needs to be included explicitly for the sake of
+# library files that are not in the /library directory (which currently means
 # under /3rdparty).
-LOCAL_CFLAGS = $(WARNING_CFLAGS) -I. -I../include -D_FILE_OFFSET_BITS=64
+LOCAL_CFLAGS = $(WARNING_CFLAGS) -I. -I../include -I../tf-psa-crypto/include -D_FILE_OFFSET_BITS=64
 LOCAL_LDFLAGS =
 
 ifdef DEBUG
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index dd39e81..4c31aa2 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -132,7 +132,7 @@
 
 int mbedtls_ssl_get_own_cid(mbedtls_ssl_context *ssl,
                             int *enabled,
-                            unsigned char own_cid[MBEDTLS_SSL_CID_OUT_LEN_MAX],
+                            unsigned char own_cid[MBEDTLS_SSL_CID_IN_LEN_MAX],
                             size_t *own_cid_len)
 {
     *enabled = MBEDTLS_SSL_CID_DISABLED;
diff --git a/pkgconfig/.gitignore b/pkgconfig/.gitignore
new file mode 100644
index 0000000..5460c20
--- /dev/null
+++ b/pkgconfig/.gitignore
@@ -0,0 +1,2 @@
+Makefile
+*.pc
diff --git a/programs/Makefile b/programs/Makefile
index 8d1da6d..9b48cc0 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -127,8 +127,8 @@
 generated_files: $(GENERATED_FILES)
 
 psa/psa_constant_names_generated.c: $(gen_file_dep) ../scripts/generate_psa_constants.py
-psa/psa_constant_names_generated.c: $(gen_file_dep) ../include/psa/crypto_values.h
-psa/psa_constant_names_generated.c: $(gen_file_dep) ../include/psa/crypto_extra.h
+psa/psa_constant_names_generated.c: $(gen_file_dep) ../tf-psa-crypto/include/psa/crypto_values.h
+psa/psa_constant_names_generated.c: $(gen_file_dep) ../tf-psa-crypto/include/psa/crypto_extra.h
 psa/psa_constant_names_generated.c: $(gen_file_dep) ../tests/suites/test_suite_psa_crypto_metadata.data
 psa/psa_constant_names_generated.c:
 	echo "  Gen   $@"
diff --git a/programs/psa/CMakeLists.txt b/programs/psa/CMakeLists.txt
index a8e4b0e..c0843e1 100644
--- a/programs/psa/CMakeLists.txt
+++ b/programs/psa/CMakeLists.txt
@@ -19,8 +19,8 @@
             ${CMAKE_CURRENT_SOURCE_DIR}/../..
         DEPENDS
             ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/generate_psa_constants.py
-            ${CMAKE_CURRENT_SOURCE_DIR}/../../include/psa/crypto_values.h
-            ${CMAKE_CURRENT_SOURCE_DIR}/../../include/psa/crypto_extra.h
+            ${CMAKE_CURRENT_SOURCE_DIR}/../../tf-psa-crypto/include/psa/crypto_values.h
+            ${CMAKE_CURRENT_SOURCE_DIR}/../../tf-psa-crypto/include/psa/crypto_extra.h
     )
 else()
     link_to_source(psa_constant_names_generated.c)
diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt
index 0d43ffd..08fb321 100644
--- a/programs/test/CMakeLists.txt
+++ b/programs/test/CMakeLists.txt
@@ -25,14 +25,18 @@
         WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
     )
     add_executable(cpp_dummy_build "${cpp_dummy_build_cpp}")
-    target_include_directories(cpp_dummy_build PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
+    target_include_directories(cpp_dummy_build
+        PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include
+        PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tf-psa-crypto/include)
     target_link_libraries(cpp_dummy_build ${mbedcrypto_target} ${CMAKE_THREAD_LIBS_INIT})
 endif()
 
 if(USE_SHARED_MBEDTLS_LIBRARY AND
    NOT ${CMAKE_SYSTEM_NAME} MATCHES "[Ww][Ii][Nn]")
     add_executable(dlopen "dlopen.c")
-    target_include_directories(dlopen PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
+    target_include_directories(dlopen
+        PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include
+        PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tf-psa-crypto/include)
     target_link_libraries(dlopen ${CMAKE_DL_LIBS})
 endif()
 
@@ -46,13 +50,13 @@
             ${PERL}
                 ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/generate_query_config.pl
                 ${CMAKE_CURRENT_SOURCE_DIR}/../../include/mbedtls/mbedtls_config.h
-                ${CMAKE_CURRENT_SOURCE_DIR}/../../include/psa/crypto_config.h
+                ${CMAKE_CURRENT_SOURCE_DIR}/../../tf-psa-crypto/include/psa/crypto_config.h
                 ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/data_files/query_config.fmt
                 ${CMAKE_CURRENT_BINARY_DIR}/query_config.c
         DEPENDS
             ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/generate_query_config.pl
             ${CMAKE_CURRENT_SOURCE_DIR}/../../include/mbedtls/mbedtls_config.h
-            ${CMAKE_CURRENT_SOURCE_DIR}/../../include/psa/crypto_config.h
+            ${CMAKE_CURRENT_SOURCE_DIR}/../../tf-psa-crypto/include/psa/crypto_config.h
             ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/data_files/query_config.fmt
     )
     # this file will also be used in another directory, so create a target, see
diff --git a/programs/test/cmake_package/.gitignore b/programs/test/cmake_package/.gitignore
index 9ae6b59..89d8c2b 100644
--- a/programs/test/cmake_package/.gitignore
+++ b/programs/test/cmake_package/.gitignore
@@ -1,3 +1,4 @@
 build
 Makefile
 cmake_package
+mbedtls
diff --git a/programs/test/cmake_package_install/.gitignore b/programs/test/cmake_package_install/.gitignore
index b9b8282..aaa5942 100644
--- a/programs/test/cmake_package_install/.gitignore
+++ b/programs/test/cmake_package_install/.gitignore
@@ -1,3 +1,4 @@
 build
 Makefile
 cmake_package_install
+mbedtls
diff --git a/programs/test/generate_cpp_dummy_build.sh b/programs/test/generate_cpp_dummy_build.sh
index 0b4bd0b..ef9996e 100755
--- a/programs/test/generate_cpp_dummy_build.sh
+++ b/programs/test/generate_cpp_dummy_build.sh
@@ -37,10 +37,16 @@
 
 EOF
 
-    for header in include/mbedtls/*.h include/psa/*.h; do
+    for header in include/mbedtls/*.h; do
         case ${header#include/} in
             mbedtls/mbedtls_config.h) :;; # not meant for direct inclusion
             mbedtls/config_*.h) :;; # not meant for direct inclusion
+            *) echo "#include \"${header#include/}\"";;
+        esac
+    done
+
+    for header in tf-psa-crypto/include/psa/*.h; do
+        case ${header#tf-psa-crypto/include/} in
             psa/crypto_config.h) :;; # not meant for direct inclusion
             psa/crypto_ajdust_config*.h) :;; # not meant for direct inclusion
             # Some of the psa/crypto_*.h headers are not meant to be included
@@ -48,7 +54,7 @@
             # psa/crypto.h has been included before. Since psa/crypto.h comes
             # before psa/crypto_*.h in the wildcard enumeration, we don't need
             # to skip those headers.
-            *) echo "#include \"${header#include/}\"";;
+            *) echo "#include \"${header#tf-psa-crypto/include/}\"";;
         esac
     done
 
diff --git a/scripts/code_size_compare.py b/scripts/code_size_compare.py
index 50749b6..ce752e4 100755
--- a/scripts/code_size_compare.py
+++ b/scripts/code_size_compare.py
@@ -149,7 +149,7 @@
 TFM_MEDIUM_CRYPTO_CONFIG_H = 'configs/ext/crypto_config_profile_medium.h'
 
 CONFIG_H = 'include/mbedtls/mbedtls_config.h'
-CRYPTO_CONFIG_H = 'include/psa/crypto_config.h'
+CRYPTO_CONFIG_H = 'tf-psa-crypto/include/psa/crypto_config.h'
 BACKUP_SUFFIX = '.code_size.bak'
 
 class CodeSizeBuildInfo: # pylint: disable=too-few-public-methods
diff --git a/scripts/common.make b/scripts/common.make
index 9908a3c..702ef5c 100644
--- a/scripts/common.make
+++ b/scripts/common.make
@@ -21,7 +21,7 @@
 WARNING_CXXFLAGS ?= -Wall -Wextra -Wformat=2 -Wno-format-nonliteral
 LDFLAGS ?=
 
-LOCAL_CFLAGS = $(WARNING_CFLAGS) -I$(MBEDTLS_TEST_PATH)/include -I$(MBEDTLS_PATH)/include -D_FILE_OFFSET_BITS=64
+LOCAL_CFLAGS = $(WARNING_CFLAGS) -I$(MBEDTLS_TEST_PATH)/include -I$(MBEDTLS_PATH)/include -I$(MBEDTLS_PATH)/tf-psa-crypto/include -D_FILE_OFFSET_BITS=64
 LOCAL_CXXFLAGS = $(WARNING_CXXFLAGS) -I$(MBEDTLS_PATH)/include -I$(MBEDTLS_PATH)/tests/include -D_FILE_OFFSET_BITS=64
 LOCAL_LDFLAGS = ${MBEDTLS_TEST_OBJS} 		\
 		-L$(MBEDTLS_PATH)/library			\
diff --git a/scripts/generate_psa_constants.py b/scripts/generate_psa_constants.py
index d57d46a..d472c6d 100755
--- a/scripts/generate_psa_constants.py
+++ b/scripts/generate_psa_constants.py
@@ -328,6 +328,7 @@
     build_tree.chdir_to_root()
     # Allow to change the directory where psa_constant_names_generated.c is written to.
     OUTPUT_FILE_DIR = sys.argv[1] if len(sys.argv) == 2 else "programs/psa"
-    generate_psa_constants(['include/psa/crypto_values.h',
-                            'include/psa/crypto_extra.h'],
+
+    generate_psa_constants(['tf-psa-crypto/include/psa/crypto_values.h',
+                            'tf-psa-crypto/include/psa/crypto_extra.h'],
                            OUTPUT_FILE_DIR + '/psa_constant_names_generated.c')
diff --git a/scripts/generate_query_config.pl b/scripts/generate_query_config.pl
index 39743da..6a2f9cb 100755
--- a/scripts/generate_query_config.pl
+++ b/scripts/generate_query_config.pl
@@ -26,7 +26,7 @@
 my ($mbedtls_config_file, $psa_crypto_config_file, $query_config_format_file, $query_config_file);
 
 my $default_mbedtls_config_file = "./include/mbedtls/mbedtls_config.h";
-my $default_psa_crypto_config_file = "./include/psa/crypto_config.h";
+my $default_psa_crypto_config_file = "./tf-psa-crypto/include/psa/crypto_config.h";
 my $default_query_config_format_file = "./scripts/data_files/query_config.fmt";
 my $default_query_config_file = "./programs/test/query_config.c";
 
diff --git a/scripts/generate_visualc_files.pl b/scripts/generate_visualc_files.pl
index a0dfc57..b566372 100755
--- a/scripts/generate_visualc_files.pl
+++ b/scripts/generate_visualc_files.pl
@@ -23,7 +23,7 @@
 
 my $programs_dir = 'programs';
 my $mbedtls_header_dir = 'include/mbedtls';
-my $psa_header_dir = 'include/psa';
+my $psa_header_dir = 'tf-psa-crypto/include/psa';
 my $source_dir = 'library';
 my $test_source_dir = 'tests/src';
 my $test_header_dir = 'tests/include/test';
@@ -44,6 +44,7 @@
 # one directory: the compiler will use the first match.
 my @include_directories = qw(
     include
+    tf-psa-crypto/include
     3rdparty/everest/include/
     3rdparty/everest/include/everest
     3rdparty/everest/include/everest/vs2013
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 5bc38b4..62be14e 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -126,9 +126,9 @@
             ${CMAKE_CURRENT_SOURCE_DIR}/../framework/scripts/mbedtls_framework/psa_storage.py
             ${CMAKE_CURRENT_SOURCE_DIR}/../framework/scripts/mbedtls_framework/test_case.py
             ${CMAKE_CURRENT_SOURCE_DIR}/../framework/scripts/mbedtls_framework/test_data_generation.py
-            ${CMAKE_CURRENT_SOURCE_DIR}/../include/psa/crypto_config.h
-            ${CMAKE_CURRENT_SOURCE_DIR}/../include/psa/crypto_values.h
-            ${CMAKE_CURRENT_SOURCE_DIR}/../include/psa/crypto_extra.h
+            ${CMAKE_CURRENT_SOURCE_DIR}/../tf-psa-crypto/include/psa/crypto_config.h
+            ${CMAKE_CURRENT_SOURCE_DIR}/../tf-psa-crypto/include/psa/crypto_values.h
+            ${CMAKE_CURRENT_SOURCE_DIR}/../tf-psa-crypto/include/psa/crypto_extra.h
     )
 
 else()
diff --git a/tests/Makefile b/tests/Makefile
index 1d5c768..d1d5ed9 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -7,6 +7,7 @@
 # Also include library headers, for the sake of invasive tests.
 LOCAL_CFLAGS += -I../library
 
+
 # Enable definition of various functions used throughout the testsuite
 # (gethostname, strdup, fileno...) even when compiling with -std=c99. Harmless
 # on non-POSIX platforms.
@@ -84,9 +85,9 @@
 ## file all the time when switching between configurations, don't declare
 ## crypto_config.h as a dependency. Remove this file from your working tree
 ## if you've just added or removed an option in crypto_config.h.
-#generated_psa_test_data: ../include/psa/crypto_config.h
-generated_psa_test_data: ../include/psa/crypto_values.h
-generated_psa_test_data: ../include/psa/crypto_extra.h
+#generated_psa_test_data: ../tf-psa-crypto/include/psa/crypto_config.h
+generated_psa_test_data: ../tf-psa-crypto/include/psa/crypto_values.h
+generated_psa_test_data: ../tf-psa-crypto/include/psa/crypto_extra.h
 generated_psa_test_data: suites/test_suite_psa_crypto_metadata.data
 generated_psa_test_data:
 	echo "  Gen   $(GENERATED_PSA_DATA_FILES) ..."
@@ -206,6 +207,8 @@
 # Generate variants of some headers for testing
 include/alt-extra/%_alt.h: ../include/%.h
 	perl -p -e 's/^(# *(define|ifndef) +\w+_)H\b/$${1}ALT_H/' $< >$@
+include/alt-extra/%_alt.h: ../tf-psa-crypto/include/%.h
+	perl -p -e 's/^(# *(define|ifndef) +\w+_)H\b/$${1}ALT_H/' $< >$@
 
 # Generate test library
 
@@ -214,7 +217,8 @@
 # library. Add a LIBTESTDRIVER1_/libtestdriver1_ to mbedtls_xxx and psa_xxx
 # symbols.
 define libtestdriver1_rewrite :=
-	s!^(\s*#\s*include\s*[\"<])(mbedtls|psa)/!$${1}libtestdriver1/include/$${2}/!; \
+	s!^(\s*#\s*include\s*[\"<])mbedtls/!$${1}libtestdriver1/include/mbedtls/!; \
+	s!^(\s*#\s*include\s*[\"<])psa/!$${1}libtestdriver1/tf-psa-crypto/include/psa/!; \
 	next if /^\s*#\s*include/; \
 	s/\b(?=MBEDTLS_|PSA_)/LIBTESTDRIVER1_/g; \
 	s/\b(?=mbedtls_|psa_)/libtestdriver1_/g;
@@ -227,6 +231,7 @@
 	mkdir ./libtestdriver1
 	cp -Rf ../library ./libtestdriver1
 	cp -Rf ../include ./libtestdriver1
+	cp -Rf ../tf-psa-crypto ./libtestdriver1
 	cp -Rf ../scripts ./libtestdriver1
 	mkdir ./libtestdriver1/3rdparty
 	touch ./libtestdriver1/3rdparty/Makefile.inc
@@ -239,22 +244,23 @@
         # library the test library is intended to be linked with extended by
         # ./include/test/drivers/crypto_config_test_driver_extension.h to
         # mirror the PSA_ACCEL_* macros.
-	mv ./libtestdriver1/include/psa/crypto_config.h ./libtestdriver1/include/psa/crypto_config.h.bak
-	head -n -1 ./libtestdriver1/include/psa/crypto_config.h.bak > ./libtestdriver1/include/psa/crypto_config.h
-	cat ./include/test/drivers/crypto_config_test_driver_extension.h >> ./libtestdriver1/include/psa/crypto_config.h
-	echo "#endif /* PSA_CRYPTO_CONFIG_H */" >> ./libtestdriver1/include/psa/crypto_config.h
+	mv ./libtestdriver1/tf-psa-crypto/include/psa/crypto_config.h ./libtestdriver1/tf-psa-crypto/include/psa/crypto_config.h.bak
+	head -n -1 ./libtestdriver1/tf-psa-crypto/include/psa/crypto_config.h.bak > ./libtestdriver1/tf-psa-crypto/include/psa/crypto_config.h
+	cat ./include/test/drivers/crypto_config_test_driver_extension.h >> ./libtestdriver1/tf-psa-crypto/include/psa/crypto_config.h
+	echo "#endif /* PSA_CRYPTO_CONFIG_H */" >> ./libtestdriver1/tf-psa-crypto/include/psa/crypto_config.h
 
 	# Prefix MBEDTLS_* PSA_* symbols with LIBTESTDRIVER1_ as well as
 	# mbedtls_* psa_* symbols with libtestdriver1_ to avoid symbol clash
 	# when this test driver library is linked with the Mbed TLS library.
 	perl -pi -e '$(libtestdriver1_rewrite)' ./libtestdriver1/library/*.[ch]
 	perl -pi -e '$(libtestdriver1_rewrite)' ./libtestdriver1/include/*/*.h
+	perl -pi -e '$(libtestdriver1_rewrite)' ./libtestdriver1/tf-psa-crypto/include/*/*.h
 
 	$(MAKE) -C ./libtestdriver1/library CFLAGS="-I../../ $(CFLAGS)" LDFLAGS="$(LDFLAGS)" libmbedcrypto.a
 	cp ./libtestdriver1/library/libmbedcrypto.a ../library/libtestdriver1.a
 
 ifdef RECORD_PSA_STATUS_COVERAGE_LOG
-include/test/instrument_record_status.h: ../include/psa/crypto.h Makefile
+include/test/instrument_record_status.h: ../tf-psa-crypto/include/psa/crypto.h Makefile
 	echo "  Gen  $@"
-	sed <../include/psa/crypto.h >$@ -n 's/^psa_status_t \([A-Za-z0-9_]*\)(.*/#define \1(...) RECORD_STATUS("\1", \1(__VA_ARGS__))/p'
+	sed <../tf-psa-crypto/include/psa/crypto.h >$@ -n 's/^psa_status_t \([A-Za-z0-9_]*\)(.*/#define \1(...) RECORD_STATUS("\1", \1(__VA_ARGS__))/p'
 endif
diff --git a/tests/include/test/psa_test_wrappers.h b/tests/include/test/psa_test_wrappers.h
index ecf926e..e6d712b 100644
--- a/tests/include/test/psa_test_wrappers.h
+++ b/tests/include/test/psa_test_wrappers.h
@@ -262,12 +262,15 @@
 #define psa_copy_key(arg0_source_key, arg1_attributes, arg2_target_key) \
     mbedtls_test_wrap_psa_copy_key(arg0_source_key, arg1_attributes, arg2_target_key)
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_cipher_suite(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     psa_pake_cipher_suite_t *arg1_cipher_suite);
 #define psa_crypto_driver_pake_get_cipher_suite(arg0_inputs, arg1_cipher_suite) \
     mbedtls_test_wrap_psa_crypto_driver_pake_get_cipher_suite(arg0_inputs, arg1_cipher_suite)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_password(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     uint8_t *arg1_buffer,
@@ -275,13 +278,17 @@
     size_t *arg3_buffer_length);
 #define psa_crypto_driver_pake_get_password(arg0_inputs, arg1_buffer, arg2_buffer_size, arg3_buffer_length) \
     mbedtls_test_wrap_psa_crypto_driver_pake_get_password(arg0_inputs, arg1_buffer, arg2_buffer_size, arg3_buffer_length)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_password_len(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     size_t *arg1_password_len);
 #define psa_crypto_driver_pake_get_password_len(arg0_inputs, arg1_password_len) \
     mbedtls_test_wrap_psa_crypto_driver_pake_get_password_len(arg0_inputs, arg1_password_len)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_peer(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     uint8_t *arg1_peer_id,
@@ -289,13 +296,17 @@
     size_t *arg3_peer_id_length);
 #define psa_crypto_driver_pake_get_peer(arg0_inputs, arg1_peer_id, arg2_peer_id_size, arg3_peer_id_length) \
     mbedtls_test_wrap_psa_crypto_driver_pake_get_peer(arg0_inputs, arg1_peer_id, arg2_peer_id_size, arg3_peer_id_length)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_peer_len(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     size_t *arg1_peer_len);
 #define psa_crypto_driver_pake_get_peer_len(arg0_inputs, arg1_peer_len) \
     mbedtls_test_wrap_psa_crypto_driver_pake_get_peer_len(arg0_inputs, arg1_peer_len)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_user(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     uint8_t *arg1_user_id,
@@ -303,12 +314,15 @@
     size_t *arg3_user_id_len);
 #define psa_crypto_driver_pake_get_user(arg0_inputs, arg1_user_id, arg2_user_id_size, arg3_user_id_len) \
     mbedtls_test_wrap_psa_crypto_driver_pake_get_user(arg0_inputs, arg1_user_id, arg2_user_id_size, arg3_user_id_len)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_user_len(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     size_t *arg1_user_len);
 #define psa_crypto_driver_pake_get_user_len(arg0_inputs, arg1_user_len) \
     mbedtls_test_wrap_psa_crypto_driver_pake_get_user_len(arg0_inputs, arg1_user_len)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 psa_status_t mbedtls_test_wrap_psa_crypto_init(void);
 #define psa_crypto_init() \
@@ -566,17 +580,22 @@
 #define psa_mac_verify_setup(arg0_operation, arg1_key, arg2_alg) \
     mbedtls_test_wrap_psa_mac_verify_setup(arg0_operation, arg1_key, arg2_alg)
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_abort(
     psa_pake_operation_t *arg0_operation);
 #define psa_pake_abort(arg0_operation) \
     mbedtls_test_wrap_psa_pake_abort(arg0_operation)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_get_implicit_key(
     psa_pake_operation_t *arg0_operation,
     psa_key_derivation_operation_t *arg1_output);
 #define psa_pake_get_implicit_key(arg0_operation, arg1_output) \
     mbedtls_test_wrap_psa_pake_get_implicit_key(arg0_operation, arg1_output)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_input(
     psa_pake_operation_t *arg0_operation,
     psa_pake_step_t arg1_step,
@@ -584,7 +603,9 @@
     size_t arg3_input_length);
 #define psa_pake_input(arg0_operation, arg1_step, arg2_input, arg3_input_length) \
     mbedtls_test_wrap_psa_pake_input(arg0_operation, arg1_step, arg2_input, arg3_input_length)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_output(
     psa_pake_operation_t *arg0_operation,
     psa_pake_step_t arg1_step,
@@ -593,38 +614,49 @@
     size_t *arg4_output_length);
 #define psa_pake_output(arg0_operation, arg1_step, arg2_output, arg3_output_size, arg4_output_length) \
     mbedtls_test_wrap_psa_pake_output(arg0_operation, arg1_step, arg2_output, arg3_output_size, arg4_output_length)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_set_password_key(
     psa_pake_operation_t *arg0_operation,
     mbedtls_svc_key_id_t arg1_password);
 #define psa_pake_set_password_key(arg0_operation, arg1_password) \
     mbedtls_test_wrap_psa_pake_set_password_key(arg0_operation, arg1_password)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_set_peer(
     psa_pake_operation_t *arg0_operation,
     const uint8_t *arg1_peer_id,
     size_t arg2_peer_id_len);
 #define psa_pake_set_peer(arg0_operation, arg1_peer_id, arg2_peer_id_len) \
     mbedtls_test_wrap_psa_pake_set_peer(arg0_operation, arg1_peer_id, arg2_peer_id_len)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_set_role(
     psa_pake_operation_t *arg0_operation,
     psa_pake_role_t arg1_role);
 #define psa_pake_set_role(arg0_operation, arg1_role) \
     mbedtls_test_wrap_psa_pake_set_role(arg0_operation, arg1_role)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_set_user(
     psa_pake_operation_t *arg0_operation,
     const uint8_t *arg1_user_id,
     size_t arg2_user_id_len);
 #define psa_pake_set_user(arg0_operation, arg1_user_id, arg2_user_id_len) \
     mbedtls_test_wrap_psa_pake_set_user(arg0_operation, arg1_user_id, arg2_user_id_len)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_setup(
     psa_pake_operation_t *arg0_operation,
     const psa_pake_cipher_suite_t *arg1_cipher_suite);
 #define psa_pake_setup(arg0_operation, arg1_cipher_suite) \
     mbedtls_test_wrap_psa_pake_setup(arg0_operation, arg1_cipher_suite)
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 psa_status_t mbedtls_test_wrap_psa_purge_key(
     mbedtls_svc_key_id_t arg0_key);
diff --git a/tests/psa-client-server/psasim/Makefile b/tests/psa-client-server/psasim/Makefile
index 06d3059..a7e22e1 100644
--- a/tests/psa-client-server/psasim/Makefile
+++ b/tests/psa-client-server/psasim/Makefile
@@ -10,10 +10,7 @@
 LIBPSASERVER := -Llibpsaserver/ -lmbedcrypto
 
 MBEDTLS_ROOT_PATH = ../../..
-COMMON_INCLUDE := -I./include -I$(MBEDTLS_ROOT_PATH)/include
-
-TEST_BIN = 	test/psa_client \
-			test/psa_partition
+COMMON_INCLUDE := -I./include -I$(MBEDTLS_ROOT_PATH)/include -I$(MBEDTLS_ROOT_PATH)/tf-psa-crypto/include
 
 GENERATED_H_FILES =	include/psa_manifest/manifest.h \
 					include/psa_manifest/pid.h \
@@ -33,7 +30,7 @@
 
 .PHONY: all clean libpsaclient libpsaserver
 
-all: $(TEST_BIN)
+all:
 
 test/seedfile:
 	dd if=/dev/urandom of=./test/seedfile bs=64 count=1
@@ -59,7 +56,7 @@
 	$(MAKE) -C $(MBEDTLS_ROOT_PATH) clean
 
 clean:
-	rm -f $(TEST_BIN)
+	rm -f test/psa_client test/psa_partition
 	rm -f $(PARTITION_SERVER_BOOTSTRAP)
 	rm -rf libpsaclient libpsaserver
 	rm -rf include/psa_manifest
diff --git a/tests/psa-client-server/psasim/include/util.h b/tests/psa-client-server/psasim/include/util.h
index 558149f..5eb8238 100644
--- a/tests/psa-client-server/psasim/include/util.h
+++ b/tests/psa-client-server/psasim/include/util.h
@@ -13,20 +13,18 @@
 #if defined(DEBUG)
 #define INFO(fmt, ...) \
     fprintf(stdout, "Info (%s - %d): " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
+#else /* !DEBUG */
+#define INFO(...)
+#endif /* DEBUG*/
 
 #define ERROR(fmt, ...) \
-    fprintf(stdout, "Error (%s - %d): " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
+    fprintf(stderr, "Error (%s - %d): " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
 
 #define FATAL(fmt, ...) \
     { \
-        fprintf(stdout, "Fatal (%s - %d): " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
+        fprintf(stderr, "Fatal (%s - %d): " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
         abort(); \
     }
-#else /* DEBUG */
-#define INFO(...)
-#define ERROR(...)
-#define FATAL(...)
-#endif /* DEBUG*/
 
 #define PROJECT_ID              'M'
 #define PATHNAMESIZE            256
diff --git a/tests/psa-client-server/psasim/src/aut_psa_aead_demo.c b/tests/psa-client-server/psasim/src/aut_psa_aead_demo.c
new file mode 100644
index 0000000..4a46c40
--- /dev/null
+++ b/tests/psa-client-server/psasim/src/aut_psa_aead_demo.c
@@ -0,0 +1,283 @@
+/**
+ * PSA API multi-part AEAD demonstration.
+ *
+ * This program AEAD-encrypts a message, using the algorithm and key size
+ * specified on the command line, using the multi-part API.
+ *
+ * It comes with a companion program cipher/cipher_aead_demo.c, which does the
+ * same operations with the legacy Cipher API. The goal is that comparing the
+ * two programs will help people migrating to the PSA Crypto API.
+ *
+ * When used with multi-part AEAD operations, the `mbedtls_cipher_context`
+ * serves a triple purpose (1) hold the key, (2) store the algorithm when no
+ * operation is active, and (3) save progress information for the current
+ * operation. With PSA those roles are held by disinct objects: (1) a
+ * psa_key_id_t to hold the key, a (2) psa_algorithm_t to represent the
+ * algorithm, and (3) a psa_operation_t for multi-part progress.
+ *
+ * On the other hand, with PSA, the algorithms encodes the desired tag length;
+ * with Cipher the desired tag length needs to be tracked separately.
+ *
+ * This program and its companion cipher/cipher_aead_demo.c illustrate this by
+ * doing the same sequence of multi-part AEAD computation with both APIs;
+ * looking at the two side by side should make the differences and
+ * similarities clear.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+/* First include Mbed TLS headers to get the Mbed TLS configuration and
+ * platform definitions that we'll use in this program. Also include
+ * standard C headers for functions we'll use here. */
+#include "mbedtls/build_info.h"
+
+#include "psa/crypto.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* If the build options we need are not enabled, compile a placeholder. */
+#if !defined(MBEDTLS_PSA_CRYPTO_CLIENT) && \
+    (!defined(MBEDTLS_PSA_CRYPTO_C) || \
+    !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_GCM_C) || \
+    !defined(MBEDTLS_CHACHAPOLY_C) || \
+    defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER))
+int main(void)
+{
+    printf("MBEDTLS_PSA_CRYPTO_CLIENT or "
+           "MBEDTLS_PSA_CRYPTO_C and/or "
+           "MBEDTLS_AES_C and/or MBEDTLS_GCM_C and/or "
+           "MBEDTLS_CHACHAPOLY_C not defined, and/or "
+           "MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER defined\r\n");
+    return 0;
+}
+#else
+
+/* The real program starts here. */
+
+const char usage[] =
+    "Usage: aead_demo [aes128-gcm|aes256-gcm|aes128-gcm_8|chachapoly]";
+
+/* Dummy data for encryption: IV/nonce, additional data, 2-part message */
+const unsigned char iv1[12] = { 0x00 };
+const unsigned char add_data1[] = { 0x01, 0x02 };
+const unsigned char msg1_part1[] = { 0x03, 0x04 };
+const unsigned char msg1_part2[] = { 0x05, 0x06, 0x07 };
+
+/* Dummy data (2nd message) */
+const unsigned char iv2[12] = { 0x10 };
+const unsigned char add_data2[] = { 0x11, 0x12 };
+const unsigned char msg2_part1[] = { 0x13, 0x14 };
+const unsigned char msg2_part2[] = { 0x15, 0x16, 0x17 };
+
+/* Maximum total size of the messages */
+#define MSG1_SIZE (sizeof(msg1_part1) + sizeof(msg1_part2))
+#define MSG2_SIZE (sizeof(msg2_part1) + sizeof(msg2_part2))
+#define MSG_MAX_SIZE (MSG1_SIZE > MSG2_SIZE ? MSG1_SIZE : MSG2_SIZE)
+
+/* Dummy key material - never do this in production!
+ * 32-byte is enough to all the key size supported by this program. */
+const unsigned char key_bytes[32] = { 0x2a };
+
+/* Print the contents of a buffer in hex */
+void print_buf(const char *title, uint8_t *buf, size_t len)
+{
+    printf("%s:", title);
+    for (size_t i = 0; i < len; i++) {
+        printf(" %02x", buf[i]);
+    }
+    printf("\n");
+}
+
+/* Run a PSA function and bail out if it fails.
+ * The symbolic name of the error code can be recovered using:
+ * programs/psa/psa_constant_name status <value> */
+#define PSA_CHECK(expr)                                       \
+    do                                                          \
+    {                                                           \
+        status = (expr);                                      \
+        if (status != PSA_SUCCESS)                             \
+        {                                                       \
+            printf("Error %d at line %d: %s\n",                \
+                   (int) status,                               \
+                   __LINE__,                                   \
+                   #expr);                                    \
+            goto exit;                                          \
+        }                                                       \
+    }                                                           \
+    while (0)
+
+/*
+ * Prepare encryption material:
+ * - interpret command-line argument
+ * - set up key
+ * - outputs: key and algorithm, which together hold all the information
+ */
+static psa_status_t aead_prepare(const char *info,
+                                 psa_key_id_t *key,
+                                 psa_algorithm_t *alg)
+{
+    psa_status_t status;
+
+    /* Convert arg to alg + key_bits + key_type */
+    size_t key_bits;
+    psa_key_type_t key_type;
+    if (strcmp(info, "aes128-gcm") == 0) {
+        *alg = PSA_ALG_GCM;
+        key_bits = 128;
+        key_type = PSA_KEY_TYPE_AES;
+    } else if (strcmp(info, "aes256-gcm") == 0) {
+        *alg = PSA_ALG_GCM;
+        key_bits = 256;
+        key_type = PSA_KEY_TYPE_AES;
+    } else if (strcmp(info, "aes128-gcm_8") == 0) {
+        *alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 8);
+        key_bits = 128;
+        key_type = PSA_KEY_TYPE_AES;
+    } else if (strcmp(info, "chachapoly") == 0) {
+        *alg = PSA_ALG_CHACHA20_POLY1305;
+        key_bits = 256;
+        key_type = PSA_KEY_TYPE_CHACHA20;
+    } else {
+        puts(usage);
+        return PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+    /* Prepare key attributes */
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
+    psa_set_key_algorithm(&attributes, *alg);
+    psa_set_key_type(&attributes, key_type);
+    psa_set_key_bits(&attributes, key_bits);   // optional
+
+    /* Import key */
+    PSA_CHECK(psa_import_key(&attributes, key_bytes, key_bits / 8, key));
+
+exit:
+    return status;
+}
+
+/*
+ * Print out some information.
+ *
+ * All of this information was present in the command line argument, but his
+ * function demonstrates how each piece can be recovered from (key, alg).
+ */
+static void aead_info(psa_key_id_t key, psa_algorithm_t alg)
+{
+    psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
+    (void) psa_get_key_attributes(key, &attr);
+    psa_key_type_t key_type = psa_get_key_type(&attr);
+    size_t key_bits = psa_get_key_bits(&attr);
+    psa_algorithm_t base_alg = PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(alg);
+    size_t tag_len = PSA_AEAD_TAG_LENGTH(key_type, key_bits, alg);
+
+    const char *type_str = key_type == PSA_KEY_TYPE_AES ? "AES"
+                         : key_type == PSA_KEY_TYPE_CHACHA20 ? "Chacha"
+                         : "???";
+    const char *base_str = base_alg == PSA_ALG_GCM ? "GCM"
+                         : base_alg == PSA_ALG_CHACHA20_POLY1305 ? "ChachaPoly"
+                         : "???";
+
+    printf("%s, %u, %s, %u\n",
+           type_str, (unsigned) key_bits, base_str, (unsigned) tag_len);
+}
+
+/*
+ * Encrypt a 2-part message.
+ */
+static int aead_encrypt(psa_key_id_t key, psa_algorithm_t alg,
+                        const unsigned char *iv, size_t iv_len,
+                        const unsigned char *ad, size_t ad_len,
+                        const unsigned char *part1, size_t part1_len,
+                        const unsigned char *part2, size_t part2_len)
+{
+    psa_status_t status;
+    size_t olen, olen_tag;
+    unsigned char out[PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(MSG_MAX_SIZE)];
+    unsigned char *p = out, *end = out + sizeof(out);
+    unsigned char tag[PSA_AEAD_TAG_MAX_SIZE];
+
+    psa_aead_operation_t op = PSA_AEAD_OPERATION_INIT;
+    PSA_CHECK(psa_aead_encrypt_setup(&op, key, alg));
+
+    PSA_CHECK(psa_aead_set_nonce(&op, iv, iv_len));
+    PSA_CHECK(psa_aead_update_ad(&op, ad, ad_len));
+    PSA_CHECK(psa_aead_update(&op, part1, part1_len, p, end - p, &olen));
+    p += olen;
+    PSA_CHECK(psa_aead_update(&op, part2, part2_len, p, end - p, &olen));
+    p += olen;
+    PSA_CHECK(psa_aead_finish(&op, p, end - p, &olen,
+                              tag, sizeof(tag), &olen_tag));
+    p += olen;
+    memcpy(p, tag, olen_tag);
+    p += olen_tag;
+
+    olen = p - out;
+    print_buf("out", out, olen);
+
+exit:
+    psa_aead_abort(&op);   // required on errors, harmless on success
+    return status;
+}
+
+/*
+ * AEAD demo: set up key/alg, print out info, encrypt messages.
+ */
+static psa_status_t aead_demo(const char *info)
+{
+    psa_status_t status;
+
+    psa_key_id_t key;
+    psa_algorithm_t alg;
+
+    PSA_CHECK(aead_prepare(info, &key, &alg));
+
+    aead_info(key, alg);
+
+    PSA_CHECK(aead_encrypt(key, alg,
+                           iv1, sizeof(iv1), add_data1, sizeof(add_data1),
+                           msg1_part1, sizeof(msg1_part1),
+                           msg1_part2, sizeof(msg1_part2)));
+    PSA_CHECK(aead_encrypt(key, alg,
+                           iv2, sizeof(iv2), add_data2, sizeof(add_data2),
+                           msg2_part1, sizeof(msg2_part1),
+                           msg2_part2, sizeof(msg2_part2)));
+
+exit:
+    psa_destroy_key(key);
+
+    return status;
+}
+
+/*
+ * Main function
+ */
+int main(int argc, char **argv)
+{
+    psa_status_t status = PSA_SUCCESS;
+
+    /* Check usage */
+    if (argc != 2) {
+        puts(usage);
+        return EXIT_FAILURE;
+    }
+
+    /* Initialize the PSA crypto library. */
+    PSA_CHECK(psa_crypto_init());
+
+    /* Run the demo */
+    PSA_CHECK(aead_demo(argv[1]));
+
+    /* Deinitialize the PSA crypto library. */
+    mbedtls_psa_crypto_free();
+
+exit:
+    return status == PSA_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+#endif
diff --git a/tests/psa-client-server/psasim/src/aut_psa_hash.c b/tests/psa-client-server/psasim/src/aut_psa_hash.c
new file mode 100644
index 0000000..6c2c07e
--- /dev/null
+++ b/tests/psa-client-server/psasim/src/aut_psa_hash.c
@@ -0,0 +1,160 @@
+/*
+ *  Example computing a SHA-256 hash using the PSA Crypto API
+ *
+ *  The example computes the SHA-256 hash of a test string using the
+ *  one-shot API call psa_hash_compute() and the using multi-part
+ *  operation, which requires psa_hash_setup(), psa_hash_update() and
+ *  psa_hash_finish(). The multi-part operation is popular on embedded
+ *  devices where a rolling hash needs to be computed.
+ *
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "psa/crypto.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mbedtls/build_info.h"
+#include "mbedtls/platform.h"
+
+/* Information about hashing with the PSA API can be
+ * found here:
+ * https://arm-software.github.io/psa-api/crypto/1.1/api/ops/hashes.html
+ *
+ * The algorithm used by this demo is SHA 256.
+ * Please see include/psa/crypto_values.h to see the other
+ * algorithms that are supported by Mbed TLS.
+ * If you switch to a different algorithm you will need to update
+ * the hash data in the EXAMPLE_HASH_VALUE macro below. */
+
+#if !defined(MBEDTLS_PSA_CRYPTO_CLIENT) && \
+    (!defined(MBEDTLS_PSA_CRYPTO_C) || !defined(PSA_WANT_ALG_SHA_256))
+int main(void)
+{
+    mbedtls_printf("MBEDTLS_PSA_CRYPTO_C and PSA_WANT_ALG_SHA_256"
+                   "not defined, and not MBEDTLS_PSA_CRYPTO_CLIENT.\r\n");
+    return EXIT_SUCCESS;
+}
+#else
+
+#define HASH_ALG PSA_ALG_SHA_256
+
+const uint8_t sample_message[] = "Hello World!";
+/* sample_message is terminated with a null byte which is not part of
+ * the message itself so we make sure to subtract it in order to get
+ * the message length. */
+const size_t sample_message_length = sizeof(sample_message) - 1;
+
+#define EXPECTED_HASH_VALUE {                                                    \
+        0x7f, 0x83, 0xb1, 0x65, 0x7f, 0xf1, 0xfc, 0x53, 0xb9, 0x2d, 0xc1, 0x81, \
+        0x48, 0xa1, 0xd6, 0x5d, 0xfc, 0x2d, 0x4b, 0x1f, 0xa3, 0xd6, 0x77, 0x28, \
+        0x4a, 0xdd, 0xd2, 0x00, 0x12, 0x6d, 0x90, 0x69 \
+}
+
+const uint8_t expected_hash[] = EXPECTED_HASH_VALUE;
+const size_t expected_hash_len = sizeof(expected_hash);
+
+int main(void)
+{
+    psa_status_t status;
+    uint8_t hash[PSA_HASH_LENGTH(HASH_ALG)];
+    size_t hash_length;
+    psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT;
+    psa_hash_operation_t cloned_hash_operation = PSA_HASH_OPERATION_INIT;
+
+    mbedtls_printf("PSA Crypto API: SHA-256 example\n\n");
+
+    status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_crypto_init failed\n");
+        return EXIT_FAILURE;
+    }
+
+    /* Compute hash using multi-part operation */
+    status = psa_hash_setup(&hash_operation, HASH_ALG);
+    if (status == PSA_ERROR_NOT_SUPPORTED) {
+        mbedtls_printf("unknown hash algorithm supplied\n");
+        return EXIT_FAILURE;
+    } else if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_setup failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_hash_update(&hash_operation, sample_message, sample_message_length);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_update failed\n");
+        goto cleanup;
+    }
+
+    status = psa_hash_clone(&hash_operation, &cloned_hash_operation);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("PSA hash clone failed\n");
+        goto cleanup;
+    }
+
+    status = psa_hash_finish(&hash_operation, hash, sizeof(hash), &hash_length);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_finish failed\n");
+        goto cleanup;
+    }
+
+    /* Check the result of the operation against the sample */
+    if (hash_length != expected_hash_len ||
+        (memcmp(hash, expected_hash, expected_hash_len) != 0)) {
+        mbedtls_printf("Multi-part hash operation gave the wrong result!\n\n");
+        goto cleanup;
+    }
+
+    status =
+        psa_hash_verify(&cloned_hash_operation, expected_hash,
+                        expected_hash_len);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_verify failed\n");
+        goto cleanup;
+    } else {
+        mbedtls_printf("Multi-part hash operation successful!\n");
+    }
+
+    /* Clear local variables prior to one-shot hash demo */
+    memset(hash, 0, sizeof(hash));
+    hash_length = 0;
+
+    /* Compute hash using one-shot function call */
+    status = psa_hash_compute(HASH_ALG,
+                              sample_message, sample_message_length,
+                              hash, sizeof(hash),
+                              &hash_length);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_compute failed\n");
+        goto cleanup;
+    }
+
+    if (hash_length != expected_hash_len ||
+        (memcmp(hash, expected_hash, expected_hash_len) != 0)) {
+        mbedtls_printf("One-shot hash operation gave the wrong result!\n\n");
+        goto cleanup;
+    }
+
+    mbedtls_printf("One-shot hash operation successful!\n\n");
+
+    /* Print out result */
+    mbedtls_printf("The SHA-256( '%s' ) is: ", sample_message);
+
+    for (size_t j = 0; j < expected_hash_len; j++) {
+        mbedtls_printf("%02x", hash[j]);
+    }
+
+    mbedtls_printf("\n");
+
+    mbedtls_psa_crypto_free();
+    return EXIT_SUCCESS;
+
+cleanup:
+    psa_hash_abort(&hash_operation);
+    psa_hash_abort(&cloned_hash_operation);
+    return EXIT_FAILURE;
+}
+#endif /* !MBEDTLS_PSA_CRYPTO_C || !PSA_WANT_ALG_SHA_256 */
diff --git a/tests/psa-client-server/psasim/src/aut_psa_hash_compute.c b/tests/psa-client-server/psasim/src/aut_psa_hash_compute.c
index 519c072..70c3e5b 100644
--- a/tests/psa-client-server/psasim/src/aut_psa_hash_compute.c
+++ b/tests/psa-client-server/psasim/src/aut_psa_hash_compute.c
@@ -32,11 +32,12 @@
  * If you switch to a different algorithm you will need to update
  * the hash data in the EXAMPLE_HASH_VALUE macro below. */
 
-#if !defined(MBEDTLS_PSA_CRYPTO_C) || !defined(PSA_WANT_ALG_SHA_256)
+#if !defined(MBEDTLS_PSA_CRYPTO_CLIENT) && \
+    (!defined(MBEDTLS_PSA_CRYPTO_C) || !defined(PSA_WANT_ALG_SHA_256))
 int main(void)
 {
     mbedtls_printf("MBEDTLS_PSA_CRYPTO_C and PSA_WANT_ALG_SHA_256"
-                   "not defined.\r\n");
+                   "not defined, and not MBEDTLS_PSA_CRYPTO_CLIENT.\r\n");
     return EXIT_SUCCESS;
 }
 #else
diff --git a/tests/psa-client-server/psasim/src/client.c b/tests/psa-client-server/psasim/src/client.c
index a8c9e08..4c63abf 100644
--- a/tests/psa-client-server/psasim/src/client.c
+++ b/tests/psa-client-server/psasim/src/client.c
@@ -7,12 +7,14 @@
 
 /* Includes from mbedtls */
 #include "psa/crypto.h"
+#include "util.h"
 
 int main()
 {
     /* psa_crypto_init() connects to the server */
     psa_status_t status = psa_crypto_init();
     if (status != PSA_SUCCESS) {
+        ERROR("psa_crypto_init returned %d", status);
         return 1;
     }
 
diff --git a/tests/psa-client-server/psasim/src/psa_ff_client.c b/tests/psa-client-server/psasim/src/psa_ff_client.c
index 21a43b3..0d6bbf3 100644
--- a/tests/psa-client-server/psasim/src/psa_ff_client.c
+++ b/tests/psa-client-server/psasim/src/psa_ff_client.c
@@ -199,7 +199,6 @@
             default:
                 FATAL("   ERROR: unknown internal message type: %ld",
                       response.message_type);
-                return ret;
         }
     }
 }
@@ -301,10 +300,10 @@
                 handles[idx].valid = 1;
                 return idx;
             } else {
-                INFO("Server didn't like you");
+                ERROR("Server didn't like you");
             }
         } else {
-            INFO("Couldn't contact RoT service. Does it exist?");
+            ERROR("Couldn't contact RoT service. Does it exist?");
 
             if (__psa_ff_client_security_state == 0) {
                 ERROR("Invalid SID");
@@ -339,7 +338,7 @@
             }
         }
     }
-    INFO("psa_version failed: does the service exist?");
+    ERROR("psa_version failed: does the service exist?");
     return PSA_VERSION_NONE;
 }
 
diff --git a/tests/psa-client-server/psasim/src/psa_ff_server.c b/tests/psa-client-server/psasim/src/psa_ff_server.c
index 219722a..7f97b9b 100644
--- a/tests/psa-client-server/psasim/src/psa_ff_server.c
+++ b/tests/psa-client-server/psasim/src/psa_ff_server.c
@@ -26,7 +26,7 @@
 #define MAX_CLIENTS 128
 #define MAX_MESSAGES 32
 
-#define SLEEP_MS        50
+#define SLEEP_US        1
 
 struct connection {
     uint32_t client;
@@ -105,7 +105,7 @@
     ssize_t len;
     int idx;
 #if !defined(PSASIM_USE_USLEEP)
-    const struct timespec ts_delay = { .tv_sec = 0, .tv_nsec = SLEEP_MS * 1000000 };
+    const struct timespec ts_delay = { .tv_sec = 0, .tv_nsec = SLEEP_US * 1000 };
 #endif
 
     if (timeout == PSA_POLL) {
@@ -262,7 +262,7 @@
         } else {
             /* There is no 'select' function in SysV to block on multiple queues, so busy-wait :( */
 #if defined(PSASIM_USE_USLEEP)
-            usleep(SLEEP_MS * 1000);
+            usleep(SLEEP_US);
 #else /* PSASIM_USE_USLEEP */
             nanosleep(&ts_delay, NULL);
 #endif /* PSASIM_USE_USLEEP */
diff --git a/tests/psa-client-server/psasim/src/psa_functions_codes.h b/tests/psa-client-server/psasim/src/psa_functions_codes.h
index 0093733..c68b416 100644
--- a/tests/psa-client-server/psasim/src/psa_functions_codes.h
+++ b/tests/psa-client-server/psasim/src/psa_functions_codes.h
@@ -12,6 +12,20 @@
     /* Start here to avoid overlap with PSA_IPC_CONNECT, PSA_IPC_DISCONNECT
      * and VERSION_REQUEST */
     PSA_CRYPTO_INIT = 100,
+    PSA_AEAD_ABORT,
+    PSA_AEAD_DECRYPT,
+    PSA_AEAD_DECRYPT_SETUP,
+    PSA_AEAD_ENCRYPT,
+    PSA_AEAD_ENCRYPT_SETUP,
+    PSA_AEAD_FINISH,
+    PSA_AEAD_GENERATE_NONCE,
+    PSA_AEAD_SET_LENGTHS,
+    PSA_AEAD_SET_NONCE,
+    PSA_AEAD_UPDATE,
+    PSA_AEAD_UPDATE_AD,
+    PSA_AEAD_VERIFY,
+    PSA_DESTROY_KEY,
+    PSA_GET_KEY_ATTRIBUTES,
     PSA_HASH_ABORT,
     PSA_HASH_CLONE,
     PSA_HASH_COMPARE,
@@ -20,6 +34,7 @@
     PSA_HASH_SETUP,
     PSA_HASH_UPDATE,
     PSA_HASH_VERIFY,
+    PSA_IMPORT_KEY,
 };
 
 #endif /*  _PSA_FUNCTIONS_CODES_H_ */
diff --git a/tests/psa-client-server/psasim/src/psa_sim_crypto_client.c b/tests/psa-client-server/psasim/src/psa_sim_crypto_client.c
index 4ac6c4a..758e9b2 100644
--- a/tests/psa-client-server/psasim/src/psa_sim_crypto_client.c
+++ b/tests/psa-client-server/psasim/src/psa_sim_crypto_client.c
@@ -22,10 +22,14 @@
 #include "psa/crypto.h"
 
 #define CLIENT_PRINT(fmt, ...) \
-    PRINT("Client: " fmt, ##__VA_ARGS__)
+    INFO("Client: " fmt, ##__VA_ARGS__)
 
 static psa_handle_t handle = -1;
 
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+#error "Error: MBEDTLS_PSA_CRYPTO_C must be disabled on client build"
+#endif
+
 int psa_crypto_call(int function,
                     uint8_t *in_params, size_t in_params_len,
                     uint8_t **out_params, size_t *out_params_len)
@@ -121,6 +125,1141 @@
 }
 
 
+psa_status_t psa_aead_abort(
+    psa_aead_operation_t *operation
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_psa_aead_operation_t_needs(*operation);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_aead_operation_t(&pos, &remaining, *operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_AEAD_ABORT,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_AEAD_ABORT server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_aead_decrypt(
+    mbedtls_svc_key_id_t key,
+    psa_algorithm_t alg,
+    const uint8_t *nonce, size_t  nonce_length,
+    const uint8_t *additional_data, size_t  additional_data_length,
+    const uint8_t *ciphertext, size_t  ciphertext_length,
+    uint8_t *plaintext, size_t  plaintext_size,
+    size_t *plaintext_length
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
+                    psasim_serialise_psa_algorithm_t_needs(alg) +
+                    psasim_serialise_buffer_needs(nonce, nonce_length) +
+                    psasim_serialise_buffer_needs(additional_data, additional_data_length) +
+                    psasim_serialise_buffer_needs(ciphertext, ciphertext_length) +
+                    psasim_serialise_buffer_needs(plaintext, plaintext_size) +
+                    psasim_serialise_size_t_needs(*plaintext_length);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_mbedtls_svc_key_id_t(&pos, &remaining, key);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_algorithm_t(&pos, &remaining, alg);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, nonce, nonce_length);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, additional_data, additional_data_length);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, ciphertext, ciphertext_length);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, plaintext, plaintext_size);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_size_t(&pos, &remaining, *plaintext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_AEAD_DECRYPT,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_AEAD_DECRYPT server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_return_buffer(&rpos, &rremain, plaintext, plaintext_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&rpos, &rremain, plaintext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_aead_decrypt_setup(
+    psa_aead_operation_t *operation,
+    mbedtls_svc_key_id_t key,
+    psa_algorithm_t alg
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_psa_aead_operation_t_needs(*operation) +
+                    psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
+                    psasim_serialise_psa_algorithm_t_needs(alg);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_aead_operation_t(&pos, &remaining, *operation);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_mbedtls_svc_key_id_t(&pos, &remaining, key);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_algorithm_t(&pos, &remaining, alg);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_AEAD_DECRYPT_SETUP,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_AEAD_DECRYPT_SETUP server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_aead_encrypt(
+    mbedtls_svc_key_id_t key,
+    psa_algorithm_t alg,
+    const uint8_t *nonce, size_t  nonce_length,
+    const uint8_t *additional_data, size_t  additional_data_length,
+    const uint8_t *plaintext, size_t  plaintext_length,
+    uint8_t *ciphertext, size_t  ciphertext_size,
+    size_t *ciphertext_length
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
+                    psasim_serialise_psa_algorithm_t_needs(alg) +
+                    psasim_serialise_buffer_needs(nonce, nonce_length) +
+                    psasim_serialise_buffer_needs(additional_data, additional_data_length) +
+                    psasim_serialise_buffer_needs(plaintext, plaintext_length) +
+                    psasim_serialise_buffer_needs(ciphertext, ciphertext_size) +
+                    psasim_serialise_size_t_needs(*ciphertext_length);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_mbedtls_svc_key_id_t(&pos, &remaining, key);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_algorithm_t(&pos, &remaining, alg);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, nonce, nonce_length);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, additional_data, additional_data_length);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, plaintext, plaintext_length);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, ciphertext, ciphertext_size);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_size_t(&pos, &remaining, *ciphertext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_AEAD_ENCRYPT,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_AEAD_ENCRYPT server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_return_buffer(&rpos, &rremain, ciphertext, ciphertext_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&rpos, &rremain, ciphertext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_aead_encrypt_setup(
+    psa_aead_operation_t *operation,
+    mbedtls_svc_key_id_t key,
+    psa_algorithm_t alg
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_psa_aead_operation_t_needs(*operation) +
+                    psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
+                    psasim_serialise_psa_algorithm_t_needs(alg);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_aead_operation_t(&pos, &remaining, *operation);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_mbedtls_svc_key_id_t(&pos, &remaining, key);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_algorithm_t(&pos, &remaining, alg);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_AEAD_ENCRYPT_SETUP,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_AEAD_ENCRYPT_SETUP server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_aead_finish(
+    psa_aead_operation_t *operation,
+    uint8_t *ciphertext, size_t  ciphertext_size,
+    size_t *ciphertext_length,
+    uint8_t *tag, size_t  tag_size,
+    size_t *tag_length
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_psa_aead_operation_t_needs(*operation) +
+                    psasim_serialise_buffer_needs(ciphertext, ciphertext_size) +
+                    psasim_serialise_size_t_needs(*ciphertext_length) +
+                    psasim_serialise_buffer_needs(tag, tag_size) +
+                    psasim_serialise_size_t_needs(*tag_length);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_aead_operation_t(&pos, &remaining, *operation);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, ciphertext, ciphertext_size);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_size_t(&pos, &remaining, *ciphertext_length);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, tag, tag_size);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_size_t(&pos, &remaining, *tag_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_AEAD_FINISH,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_AEAD_FINISH server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_return_buffer(&rpos, &rremain, ciphertext, ciphertext_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&rpos, &rremain, ciphertext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_return_buffer(&rpos, &rremain, tag, tag_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&rpos, &rremain, tag_length);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_aead_generate_nonce(
+    psa_aead_operation_t *operation,
+    uint8_t *nonce, size_t  nonce_size,
+    size_t *nonce_length
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_psa_aead_operation_t_needs(*operation) +
+                    psasim_serialise_buffer_needs(nonce, nonce_size) +
+                    psasim_serialise_size_t_needs(*nonce_length);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_aead_operation_t(&pos, &remaining, *operation);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, nonce, nonce_size);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_size_t(&pos, &remaining, *nonce_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_AEAD_GENERATE_NONCE,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_AEAD_GENERATE_NONCE server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_return_buffer(&rpos, &rremain, nonce, nonce_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&rpos, &rremain, nonce_length);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_aead_set_lengths(
+    psa_aead_operation_t *operation,
+    size_t ad_length,
+    size_t plaintext_length
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_psa_aead_operation_t_needs(*operation) +
+                    psasim_serialise_size_t_needs(ad_length) +
+                    psasim_serialise_size_t_needs(plaintext_length);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_aead_operation_t(&pos, &remaining, *operation);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_size_t(&pos, &remaining, ad_length);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_size_t(&pos, &remaining, plaintext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_AEAD_SET_LENGTHS,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_AEAD_SET_LENGTHS server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_aead_set_nonce(
+    psa_aead_operation_t *operation,
+    const uint8_t *nonce, size_t  nonce_length
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_psa_aead_operation_t_needs(*operation) +
+                    psasim_serialise_buffer_needs(nonce, nonce_length);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_aead_operation_t(&pos, &remaining, *operation);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, nonce, nonce_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_AEAD_SET_NONCE,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_AEAD_SET_NONCE server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_aead_update(
+    psa_aead_operation_t *operation,
+    const uint8_t *input, size_t  input_length,
+    uint8_t *output, size_t  output_size,
+    size_t *output_length
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_psa_aead_operation_t_needs(*operation) +
+                    psasim_serialise_buffer_needs(input, input_length) +
+                    psasim_serialise_buffer_needs(output, output_size) +
+                    psasim_serialise_size_t_needs(*output_length);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_aead_operation_t(&pos, &remaining, *operation);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, input, input_length);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, output, output_size);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_size_t(&pos, &remaining, *output_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_AEAD_UPDATE,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_AEAD_UPDATE server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_return_buffer(&rpos, &rremain, output, output_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&rpos, &rremain, output_length);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_aead_update_ad(
+    psa_aead_operation_t *operation,
+    const uint8_t *input, size_t  input_length
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_psa_aead_operation_t_needs(*operation) +
+                    psasim_serialise_buffer_needs(input, input_length);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_aead_operation_t(&pos, &remaining, *operation);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, input, input_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_AEAD_UPDATE_AD,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_AEAD_UPDATE_AD server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_aead_verify(
+    psa_aead_operation_t *operation,
+    uint8_t *plaintext, size_t  plaintext_size,
+    size_t *plaintext_length,
+    const uint8_t *tag, size_t  tag_length
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_psa_aead_operation_t_needs(*operation) +
+                    psasim_serialise_buffer_needs(plaintext, plaintext_size) +
+                    psasim_serialise_size_t_needs(*plaintext_length) +
+                    psasim_serialise_buffer_needs(tag, tag_length);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_aead_operation_t(&pos, &remaining, *operation);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, plaintext, plaintext_size);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_size_t(&pos, &remaining, *plaintext_length);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, tag, tag_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_AEAD_VERIFY,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_AEAD_VERIFY server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_return_buffer(&rpos, &rremain, plaintext, plaintext_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&rpos, &rremain, plaintext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_destroy_key(
+    mbedtls_svc_key_id_t key
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_mbedtls_svc_key_id_t_needs(key);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_mbedtls_svc_key_id_t(&pos, &remaining, key);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_DESTROY_KEY,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_DESTROY_KEY server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
+psa_status_t psa_get_key_attributes(
+    mbedtls_svc_key_id_t key,
+    psa_key_attributes_t *attributes
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
+                    psasim_serialise_psa_key_attributes_t_needs(*attributes);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_mbedtls_svc_key_id_t(&pos, &remaining, key);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_key_attributes_t(&pos, &remaining, *attributes);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_GET_KEY_ATTRIBUTES,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_GET_KEY_ATTRIBUTES server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_key_attributes_t(&rpos, &rremain, attributes);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
+
+
 psa_status_t psa_hash_abort(
     psa_hash_operation_t *operation
     )
@@ -154,7 +1293,7 @@
     ok = psa_crypto_call(PSA_HASH_ABORT,
                          params, (size_t) (pos - params), &result, &result_length);
     if (!ok) {
-        printf("XXX server call failed\n");
+        printf("PSA_HASH_ABORT server call failed\n");
         goto fail;
     }
 
@@ -223,7 +1362,7 @@
     ok = psa_crypto_call(PSA_HASH_CLONE,
                          params, (size_t) (pos - params), &result, &result_length);
     if (!ok) {
-        printf("XXX server call failed\n");
+        printf("PSA_HASH_CLONE server call failed\n");
         goto fail;
     }
 
@@ -298,7 +1437,7 @@
     ok = psa_crypto_call(PSA_HASH_COMPARE,
                          params, (size_t) (pos - params), &result, &result_length);
     if (!ok) {
-        printf("XXX server call failed\n");
+        printf("PSA_HASH_COMPARE server call failed\n");
         goto fail;
     }
 
@@ -374,7 +1513,7 @@
     ok = psa_crypto_call(PSA_HASH_COMPUTE,
                          params, (size_t) (pos - params), &result, &result_length);
     if (!ok) {
-        printf("XXX server call failed\n");
+        printf("PSA_HASH_COMPUTE server call failed\n");
         goto fail;
     }
 
@@ -454,7 +1593,7 @@
     ok = psa_crypto_call(PSA_HASH_FINISH,
                          params, (size_t) (pos - params), &result, &result_length);
     if (!ok) {
-        printf("XXX server call failed\n");
+        printf("PSA_HASH_FINISH server call failed\n");
         goto fail;
     }
 
@@ -533,7 +1672,7 @@
     ok = psa_crypto_call(PSA_HASH_SETUP,
                          params, (size_t) (pos - params), &result, &result_length);
     if (!ok) {
-        printf("XXX server call failed\n");
+        printf("PSA_HASH_SETUP server call failed\n");
         goto fail;
     }
 
@@ -602,7 +1741,7 @@
     ok = psa_crypto_call(PSA_HASH_UPDATE,
                          params, (size_t) (pos - params), &result, &result_length);
     if (!ok) {
-        printf("XXX server call failed\n");
+        printf("PSA_HASH_UPDATE server call failed\n");
         goto fail;
     }
 
@@ -671,7 +1810,7 @@
     ok = psa_crypto_call(PSA_HASH_VERIFY,
                          params, (size_t) (pos - params), &result, &result_length);
     if (!ok) {
-        printf("XXX server call failed\n");
+        printf("PSA_HASH_VERIFY server call failed\n");
         goto fail;
     }
 
@@ -699,3 +1838,78 @@
 
     return status;
 }
+
+
+psa_status_t psa_import_key(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *data, size_t  data_length,
+    mbedtls_svc_key_id_t *key
+    )
+{
+    uint8_t *params = NULL;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t needed = psasim_serialise_begin_needs() +
+                    psasim_serialise_psa_key_attributes_t_needs(*attributes) +
+                    psasim_serialise_buffer_needs(data, data_length) +
+                    psasim_serialise_mbedtls_svc_key_id_t_needs(*key);
+
+    params = malloc(needed);
+    if (params == NULL) {
+        status = PSA_ERROR_INSUFFICIENT_MEMORY;
+        goto fail;
+    }
+
+    uint8_t *pos = params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_psa_key_attributes_t(&pos, &remaining, *attributes);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_buffer(&pos, &remaining, data, data_length);
+    if (!ok) {
+        goto fail;
+    }
+    ok = psasim_serialise_mbedtls_svc_key_id_t(&pos, &remaining, *key);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psa_crypto_call(PSA_IMPORT_KEY,
+                         params, (size_t) (pos - params), &result, &result_length);
+    if (!ok) {
+        printf("PSA_IMPORT_KEY server call failed\n");
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_mbedtls_svc_key_id_t(&rpos, &rremain, key);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(params);
+    free(result);
+
+    return status;
+}
diff --git a/tests/psa-client-server/psasim/src/psa_sim_crypto_server.c b/tests/psa-client-server/psasim/src/psa_sim_crypto_server.c
index 919eb84..30d4b26 100644
--- a/tests/psa-client-server/psasim/src/psa_sim_crypto_server.c
+++ b/tests/psa-client-server/psasim/src/psa_sim_crypto_server.c
@@ -17,6 +17,10 @@
 
 #include "service.h"
 
+#if !defined(MBEDTLS_PSA_CRYPTO_C)
+#error "Error: MBEDTLS_PSA_CRYPTO_C must be enabled on server build"
+#endif
+
 // Returns 1 for success, 0 for failure
 int psa_crypto_init_wrapper(
     uint8_t *in_params, size_t in_params_len,
@@ -67,12 +71,12 @@
 }
 
 // Returns 1 for success, 0 for failure
-int psa_hash_abort_wrapper(
+int psa_aead_abort_wrapper(
     uint8_t *in_params, size_t in_params_len,
     uint8_t **out_params, size_t *out_params_len)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_hash_operation_t operation;
+    psa_aead_operation_t *operation;
 
     uint8_t *pos = in_params;
     size_t remaining = in_params_len;
@@ -84,22 +88,22 @@
         goto fail;
     }
 
-    ok = psasim_deserialise_psa_hash_operation_t(&pos, &remaining, &operation);
+    ok = psasim_server_deserialise_psa_aead_operation_t(&pos, &remaining, &operation);
     if (!ok) {
         goto fail;
     }
 
     // Now we call the actual target function
 
-    status = psa_hash_abort(
-        &operation
+    status = psa_aead_abort(
+        operation
         );
 
     // NOTE: Should really check there is no overflow as we go along.
     size_t result_size =
         psasim_serialise_begin_needs() +
         psasim_serialise_psa_status_t_needs(status) +
-        psasim_serialise_psa_hash_operation_t_needs(operation);
+        psasim_server_serialise_psa_aead_operation_t_needs(operation);
 
     result = malloc(result_size);
     if (result == NULL) {
@@ -119,7 +123,1337 @@
         goto fail;
     }
 
-    ok = psasim_serialise_psa_hash_operation_t(&rpos, &rremain, operation);
+    ok = psasim_server_serialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_aead_decrypt_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    mbedtls_svc_key_id_t key;
+    psa_algorithm_t alg;
+    uint8_t *nonce = NULL;
+    size_t nonce_length;
+    uint8_t *additional_data = NULL;
+    size_t additional_data_length;
+    uint8_t *ciphertext = NULL;
+    size_t ciphertext_length;
+    uint8_t *plaintext = NULL;
+    size_t plaintext_size;
+    size_t plaintext_length;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_mbedtls_svc_key_id_t(&pos, &remaining, &key);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_algorithm_t(&pos, &remaining, &alg);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &nonce, &nonce_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &additional_data, &additional_data_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &ciphertext, &ciphertext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &plaintext, &plaintext_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&pos, &remaining, &plaintext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_aead_decrypt(
+        key,
+        alg,
+        nonce, nonce_length,
+        additional_data, additional_data_length,
+        ciphertext, ciphertext_length,
+        plaintext, plaintext_size,
+        &plaintext_length
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_serialise_buffer_needs(plaintext, plaintext_size) +
+        psasim_serialise_size_t_needs(plaintext_length);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_buffer(&rpos, &rremain, plaintext, plaintext_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_size_t(&rpos, &rremain, plaintext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    free(nonce);
+    free(additional_data);
+    free(ciphertext);
+    free(plaintext);
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    free(nonce);
+    free(additional_data);
+    free(ciphertext);
+    free(plaintext);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_aead_decrypt_setup_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_aead_operation_t *operation;
+    mbedtls_svc_key_id_t key;
+    psa_algorithm_t alg;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_deserialise_psa_aead_operation_t(&pos, &remaining, &operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_mbedtls_svc_key_id_t(&pos, &remaining, &key);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_algorithm_t(&pos, &remaining, &alg);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_aead_decrypt_setup(
+        operation,
+        key,
+        alg
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_server_serialise_psa_aead_operation_t_needs(operation);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_serialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_aead_encrypt_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    mbedtls_svc_key_id_t key;
+    psa_algorithm_t alg;
+    uint8_t *nonce = NULL;
+    size_t nonce_length;
+    uint8_t *additional_data = NULL;
+    size_t additional_data_length;
+    uint8_t *plaintext = NULL;
+    size_t plaintext_length;
+    uint8_t *ciphertext = NULL;
+    size_t ciphertext_size;
+    size_t ciphertext_length;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_mbedtls_svc_key_id_t(&pos, &remaining, &key);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_algorithm_t(&pos, &remaining, &alg);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &nonce, &nonce_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &additional_data, &additional_data_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &plaintext, &plaintext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &ciphertext, &ciphertext_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&pos, &remaining, &ciphertext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_aead_encrypt(
+        key,
+        alg,
+        nonce, nonce_length,
+        additional_data, additional_data_length,
+        plaintext, plaintext_length,
+        ciphertext, ciphertext_size,
+        &ciphertext_length
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_serialise_buffer_needs(ciphertext, ciphertext_size) +
+        psasim_serialise_size_t_needs(ciphertext_length);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_buffer(&rpos, &rremain, ciphertext, ciphertext_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_size_t(&rpos, &rremain, ciphertext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    free(nonce);
+    free(additional_data);
+    free(plaintext);
+    free(ciphertext);
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    free(nonce);
+    free(additional_data);
+    free(plaintext);
+    free(ciphertext);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_aead_encrypt_setup_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_aead_operation_t *operation;
+    mbedtls_svc_key_id_t key;
+    psa_algorithm_t alg;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_deserialise_psa_aead_operation_t(&pos, &remaining, &operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_mbedtls_svc_key_id_t(&pos, &remaining, &key);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_algorithm_t(&pos, &remaining, &alg);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_aead_encrypt_setup(
+        operation,
+        key,
+        alg
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_server_serialise_psa_aead_operation_t_needs(operation);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_serialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_aead_finish_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_aead_operation_t *operation;
+    uint8_t *ciphertext = NULL;
+    size_t ciphertext_size;
+    size_t ciphertext_length;
+    uint8_t *tag = NULL;
+    size_t tag_size;
+    size_t tag_length;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_deserialise_psa_aead_operation_t(&pos, &remaining, &operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &ciphertext, &ciphertext_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&pos, &remaining, &ciphertext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &tag, &tag_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&pos, &remaining, &tag_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_aead_finish(
+        operation,
+        ciphertext, ciphertext_size,
+        &ciphertext_length,
+        tag, tag_size,
+        &tag_length
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_server_serialise_psa_aead_operation_t_needs(operation) +
+        psasim_serialise_buffer_needs(ciphertext, ciphertext_size) +
+        psasim_serialise_size_t_needs(ciphertext_length) +
+        psasim_serialise_buffer_needs(tag, tag_size) +
+        psasim_serialise_size_t_needs(tag_length);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_serialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_buffer(&rpos, &rremain, ciphertext, ciphertext_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_size_t(&rpos, &rremain, ciphertext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_buffer(&rpos, &rremain, tag, tag_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_size_t(&rpos, &rremain, tag_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    free(ciphertext);
+    free(tag);
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    free(ciphertext);
+    free(tag);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_aead_generate_nonce_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_aead_operation_t *operation;
+    uint8_t *nonce = NULL;
+    size_t nonce_size;
+    size_t nonce_length;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_deserialise_psa_aead_operation_t(&pos, &remaining, &operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &nonce, &nonce_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&pos, &remaining, &nonce_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_aead_generate_nonce(
+        operation,
+        nonce, nonce_size,
+        &nonce_length
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_server_serialise_psa_aead_operation_t_needs(operation) +
+        psasim_serialise_buffer_needs(nonce, nonce_size) +
+        psasim_serialise_size_t_needs(nonce_length);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_serialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_buffer(&rpos, &rremain, nonce, nonce_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_size_t(&rpos, &rremain, nonce_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    free(nonce);
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    free(nonce);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_aead_set_lengths_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_aead_operation_t *operation;
+    size_t ad_length;
+    size_t plaintext_length;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_deserialise_psa_aead_operation_t(&pos, &remaining, &operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&pos, &remaining, &ad_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&pos, &remaining, &plaintext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_aead_set_lengths(
+        operation,
+        ad_length,
+        plaintext_length
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_server_serialise_psa_aead_operation_t_needs(operation);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_serialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_aead_set_nonce_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_aead_operation_t *operation;
+    uint8_t *nonce = NULL;
+    size_t nonce_length;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_deserialise_psa_aead_operation_t(&pos, &remaining, &operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &nonce, &nonce_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_aead_set_nonce(
+        operation,
+        nonce, nonce_length
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_server_serialise_psa_aead_operation_t_needs(operation);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_serialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    free(nonce);
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    free(nonce);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_aead_update_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_aead_operation_t *operation;
+    uint8_t *input = NULL;
+    size_t input_length;
+    uint8_t *output = NULL;
+    size_t output_size;
+    size_t output_length;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_deserialise_psa_aead_operation_t(&pos, &remaining, &operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &input, &input_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &output, &output_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&pos, &remaining, &output_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_aead_update(
+        operation,
+        input, input_length,
+        output, output_size,
+        &output_length
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_server_serialise_psa_aead_operation_t_needs(operation) +
+        psasim_serialise_buffer_needs(output, output_size) +
+        psasim_serialise_size_t_needs(output_length);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_serialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_buffer(&rpos, &rremain, output, output_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_size_t(&rpos, &rremain, output_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    free(input);
+    free(output);
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    free(input);
+    free(output);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_aead_update_ad_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_aead_operation_t *operation;
+    uint8_t *input = NULL;
+    size_t input_length;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_deserialise_psa_aead_operation_t(&pos, &remaining, &operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &input, &input_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_aead_update_ad(
+        operation,
+        input, input_length
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_server_serialise_psa_aead_operation_t_needs(operation);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_serialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    free(input);
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    free(input);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_aead_verify_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_aead_operation_t *operation;
+    uint8_t *plaintext = NULL;
+    size_t plaintext_size;
+    size_t plaintext_length;
+    uint8_t *tag = NULL;
+    size_t tag_length;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_deserialise_psa_aead_operation_t(&pos, &remaining, &operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &plaintext, &plaintext_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_size_t(&pos, &remaining, &plaintext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &tag, &tag_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_aead_verify(
+        operation,
+        plaintext, plaintext_size,
+        &plaintext_length,
+        tag, tag_length
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_server_serialise_psa_aead_operation_t_needs(operation) +
+        psasim_serialise_buffer_needs(plaintext, plaintext_size) +
+        psasim_serialise_size_t_needs(plaintext_length);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_serialise_psa_aead_operation_t(&rpos, &rremain, operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_buffer(&rpos, &rremain, plaintext, plaintext_size);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_size_t(&rpos, &rremain, plaintext_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    free(plaintext);
+    free(tag);
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    free(plaintext);
+    free(tag);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_destroy_key_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    mbedtls_svc_key_id_t key;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_mbedtls_svc_key_id_t(&pos, &remaining, &key);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_destroy_key(
+        key
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_get_key_attributes_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    mbedtls_svc_key_id_t key;
+    psa_key_attributes_t attributes;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_mbedtls_svc_key_id_t(&pos, &remaining, &key);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_key_attributes_t(&pos, &remaining, &attributes);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_get_key_attributes(
+        key,
+        &attributes
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_serialise_psa_key_attributes_t_needs(attributes);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_key_attributes_t(&rpos, &rremain, attributes);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    return 0;       // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_hash_abort_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_hash_operation_t *operation;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_deserialise_psa_hash_operation_t(&pos, &remaining, &operation);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_hash_abort(
+        operation
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_server_serialise_psa_hash_operation_t_needs(operation);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_server_serialise_psa_hash_operation_t(&rpos, &rremain, operation);
     if (!ok) {
         goto fail;
     }
@@ -141,8 +1475,8 @@
     uint8_t **out_params, size_t *out_params_len)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_hash_operation_t source_operation;
-    psa_hash_operation_t target_operation;
+    psa_hash_operation_t *source_operation;
+    psa_hash_operation_t *target_operation;
 
     uint8_t *pos = in_params;
     size_t remaining = in_params_len;
@@ -154,12 +1488,12 @@
         goto fail;
     }
 
-    ok = psasim_deserialise_psa_hash_operation_t(&pos, &remaining, &source_operation);
+    ok = psasim_server_deserialise_psa_hash_operation_t(&pos, &remaining, &source_operation);
     if (!ok) {
         goto fail;
     }
 
-    ok = psasim_deserialise_psa_hash_operation_t(&pos, &remaining, &target_operation);
+    ok = psasim_server_deserialise_psa_hash_operation_t(&pos, &remaining, &target_operation);
     if (!ok) {
         goto fail;
     }
@@ -167,15 +1501,15 @@
     // Now we call the actual target function
 
     status = psa_hash_clone(
-        &source_operation,
-        &target_operation
+        source_operation,
+        target_operation
         );
 
     // NOTE: Should really check there is no overflow as we go along.
     size_t result_size =
         psasim_serialise_begin_needs() +
         psasim_serialise_psa_status_t_needs(status) +
-        psasim_serialise_psa_hash_operation_t_needs(target_operation);
+        psasim_server_serialise_psa_hash_operation_t_needs(target_operation);
 
     result = malloc(result_size);
     if (result == NULL) {
@@ -195,7 +1529,7 @@
         goto fail;
     }
 
-    ok = psasim_serialise_psa_hash_operation_t(&rpos, &rremain, target_operation);
+    ok = psasim_server_serialise_psa_hash_operation_t(&rpos, &rremain, target_operation);
     if (!ok) {
         goto fail;
     }
@@ -406,7 +1740,7 @@
     uint8_t **out_params, size_t *out_params_len)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_hash_operation_t operation;
+    psa_hash_operation_t *operation;
     uint8_t *hash = NULL;
     size_t hash_size;
     size_t hash_length;
@@ -421,7 +1755,7 @@
         goto fail;
     }
 
-    ok = psasim_deserialise_psa_hash_operation_t(&pos, &remaining, &operation);
+    ok = psasim_server_deserialise_psa_hash_operation_t(&pos, &remaining, &operation);
     if (!ok) {
         goto fail;
     }
@@ -439,7 +1773,7 @@
     // Now we call the actual target function
 
     status = psa_hash_finish(
-        &operation,
+        operation,
         hash, hash_size,
         &hash_length
         );
@@ -448,7 +1782,7 @@
     size_t result_size =
         psasim_serialise_begin_needs() +
         psasim_serialise_psa_status_t_needs(status) +
-        psasim_serialise_psa_hash_operation_t_needs(operation) +
+        psasim_server_serialise_psa_hash_operation_t_needs(operation) +
         psasim_serialise_buffer_needs(hash, hash_size) +
         psasim_serialise_size_t_needs(hash_length);
 
@@ -470,7 +1804,7 @@
         goto fail;
     }
 
-    ok = psasim_serialise_psa_hash_operation_t(&rpos, &rremain, operation);
+    ok = psasim_server_serialise_psa_hash_operation_t(&rpos, &rremain, operation);
     if (!ok) {
         goto fail;
     }
@@ -506,7 +1840,7 @@
     uint8_t **out_params, size_t *out_params_len)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_hash_operation_t operation;
+    psa_hash_operation_t *operation;
     psa_algorithm_t alg;
 
     uint8_t *pos = in_params;
@@ -519,7 +1853,7 @@
         goto fail;
     }
 
-    ok = psasim_deserialise_psa_hash_operation_t(&pos, &remaining, &operation);
+    ok = psasim_server_deserialise_psa_hash_operation_t(&pos, &remaining, &operation);
     if (!ok) {
         goto fail;
     }
@@ -532,7 +1866,7 @@
     // Now we call the actual target function
 
     status = psa_hash_setup(
-        &operation,
+        operation,
         alg
         );
 
@@ -540,7 +1874,7 @@
     size_t result_size =
         psasim_serialise_begin_needs() +
         psasim_serialise_psa_status_t_needs(status) +
-        psasim_serialise_psa_hash_operation_t_needs(operation);
+        psasim_server_serialise_psa_hash_operation_t_needs(operation);
 
     result = malloc(result_size);
     if (result == NULL) {
@@ -560,7 +1894,7 @@
         goto fail;
     }
 
-    ok = psasim_serialise_psa_hash_operation_t(&rpos, &rremain, operation);
+    ok = psasim_server_serialise_psa_hash_operation_t(&rpos, &rremain, operation);
     if (!ok) {
         goto fail;
     }
@@ -582,7 +1916,7 @@
     uint8_t **out_params, size_t *out_params_len)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_hash_operation_t operation;
+    psa_hash_operation_t *operation;
     uint8_t *input = NULL;
     size_t input_length;
 
@@ -596,7 +1930,7 @@
         goto fail;
     }
 
-    ok = psasim_deserialise_psa_hash_operation_t(&pos, &remaining, &operation);
+    ok = psasim_server_deserialise_psa_hash_operation_t(&pos, &remaining, &operation);
     if (!ok) {
         goto fail;
     }
@@ -609,7 +1943,7 @@
     // Now we call the actual target function
 
     status = psa_hash_update(
-        &operation,
+        operation,
         input, input_length
         );
 
@@ -617,7 +1951,7 @@
     size_t result_size =
         psasim_serialise_begin_needs() +
         psasim_serialise_psa_status_t_needs(status) +
-        psasim_serialise_psa_hash_operation_t_needs(operation);
+        psasim_server_serialise_psa_hash_operation_t_needs(operation);
 
     result = malloc(result_size);
     if (result == NULL) {
@@ -637,7 +1971,7 @@
         goto fail;
     }
 
-    ok = psasim_serialise_psa_hash_operation_t(&rpos, &rremain, operation);
+    ok = psasim_server_serialise_psa_hash_operation_t(&rpos, &rremain, operation);
     if (!ok) {
         goto fail;
     }
@@ -663,7 +1997,7 @@
     uint8_t **out_params, size_t *out_params_len)
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    psa_hash_operation_t operation;
+    psa_hash_operation_t *operation;
     uint8_t *hash = NULL;
     size_t hash_length;
 
@@ -677,7 +2011,7 @@
         goto fail;
     }
 
-    ok = psasim_deserialise_psa_hash_operation_t(&pos, &remaining, &operation);
+    ok = psasim_server_deserialise_psa_hash_operation_t(&pos, &remaining, &operation);
     if (!ok) {
         goto fail;
     }
@@ -690,7 +2024,7 @@
     // Now we call the actual target function
 
     status = psa_hash_verify(
-        &operation,
+        operation,
         hash, hash_length
         );
 
@@ -698,7 +2032,7 @@
     size_t result_size =
         psasim_serialise_begin_needs() +
         psasim_serialise_psa_status_t_needs(status) +
-        psasim_serialise_psa_hash_operation_t_needs(operation);
+        psasim_server_serialise_psa_hash_operation_t_needs(operation);
 
     result = malloc(result_size);
     if (result == NULL) {
@@ -718,7 +2052,7 @@
         goto fail;
     }
 
-    ok = psasim_serialise_psa_hash_operation_t(&rpos, &rremain, operation);
+    ok = psasim_server_serialise_psa_hash_operation_t(&rpos, &rremain, operation);
     if (!ok) {
         goto fail;
     }
@@ -738,6 +2072,94 @@
     return 0;       // This shouldn't happen!
 }
 
+// Returns 1 for success, 0 for failure
+int psa_import_key_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_key_attributes_t attributes;
+    uint8_t *data = NULL;
+    size_t data_length;
+    mbedtls_svc_key_id_t key;
+
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+    uint8_t *result = NULL;
+    int ok;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_key_attributes_t(&pos, &remaining, &attributes);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_buffer(&pos, &remaining, &data, &data_length);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_mbedtls_svc_key_id_t(&pos, &remaining, &key);
+    if (!ok) {
+        goto fail;
+    }
+
+    // Now we call the actual target function
+
+    status = psa_import_key(
+        &attributes,
+        data, data_length,
+        &key
+        );
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs() +
+        psasim_serialise_psa_status_t_needs(status) +
+        psasim_serialise_mbedtls_svc_key_id_t_needs(key);
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_serialise_mbedtls_svc_key_id_t(&rpos, &rremain, key);
+    if (!ok) {
+        goto fail;
+    }
+
+    *out_params = result;
+    *out_params_len = result_size;
+
+    free(data);
+
+    return 1;   // success
+
+fail:
+    free(result);
+
+    free(data);
+
+    return 0;       // This shouldn't happen!
+}
+
 psa_status_t psa_crypto_call(psa_msg_t msg)
 {
     int ok = 0;
@@ -778,6 +2200,62 @@
             ok = psa_crypto_init_wrapper(in_params, in_params_len,
                                          &out_params, &out_params_len);
             break;
+        case PSA_AEAD_ABORT:
+            ok = psa_aead_abort_wrapper(in_params, in_params_len,
+                                        &out_params, &out_params_len);
+            break;
+        case PSA_AEAD_DECRYPT:
+            ok = psa_aead_decrypt_wrapper(in_params, in_params_len,
+                                          &out_params, &out_params_len);
+            break;
+        case PSA_AEAD_DECRYPT_SETUP:
+            ok = psa_aead_decrypt_setup_wrapper(in_params, in_params_len,
+                                                &out_params, &out_params_len);
+            break;
+        case PSA_AEAD_ENCRYPT:
+            ok = psa_aead_encrypt_wrapper(in_params, in_params_len,
+                                          &out_params, &out_params_len);
+            break;
+        case PSA_AEAD_ENCRYPT_SETUP:
+            ok = psa_aead_encrypt_setup_wrapper(in_params, in_params_len,
+                                                &out_params, &out_params_len);
+            break;
+        case PSA_AEAD_FINISH:
+            ok = psa_aead_finish_wrapper(in_params, in_params_len,
+                                         &out_params, &out_params_len);
+            break;
+        case PSA_AEAD_GENERATE_NONCE:
+            ok = psa_aead_generate_nonce_wrapper(in_params, in_params_len,
+                                                 &out_params, &out_params_len);
+            break;
+        case PSA_AEAD_SET_LENGTHS:
+            ok = psa_aead_set_lengths_wrapper(in_params, in_params_len,
+                                              &out_params, &out_params_len);
+            break;
+        case PSA_AEAD_SET_NONCE:
+            ok = psa_aead_set_nonce_wrapper(in_params, in_params_len,
+                                            &out_params, &out_params_len);
+            break;
+        case PSA_AEAD_UPDATE:
+            ok = psa_aead_update_wrapper(in_params, in_params_len,
+                                         &out_params, &out_params_len);
+            break;
+        case PSA_AEAD_UPDATE_AD:
+            ok = psa_aead_update_ad_wrapper(in_params, in_params_len,
+                                            &out_params, &out_params_len);
+            break;
+        case PSA_AEAD_VERIFY:
+            ok = psa_aead_verify_wrapper(in_params, in_params_len,
+                                         &out_params, &out_params_len);
+            break;
+        case PSA_DESTROY_KEY:
+            ok = psa_destroy_key_wrapper(in_params, in_params_len,
+                                         &out_params, &out_params_len);
+            break;
+        case PSA_GET_KEY_ATTRIBUTES:
+            ok = psa_get_key_attributes_wrapper(in_params, in_params_len,
+                                                &out_params, &out_params_len);
+            break;
         case PSA_HASH_ABORT:
             ok = psa_hash_abort_wrapper(in_params, in_params_len,
                                         &out_params, &out_params_len);
@@ -810,6 +2288,10 @@
             ok = psa_hash_verify_wrapper(in_params, in_params_len,
                                          &out_params, &out_params_len);
             break;
+        case PSA_IMPORT_KEY:
+            ok = psa_import_key_wrapper(in_params, in_params_len,
+                                        &out_params, &out_params_len);
+            break;
     }
 
     free(in_params);
@@ -832,3 +2314,8 @@
 
     return ok ? PSA_SUCCESS : PSA_ERROR_GENERIC_ERROR;
 }
+
+void psa_crypto_close(void)
+{
+    psa_sim_serialize_reset();
+}
diff --git a/tests/psa-client-server/psasim/src/psa_sim_generate.pl b/tests/psa-client-server/psasim/src/psa_sim_generate.pl
index 19c6a0b..43de1db 100755
--- a/tests/psa-client-server/psasim/src/psa_sim_generate.pl
+++ b/tests/psa-client-server/psasim/src/psa_sim_generate.pl
@@ -244,6 +244,16 @@
 }
 EOF
 
+    # Finally, add psa_crypto_close()
+
+    print $fh <<EOF;
+
+void psa_crypto_close(void)
+{
+    psa_sim_serialize_reset();
+}
+EOF
+
     close($fh);
 }
 
@@ -268,6 +278,10 @@
 #include "psa_sim_serialise.h"
 
 #include "service.h"
+
+#if !defined(MBEDTLS_PSA_CRYPTO_C)
+#error "Error: MBEDTLS_PSA_CRYPTO_C must be enabled on server build"
+#endif
 EOF
 }
 
@@ -298,9 +312,13 @@
 #include "psa/crypto.h"
 
 #define CLIENT_PRINT(fmt, ...) \
-    PRINT("Client: " fmt, ##__VA_ARGS__)
+    INFO("Client: " fmt, ##__VA_ARGS__)
 
 static psa_handle_t handle = -1;
+
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+#error "Error: MBEDTLS_PSA_CRYPTO_C must be disabled on client build"
+#endif
 EOF
 
     $code .= debug_functions() if $debug;
@@ -522,8 +540,9 @@
             push(@buffers, $n1);        # Add to the list to be free()d at end
         } else {
             $argname =~ s/^\*//;        # Remove any leading *
+            my $pointer = ($argtype =~ /^psa_\w+_operation_t/) ? "*" : "";
             print $fh <<EOF;
-    $argtype $argname;
+    $argtype $pointer$argname;
 EOF
         }
     }
@@ -574,9 +593,10 @@
 EOF
         } else {
             $argname =~ s/^\*//;        # Remove any leading *
+            my $server_specific = ($argtype =~ /^psa_\w+_operation_t/) ? "server_" : "";
             print $fh <<EOF;
 
-    ok = psasim_deserialise_${argtype}(&pos, &remaining, &$argname);
+    ok = psasim_${server_specific}deserialise_${argtype}(&pos, &remaining, &$argname);
     if (!ok) {
         goto fail;
     }
@@ -588,7 +608,7 @@
 
     // Now we call the actual target function
 EOF
-    output_call($fh, $f, $name);
+    output_call($fh, $f, $name, 1);
 
     my @outputs = grep($_->{is_output}, @$args);
 
@@ -616,9 +636,10 @@
         my $sep = ($i == $#outputs) ? ";" : " +";
         $argtype =~ s/^const //;
         $argname =~ s/^\*//;        # Remove any leading *
+        my $server_specific = ($argtype =~ /^psa_\w+_operation_t/) ? "server_" : "";
 
         print $fh <<EOF;
-        psasim_serialise_${argtype}_needs($argname)$sep
+        psasim_${server_specific}serialise_${argtype}_needs($argname)$sep
 EOF
     }
 
@@ -673,9 +694,11 @@
                 die("$0: $argname: HOW TO OUTPUT?\n");
             }
 
+            my $server_specific = ($argtype =~ /^psa_\w+_operation_t/) ? "server_" : "";
+
             print $fh <<EOF;
 
-    ok = psasim_serialise_${argtype}(&rpos, &rremain, $argname);
+    ok = psasim_${server_specific}serialise_${argtype}(&rpos, &rremain, $argname);
     if (!ok) {
         goto fail;
     }
@@ -790,7 +813,7 @@
     ok = psa_crypto_call($enum,
                          params, (size_t) (pos - params), &result, &result_length);
     if (!ok) {
-        printf("XXX server call failed\\n");
+        printf("$enum server call failed\\n");
         goto fail;
     }
 EOF
@@ -881,7 +904,7 @@
 
 sub output_call
 {
-    my ($fh, $f, $name) = @_;
+    my ($fh, $f, $name, $is_server) = @_;
 
     my $ret_name = $f->{return}->{name};
     my $args = $f->{args};
@@ -900,6 +923,9 @@
             print $fh "        $n1, $n2";
         } else {
             $argname =~ s/^\*/\&/;      # Replace leading * with &
+            if ($is_server && $argtype =~ /^psa_\w+_operation_t/) {
+                $argname =~ s/^\&//;    # Actually, for psa_XXX_operation_t, don't do this on the server side
+            }
             print $fh "        $argname";
         }
         my $sep = ($i == $#$args) ? "\n        );" : ",";
@@ -1409,3 +1435,939 @@
                               size_t input_length,
                               const uint8_t *hash,
                               size_t hash_length);
+
+/** Process an authenticated encryption operation.
+ *
+ * \param key                     Identifier of the key to use for the
+ *                                operation. It must allow the usage
+ *                                #PSA_KEY_USAGE_ENCRYPT.
+ * \param alg                     The AEAD algorithm to compute
+ *                                (\c PSA_ALG_XXX value such that
+ *                                #PSA_ALG_IS_AEAD(\p alg) is true).
+ * \param[in] nonce               Nonce or IV to use.
+ * \param nonce_length            Size of the \p nonce buffer in bytes.
+ * \param[in] additional_data     Additional data that will be authenticated
+ *                                but not encrypted.
+ * \param additional_data_length  Size of \p additional_data in bytes.
+ * \param[in] plaintext           Data that will be authenticated and
+ *                                encrypted.
+ * \param plaintext_length        Size of \p plaintext in bytes.
+ * \param[out] ciphertext         Output buffer for the authenticated and
+ *                                encrypted data. The additional data is not
+ *                                part of this output. For algorithms where the
+ *                                encrypted data and the authentication tag
+ *                                are defined as separate outputs, the
+ *                                authentication tag is appended to the
+ *                                encrypted data.
+ * \param ciphertext_size         Size of the \p ciphertext buffer in bytes.
+ *                                This must be appropriate for the selected
+ *                                algorithm and key:
+ *                                - A sufficient output size is
+ *                                  #PSA_AEAD_ENCRYPT_OUTPUT_SIZE(\c key_type,
+ *                                  \p alg, \p plaintext_length) where
+ *                                  \c key_type is the type of \p key.
+ *                                - #PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(\p
+ *                                  plaintext_length) evaluates to the maximum
+ *                                  ciphertext size of any supported AEAD
+ *                                  encryption.
+ * \param[out] ciphertext_length  On success, the size of the output
+ *                                in the \p ciphertext buffer.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_INVALID_HANDLE \emptydescription
+ * \retval #PSA_ERROR_NOT_PERMITTED \emptydescription
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         \p key is not compatible with \p alg.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ *         \p alg is not supported or is not an AEAD algorithm.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ *         \p ciphertext_size is too small.
+ *         #PSA_AEAD_ENCRYPT_OUTPUT_SIZE(\c key_type, \p alg,
+ *         \p plaintext_length) or
+ *         #PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(\p plaintext_length) can be used to
+ *         determine the required buffer size.
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The library has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_aead_encrypt(mbedtls_svc_key_id_t key,
+                              psa_algorithm_t alg,
+                              const uint8_t *nonce,
+                              size_t nonce_length,
+                              const uint8_t *additional_data,
+                              size_t additional_data_length,
+                              const uint8_t *plaintext,
+                              size_t plaintext_length,
+                              uint8_t *ciphertext,
+                              size_t ciphertext_size,
+                              size_t *ciphertext_length);
+
+/** Process an authenticated decryption operation.
+ *
+ * \param key                     Identifier of the key to use for the
+ *                                operation. It must allow the usage
+ *                                #PSA_KEY_USAGE_DECRYPT.
+ * \param alg                     The AEAD algorithm to compute
+ *                                (\c PSA_ALG_XXX value such that
+ *                                #PSA_ALG_IS_AEAD(\p alg) is true).
+ * \param[in] nonce               Nonce or IV to use.
+ * \param nonce_length            Size of the \p nonce buffer in bytes.
+ * \param[in] additional_data     Additional data that has been authenticated
+ *                                but not encrypted.
+ * \param additional_data_length  Size of \p additional_data in bytes.
+ * \param[in] ciphertext          Data that has been authenticated and
+ *                                encrypted. For algorithms where the
+ *                                encrypted data and the authentication tag
+ *                                are defined as separate inputs, the buffer
+ *                                must contain the encrypted data followed
+ *                                by the authentication tag.
+ * \param ciphertext_length       Size of \p ciphertext in bytes.
+ * \param[out] plaintext          Output buffer for the decrypted data.
+ * \param plaintext_size          Size of the \p plaintext buffer in bytes.
+ *                                This must be appropriate for the selected
+ *                                algorithm and key:
+ *                                - A sufficient output size is
+ *                                  #PSA_AEAD_DECRYPT_OUTPUT_SIZE(\c key_type,
+ *                                  \p alg, \p ciphertext_length) where
+ *                                  \c key_type is the type of \p key.
+ *                                - #PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE(\p
+ *                                  ciphertext_length) evaluates to the maximum
+ *                                  plaintext size of any supported AEAD
+ *                                  decryption.
+ * \param[out] plaintext_length   On success, the size of the output
+ *                                in the \p plaintext buffer.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_INVALID_HANDLE \emptydescription
+ * \retval #PSA_ERROR_INVALID_SIGNATURE
+ *         The ciphertext is not authentic.
+ * \retval #PSA_ERROR_NOT_PERMITTED \emptydescription
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         \p key is not compatible with \p alg.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ *         \p alg is not supported or is not an AEAD algorithm.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ *         \p plaintext_size is too small.
+ *         #PSA_AEAD_DECRYPT_OUTPUT_SIZE(\c key_type, \p alg,
+ *         \p ciphertext_length) or
+ *         #PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE(\p ciphertext_length) can be used
+ *         to determine the required buffer size.
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The library has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_aead_decrypt(mbedtls_svc_key_id_t key,
+                              psa_algorithm_t alg,
+                              const uint8_t *nonce,
+                              size_t nonce_length,
+                              const uint8_t *additional_data,
+                              size_t additional_data_length,
+                              const uint8_t *ciphertext,
+                              size_t ciphertext_length,
+                              uint8_t *plaintext,
+                              size_t plaintext_size,
+                              size_t *plaintext_length);
+
+/** The type of the state data structure for multipart AEAD operations.
+ *
+ * Before calling any function on an AEAD operation object, the application
+ * must initialize it by any of the following means:
+ * - Set the structure to all-bits-zero, for example:
+ *   \code
+ *   psa_aead_operation_t operation;
+ *   memset(&operation, 0, sizeof(operation));
+ *   \endcode
+ * - Initialize the structure to logical zero values, for example:
+ *   \code
+ *   psa_aead_operation_t operation = {0};
+ *   \endcode
+ * - Initialize the structure to the initializer #PSA_AEAD_OPERATION_INIT,
+ *   for example:
+ *   \code
+ *   psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT;
+ *   \endcode
+ * - Assign the result of the function psa_aead_operation_init()
+ *   to the structure, for example:
+ *   \code
+ *   psa_aead_operation_t operation;
+ *   operation = psa_aead_operation_init();
+ *   \endcode
+ *
+ * This is an implementation-defined \c struct. Applications should not
+ * make any assumptions about the content of this structure.
+ * Implementation details can change in future versions without notice. */
+typedef struct psa_aead_operation_s psa_aead_operation_t;
+
+/** \def PSA_AEAD_OPERATION_INIT
+ *
+ * This macro returns a suitable initializer for an AEAD operation object of
+ * type #psa_aead_operation_t.
+ */
+
+/** Return an initial value for an AEAD operation object.
+ */
+static psa_aead_operation_t psa_aead_operation_init(void);
+
+/** Set the key for a multipart authenticated encryption operation.
+ *
+ * The sequence of operations to encrypt a message with authentication
+ * is as follows:
+ * -# Allocate an operation object which will be passed to all the functions
+ *    listed here.
+ * -# Initialize the operation object with one of the methods described in the
+ *    documentation for #psa_aead_operation_t, e.g.
+ *    #PSA_AEAD_OPERATION_INIT.
+ * -# Call psa_aead_encrypt_setup() to specify the algorithm and key.
+ * -# If needed, call psa_aead_set_lengths() to specify the length of the
+ *    inputs to the subsequent calls to psa_aead_update_ad() and
+ *    psa_aead_update(). See the documentation of psa_aead_set_lengths()
+ *    for details.
+ * -# Call either psa_aead_generate_nonce() or psa_aead_set_nonce() to
+ *    generate or set the nonce. You should use
+ *    psa_aead_generate_nonce() unless the protocol you are implementing
+ *    requires a specific nonce value.
+ * -# Call psa_aead_update_ad() zero, one or more times, passing a fragment
+ *    of the non-encrypted additional authenticated data each time.
+ * -# Call psa_aead_update() zero, one or more times, passing a fragment
+ *    of the message to encrypt each time.
+ * -# Call psa_aead_finish().
+ *
+ * If an error occurs at any step after a call to psa_aead_encrypt_setup(),
+ * the operation will need to be reset by a call to psa_aead_abort(). The
+ * application may call psa_aead_abort() at any time after the operation
+ * has been initialized.
+ *
+ * After a successful call to psa_aead_encrypt_setup(), the application must
+ * eventually terminate the operation. The following events terminate an
+ * operation:
+ * - A successful call to psa_aead_finish().
+ * - A call to psa_aead_abort().
+ *
+ * \param[in,out] operation     The operation object to set up. It must have
+ *                              been initialized as per the documentation for
+ *                              #psa_aead_operation_t and not yet in use.
+ * \param key                   Identifier of the key to use for the operation.
+ *                              It must remain valid until the operation
+ *                              terminates. It must allow the usage
+ *                              #PSA_KEY_USAGE_ENCRYPT.
+ * \param alg                   The AEAD algorithm to compute
+ *                              (\c PSA_ALG_XXX value such that
+ *                              #PSA_ALG_IS_AEAD(\p alg) is true).
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The operation state is not valid (it must be inactive), or
+ *         the library has not been previously initialized by psa_crypto_init().
+ * \retval #PSA_ERROR_INVALID_HANDLE \emptydescription
+ * \retval #PSA_ERROR_NOT_PERMITTED \emptydescription
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         \p key is not compatible with \p alg.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ *         \p alg is not supported or is not an AEAD algorithm.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE
+ *         The library has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation,
+                                    mbedtls_svc_key_id_t key,
+                                    psa_algorithm_t alg);
+
+/** Set the key for a multipart authenticated decryption operation.
+ *
+ * The sequence of operations to decrypt a message with authentication
+ * is as follows:
+ * -# Allocate an operation object which will be passed to all the functions
+ *    listed here.
+ * -# Initialize the operation object with one of the methods described in the
+ *    documentation for #psa_aead_operation_t, e.g.
+ *    #PSA_AEAD_OPERATION_INIT.
+ * -# Call psa_aead_decrypt_setup() to specify the algorithm and key.
+ * -# If needed, call psa_aead_set_lengths() to specify the length of the
+ *    inputs to the subsequent calls to psa_aead_update_ad() and
+ *    psa_aead_update(). See the documentation of psa_aead_set_lengths()
+ *    for details.
+ * -# Call psa_aead_set_nonce() with the nonce for the decryption.
+ * -# Call psa_aead_update_ad() zero, one or more times, passing a fragment
+ *    of the non-encrypted additional authenticated data each time.
+ * -# Call psa_aead_update() zero, one or more times, passing a fragment
+ *    of the ciphertext to decrypt each time.
+ * -# Call psa_aead_verify().
+ *
+ * If an error occurs at any step after a call to psa_aead_decrypt_setup(),
+ * the operation will need to be reset by a call to psa_aead_abort(). The
+ * application may call psa_aead_abort() at any time after the operation
+ * has been initialized.
+ *
+ * After a successful call to psa_aead_decrypt_setup(), the application must
+ * eventually terminate the operation. The following events terminate an
+ * operation:
+ * - A successful call to psa_aead_verify().
+ * - A call to psa_aead_abort().
+ *
+ * \param[in,out] operation     The operation object to set up. It must have
+ *                              been initialized as per the documentation for
+ *                              #psa_aead_operation_t and not yet in use.
+ * \param key                   Identifier of the key to use for the operation.
+ *                              It must remain valid until the operation
+ *                              terminates. It must allow the usage
+ *                              #PSA_KEY_USAGE_DECRYPT.
+ * \param alg                   The AEAD algorithm to compute
+ *                              (\c PSA_ALG_XXX value such that
+ *                              #PSA_ALG_IS_AEAD(\p alg) is true).
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_INVALID_HANDLE \emptydescription
+ * \retval #PSA_ERROR_NOT_PERMITTED \emptydescription
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         \p key is not compatible with \p alg.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ *         \p alg is not supported or is not an AEAD algorithm.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The operation state is not valid (it must be inactive), or the
+ *         library has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_aead_decrypt_setup(psa_aead_operation_t *operation,
+                                    mbedtls_svc_key_id_t key,
+                                    psa_algorithm_t alg);
+
+/** Generate a random nonce for an authenticated encryption operation.
+ *
+ * This function generates a random nonce for the authenticated encryption
+ * operation with an appropriate size for the chosen algorithm, key type
+ * and key size.
+ *
+ * The application must call psa_aead_encrypt_setup() before
+ * calling this function.
+ *
+ * If this function returns an error status, the operation enters an error
+ * state and must be aborted by calling psa_aead_abort().
+ *
+ * \param[in,out] operation     Active AEAD operation.
+ * \param[out] nonce            Buffer where the generated nonce is to be
+ *                              written.
+ * \param nonce_size            Size of the \p nonce buffer in bytes.
+ * \param[out] nonce_length     On success, the number of bytes of the
+ *                              generated nonce.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ *         The size of the \p nonce buffer is too small.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The operation state is not valid (it must be an active aead encrypt
+ *         operation, with no nonce set), or the library has not been
+ *         previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_aead_generate_nonce(psa_aead_operation_t *operation,
+                                     uint8_t *nonce,
+                                     size_t nonce_size,
+                                     size_t *nonce_length);
+
+/** Set the nonce for an authenticated encryption or decryption operation.
+ *
+ * This function sets the nonce for the authenticated
+ * encryption or decryption operation.
+ *
+ * The application must call psa_aead_encrypt_setup() or
+ * psa_aead_decrypt_setup() before calling this function.
+ *
+ * If this function returns an error status, the operation enters an error
+ * state and must be aborted by calling psa_aead_abort().
+ *
+ * \note When encrypting, applications should use psa_aead_generate_nonce()
+ * instead of this function, unless implementing a protocol that requires
+ * a non-random IV.
+ *
+ * \param[in,out] operation     Active AEAD operation.
+ * \param[in] nonce             Buffer containing the nonce to use.
+ * \param nonce_length          Size of the nonce in bytes.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         The size of \p nonce is not acceptable for the chosen algorithm.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The operation state is not valid (it must be active, with no nonce
+ *         set), or the library has not been previously initialized
+ *         by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_aead_set_nonce(psa_aead_operation_t *operation,
+                                const uint8_t *nonce,
+                                size_t nonce_length);
+
+/** Declare the lengths of the message and additional data for AEAD.
+ *
+ * The application must call this function before calling
+ * psa_aead_update_ad() or psa_aead_update() if the algorithm for
+ * the operation requires it. If the algorithm does not require it,
+ * calling this function is optional, but if this function is called
+ * then the implementation must enforce the lengths.
+ *
+ * You may call this function before or after setting the nonce with
+ * psa_aead_set_nonce() or psa_aead_generate_nonce().
+ *
+ * - For #PSA_ALG_CCM, calling this function is required.
+ * - For the other AEAD algorithms defined in this specification, calling
+ *   this function is not required.
+ * - For vendor-defined algorithm, refer to the vendor documentation.
+ *
+ * If this function returns an error status, the operation enters an error
+ * state and must be aborted by calling psa_aead_abort().
+ *
+ * \param[in,out] operation     Active AEAD operation.
+ * \param ad_length             Size of the non-encrypted additional
+ *                              authenticated data in bytes.
+ * \param plaintext_length      Size of the plaintext to encrypt in bytes.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         At least one of the lengths is not acceptable for the chosen
+ *         algorithm.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The operation state is not valid (it must be active, and
+ *         psa_aead_update_ad() and psa_aead_update() must not have been
+ *         called yet), or the library has not been previously initialized
+ *         by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_aead_set_lengths(psa_aead_operation_t *operation,
+                                  size_t ad_length,
+                                  size_t plaintext_length);
+
+/** Pass additional data to an active AEAD operation.
+ *
+ * Additional data is authenticated, but not encrypted.
+ *
+ * You may call this function multiple times to pass successive fragments
+ * of the additional data. You may not call this function after passing
+ * data to encrypt or decrypt with psa_aead_update().
+ *
+ * Before calling this function, you must:
+ * 1. Call either psa_aead_encrypt_setup() or psa_aead_decrypt_setup().
+ * 2. Set the nonce with psa_aead_generate_nonce() or psa_aead_set_nonce().
+ *
+ * If this function returns an error status, the operation enters an error
+ * state and must be aborted by calling psa_aead_abort().
+ *
+ * \warning When decrypting, until psa_aead_verify() has returned #PSA_SUCCESS,
+ *          there is no guarantee that the input is valid. Therefore, until
+ *          you have called psa_aead_verify() and it has returned #PSA_SUCCESS,
+ *          treat the input as untrusted and prepare to undo any action that
+ *          depends on the input if psa_aead_verify() returns an error status.
+ *
+ * \param[in,out] operation     Active AEAD operation.
+ * \param[in] input             Buffer containing the fragment of
+ *                              additional data.
+ * \param input_length          Size of the \p input buffer in bytes.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         The total input length overflows the additional data length that
+ *         was previously specified with psa_aead_set_lengths().
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The operation state is not valid (it must be active, have a nonce
+ *         set, have lengths set if required by the algorithm, and
+ *         psa_aead_update() must not have been called yet), or the library
+ *         has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_aead_update_ad(psa_aead_operation_t *operation,
+                                const uint8_t *input,
+                                size_t input_length);
+
+/** Encrypt or decrypt a message fragment in an active AEAD operation.
+ *
+ * Before calling this function, you must:
+ * 1. Call either psa_aead_encrypt_setup() or psa_aead_decrypt_setup().
+ *    The choice of setup function determines whether this function
+ *    encrypts or decrypts its input.
+ * 2. Set the nonce with psa_aead_generate_nonce() or psa_aead_set_nonce().
+ * 3. Call psa_aead_update_ad() to pass all the additional data.
+ *
+ * If this function returns an error status, the operation enters an error
+ * state and must be aborted by calling psa_aead_abort().
+ *
+ * \warning When decrypting, until psa_aead_verify() has returned #PSA_SUCCESS,
+ *          there is no guarantee that the input is valid. Therefore, until
+ *          you have called psa_aead_verify() and it has returned #PSA_SUCCESS:
+ *          - Do not use the output in any way other than storing it in a
+ *            confidential location. If you take any action that depends
+ *            on the tentative decrypted data, this action will need to be
+ *            undone if the input turns out not to be valid. Furthermore,
+ *            if an adversary can observe that this action took place
+ *            (for example through timing), they may be able to use this
+ *            fact as an oracle to decrypt any message encrypted with the
+ *            same key.
+ *          - In particular, do not copy the output anywhere but to a
+ *            memory or storage space that you have exclusive access to.
+ *
+ * This function does not require the input to be aligned to any
+ * particular block boundary. If the implementation can only process
+ * a whole block at a time, it must consume all the input provided, but
+ * it may delay the end of the corresponding output until a subsequent
+ * call to psa_aead_update(), psa_aead_finish() or psa_aead_verify()
+ * provides sufficient input. The amount of data that can be delayed
+ * in this way is bounded by #PSA_AEAD_UPDATE_OUTPUT_SIZE.
+ *
+ * \param[in,out] operation     Active AEAD operation.
+ * \param[in] input             Buffer containing the message fragment to
+ *                              encrypt or decrypt.
+ * \param input_length          Size of the \p input buffer in bytes.
+ * \param[out] output           Buffer where the output is to be written.
+ * \param output_size           Size of the \p output buffer in bytes.
+ *                              This must be appropriate for the selected
+ *                                algorithm and key:
+ *                                - A sufficient output size is
+ *                                  #PSA_AEAD_UPDATE_OUTPUT_SIZE(\c key_type,
+ *                                  \c alg, \p input_length) where
+ *                                  \c key_type is the type of key and \c alg is
+ *                                  the algorithm that were used to set up the
+ *                                  operation.
+ *                                - #PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE(\p
+ *                                  input_length) evaluates to the maximum
+ *                                  output size of any supported AEAD
+ *                                  algorithm.
+ * \param[out] output_length    On success, the number of bytes
+ *                              that make up the returned output.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ *         The size of the \p output buffer is too small.
+ *         #PSA_AEAD_UPDATE_OUTPUT_SIZE(\c key_type, \c alg, \p input_length) or
+ *         #PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE(\p input_length) can be used to
+ *         determine the required buffer size.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         The total length of input to psa_aead_update_ad() so far is
+ *         less than the additional data length that was previously
+ *         specified with psa_aead_set_lengths(), or
+ *         the total input length overflows the plaintext length that
+ *         was previously specified with psa_aead_set_lengths().
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The operation state is not valid (it must be active, have a nonce
+ *         set, and have lengths set if required by the algorithm), or the
+ *         library has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_aead_update(psa_aead_operation_t *operation,
+                             const uint8_t *input,
+                             size_t input_length,
+                             uint8_t *output,
+                             size_t output_size,
+                             size_t *output_length);
+
+/** Finish encrypting a message in an AEAD operation.
+ *
+ * The operation must have been set up with psa_aead_encrypt_setup().
+ *
+ * This function finishes the authentication of the additional data
+ * formed by concatenating the inputs passed to preceding calls to
+ * psa_aead_update_ad() with the plaintext formed by concatenating the
+ * inputs passed to preceding calls to psa_aead_update().
+ *
+ * This function has two output buffers:
+ * - \p ciphertext contains trailing ciphertext that was buffered from
+ *   preceding calls to psa_aead_update().
+ * - \p tag contains the authentication tag.
+ *
+ * When this function returns successfully, the operation becomes inactive.
+ * If this function returns an error status, the operation enters an error
+ * state and must be aborted by calling psa_aead_abort().
+ *
+ * \param[in,out] operation     Active AEAD operation.
+ * \param[out] ciphertext       Buffer where the last part of the ciphertext
+ *                              is to be written.
+ * \param ciphertext_size       Size of the \p ciphertext buffer in bytes.
+ *                              This must be appropriate for the selected
+ *                              algorithm and key:
+ *                              - A sufficient output size is
+ *                                #PSA_AEAD_FINISH_OUTPUT_SIZE(\c key_type,
+ *                                \c alg) where \c key_type is the type of key
+ *                                and \c alg is the algorithm that were used to
+ *                                set up the operation.
+ *                              - #PSA_AEAD_FINISH_OUTPUT_MAX_SIZE evaluates to
+ *                                the maximum output size of any supported AEAD
+ *                                algorithm.
+ * \param[out] ciphertext_length On success, the number of bytes of
+ *                              returned ciphertext.
+ * \param[out] tag              Buffer where the authentication tag is
+ *                              to be written.
+ * \param tag_size              Size of the \p tag buffer in bytes.
+ *                              This must be appropriate for the selected
+ *                              algorithm and key:
+ *                              - The exact tag size is #PSA_AEAD_TAG_LENGTH(\c
+ *                                key_type, \c key_bits, \c alg) where
+ *                                \c key_type and \c key_bits are the type and
+ *                                bit-size of the key, and \c alg is the
+ *                                algorithm that were used in the call to
+ *                                psa_aead_encrypt_setup().
+ *                              - #PSA_AEAD_TAG_MAX_SIZE evaluates to the
+ *                                maximum tag size of any supported AEAD
+ *                                algorithm.
+ * \param[out] tag_length       On success, the number of bytes
+ *                              that make up the returned tag.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ *         The size of the \p ciphertext or \p tag buffer is too small.
+ *         #PSA_AEAD_FINISH_OUTPUT_SIZE(\c key_type, \c alg) or
+ *         #PSA_AEAD_FINISH_OUTPUT_MAX_SIZE can be used to determine the
+ *         required \p ciphertext buffer size. #PSA_AEAD_TAG_LENGTH(\c key_type,
+ *         \c key_bits, \c alg) or #PSA_AEAD_TAG_MAX_SIZE can be used to
+ *         determine the required \p tag buffer size.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         The total length of input to psa_aead_update_ad() so far is
+ *         less than the additional data length that was previously
+ *         specified with psa_aead_set_lengths(), or
+ *         the total length of input to psa_aead_update() so far is
+ *         less than the plaintext length that was previously
+ *         specified with psa_aead_set_lengths().
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The operation state is not valid (it must be an active encryption
+ *         operation with a nonce set), or the library has not been previously
+ *         initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_aead_finish(psa_aead_operation_t *operation,
+                             uint8_t *ciphertext,
+                             size_t ciphertext_size,
+                             size_t *ciphertext_length,
+                             uint8_t *tag,
+                             size_t tag_size,
+                             size_t *tag_length);
+
+/** Finish authenticating and decrypting a message in an AEAD operation.
+ *
+ * The operation must have been set up with psa_aead_decrypt_setup().
+ *
+ * This function finishes the authenticated decryption of the message
+ * components:
+ *
+ * -  The additional data consisting of the concatenation of the inputs
+ *    passed to preceding calls to psa_aead_update_ad().
+ * -  The ciphertext consisting of the concatenation of the inputs passed to
+ *    preceding calls to psa_aead_update().
+ * -  The tag passed to this function call.
+ *
+ * If the authentication tag is correct, this function outputs any remaining
+ * plaintext and reports success. If the authentication tag is not correct,
+ * this function returns #PSA_ERROR_INVALID_SIGNATURE.
+ *
+ * When this function returns successfully, the operation becomes inactive.
+ * If this function returns an error status, the operation enters an error
+ * state and must be aborted by calling psa_aead_abort().
+ *
+ * \note Implementations shall make the best effort to ensure that the
+ * comparison between the actual tag and the expected tag is performed
+ * in constant time.
+ *
+ * \param[in,out] operation     Active AEAD operation.
+ * \param[out] plaintext        Buffer where the last part of the plaintext
+ *                              is to be written. This is the remaining data
+ *                              from previous calls to psa_aead_update()
+ *                              that could not be processed until the end
+ *                              of the input.
+ * \param plaintext_size        Size of the \p plaintext buffer in bytes.
+ *                              This must be appropriate for the selected algorithm and key:
+ *                              - A sufficient output size is
+ *                                #PSA_AEAD_VERIFY_OUTPUT_SIZE(\c key_type,
+ *                                \c alg) where \c key_type is the type of key
+ *                                and \c alg is the algorithm that were used to
+ *                                set up the operation.
+ *                              - #PSA_AEAD_VERIFY_OUTPUT_MAX_SIZE evaluates to
+ *                                the maximum output size of any supported AEAD
+ *                                algorithm.
+ * \param[out] plaintext_length On success, the number of bytes of
+ *                              returned plaintext.
+ * \param[in] tag               Buffer containing the authentication tag.
+ * \param tag_length            Size of the \p tag buffer in bytes.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_INVALID_SIGNATURE
+ *         The calculations were successful, but the authentication tag is
+ *         not correct.
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ *         The size of the \p plaintext buffer is too small.
+ *         #PSA_AEAD_VERIFY_OUTPUT_SIZE(\c key_type, \c alg) or
+ *         #PSA_AEAD_VERIFY_OUTPUT_MAX_SIZE can be used to determine the
+ *         required buffer size.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         The total length of input to psa_aead_update_ad() so far is
+ *         less than the additional data length that was previously
+ *         specified with psa_aead_set_lengths(), or
+ *         the total length of input to psa_aead_update() so far is
+ *         less than the plaintext length that was previously
+ *         specified with psa_aead_set_lengths().
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The operation state is not valid (it must be an active decryption
+ *         operation with a nonce set), or the library has not been previously
+ *         initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_aead_verify(psa_aead_operation_t *operation,
+                             uint8_t *plaintext,
+                             size_t plaintext_size,
+                             size_t *plaintext_length,
+                             const uint8_t *tag,
+                             size_t tag_length);
+
+/** Abort an AEAD operation.
+ *
+ * Aborting an operation frees all associated resources except for the
+ * \p operation structure itself. Once aborted, the operation object
+ * can be reused for another operation by calling
+ * psa_aead_encrypt_setup() or psa_aead_decrypt_setup() again.
+ *
+ * You may call this function any time after the operation object has
+ * been initialized as described in #psa_aead_operation_t.
+ *
+ * In particular, calling psa_aead_abort() after the operation has been
+ * terminated by a call to psa_aead_abort(), psa_aead_finish() or
+ * psa_aead_verify() is safe and has no effect.
+ *
+ * \param[in,out] operation     Initialized AEAD operation.
+ *
+ * \retval #PSA_SUCCESS \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The library has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_aead_abort(psa_aead_operation_t *operation);
+
+/**
+ * \brief Import a key in binary format.
+ *
+ * This function supports any output from psa_export_key(). Refer to the
+ * documentation of psa_export_public_key() for the format of public keys
+ * and to the documentation of psa_export_key() for the format for
+ * other key types.
+ *
+ * The key data determines the key size. The attributes may optionally
+ * specify a key size; in this case it must match the size determined
+ * from the key data. A key size of 0 in \p attributes indicates that
+ * the key size is solely determined by the key data.
+ *
+ * Implementations must reject an attempt to import a key of size 0.
+ *
+ * This specification supports a single format for each key type.
+ * Implementations may support other formats as long as the standard
+ * format is supported. Implementations that support other formats
+ * should ensure that the formats are clearly unambiguous so as to
+ * minimize the risk that an invalid input is accidentally interpreted
+ * according to a different format.
+ *
+ * \param[in] attributes    The attributes for the new key.
+ *                          The key size is always determined from the
+ *                          \p data buffer.
+ *                          If the key size in \p attributes is nonzero,
+ *                          it must be equal to the size from \p data.
+ * \param[out] key          On success, an identifier to the newly created key.
+ *                          For persistent keys, this is the key identifier
+ *                          defined in \p attributes.
+ *                          \c 0 on failure.
+ * \param[in] data    Buffer containing the key data. The content of this
+ *                    buffer is interpreted according to the type declared
+ *                    in \p attributes.
+ *                    All implementations must support at least the format
+ *                    described in the documentation
+ *                    of psa_export_key() or psa_export_public_key() for
+ *                    the chosen type. Implementations may allow other
+ *                    formats, but should be conservative: implementations
+ *                    should err on the side of rejecting content if it
+ *                    may be erroneous (e.g. wrong type or truncated data).
+ * \param data_length Size of the \p data buffer in bytes.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ *         If the key is persistent, the key material and the key's metadata
+ *         have been saved to persistent storage.
+ * \retval #PSA_ERROR_ALREADY_EXISTS
+ *         This is an attempt to create a persistent key, and there is
+ *         already a persistent key with the given identifier.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ *         The key type or key size is not supported, either by the
+ *         implementation in general or in this particular persistent location.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         The key attributes, as a whole, are invalid, or
+ *         the key data is not correctly formatted, or
+ *         the size in \p attributes is nonzero and does not match the size
+ *         of the key data.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_INSUFFICIENT_STORAGE \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription
+ * \retval #PSA_ERROR_DATA_INVALID \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The library has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_import_key(const psa_key_attributes_t *attributes,
+                            const uint8_t *data,
+                            size_t data_length,
+                            mbedtls_svc_key_id_t *key);
+
+/** Retrieve the attributes of a key.
+ *
+ * This function first resets the attribute structure as with
+ * psa_reset_key_attributes(). It then copies the attributes of
+ * the given key into the given attribute structure.
+ *
+ * \note This function may allocate memory or other resources.
+ *       Once you have called this function on an attribute structure,
+ *       you must call psa_reset_key_attributes() to free these resources.
+ *
+ * \param[in] key               Identifier of the key to query.
+ * \param[in,out] attributes    On success, the attributes of the key.
+ *                              On failure, equivalent to a
+ *                              freshly-initialized structure.
+ *
+ * \retval #PSA_SUCCESS \emptydescription
+ * \retval #PSA_ERROR_INVALID_HANDLE \emptydescription
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_DATA_CORRUPT \emptydescription
+ * \retval #PSA_ERROR_DATA_INVALID \emptydescription
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The library has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_get_key_attributes(mbedtls_svc_key_id_t key,
+                                    psa_key_attributes_t *attributes);
+
+/**
+ * \brief Destroy a key.
+ *
+ * This function destroys a key from both volatile
+ * memory and, if applicable, non-volatile storage. Implementations shall
+ * make a best effort to ensure that the key material cannot be recovered.
+ *
+ * This function also erases any metadata such as policies and frees
+ * resources associated with the key.
+ *
+ * If a key is currently in use in a multipart operation, then destroying the
+ * key will cause the multipart operation to fail.
+ *
+ * \warning    We can only guarantee that the the key material will
+ *             eventually be wiped from memory. With threading enabled
+ *             and during concurrent execution, copies of the key material may
+ *             still exist until all threads have finished using the key.
+ *
+ * \param key  Identifier of the key to erase. If this is \c 0, do nothing and
+ *             return #PSA_SUCCESS.
+ *
+ * \retval #PSA_SUCCESS
+ *         \p key was a valid identifier and the key material that it
+ *         referred to has been erased. Alternatively, \p key is \c 0.
+ * \retval #PSA_ERROR_NOT_PERMITTED
+ *         The key cannot be erased because it is
+ *         read-only, either due to a policy or due to physical restrictions.
+ * \retval #PSA_ERROR_INVALID_HANDLE
+ *         \p key is not a valid identifier nor \c 0.
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE
+ *         There was a failure in communication with the cryptoprocessor.
+ *         The key material may still be present in the cryptoprocessor.
+ * \retval #PSA_ERROR_DATA_INVALID
+ *         This error is typically a result of either storage corruption on a
+ *         cleartext storage backend, or an attempt to read data that was
+ *         written by an incompatible version of the library.
+ * \retval #PSA_ERROR_STORAGE_FAILURE
+ *         The storage is corrupted. Implementations shall make a best effort
+ *         to erase key material even in this stage, however applications
+ *         should be aware that it may be impossible to guarantee that the
+ *         key material is not recoverable in such cases.
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
+ *         An unexpected condition which is not a storage corruption or
+ *         a communication failure occurred. The cryptoprocessor may have
+ *         been compromised.
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The library has not been previously initialized by psa_crypto_init().
+ *         It is implementation-dependent whether a failure to initialize
+ *         results in this error code.
+ */
+psa_status_t psa_destroy_key(mbedtls_svc_key_id_t key);
diff --git a/tests/psa-client-server/psasim/src/psa_sim_serialise.c b/tests/psa-client-server/psasim/src/psa_sim_serialise.c
index 78ae9d6..651e046 100644
--- a/tests/psa-client-server/psasim/src/psa_sim_serialise.c
+++ b/tests/psa-client-server/psasim/src/psa_sim_serialise.c
@@ -10,6 +10,7 @@
  */
 
 #include "psa_sim_serialise.h"
+#include "util.h"
 #include <stdlib.h>
 #include <string.h>
 
@@ -51,6 +52,93 @@
  * don't contain pointers.
  */
 
+/* include/psa/crypto_platform.h:typedef uint32_t mbedtls_psa_client_handle_t;
+ * but we don't get it on server builds, so redefine it here with a unique type name
+ */
+typedef uint32_t psasim_client_handle_t;
+
+typedef struct psasim_operation_s {
+    psasim_client_handle_t handle;
+} psasim_operation_t;
+
+#define MAX_LIVE_HANDLES_PER_CLASS   100        /* this many slots */
+
+static psa_hash_operation_t hash_operations[MAX_LIVE_HANDLES_PER_CLASS];
+static psasim_client_handle_t hash_operation_handles[MAX_LIVE_HANDLES_PER_CLASS];
+static psasim_client_handle_t next_hash_operation_handle = 1;
+
+/* Get a free slot */
+static ssize_t allocate_hash_operation_slot(void)
+{
+    psasim_client_handle_t handle = next_hash_operation_handle++;
+    if (next_hash_operation_handle == 0) {      /* wrapped around */
+        FATAL("Hash operation handle wrapped");
+    }
+
+    for (ssize_t i = 0; i < MAX_LIVE_HANDLES_PER_CLASS; i++) {
+        if (hash_operation_handles[i] == 0) {
+            hash_operation_handles[i] = handle;
+            return i;
+        }
+    }
+
+    ERROR("All slots are currently used. Unable to allocate a new one.");
+
+    return -1;  /* all in use */
+}
+
+/* Find the slot given the handle */
+static ssize_t find_hash_slot_by_handle(psasim_client_handle_t handle)
+{
+    for (ssize_t i = 0; i < MAX_LIVE_HANDLES_PER_CLASS; i++) {
+        if (hash_operation_handles[i] == handle) {
+            return i;
+        }
+    }
+
+    ERROR("Unable to find slot by handle %u", handle);
+
+    return -1;  /* not found */
+}
+
+static psa_aead_operation_t aead_operations[MAX_LIVE_HANDLES_PER_CLASS];
+static psasim_client_handle_t aead_operation_handles[MAX_LIVE_HANDLES_PER_CLASS];
+static psasim_client_handle_t next_aead_operation_handle = 1;
+
+/* Get a free slot */
+static ssize_t allocate_aead_operation_slot(void)
+{
+    psasim_client_handle_t handle = next_aead_operation_handle++;
+    if (next_aead_operation_handle == 0) {      /* wrapped around */
+        FATAL("Aead operation handle wrapped");
+    }
+
+    for (ssize_t i = 0; i < MAX_LIVE_HANDLES_PER_CLASS; i++) {
+        if (aead_operation_handles[i] == 0) {
+            aead_operation_handles[i] = handle;
+            return i;
+        }
+    }
+
+    ERROR("All slots are currently used. Unable to allocate a new one.");
+
+    return -1;  /* all in use */
+}
+
+/* Find the slot given the handle */
+static ssize_t find_aead_slot_by_handle(psasim_client_handle_t handle)
+{
+    for (ssize_t i = 0; i < MAX_LIVE_HANDLES_PER_CLASS; i++) {
+        if (aead_operation_handles[i] == handle) {
+            return i;
+        }
+    }
+
+    ERROR("Unable to find slot by handle %u", handle);
+
+    return -1;  /* not found */
+}
+
 size_t psasim_serialise_begin_needs(void)
 {
     /* The serialisation buffer will
@@ -404,3 +492,232 @@
 
     return 1;
 }
+
+size_t psasim_server_serialise_psa_hash_operation_t_needs(psa_hash_operation_t *operation)
+{
+    (void) operation;
+
+    /* We will actually return a handle */
+    return sizeof(psasim_operation_t);
+}
+
+int psasim_server_serialise_psa_hash_operation_t(uint8_t **pos,
+                                                 size_t *remaining,
+                                                 psa_hash_operation_t *operation)
+{
+    psasim_operation_t client_operation;
+
+    if (*remaining < sizeof(client_operation)) {
+        return 0;
+    }
+
+    ssize_t slot = operation - hash_operations;
+
+    client_operation.handle = hash_operation_handles[slot];
+
+    memcpy(*pos, &client_operation, sizeof(client_operation));
+    *pos += sizeof(client_operation);
+
+    return 1;
+}
+
+int psasim_server_deserialise_psa_hash_operation_t(uint8_t **pos,
+                                                   size_t *remaining,
+                                                   psa_hash_operation_t **operation)
+{
+    psasim_operation_t client_operation;
+
+    if (*remaining < sizeof(psasim_operation_t)) {
+        return 0;
+    }
+
+    memcpy(&client_operation, *pos, sizeof(psasim_operation_t));
+    *pos += sizeof(psasim_operation_t);
+    *remaining -= sizeof(psasim_operation_t);
+
+    ssize_t slot;
+    if (client_operation.handle == 0) {         /* We need a new handle */
+        slot = allocate_hash_operation_slot();
+    } else {
+        slot = find_hash_slot_by_handle(client_operation.handle);
+    }
+
+    if (slot < 0) {
+        return 0;
+    }
+
+    *operation = &hash_operations[slot];
+
+    return 1;
+}
+
+size_t psasim_serialise_psa_aead_operation_t_needs(psa_aead_operation_t value)
+{
+    return sizeof(value);
+}
+
+int psasim_serialise_psa_aead_operation_t(uint8_t **pos,
+                                          size_t *remaining,
+                                          psa_aead_operation_t value)
+{
+    if (*remaining < sizeof(value)) {
+        return 0;
+    }
+
+    memcpy(*pos, &value, sizeof(value));
+    *pos += sizeof(value);
+
+    return 1;
+}
+
+int psasim_deserialise_psa_aead_operation_t(uint8_t **pos,
+                                            size_t *remaining,
+                                            psa_aead_operation_t *value)
+{
+    if (*remaining < sizeof(*value)) {
+        return 0;
+    }
+
+    memcpy(value, *pos, sizeof(*value));
+
+    *pos += sizeof(*value);
+    *remaining -= sizeof(*value);
+
+    return 1;
+}
+
+size_t psasim_server_serialise_psa_aead_operation_t_needs(psa_aead_operation_t *operation)
+{
+    (void) operation;
+
+    /* We will actually return a handle */
+    return sizeof(psasim_operation_t);
+}
+
+int psasim_server_serialise_psa_aead_operation_t(uint8_t **pos,
+                                                 size_t *remaining,
+                                                 psa_aead_operation_t *operation)
+{
+    psasim_operation_t client_operation;
+
+    if (*remaining < sizeof(client_operation)) {
+        return 0;
+    }
+
+    ssize_t slot = operation - aead_operations;
+
+    client_operation.handle = aead_operation_handles[slot];
+
+    memcpy(*pos, &client_operation, sizeof(client_operation));
+    *pos += sizeof(client_operation);
+
+    return 1;
+}
+
+int psasim_server_deserialise_psa_aead_operation_t(uint8_t **pos,
+                                                   size_t *remaining,
+                                                   psa_aead_operation_t **operation)
+{
+    psasim_operation_t client_operation;
+
+    if (*remaining < sizeof(psasim_operation_t)) {
+        return 0;
+    }
+
+    memcpy(&client_operation, *pos, sizeof(psasim_operation_t));
+    *pos += sizeof(psasim_operation_t);
+    *remaining -= sizeof(psasim_operation_t);
+
+    ssize_t slot;
+    if (client_operation.handle == 0) {         /* We need a new handle */
+        slot = allocate_aead_operation_slot();
+    } else {
+        slot = find_aead_slot_by_handle(client_operation.handle);
+    }
+
+    if (slot < 0) {
+        return 0;
+    }
+
+    *operation = &aead_operations[slot];
+
+    return 1;
+}
+
+size_t psasim_serialise_psa_key_attributes_t_needs(psa_key_attributes_t value)
+{
+    return sizeof(value);
+}
+
+int psasim_serialise_psa_key_attributes_t(uint8_t **pos,
+                                          size_t *remaining,
+                                          psa_key_attributes_t value)
+{
+    if (*remaining < sizeof(value)) {
+        return 0;
+    }
+
+    memcpy(*pos, &value, sizeof(value));
+    *pos += sizeof(value);
+
+    return 1;
+}
+
+int psasim_deserialise_psa_key_attributes_t(uint8_t **pos,
+                                            size_t *remaining,
+                                            psa_key_attributes_t *value)
+{
+    if (*remaining < sizeof(*value)) {
+        return 0;
+    }
+
+    memcpy(value, *pos, sizeof(*value));
+
+    *pos += sizeof(*value);
+    *remaining -= sizeof(*value);
+
+    return 1;
+}
+
+size_t psasim_serialise_mbedtls_svc_key_id_t_needs(mbedtls_svc_key_id_t value)
+{
+    return sizeof(value);
+}
+
+int psasim_serialise_mbedtls_svc_key_id_t(uint8_t **pos,
+                                          size_t *remaining,
+                                          mbedtls_svc_key_id_t value)
+{
+    if (*remaining < sizeof(value)) {
+        return 0;
+    }
+
+    memcpy(*pos, &value, sizeof(value));
+    *pos += sizeof(value);
+
+    return 1;
+}
+
+int psasim_deserialise_mbedtls_svc_key_id_t(uint8_t **pos,
+                                            size_t *remaining,
+                                            mbedtls_svc_key_id_t *value)
+{
+    if (*remaining < sizeof(*value)) {
+        return 0;
+    }
+
+    memcpy(value, *pos, sizeof(*value));
+
+    *pos += sizeof(*value);
+    *remaining -= sizeof(*value);
+
+    return 1;
+}
+
+void psa_sim_serialize_reset(void)
+{
+    memset(hash_operation_handles, 0, sizeof(hash_operation_handles));
+    memset(hash_operations, 0, sizeof(hash_operations));
+    memset(aead_operation_handles, 0, sizeof(aead_operation_handles));
+    memset(aead_operations, 0, sizeof(aead_operations));
+}
diff --git a/tests/psa-client-server/psasim/src/psa_sim_serialise.h b/tests/psa-client-server/psasim/src/psa_sim_serialise.h
index d5eaccf..537730c 100644
--- a/tests/psa-client-server/psasim/src/psa_sim_serialise.h
+++ b/tests/psa-client-server/psasim/src/psa_sim_serialise.h
@@ -54,6 +54,12 @@
  * don't contain pointers.
  */
 
+/** Reset all operation slots.
+ *
+ * Should be called when all clients have disconnected.
+ */
+void psa_sim_serialize_reset(void);
+
 /** Return how much buffer space is needed by \c psasim_serialise_begin().
  *
  * \return                   The number of bytes needed in the buffer for
@@ -408,3 +414,213 @@
 int psasim_deserialise_psa_hash_operation_t(uint8_t **pos,
                                             size_t *remaining,
                                             psa_hash_operation_t *value);
+
+/** Return how much buffer space is needed by \c psasim_server_serialise_psa_hash_operation_t()
+ *  to serialise a `psa_hash_operation_t`.
+ *
+ * \param value              The value that will be serialised into the buffer
+ *                           (needed in case some serialisations are value-
+ *                           dependent).
+ *
+ * \return                   The number of bytes needed in the buffer by
+ *                           \c psasim_serialise_psa_hash_operation_t() to serialise
+ *                           the given value.
+ */
+size_t psasim_server_serialise_psa_hash_operation_t_needs(psa_hash_operation_t *value);
+
+/** Serialise a `psa_hash_operation_t` into a buffer on the server side.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \param value              The value to serialise into the buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_server_serialise_psa_hash_operation_t(uint8_t **pos,
+                                                 size_t *remaining,
+                                                 psa_hash_operation_t *value);
+
+/** Deserialise a `psa_hash_operation_t` from a buffer on the server side.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \param value              Pointer to a `psa_hash_operation_t` to receive the value
+ *                           deserialised from the buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_server_deserialise_psa_hash_operation_t(uint8_t **pos,
+                                                   size_t *remaining,
+                                                   psa_hash_operation_t **value);
+
+/** Return how much buffer space is needed by \c psasim_serialise_psa_aead_operation_t()
+ *  to serialise a `psa_aead_operation_t`.
+ *
+ * \param value              The value that will be serialised into the buffer
+ *                           (needed in case some serialisations are value-
+ *                           dependent).
+ *
+ * \return                   The number of bytes needed in the buffer by
+ *                           \c psasim_serialise_psa_aead_operation_t() to serialise
+ *                           the given value.
+ */
+size_t psasim_serialise_psa_aead_operation_t_needs(psa_aead_operation_t value);
+
+/** Serialise a `psa_aead_operation_t` into a buffer.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \param value              The value to serialise into the buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_serialise_psa_aead_operation_t(uint8_t **pos,
+                                          size_t *remaining,
+                                          psa_aead_operation_t value);
+
+/** Deserialise a `psa_aead_operation_t` from a buffer.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \param value              Pointer to a `psa_aead_operation_t` to receive the value
+ *                           deserialised from the buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_deserialise_psa_aead_operation_t(uint8_t **pos,
+                                            size_t *remaining,
+                                            psa_aead_operation_t *value);
+
+/** Return how much buffer space is needed by \c psasim_server_serialise_psa_aead_operation_t()
+ *  to serialise a `psa_aead_operation_t`.
+ *
+ * \param value              The value that will be serialised into the buffer
+ *                           (needed in case some serialisations are value-
+ *                           dependent).
+ *
+ * \return                   The number of bytes needed in the buffer by
+ *                           \c psasim_serialise_psa_aead_operation_t() to serialise
+ *                           the given value.
+ */
+size_t psasim_server_serialise_psa_aead_operation_t_needs(psa_aead_operation_t *value);
+
+/** Serialise a `psa_aead_operation_t` into a buffer on the server side.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \param value              The value to serialise into the buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_server_serialise_psa_aead_operation_t(uint8_t **pos,
+                                                 size_t *remaining,
+                                                 psa_aead_operation_t *value);
+
+/** Deserialise a `psa_aead_operation_t` from a buffer on the server side.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \param value              Pointer to a `psa_aead_operation_t` to receive the value
+ *                           deserialised from the buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_server_deserialise_psa_aead_operation_t(uint8_t **pos,
+                                                   size_t *remaining,
+                                                   psa_aead_operation_t **value);
+
+/** Return how much buffer space is needed by \c psasim_serialise_psa_key_attributes_t()
+ *  to serialise a `psa_key_attributes_t`.
+ *
+ * \param value              The value that will be serialised into the buffer
+ *                           (needed in case some serialisations are value-
+ *                           dependent).
+ *
+ * \return                   The number of bytes needed in the buffer by
+ *                           \c psasim_serialise_psa_key_attributes_t() to serialise
+ *                           the given value.
+ */
+size_t psasim_serialise_psa_key_attributes_t_needs(psa_key_attributes_t value);
+
+/** Serialise a `psa_key_attributes_t` into a buffer.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \param value              The value to serialise into the buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_serialise_psa_key_attributes_t(uint8_t **pos,
+                                          size_t *remaining,
+                                          psa_key_attributes_t value);
+
+/** Deserialise a `psa_key_attributes_t` from a buffer.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \param value              Pointer to a `psa_key_attributes_t` to receive the value
+ *                           deserialised from the buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_deserialise_psa_key_attributes_t(uint8_t **pos,
+                                            size_t *remaining,
+                                            psa_key_attributes_t *value);
+
+/** Return how much buffer space is needed by \c psasim_serialise_mbedtls_svc_key_id_t()
+ *  to serialise a `mbedtls_svc_key_id_t`.
+ *
+ * \param value              The value that will be serialised into the buffer
+ *                           (needed in case some serialisations are value-
+ *                           dependent).
+ *
+ * \return                   The number of bytes needed in the buffer by
+ *                           \c psasim_serialise_mbedtls_svc_key_id_t() to serialise
+ *                           the given value.
+ */
+size_t psasim_serialise_mbedtls_svc_key_id_t_needs(mbedtls_svc_key_id_t value);
+
+/** Serialise a `mbedtls_svc_key_id_t` into a buffer.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \param value              The value to serialise into the buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_serialise_mbedtls_svc_key_id_t(uint8_t **pos,
+                                          size_t *remaining,
+                                          mbedtls_svc_key_id_t value);
+
+/** Deserialise a `mbedtls_svc_key_id_t` from a buffer.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \param value              Pointer to a `mbedtls_svc_key_id_t` to receive the value
+ *                           deserialised from the buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_deserialise_mbedtls_svc_key_id_t(uint8_t **pos,
+                                            size_t *remaining,
+                                            mbedtls_svc_key_id_t *value);
diff --git a/tests/psa-client-server/psasim/src/psa_sim_serialise.pl b/tests/psa-client-server/psasim/src/psa_sim_serialise.pl
index 5161db1..e89fafe 100755
--- a/tests/psa-client-server/psasim/src/psa_sim_serialise.pl
+++ b/tests/psa-client-server/psasim/src/psa_sim_serialise.pl
@@ -38,7 +38,11 @@
 my @types = qw(unsigned-int int size_t
                buffer
                psa_status_t psa_algorithm_t
-               psa_hash_operation_t);
+               psa_hash_operation_t
+               psa_aead_operation_t
+               psa_key_attributes_t
+               mbedtls_svc_key_id_t);
+
 grep(s/-/ /g, @types);
 
 # IS-A: Some data types are typedef'd; we serialise them as the other type
@@ -55,15 +59,31 @@
         if ($type eq "buffer") {
             print declare_buffer_functions();
         } else {
-            print declare_needs($type);
-            print declare_serialise($type);
-            print declare_deserialise($type);
+            print declare_needs($type, "");
+            print declare_serialise($type, "");
+            print declare_deserialise($type, "");
+
+            if ($type =~ /^psa_\w+_operation_t$/) {
+                print declare_needs($type, "server_");
+                print declare_serialise($type, "server_");
+                print declare_deserialise($type, "server_");
+            }
         }
     }
 
 } elsif ($which eq "c") {
 
+    my $have_operation_types = (grep(/psa_\w+_operation_t/, @types)) ? 1 : 0;
+
     print c_header();
+    print c_define_types_for_operation_types() if $have_operation_types;
+
+    for my $type (@types) {
+        next unless $type =~ /^psa_(\w+)_operation_t$/;
+        print define_operation_type_data_and_functions($1);
+    }
+
+    print c_define_begins();
 
     for my $type (@types) {
         if ($type eq "buffer") {
@@ -76,24 +96,33 @@
             print define_needs($type);
             print define_serialise($type);
             print define_deserialise($type);
+
+            if ($type =~ /^psa_\w+_operation_t$/) {
+                print define_server_needs($type);
+                print define_server_serialise($type);
+                print define_server_deserialise($type);
+            }
         }
     }
 
+    print define_server_serialize_reset(@types);
 } else {
     die("internal error - shouldn't happen");
 }
 
 sub declare_needs
 {
-    my ($type) = @_;
+    my ($type, $server) = @_;
 
     my $an = ($type =~ /^[ui]/) ? "an" : "a";
     my $type_d = $type;
     $type_d =~ s/ /_/g;
 
+    my $ptr = (length($server)) ? "*" : "";
+
     return <<EOF;
 
-/** Return how much buffer space is needed by \\c psasim_serialise_$type_d()
+/** Return how much buffer space is needed by \\c psasim_${server}serialise_$type_d()
  *  to serialise $an `$type`.
  *
  * \\param value              The value that will be serialised into the buffer
@@ -104,21 +133,25 @@
  *                           \\c psasim_serialise_$type_d() to serialise
  *                           the given value.
  */
-size_t psasim_serialise_${type_d}_needs($type value);
+size_t psasim_${server}serialise_${type_d}_needs($type ${ptr}value);
 EOF
 }
 
 sub declare_serialise
 {
-    my ($type) = @_;
+    my ($type, $server) = @_;
 
     my $an = ($type =~ /^[ui]/) ? "an" : "a";
     my $type_d = $type;
     $type_d =~ s/ /_/g;
 
+    my $server_side = (length($server)) ? " on the server side" : "";
+
+    my $ptr = (length($server)) ? "*" : "";
+
     return align_declaration(<<EOF);
 
-/** Serialise $an `$type` into a buffer.
+/** Serialise $an `$type` into a buffer${server_side}.
  *
  * \\param pos[in,out]        Pointer to a `uint8_t *` holding current position
  *                           in the buffer.
@@ -128,23 +161,27 @@
  *
  * \\return                   \\c 1 on success ("okay"), \\c 0 on error.
  */
-int psasim_serialise_$type_d(uint8_t **pos,
+int psasim_${server}serialise_$type_d(uint8_t **pos,
                              size_t *remaining,
-                             $type value);
+                             $type ${ptr}value);
 EOF
 }
 
 sub declare_deserialise
 {
-    my ($type) = @_;
+    my ($type, $server) = @_;
 
     my $an = ($type =~ /^[ui]/) ? "an" : "a";
     my $type_d = $type;
     $type_d =~ s/ /_/g;
 
+    my $server_side = (length($server)) ? " on the server side" : "";
+
+    my $ptr = (length($server)) ? "*" : "";
+
     return align_declaration(<<EOF);
 
-/** Deserialise $an `$type` from a buffer.
+/** Deserialise $an `$type` from a buffer${server_side}.
  *
  * \\param pos[in,out]        Pointer to a `uint8_t *` holding current position
  *                           in the buffer.
@@ -155,9 +192,9 @@
  *
  * \\return                   \\c 1 on success ("okay"), \\c 0 on error.
  */
-int psasim_deserialise_$type_d(uint8_t **pos,
+int psasim_${server}deserialise_$type_d(uint8_t **pos,
                                size_t *remaining,
-                               $type *value);
+                               $type ${ptr}*value);
 EOF
 }
 
@@ -293,6 +330,12 @@
  * don't contain pointers.
  */
 
+/** Reset all operation slots.
+ *
+ * Should be called when all clients have disconnected.
+ */
+void psa_sim_serialize_reset(void);
+
 /** Return how much buffer space is needed by \c psasim_serialise_begin().
  *
  * \return                   The number of bytes needed in the buffer for
@@ -347,6 +390,25 @@
 EOF
 }
 
+sub define_server_needs
+{
+    my ($type) = @_;
+
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    return <<EOF;
+
+size_t psasim_server_serialise_${type_d}_needs($type *operation)
+{
+    (void) operation;
+
+    /* We will actually return a handle */
+    return sizeof(psasim_operation_t);
+}
+EOF
+}
+
 sub define_needs_isa
 {
     my ($type, $isa) = @_;
@@ -391,6 +453,44 @@
 EOF
 }
 
+sub define_server_serialise
+{
+    my ($type) = @_;
+
+    my $t;
+    if ($type =~ /^psa_(\w+)_operation_t$/) {
+        $t = $1;
+    } else {
+        die("$0: define_server_serialise: $type: not supported\n");
+    }
+
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    return align_signature(<<EOF);
+
+int psasim_server_serialise_$type_d(uint8_t **pos,
+                             size_t *remaining,
+                             $type *operation)
+{
+    psasim_operation_t client_operation;
+
+    if (*remaining < sizeof(client_operation)) {
+        return 0;
+    }
+
+    ssize_t slot = operation - ${t}_operations;
+
+    client_operation.handle = ${t}_operation_handles[slot];
+
+    memcpy(*pos, &client_operation, sizeof(client_operation));
+    *pos += sizeof(client_operation);
+
+    return 1;
+}
+EOF
+}
+
 sub define_serialise_isa
 {
     my ($type, $isa) = @_;
@@ -439,6 +539,54 @@
 EOF
 }
 
+sub define_server_deserialise
+{
+    my ($type) = @_;
+
+    my $t;
+    if ($type =~ /^psa_(\w+)_operation_t$/) {
+        $t = $1;
+    } else {
+        die("$0: define_server_serialise: $type: not supported\n");
+    }
+
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    return align_signature(<<EOF);
+
+int psasim_server_deserialise_$type_d(uint8_t **pos,
+                               size_t *remaining,
+                               $type **operation)
+{
+    psasim_operation_t client_operation;
+
+    if (*remaining < sizeof(psasim_operation_t)) {
+        return 0;
+    }
+
+    memcpy(&client_operation, *pos, sizeof(psasim_operation_t));
+    *pos += sizeof(psasim_operation_t);
+    *remaining -= sizeof(psasim_operation_t);
+
+    ssize_t slot;
+    if (client_operation.handle == 0) {         /* We need a new handle */
+        slot = allocate_${t}_operation_slot();
+    } else {
+        slot = find_${t}_slot_by_handle(client_operation.handle);
+    }
+
+    if (slot < 0) {
+        return 0;
+    }
+
+    *operation = &${t}_operations[slot];
+
+    return 1;
+}
+EOF
+}
+
 sub define_deserialise_isa
 {
     my ($type, $isa) = @_;
@@ -583,6 +731,7 @@
  */
 
 #include "psa_sim_serialise.h"
+#include "util.h"
 #include <stdlib.h>
 #include <string.h>
 
@@ -623,6 +772,77 @@
  * data types (e.g. int), types typedef'd to those, and even structures that
  * don't contain pointers.
  */
+EOF
+}
+
+sub c_define_types_for_operation_types
+{
+    return <<'EOF';
+
+/* include/psa/crypto_platform.h:typedef uint32_t mbedtls_psa_client_handle_t;
+ * but we don't get it on server builds, so redefine it here with a unique type name
+ */
+typedef uint32_t psasim_client_handle_t;
+
+typedef struct psasim_operation_s {
+    psasim_client_handle_t handle;
+} psasim_operation_t;
+
+#define MAX_LIVE_HANDLES_PER_CLASS   100        /* this many slots */
+EOF
+}
+
+sub define_operation_type_data_and_functions
+{
+    my ($type) = @_;    # e.g. 'hash' rather than 'psa_hash_operation_t'
+
+    my $utype = ucfirst($type);
+
+    return <<EOF;
+
+static psa_${type}_operation_t ${type}_operations[MAX_LIVE_HANDLES_PER_CLASS];
+static psasim_client_handle_t ${type}_operation_handles[MAX_LIVE_HANDLES_PER_CLASS];
+static psasim_client_handle_t next_${type}_operation_handle = 1;
+
+/* Get a free slot */
+static ssize_t allocate_${type}_operation_slot(void)
+{
+    psasim_client_handle_t handle = next_${type}_operation_handle++;
+    if (next_${type}_operation_handle == 0) {      /* wrapped around */
+        FATAL("$utype operation handle wrapped");
+    }
+
+    for (ssize_t i = 0; i < MAX_LIVE_HANDLES_PER_CLASS; i++) {
+        if (${type}_operation_handles[i] == 0) {
+            ${type}_operation_handles[i] = handle;
+            return i;
+        }
+    }
+
+    ERROR("All slots are currently used. Unable to allocate a new one.");
+
+    return -1;  /* all in use */
+}
+
+/* Find the slot given the handle */
+static ssize_t find_${type}_slot_by_handle(psasim_client_handle_t handle)
+{
+    for (ssize_t i = 0; i < MAX_LIVE_HANDLES_PER_CLASS; i++) {
+        if (${type}_operation_handles[i] == handle) {
+            return i;
+        }
+    }
+
+    ERROR("Unable to find slot by handle %u", handle);
+
+    return -1;  /* not found */
+}
+EOF
+}
+
+sub c_define_begins
+{
+    return <<'EOF';
 
 size_t psasim_serialise_begin_needs(void)
 {
@@ -700,6 +920,33 @@
 EOF
 }
 
+# Return the code for psa_sim_serialize_reset()
+sub define_server_serialize_reset
+{
+    my @types = @_;
+
+    my $code = <<EOF;
+
+void psa_sim_serialize_reset(void)
+{
+EOF
+
+    for my $type (@types) {
+        next unless $type =~ /^psa_(\w+_operation)_t$/;
+
+        my $what = $1;  # e.g. "hash_operation"
+
+        $code .= <<EOF;
+    memset(${what}_handles, 0, sizeof(${what}_handles));
+    memset(${what}s, 0, sizeof(${what}s));
+EOF
+    }
+
+    $code .= <<EOF;
+}
+EOF
+}
+
 # Horrible way to align first, second and third lines of function signature to
 # appease uncrustify (these are the 2nd-4th lines of code, indices 1, 2 and 3)
 #
diff --git a/tests/psa-client-server/psasim/src/server.c b/tests/psa-client-server/psasim/src/server.c
index 77ce269..10ab5a2 100644
--- a/tests/psa-client-server/psasim/src/server.c
+++ b/tests/psa-client-server/psasim/src/server.c
@@ -54,6 +54,7 @@
     int client_disconnected = 0;
     char mbedtls_version[18];
     extern psa_status_t psa_crypto_call(psa_msg_t msg);
+    extern psa_status_t psa_crypto_close(void);
 
     mbedtls_version_get_string_full(mbedtls_version);
     SERVER_PRINT("%s", mbedtls_version);
@@ -81,6 +82,7 @@
                         SERVER_PRINT("Got a disconnection message");
                         ret = PSA_SUCCESS;
                         client_disconnected = 1;
+                        psa_crypto_close();
                         break;
                     default:
                         SERVER_PRINT("Got an IPC call of type %d", msg.type);
diff --git a/tests/psa-client-server/psasim/test/run_test.sh b/tests/psa-client-server/psasim/test/run_test.sh
index 31429c8..45a317a 100755
--- a/tests/psa-client-server/psasim/test/run_test.sh
+++ b/tests/psa-client-server/psasim/test/run_test.sh
@@ -33,5 +33,5 @@
 ./psa_partition -k &
 SERV_PID=$!
 wait_for_server_startup
-./psa_client
+./psa_client "$@"
 wait $SERV_PID
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 06ccc73..93054e5 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -133,10 +133,11 @@
 pre_initialize_variables () {
     if in_mbedtls_repo; then
         CONFIG_H='include/mbedtls/mbedtls_config.h'
+        CRYPTO_CONFIG_H='tf-psa-crypto/include/psa/crypto_config.h'
     else
         CONFIG_H='drivers/builtin/include/mbedtls/mbedtls_config.h'
+        CRYPTO_CONFIG_H='include/psa/crypto_config.h'
     fi
-    CRYPTO_CONFIG_H='include/psa/crypto_config.h'
     CONFIG_TEST_DRIVER_H='tests/include/test/drivers/config_test_driver.h'
 
     # Files that are clobbered by some jobs will be backed up. Use a different
@@ -327,8 +328,10 @@
               -iname CTestTestfile.cmake -o \
               -iname CMakeCache.txt -o \
               -path './cmake/*.cmake' \) -exec rm -f {} \+
-    # Recover files overwritten by in-tree CMake builds
-    rm -f include/Makefile include/mbedtls/Makefile programs/!(fuzz)/Makefile
+    # Remove Makefiles generated by in-tree CMake builds
+    rm -f 3rdparty/Makefile 3rdparty/*/Makefile pkgconfig/Makefile framework/Makefile
+    rm -f include/Makefile programs/!(fuzz)/Makefile
+    rm -f tf-psa-crypto/Makefile tf-psa-crypto/include/Makefile
 
     # Remove any artifacts from the component_test_cmake_as_subdirectory test.
     rm -rf programs/test/cmake_subproject/build
@@ -964,18 +967,17 @@
         scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
         scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
         scripts/config.py unset MBEDTLS_ECP_RESTARTABLE
+        scripts/config.py unset MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
     else
         scripts/config.py crypto_full
         scripts/config.py unset MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS
-        scripts/config.py set MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+        # We need to match the client with MBEDTLS_PSA_CRYPTO_SE_C
+        scripts/config.py unset MBEDTLS_PSA_CRYPTO_SE_C
+        # Also ensure MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER not set (to match client)
+        scripts/config.py unset MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
     fi
 
     make -C tests/psa-client-server/psasim/ CFLAGS="$ASAN_CFLAGS" LDFLAGS="$ASAN_CFLAGS" $TARGET_LIB "$@"
-
-    # cleanup() will restore some backed-up files which include $CONFIG_H and
-    # $CRYPTO_CONFIG_H. Built libraries were already copied to psasim at this
-    # point.
-    cleanup
 }
 
 ################################################################
@@ -1687,7 +1689,7 @@
 component_test_crypto_full_md_light_only () {
     msg "build: crypto_full with only the light subset of MD"
     scripts/config.py crypto_full
-    scripts/config.py unset MBEDTLS_PSA_CRYPTO_CONFIG
+
     # Disable MD
     scripts/config.py unset MBEDTLS_MD_C
     # Disable direct dependencies of MD_C
@@ -1696,6 +1698,7 @@
     scripts/config.py unset MBEDTLS_PKCS7_C
     # Disable indirect dependencies of MD_C
     scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # needs HMAC_DRBG
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_DETERMINISTIC_ECDSA
     # Disable things that would auto-enable MD_C
     scripts/config.py unset MBEDTLS_PKCS5_C
 
@@ -1711,69 +1714,28 @@
     make test
 }
 
-component_test_full_no_cipher_no_psa_crypto () {
-    msg "build: full no CIPHER no PSA_CRYPTO_C"
-    scripts/config.py full
-    scripts/config.py unset MBEDTLS_CIPHER_C
-    # Don't pull in cipher via PSA mechanisms
-    # (currently ignored anyway because we completely disable PSA)
-    scripts/config.py unset MBEDTLS_PSA_CRYPTO_CONFIG
-    # Disable features that depend on CIPHER_C
-    scripts/config.py unset MBEDTLS_CMAC_C
-    scripts/config.py unset MBEDTLS_NIST_KW_C
-    scripts/config.py unset MBEDTLS_PSA_CRYPTO_C
-    scripts/config.py unset MBEDTLS_PSA_CRYPTO_CLIENT
-    scripts/config.py unset MBEDTLS_SSL_TLS_C
-    scripts/config.py unset MBEDTLS_SSL_TICKET_C
-    # Disable features that depend on PSA_CRYPTO_C
-    scripts/config.py unset MBEDTLS_PSA_CRYPTO_SE_C
-    scripts/config.py unset MBEDTLS_PSA_CRYPTO_STORAGE_C
-    scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
-    scripts/config.py unset MBEDTLS_LMS_C
-    scripts/config.py unset MBEDTLS_LMS_PRIVATE
-
-    msg "test: full no CIPHER no PSA_CRYPTO_C"
-    make test
-}
-
-# This is a common configurator and test function that is used in:
-# - component_test_full_no_cipher_with_psa_crypto
-# - component_test_full_no_cipher_with_psa_crypto_config
-# It accepts 2 input parameters:
-# - $1: boolean value which basically reflects status of MBEDTLS_PSA_CRYPTO_CONFIG
-# - $2: a text string which describes the test component
-common_test_full_no_cipher_with_psa_crypto () {
-    USE_CRYPTO_CONFIG="$1"
-    COMPONENT_DESCRIPTION="$2"
-
-    msg "build: $COMPONENT_DESCRIPTION"
+component_test_full_no_cipher () {
+    msg "build: full no CIPHER"
 
     scripts/config.py full
     scripts/config.py unset MBEDTLS_CIPHER_C
 
-    if [ "$USE_CRYPTO_CONFIG" -eq 1 ]; then
-        # The built-in implementation of the following algs/key-types depends
-        # on CIPHER_C so we disable them.
-        # This does not hold for KEY_TYPE_CHACHA20 and ALG_CHACHA20_POLY1305
-        # so we keep them enabled.
-        scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CCM_STAR_NO_TAG
-        scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CMAC
-        scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CBC_NO_PADDING
-        scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CBC_PKCS7
-        scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CFB
-        scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CTR
-        scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_ECB_NO_PADDING
-        scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_OFB
-        scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128
-        scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_STREAM_CIPHER
-        scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_KEY_TYPE_DES
-    else
-        # Don't pull in cipher via PSA mechanisms
-        scripts/config.py unset MBEDTLS_PSA_CRYPTO_CONFIG
-        # Disable cipher modes/keys that make PSA depend on CIPHER_C.
-        # Keep CHACHA20 and CHACHAPOLY enabled since they do not depend on CIPHER_C.
-        scripts/config.py unset-all MBEDTLS_CIPHER_MODE
-    fi
+    # The built-in implementation of the following algs/key-types depends
+    # on CIPHER_C so we disable them.
+    # This does not hold for KEY_TYPE_CHACHA20 and ALG_CHACHA20_POLY1305
+    # so we keep them enabled.
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CCM_STAR_NO_TAG
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CMAC
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CBC_NO_PADDING
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CBC_PKCS7
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CFB
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_CTR
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_ECB_NO_PADDING
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_OFB
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_ALG_STREAM_CIPHER
+    scripts/config.py -f $CRYPTO_CONFIG_H unset PSA_WANT_KEY_TYPE_DES
+
     # The following modules directly depends on CIPHER_C
     scripts/config.py unset MBEDTLS_CMAC_C
     scripts/config.py unset MBEDTLS_NIST_KW_C
@@ -1783,18 +1745,10 @@
     # Ensure that CIPHER_C was not re-enabled
     not grep mbedtls_cipher_init library/cipher.o
 
-    msg "test: $COMPONENT_DESCRIPTION"
+    msg "test: full no CIPHER"
     make test
 }
 
-component_test_full_no_cipher_with_psa_crypto() {
-    common_test_full_no_cipher_with_psa_crypto 0 "full no CIPHER no CRYPTO_CONFIG"
-}
-
-component_test_full_no_cipher_with_psa_crypto_config() {
-    common_test_full_no_cipher_with_psa_crypto 1 "full no CIPHER"
-}
-
 component_test_full_no_ccm() {
     msg "build: full no PSA_WANT_ALG_CCM"
 
@@ -1848,60 +1802,6 @@
     make test
 }
 
-component_test_full_no_bignum () {
-    msg "build: full minus bignum"
-    scripts/config.py full
-    scripts/config.py unset MBEDTLS_BIGNUM_C
-    # Direct dependencies of bignum
-    scripts/config.py unset MBEDTLS_ECP_C
-    scripts/config.py unset MBEDTLS_RSA_C
-    scripts/config.py unset MBEDTLS_DHM_C
-    # Direct dependencies of ECP
-    scripts/config.py unset MBEDTLS_ECDH_C
-    scripts/config.py unset MBEDTLS_ECDSA_C
-    scripts/config.py unset MBEDTLS_ECJPAKE_C
-    scripts/config.py unset MBEDTLS_ECP_RESTARTABLE
-    # Disable what auto-enables ECP_LIGHT
-    scripts/config.py unset MBEDTLS_PK_PARSE_EC_EXTENDED
-    scripts/config.py unset MBEDTLS_PK_PARSE_EC_COMPRESSED
-    # Indirect dependencies of ECP
-    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
-    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
-    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
-    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
-    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
-    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
-    scripts/config.py unset MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
-    scripts/config.py unset MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
-    # Direct dependencies of DHM
-    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED
-    # Direct dependencies of RSA
-    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
-    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED
-    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
-    scripts/config.py unset MBEDTLS_X509_RSASSA_PSS_SUPPORT
-    # PK and its dependencies
-    scripts/config.py unset MBEDTLS_PK_C
-    scripts/config.py unset MBEDTLS_PK_PARSE_C
-    scripts/config.py unset MBEDTLS_PK_WRITE_C
-    scripts/config.py unset MBEDTLS_X509_USE_C
-    scripts/config.py unset MBEDTLS_X509_CRT_PARSE_C
-    scripts/config.py unset MBEDTLS_X509_CRL_PARSE_C
-    scripts/config.py unset MBEDTLS_X509_CSR_PARSE_C
-    scripts/config.py unset MBEDTLS_X509_CREATE_C
-    scripts/config.py unset MBEDTLS_X509_CRT_WRITE_C
-    scripts/config.py unset MBEDTLS_X509_CSR_WRITE_C
-    scripts/config.py unset MBEDTLS_PKCS7_C
-    scripts/config.py unset MBEDTLS_SSL_SERVER_NAME_INDICATION
-    scripts/config.py unset MBEDTLS_SSL_ASYNC_PRIVATE
-    scripts/config.py unset MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK
-
-    make
-
-    msg "test: full minus bignum"
-    make test
-}
-
 component_test_tls1_2_default_stream_cipher_only () {
     msg "build: default with only stream cipher use psa"
 
@@ -3225,7 +3125,7 @@
     if [ "$test_target" = "ECC" ]; then
         # When testing ECC only, we disable FFDH support, both from builtin and
         # PSA sides, and also disable the key exchanges that depend on DHM.
-        scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_FFDH
+        scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_FFDH
         scripts/config.py -f "$CRYPTO_CONFIG_H" unset-all "PSA_WANT_KEY_TYPE_DH_[0-9A-Z_a-z]*"
         scripts/config.py -f "$CRYPTO_CONFIG_H" unset-all "PSA_WANT_DH_RFC7919_[0-9]*"
         scripts/config.py unset MBEDTLS_DHM_C
@@ -4473,15 +4373,22 @@
 
 component_test_when_no_ciphersuites_have_mac () {
     msg "build: when no ciphersuites have MAC"
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_CBC_NO_PADDING
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_CBC_PKCS7
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_CMAC
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128
+
     scripts/config.py unset MBEDTLS_CIPHER_NULL_CIPHER
     scripts/config.py unset MBEDTLS_CIPHER_MODE_CBC
     scripts/config.py unset MBEDTLS_CMAC_C
+
     make
 
-    msg "test: !MBEDTLS_SSL_SOME_MODES_USE_MAC"
+    msg "test: !MBEDTLS_SSL_SOME_SUITES_USE_MAC"
     make test
 
-    msg "test ssl-opt.sh: !MBEDTLS_SSL_SOME_MODES_USE_MAC"
+    msg "test ssl-opt.sh: !MBEDTLS_SSL_SOME_SUITES_USE_MAC"
     tests/ssl-opt.sh -f 'Default\|EtM' -e 'without EtM'
 }
 
@@ -6122,45 +6029,60 @@
 }
 
 component_test_psasim() {
-    msg "build library for client"
-
-    helper_crypto_client_build client
-
     msg "build library for server"
-
     scripts/config.py crypto
-
     helper_crypto_client_build server
 
-    msg "build psasim"
-    make -C tests/psa-client-server/psasim CFLAGS="$ASAN_CFLAGS" LDFLAGS="$ASAN_CFLAGS"
+    msg "build server"
+    make -C tests/psa-client-server/psasim CFLAGS="$ASAN_CFLAGS" LDFLAGS="$ASAN_CFLAGS" test/psa_partition
+
+    # cleanup() will restore some backed-up files which include $CONFIG_H and
+    # $CRYPTO_CONFIG_H. Built libraries were already copied to psasim at this
+    # point.
+    cleanup
+
+    msg "build library for client"
+    helper_crypto_client_build client
+
+    msg "build psasim to test psa_client"
+    rm -f tests/psa-client-server/psasim/test/psa_client        # In case left behind
+    make -C tests/psa-client-server/psasim CFLAGS="$ASAN_CFLAGS" LDFLAGS="$ASAN_CFLAGS" test/psa_client
 
     msg "test psasim"
     tests/psa-client-server/psasim/test/run_test.sh
 
+
     msg "build psasim to test psa_hash_compute"
     # Delete the executable to ensure we build using the right MAIN
     rm tests/psa-client-server/psasim/test/psa_client
     # API under test: psa_hash_compute()
-    make -C tests/psa-client-server/psasim CFLAGS="$ASAN_CFLAGS" LDFLAGS="$ASAN_CFLAGS" MAIN="src/aut_psa_hash_compute.c"
+    make -C tests/psa-client-server/psasim CFLAGS="$ASAN_CFLAGS" LDFLAGS="$ASAN_CFLAGS" MAIN="src/aut_psa_hash_compute.c" test/psa_client
 
     msg "test psasim running psa_hash_compute"
     tests/psa-client-server/psasim/test/run_test.sh
 
-    # Next APIs under test: psa_hash_*(). Just use the PSA hash example.
-    aut_psa_hash="../../../programs/psa/psa_hash.c"
-    if [ -f "tests/psa-client-server/psasim/$aut_psa_hash" ]; then
 
-        msg "build psasim to test all psa_hash_* APIs"
-        # Delete the executable to ensure we build using the right MAIN
-        rm tests/psa-client-server/psasim/test/psa_client
-        make -C tests/psa-client-server/psasim CFLAGS="$ASAN_CFLAGS" LDFLAGS="$ASAN_CFLAGS" MAIN="$aut_psa_hash"
+    # Next APIs under test: psa_hash_*(). Use our copy of the PSA hash example.
+    msg "build psasim to test all psa_hash_* APIs"
+    # Delete the executable to ensure we build using the right MAIN
+    rm tests/psa-client-server/psasim/test/psa_client
+    make -C tests/psa-client-server/psasim CFLAGS="$ASAN_CFLAGS" LDFLAGS="$ASAN_CFLAGS" MAIN="src/aut_psa_hash.c" test/psa_client
 
-        msg "test psasim running psa_hash sample"
-        tests/psa-client-server/psasim/test/run_test.sh
-    else
-        echo $aut_psa_hash NOT FOUND, so not running that test
-    fi
+    msg "test psasim running psa_hash sample"
+    tests/psa-client-server/psasim/test/run_test.sh
+
+
+    # Next APIs under test: psa_aead_*(). Use our copy of the PSA aead example.
+    msg "build psasim to test all psa_aead_* APIs"
+    # Delete the executable to ensure we build using the right MAIN
+    rm tests/psa-client-server/psasim/test/psa_client
+    make -C tests/psa-client-server/psasim CFLAGS="$ASAN_CFLAGS" LDFLAGS="$ASAN_CFLAGS" MAIN="src/aut_psa_aead_demo.c" test/psa_client
+
+    msg "test psasim running psa_aead_demo sample"
+    tests/psa-client-server/psasim/test/run_test.sh aes128-gcm
+    tests/psa-client-server/psasim/test/run_test.sh aes256-gcm
+    tests/psa-client-server/psasim/test/run_test.sh aes128-gcm_8
+    tests/psa-client-server/psasim/test/run_test.sh chachapoly
 
     msg "clean psasim"
     make -C tests/psa-client-server/psasim clean
diff --git a/tests/scripts/check_names.py b/tests/scripts/check_names.py
index 5128dc8..01c3f3c 100755
--- a/tests/scripts/check_names.py
+++ b/tests/scripts/check_names.py
@@ -238,6 +238,7 @@
         all_macros["public"] = self.parse_macros([
             "include/mbedtls/*.h",
             "include/psa/*.h",
+            "tf-psa-crypto/include/psa/*.h",
             "3rdparty/everest/include/everest/everest.h",
             "3rdparty/everest/include/everest/x25519.h"
         ])
@@ -251,6 +252,7 @@
         enum_consts = self.parse_enum_consts([
             "include/mbedtls/*.h",
             "include/psa/*.h",
+            "tf-psa-crypto/include/psa/*.h",
             "library/*.h",
             "library/*.c",
             "3rdparty/everest/include/everest/everest.h",
@@ -259,6 +261,7 @@
         identifiers, excluded_identifiers = self.parse_identifiers([
             "include/mbedtls/*.h",
             "include/psa/*.h",
+            "tf-psa-crypto/include/psa/*.h",
             "library/*.h",
             "3rdparty/everest/include/everest/everest.h",
             "3rdparty/everest/include/everest/x25519.h"
@@ -266,6 +269,7 @@
         mbed_psa_words = self.parse_mbed_psa_words([
             "include/mbedtls/*.h",
             "include/psa/*.h",
+            "tf-psa-crypto/include/psa/*.h",
             "library/*.h",
             "3rdparty/everest/include/everest/everest.h",
             "3rdparty/everest/include/everest/x25519.h",
diff --git a/tests/scripts/test-ref-configs.pl b/tests/scripts/test-ref-configs.pl
index 5557de3..9198293 100755
--- a/tests/scripts/test-ref-configs.pl
+++ b/tests/scripts/test-ref-configs.pl
@@ -24,8 +24,6 @@
         'opt' => ' ',
         'opt_needs_debug' => 1,
     },
-    'config-no-entropy.h' => {
-    },
     'config-suite-b.h' => {
         'compat' => "-m tls12 -f 'ECDHE_ECDSA.*AES.*GCM' -p mbedTLS",
         'opt' => ' ',
diff --git a/tests/scripts/test_psa_compliance.py b/tests/scripts/test_psa_compliance.py
index f7d1895..b500fe5 100755
--- a/tests/scripts/test_psa_compliance.py
+++ b/tests/scripts/test_psa_compliance.py
@@ -74,7 +74,8 @@
         os.chdir(build_dir)
 
         extra_includes = (';{}/drivers/builtin/include'.format(root_dir)
-                          if in_tf_psa_crypto_repo else '')
+                          if in_tf_psa_crypto_repo else
+                          ';{}/tf-psa-crypto/include'.format(root_dir))
 
         #pylint: disable=bad-continuation
         subprocess.check_call([
diff --git a/tests/scripts/test_psa_constant_names.py b/tests/scripts/test_psa_constant_names.py
index 86d9e6f..6c9d905 100755
--- a/tests/scripts/test_psa_constant_names.py
+++ b/tests/scripts/test_psa_constant_names.py
@@ -161,7 +161,7 @@
 def main():
     parser = argparse.ArgumentParser(description=globals()['__doc__'])
     parser.add_argument('--include', '-I',
-                        action='append', default=['include'],
+                        action='append', default=['tf-psa-crypto/include', 'include'],
                         help='Directory for header files')
     parser.add_argument('--keep-c',
                         action='store_true', dest='keep_c', default=False,
diff --git a/tests/src/drivers/test_driver_key_agreement.c b/tests/src/drivers/test_driver_key_agreement.c
index 8471959..594fcd5 100644
--- a/tests/src/drivers/test_driver_key_agreement.c
+++ b/tests/src/drivers/test_driver_key_agreement.c
@@ -20,7 +20,7 @@
 #include <string.h>
 
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
-#include "libtestdriver1/include/psa/crypto.h"
+#include "libtestdriver1/tf-psa-crypto/include/psa/crypto.h"
 #include "libtestdriver1/library/psa_crypto_ecp.h"
 #include "libtestdriver1/library/psa_crypto_ffdh.h"
 #endif
diff --git a/tests/src/psa_test_wrappers.c b/tests/src/psa_test_wrappers.c
index 809f1cd..24e05c8 100644
--- a/tests/src/psa_test_wrappers.c
+++ b/tests/src/psa_test_wrappers.c
@@ -465,6 +465,7 @@
 }
 
 /* Wrapper for psa_crypto_driver_pake_get_cipher_suite */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_cipher_suite(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     psa_pake_cipher_suite_t *arg1_cipher_suite)
@@ -472,8 +473,10 @@
     psa_status_t status = (psa_crypto_driver_pake_get_cipher_suite)(arg0_inputs, arg1_cipher_suite);
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_crypto_driver_pake_get_password */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_password(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     uint8_t *arg1_buffer,
@@ -483,8 +486,10 @@
     psa_status_t status = (psa_crypto_driver_pake_get_password)(arg0_inputs, arg1_buffer, arg2_buffer_size, arg3_buffer_length);
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_crypto_driver_pake_get_password_len */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_password_len(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     size_t *arg1_password_len)
@@ -492,8 +497,10 @@
     psa_status_t status = (psa_crypto_driver_pake_get_password_len)(arg0_inputs, arg1_password_len);
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_crypto_driver_pake_get_peer */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_peer(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     uint8_t *arg1_peer_id,
@@ -503,8 +510,10 @@
     psa_status_t status = (psa_crypto_driver_pake_get_peer)(arg0_inputs, arg1_peer_id, arg2_peer_id_size, arg3_peer_id_length);
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_crypto_driver_pake_get_peer_len */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_peer_len(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     size_t *arg1_peer_len)
@@ -512,8 +521,10 @@
     psa_status_t status = (psa_crypto_driver_pake_get_peer_len)(arg0_inputs, arg1_peer_len);
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_crypto_driver_pake_get_user */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_user(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     uint8_t *arg1_user_id,
@@ -523,8 +534,10 @@
     psa_status_t status = (psa_crypto_driver_pake_get_user)(arg0_inputs, arg1_user_id, arg2_user_id_size, arg3_user_id_len);
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_crypto_driver_pake_get_user_len */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_crypto_driver_pake_get_user_len(
     const psa_crypto_driver_pake_inputs_t *arg0_inputs,
     size_t *arg1_user_len)
@@ -532,6 +545,7 @@
     psa_status_t status = (psa_crypto_driver_pake_get_user_len)(arg0_inputs, arg1_user_len);
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_crypto_init */
 psa_status_t mbedtls_test_wrap_psa_crypto_init(void)
@@ -1008,14 +1022,17 @@
 }
 
 /* Wrapper for psa_pake_abort */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_abort(
     psa_pake_operation_t *arg0_operation)
 {
     psa_status_t status = (psa_pake_abort)(arg0_operation);
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_pake_get_implicit_key */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_get_implicit_key(
     psa_pake_operation_t *arg0_operation,
     psa_key_derivation_operation_t *arg1_output)
@@ -1023,8 +1040,10 @@
     psa_status_t status = (psa_pake_get_implicit_key)(arg0_operation, arg1_output);
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_pake_input */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_input(
     psa_pake_operation_t *arg0_operation,
     psa_pake_step_t arg1_step,
@@ -1040,8 +1059,10 @@
 #endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_pake_output */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_output(
     psa_pake_operation_t *arg0_operation,
     psa_pake_step_t arg1_step,
@@ -1058,8 +1079,10 @@
 #endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_pake_set_password_key */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_set_password_key(
     psa_pake_operation_t *arg0_operation,
     mbedtls_svc_key_id_t arg1_password)
@@ -1067,8 +1090,10 @@
     psa_status_t status = (psa_pake_set_password_key)(arg0_operation, arg1_password);
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_pake_set_peer */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_set_peer(
     psa_pake_operation_t *arg0_operation,
     const uint8_t *arg1_peer_id,
@@ -1083,8 +1108,10 @@
 #endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_pake_set_role */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_set_role(
     psa_pake_operation_t *arg0_operation,
     psa_pake_role_t arg1_role)
@@ -1092,8 +1119,10 @@
     psa_status_t status = (psa_pake_set_role)(arg0_operation, arg1_role);
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_pake_set_user */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_set_user(
     psa_pake_operation_t *arg0_operation,
     const uint8_t *arg1_user_id,
@@ -1108,8 +1137,10 @@
 #endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_pake_setup */
+#if defined(PSA_WANT_ALG_SOME_PAKE)
 psa_status_t mbedtls_test_wrap_psa_pake_setup(
     psa_pake_operation_t *arg0_operation,
     const psa_pake_cipher_suite_t *arg1_cipher_suite)
@@ -1117,6 +1148,7 @@
     psa_status_t status = (psa_pake_setup)(arg0_operation, arg1_cipher_suite);
     return status;
 }
+#endif /* defined(PSA_WANT_ALG_SOME_PAKE) */
 
 /* Wrapper for psa_purge_key */
 psa_status_t mbedtls_test_wrap_psa_purge_key(
diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function
index 23f5cda..38c27e3 100644
--- a/tests/suites/test_suite_pk.function
+++ b/tests/suites/test_suite_pk.function
@@ -64,14 +64,22 @@
 #define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
 #define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 192
 #define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP192R1
-#elif defined(PSA_WANT_ECC_SECP_R1_224)
-#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
-#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 224
-#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP224R1
 #elif defined(PSA_WANT_ECC_SECP_R1_256)
 #define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
 #define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 256
 #define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP256R1
+#elif defined(PSA_WANT_ECC_SECP_K1_192)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_K1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 192
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP192K1
+#elif defined(PSA_WANT_ECC_SECP_K1_256)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_K1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 256
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP256K1
+#elif defined(PSA_WANT_ECC_SECP_R1_224)
+#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
+#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 224
+#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP224R1
 #elif defined(PSA_WANT_ECC_SECP_R1_384)
 #define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
 #define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 384
@@ -80,18 +88,10 @@
 #define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
 #define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 521
 #define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP521R1
-#elif defined(PSA_WANT_ECC_SECP_K1_192)
-#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_K1
-#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 192
-#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP192K1
 #elif defined(PSA_WANT_ECC_SECP_K1_224)
 #define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_K1
 #define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 224
 #define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP224K1
-#elif defined(PSA_WANT_ECC_SECP_K1_256)
-#define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_K1
-#define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 256
-#define MBEDTLS_TEST_ECP_DP_ONE_CURVE MBEDTLS_ECP_DP_SECP256K1
 #elif defined(PSA_WANT_ECC_BRAINPOOL_P_R1_256)
 #define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_BRAINPOOL_P_R1
 #define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 256
@@ -128,7 +128,8 @@
 #define MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY PSA_ECC_FAMILY_SECP_K1
 #define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 192
 #define MBEDTLS_TEST_PSA_ECC_HAVE_TWO_FAMILIES
-#elif defined(PSA_WANT_ECC_SECP_R1_256) && defined(PSA_WANT_ECC_SECP_K1_256)
+#elif defined(PSA_WANT_ECC_SECP_R1_256) && defined(PSA_WANT_ECC_SECP_K1_256) && \
+    !defined(PSA_WANT_ECC_SECP_R1_192)
 #define MBEDTLS_TEST_PSA_ECC_ONE_FAMILY PSA_ECC_FAMILY_SECP_R1
 #define MBEDTLS_TEST_PSA_ECC_ANOTHER_FAMILY PSA_ECC_FAMILY_SECP_K1
 #define MBEDTLS_TEST_PSA_ECC_ONE_CURVE_BITS 256
diff --git a/tf-psa-crypto/.gitignore b/tf-psa-crypto/.gitignore
new file mode 100644
index 0000000..f3c7a7c
--- /dev/null
+++ b/tf-psa-crypto/.gitignore
@@ -0,0 +1 @@
+Makefile
diff --git a/tf-psa-crypto/CMakeLists.txt b/tf-psa-crypto/CMakeLists.txt
new file mode 100644
index 0000000..1425abb
--- /dev/null
+++ b/tf-psa-crypto/CMakeLists.txt
@@ -0,0 +1,38 @@
+#
+# CMake build system design considerations:
+#
+# - Include directories:
+#   + Do not define include directories globally using the include_directories
+#     command but rather at the target level using the
+#     target_include_directories command. That way, it is easier to guarantee
+#     that targets are built using the proper list of include directories.
+#   + Use the PUBLIC and PRIVATE keywords to specify the scope of include
+#     directories. That way, a target linking to a library (using the
+#     target_link_libraries command) inherits from the library PUBLIC include
+#     directories and not from the PRIVATE ones.
+# - TF_PSA_CRYPTO_TARGET_PREFIX: CMake targets are designed to be alterable by
+#   calling CMake in order to avoid target name clashes, via the use of
+#   TF_PSA_CRYPTO_TARGET_PREFIX. The value of this variable is prefixed to the
+#   tfpsacrypto and apidoc targets.
+#
+
+# We specify a minimum requirement of 3.10.2, but for now use 3.5.1 here
+# until our infrastructure catches up.
+cmake_minimum_required(VERSION 3.5.1)
+
+# 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.
+cmake_policy(SET CMP0011 NEW)
+# https://cmake.org/cmake/help/latest/policy/CMP0012.html
+# Setting the CMP0012 policy to NEW is required for FindPython3 to work with CMake 3.18.2
+# (there is a bug in this particular version), otherwise, setting the CMP0012 policy is required
+# for CMake versions >= 3.18.3 otherwise a deprecated warning is generated. The OLD policy setting
+# is deprecated and will be removed in future versions.
+cmake_policy(SET CMP0012 NEW)
+
+if(LIB_INSTALL_DIR)
+    set(CMAKE_INSTALL_LIBDIR "${LIB_INSTALL_DIR}")
+endif()
+
+add_subdirectory(include)
diff --git a/tf-psa-crypto/include/.gitignore b/tf-psa-crypto/include/.gitignore
new file mode 100644
index 0000000..f3c7a7c
--- /dev/null
+++ b/tf-psa-crypto/include/.gitignore
@@ -0,0 +1 @@
+Makefile
diff --git a/tf-psa-crypto/include/CMakeLists.txt b/tf-psa-crypto/include/CMakeLists.txt
new file mode 100644
index 0000000..dea92fe
--- /dev/null
+++ b/tf-psa-crypto/include/CMakeLists.txt
@@ -0,0 +1,16 @@
+option(INSTALL_PSA_CRYPTO_HEADERS "Install PSA Crypto headers." ON)
+
+if(INSTALL_PSA_CRYPTO_HEADERS)
+
+    file(GLOB psa_headers "psa/*.h")
+
+    install(FILES ${psa_headers}
+        DESTINATION include/psa
+        PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+
+endif(INSTALL_PSA_CRYPTO_HEADERS)
+
+# Make includes available in an out-of-source build. ssl-opt.sh requires it.
+if (ENABLE_TESTING AND NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
+    link_to_source(psa)
+endif()
diff --git a/include/psa/build_info.h b/tf-psa-crypto/include/psa/build_info.h
similarity index 100%
rename from include/psa/build_info.h
rename to tf-psa-crypto/include/psa/build_info.h
diff --git a/include/psa/crypto.h b/tf-psa-crypto/include/psa/crypto.h
similarity index 100%
rename from include/psa/crypto.h
rename to tf-psa-crypto/include/psa/crypto.h
diff --git a/include/psa/crypto_adjust_auto_enabled.h b/tf-psa-crypto/include/psa/crypto_adjust_auto_enabled.h
similarity index 100%
rename from include/psa/crypto_adjust_auto_enabled.h
rename to tf-psa-crypto/include/psa/crypto_adjust_auto_enabled.h
diff --git a/include/psa/crypto_adjust_config_dependencies.h b/tf-psa-crypto/include/psa/crypto_adjust_config_dependencies.h
similarity index 100%
rename from include/psa/crypto_adjust_config_dependencies.h
rename to tf-psa-crypto/include/psa/crypto_adjust_config_dependencies.h
diff --git a/include/psa/crypto_adjust_config_key_pair_types.h b/tf-psa-crypto/include/psa/crypto_adjust_config_key_pair_types.h
similarity index 100%
rename from include/psa/crypto_adjust_config_key_pair_types.h
rename to tf-psa-crypto/include/psa/crypto_adjust_config_key_pair_types.h
diff --git a/include/psa/crypto_adjust_config_synonyms.h b/tf-psa-crypto/include/psa/crypto_adjust_config_synonyms.h
similarity index 100%
rename from include/psa/crypto_adjust_config_synonyms.h
rename to tf-psa-crypto/include/psa/crypto_adjust_config_synonyms.h
diff --git a/include/psa/crypto_builtin_composites.h b/tf-psa-crypto/include/psa/crypto_builtin_composites.h
similarity index 100%
rename from include/psa/crypto_builtin_composites.h
rename to tf-psa-crypto/include/psa/crypto_builtin_composites.h
diff --git a/include/psa/crypto_builtin_key_derivation.h b/tf-psa-crypto/include/psa/crypto_builtin_key_derivation.h
similarity index 100%
rename from include/psa/crypto_builtin_key_derivation.h
rename to tf-psa-crypto/include/psa/crypto_builtin_key_derivation.h
diff --git a/include/psa/crypto_builtin_primitives.h b/tf-psa-crypto/include/psa/crypto_builtin_primitives.h
similarity index 100%
rename from include/psa/crypto_builtin_primitives.h
rename to tf-psa-crypto/include/psa/crypto_builtin_primitives.h
diff --git a/include/psa/crypto_compat.h b/tf-psa-crypto/include/psa/crypto_compat.h
similarity index 100%
rename from include/psa/crypto_compat.h
rename to tf-psa-crypto/include/psa/crypto_compat.h
diff --git a/include/psa/crypto_config.h b/tf-psa-crypto/include/psa/crypto_config.h
similarity index 100%
rename from include/psa/crypto_config.h
rename to tf-psa-crypto/include/psa/crypto_config.h
diff --git a/include/psa/crypto_driver_common.h b/tf-psa-crypto/include/psa/crypto_driver_common.h
similarity index 100%
rename from include/psa/crypto_driver_common.h
rename to tf-psa-crypto/include/psa/crypto_driver_common.h
diff --git a/include/psa/crypto_driver_contexts_composites.h b/tf-psa-crypto/include/psa/crypto_driver_contexts_composites.h
similarity index 98%
rename from include/psa/crypto_driver_contexts_composites.h
rename to tf-psa-crypto/include/psa/crypto_driver_contexts_composites.h
index d717c51..5a484fc 100644
--- a/include/psa/crypto_driver_contexts_composites.h
+++ b/tf-psa-crypto/include/psa/crypto_driver_contexts_composites.h
@@ -31,7 +31,7 @@
  * declared during the autogeneration process. */
 
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
-#include <libtestdriver1/include/psa/crypto.h>
+#include <libtestdriver1/tf-psa-crypto/include/psa/crypto.h>
 #endif
 
 #if defined(PSA_CRYPTO_DRIVER_TEST)
diff --git a/include/psa/crypto_driver_contexts_key_derivation.h b/tf-psa-crypto/include/psa/crypto_driver_contexts_key_derivation.h
similarity index 100%
rename from include/psa/crypto_driver_contexts_key_derivation.h
rename to tf-psa-crypto/include/psa/crypto_driver_contexts_key_derivation.h
diff --git a/include/psa/crypto_driver_contexts_primitives.h b/tf-psa-crypto/include/psa/crypto_driver_contexts_primitives.h
similarity index 98%
rename from include/psa/crypto_driver_contexts_primitives.h
rename to tf-psa-crypto/include/psa/crypto_driver_contexts_primitives.h
index c90a5fb..281e0a1 100644
--- a/include/psa/crypto_driver_contexts_primitives.h
+++ b/tf-psa-crypto/include/psa/crypto_driver_contexts_primitives.h
@@ -30,7 +30,7 @@
  * declared during the autogeneration process. */
 
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
-#include <libtestdriver1/include/psa/crypto.h>
+#include <libtestdriver1/tf-psa-crypto/include/psa/crypto.h>
 #endif
 
 #if defined(PSA_CRYPTO_DRIVER_TEST)
diff --git a/include/psa/crypto_extra.h b/tf-psa-crypto/include/psa/crypto_extra.h
similarity index 100%
rename from include/psa/crypto_extra.h
rename to tf-psa-crypto/include/psa/crypto_extra.h
diff --git a/include/psa/crypto_legacy.h b/tf-psa-crypto/include/psa/crypto_legacy.h
similarity index 100%
rename from include/psa/crypto_legacy.h
rename to tf-psa-crypto/include/psa/crypto_legacy.h
diff --git a/include/psa/crypto_platform.h b/tf-psa-crypto/include/psa/crypto_platform.h
similarity index 100%
rename from include/psa/crypto_platform.h
rename to tf-psa-crypto/include/psa/crypto_platform.h
diff --git a/include/psa/crypto_se_driver.h b/tf-psa-crypto/include/psa/crypto_se_driver.h
similarity index 100%
rename from include/psa/crypto_se_driver.h
rename to tf-psa-crypto/include/psa/crypto_se_driver.h
diff --git a/include/psa/crypto_sizes.h b/tf-psa-crypto/include/psa/crypto_sizes.h
similarity index 100%
rename from include/psa/crypto_sizes.h
rename to tf-psa-crypto/include/psa/crypto_sizes.h
diff --git a/include/psa/crypto_struct.h b/tf-psa-crypto/include/psa/crypto_struct.h
similarity index 100%
rename from include/psa/crypto_struct.h
rename to tf-psa-crypto/include/psa/crypto_struct.h
diff --git a/include/psa/crypto_types.h b/tf-psa-crypto/include/psa/crypto_types.h
similarity index 100%
rename from include/psa/crypto_types.h
rename to tf-psa-crypto/include/psa/crypto_types.h
diff --git a/include/psa/crypto_values.h b/tf-psa-crypto/include/psa/crypto_values.h
similarity index 100%
rename from include/psa/crypto_values.h
rename to tf-psa-crypto/include/psa/crypto_values.h