diff --git a/configure.ac b/configure.ac
index 3d493eab9..eca24b329 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1173,6 +1173,82 @@ AC_ARG_ENABLE([smime],
[ ENABLED_SMIME=no ]
)
+# Platform Security Architecture (PSA)
+AC_ARG_ENABLE([psa],
+[AS_HELP_STRING([--enable-psa],[use Platform Security Architecture (PSA) interface (default: disabled)])],
+[ ENABLED_PSA=$enableval ],
+[ ENABLED_PSA=no ]
+)
+
+AC_ARG_WITH([psa-include],
+ [AS_HELP_STRING([--with-psa-include=PATH],
+ [PATH to directory with PSA header files])],
+ [PSA_INCLUDE=$withval],
+ [PSA_INCLUDE=""])
+
+AC_ARG_WITH([psa-lib],
+ [AS_HELP_STRING([--with-psa-lib=PATH],[PATH to directory with the PSA library])],
+ [PSA_LIB=$withval],
+ [PSA_LIB=""])
+
+AC_ARG_WITH([psa-lib-name],
+ [AS_HELP_STRING([--with-psa-lib-name=NAME],[NAME of PSA library])],
+ [PSA_LIB_NAME=$withval],
+ [PSA_LIB_NAME=""])
+
+AC_ARG_ENABLE([psa-lib-static],
+ [AS_HELP_STRING([--enable-psa-lib-static],[Link PSA as static library (default: disable)])],
+ [ ENABLED_PSA_STATIC=$enableval ],
+ [ ENABLED_PSA_STATIC=no ]
+)
+
+if test "x$ENABLED_PSA" = "xyes"
+then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_PSA"
+fi
+
+if test "x$ENABLED_PSA" != "xyes" && \
+ (test "x$PSA_LIB"! = "x" || test "x$PSA_INCLUDE" != "x" || test "x$PSA_LIB_NAME" != "x" )
+then
+ AC_MSG_ERROR([to use PSA you need to enable it with --enable-psa])
+fi
+
+if test -n "$PSA_LIB"
+then
+ AC_MSG_CHECKING([for $PSA_LIB])
+ if ! test -d "$PSA_LIB"
+ then
+ AC_MSG_ERROR([PSA lib dir $PSA_LIB not found.])
+ fi
+ AC_MSG_RESULT([yes])
+ AM_LDFLAGS="$AM_LDFLAGS -L$PSA_LIB"
+fi
+
+if test -n "$PSA_LIB_NAME"
+then
+ if test "x$ENABLED_PSA_STATIC" = "xyes"
+ then
+ LIB_STATIC_ADD="$LIB_STATIC_ADD $PSA_LIB/$PSA_LIB_NAME"
+ else
+ LIB_ADD="$LIB_ADD -l$PSA_LIB_NAME"
+ fi
+fi
+
+if test -n "$PSA_INCLUDE"
+then
+ AC_MSG_CHECKING([for $PSA_INCLUDE])
+ if ! test -d "$PSA_INCLUDE"
+ then
+ AC_MSG_ERROR([psa include dir $PSA_INCLUDE not found.])
+ fi
+ AC_MSG_RESULT([yes])
+ AM_CFLAGS="$AM_CFLAGS -I$PSA_INCLUDE"
+fi
+
+AC_SUBST([PSA_LIB])
+AC_SUBST([PSA_LIB_NAME])
+AC_SUBST([PSA_INCLUDE])
+
# OPENSSL Compatibility ALL
AC_ARG_ENABLE([opensslall],
[AS_HELP_STRING([--enable-opensslall],[Enable all OpenSSL API, size++ (default: disabled)])],
@@ -7512,6 +7588,7 @@ AM_CONDITIONAL([BUILD_KDF],[test "x$ENABLED_KDF" = "xyes"])
AM_CONDITIONAL([BUILD_HMAC],[test "x$ENABLED_HMAC" = "xyes"])
AM_CONDITIONAL([BUILD_ERROR_STRINGS],[test "x$ENABLED_ERROR_STRINGS" = "xyes"])
AM_CONDITIONAL([BUILD_DO178],[test "x$ENABLED_DO178" = "xyes"])
+AM_CONDITIONAL([BUILD_PSA],[test "x$ENABLED_PSA" = "xyes"])
if test "$ENABLED_REPRODUCIBLE_BUILD" != "yes" &&
(test "$ax_enable_debug" = "yes" ||
@@ -7911,6 +7988,7 @@ echo " * i.MX6 CAAM: $ENABLED_CAAM"
echo " * IoT-Safe: $ENABLED_IOTSAFE"
echo " * IoT-Safe HWRNG: $ENABLED_IOTSAFE_HWRNG"
echo " * NXP SE050: $ENABLED_SE050"
+echo " * PSA: $ENABLED_PSA"
echo ""
echo "---"
diff --git a/doc/dox_comments/header_files/doxygen_groups.h b/doc/dox_comments/header_files/doxygen_groups.h
index 1bc719dad..e7102a52c 100644
--- a/doc/dox_comments/header_files/doxygen_groups.h
+++ b/doc/dox_comments/header_files/doxygen_groups.h
@@ -226,7 +226,7 @@
If compiled in, the module supports IoT-Safe random number generator as source of entropy for wolfCrypt.
-
+ \defgroup PSA Platform Security Architecture (PSA) API
\defgroup Keys Key and Cert Conversion
\defgroup Logging Logging
\defgroup Math Math API
diff --git a/doc/dox_comments/header_files/doxygen_pages.h b/doc/dox_comments/header_files/doxygen_pages.h
index 700171d07..39065f819 100644
--- a/doc/dox_comments/header_files/doxygen_pages.h
+++ b/doc/dox_comments/header_files/doxygen_pages.h
@@ -18,6 +18,7 @@
\ref Compression
\ref Error
\ref IoTSafe
+ \ref PSA
\ref Keys
\ref Logging
\ref Math
diff --git a/doc/dox_comments/header_files/psa.h b/doc/dox_comments/header_files/psa.h
new file mode 100644
index 000000000..4259bfa00
--- /dev/null
+++ b/doc/dox_comments/header_files/psa.h
@@ -0,0 +1,96 @@
+/*!
+ \ingroup PSA
+ \brief This function enables PSA support on the given context.
+
+ \param ctx pointer to the WOLFSSL_CTX object on which the PSA support must be enabled
+ \return WOLFSSL_SUCCESS on success
+ \return BAD_FUNC_ARG if ctx == NULL
+
+ _Example_
+ \code
+ WOLFSSL_CTX *ctx;
+ ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method());
+ if (!ctx)
+ return NULL;
+ ret = wolfSSL_CTX_psa_enable(ctx);
+ if (ret != WOLFSSL_SUCCESS)
+ printf("can't enable PSA on ctx");
+
+ \endcode
+
+ \sa wolfSSL_set_psa_ctx
+*/
+WOLFSSL_API int wolfSSL_CTX_psa_enable(WOLFSSL_CTX *ctx);
+
+/*!
+ \ingroup PSA
+
+ \brief This function setup the PSA context for the given SSL session
+
+ \param ssl pointer to the WOLFSSL where the ctx will be enabled
+ \param ctx pointer to a struct psa_ssl_ctx (must be unique for a ssl session)
+
+ \return WOLFSSL_SUCCESS on success
+ \return BAD_FUNC_ARG if ssl or ctx are NULL
+
+ This function setup the PSA context for the TLS callbacks to the given SSL
+ session. At the end of the session, the resources used by the context
+ should be freed using wolfSSL_free_psa_ctx().
+
+ _Example_
+ \code
+ // Create new ssl session
+ WOLFSSL *ssl;
+ struct psa_ssl_ctx psa_ctx = { 0 };
+ ssl = wolfSSL_new(ctx);
+ if (!ssl)
+ return NULL;
+ // setup PSA context
+ ret = wolfSSL_set_psa_ctx(ssl, ctx);
+ \endcode
+
+ \sa wolfSSL_psa_set_private_key_id
+ \sa wolfSSL_psa_free_psa_ctx
+*/
+WOLFSSL_API int wolfSSL_set_psa_ctx(WOLFSSL *ssl, struct psa_ssl_ctx *ctx);
+
+/*!
+ \ingroup PSA
+ \brief This function releases the resources used by a PSA context
+
+ \param ctx pointer to a struct psa_ssl_ctx
+
+ \sa wolfSSL_set_psa_ctx
+*/
+WOLFSSL_API void wolfSSL_free_psa_ctx(struct psa_ssl_ctx *ctx);
+
+/*!
+ \ingroup PSA
+ \brief This function set the private key used by an SSL session
+
+ \param ctx pointer to a struct psa_ssl_ctx
+ \param id PSA id of the key to be used as private key
+
+ _Example_
+ \code
+ // Create new ssl session
+ WOLFSSL *ssl;
+ struct psa_ssl_ctx psa_ctx = { 0 };
+ psa_key_id_t key_id;
+
+ // key provisioning already done
+ get_private_key_id(&key_id);
+
+ ssl = wolfSSL_new(ctx);
+ if (!ssl)
+ return NULL;
+
+ wolfSSL_psa_set_private_key_id(&psa_ctx, key_id);
+ wolfSSL_set_psa_ctx(ssl, ctx);
+ \endcode
+
+ \sa wolfSSL_set_psa_ctx
+*/
+
+WOLFSSL_API int wolfSSL_psa_set_private_key_id(struct psa_ssl_ctx *ctx,
+ psa_key_id_t id);
diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c
index 58404292c..7c9aacf09 100644
--- a/wolfcrypt/src/aes.c
+++ b/wolfcrypt/src/aes.c
@@ -76,6 +76,10 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits
#include
#endif
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES)
+ #include
+#endif
+
/* fips wrapper calls, user can call direct */
#if defined(HAVE_FIPS) && \
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))
@@ -1063,6 +1067,8 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits
defined(WOLFSSL_AES_CFB) || defined(HAVE_AES_ECB)
#define NEED_AES_TABLES
#endif
+#elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES)
+/* implemented in wolfcrypt/src/port/psa/psa_aes.c */
#else
/* using wolfCrypt software implementation */
@@ -2905,6 +2911,11 @@ static WARN_UNUSED_RESULT int wc_AesDecrypt(
if (keylen > sizeof(aes->key)) {
return BAD_FUNC_ARG;
}
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES)
+ return wc_psa_aes_set_key(aes, userKey, keylen, (uint8_t*)iv,
+ ((psa_algorithm_t)0), dir);
+#endif
+
rk = aes->key;
XMEMCPY(rk, userKey, keylen);
#if defined(LITTLE_ENDIAN_ORDER) && !defined(WOLFSSL_PIC32MZ_CRYPT) && \
@@ -3910,6 +3921,9 @@ int wc_AesSetIV(Aes* aes, const byte* iv)
#elif defined(WOLFSSL_SILABS_SE_ACCEL)
/* implemented in wolfcrypt/src/port/silabs/silabs_hash.c */
+#elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES)
+ /* implemented in wolfcrypt/src/port/psa/psa_aes.c */
+
#else
/* Software AES - CBC Encrypt */
@@ -4341,6 +4355,8 @@ int wc_AesSetIV(Aes* aes, const byte* iv)
/* use aes ecnryption plus sw implementation */
#define NEED_AES_CTR_SOFT
+ #elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES)
+ /* implemented in wolfcrypt/src/port/psa/psa_aes.c */
#else
/* Use software based AES counter */
@@ -10436,6 +10452,10 @@ int wc_AesInit(Aes* aes, void* heap, int devId)
aes->ctrSet = 0;
#endif
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES)
+ ret = wc_psa_aes_init(aes);
+#endif
+
return ret;
}
@@ -10534,6 +10554,10 @@ void wc_AesFree(Aes* aes)
se050_aes_free(aes);
#endif
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES)
+ wc_psa_aes_free(aes);
+#endif
+
}
@@ -10544,6 +10568,10 @@ int wc_AesGetKeySize(Aes* aes, word32* keySize)
if (aes == NULL || keySize == NULL) {
return BAD_FUNC_ARG;
}
+
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES)
+ return wc_psa_aes_get_key_size(aes, keySize);
+#endif
#if defined(WOLFSSL_CRYPTOCELL) && defined(WOLFSSL_CRYPTOCELL_AES)
*keySize = aes->ctx.key.keySize;
return ret;
diff --git a/wolfcrypt/src/include.am b/wolfcrypt/src/include.am
index 5324cf370..593374121 100644
--- a/wolfcrypt/src/include.am
+++ b/wolfcrypt/src/include.am
@@ -184,3 +184,11 @@ endif
if BUILD_SE050
src_libwolfssl_la_SOURCES += wolfcrypt/src/port/nxp/se050_port.c
endif
+
+if BUILD_PSA
+src_libwolfssl_la_SOURCES += wolfcrypt/src/port/psa/psa.c
+src_libwolfssl_la_SOURCES += wolfcrypt/src/port/psa/psa_hash.c
+src_libwolfssl_la_SOURCES += wolfcrypt/src/port/psa/psa_aes.c
+src_libwolfssl_la_SOURCES += wolfcrypt/src/port/psa/psa_pkcbs.c
+endif
+EXTRA_DIST += wolfcrypt/src/port/psa/README.md
diff --git a/wolfcrypt/src/port/psa/README.md b/wolfcrypt/src/port/psa/README.md
new file mode 100644
index 000000000..59bf89bc8
--- /dev/null
+++ b/wolfcrypt/src/port/psa/README.md
@@ -0,0 +1,115 @@
+wolfSSL using Platform Security Architecture (PSA)
+=================================================
+
+## Overview
+
+wolfSSL can be configured to use a PSA library for the following operations:
+* hashes: SHA-1, SHA-224, SAH-256
+* AES: AES-ECB, AES-CBC, AES-CTR, AES-GCM, AES-CCM
+* ECDH PK callbacks (P-256)
+* ECDSA PK callbacks (P-256)
+* RNG
+
+Client certificates are not supported.
+
+## Build
+### Basic configuration
+
+To enable PSA support in wolfSSL you need to provide the name of the library
+that implements the PSA interface using `--with-psa-lib-name=LIBNAME`. You may
+also provide the path to the library headers (with `--with-psa-include`) and to
+to the PSA library itself (with `--with-psa-lib`). As an example, to use mbedtls
+PSA implementation you may use:
+
+```
+./configure --enable-psa --with-psa-include=/dir/to/mbedtls/include --with-psa-lib=/dir/to/mbedtls/library --with-psa-lib-name=mbedcrypto
+```
+
+### Customize build
+
+You can switch off some of the algorithms supported using the following defines:
+
+ * `WOLFSSL_PSA_NO_RNG`: disable PSA random generator support
+ * `WOLFSSL_PSA_NO_HASH`: disable PSA hashing support
+ * `WOLFSSL_PSA_NO_AES`: disable PSA AES support
+ * `WOLFSSL_PSA_NO_PKCBS`: disable PK callbacks support
+
+## Supporting non-thread safe PSA implementation
+
+If the PSA implementation used is not thread-safe, you can serialize all calls
+to the PSA library using the define `WOLFSSL_PSA_GLOBAL_LOCK`.
+
+## Using PSA PK callbacks
+
+To use Public Key PSA callbacks you need to enable them using the function:
+
+`wolfSSL_CTX_psa_enable(WOLFSSL_CTX *ctx)`
+
+Context information regarding a single SSL session is stored inside a `struct
+psa_ssl_ctx`. The user needs to define and setup a `struct psa_ssl_ctx`, then
+to attach it to an ssl session with `wolfSSL_set_psa_ctx(WOLFSSL *ssl, struct
+psa_ssl_ctx *ctx)`. When the session is over, the application should free the
+psa context with `wolfSSL_free_psa_ctx(struct psa_ssl_ctx *ctx)`.
+
+Example:
+```
+ struct psa_ssl_ctx psa_ctx = { 0 };
+ WOLFSSL_CTX* ctx;
+ WOLFSSL* ssl;
+ int ret
+
+ /* WOLFSSL_CTX initialization here */
+
+ ret = wolfSSL_CTX_psa_enable(ctx);
+ if (ret != WOLFSSL_SUCCESS)
+ printf("can't enable PSA on ctx");
+
+ ssl = wolfSSL_new(ctx);
+ ret = wolfSSL_set_psa_ctx(ssl, &psa_ctx);
+ if (ret != WOLFSSL_SUCCESS)
+ printf("can't enable PSA on ctx");
+
+ /* SSL communication */
+
+ wolfSSL_free_psa_ctx(&psa_ctx);
+ SSL_free(ssl); ssl = NULL;
+ SSL_CTX_free(ctx); ctx = NULL;
+```
+
+### Setup server side private key
+
+On the server side, the private key of the server should be loaded inside the
+PSA engine storage. To use the key inside the ssl session you have to invoke
+`wolfSSL_psa_set_private_key_id(struct psa_ssl_ctx *ctx, psa_key_id_t id);`. The
+key needs to have `PSA_KEY_USAGE_SIGN_HASH` usage flag set. Example:
+
+```
+ psa_key_attributes_t key_attr = { 0 };
+ struct psa_ssl_ctx psa_ctx = { 0 };
+ psa_key_type_t key_type;
+ psa_key_id_t key_id;
+ psa_status_t status;
+
+ key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
+
+ psa_set_key_type(&key_attr, key_type);
+ psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_HASH);
+ psa_set_key_algorithm(&key_attr, PSA_ALG_ECDSA_ANY);
+
+ status = psa_import_key(&key_attr, ecc_key_256,
+ sizeof(ecc_key_256), &key_id);
+
+ if (status != PSA_SUCCESS) {
+ fprintf(stderr,
+ "ERROR: provisioning of private key failed: [%d] \n", status);
+ exit(-1);
+ }
+
+ wolfSSL_psa_set_private_key_id(&psa_ctx, key_id);
+}
+
+```
+
+## Additional note
+ - AES-GCM, AES-CTR, AES-CCM are not implemented directly. The software
+ implementation uses the AES-ECB PSA one to implement them.
diff --git a/wolfcrypt/src/port/psa/psa.c b/wolfcrypt/src/port/psa/psa.c
new file mode 100644
index 000000000..a019d3a5d
--- /dev/null
+++ b/wolfcrypt/src/port/psa/psa.c
@@ -0,0 +1,95 @@
+/* psa.c
+ *
+ * Copyright (C) 2006-2021 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+ #include
+#endif
+
+#include
+
+#if defined(WOLFSSL_HAVE_PSA)
+
+#include
+
+#include
+
+#include
+#include
+
+#if defined(WOLFSSL_PSA_GLOBAL_LOCK)
+static wolfSSL_Mutex psa_global_mutex;
+
+void PSA_LOCK()
+{
+ /* ideally we should propagate the return error here. Leaving out for code
+ simplicity for now. */
+ wc_LockMutex(&psa_global_mutex);
+}
+
+void PSA_UNLOCK()
+{
+ wc_UnLockMutex(&psa_global_mutex);
+}
+
+#endif
+
+
+int wc_psa_init()
+{
+ psa_status_t s;
+
+#if defined(WOLFSSL_PSA_GLOBAL_LOCK)
+ wc_InitMutex(&psa_global_mutex);
+#endif
+
+ PSA_LOCK();
+ s = psa_crypto_init();
+ PSA_UNLOCK();
+ if (s != PSA_SUCCESS)
+ return WC_HW_E;
+
+ return 0;
+}
+
+#if !defined(WOLFSSL_PSA_NO_RNG)
+/**
+ * wc_psa_get_random() - generate @size random bytes in @out
+ * @out: output buffer
+ * @size: number of random bytes to generate
+ *
+ * return: 0 on success
+ */
+int wc_psa_get_random(unsigned char *out, word32 sz)
+{
+ psa_status_t s;
+
+ PSA_LOCK();
+ s = psa_generate_random((uint8_t*)out, sz);
+ PSA_UNLOCK();
+ if (s != PSA_SUCCESS)
+ return WC_HW_E;
+
+ return 0;
+}
+#endif
+
+#endif /* WOLFSSL_HAVE_PSA */
diff --git a/wolfcrypt/src/port/psa/psa_aes.c b/wolfcrypt/src/port/psa/psa_aes.c
new file mode 100644
index 000000000..e69ea9969
--- /dev/null
+++ b/wolfcrypt/src/port/psa/psa_aes.c
@@ -0,0 +1,351 @@
+/* psa_aes.c
+ *
+ * Copyright (C) 2006-2021 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+#ifdef HAVE_CONFIG_H
+ #include
+#endif
+
+#include
+
+#if defined(WOLFSSL_HAVE_PSA)
+#if !defined(WOLFSSL_PSA_NO_AES)
+#if !defined(NO_AES)
+
+#include
+#include
+#include
+
+#ifndef NO_INLINE
+#define WOLFSSL_MISC_INCLUDED
+#include
+#else
+#include
+#endif
+
+static int wc_psa_aes_import_key(Aes *aes, const uint8_t *key,
+ size_t key_length, psa_algorithm_t alg,
+ int dir)
+{
+ psa_key_attributes_t key_attr;
+ psa_key_id_t id;
+ psa_status_t s;
+
+ XMEMSET(&key_attr, 0, sizeof(key_attr));
+ aes->key_id = 0;
+ aes->ctx_initialized = 0;
+
+ psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES);
+ psa_set_key_usage_flags(&key_attr,
+ dir == AES_ENCRYPTION ? PSA_KEY_USAGE_ENCRYPT :
+ dir == AES_DECRYPTION ? PSA_KEY_USAGE_DECRYPT : 0);
+ psa_set_key_algorithm(&key_attr, alg);
+
+ PSA_LOCK();
+ s = psa_import_key(&key_attr, key, key_length, &id);
+ PSA_UNLOCK();
+ if (s != PSA_SUCCESS)
+ return WC_HW_E;
+
+ aes->key_id = id;
+ aes->key_need_importing = 0;
+
+ return 0;
+}
+
+/**
+ * wc_psa_aes_init() - init @aes PSA resources
+ * @aes: Aes object
+ */
+int wc_psa_aes_init(Aes *aes)
+{
+ aes->key_id = 0;
+ aes->ctx_initialized = 0;
+ aes->key_need_importing = 0;
+ XMEMSET(&aes->psa_ctx, 0, sizeof(aes->psa_ctx));
+ return 0;
+}
+
+/**
+ * wc_psa_aes_get_key_size() - get the size of the key in @aes
+ * @aes: Aes object
+ * @keySize: where to store the size of the key
+ *
+ * returns: 0 on success
+ */
+int wc_psa_aes_get_key_size(Aes *aes, word32 *keySize)
+{
+ psa_key_attributes_t attr;
+ psa_status_t s;
+
+ if (aes->key_need_importing == 1) {
+ *keySize = aes->keylen;
+ return 0;
+ }
+
+ if (aes->key_id == PSA_KEY_ID_NULL)
+ return BAD_FUNC_ARG;
+
+ PSA_LOCK();
+ s = psa_get_key_attributes(aes->key_id, &attr);
+ PSA_UNLOCK();
+ if (s != PSA_SUCCESS)
+ return WC_HW_E;
+
+ *keySize = (word32)(psa_get_key_bits(&attr) / 8);
+ PSA_LOCK();
+ psa_reset_key_attributes(&attr);
+ PSA_UNLOCK();
+ return 0;
+}
+
+/**
+ * wc_psa_aes_set_key() - set key / iv to object *aes
+ * @aes: object to set the key into
+ * @key: key to import
+ * @key_length: size of the key in bytes
+ * @iv: IV (can be null)
+ * @alg: algorithm (mode) to use with this key (can be 0)
+ * @dir: direction to use with this key
+ *
+ *
+ * NOTE: if we don't know for teh mode or the direction (@alg == 0) the key
+ * import operation will be delayed until the first wc_psa_aes_encrypt_decrypt()
+ * invocation. In this case the key is temporary stored inside the AES
+ * object. Indeed PSA requires that the mode of operation is already known when
+ * importing a new key.
+ *
+ * returns: 0 on success, WC_HW_E on PSA error
+*/
+int wc_psa_aes_set_key(Aes *aes, const uint8_t *key, size_t key_length,
+ uint8_t *iv, psa_algorithm_t alg, int dir)
+{
+ psa_status_t s;
+ int ret;
+
+ /* the object was already used for other encryption. Reset the context */
+ if (aes->ctx_initialized) {
+ PSA_LOCK();
+ s = psa_cipher_abort(&aes->psa_ctx);
+ PSA_UNLOCK();
+ if (s != PSA_SUCCESS)
+ return WC_HW_E;
+
+ aes->ctx_initialized =0;
+ }
+
+ /* a key was already imported, destroy it first */
+ if (aes->key_id != PSA_KEY_ID_NULL) {
+ PSA_LOCK();
+ psa_destroy_key(aes->key_id);
+ PSA_UNLOCK();
+
+ aes->key_id = PSA_KEY_ID_NULL;
+ }
+
+ /* we have been invoked from a generic wcSetKey. We don't know the mode that
+ will be used, so we can't import the key in PSA yet. Let's copy the key
+ inside the object, we will import it when we'll know the cipher mode */
+ if (alg == PSA_ALG_NONE) {
+ XMEMCPY(aes->key, key, key_length);
+ aes->key_need_importing = 1;
+ } else {
+ PSA_LOCK();
+ ret = wc_psa_aes_import_key(aes, key, key_length, alg, dir);
+ PSA_UNLOCK();
+ if (ret != 0)
+ return ret;
+ }
+
+ return wc_AesSetIV(aes, iv);
+}
+
+/**
+ * wc_psa_aes_encrypt_decrypt() - do an encrypt/decrypt step
+ * @aes: Aes object
+ * @input: input data
+ * @output: where to store the result of the operation
+ * @length: size of the input data
+ * @alg: algorithm (mode) to use in the operation
+ * @direction: either @AES_ENCRYPT or @AES_DECRYPT
+ *
+ * returns:
+ * 0 on success
+ * BAD_FUNC_ARG for bad argument
+ * WC_HW_E for PSA error
+ */
+int wc_psa_aes_encrypt_decrypt(Aes *aes, const uint8_t *input,
+ uint8_t *output, size_t length,
+ psa_algorithm_t alg, int direction)
+{
+ size_t output_length;
+ psa_status_t s;
+ int r;
+
+ if (aes == NULL || input == NULL || output == NULL)
+ return BAD_FUNC_ARG;
+
+ /* This is the first time we invoke encrypt/decrypt */
+ if (aes->ctx_initialized == 0) {
+
+ /* import the key */
+ if (aes->key_need_importing == 1) {
+ r = wc_psa_aes_import_key(aes, (uint8_t*)aes->key, aes->keylen,
+ alg, direction);
+ if (r != 0)
+ return r;
+
+ ForceZero(aes->key, aes->keylen);
+ aes->key_need_importing = 0;
+ aes->keylen = 0;
+ }
+
+ if (direction == AES_ENCRYPTION) {
+ PSA_LOCK();
+ s = psa_cipher_encrypt_setup(&aes->psa_ctx, aes->key_id, alg);
+ PSA_UNLOCK();
+ } else {
+ PSA_LOCK();
+ s = psa_cipher_decrypt_setup(&aes->psa_ctx, aes->key_id, alg);
+ PSA_UNLOCK();
+ }
+
+ if (s != PSA_SUCCESS)
+ goto err;
+
+ aes->ctx_initialized = 1;
+
+ /* ECB doesn't use IV */
+ if (alg != PSA_ALG_ECB_NO_PADDING) {
+
+ /* wc_SetIV stores the IV in reg */
+ PSA_LOCK();
+ s = psa_cipher_set_iv(&aes->psa_ctx,
+ (uint8_t*)aes->reg, AES_IV_SIZE);
+ PSA_UNLOCK();
+
+ if (s != PSA_SUCCESS)
+ goto err;
+ }
+
+ }
+
+ PSA_LOCK();
+ s = psa_cipher_update(&aes->psa_ctx, input,
+ length, output, length, &output_length);
+ PSA_UNLOCK();
+ if (s != PSA_SUCCESS)
+ goto err;
+
+ if (output_length != length)
+ goto err;
+
+ return 0;
+
+ err:
+ wc_psa_aes_free(aes);
+ return WC_HW_E;
+ }
+
+/**
+ * wc_psa_aes_free() - PSA cipher cleanup
+ * @aes: the Aes object to cleanup
+ */
+int wc_psa_aes_free(Aes *aes)
+{
+ if (aes->key_id != PSA_KEY_ID_NULL) {
+ PSA_LOCK();
+ psa_destroy_key(aes->key_id);
+ PSA_UNLOCK();
+ aes->key_id = PSA_KEY_ID_NULL;
+ }
+
+ if (aes->ctx_initialized == 1) {
+ PSA_LOCK();
+ psa_cipher_abort(&aes->psa_ctx);
+ PSA_UNLOCK();
+ aes->ctx_initialized = 0;
+ }
+
+ aes->ctx_initialized = 0;
+ aes->key_need_importing = 0;
+
+ return 0;
+}
+
+int wc_AesEncrypt(Aes *aes, const byte *inBlock, byte *outBlock)
+{
+ return wc_psa_aes_encrypt_decrypt(aes, inBlock, outBlock,
+ AES_BLOCK_SIZE, PSA_ALG_ECB_NO_PADDING,
+ AES_ENCRYPTION);
+}
+
+#if defined(HAVE_AES_DECRYPT)
+int wc_AesDecrypt(Aes *aes, const byte *inBlock, byte *outBlock)
+{
+ return wc_psa_aes_encrypt_decrypt(aes, inBlock, outBlock,
+ AES_BLOCK_SIZE, PSA_ALG_ECB_NO_PADDING,
+ AES_DECRYPTION);
+}
+#endif
+
+#if defined(WOLFSSL_AES_COUNTER)
+
+int wc_AesCtrEncrypt(Aes *aes, byte *out, const byte *in, word32 sz)
+{
+ return wc_psa_aes_encrypt_decrypt(aes, in, out, sz, PSA_ALG_CTR,
+ AES_ENCRYPTION);
+}
+#endif
+
+#if defined (HAVE_AES_CBC)
+int wc_AesCbcEncrypt(Aes *aes, byte *out, const byte *in, word32 sz)
+{
+
+ if (sz % AES_BLOCK_SIZE != 0)
+#if defined (WOLFSSL_AES_CBC_LENGTH_CHECKS)
+ return BAD_LENGTH_E;
+#else
+ return BAD_FUNC_ARG;
+#endif
+
+ return wc_psa_aes_encrypt_decrypt(aes, in, out, sz,
+ PSA_ALG_CBC_NO_PADDING,
+ AES_ENCRYPTION);
+}
+
+int wc_AesCbcDecrypt(Aes *aes, byte *out, const byte *in, word32 sz)
+{
+
+ if (sz % AES_BLOCK_SIZE != 0)
+#if defined (WOLFSSL_AES_CBC_LENGTH_CHECKS)
+ return BAD_LENGTH_E;
+#else
+ return BAD_FUNC_ARG;
+#endif
+
+ return wc_psa_aes_encrypt_decrypt(aes, in, out, sz,
+ PSA_ALG_CBC_NO_PADDING,
+ AES_DECRYPTION);
+}
+#endif /* HAVE_AES_CBC */
+
+#endif /* ! NO_AES */
+#endif /* ! WOLFSSL_PSA_NO_AES */
+#endif /* WOLFSSL_HAVE_PSA */
diff --git a/wolfcrypt/src/port/psa/psa_hash.c b/wolfcrypt/src/port/psa/psa_hash.c
new file mode 100644
index 000000000..9d3e678ea
--- /dev/null
+++ b/wolfcrypt/src/port/psa/psa_hash.c
@@ -0,0 +1,305 @@
+/* psa_hash.c
+ *
+ * Copyright (C) 2006-2021 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+ #include
+#endif
+
+#include
+
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_HASH)
+
+#if !defined(NO_SHA)
+#include
+#endif
+
+#if !defined(NO_SHA256)
+#include
+#endif
+
+#include
+#include
+
+#if !defined(NO_SHA) || !defined(NO_SHA256) || defined(WOLFSSL_SHA224)
+static int wc_psa_hash_init_and_setup(psa_hash_operation_t *ctx,
+ psa_algorithm_t alg)
+{
+ psa_status_t s;
+
+ if (ctx == NULL)
+ return BAD_FUNC_ARG;
+
+ XMEMSET(ctx, 0, sizeof(*ctx));
+
+ PSA_LOCK();
+ s = psa_hash_setup(ctx, alg);
+ PSA_UNLOCK();
+
+ if (s != PSA_SUCCESS) {
+ PSA_LOCK();
+ psa_hash_abort(ctx);
+ PSA_UNLOCK();
+ return WC_HW_E;
+ }
+
+ return 0;
+}
+
+static int wc_psa_hash_update(psa_hash_operation_t *ctx, const uint8_t *input,
+ size_t input_length)
+{
+ psa_status_t s;
+
+ if (ctx == NULL || (input == NULL && input_length > 0))
+ return BAD_FUNC_ARG;
+
+ PSA_LOCK();
+ s = psa_hash_update(ctx, input, input_length);
+ PSA_UNLOCK();
+
+ if (s != PSA_SUCCESS) {
+ PSA_LOCK();
+ psa_hash_abort(ctx);
+ PSA_UNLOCK();
+ return WC_HW_E;
+ }
+
+ return 0;
+}
+
+static int wc_psa_hash_finish_setup(psa_hash_operation_t *ctx,
+ uint8_t *output, psa_algorithm_t alg)
+{
+ size_t hash_length;
+ psa_status_t s;
+
+ if (ctx == NULL || output == NULL)
+ return BAD_FUNC_ARG;
+
+ PSA_LOCK();
+ s = psa_hash_finish(ctx, output, PSA_HASH_LENGTH(alg), &hash_length);
+ PSA_UNLOCK();
+ if (s != PSA_SUCCESS) {
+ PSA_LOCK();
+ psa_hash_abort(ctx);
+ PSA_UNLOCK();
+ return WC_HW_E;
+ }
+
+ PSA_LOCK();
+ s = psa_hash_setup(ctx, alg);
+ PSA_UNLOCK();
+ if (s != PSA_SUCCESS) {
+ PSA_LOCK();
+ psa_hash_abort(ctx);
+ PSA_UNLOCK();
+ return WC_HW_E;
+ }
+
+ return 0;
+}
+
+static int wc_psa_hash_clone(const psa_hash_operation_t *src,
+ psa_hash_operation_t *dst)
+{
+ psa_status_t s;
+
+ if (src == NULL || dst == NULL)
+ return BAD_FUNC_ARG;
+
+ PSA_LOCK();
+ psa_hash_abort(dst);
+ PSA_UNLOCK();
+
+ PSA_LOCK();
+ s = psa_hash_clone(src, dst);
+ PSA_UNLOCK();
+
+ if (s != PSA_SUCCESS)
+ return WC_HW_E;
+
+ return 0;
+}
+
+static int wc_psa_hash_abort(psa_hash_operation_t *ctx)
+{
+ psa_status_t s;
+
+ if (ctx == NULL)
+ return BAD_FUNC_ARG;
+
+ PSA_LOCK();
+ s = psa_hash_abort(ctx);
+ PSA_UNLOCK();
+ if (s != PSA_SUCCESS)
+ return WC_HW_E;
+
+ return 0;
+}
+
+static int wc_psa_get_hash(psa_hash_operation_t *ctx,
+ uint8_t *out, psa_algorithm_t alg)
+{
+ psa_hash_operation_t tmp;
+ size_t hash_length;
+ psa_status_t s;
+
+ (void)hash_length;
+
+ if (ctx == NULL || out == NULL)
+ return BAD_FUNC_ARG;
+
+ XMEMSET(&tmp, 0, sizeof(tmp));
+ PSA_LOCK();
+ s = psa_hash_clone(ctx, &tmp);
+ PSA_UNLOCK();
+ if (s != PSA_SUCCESS) {
+ psa_hash_abort(&tmp);
+ return WC_HW_E;
+ }
+
+ PSA_LOCK();
+ s = psa_hash_finish(&tmp, out, PSA_HASH_LENGTH(alg), &hash_length);
+ PSA_UNLOCK();
+ if (s != PSA_SUCCESS) {
+ PSA_LOCK();
+ psa_hash_abort(&tmp);
+ PSA_UNLOCK();
+ return WC_HW_E;
+ }
+
+ return 0;
+}
+#endif /* !defined(NO_SHA) || !defined(NO_SHA256) || defined(WOLFSSL_SHA224)*/
+
+#if !defined(NO_SHA)
+
+int wc_InitSha_ex(wc_Sha *sha, void *heap, int devId)
+{
+ (void)heap;
+ (void)devId;
+
+ return wc_psa_hash_init_and_setup(&sha->psa_ctx, PSA_ALG_SHA_1);
+}
+
+int wc_ShaUpdate(wc_Sha *sha, const byte *in, word32 size)
+{
+ return wc_psa_hash_update(&sha->psa_ctx, in, size);
+}
+
+int wc_ShaFinal(wc_Sha *sha, byte *out)
+{
+ return wc_psa_hash_finish_setup(&sha->psa_ctx, out, PSA_ALG_SHA_1);
+}
+
+int wc_ShaGetHash(wc_Sha *sha, byte *out)
+{
+
+ return wc_psa_get_hash(&sha->psa_ctx, out, PSA_ALG_SHA_1);
+}
+
+int wc_ShaCopy(wc_Sha *src, wc_Sha *dst)
+{
+ return wc_psa_hash_clone(&src->psa_ctx, &dst->psa_ctx);
+}
+
+void wc_ShaFree(wc_Sha *sha)
+{
+ wc_psa_hash_abort(&sha->psa_ctx);
+}
+#endif /* !NO_SHA */
+
+#if !defined(NO_SHA256)
+
+int wc_InitSha256_ex(wc_Sha256 *sha, void *heap, int devId)
+{
+ (void)heap;
+ (void)devId;
+
+ return wc_psa_hash_init_and_setup(&sha->psa_ctx, PSA_ALG_SHA_256);
+}
+
+int wc_Sha256Update(wc_Sha256 *sha, const byte *in, word32 size)
+{
+ return wc_psa_hash_update(&sha->psa_ctx, in, size);
+}
+
+int wc_Sha256Final(wc_Sha256 *sha, byte *out)
+{
+ return wc_psa_hash_finish_setup(&sha->psa_ctx, out, PSA_ALG_SHA_256);
+}
+
+int wc_Sha256GetHash(wc_Sha256 *sha, byte *out)
+{
+ return wc_psa_get_hash(&sha->psa_ctx, out, PSA_ALG_SHA_256);
+}
+
+int wc_Sha256Copy(wc_Sha256 *src, wc_Sha256 *dst)
+{
+ return wc_psa_hash_clone(&src->psa_ctx, &dst->psa_ctx);
+}
+
+void wc_Sha256Free(wc_Sha256 *sha)
+{
+ wc_psa_hash_abort(&sha->psa_ctx);
+}
+
+#endif /* !NO_SHA256 */
+
+#if defined(WOLFSSL_SHA224)
+
+int wc_InitSha224_ex(wc_Sha224 *sha, void *heap, int devId)
+{
+ (void)heap;
+ (void)devId;
+
+ return wc_psa_hash_init_and_setup(&sha->psa_ctx, PSA_ALG_SHA_224);
+}
+
+int wc_Sha224Update(wc_Sha224 *sha, const byte *in, word32 size)
+{
+ return wc_psa_hash_update(&sha->psa_ctx, in, size);
+}
+
+int wc_Sha224Final(wc_Sha224 *sha, byte *out)
+{
+ return wc_psa_hash_finish_setup(&sha->psa_ctx, out, PSA_ALG_SHA_224);
+}
+
+int wc_Sha224GetHash(wc_Sha224 *sha, byte *out)
+{
+ return wc_psa_get_hash(&sha->psa_ctx, out, PSA_ALG_SHA_224);
+}
+
+int wc_Sha224Copy(wc_Sha224 *src, wc_Sha224 *dst)
+{
+ return wc_psa_hash_clone(&src->psa_ctx, &dst->psa_ctx);
+}
+
+void wc_Sha224Free(wc_Sha224 *sha)
+{
+ wc_psa_hash_abort(&sha->psa_ctx);
+}
+
+#endif /* WOLFSSL_SHA224 */
+
+#endif /* WOLFSSL_HAVE_PSA && !WOLFSSL_PSA_NO_HASH */
diff --git a/wolfcrypt/src/port/psa/psa_pkcbs.c b/wolfcrypt/src/port/psa/psa_pkcbs.c
new file mode 100644
index 000000000..12a69a667
--- /dev/null
+++ b/wolfcrypt/src/port/psa/psa_pkcbs.c
@@ -0,0 +1,546 @@
+/* psa_pkcbs.c
+ *
+ * Copyright (C) 2006-2021 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+#ifdef HAVE_CONFIG_H
+ #include
+#endif
+
+#include
+
+#if defined(WOLFSSL_HAVE_PSA)
+#if defined(HAVE_PK_CALLBACKS)
+#if !defined(WOLFSSL_PSA_NO_PKCBS)
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_ECC
+
+#include
+
+static int psa_ecc_get_curve_info_from_curve_id(int ecc_curve,
+ psa_ecc_family_t *family,
+ size_t *key_size)
+{
+ if (ecc_curve != ECC_SECP256R1)
+ return NOT_COMPILED_IN;
+
+ *family = PSA_ECC_FAMILY_SECP_R1;
+ if (key_size != NULL)
+ *key_size = 32;
+
+ return 0;
+}
+
+/**
+ * psa_ecc_export_to_wc_key() - export psa @key_id into ecc_key @key
+ * @key: already initialized ecc_key to export the key into [out]
+ * @key_id: key to export [in]
+ * @key_size: size fo the key [in]
+ * @curve_id: wc id of the curve [in]
+ *
+ * returns 0 on success
+ */
+static int psa_ecc_export_to_wc_key(struct ecc_key *key,
+ psa_key_id_t key_id,
+ int curve_id)
+{
+ uint8_t raw[(MAX_ECC_BYTES * 2) + 1];
+ psa_status_t status;
+ size_t length;
+ int ret;
+
+ PSA_LOCK();
+ status = psa_export_public_key(key_id,
+ raw, sizeof(raw), &length);
+ PSA_UNLOCK();
+
+ if (status != PSA_SUCCESS) {
+ WOLFSSL_MSG("PSA: export key error");
+ return WC_HW_E;
+ }
+
+ ret = wc_ecc_import_x963_ex(raw, (word32)length, key, curve_id);
+ if (ret != 0) {
+ WOLFSSL_MSG("PSA: import key error");
+ return WC_HW_E;
+ }
+
+ return 0;
+}
+
+static int psa_ecc_keygen(int ecc_curve, unsigned key_size,
+ psa_key_id_t *key_id)
+{
+ psa_key_attributes_t key_attr = { 0 };
+ size_t ecc_curve_key_size;
+ psa_ecc_family_t family;
+ psa_status_t status;
+ int ret;
+
+ ret = psa_ecc_get_curve_info_from_curve_id(ecc_curve, &family,
+ &ecc_curve_key_size);
+ if (ret != 0)
+ return ret;
+
+ if (key_size != 0 && key_size != ecc_curve_key_size)
+ return BAD_FUNC_ARG;
+
+ psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(family));
+ psa_set_key_bits(&key_attr, ecc_curve_key_size * 8);
+ psa_set_key_algorithm(&key_attr, PSA_ALG_ECDH);
+ psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_DERIVE);
+
+ PSA_LOCK();
+ status = psa_generate_key(&key_attr, key_id);
+ PSA_UNLOCK();
+ if (status != PSA_SUCCESS)
+ return WC_HW_E;
+
+ return 0;
+}
+
+static int psa_ecc_keygen_cb(WOLFSSL* ssl, struct ecc_key* key,
+ unsigned int key_size, int ecc_curve, void* ctx)
+{
+ struct psa_ssl_ctx *psa_ctx = (struct psa_ssl_ctx *)ctx;
+ psa_key_id_t psa_key_id;
+ int ret;
+
+ (void)ssl;
+
+ WOLFSSL_ENTER("psa_ecc_keygen_cb");
+
+ if (psa_ctx == NULL)
+ return BAD_FUNC_ARG;
+
+ ret = psa_ecc_keygen(ecc_curve, key_size, &psa_key_id);
+ if (ret != 0)
+ return WC_HW_E;
+
+ ret = psa_ecc_export_to_wc_key(key, psa_key_id, ecc_curve);
+ if (ret != 0) {
+ PSA_LOCK();
+ psa_destroy_key(psa_key_id);
+ PSA_UNLOCK();
+ return WC_HW_E;
+ }
+
+ psa_ctx->dh_key = psa_key_id;
+
+ return 0;
+}
+
+static int psa_ecc_shared_secret_tls12_client(struct ecc_key* other_key,
+ unsigned char* pubKeyDer,
+ word32* pubKeySz,
+ unsigned char* out,
+ word32* output_size)
+{
+ uint8_t raw[(MAX_ECC_BYTES * 2) + 1];
+ psa_status_t status;
+ word32 raw_length;
+ psa_key_id_t key;
+ size_t length;
+ int ret;
+
+ ret = psa_ecc_keygen(other_key->dp->id, 0, &key);
+ if (ret != 0)
+ return ret;
+
+ PSA_LOCK();
+ status = psa_export_public_key(key, pubKeyDer, *pubKeySz, &length);
+ PSA_UNLOCK();
+ if (status != PSA_SUCCESS) {
+ ret = WC_HW_E;
+ goto exit;
+ }
+
+ *pubKeySz = (word32)length;
+
+ raw_length = (word32)sizeof(raw);
+ ret = wc_ecc_export_x963_ex(other_key, raw, &raw_length, 0);
+ if (ret != 0)
+ goto exit;
+
+ PSA_LOCK();
+ status = psa_raw_key_agreement(PSA_ALG_ECDH, key,
+ raw, raw_length,
+ out, *output_size,
+ &length);
+ PSA_UNLOCK();
+ if (status != PSA_SUCCESS) {
+ ret = WC_HW_E;
+ goto exit;
+ }
+
+ *output_size = (word32)length;
+ ret = 0;
+
+ exit:
+ PSA_LOCK();
+ psa_destroy_key(key);
+ PSA_UNLOCK();
+
+ return ret;
+}
+
+static int psa_ecc_shared_secret_cb(WOLFSSL* ssl, struct ecc_key* other_key,
+ unsigned char* pubKeyDer, word32* pubKeySz,
+ unsigned char* out, word32* output_size,
+ int side, void* ctx)
+{
+ struct psa_ssl_ctx *psa_ctx = (struct psa_ssl_ctx *)ctx;
+ size_t output_length;
+ psa_status_t status;
+
+ if (psa_ctx == NULL)
+ return BAD_FUNC_ARG;
+
+ WOLFSSL_ENTER("psa_ecc_shared_secret_cb");
+
+ /* client before tls13 must create the key and export it in pubkeyDer. The
+ server key is stored in other_key */
+ if (side == WOLFSSL_CLIENT_END &&
+ wolfSSL_GetVersion(ssl) < WOLFSSL_TLSV1_3) {
+ return psa_ecc_shared_secret_tls12_client(other_key,
+ pubKeyDer, pubKeySz,
+ out, output_size);
+ }
+
+ PSA_LOCK();
+ status = psa_raw_key_agreement(PSA_ALG_ECDH,
+ psa_ctx->dh_key,
+ pubKeyDer,
+ *pubKeySz,
+ out, *output_size,
+ &output_length);
+ PSA_UNLOCK();
+
+ if (status != PSA_SUCCESS) {
+ WOLFSSL_MSG("PSA: error raw_key_agreement");
+ return WC_HW_E;
+ }
+
+ *output_size = (word32)output_length;
+
+ PSA_LOCK();
+ psa_destroy_key(psa_ctx->dh_key);
+ PSA_UNLOCK();
+
+ psa_ctx->dh_key = PSA_KEY_ID_NULL;
+
+ return 0;
+}
+
+static int psa_ecc_sign_cb(WOLFSSL* ssl, const unsigned char* input,
+ unsigned int input_length,
+ unsigned char* signature, word32* signature_size,
+ const unsigned char* keyDer, unsigned int keySz,
+ void* ctx)
+{
+ struct psa_ssl_ctx *psa_ctx = (struct psa_ssl_ctx*)ctx;
+ uint8_t rs[MAX_ECC_BYTES * 2];
+ psa_status_t status;
+ size_t rs_length;
+ word32 point_len;
+ int ret;
+
+ (void)ssl;
+ (void)keyDer;
+ (void)keySz;
+
+ WOLFSSL_ENTER("psa_ecc_sign_cb");
+
+ if (psa_ctx == NULL)
+ return BAD_FUNC_ARG;
+
+ status = psa_sign_hash(psa_ctx->private_key,
+ PSA_ALG_ECDSA_ANY, input,
+ input_length, rs, sizeof(rs),
+ &rs_length);
+ if (status != PSA_SUCCESS)
+ return WC_HW_E;
+
+ point_len = (word32)(rs_length / 2);
+ ret = wc_ecc_rs_raw_to_sig(rs, point_len, rs + point_len, point_len,
+ signature, signature_size);
+ if (ret != 0)
+ return -1;
+
+ return 0;
+}
+
+static int psa_ecc_decode_public_key(const uint8_t *key, word32 key_length,
+ psa_key_id_t *key_id)
+{
+ uint8_t raw_key[(MAX_ECC_BYTES * 2) + 1];
+ psa_key_attributes_t attr = { 0 };
+ word32 raw_key_length, idx;
+ psa_ecc_family_t ecc_curve;
+ size_t ecc_curve_size;
+ psa_status_t status;
+ ecc_key tmp_key;
+ int ret;
+
+ ret = wc_ecc_init(&tmp_key);
+ if (ret != 0 )
+ return ret;
+
+ idx = 0;
+ ret = wc_EccPublicKeyDecode(key, &idx, &tmp_key, key_length);
+ if (ret != 0 )
+ goto exit;
+
+ raw_key_length = (word32)sizeof(raw_key);
+ ret = wc_ecc_export_x963_ex(&tmp_key, raw_key, &raw_key_length, 0);
+ if (ret != 0 )
+ goto exit;
+
+ ret = psa_ecc_get_curve_info_from_curve_id(tmp_key.dp->id,
+ &ecc_curve, &ecc_curve_size);
+ if (ret != 0 )
+ goto exit;
+
+ psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(ecc_curve));
+ psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_VERIFY_HASH);
+ psa_set_key_bits(&attr, ecc_curve_size * 8);
+ psa_set_key_algorithm(&attr, PSA_ALG_ECDSA_ANY);
+
+ PSA_LOCK();
+ status = psa_import_key(&attr, raw_key, raw_key_length, key_id);
+ PSA_UNLOCK();
+ if (status != PSA_SUCCESS) {
+ WOLFSSL_MSG("psa_ecc_decode_public_key: can't import the key");
+ ret = WC_HW_E;
+ goto exit;
+ }
+
+ ret = 0;
+
+exit:
+ wc_ecc_free(&tmp_key);
+ return ret;
+}
+
+static int psa_ecc_verify_cb(WOLFSSL* ssl, const byte* sig, word32 sig_length,
+ const byte* hash, word32 hash_length,
+ const byte* key, word32 key_length,
+ int* result, void* ctx)
+{
+ uint8_t raw_signature[MAX_ECC_BYTES * 2], *s;
+ psa_key_id_t tmp_key;
+ word32 r_len, s_len;
+ psa_status_t status;
+ int ret;
+
+ (void)ssl;
+ (void)ctx;
+ WOLFSSL_ENTER("psa_ecc_verify_cb");
+
+ ret = psa_ecc_decode_public_key(key, key_length, &tmp_key);
+ if (ret != 0)
+ return ret;
+
+ r_len = s_len = MAX_ECC_BYTES;
+ s = raw_signature + r_len;
+ ret = wc_ecc_sig_to_rs(sig, sig_length, raw_signature, &r_len,
+ s, &s_len);
+ if (ret != 0)
+ goto exit;
+
+ /* coalescence of r and s in the buffer */
+ XMEMCPY(raw_signature + r_len, s, s_len);
+
+ PSA_LOCK();
+ status = psa_verify_hash(tmp_key, PSA_ALG_ECDSA_ANY, hash,
+ hash_length, raw_signature, r_len + s_len);
+ PSA_UNLOCK();
+
+ if (status == PSA_SUCCESS) {
+ *result = 1;
+ } else {
+ *result = 0;
+
+ if (status != PSA_ERROR_INVALID_SIGNATURE) {
+ WOLFSSL_MSG("psa_ecc_verify_cb: can't verify hash");
+ ret = WC_HW_E;
+ }
+
+ /* returns 0 for invalid signature as well */
+ }
+
+ exit:
+ PSA_LOCK();
+ psa_destroy_key(tmp_key);
+ PSA_UNLOCK();
+
+ return ret;
+}
+#endif /* HAVE_ECC */
+
+#ifdef HAVE_HKDF
+static int psa_hkdf_extract_cb(byte* prk, const byte* salt,
+ word32 salt_length, byte* ikm,
+ word32 ikm_length, int digest,
+ void* ctx)
+{
+ psa_key_attributes_t attr = { 0 };
+ psa_algorithm_t hash;
+ psa_key_id_t tmp_key;
+ psa_status_t status;
+ size_t digest_len;
+
+ (void)ctx;
+
+ WOLFSSL_ENTER("psa hkdf cb");
+
+ if (salt_length != 0 && salt == NULL)
+ return BAD_FUNC_ARG;
+
+ switch (digest) {
+#ifndef NO_SHA256
+ case WC_SHA256:
+ digest_len = WC_SHA256_DIGEST_SIZE;
+ hash = PSA_ALG_SHA_256;
+ break;
+#endif
+#ifdef WOLFSSL_SHA384
+ case WC_SHA384:
+ digest_len = WC_SHA384_DIGEST_SIZE;
+ hash = PSA_ALG_SHA_384;
+ break;
+#endif
+ default:
+ return BAD_FUNC_ARG;
+ }
+
+ psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC);
+ psa_set_key_algorithm(&attr, PSA_ALG_HMAC(hash));
+ psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_MESSAGE);
+
+ /* salt not provided, use zeroed digest len string. Use temporarily the prk
+ buffer as we are sure is big enough */
+ if (salt == NULL) {
+ XMEMSET(prk, 0, digest_len);
+ salt = prk;
+ salt_length = (word32)digest_len;
+ }
+
+ /* When length is 0 then use zeroed data of digest length. */
+ if (ikm_length == 0) {
+ ikm_length = (word32)digest_len;
+ XMEMSET(ikm, 0, digest_len);
+ }
+
+ PSA_LOCK();
+ status = psa_import_key(&attr, salt, salt_length, &tmp_key);
+ PSA_UNLOCK();
+ if (status != PSA_SUCCESS) {
+ WOLFSSL_MSG("psa_hkdf_cb: failed to import tmp key");
+ return WC_HW_E;
+ }
+
+ PSA_LOCK();
+ status = psa_mac_compute(tmp_key, PSA_ALG_HMAC(hash),
+ ikm, ikm_length, prk, digest_len,
+ &digest_len);
+ PSA_UNLOCK();
+ if (status != PSA_SUCCESS) {
+ WOLFSSL_MSG("psa_hkdf_cb: failed to compute hashed mac");
+ PSA_LOCK();
+ psa_destroy_key(tmp_key);
+ PSA_UNLOCK();
+ return WC_HW_E;
+ }
+
+ PSA_LOCK();
+ psa_destroy_key(tmp_key);
+ PSA_UNLOCK();
+
+ return 0;
+}
+#endif /* HAVE_HKDF */
+
+int wolfSSL_psa_set_private_key_id(struct psa_ssl_ctx *ctx, psa_key_id_t id)
+{
+ if (ctx == NULL)
+ return BAD_FUNC_ARG;
+ if (id == PSA_KEY_ID_NULL)
+ return BAD_FUNC_ARG;
+
+ ctx->private_key = id;
+
+ return WOLFSSL_SUCCESS;
+}
+
+void wolfSSL_free_psa_ctx(struct psa_ssl_ctx *ctx)
+{
+ if (ctx->dh_key != PSA_KEY_ID_NULL) {
+ PSA_LOCK();
+ psa_destroy_key(ctx->dh_key);
+ PSA_UNLOCK();
+ ctx->dh_key = PSA_KEY_ID_NULL;
+ }
+}
+
+int wolfSSL_set_psa_ctx(WOLFSSL *ssl, struct psa_ssl_ctx *ctx)
+{
+ if (ctx == NULL || ssl == NULL)
+ return BAD_FUNC_ARG;
+
+#ifdef HAVE_ECC
+ wolfSSL_SetEccSignCtx(ssl, ctx);
+ wolfSSL_SetEccKeyGenCtx(ssl, ctx);
+ wolfSSL_SetEccSharedSecretCtx(ssl, ctx);
+ wolfSSL_SetEccVerifyCtx(ssl, ctx);
+#endif
+#ifdef HAVE_HKDF
+ wolfSSL_SetHKDFExtractCtx(ssl, ctx);
+#endif
+
+ return WOLFSSL_SUCCESS;
+}
+
+int wolfSSL_CTX_psa_enable(WOLFSSL_CTX *ctx)
+{
+ if (ctx == NULL)
+ return BAD_FUNC_ARG;
+
+#ifdef HAVE_ECC
+ wolfSSL_CTX_SetEccSignCb(ctx, psa_ecc_sign_cb);
+ wolfSSL_CTX_SetEccKeyGenCb(ctx, psa_ecc_keygen_cb);
+ wolfSSL_CTX_SetEccSharedSecretCb(ctx, psa_ecc_shared_secret_cb);
+ wolfSSL_CTX_SetEccVerifyCb(ctx, psa_ecc_verify_cb);
+#endif
+#ifdef HAVE_HKDF
+ wolfSSL_CTX_SetHKDFExtractCb(ctx, psa_hkdf_extract_cb);
+#endif
+ return WOLFSSL_SUCCESS;
+}
+
+#endif /* !WOLFSSL_PSA_NO_PKCBS */
+#endif /* HAVE_PK_CALLBACKS */
+#endif /* WOLFSSL_HAVE_PSA */
diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c
index 35ee476bf..330308160 100644
--- a/wolfcrypt/src/random.c
+++ b/wolfcrypt/src/random.c
@@ -177,6 +177,10 @@ int wc_RNG_GenerateByte(WC_RNG* rng, byte* b)
#include
#endif
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_RNG)
+#include
+#endif
+
#if defined(HAVE_INTEL_RDRAND) || defined(HAVE_INTEL_RDSEED)
static word32 intel_flags = 0;
static void wc_InitRng_IntelRD(void)
diff --git a/wolfcrypt/src/sha.c b/wolfcrypt/src/sha.c
index 9df07ef14..bc38ae4f6 100644
--- a/wolfcrypt/src/sha.c
+++ b/wolfcrypt/src/sha.c
@@ -370,6 +370,8 @@
return ret;
}
+#elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_HASH)
+/* implemented in wolfcrypt/src/port/psa/psa_hash.c */
#else
/* Software implementation */
#define USE_SHA_SOFTWARE_IMPL
@@ -832,6 +834,8 @@ int wc_InitSha(wc_Sha* sha)
return wc_InitSha_ex(sha, NULL, INVALID_DEVID);
}
+#if !defined(WOLFSSL_HAVE_PSA) || defined(WOLFSSL_PSA_NO_HASH)
+
void wc_ShaFree(wc_Sha* sha)
{
if (sha == NULL)
@@ -859,6 +863,7 @@ void wc_ShaFree(wc_Sha* sha)
#endif
}
+#endif /* !defined(WOLFSSL_HAVE_PSA) || defined(WOLFSSL_PSA_NO_HASH) */
#endif /* !WOLFSSL_TI_HASH */
#endif /* HAVE_FIPS */
@@ -866,6 +871,8 @@ void wc_ShaFree(wc_Sha* sha)
#if !defined(WOLFSSL_RENESAS_TSIP_CRYPT) || \
defined(NO_WOLFSSL_RENESAS_TSIP_CRYPT_HASH)
+
+#if !defined(WOLFSSL_HAVE_PSA) || defined(WOLFSSL_PSA_NO_HASH)
int wc_ShaGetHash(wc_Sha* sha, byte* hash)
{
int ret;
@@ -929,7 +936,7 @@ int wc_ShaCopy(wc_Sha* src, wc_Sha* dst)
}
#endif /* defined(WOLFSSL_RENESAS_TSIP_CRYPT) ... */
#endif /* !WOLFSSL_TI_HASH && !WOLFSSL_IMXRT_DCP */
-
+#endif /* !defined(WOLFSSL_HAVE_PSA) || defined(WOLFSSL_PSA_NO_HASH) */
#ifdef WOLFSSL_HASH_FLAGS
int wc_ShaSetFlags(wc_Sha* sha, word32 flags)
diff --git a/wolfcrypt/src/sha256.c b/wolfcrypt/src/sha256.c
index 6f9ea6191..45dcb433f 100644
--- a/wolfcrypt/src/sha256.c
+++ b/wolfcrypt/src/sha256.c
@@ -185,7 +185,8 @@ where 0 <= L < 2^64.
(!defined(WOLFSSL_RENESAS_TSIP_CRYPT) || defined(NO_WOLFSSL_RENESAS_TSIP_HASH)) && \
!defined(WOLFSSL_PSOC6_CRYPTO) && !defined(WOLFSSL_IMXRT_DCP) && !defined(WOLFSSL_SILABS_SE_ACCEL) && \
!defined(WOLFSSL_KCAPI_HASH) && !defined(WOLFSSL_SE050_HASH) && \
- (!defined(WOLFSSL_RENESAS_SCEPROTECT) || defined(NO_WOLFSSL_RENESAS_SCEPROTECT_HASH))
+ (!defined(WOLFSSL_RENESAS_SCEPROTECT) || defined(NO_WOLFSSL_RENESAS_SCEPROTECT_HASH)) && \
+ (!defined(WOLFSSL_HAVE_PSA) || defined(WOLFSSL_PSA_NO_HASH))
@@ -765,6 +766,9 @@ static int InitSha256(wc_Sha256* sha256)
#elif defined(WOLFSSL_KCAPI_HASH)
/* implemented in wolfcrypt/src/port/kcapi/kcapi_hash.c */
+#elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_HASH)
+ /* implemented in wolfcrypt/src/port/psa/psa_hash.c */
+
#else
#define NEED_SOFT_SHA256
@@ -1459,6 +1463,9 @@ static int InitSha256(wc_Sha256* sha256)
#elif defined(WOLFSSL_KCAPI_HASH) && !defined(WOLFSSL_NO_KCAPI_SHA224)
/* implemented in wolfcrypt/src/port/kcapi/kcapi_hash.c */
+#elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_HASH)
+ /* implemented in wolfcrypt/src/port/psa/psa_hash.c */
+
#else
#define NEED_SOFT_SHA224
@@ -1582,6 +1589,9 @@ static int InitSha256(wc_Sha256* sha256)
return wc_InitSha224_ex(sha224, NULL, INVALID_DEVID);
}
+#if !defined(WOLFSSL_HAVE_PSA) || defined(WOLFSSL_PSA_NO_HASH)
+ /* implemented in wolfcrypt/src/port/psa/psa_hash.c */
+
void wc_Sha224Free(wc_Sha224* sha224)
{
if (sha224 == NULL)
@@ -1606,6 +1616,7 @@ static int InitSha256(wc_Sha256* sha256)
#endif
}
#endif /* WOLFSSL_SHA224 */
+#endif /* !defined(WOLFSSL_HAVE_PSA) || defined(WOLFSSL_PSA_NO_HASH) */
int wc_InitSha256(wc_Sha256* sha256)
@@ -1613,6 +1624,9 @@ int wc_InitSha256(wc_Sha256* sha256)
return wc_InitSha256_ex(sha256, NULL, INVALID_DEVID);
}
+#if !defined(WOLFSSL_HAVE_PSA) || defined(WOLFSSL_PSA_NO_HASH)
+ /* implemented in wolfcrypt/src/port/psa/psa_hash.c */
+
void wc_Sha256Free(wc_Sha256* sha256)
{
if (sha256 == NULL)
@@ -1664,6 +1678,7 @@ void wc_Sha256Free(wc_Sha256* sha256)
#endif
}
+#endif /* !defined(WOLFSSL_HAVE_PSA) || defined(WOLFSSL_PSA_NO_HASH) */
#endif /* !WOLFSSL_TI_HASH */
#endif /* HAVE_FIPS */
@@ -1673,6 +1688,8 @@ void wc_Sha256Free(wc_Sha256* sha256)
#if defined(WOLFSSL_KCAPI_HASH) && !defined(WOLFSSL_NO_KCAPI_SHA224)
/* implemented in wolfcrypt/src/port/kcapi/kcapi_hash.c */
+#elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_HASH)
+ /* implemented in wolfcrypt/src/port/psa/psa_hash.c */
#else
@@ -1762,6 +1779,9 @@ void wc_Sha256Free(wc_Sha256* sha256)
#elif defined(WOLFSSL_KCAPI_HASH)
/* implemented in wolfcrypt/src/port/kcapi/kcapi_hash.c */
+#elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_HASH)
+ /* implemented in wolfcrypt/src/port/psa/psa_hash.c */
+
#else
int wc_Sha256GetHash(wc_Sha256* sha256, byte* hash)
diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c
index 695ea7e2f..bd3a27d0c 100644
--- a/wolfcrypt/src/wc_port.c
+++ b/wolfcrypt/src/wc_port.c
@@ -112,6 +112,11 @@
#pragma warning(disable: 4996)
#endif
+#if defined(WOLFSSL_HAVE_PSA)
+ #include
+#endif
+
+
/* prevent multiple mutex initializations */
static volatile int initRefCount = 0;
@@ -270,6 +275,11 @@ int wolfCrypt_Init(void)
}
#endif
+ #if defined(WOLFSSL_HAVE_PSA)
+ if ((ret = wc_psa_init()) != 0)
+ return ret;
+ #endif
+
#ifdef HAVE_ECC
#ifdef FP_ECC
wc_ecc_fp_init();
diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c
index 56818857b..e9de88aff 100644
--- a/wolfcrypt/test/test.c
+++ b/wolfcrypt/test/test.c
@@ -7702,11 +7702,14 @@ static int aes_key_size_test(void)
ERROR_OUT(-5307, out);
/* CryptoCell handles rounds internally */
#if !defined(HAVE_FIPS) && !defined(WOLFSSL_CRYPTOCELL)
+ /* PSA don't use aes->rounds */
+#if !defined(WOLFSSL_HAVE_PSA) || defined(WOLFSSL_PSA_NO_AES)
/* Force invalid rounds */
aes->rounds = 16;
ret = wc_AesGetKeySize(aes, &keySize);
if (ret != BAD_FUNC_ARG)
ERROR_OUT(-5308, out);
+#endif
#endif
ret = wc_AesSetKey(aes, key16, sizeof(key16), iv, AES_ENCRYPTION);
@@ -7909,7 +7912,6 @@ static int aes_xts_128_test(void)
ERROR_OUT(-5410, out);
if (XMEMCMP(p1, buf, AES_BLOCK_SIZE))
ERROR_OUT(-5411, out);
- wc_AesXtsFree(aes);
/* fail case with decrypting using wrong key */
XMEMSET(buf, 0, sizeof(buf));
@@ -7922,6 +7924,8 @@ static int aes_xts_128_test(void)
if (XMEMCMP(p2, buf, sizeof(p2)) == 0) /* fail case with wrong key */
ERROR_OUT(-5413, out);
+ wc_AesXtsFree(aes);
+
/* set correct key and retest */
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(aes, k2, sizeof(k2), AES_DECRYPTION,
diff --git a/wolfssl/wolfcrypt/aes.h b/wolfssl/wolfcrypt/aes.h
index 18f2cd0b8..921b3219c 100644
--- a/wolfssl/wolfcrypt/aes.h
+++ b/wolfssl/wolfcrypt/aes.h
@@ -96,6 +96,10 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits
#include
#endif
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES)
+#include
+#endif
+
#if defined(WOLFSSL_CRYPTOCELL)
#include
#endif
@@ -270,6 +274,12 @@ struct Aes {
#endif
#if defined(WOLFSSL_SILABS_SE_ACCEL)
silabs_aes_t ctx;
+#endif
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_AES)
+ psa_key_id_t key_id;
+ psa_cipher_operation_t psa_ctx;
+ int ctx_initialized;
+ int key_need_importing;
#endif
void* heap; /* memory hint to use */
#ifdef WOLFSSL_AESGCM_STREAM
diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am
index d39d435cb..9bf1d9a8d 100644
--- a/wolfssl/wolfcrypt/include.am
+++ b/wolfssl/wolfcrypt/include.am
@@ -171,3 +171,7 @@ endif
if BUILD_IOTSAFE
nobase_include_HEADERS+= wolfssl/wolfcrypt/port/iotsafe/iotsafe.h
endif
+
+if BUILD_PSA
+nobase_include_HEADERS+= wolfssl/wolfcrypt/port/psa/psa.h
+endif
diff --git a/wolfssl/wolfcrypt/port/psa/psa.h b/wolfssl/wolfcrypt/port/psa/psa.h
new file mode 100644
index 000000000..e4683b28b
--- /dev/null
+++ b/wolfssl/wolfcrypt/port/psa/psa.h
@@ -0,0 +1,127 @@
+/* psa.h
+ *
+ * Copyright (C) 2006-2021 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
+/**
+ * Platform Security Architecture (PSA) header
+ *
+ * If WOLFSSL_HAVE_PSA is defined, wolfSSL can use the cryptographic primitives
+ * exported by a PSA Crypto API.
+ *
+ * Defines:
+ *
+ * WOLFSSL_HAVE_PSA: Global switch to enable PSA
+ * WOLFSSL_PSA_NO_RNG: disable PSA random generator support
+ * WOLFSSL_PSA_NO_HASH: disable PSA hashing support
+ * WOLFSSL_PSA_NO_AES: disable PSA AES support
+ * WOLFSSL_PSA_GLOBAL_LOCK: serialize the access to the underlying PSA lib
+ * WOLFSSL_PSA_NO_PKCBS: disable PK callbacks support
+ */
+
+#ifndef WOLFSSL_PSA_H
+#define WOLFSSL_PSA_H
+
+#ifdef HAVE_CONFIG_H
+ #include
+#endif
+
+#include
+
+/* PSA implementation takes over the Sha struct and Sha functions implementation
+ completely. Devoiding the struct of the DevId field and hooks to make
+ crypto_cb work. */
+#if !defined(WOLFSSL_PSA_NO_HASH) && defined(WOLF_CRYPTO_CB)
+#error "WOLFSSL PSA is not supported with WOLF_CRYPTO_CB"
+#endif
+
+#if defined(WOLFSSL_HAVE_PSA)
+
+#include
+#include
+#include
+
+#if !defined(WOLFSSL_PSA_NO_AES)
+#if !defined(NO_AES)
+#include
+#endif
+#endif /* WOLFSSL_PSA_NO_AES */
+
+#if !defined(WOLFSSL_PSA_NO_PKCB)
+#include
+#endif
+
+#if defined(WOLFSSL_PSA_GLOBAL_LOCK)
+void PSA_LOCK(void);
+void PSA_UNLOCK(void);
+#else
+#define PSA_LOCK()
+#define PSA_UNLOCK()
+#endif
+
+int wc_psa_init(void);
+
+#if !defined(WOLFSSL_PSA_NO_RNG)
+
+WOLFSSL_API int wc_psa_get_random(unsigned char *out, word32 sz);
+#ifndef HAVE_HASHDRBG
+#define CUSTOM_RAND_GENERATE_BLOCK wc_psa_get_random
+#else
+#define CUSTOM_RAND_GENERATE_SEED wc_psa_get_random
+#endif
+
+#endif /* WOLFSSL_HAVE_PSA_RNG */
+
+#if !defined(WOLFSSL_PSA_NO_AES) && !defined(NO_AES)
+
+int wc_psa_aes_init(Aes *aes);
+int wc_psa_aes_free(Aes *aes);
+int wc_psa_aes_get_key_size(Aes *aes, word32 *keySize);
+int wc_psa_aes_set_key(Aes *aes, const uint8_t *key,
+ size_t key_length, uint8_t *iv,
+ psa_algorithm_t alg, int dir);
+
+WOLFSSL_API int wc_psa_aes_encrypt_decrypt(Aes *aes, const uint8_t *input,
+ uint8_t *output, size_t length,
+ psa_algorithm_t alg, int direction);
+
+WOLFSSL_API int wc_AesEncrypt(Aes *aes, const byte *inBlock, byte *outBlock);
+
+#if defined(HAVE_AES_DECRYPT)
+WOLFSSL_API int wc_AesDecrypt(Aes *aes, const byte *inBlock, byte *outBlock);
+#endif
+
+#endif
+
+#if defined(HAVE_PK_CALLBACKS) && !defined(WOLFSSL_PSA_NO_PKCB)
+
+struct psa_ssl_ctx {
+ psa_key_id_t private_key;
+ psa_key_id_t dh_key;
+};
+
+WOLFSSL_API int wolfSSL_CTX_psa_enable(WOLFSSL_CTX *ctx);
+WOLFSSL_API int wolfSSL_set_psa_ctx(WOLFSSL *ssl, struct psa_ssl_ctx *ctx);
+WOLFSSL_API void wolfSSL_free_psa_ctx(struct psa_ssl_ctx *ctx);
+WOLFSSL_API int wolfSSL_psa_set_private_key_id(struct psa_ssl_ctx *ctx,
+ psa_key_id_t id);
+#endif
+
+#endif /* WOLFSSL_HAVE_PSA */
+#endif /* WOLFSSL_PSA_H */
diff --git a/wolfssl/wolfcrypt/sha.h b/wolfssl/wolfcrypt/sha.h
index 1f3de3b09..ad93830cd 100644
--- a/wolfssl/wolfcrypt/sha.h
+++ b/wolfssl/wolfcrypt/sha.h
@@ -114,6 +114,12 @@ enum {
#include "wolfssl/wolfcrypt/port/nxp/se050_port.h"
#endif
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_HASH)
+#include
+#undef WOLFSSL_NO_HASH_RAW
+#define WOLFSSL_NO_HASH_RAW
+#endif
+
/* Sha digest */
struct wc_Sha {
#ifdef FREESCALE_LTC_SHA
@@ -127,6 +133,8 @@ struct wc_Sha {
#elif defined(WOLFSSL_IMXRT_DCP)
dcp_handle_t handle;
dcp_hash_ctx_t ctx;
+#elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_HASH)
+ psa_hash_operation_t psa_ctx;
#else
word32 buffLen; /* in bytes */
word32 loLen; /* length in bytes */
diff --git a/wolfssl/wolfcrypt/sha256.h b/wolfssl/wolfcrypt/sha256.h
index 1f5030604..56a9ae859 100644
--- a/wolfssl/wolfcrypt/sha256.h
+++ b/wolfssl/wolfcrypt/sha256.h
@@ -105,6 +105,12 @@
#include "wolfssl/wolfcrypt/port/kcapi/kcapi_hash.h"
#endif
+#if defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_HASH)
+#include
+#undef WOLFSSL_NO_HASH_RAW
+#define WOLFSSL_NO_HASH_RAW
+#endif
+
#if defined(_MSC_VER)
#define SHA256_NOINLINE __declspec(noinline)
#elif defined(__IAR_SYSTEMS_ICC__) || defined(__GNUC__)
@@ -168,6 +174,8 @@ struct wc_Sha256 {
cy_stc_crypto_sha_state_t hash_state;
cy_en_crypto_sha_mode_t sha_mode;
cy_stc_crypto_v2_sha256_buffers_t sha_buffers;
+#elif defined(WOLFSSL_HAVE_PSA) && !defined(WOLFSSL_PSA_NO_HASH)
+ psa_hash_operation_t psa_ctx;
#else
/* alignment on digest and buffer speeds up ARMv8 crypto operations */
ALIGN16 word32 digest[WC_SHA256_DIGEST_SIZE / sizeof(word32)];