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/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},