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