Crypto: Add support for HMAC functionalities
This patch introduces support for the HMAC functionalities.
The HMAC construction procedure is as described by RFC-2104.
It also adds the related Regression test suite to validate
the API implementation.
Change-Id: I622d866b34ba7e3a3e61e1a28d43fb80e49fd8ec
Signed-off-by: Louis Mayencourt <louis.mayencourt@arm.com>
diff --git a/docs/user_guides/services/tfm_crypto_integration_guide.md b/docs/user_guides/services/tfm_crypto_integration_guide.md
index c58ea9b..c16b102 100644
--- a/docs/user_guides/services/tfm_crypto_integration_guide.md
+++ b/docs/user_guides/services/tfm_crypto_integration_guide.md
@@ -50,7 +50,9 @@
- `crypto_engine.c` : This file implements the layer which the other modules
use to interact with the cryptography primitives available (in SW or HW).
The current implementation provides only SW primitives based on Mbed TLS
- functions.
+ functions;
+ - `crypto_mac.c` : This file implements functionalities related to the
+ MAC (Message Authentication Code) module.
## Crypto service integration guide
diff --git a/interface/include/tfm_crypto_defs.h b/interface/include/tfm_crypto_defs.h
index 391df84..ed85dc8 100644
--- a/interface/include/tfm_crypto_defs.h
+++ b/interface/include/tfm_crypto_defs.h
@@ -25,7 +25,13 @@
* \brief This defines the maximum supported key length in bytes
*
*/
-#define TFM_CRYPTO_MAX_KEY_LENGTH (16)
+#define TFM_CRYPTO_MAX_KEY_LENGTH (32)
+
+/**
+ * \brief This value is used to mark an handle as invalid.
+ *
+ */
+#define TFM_CRYPTO_INVALID_HANDLE (0xFFFFFFFF)
/**
* \brief Define miscellaneous literal constants that are used in the module
diff --git a/interface/include/tfm_crypto_veneers.h b/interface/include/tfm_crypto_veneers.h
index 5079901..312c2c3 100644
--- a/interface/include/tfm_crypto_veneers.h
+++ b/interface/include/tfm_crypto_veneers.h
@@ -243,6 +243,106 @@
enum tfm_crypto_err_t tfm_crypto_veneer_hash_abort(
psa_hash_operation_t *operation);
+/**
+ * \brief Start a MAC operation with the provided algorithm (for signing)
+ * (veneer function)
+ *
+ * \note A successful call to this function initialises a MAC operation
+ * context which will be referred using the operation parameter
+ *
+ * \param[out] operation MAC operation context
+ * \param[in] key Key slot to bind to the MAC context
+ * \param[in] alg Algorithm chosen as MAC
+ *
+ * \return Return values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_veneer_mac_sign_setup(
+ psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg);
+/**
+ * \brief Start a MAC operation with the provided algorithm (for verifying)
+ * (veneer function)
+ *
+ * \note A successful call to this function initialises a MAC operation
+ * context which will be referred using the operation parameter
+ *
+ * \param[out] operation MAC operation context
+ * \param[in] key Key slot to bind to the MAC context
+ * \param[in] alg Algorithm chosen as MAC
+ *
+ * \return Return values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_veneer_mac_verify_setup(
+ psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg);
+/**
+ * \brief Adds a new input chunk to the data for which the final MAC value
+ * will be computed (veneer function)
+ *
+ * \param[in/out] operation MAC operation context
+ * \param[in] input Buffer containing the input data
+ * \param[in] input_length Size of the provided input data
+ *
+ * \return Return values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_veneer_mac_update(
+ psa_mac_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length);
+
+/**
+ * \brief Finalises a MAC context operation producing the final MAC value
+ * (veneer function)
+ *
+ * \note A successful call to this function releases the MAC operation
+ * context provided as parameter
+ *
+ * \param[in/out] operation MAC operation context
+ * \param[out] mac Buffer containing MAC data
+ * \param[in] mac_size Size of the MAC buffer
+ * \param[out] mac_length Size of the produced MAC
+ *
+ * \return Return values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_veneer_mac_sign_finish(
+ psa_mac_operation_t *operation,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length);
+/**
+ * \brief Finalise a MAC context operation, verifying that the final MAC value
+ * matches the one provided as input (veneer function)
+ *
+ * \note A successful call to this function releases the MAC operation
+ * context provided as parameter. The MAC operation is released
+ * also in case TFM_CRYPTO_ERR_PSA_ERROR_INVALID_SIGNATURE is returned
+ *
+ * \param[in/out] operation MAC operation context
+ * \param[in] mac Buffer containing the provided MAC value
+ * \param[in] mac_length Size of the provided MAC value
+ *
+ * \return Return values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_veneer_mac_verify_finish(
+ psa_mac_operation_t *operation,
+ const uint8_t *mac,
+ size_t mac_length);
+/**
+ * \brief Abort a MAC operation, clear the operation context provided
+ * (veneer function)
+ *
+ * \note A successful call to this function releases the MAC operation
+ * context provided as parameter
+ *
+ * \param[in/out] operation MAC operation context
+ *
+ * \return Return values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_veneer_mac_abort(
+ psa_mac_operation_t *operation);
+
#ifdef __cplusplus
}
#endif
diff --git a/interface/src/tfm_crypto_api.c b/interface/src/tfm_crypto_api.c
index 7eb0669..a1bf389 100644
--- a/interface/src/tfm_crypto_api.c
+++ b/interface/src/tfm_crypto_api.c
@@ -263,3 +263,92 @@
return TFM_CRYPTO_ERR_TO_PSA_STATUS(err);
}
+
+psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg)
+{
+ enum tfm_crypto_err_t err;
+
+ err = tfm_ns_lock_dispatch((veneer_fn)tfm_crypto_veneer_mac_sign_setup,
+ (uint32_t)operation,
+ (uint32_t)key,
+ (uint32_t)alg,
+ 0);
+
+ return TFM_CRYPTO_ERR_TO_PSA_STATUS(err);
+}
+
+psa_status_t psa_mac_verify_setup(psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg)
+{
+ enum tfm_crypto_err_t err;
+
+ err = tfm_ns_lock_dispatch((veneer_fn)tfm_crypto_veneer_mac_verify_setup,
+ (uint32_t)operation,
+ (uint32_t)key,
+ (uint32_t)alg,
+ 0);
+
+ return TFM_CRYPTO_ERR_TO_PSA_STATUS(err);
+}
+
+psa_status_t psa_mac_update(psa_mac_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length)
+{
+ enum tfm_crypto_err_t err;
+
+ err = tfm_ns_lock_dispatch((veneer_fn)tfm_crypto_veneer_mac_update,
+ (uint32_t)operation,
+ (uint32_t)input,
+ (uint32_t)input_length,
+ 0);
+
+ return TFM_CRYPTO_ERR_TO_PSA_STATUS(err);
+}
+
+psa_status_t psa_mac_sign_finish(psa_mac_operation_t *operation,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length)
+{
+ enum tfm_crypto_err_t err;
+
+ err = tfm_ns_lock_dispatch((veneer_fn)tfm_crypto_veneer_mac_sign_finish,
+ (uint32_t)operation,
+ (uint32_t)mac,
+ (uint32_t)mac_size,
+ (uint32_t)mac_length);
+
+ return TFM_CRYPTO_ERR_TO_PSA_STATUS(err);
+}
+
+psa_status_t psa_mac_verify_finish(psa_mac_operation_t *operation,
+ const uint8_t *mac,
+ size_t mac_length)
+{
+ enum tfm_crypto_err_t err;
+
+ err = tfm_ns_lock_dispatch((veneer_fn)tfm_crypto_veneer_mac_verify_finish,
+ (uint32_t)operation,
+ (uint32_t)mac,
+ (uint32_t)mac_length,
+ 0);
+
+ return TFM_CRYPTO_ERR_TO_PSA_STATUS(err);
+}
+
+psa_status_t psa_mac_abort(psa_mac_operation_t *operation)
+{
+ enum tfm_crypto_err_t err;
+
+ err = tfm_ns_lock_dispatch((veneer_fn)tfm_crypto_veneer_mac_abort,
+ (uint32_t)operation,
+ 0,
+ 0,
+ 0);
+
+ return TFM_CRYPTO_ERR_TO_PSA_STATUS(err);
+}
diff --git a/secure_fw/ns_callable/tfm_crypto_veneers.c b/secure_fw/ns_callable/tfm_crypto_veneers.c
index 07f6979..7f8208d 100644
--- a/secure_fw/ns_callable/tfm_crypto_veneers.c
+++ b/secure_fw/ns_callable/tfm_crypto_veneers.c
@@ -159,3 +159,62 @@
TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_hash_abort,
operation, 0, 0, 0);
}
+
+__tfm_secure_gateway_attributes__
+enum tfm_crypto_err_t tfm_crypto_veneer_mac_sign_setup(
+ psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg)
+{
+ TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_mac_sign_setup,
+ operation, key, alg, 0);
+}
+
+__tfm_secure_gateway_attributes__
+enum tfm_crypto_err_t tfm_crypto_veneer_mac_verify_setup(
+ psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg)
+{
+ TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_mac_verify_setup,
+ operation, key, alg, 0);
+}
+
+__tfm_secure_gateway_attributes__
+enum tfm_crypto_err_t tfm_crypto_veneer_mac_update(
+ psa_mac_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length)
+{
+ TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_mac_update,
+ operation, input, input_length, 0);
+}
+
+__tfm_secure_gateway_attributes__
+enum tfm_crypto_err_t tfm_crypto_veneer_mac_sign_finish(
+ psa_mac_operation_t *operation,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length)
+{
+ TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_mac_sign_finish,
+ operation, mac, mac_size, mac_length);
+}
+
+__tfm_secure_gateway_attributes__
+enum tfm_crypto_err_t tfm_crypto_veneer_mac_verify_finish(
+ psa_mac_operation_t *operation,
+ const uint8_t *mac,
+ size_t mac_length)
+{
+ TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_mac_verify_finish,
+ operation, mac, mac_length, 0);
+}
+
+__tfm_secure_gateway_attributes__
+enum tfm_crypto_err_t tfm_crypto_veneer_mac_abort(
+ psa_mac_operation_t *operation)
+{
+ TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_mac_abort,
+ operation, 0, 0, 0);
+}
diff --git a/secure_fw/services/crypto/CMakeLists.inc b/secure_fw/services/crypto/CMakeLists.inc
index 5ee5dd9..18dcbb0 100644
--- a/secure_fw/services/crypto/CMakeLists.inc
+++ b/secure_fw/services/crypto/CMakeLists.inc
@@ -45,6 +45,7 @@
"${CRYPTO_DIR}/crypto_alloc.c"
"${CRYPTO_DIR}/crypto_cipher.c"
"${CRYPTO_DIR}/crypto_hash.c"
+ "${CRYPTO_DIR}/crypto_mac.c"
"${CRYPTO_DIR}/crypto_key.c"
"${CRYPTO_DIR}/crypto_wrappers.c"
"${CRYPTO_DIR}/crypto_utils.c"
diff --git a/secure_fw/services/crypto/crypto_alloc.c b/secure_fw/services/crypto/crypto_alloc.c
index 119e664..2a4d6bd 100644
--- a/secure_fw/services/crypto/crypto_alloc.c
+++ b/secure_fw/services/crypto/crypto_alloc.c
@@ -21,12 +21,6 @@
*/
#define TFM_CRYPTO_CONC_OPER_NUM (8)
-/**
- * \brief This value is used to mark an handle as invalid.
- *
- */
-#define INVALID_HANDLE (0xFFFFFFFF)
-
struct tfm_crypto_operation_s {
uint32_t in_use; /*!< Indicates if the operation is in use */
enum tfm_crypto_operation_type type; /*!< Type of the operation */
@@ -93,7 +87,7 @@
return TFM_CRYPTO_ERR_PSA_SUCCESS;
}
}
- *handle = INVALID_HANDLE;
+ *handle = TFM_CRYPTO_INVALID_HANDLE;
return TFM_CRYPTO_ERR_PSA_ERROR_NOT_PERMITTED;
}
@@ -107,7 +101,7 @@
memset_operation_context(i);
operation[i].in_use = TFM_CRYPTO_NOT_IN_USE;
operation[i].type = TFM_CRYPTO_OPERATION_NONE;
- *handle = INVALID_HANDLE;
+ *handle = TFM_CRYPTO_INVALID_HANDLE;
return TFM_CRYPTO_ERR_PSA_SUCCESS;
}
diff --git a/secure_fw/services/crypto/crypto_mac.c b/secure_fw/services/crypto/crypto_mac.c
new file mode 100644
index 0000000..a068830
--- /dev/null
+++ b/secure_fw/services/crypto/crypto_mac.c
@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "secure_fw/core/secure_utilities.h"
+#include "tfm_crypto_defs.h"
+
+#include "psa_crypto.h"
+
+#include "tfm_crypto_struct.h"
+
+#include "tfm_crypto_api.h"
+#include "crypto_utils.h"
+
+static void mac_zeroize(void *data, size_t size)
+{
+ tfm_memset(data, 0, size);
+}
+
+static size_t get_hash_block_size(psa_algorithm_t alg)
+{
+ switch (alg) {
+ case PSA_ALG_MD2:
+ return 16;
+ case PSA_ALG_MD4:
+ return 64;
+ case PSA_ALG_MD5:
+ return 64;
+ case PSA_ALG_RIPEMD160:
+ return 64;
+ case PSA_ALG_SHA_1:
+ return 64;
+ case PSA_ALG_SHA_224:
+ return 64;
+ case PSA_ALG_SHA_256:
+ return 64;
+ case PSA_ALG_SHA_384:
+ return 128;
+ case PSA_ALG_SHA_512:
+ return 128;
+ default:
+ return 0;
+ }
+}
+
+static enum tfm_crypto_err_t tfm_crypto_hmac_setup(
+ struct tfm_mac_operation_s *ctx,
+ psa_key_slot_t key,
+ psa_algorithm_t alg)
+{
+ enum tfm_crypto_err_t err;
+ psa_key_type_t key_type;
+ size_t key_size;
+ uint8_t key_data[TFM_CRYPTO_MAX_KEY_LENGTH];
+ uint8_t hashed_key[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
+ size_t block_size;
+ uint8_t ipad[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
+ uint8_t *opad = ctx->ctx.hmac.opad;
+ size_t i;
+
+ /* Check provided key */
+ err = tfm_crypto_get_key_information(key, &key_type, &key_size);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ if (key_type != PSA_KEY_TYPE_HMAC){
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Get the key data to start the HMAC */
+ err = tfm_crypto_export_key(key,
+ &key_data[0],
+ TFM_CRYPTO_MAX_KEY_LENGTH,
+ &key_size);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ /* Bind the digest size to the MAC operation */
+ ctx->mac_size = PSA_HASH_SIZE(PSA_ALG_HMAC_HASH(alg));
+
+ block_size = get_hash_block_size(PSA_ALG_HMAC_HASH(alg));
+
+ /* The HMAC algorithm is the standard procedure as described in
+ * RFC-2104 (https://tools.ietf.org/html/rfc2104)
+ */
+ if (key_size > block_size) {
+ /* Hash the key to reduce it to block size */
+ err = tfm_crypto_hash_setup(&(ctx->ctx.hmac.hash_operation),
+ PSA_ALG_HMAC_HASH(alg));
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ err = tfm_crypto_hash_update(&(ctx->ctx.hmac.hash_operation),
+ &key_data[0],
+ key_size);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ tfm_crypto_hash_abort(&(ctx->ctx.hmac.hash_operation));
+ return err;
+ }
+
+ /* Replace the key with the hashed key */
+ err = tfm_crypto_hash_finish(&(ctx->ctx.hmac.hash_operation),
+ hashed_key, sizeof(hashed_key),
+ &key_size);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ tfm_crypto_hash_abort(&(ctx->ctx.hmac.hash_operation));
+ return err;
+ }
+ } else {
+ /* Copy the key inside the hashed_key buffer */
+ for (i=0; i<key_size; i++) {
+ hashed_key[i] = key_data[i];
+ }
+ }
+
+ /* Create ipad = hashed_key XOR 0x36 and opad = hashed_key XOR 0x5C */
+ for (i=0; i<key_size; i++) {
+ ipad[i] = hashed_key[i] ^ 0x36;
+ opad[i] = hashed_key[i] ^ 0x5C;
+ }
+ /* Fill ipad and opad to match block size */
+ for (i=key_size; i<block_size; i++) {
+ ipad[i] = 0x36;
+ opad[i] = 0x5C;
+ }
+
+ /* Start hash1 = H(i_key_pad || message) */
+ err = tfm_crypto_hash_setup(&(ctx->ctx.hmac.hash_operation),
+ PSA_ALG_HMAC_HASH(alg));
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ /* Clear key information on stack */
+ for (i=0; i<key_size; i++) {
+ hashed_key[i] = 0;
+ ipad[i] = 0;
+ }
+ return err;
+ }
+
+ err = tfm_crypto_hash_update(&(ctx->ctx.hmac.hash_operation),
+ ipad,
+ block_size);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ tfm_crypto_hash_abort(&(ctx->ctx.hmac.hash_operation));
+ return err;
+ }
+
+ return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+static enum tfm_crypto_err_t tfm_crypto_mac_setup(psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg,
+ uint8_t sign_operation)
+{
+ enum tfm_crypto_err_t err;
+
+ struct tfm_mac_operation_s *ctx = NULL;
+
+ if (!PSA_ALG_IS_MAC(alg)) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ /* Validate pointers */
+ err = tfm_crypto_memory_check(operation,
+ sizeof(psa_mac_operation_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Allocate the operation context in the secure world */
+ err = tfm_crypto_operation_alloc(TFM_CRYPTO_MAC_OPERATION,
+ &(operation->handle));
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ /* Look up the corresponding operation context */
+ err = tfm_crypto_operation_lookup(TFM_CRYPTO_MAC_OPERATION,
+ operation->handle,
+ (void **)&ctx);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(&(operation->handle));
+ return err;
+ }
+
+ /* Bind the algorithm to the mac operation */
+ ctx->alg = alg;
+
+ /* Specify if this will be used for a sign or verify operation */
+ if (sign_operation) {
+ ctx->key_usage_verify = 0;
+ ctx->key_usage_sign = 1;
+ } else {
+ ctx->key_usage_verify = 1;
+ ctx->key_usage_sign = 0;
+ }
+
+ if (PSA_ALG_IS_HMAC(alg)) {
+ err = tfm_crypto_hmac_setup(ctx, key, alg);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ /* Release the operation context */
+ tfm_crypto_operation_release(&(operation->handle));
+ return err;
+ }
+
+ ctx->key_set = 1;
+ } else {
+ /* Other MAC types constructions are not supported */
+ /* Release the operation context */
+ tfm_crypto_operation_release(&(operation->handle));
+ return TFM_CRYPTO_ERR_PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+static enum tfm_crypto_err_t tfm_crypto_mac_finish(
+ struct tfm_mac_operation_s *ctx,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length)
+{
+ enum tfm_crypto_err_t err;
+ uint8_t hash1[PSA_HASH_MAX_SIZE];
+ size_t hash_size;
+ uint8_t *opad;
+ size_t block_size;
+
+ /* Sanity checks */
+ if (mac_size < ctx->mac_size) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ if (!(ctx->has_input)) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_BAD_STATE;
+ }
+
+ if (PSA_ALG_IS_HMAC(ctx->alg)) {
+ opad = ctx->ctx.hmac.opad;
+ block_size = get_hash_block_size(PSA_ALG_HMAC_HASH(ctx->alg));
+
+ /* finish the hash1 = H(ipad || message) */
+ err = tfm_crypto_hash_finish(&(ctx->ctx.hmac.hash_operation),
+ hash1,
+ sizeof(hash1),
+ &hash_size);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ /* compute the final mac value = H(opad || hash1) */
+ err = tfm_crypto_hash_setup(&(ctx->ctx.hmac.hash_operation),
+ PSA_ALG_HMAC_HASH(ctx->alg));
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ mac_zeroize(hash1, sizeof(hash1));
+ return err;
+ }
+
+ err = tfm_crypto_hash_update(&(ctx->ctx.hmac.hash_operation),
+ opad,
+ block_size);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ mac_zeroize(hash1, sizeof(hash1));
+ return err;
+ }
+
+ err = tfm_crypto_hash_update(&(ctx->ctx.hmac.hash_operation),
+ hash1,
+ hash_size);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ mac_zeroize(hash1, sizeof(hash1));
+ return err;
+ }
+
+ err = tfm_crypto_hash_finish(&(ctx->ctx.hmac.hash_operation),
+ mac,
+ mac_size,
+ mac_length);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ mac_zeroize(hash1, sizeof(hash1));
+ return err;
+ }
+
+ /* Clear intermediate hash value */
+ mac_zeroize(hash1, sizeof(hash1));
+
+ } else {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Clear the mac context */
+ mac_zeroize(ctx, sizeof(struct tfm_mac_operation_s));
+
+ return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+/*!
+ * \defgroup public_psa Public functions, PSA
+ *
+ */
+
+/*!@{*/
+enum tfm_crypto_err_t tfm_crypto_mac_sign_setup(psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg)
+{
+ return tfm_crypto_mac_setup(operation, key, alg, 1);
+}
+
+enum tfm_crypto_err_t tfm_crypto_mac_verify_setup(
+ psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg)
+{
+ return tfm_crypto_mac_setup(operation, key, alg, 0);
+}
+
+enum tfm_crypto_err_t tfm_crypto_mac_update(psa_mac_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length)
+{
+ enum tfm_crypto_err_t err;
+
+ struct tfm_mac_operation_s *ctx = NULL;
+
+ if (input_length == 0) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Validate pointers */
+ err = tfm_crypto_memory_check(operation,
+ sizeof(psa_mac_operation_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ err = tfm_crypto_memory_check((void *)input,
+ input_length,
+ TFM_MEMORY_ACCESS_RO);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Look up the corresponding operation context */
+ err = tfm_crypto_operation_lookup(TFM_CRYPTO_MAC_OPERATION,
+ operation->handle,
+ (void **)&ctx);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ /* Sanity check */
+ if (!(ctx->key_set)) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_BAD_STATE;
+ }
+
+ /* Process the input chunk */
+ if (PSA_ALG_IS_HMAC(ctx->alg)) {
+ err = tfm_crypto_hash_update(&(ctx->ctx.hmac.hash_operation),
+ input,
+ input_length);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ /* Set this flag to avoid HMAC without data */
+ ctx->has_input = 1;
+ } else {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+enum tfm_crypto_err_t tfm_crypto_mac_sign_finish(psa_mac_operation_t *operation,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length)
+{
+ enum tfm_crypto_err_t err;
+ struct tfm_mac_operation_s *ctx = NULL;
+
+ if (mac_size == 0) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Validate pointers */
+ err = tfm_crypto_memory_check(operation,
+ sizeof(psa_mac_operation_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ err = tfm_crypto_memory_check((void *)mac,
+ mac_size,
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ err = tfm_crypto_memory_check(mac_length,
+ sizeof(size_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Look up the corresponding operation context */
+ err = tfm_crypto_operation_lookup(TFM_CRYPTO_MAC_OPERATION,
+ operation->handle,
+ (void **)&ctx);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ if ((ctx->key_usage_sign == 1) && (ctx->key_usage_verify == 0)) {
+ /* Finalise the mac operation */
+ err = tfm_crypto_mac_finish(ctx, mac, mac_size, mac_length);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+ /* Release the operation context */
+ err = tfm_crypto_operation_release(&(operation->handle));
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+ } else {
+ return TFM_CRYPTO_ERR_PSA_ERROR_BAD_STATE;
+ }
+
+ return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+enum tfm_crypto_err_t tfm_crypto_mac_verify_finish(
+ psa_mac_operation_t *operation,
+ const uint8_t *mac,
+ size_t mac_length)
+{
+ enum tfm_crypto_err_t err;
+ struct tfm_mac_operation_s *ctx = NULL;
+ uint8_t computed_mac[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
+ size_t computed_mac_length;
+ size_t i;
+ uint32_t comp_mismatch = 0;
+
+ if (mac_length == 0) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Validate pointers */
+ err = tfm_crypto_memory_check(operation,
+ sizeof(psa_mac_operation_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ err = tfm_crypto_memory_check((void *)mac,
+ mac_length,
+ TFM_MEMORY_ACCESS_RO);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Look up the corresponding operation context */
+ err = tfm_crypto_operation_lookup(TFM_CRYPTO_MAC_OPERATION,
+ operation->handle,
+ (void **)&ctx);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ if ((ctx->key_usage_sign == 0) && (ctx->key_usage_verify == 1)) {
+ /* Finalise the mac operation */
+ err = tfm_crypto_mac_finish(ctx,
+ computed_mac,
+ sizeof(computed_mac),
+ &computed_mac_length);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+ /* Release the operation context */
+ err = tfm_crypto_operation_release(&(operation->handle));
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ /* Check that the computed mac match the expected one */
+ if (computed_mac_length != mac_length) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ for (i=0; i<computed_mac_length ; i++) {
+ if (computed_mac[i] != mac[i]) {
+ comp_mismatch = 1;
+ }
+ }
+
+ if (comp_mismatch == 1) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_SIGNATURE;
+ }
+ } else {
+ return TFM_CRYPTO_ERR_PSA_ERROR_BAD_STATE;
+ }
+
+ return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+enum tfm_crypto_err_t tfm_crypto_mac_abort(psa_mac_operation_t *operation)
+{
+ enum tfm_crypto_err_t err;
+ struct tfm_mac_operation_s *ctx = NULL;
+
+ /* Validate pointers */
+ err = tfm_crypto_memory_check(operation,
+ sizeof(psa_mac_operation_t),
+ TFM_MEMORY_ACCESS_RW);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Look up the corresponding operation context */
+ err = tfm_crypto_operation_lookup(TFM_CRYPTO_MAC_OPERATION,
+ operation->handle,
+ (void **)&ctx);
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+
+ if (PSA_ALG_IS_HMAC(ctx->alg)){
+ /* Check if the HMAC internal context needs to be deallocated */
+ if (ctx->ctx.hmac.hash_operation.handle != TFM_CRYPTO_INVALID_HANDLE) {
+ /* Clear hash context */
+ err = tfm_crypto_hash_abort(&(ctx->ctx.hmac.hash_operation));
+ if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+ return err;
+ }
+ }
+
+ /* Release the operation context */
+ tfm_crypto_operation_release(&(operation->handle));
+ } else {
+ /* MACs other than HMACs not currently supported */
+ return TFM_CRYPTO_ERR_PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+/*!@}*/
diff --git a/secure_fw/services/crypto/manifest.yaml b/secure_fw/services/crypto/manifest.yaml
index f8fa5d3..c6037a9 100644
--- a/secure_fw/services/crypto/manifest.yaml
+++ b/secure_fw/services/crypto/manifest.yaml
@@ -137,6 +137,54 @@
"minor_version": 1,
"minor_policy": "strict"
},
+ {
+ "sfid": "TFM_CRYPTO_MAC_SIGN_SETUP_SFID",
+ "signal": "TFM_CRYPTO_MAC_SIGN_SETUP",
+ "tfm_symbol": "tfm_crypto_mac_sign_setup",
+ "non_secure_clients": true,
+ "minor_version": 1,
+ "minor_policy": "strict"
+ },
+ {
+ "sfid": "TFM_CRYPTO_MAC_VERIFY_SETUP_SFID",
+ "signal": "TFM_CRYPTO_MAC_VERIFY_SETUP",
+ "tfm_symbol": "tfm_crypto_mac_verify_setup",
+ "non_secure_clients": true,
+ "minor_version": 1,
+ "minor_policy": "strict"
+ },
+ {
+ "sfid": "TFM_CRYPTO_MAC_UPDATE_SFID",
+ "signal": "TFM_CRYPTO_MAC_UPDATE",
+ "tfm_symbol": "tfm_crypto_mac_update",
+ "non_secure_clients": true,
+ "minor_version": 1,
+ "minor_policy": "strict"
+ },
+ {
+ "sfid": "TFM_CRYPTO_MAC_SIGN_FINISH_SFID",
+ "signal": "TFM_CRYPTO_MAC_SIGN_FINISH",
+ "tfm_symbol": "tfm_crypto_mac_sign_finish",
+ "non_secure_clients": true,
+ "minor_version": 1,
+ "minor_policy": "strict"
+ },
+ {
+ "sfid": "TFM_CRYPTO_MAC_VERIFY_FINISH_SFID",
+ "signal": "TFM_CRYPTO_MAC_VERIFY_FINISH",
+ "tfm_symbol": "tfm_crypto_mac_verify_finish",
+ "non_secure_clients": true,
+ "minor_version": 1,
+ "minor_policy": "strict"
+ },
+ {
+ "sfid": "TFM_CRYPTO_MAC_ABORT_SFID",
+ "signal": "TFM_CRYPTO_MAC_ABORT",
+ "tfm_symbol": "tfm_crypto_mac_abort",
+ "non_secure_clients": true,
+ "minor_version": 1,
+ "minor_policy": "strict"
+ },
],
"source_files": [
"crypto_alloc.c",
@@ -147,6 +195,7 @@
"crypto_utils.c",
"crypto_hash.c",
"crypto_engine.c",
+ "crypto_mac.c"
],
"tfm_linker_pattern": [
"library_list": [
diff --git a/secure_fw/services/crypto/tfm_crypto_api.h b/secure_fw/services/crypto/tfm_crypto_api.h
index 488b432..3638885 100644
--- a/secure_fw/services/crypto/tfm_crypto_api.h
+++ b/secure_fw/services/crypto/tfm_crypto_api.h
@@ -324,6 +324,87 @@
*/
enum tfm_crypto_err_t tfm_crypto_hash_abort(psa_hash_operation_t *operation);
+/**
+ * \brief Start a MAC operation with the provided algorithm (for signing)
+ *
+ * \note A successful call to this function initialises a MAC operation
+ * context which will be referred using the operation parameter
+ *
+ * \param[out] operation MAC operation context
+ * \param[in] key Key slot to bind to the MAC context
+ * \param[in] alg Algorithm chosen as MAC
+ *
+ * \return Return values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_mac_sign_setup(psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg);
+/**
+ * \brief Start a MAC operation with the provided algorithm (for verifying)
+ *
+ * \note A successful call to this function initialises a MAC operation
+ * context which will be referred using the operation parameter
+ *
+ * \param[out] operation MAC operation context
+ * \param[in] key Key slot to bind to the MAC context
+ * \param[in] alg Algorithm chosen as MAC
+ *
+ * \return Return values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_mac_verify_setup(
+ psa_mac_operation_t *operation,
+ psa_key_slot_t key,
+ psa_algorithm_t alg);
+/**
+ * \brief Adds a new input chunk to the data for which the final MAC value
+ * will be computed
+ *
+ * \param[in] operation MAC operation context
+ * \param[in] input Buffer containing the input data
+ * \param[in] input_length Size of the provided input data
+ *
+ * \return Return values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_mac_update(psa_mac_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length);
+/**
+ * \brief Finalise a MAC context operation producing the final MAC value
+ *
+ * \param[in/out] operation Mac operation context
+ * \param[out] mac Buffer containing MAC data
+ * \param[in] mac_size Size of the mac buffer
+ * \param[out] mac_length Size of the produced mac
+ *
+ * \return Return values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_mac_sign_finish(psa_mac_operation_t *operation,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length);
+/**
+ * \brief Finalise a MAC context operation, verifying that the final MAC value
+ * matches the one provided as input
+ *
+ * \param[in/out] operation MAC operation context
+ * \param[in] mac Buffer containing the provided MAC value
+ * \param[in] mac_length Size of the provided MAC value
+ *
+ * \return Return values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_mac_verify_finish(
+ psa_mac_operation_t *operation,
+ const uint8_t *mac,
+ size_t mac_length);
+/**
+ * \brief Abort a MAC operation, clear the operation context provided
+ *
+ * \param[in/out] operation MAC operation context
+ *
+ * \return Return values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_mac_abort(psa_mac_operation_t *operation);
+
#ifdef __cplusplus
}
#endif
diff --git a/secure_fw/services/tfm_sfid_list.inc b/secure_fw/services/tfm_sfid_list.inc
index 80ebb98..0a38ac1 100644
--- a/secure_fw/services/tfm_sfid_list.inc
+++ b/secure_fw/services/tfm_sfid_list.inc
@@ -42,6 +42,12 @@
{tfm_crypto_hash_finish, TFM_CRYPTO_HASH_FINISH_SFID},
{tfm_crypto_hash_verify, TFM_CRYPTO_HASH_VERIFY_SFID},
{tfm_crypto_hash_abort, TFM_CRYPTO_HASH_ABORT_SFID},
+ {tfm_crypto_mac_sign_setup, TFM_CRYPTO_MAC_SIGN_SETUP_SFID},
+ {tfm_crypto_mac_verify_setup, TFM_CRYPTO_MAC_VERIFY_SETUP_SFID},
+ {tfm_crypto_mac_update, TFM_CRYPTO_MAC_UPDATE_SFID},
+ {tfm_crypto_mac_sign_finish, TFM_CRYPTO_MAC_SIGN_FINISH_SFID},
+ {tfm_crypto_mac_verify_finish, TFM_CRYPTO_MAC_VERIFY_FINISH_SFID},
+ {tfm_crypto_mac_abort, TFM_CRYPTO_MAC_ABORT_SFID},
/******** TFM_SP_PLATFORM ********/
{platform_sp_system_reset, TFM_SP_PLATFORM_SYSTEM_RESET_SFID},
diff --git a/test/suites/crypto/non_secure/crypto_ns_interface_testsuite.c b/test/suites/crypto/non_secure/crypto_ns_interface_testsuite.c
index 06a5a47..6511564 100644
--- a/test/suites/crypto/non_secure/crypto_ns_interface_testsuite.c
+++ b/test/suites/crypto/non_secure/crypto_ns_interface_testsuite.c
@@ -10,6 +10,7 @@
#include "psa_crypto.h"
#define BIT_SIZE_TEST_KEY (128)
+#define BIT_SIZE_TEST_LONG_KEY (256)
#define BYTE_SIZE_TEST_KEY (BIT_SIZE_TEST_KEY/8)
#define BYTE_SIZE_CHUNK (16)
#define ENC_DEC_BUFFER_SIZE (32)
@@ -29,6 +30,12 @@
static void tfm_crypto_test_6008(struct test_result_t *ret);
static void tfm_crypto_test_6009(struct test_result_t *ret);
static void tfm_crypto_test_6010(struct test_result_t *ret);
+static void tfm_crypto_test_6011(struct test_result_t *ret);
+static void tfm_crypto_test_6012(struct test_result_t *ret);
+static void tfm_crypto_test_6013(struct test_result_t *ret);
+static void tfm_crypto_test_6014(struct test_result_t *ret);
+static void tfm_crypto_test_6015(struct test_result_t *ret);
+static void tfm_crypto_test_6016(struct test_result_t *ret);
static struct test_t crypto_veneers_tests[] = {
{&tfm_crypto_test_6001, "TFM_CRYPTO_TEST_6001",
@@ -51,6 +58,18 @@
"Non Secure Hash (MD-5) interface", {0} },
{&tfm_crypto_test_6010, "TFM_CRYPTO_TEST_6010",
"Non Secure Hash (RIPEMD-160) interface", {0} },
+ {&tfm_crypto_test_6011, "TFM_CRYPTO_TEST_6011",
+ "Non Secure HMAC (SHA-1) interface", {0} },
+ {&tfm_crypto_test_6012, "TFM_CRYPTO_TEST_6012",
+ "Non Secure HMAC (SHA-256) interface", {0} },
+ {&tfm_crypto_test_6013, "TFM_CRYPTO_TEST_6013",
+ "Non Secure HMAC (SHA-384) interface", {0} },
+ {&tfm_crypto_test_6014, "TFM_CRYPTO_TEST_6014",
+ "Non Secure HMAC (SHA-512) interface", {0} },
+ {&tfm_crypto_test_6015, "TFM_CRYPTO_TEST_6015",
+ "Non Secure HMAC (MD-5) interface", {0} },
+ {&tfm_crypto_test_6016, "TFM_CRYPTO_TEST_6016",
+ "Non Secure HMAC with long key (SHA-1) interface", {0} },
};
void register_testsuite_ns_crypto_interface(struct test_suite_t *p_test_suite)
@@ -488,3 +507,177 @@
{
psa_hash_test(PSA_ALG_RIPEMD160, ret);
}
+
+static const uint8_t hmac_val[][PSA_HASH_SIZE(PSA_ALG_SHA_512)] = {
+ {0x0d, 0xa6, 0x9d, 0x02, 0x43, 0x17, 0x3e, 0x7e, /*!< SHA-1 */
+ 0xe7, 0x3b, 0xc6, 0xa9, 0x51, 0x06, 0x8a, 0xea,
+ 0x12, 0xb0, 0xa7, 0x1d},
+ {0xc1, 0x9f, 0x19, 0xac, 0x05, 0x65, 0x5f, 0x02, /*!< SHA-224 */
+ 0x1b, 0x64, 0x32, 0xd9, 0xb1, 0x49, 0xba, 0x75,
+ 0x05, 0x60, 0x52, 0x4e, 0x78, 0xfa, 0x61, 0xc9,
+ 0x37, 0x5d, 0x7f, 0x58},
+ {0x94, 0x37, 0xbe, 0xb5, 0x7f, 0x7c, 0x5c, 0xb0, /*!< SHA-256 */
+ 0x0a, 0x92, 0x4d, 0xd3, 0xba, 0x7e, 0xb1, 0x1a,
+ 0xdb, 0xa2, 0x25, 0xb2, 0x82, 0x8e, 0xdf, 0xbb,
+ 0x61, 0xbf, 0x91, 0x1d, 0x28, 0x23, 0x4a, 0x04},
+ {0x94, 0x21, 0x9b, 0xc3, 0xd5, 0xed, 0xe6, 0xee, /*!< SHA-384 */
+ 0x42, 0x10, 0x5a, 0x58, 0xa4, 0x4d, 0x67, 0x87,
+ 0x16, 0xa2, 0xa7, 0x6c, 0x2e, 0xc5, 0x85, 0xb7,
+ 0x6a, 0x4c, 0x90, 0xb2, 0x73, 0xee, 0x58, 0x3c,
+ 0x59, 0x16, 0x67, 0xf3, 0x6f, 0x30, 0x99, 0x1c,
+ 0x2a, 0xf7, 0xb1, 0x5f, 0x45, 0x83, 0xf5, 0x9f},
+ {0x8f, 0x76, 0xef, 0x12, 0x0b, 0x92, 0xc2, 0x06, /*!< SHA-512 */
+ 0xce, 0x01, 0x18, 0x75, 0x84, 0x96, 0xd9, 0x6f,
+ 0x23, 0x88, 0xd4, 0xf8, 0xcf, 0x79, 0xf8, 0xcf,
+ 0x27, 0x12, 0x9f, 0xa6, 0x7e, 0x87, 0x9a, 0x68,
+ 0xee, 0xe2, 0xe7, 0x1d, 0x4b, 0xf2, 0x87, 0xc0,
+ 0x05, 0x6a, 0xbd, 0x7f, 0x9d, 0xff, 0xaa, 0xf3,
+ 0x9a, 0x1c, 0xb7, 0xb7, 0xbd, 0x03, 0x61, 0xa3,
+ 0xa9, 0x6a, 0x5d, 0xb2, 0x81, 0xe1, 0x6f, 0x1f},
+ {0x26, 0xfb, 0x68, 0xd2, 0x28, 0x17, 0xc2, 0x9c, /*!< MD-5 */
+ 0xbe, 0xed, 0x95, 0x16, 0x82, 0xb0, 0xd8, 0x99},
+ {0x5c, 0xd9, 0x49, 0xc8, 0x66, 0x7a, 0xfa, 0x79, /*!< RIPEMD-160 */
+ 0xa8, 0x88, 0x2e, 0x53, 0xf4, 0xee, 0xc0, 0x2d,
+ 0x1e, 0xf0, 0x80, 0x25},
+ {0x0c, 0x8c, 0x8c, 0x16, 0x49, 0x92, 0x76, 0xf1, /*!< MD-2 */
+ 0xc4, 0xcc, 0xdc, 0x9f, 0x7c, 0xb2, 0xeb, 0x87},
+ {0x44, 0xdf, 0x1b, 0x97, 0xe9, 0xe8, 0xd3, 0xb0, /*!< MD-4 */
+ 0xe8, 0x8d, 0xad, 0xdb, 0x86, 0xab, 0xa6, 0xc6},
+};
+
+static const uint8_t long_key_hmac_val[PSA_HASH_SIZE(PSA_ALG_SHA_1)] = {
+ 0xb5, 0x06, 0x7b, 0x9a, 0xb9, 0xe7, 0x47, 0x3c, /*!< SHA-1 */
+ 0x2d, 0x44, 0x46, 0x1f, 0x4a, 0xbd, 0x22, 0x53,
+ 0x9c, 0x05, 0x34, 0x34
+};
+
+static void psa_mac_test(const psa_algorithm_t alg,
+ uint8_t use_long_key,
+ struct test_result_t *ret)
+{
+ const char *msg[] = {"This is my test message, ",
+ "please generate a hmac for this."};
+ const size_t msg_size[] = {25, 32}; /* Length in bytes of msg[0], msg[1] */
+ const uint32_t msg_num = sizeof(msg)/sizeof(msg[0]);
+ uint32_t idx;
+
+ const psa_key_slot_t slot = 0;
+ const uint8_t data[] = "THIS IS MY KEY1";
+ const uint8_t long_data[] = "THIS IS MY UNCOMMONLY LONG KEY1";
+ psa_key_type_t type = PSA_KEY_TYPE_NONE;
+ size_t bits = 0;
+ size_t bit_size_test_key = 0;
+ psa_status_t status;
+ psa_mac_operation_t handle;
+
+ ret->val = TEST_PASSED;
+
+ /* Import key on slot 0 */
+ if (use_long_key == 1) {
+ status = psa_import_key(slot,
+ PSA_KEY_TYPE_HMAC,
+ long_data,
+ sizeof(long_data));
+ } else {
+ status = psa_import_key(slot, PSA_KEY_TYPE_HMAC, data, sizeof(data));
+ }
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Error importing a key");
+ return;
+ }
+
+ status = psa_get_key_information(slot, &type, &bits);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Error getting key metadata");
+ goto destroy_key_mac;
+ }
+
+ if (use_long_key == 1) {
+ bit_size_test_key = BIT_SIZE_TEST_LONG_KEY;
+ } else {
+ bit_size_test_key = BIT_SIZE_TEST_KEY;
+ }
+
+ if (bits != bit_size_test_key) {
+ TEST_FAIL("The number of key bits is different from expected");
+ goto destroy_key_mac;
+ }
+
+ if (type != PSA_KEY_TYPE_HMAC) {
+ TEST_FAIL("The type of the key is different from expected");
+ goto destroy_key_mac;
+ }
+
+ /* Setup the mac object for hmac */
+ status = psa_mac_verify_setup(&handle, slot, alg);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Error setting up mac operation object");
+ goto destroy_key_mac;
+ }
+
+ /* Update object with all the chunks of message */
+ for (idx=0; idx<msg_num; idx++) {
+ status = psa_mac_update(&handle,
+ (const uint8_t *)msg[idx],
+ msg_size[idx]);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Error during mac operation");
+ goto destroy_key_mac;
+ }
+ }
+
+ /* Cycle until idx points to the correct index in the algorithm table */
+ for (idx=0; hash_alg[idx] != PSA_ALG_HMAC_HASH(alg); idx++);
+
+ /* Finalise and verify the mac value */
+ if (use_long_key == 1) {
+ status = psa_mac_verify_finish(&handle,
+ &(long_key_hmac_val[0]),
+ PSA_HASH_SIZE(PSA_ALG_HMAC_HASH(alg)));
+ } else {
+ status = psa_mac_verify_finish(&handle,
+ &(hmac_val[idx][0]),
+ PSA_HASH_SIZE(PSA_ALG_HMAC_HASH(alg)));
+ }
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Error during finalising the mac operation");
+ goto destroy_key_mac;
+ }
+
+destroy_key_mac:
+ /* Destroy the key */
+ status = psa_destroy_key(slot);
+ if (status != PSA_SUCCESS) {
+ TEST_FAIL("Error destroying the key");
+ }
+}
+
+static void tfm_crypto_test_6011(struct test_result_t *ret)
+{
+ psa_mac_test(PSA_ALG_HMAC(PSA_ALG_SHA_1), 0, ret);
+}
+
+static void tfm_crypto_test_6012(struct test_result_t *ret)
+{
+ psa_mac_test(PSA_ALG_HMAC(PSA_ALG_SHA_256), 0, ret);
+}
+
+static void tfm_crypto_test_6013(struct test_result_t *ret)
+{
+ psa_mac_test(PSA_ALG_HMAC(PSA_ALG_SHA_384), 0, ret);
+}
+
+static void tfm_crypto_test_6014(struct test_result_t *ret)
+{
+ psa_mac_test(PSA_ALG_HMAC(PSA_ALG_SHA_512), 0, ret);
+}
+
+static void tfm_crypto_test_6015(struct test_result_t *ret)
+{
+ psa_mac_test(PSA_ALG_HMAC(PSA_ALG_MD5), 0, ret);
+}
+
+static void tfm_crypto_test_6016(struct test_result_t *ret)
+{
+ psa_mac_test(PSA_ALG_HMAC(PSA_ALG_SHA_1), 1, ret);
+}