Crypto: Add support for Hash functionalities

This patch introduces support for the Hash functionalities
exposed by the PSA Crypto API, and adds a set of tests to
the Regression test suite to validate the API functions.

Change-Id: I4169b7a1a7a04140d557edef4e9d86a9c6ae0f50
Signed-off-by: Antonio de Angelis <antonio.deangelis@arm.com>
diff --git a/interface/include/tfm_crypto_veneers.h b/interface/include/tfm_crypto_veneers.h
index b158f51..cce9432 100644
--- a/interface/include/tfm_crypto_veneers.h
+++ b/interface/include/tfm_crypto_veneers.h
@@ -149,10 +149,76 @@
  * \return Return values as described in \ref tfm_crypto_err_t
  */
 enum tfm_crypto_err_t tfm_crypto_veneer_cipher_finish(
-                                             psa_cipher_operation_t *operation,
-                                             uint8_t *output,
-                                             size_t output_size,
-                                             size_t *output_length);
+                                              psa_cipher_operation_t *operation,
+                                              uint8_t *output,
+                                              size_t output_size,
+                                              size_t *output_length);
+/**
+ * \brief Starts a hash operation with the provided algorithm (veneer function)
+ *
+ * \param[in] operation Hash operation context
+ * \param[in] alg       Algorithm chosen as hash
+ *
+ * \return Returns values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_veneer_hash_start(
+                                                psa_hash_operation_t *operation,
+                                                psa_algorithm_t alg);
+/**
+ * \brief Adds a new input chunk to the data for which the final hash value
+ *        will be computed (veneer function)
+ *
+ * \param[in] operation    Hash operation context
+ * \param[in] input        Buffer containing the input data
+ * \param[in] input_length Size of the provided input data
+ *
+ * \return Returns values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_veneer_hash_update(
+                                                psa_hash_operation_t *operation,
+                                                const uint8_t *input,
+                                                size_t input_length);
+/**
+ * \brief Finalises a hash context operation producing the final hash value
+ *        (veneer function)
+ *
+ * \param[in]  operation   Hash operation context
+ * \param[out] hash        Buffer containing hash data
+ * \param[in]  hash_size   Size of the hash buffer
+ * \param[out] hash_length Size of the produced hash
+ *
+ * \return Returns values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_veneer_hash_finish(
+                                                psa_hash_operation_t *operation,
+                                                uint8_t *hash,
+                                                size_t hash_size,
+                                                size_t *hash_length);
+/**
+ * \brief Finalises a hash context operation, verifying that the final hash
+ *        value matches the one provided as input (veneer function)
+ *
+ * \param[in] operation   Hash operation context
+ * \param[in] hash        Buffer containing the provided hash value
+ * \param[in] hash_length Size of the provided hash value
+ *
+ * \return Returns values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_veneer_hash_verify(
+                                                psa_hash_operation_t *operation,
+                                                const uint8_t *hash,
+                                                size_t hash_length);
+/**
+ * \brief Aborts a hash operation, clears the operation context provided
+ *        (veneer function)
+ *
+ * \param[in] operation Hash operation context
+ *
+ * \return Returns values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_veneer_hash_abort(
+                                               psa_hash_operation_t *operation);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/interface/src/tfm_crypto_api.c b/interface/src/tfm_crypto_api.c
index d98f85f..dbeb6a8 100644
--- a/interface/src/tfm_crypto_api.c
+++ b/interface/src/tfm_crypto_api.c
@@ -188,3 +188,76 @@
 
     return TFM_CRYPTO_PSA_RETURN(err);
 }
+
+psa_status_t psa_hash_start(psa_hash_operation_t *operation,
+                            psa_algorithm_t alg)
+{
+    enum tfm_crypto_err_t err;
+
+    err = tfm_ns_lock_dispatch((veneer_fn)tfm_crypto_veneer_hash_start,
+                               (uint32_t)operation,
+                               (uint32_t)alg,
+                               0,
+                               0);
+
+    return TFM_CRYPTO_PSA_RETURN(err);
+}
+
+psa_status_t psa_hash_update(psa_hash_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_hash_update,
+                               (uint32_t)operation,
+                               (uint32_t)input,
+                               (uint32_t)input_length,
+                               0);
+
+    return TFM_CRYPTO_PSA_RETURN(err);
+}
+
+psa_status_t psa_hash_finish(psa_hash_operation_t *operation,
+                             uint8_t *hash,
+                             size_t hash_size,
+                             size_t *hash_length)
+{
+    enum tfm_crypto_err_t err;
+
+    err = tfm_ns_lock_dispatch((veneer_fn)tfm_crypto_veneer_hash_finish,
+                               (uint32_t)operation,
+                               (uint32_t)hash,
+                               (uint32_t)hash_size,
+                               (uint32_t)hash_length);
+
+    return TFM_CRYPTO_PSA_RETURN(err);
+}
+
+psa_status_t psa_hash_verify(psa_hash_operation_t *operation,
+                             const uint8_t *hash,
+                             size_t hash_length)
+{
+    enum tfm_crypto_err_t err;
+
+    err = tfm_ns_lock_dispatch((veneer_fn)tfm_crypto_veneer_hash_verify,
+                               (uint32_t)operation,
+                               (uint32_t)hash,
+                               (uint32_t)hash_length,
+                               0);
+
+    return TFM_CRYPTO_PSA_RETURN(err);
+}
+
+psa_status_t psa_hash_abort(psa_hash_operation_t *operation)
+{
+    enum tfm_crypto_err_t err;
+
+    err = tfm_ns_lock_dispatch((veneer_fn)tfm_crypto_veneer_hash_abort,
+                               (uint32_t)operation,
+                               0,
+                               0,
+                               0);
+
+    return TFM_CRYPTO_PSA_RETURN(err);
+}
diff --git a/secure_fw/ns_callable/tfm_crypto_veneers.c b/secure_fw/ns_callable/tfm_crypto_veneers.c
index b91f02c..a2c0652 100644
--- a/secure_fw/ns_callable/tfm_crypto_veneers.c
+++ b/secure_fw/ns_callable/tfm_crypto_veneers.c
@@ -111,3 +111,51 @@
     TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_cipher_finish,
                          operation, output, output_size, output_length);
 }
+
+__tfm_secure_gateway_attributes__
+enum tfm_crypto_err_t tfm_crypto_veneer_hash_start(
+                                                psa_hash_operation_t *operation,
+                                                psa_algorithm_t alg)
+{
+    TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_hash_start,
+                         operation, alg, 0, 0);
+}
+
+__tfm_secure_gateway_attributes__
+enum tfm_crypto_err_t tfm_crypto_veneer_hash_update(
+                                                psa_hash_operation_t *operation,
+                                                const uint8_t *input,
+                                                size_t input_length)
+{
+    TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_hash_update,
+                         operation, input, input_length, 0);
+}
+
+__tfm_secure_gateway_attributes__
+enum tfm_crypto_err_t tfm_crypto_veneer_hash_finish(
+                                                psa_hash_operation_t *operation,
+                                                uint8_t *hash,
+                                                size_t hash_size,
+                                                size_t *hash_length)
+{
+    TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_hash_finish,
+                         operation, hash, hash_size, hash_length);
+}
+
+__tfm_secure_gateway_attributes__
+enum tfm_crypto_err_t tfm_crypto_veneer_hash_verify(
+                                                psa_hash_operation_t *operation,
+                                                const uint8_t *hash,
+                                                size_t hash_length)
+{
+    TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_hash_verify,
+                         operation, hash, hash_length, 0);
+}
+
+__tfm_secure_gateway_attributes__
+enum tfm_crypto_err_t tfm_crypto_veneer_hash_abort(
+                                                psa_hash_operation_t *operation)
+{
+    TFM_CORE_SFN_REQUEST(TFM_SP_CRYPTO_ID, tfm_crypto_hash_abort,
+                         operation, 0, 0, 0);
+}
diff --git a/secure_fw/services/crypto/CMakeLists.inc b/secure_fw/services/crypto/CMakeLists.inc
index cfaa709..041e971 100644
--- a/secure_fw/services/crypto/CMakeLists.inc
+++ b/secure_fw/services/crypto/CMakeLists.inc
@@ -38,6 +38,7 @@
   set (CRYPTO_C_SRC "${CRYPTO_DIR}/crypto_init.c"
                     "${CRYPTO_DIR}/crypto_alloc.c"
                     "${CRYPTO_DIR}/crypto_cipher.c"
+                    "${CRYPTO_DIR}/crypto_hash.c"
                     "${CRYPTO_DIR}/crypto_key.c"
                     "${CRYPTO_DIR}/crypto_wrappers.c"
                     "${CRYPTO_DIR}/crypto_utils.c"
diff --git a/secure_fw/services/crypto/crypto_hash.c b/secure_fw/services/crypto/crypto_hash.c
new file mode 100644
index 0000000..6983b8f
--- /dev/null
+++ b/secure_fw/services/crypto/crypto_hash.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <limits.h>
+
+#include "tfm_crypto_defs.h"
+
+/* Pre include Mbed TLS headers */
+#define LIB_PREFIX_NAME __tfm_crypto__
+#include "mbedtls_global_symbols.h"
+
+/* Include the Mbed TLS configuration file, the way Mbed TLS does it
+ * in each of its header files. */
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "platform/ext/common/tfm_mbedtls_config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include "psa_crypto.h"
+
+/* The file "psa_crypto_struct.h" contains definitions for
+ * implementation-specific structs that are declared in "psa_crypto.h". */
+#include "psa_crypto_struct.h"
+
+#include "tfm_crypto_api.h"
+#include "crypto_utils.h"
+
+/*!
+ * \defgroup public_psa Public functions, PSA
+ *
+ */
+
+/*!@{*/
+enum tfm_crypto_err_t tfm_crypto_hash_start(psa_hash_operation_t *handle,
+                                            psa_algorithm_t alg)
+{
+    int ret;
+    enum tfm_crypto_err_t err;
+    const mbedtls_md_info_t *info = NULL;
+    mbedtls_md_type_t type = MBEDTLS_MD_NONE;
+
+    struct psa_hash_operation_s *operation = NULL;
+
+    /* Validate pointers */
+    err = tfm_crypto_memory_check(handle,
+                                  sizeof(psa_hash_operation_t),
+                                  TFM_MEMORY_ACCESS_RW);
+    if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+        return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+    if (PSA_ALG_IS_HASH(alg) == 0) {
+        return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+    /* Mbed TLS message digest setup */
+    switch(alg) {
+    case PSA_ALG_MD2:
+#if defined(MBEDTLS_MD2_C)
+        type = MBEDTLS_MD_MD2;
+#endif
+        break;
+    case PSA_ALG_MD4:
+#if defined(MBEDTLS_MD4_C)
+        type = MBEDTLS_MD_MD4;
+#endif
+        break;
+    case PSA_ALG_MD5:
+#if defined(MBEDTLS_MD5_C)
+        type = MBEDTLS_MD_MD5;
+#endif
+        break;
+    case PSA_ALG_RIPEMD160:
+#if defined(MBEDTLS_RIPEMD160_C)
+        type = MBEDTLS_MD_RIPEMD160;
+#endif
+        break;
+    case PSA_ALG_SHA_1:
+#if defined(MBEDTLS_SHA1_C)
+        type = MBEDTLS_MD_SHA1;
+#endif
+        break;
+    case PSA_ALG_SHA_224:
+#if defined(MBEDTLS_SHA256_C)
+        type = MBEDTLS_MD_SHA224;
+#endif
+        break;
+    case PSA_ALG_SHA_256:
+#if defined(MBEDTLS_SHA256_C)
+        type = MBEDTLS_MD_SHA256;
+#endif
+        break;
+    case PSA_ALG_SHA_384:
+#if defined(MBEDTLS_SHA512_C)
+        type = MBEDTLS_MD_SHA384;
+#endif
+        break;
+    case PSA_ALG_SHA_512:
+#if defined(MBEDTLS_SHA512_C)
+        type = MBEDTLS_MD_SHA512;
+#endif
+        break;
+    default:
+        break;
+    }
+
+    /* Mbed TLS currently does not support SHA3: PSA_ALG_SHA3_224,
+     * PSA_ALG_SHA3_256, PSA_ALG_SHA3_384, PSA_ALG_SHA3_512;
+     * Mbed TLS currently does not support SHA-512 Truncated modes:
+     * PSA_ALG_SHA_512_224, PSA_ALG_SHA_512_256
+     */
+    if (type == MBEDTLS_MD_NONE) {
+        return TFM_CRYPTO_ERR_PSA_ERROR_NOT_SUPPORTED;
+    }
+
+    /* Allocate the operation context in the TFM space */
+    err = tfm_crypto_operation_alloc(TFM_CRYPTO_HASH_OPERATION, handle);
+    if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+        return err;
+    }
+
+    /* Look up the corresponding operation context */
+    err = tfm_crypto_operation_lookup(TFM_CRYPTO_HASH_OPERATION,
+                                      handle,
+                                      (void **)&operation);
+
+    if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+        /* Release the operation context */
+        tfm_crypto_operation_release(handle);
+        return err;
+    }
+
+    /* Bind the algorithm to the hash operation */
+    operation->alg = alg;
+
+    /* Mbed TLS message digest init */
+    mbedtls_md_init(&operation->ctx.md);
+    info = mbedtls_md_info_from_type(type);
+    ret = mbedtls_md_setup(&(operation->ctx.md), info, 0); /* 0: not HMAC */
+    if (ret != 0) {
+        /* Release the operation context */
+        tfm_crypto_operation_release(handle);
+        return TFM_CRYPTO_ERR_PSA_ERROR_COMMUNICATION_FAILURE;
+    }
+
+    /* Start the message digest context */
+    ret = mbedtls_md_starts(&(operation->ctx.md));
+    if (ret != 0) {
+        /* Release the operation context */
+        tfm_crypto_operation_release(handle);
+        return TFM_CRYPTO_ERR_PSA_ERROR_COMMUNICATION_FAILURE;
+    }
+
+    return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+enum tfm_crypto_err_t tfm_crypto_hash_update(psa_hash_operation_t *handle,
+                                             const uint8_t *input,
+                                             size_t input_length)
+{
+    int ret;
+    enum tfm_crypto_err_t err;
+    struct psa_hash_operation_s *operation = NULL;
+
+    /* Validate pointers */
+    err = tfm_crypto_memory_check(handle,
+                                  sizeof(psa_hash_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_HASH_OPERATION,
+                                      handle,
+                                      (void **)&operation);
+
+    if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+        return err;
+    }
+
+    /* Process the input chunk */
+    ret = mbedtls_md_update(&(operation->ctx.md), input, input_length);
+    if (ret != 0) {
+        /* Release the operation context */
+        tfm_crypto_operation_release(handle);
+        return TFM_CRYPTO_ERR_PSA_ERROR_COMMUNICATION_FAILURE;
+    }
+
+    return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+enum tfm_crypto_err_t tfm_crypto_hash_finish(psa_hash_operation_t *handle,
+                                             uint8_t *hash,
+                                             size_t hash_size,
+                                             size_t *hash_length)
+{
+    int ret;
+    enum tfm_crypto_err_t err;
+    struct psa_hash_operation_s *operation = NULL;
+
+    /* Validate pointers */
+    err = tfm_crypto_memory_check(handle,
+                                  sizeof(psa_hash_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 *)hash,
+                                  hash_size,
+                                  TFM_MEMORY_ACCESS_RO);
+    if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+        return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+    }
+    err = tfm_crypto_memory_check(hash_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_HASH_OPERATION,
+                                      handle,
+                                      (void **)&operation);
+
+    if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+        return err;
+    }
+
+    if (hash_size < PSA_HASH_SIZE(operation->alg)) {
+        /* Release the operation context */
+        tfm_crypto_operation_release(handle);
+        return TFM_CRYPTO_ERR_PSA_ERROR_BUFFER_TOO_SMALL;
+    }
+
+    /* Finalise the hash value */
+    ret = mbedtls_md_finish(&(operation->ctx.md), hash);
+    if (ret != 0) {
+        /* Release the operation context */
+        tfm_crypto_operation_release(handle);
+        return TFM_CRYPTO_ERR_PSA_ERROR_COMMUNICATION_FAILURE;
+    }
+
+    /* Set the length of the hash that has been produced */
+    *hash_length = PSA_HASH_SIZE(operation->alg);
+
+    /* Clear the Mbed TLS message digest context */
+    mbedtls_md_free(&(operation->ctx.md));
+
+    /* Release the operation context */
+    err = tfm_crypto_operation_release(handle);
+    if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+        return err;
+    }
+
+    return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+enum tfm_crypto_err_t tfm_crypto_hash_verify(psa_hash_operation_t *handle,
+                                             const uint8_t *hash,
+                                             size_t hash_length)
+{
+    enum tfm_crypto_err_t err;
+    uint8_t digest[PSA_HASH_MAX_SIZE] = {0};
+    size_t digest_length;
+    uint32_t idx, comp_mismatch = 0;
+
+    /* Validate pointers */
+    err = tfm_crypto_memory_check(handle,
+                                  sizeof(psa_hash_operation_t),
+                                  TFM_MEMORY_ACCESS_RW);
+    if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+        return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+    /* Finalise the hash operation */
+    err = tfm_crypto_hash_finish(handle,
+                                 digest,
+                                 PSA_HASH_MAX_SIZE,
+                                 &digest_length);
+
+    if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+        return err;
+    }
+
+    /* Verify that the computed hash matches the provided one */
+    for (idx=0; idx<(uint32_t)digest_length; idx++) {
+        if (digest[idx] != hash[idx]) {
+            comp_mismatch = 1;
+        }
+    }
+
+    if (comp_mismatch == 1) {
+        return TFM_CRYPTO_ERR_PSA_ERROR_INVALID_SIGNATURE;
+    }
+
+    return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+
+enum tfm_crypto_err_t tfm_crypto_hash_abort(psa_hash_operation_t *handle)
+{
+    enum tfm_crypto_err_t err;
+    struct psa_hash_operation_s *operation = NULL;
+
+    /* Look up the corresponding operation context */
+    err = tfm_crypto_operation_lookup(TFM_CRYPTO_HASH_OPERATION,
+                                      handle,
+                                      (void **)&operation);
+
+    if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+        return err;
+    }
+
+    /* Clear the Mbed TLS message digest context */
+    mbedtls_md_free(&(operation->ctx.md));
+
+    /* Release the operation context */
+    err = tfm_crypto_operation_release(handle);
+    if (err != TFM_CRYPTO_ERR_PSA_SUCCESS) {
+        return err;
+    }
+
+    return TFM_CRYPTO_ERR_PSA_SUCCESS;
+}
+/*!@}*/
diff --git a/secure_fw/services/crypto/manifest.yaml b/secure_fw/services/crypto/manifest.yaml
index 8f222b6..05a2331 100644
--- a/secure_fw/services/crypto/manifest.yaml
+++ b/secure_fw/services/crypto/manifest.yaml
@@ -120,7 +120,47 @@
       "non_secure_clients": true,
       "minor_version": 1,
       "minor_policy": "strict"
-    }
+    },
+    {
+      "sfid": "TFM_CRYPTO_HASH_START_SFID",
+      "signal": "TFM_CRYPTO_HASH_START",
+      "tfm_symbol": "tfm_crypto_hash_start",
+      "non_secure_clients": true,
+      "minor_version": 1,
+      "minor_policy": "strict"
+    },
+    {
+      "sfid": "TFM_CRYPTO_HASH_UPDATE_SFID",
+      "signal": "TFM_CRYPTO_HASH_UPDATE",
+      "tfm_symbol": "tfm_crypto_hash_update",
+      "non_secure_clients": true,
+      "minor_version": 1,
+      "minor_policy": "strict"
+    },
+    {
+      "sfid": "TFM_CRYPTO_HASH_FINISH_SFID",
+      "signal": "TFM_CRYPTO_HASH_FINISH",
+      "tfm_symbol": "tfm_crypto_hash_finish",
+      "non_secure_clients": true,
+      "minor_version": 1,
+      "minor_policy": "strict"
+    },
+    {
+      "sfid": "TFM_CRYPTO_HASH_VERIFY_SFID",
+      "signal": "TFM_CRYPTO_HASH_VERIFY",
+      "tfm_symbol": "tfm_crypto_hash_verify",
+      "non_secure_clients": true,
+      "minor_version": 1,
+      "minor_policy": "strict"
+    },
+    {
+      "sfid": "TFM_CRYPTO_HASH_ABORT_SFID",
+      "signal": "TFM_CRYPTO_HASH_ABORT",
+      "tfm_symbol": "tfm_crypto_hash_abort",
+      "non_secure_clients": true,
+      "minor_version": 1,
+      "minor_policy": "strict"
+    },
   ],
   "source_files": [
     "crypto_alloc.c",
@@ -129,6 +169,7 @@
     "crypto_init.c",
     "crypto_wrappers.c",
     "crypto_utils.c",
+    "crypto_hash.c",
   ],
   "tfm_linker_pattern": [
     "library_list": [
diff --git a/secure_fw/services/crypto/psa_crypto_struct.h b/secure_fw/services/crypto/psa_crypto_struct.h
index de724dd..651d434 100644
--- a/secure_fw/services/crypto/psa_crypto_struct.h
+++ b/secure_fw/services/crypto/psa_crypto_struct.h
@@ -49,26 +49,8 @@
     union
     {
         uint32_t dummy; /* Make the union non-empty in any case */
-#if defined(MBEDTLS_MD2_C)
-        mbedtls_md2_context md2;
-#endif
-#if defined(MBEDTLS_MD4_C)
-        mbedtls_md4_context md4;
-#endif
-#if defined(MBEDTLS_MD5_C)
-        mbedtls_md5_context md5;
-#endif
-#if defined(MBEDTLS_RIPEMD160_C)
-        mbedtls_ripemd160_context ripemd160;
-#endif
-#if defined(MBEDTLS_SHA1_C)
-        mbedtls_sha1_context sha1;
-#endif
-#if defined(MBEDTLS_SHA256_C)
-        mbedtls_sha256_context sha256;
-#endif
-#if defined(MBEDTLS_SHA512_C)
-        mbedtls_sha512_context sha512;
+#if defined(MBEDTLS_MD_C)
+        mbedtls_md_context_t md;
 #endif
     } ctx;
 };
diff --git a/secure_fw/services/crypto/tfm_crypto_api.h b/secure_fw/services/crypto/tfm_crypto_api.h
index c415c09..9b575a5 100644
--- a/secure_fw/services/crypto/tfm_crypto_api.h
+++ b/secure_fw/services/crypto/tfm_crypto_api.h
@@ -221,12 +221,70 @@
 /**
  * \brief Aborts a cipher operation, clears the operation context provided
  *
- * \param[in]  operation     Cipher operation context
+ * \param[in] operation Cipher operation context
  *
  * \return Returns values as described in \ref tfm_crypto_err_t
  */
 enum tfm_crypto_err_t tfm_crypto_cipher_abort(
                                              psa_cipher_operation_t *operation);
+/**
+ * \brief Starts a hash operation with the provided algorithm
+ *
+ * \param[in] operation Hash operation context
+ * \param[in] alg       Algorithm chosen as hash
+ *
+ * \return Returns values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_hash_start(psa_hash_operation_t *operation,
+                                            psa_algorithm_t alg);
+/**
+ * \brief Adds a new input chunk to the data for which the final hash value
+ *        will be computed
+ *
+ * \param[in] operation    Hash operation context
+ * \param[in] input        Buffer containing the input data
+ * \param[in] input_length Size of the provided input data
+ *
+ * \return Returns values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_hash_update(psa_hash_operation_t *operation,
+                                             const uint8_t *input,
+                                             size_t input_length);
+/**
+ * \brief Finalises a hash context operation producing the final hash value
+ *
+ * \param[in]  operation   Hash operation context
+ * \param[out] hash        Buffer containing hash data
+ * \param[in]  hash_size   Size of the hash buffer
+ * \param[out] hash_length Size of the produced hash
+ *
+ * \return Returns values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_hash_finish(psa_hash_operation_t *operation,
+                                             uint8_t *hash,
+                                             size_t hash_size,
+                                             size_t *hash_length);
+/**
+ * \brief Finalises a hash context operation, verifying that the final hash
+ *        value matches the one provided as input
+ *
+ * \param[in] operation   Hash operation context
+ * \param[in] hash        Buffer containing the provided hash value
+ * \param[in] hash_length Size of the provided hash value
+ *
+ * \return Returns values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_hash_verify(psa_hash_operation_t *operation,
+                                             const uint8_t *hash,
+                                             size_t hash_length);
+/**
+ * \brief Aborts a hash operation, clears the operation context provided
+ *
+ * \param[in] operation Hash operation context
+ *
+ * \return Returns values as described in \ref tfm_crypto_err_t
+ */
+enum tfm_crypto_err_t tfm_crypto_hash_abort(psa_hash_operation_t *operation);
 
 #ifdef __cplusplus
 }
diff --git a/secure_fw/services/tfm_sfid_list.inc b/secure_fw/services/tfm_sfid_list.inc
index 6934058..cad8444 100644
--- a/secure_fw/services/tfm_sfid_list.inc
+++ b/secure_fw/services/tfm_sfid_list.inc
@@ -40,6 +40,11 @@
     {tfm_crypto_cipher_update_wrapper, TFM_CRYPTO_CIPHER_UPDATE_SFID},
     {tfm_crypto_cipher_abort, TFM_CRYPTO_CIPHER_ABORT_SFID},
     {tfm_crypto_cipher_finish, TFM_CRYPTO_CIPHER_FINISH_SFID},
+    {tfm_crypto_hash_start, TFM_CRYPTO_HASH_START_SFID},
+    {tfm_crypto_hash_update, TFM_CRYPTO_HASH_UPDATE_SFID},
+    {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},
 
 #ifdef TFM_PARTITION_TEST_CORE
     /******** TFM_SP_CORE_TEST ********/
diff --git a/test/framework/test_framework.h b/test/framework/test_framework.h
index a2b64c4..b27e298 100644
--- a/test/framework/test_framework.h
+++ b/test/framework/test_framework.h
@@ -10,6 +10,7 @@
 
 #include <stdarg.h>
 #include <stdint.h>
+#include <stdio.h>
 
 #include "test_framework_helpers.h"
 
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 40d49ad..3ed6af1 100644
--- a/test/suites/crypto/non_secure/crypto_ns_interface_testsuite.c
+++ b/test/suites/crypto/non_secure/crypto_ns_interface_testsuite.c
@@ -22,6 +22,13 @@
 static void tfm_crypto_test_6001(struct test_result_t *ret);
 static void tfm_crypto_test_6002(struct test_result_t *ret);
 static void tfm_crypto_test_6003(struct test_result_t *ret);
+static void tfm_crypto_test_6004(struct test_result_t *ret);
+static void tfm_crypto_test_6005(struct test_result_t *ret);
+static void tfm_crypto_test_6006(struct test_result_t *ret);
+static void tfm_crypto_test_6007(struct test_result_t *ret);
+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 struct test_t crypto_veneers_tests[] = {
     {&tfm_crypto_test_6001, "TFM_CRYPTO_TEST_6001",
@@ -30,6 +37,20 @@
      "Non Secure Symmetric encryption (AES-128-CBC) interface", {0} },
     {&tfm_crypto_test_6003, "TFM_CRYPTO_TEST_6003",
      "Non Secure Symmetric encryption (AES-128-CFB) interface", {0} },
+    {&tfm_crypto_test_6004, "TFM_CRYPTO_TEST_6004",
+     "Non Secure Hash (SHA-1) interface", {0} },
+    {&tfm_crypto_test_6005, "TFM_CRYPTO_TEST_6005",
+     "Non Secure Hash (SHA-224) interface", {0} },
+    {&tfm_crypto_test_6006, "TFM_CRYPTO_TEST_6006",
+     "Non Secure Hash (SHA-256) interface", {0} },
+    {&tfm_crypto_test_6007, "TFM_CRYPTO_TEST_6007",
+     "Non Secure Hash (SHA-384) interface", {0} },
+    {&tfm_crypto_test_6008, "TFM_CRYPTO_TEST_6008",
+     "Non Secure Hash (SHA-512) interface", {0} },
+    {&tfm_crypto_test_6009, "TFM_CRYPTO_TEST_6009",
+     "Non Secure Hash (MD-5) interface", {0} },
+    {&tfm_crypto_test_6010, "TFM_CRYPTO_TEST_6010",
+     "Non Secure Hash (RIPEMD-160) interface", {0} },
 };
 
 void register_testsuite_ns_crypto_interface(struct test_suite_t *p_test_suite)
@@ -325,3 +346,140 @@
 {
     psa_cipher_test(PSA_ALG_CFB_BASE, ret);
 }
+
+/*
+ * \brief This is the list of algorithms supported by the current
+ *        configuration of the crypto engine used by the crypto
+ *        service. In case the crypto engine default capabilities
+ *        is changed, this list needs to be updated accordingly
+ */
+static const psa_algorithm_t hash_alg[] = {
+    PSA_ALG_SHA_1,
+    PSA_ALG_SHA_224,
+    PSA_ALG_SHA_256,
+    PSA_ALG_SHA_384,
+    PSA_ALG_SHA_512,
+    PSA_ALG_MD5,
+    PSA_ALG_RIPEMD160
+};
+
+static const uint8_t hash_val[][PSA_HASH_SIZE(PSA_ALG_SHA_512)] = {
+    {0x56, 0x4A, 0x0E, 0x35, 0xF1, 0xC7, 0xBC, 0xD0, /*!< SHA-1 */
+     0x7D, 0xCF, 0xB1, 0xBC, 0xC9, 0x16, 0xFA, 0x2E,
+     0xF5, 0xBE, 0x96, 0xB2},
+    {0x00, 0xD2, 0x90, 0xE2, 0x0E, 0x4E, 0xC1, 0x7E, /*!< SHA-224 */
+     0x7A, 0x95, 0xF5, 0x10, 0x5C, 0x76, 0x74, 0x04,
+     0x6E, 0xB5, 0x56, 0x5E, 0xE5, 0xE7, 0xBA, 0x15,
+     0x6C, 0x23, 0x47, 0xF3},
+    {0x6B, 0x22, 0x09, 0x2A, 0x37, 0x1E, 0xF5, 0x14, /*!< SHA-256 */
+     0xF7, 0x39, 0x4D, 0xCF, 0xAD, 0x4D, 0x17, 0x46,
+     0x66, 0xCB, 0x33, 0xA0, 0x39, 0xD8, 0x41, 0x4E,
+     0xF1, 0x2A, 0xD3, 0x4D, 0x69, 0xC3, 0xB5, 0x3E},
+    {0x64, 0x79, 0x11, 0xBB, 0x47, 0x4E, 0x47, 0x59, /*!< SHA-384 */
+     0x3E, 0x4D, 0xBC, 0x60, 0xA5, 0xF9, 0xBF, 0x9C,
+     0xC0, 0xBA, 0x55, 0x0F, 0x93, 0xCA, 0x72, 0xDF,
+     0x57, 0x1E, 0x50, 0x56, 0xF9, 0x4A, 0x01, 0xD6,
+     0xA5, 0x6F, 0xF7, 0x62, 0x34, 0x4F, 0x48, 0xFD,
+     0x9D, 0x15, 0x07, 0x42, 0xB7, 0x72, 0x94, 0xB8},
+    {0xB4, 0x1C, 0xA3, 0x6C, 0xA9, 0x67, 0x1D, 0xAD, /*!< SHA-512 */
+     0x34, 0x1F, 0xBE, 0x1B, 0x83, 0xC4, 0x40, 0x2A,
+     0x47, 0x42, 0x79, 0xBB, 0x21, 0xCA, 0xF0, 0x60,
+     0xE4, 0xD2, 0x6E, 0x9B, 0x70, 0x12, 0x34, 0x3F,
+     0x55, 0x2C, 0x09, 0x31, 0x0A, 0x5B, 0x40, 0x21,
+     0x01, 0xA8, 0x3B, 0x58, 0xE7, 0x48, 0x13, 0x1A,
+     0x7E, 0xCD, 0xE1, 0xD2, 0x46, 0x10, 0x58, 0x34,
+     0x49, 0x14, 0x4B, 0xAA, 0x89, 0xA9, 0xF5, 0xB1},
+    {0x63, 0xFC, 0x11, 0x88, 0xB7, 0x03, 0xDD, 0xD5, /*!< MD-5 */
+     0x36, 0xB9, 0x2F, 0xD6, 0x9E, 0x91, 0x96, 0xF8},
+    {0xF5, 0x8E, 0xB3, 0xCB, 0xE5, 0xF0, 0x3B, 0xC5, /*!< RIPEMD-160 */
+     0x7C, 0x45, 0xE2, 0x49, 0xAA, 0x66, 0xC6, 0x5A,
+     0x47, 0xEA, 0x34, 0x91},
+    {0x7E, 0x28, 0x13, 0xAE, 0x98, 0xBD, 0x38, 0x6C, /*!< MD-2 */
+     0xDC, 0x8C, 0xF8, 0x04, 0xC6, 0x58, 0xA9, 0x69},
+    {0xA0, 0xB9, 0x82, 0x4E, 0xE0, 0x74, 0x4F, 0x1E, /*!< MD-4 */
+     0xA4, 0x7F, 0xA3, 0xDF, 0xD0, 0x0D, 0x97, 0xEB},
+};
+
+static void psa_hash_test(const psa_algorithm_t alg,
+                          struct test_result_t *ret)
+{
+    const char *msg[] = {"This is my test message, ",
+                         "please generate a hash 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;
+
+    psa_status_t status;
+    psa_hash_operation_t handle;
+
+    /* Setup the hash object for the desired hash*/
+    status = psa_hash_start(&handle, alg);
+
+    if (status != PSA_SUCCESS) {
+        if (status == PSA_ERROR_NOT_SUPPORTED) {
+            TEST_FAIL("Algorithm NOT SUPPORTED by the implementation");
+            return;
+        }
+
+        TEST_FAIL("Error setting up hash operation object");
+        return;
+    }
+
+    /* Update object with all the chunks of message */
+    for (idx=0; idx<msg_num; idx++) {
+        status = psa_hash_update(&handle,
+                                 (const uint8_t *)msg[idx],msg_size[idx]);
+        if (status != PSA_SUCCESS) {
+            TEST_FAIL("Error updating the hash operation object");
+            return;
+        }
+    }
+
+    /* Cycle until idx points to the correct index in the algorithm table */
+    for (idx=0; hash_alg[idx] != alg; idx++);
+
+    /* Finalise and verify that the hash is as expected */
+    status = psa_hash_verify(&handle, &(hash_val[idx][0]), PSA_HASH_SIZE(alg));
+    if (status != PSA_SUCCESS) {
+        TEST_FAIL("Error verifying the hash operation object");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
+
+static void tfm_crypto_test_6004(struct test_result_t *ret)
+{
+    psa_hash_test(PSA_ALG_SHA_1, ret);
+}
+
+static void tfm_crypto_test_6005(struct test_result_t *ret)
+{
+    psa_hash_test(PSA_ALG_SHA_224, ret);
+}
+
+static void tfm_crypto_test_6006(struct test_result_t *ret)
+{
+    psa_hash_test(PSA_ALG_SHA_256, ret);
+}
+
+static void tfm_crypto_test_6007(struct test_result_t *ret)
+{
+    psa_hash_test(PSA_ALG_SHA_384, ret);
+}
+
+static void tfm_crypto_test_6008(struct test_result_t *ret)
+{
+    psa_hash_test(PSA_ALG_SHA_512, ret);
+}
+
+static void tfm_crypto_test_6009(struct test_result_t *ret)
+{
+    psa_hash_test(PSA_ALG_MD5, ret);
+}
+
+static void tfm_crypto_test_6010(struct test_result_t *ret)
+{
+    psa_hash_test(PSA_ALG_RIPEMD160, ret);
+}