libmbedtls: support mbedtls HMAC algorithm

Implement HMAC function based on mbedtls.

Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
Signed-off-by: Edison Ai <edison.ai@arm.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/lib/libmbedtls/core/hmac.c b/lib/libmbedtls/core/hmac.c
new file mode 100644
index 0000000..391693a
--- /dev/null
+++ b/lib/libmbedtls/core/hmac.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (C) 2018, ARM Limited
+ * Copyright (C) 2019, Linaro Limited
+ */
+
+#include <assert.h>
+#include <compiler.h>
+#include <crypto/crypto.h>
+#include <crypto/crypto_impl.h>
+#include <kernel/panic.h>
+#include <mbedtls/md.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tee_api_types.h>
+#include <utee_defines.h>
+#include <util.h>
+
+struct mbed_hmac_ctx {
+	struct crypto_mac_ctx mac_ctx;
+	mbedtls_md_context_t md_ctx;
+};
+
+static const struct crypto_mac_ops mbed_hmac_ops;
+
+static struct mbed_hmac_ctx *to_hmac_ctx(struct crypto_mac_ctx *ctx)
+{
+	assert(ctx && ctx->ops == &mbed_hmac_ops);
+
+	return container_of(ctx, struct mbed_hmac_ctx, mac_ctx);
+}
+
+static TEE_Result mbed_hmac_init(struct crypto_mac_ctx *ctx,
+				 const uint8_t *key, size_t len)
+{
+	if (mbedtls_md_hmac_starts(&to_hmac_ctx(ctx)->md_ctx, key, len))
+		return TEE_ERROR_BAD_STATE;
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result mbed_hmac_update(struct crypto_mac_ctx *ctx,
+				   const uint8_t *data, size_t len)
+{
+	if (mbedtls_md_hmac_update(&to_hmac_ctx(ctx)->md_ctx, data, len))
+		return TEE_ERROR_BAD_STATE;
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result mbed_hmac_final(struct crypto_mac_ctx *ctx, uint8_t *digest,
+				  size_t len)
+{
+	struct mbed_hmac_ctx *c = to_hmac_ctx(ctx);
+	size_t hmac_size = mbedtls_md_get_size(c->md_ctx.md_info);
+	uint8_t block_digest[TEE_MAX_HASH_SIZE] = { 0 };
+	uint8_t *tmp_digest = NULL;
+
+	if (len == 0)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	if (hmac_size > len) {
+		if (hmac_size > sizeof(block_digest))
+			return TEE_ERROR_BAD_STATE;
+		tmp_digest = block_digest; /* use a tempory buffer */
+	} else {
+		tmp_digest = digest;
+	}
+
+	if (mbedtls_md_hmac_finish(&c->md_ctx, tmp_digest))
+		return TEE_ERROR_BAD_STATE;
+
+	if (hmac_size > len)
+		memcpy(digest, tmp_digest, len);
+
+	return TEE_SUCCESS;
+}
+
+static void mbed_hmac_free_ctx(struct crypto_mac_ctx *ctx)
+{
+	struct mbed_hmac_ctx *c = to_hmac_ctx(ctx);
+
+	mbedtls_md_free(&c->md_ctx);
+	free(c);
+}
+
+static void mbed_hmac_copy_state(struct crypto_mac_ctx *dst_ctx,
+				 struct crypto_mac_ctx *src_ctx)
+{
+	struct mbed_hmac_ctx *src = to_hmac_ctx(src_ctx);
+	struct mbed_hmac_ctx *dst = to_hmac_ctx(dst_ctx);
+
+	if (mbedtls_md_clone(&dst->md_ctx, &src->md_ctx))
+		panic();
+}
+
+static const struct crypto_mac_ops mbed_hmac_ops = {
+	.init = mbed_hmac_init,
+	.update = mbed_hmac_update,
+	.final = mbed_hmac_final,
+	.free_ctx = mbed_hmac_free_ctx,
+	.copy_state = mbed_hmac_copy_state,
+};
+
+static TEE_Result mbed_hmac_alloc_ctx(struct crypto_mac_ctx **ctx_ret,
+				      mbedtls_md_type_t md_type)
+{
+	int mbed_res = 0;
+	struct mbed_hmac_ctx *c = NULL;
+	const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
+
+	if (!md_info)
+		return TEE_ERROR_NOT_SUPPORTED;
+
+	c = calloc(1, sizeof(*c));
+	if (!c)
+		return TEE_ERROR_OUT_OF_MEMORY;
+
+	c->mac_ctx.ops = &mbed_hmac_ops;
+	mbed_res = mbedtls_md_setup(&c->md_ctx, md_info, 1);
+	if (mbed_res) {
+		free(c);
+		if (mbed_res == MBEDTLS_ERR_MD_ALLOC_FAILED)
+			return TEE_ERROR_OUT_OF_MEMORY;
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+
+	*ctx_ret = &c->mac_ctx;
+
+	return TEE_SUCCESS;
+}
+
+#if defined(CFG_CRYPTO_MD5)
+TEE_Result crypto_hmac_md5_alloc_ctx(struct crypto_mac_ctx **ctx)
+{
+	return mbed_hmac_alloc_ctx(ctx, MBEDTLS_MD_MD5);
+}
+#endif
+
+#if defined(CFG_CRYPTO_SHA1)
+TEE_Result crypto_hmac_sha1_alloc_ctx(struct crypto_mac_ctx **ctx)
+{
+	return mbed_hmac_alloc_ctx(ctx, MBEDTLS_MD_SHA1);
+}
+#endif
+
+#if defined(CFG_CRYPTO_SHA224)
+TEE_Result crypto_hmac_sha224_alloc_ctx(struct crypto_mac_ctx **ctx)
+{
+	return mbed_hmac_alloc_ctx(ctx, MBEDTLS_MD_SHA224);
+}
+#endif
+
+#if defined(CFG_CRYPTO_SHA256)
+TEE_Result crypto_hmac_sha256_alloc_ctx(struct crypto_mac_ctx **ctx)
+{
+	return mbed_hmac_alloc_ctx(ctx, MBEDTLS_MD_SHA256);
+}
+#endif
+
+#if defined(CFG_CRYPTO_SHA384)
+TEE_Result crypto_hmac_sha384_alloc_ctx(struct crypto_mac_ctx **ctx)
+{
+	return mbed_hmac_alloc_ctx(ctx, MBEDTLS_MD_SHA384);
+}
+#endif
+
+#if defined(CFG_CRYPTO_SHA512)
+TEE_Result crypto_hmac_sha512_alloc_ctx(struct crypto_mac_ctx **ctx)
+{
+	return mbed_hmac_alloc_ctx(ctx, MBEDTLS_MD_SHA512);
+}
+#endif
diff --git a/lib/libmbedtls/core/stubbed.c b/lib/libmbedtls/core/stubbed.c
index 58ddcf5..2aca4e4 100644
--- a/lib/libmbedtls/core/stubbed.c
+++ b/lib/libmbedtls/core/stubbed.c
@@ -283,15 +283,6 @@
 	crypto_##name##_alloc_ctx(struct crypto_##type##_ctx **ctx __unused) \
 	{ return TEE_ERROR_NOT_IMPLEMENTED; }
 
-#if defined(CFG_CRYPTO_HMAC)
-CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(hmac_md5, mac)
-CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(hmac_sha1, mac)
-CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(hmac_sha224, mac)
-CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(hmac_sha256, mac)
-CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(hmac_sha384, mac)
-CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(hmac_sha512, mac)
-#endif
-
 #if defined(CFG_CRYPTO_CMAC)
 CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(aes_cmac, mac)
 #endif
diff --git a/lib/libmbedtls/core/sub.mk b/lib/libmbedtls/core/sub.mk
index 0626574..cd0bdb0 100644
--- a/lib/libmbedtls/core/sub.mk
+++ b/lib/libmbedtls/core/sub.mk
@@ -18,3 +18,5 @@
 srcs-$(CFG_CRYPTO_CBC) += des_cbc.c
 srcs-$(CFG_CRYPTO_CBC) += des3_cbc.c
 endif
+
+srcs-$(CFG_CRYPTO_HMAC) += hmac.c
diff --git a/lib/libmbedtls/include/mbedtls_config_kernel.h b/lib/libmbedtls/include/mbedtls_config_kernel.h
index 0c8ad37..bdb34e8 100644
--- a/lib/libmbedtls/include/mbedtls_config_kernel.h
+++ b/lib/libmbedtls/include/mbedtls_config_kernel.h
@@ -37,6 +37,10 @@
 #define MBEDTLS_MD_C
 #endif
 
+#if defined(CFG_CRYPTO_HMAC)
+#define MBEDTLS_MD_C
+#endif
+
 #if defined(CFG_CRYPTO_AES)
 #define MBEDTLS_AES_C
 #define MBEDTLS_AES_ROM_TABLES