Upstream-Status: Pending [Not submitted to upstream yet]
Signed-off-by: Emekcan Aras <Emekcan.Aras@arm.com>

From d800f7eaa25efca41535a223ef5d524651dee103 Mon Sep 17 00:00:00 2001
From: Julian Hall <julian.hall@arm.com>
Date: Fri, 11 Feb 2022 14:24:53 +0000
Subject: [PATCH 06/15] Integrate AEAD operation support

Resolves issues and integrates AEAD support into the crypto service
provider and clients.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I5fbe78a2dd825f592e26fd665f60c18b576f9de9
---
 .../caller/packed-c/crypto_caller_aead.h      |  70 +++---
 .../client/caller/stub/crypto_caller_aead.h   |  12 +-
 .../service/crypto/client/psa/psa_aead.c      | 221 +++++++++++++++---
 .../factory/full/crypto_provider_factory.c    |  16 +-
 .../component-test/component-test.cmake       |   4 +-
 deployments/crypto/opteesp/CMakeLists.txt     |   4 +-
 deployments/libts/linux-pc/CMakeLists.txt     |   4 +-
 deployments/se-proxy/opteesp/CMakeLists.txt   |   4 +-
 8 files changed, 263 insertions(+), 72 deletions(-)

diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_aead.h b/components/service/crypto/client/caller/packed-c/crypto_caller_aead.h
index 3d9947d5..c4ffb20c 100644
--- a/components/service/crypto/client/caller/packed-c/crypto_caller_aead.h
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_aead.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -20,38 +20,6 @@
 extern "C" {
 #endif

-static inline psa_status_t crypto_caller_aead_encrypt(struct service_client *context,
-	psa_key_id_t key,
-	psa_algorithm_t alg,
-	const uint8_t *nonce,
-	size_t nonce_length,
-	const uint8_t *additional_data,
-	size_t additional_data_length,
-	const uint8_t *plaintext,
-	size_t plaintext_length,
-	uint8_t *aeadtext,
-	size_t aeadtext_size,
-	size_t *aeadtext_length)
-{
-	return PSA_ERROR_NOT_SUPPORTED;
-}
-
-static inline psa_status_t crypto_caller_aead_decrypt(struct service_client *context,
-	psa_key_id_t key,
-	psa_algorithm_t alg,
-	const uint8_t *nonce,
-	size_t nonce_length,
-	const uint8_t *additional_data,
-	size_t additional_data_length,
-	const uint8_t *aeadtext,
-	size_t aeadtext_length,
-	uint8_t *plaintext,
-	size_t plaintext_size,
-	size_t *plaintext_length)
-{
-	return PSA_ERROR_NOT_SUPPORTED;
-}
-
 static inline psa_status_t common_aead_setup(struct service_client *context,
 	uint32_t *op_handle,
 	psa_key_id_t key,
@@ -247,7 +215,7 @@ static inline psa_status_t crypto_caller_aead_set_lengths(struct service_client
 {
 	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
 	struct ts_crypto_aead_set_lengths_in req_msg;
-	size_t req_fixed_len = sizeof(struct ts_crypto_aead_abort_in);
+	size_t req_fixed_len = sizeof(struct ts_crypto_aead_set_lengths_in);
 	size_t req_len = req_fixed_len;

 	req_msg.op_handle = op_handle;
@@ -611,6 +579,40 @@ static inline psa_status_t crypto_caller_aead_abort(struct service_client *conte
 	return psa_status;
 }

+/**
+ * The maximum data length that may be carried in an update operation will be
+ * constrained by the maximum call payload capacity imposed by the end-to-end
+ * RPC call path. These functions return the maximum update size when serialization
+ * overheads are considered. This allows large paylaods to be processed in
+ * maximum size chunks.
+ */
+static inline size_t crypto_caller_aead_max_update_ad_size(const struct service_client *context)
+{
+	/* Returns the maximum number of bytes of additional data that may be
+	 * carried as a parameter of the aead_update_ad operation
+	 * using the packed-c encoding.
+	 */
+	size_t payload_space = context->service_info.max_payload;
+	size_t overhead = sizeof(struct ts_crypto_aead_update_ad_in) + TLV_HDR_LEN;
+
+	return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
+static inline size_t crypto_caller_aead_max_update_size(const struct service_client *context)
+{
+	/* Returns the maximum number of bytes that may be
+	 * carried as a parameter of the aead_update operation
+	 * using the packed-c encoding.
+	 */
+	size_t payload_space = context->service_info.max_payload;
+	size_t overhead = sizeof(struct ts_crypto_aead_update_in) + TLV_HDR_LEN;
+
+	/* Allow for output to be a whole number of blocks */
+	overhead += PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE;
+
+	return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_aead.h b/components/service/crypto/client/caller/stub/crypto_caller_aead.h
index 18aa8cec..455e7ac1 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller_aead.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller_aead.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -135,6 +135,16 @@ static inline psa_status_t crypto_caller_aead_abort(struct service_client *conte
 	return PSA_ERROR_NOT_SUPPORTED;
 }

+static inline size_t crypto_caller_aead_max_update_ad_size(const struct service_client *context)
+{
+	return 0;
+}
+
+static inline size_t crypto_caller_aead_max_update_size(const struct service_client *context)
+{
+	return 0;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/components/service/crypto/client/psa/psa_aead.c b/components/service/crypto/client/psa/psa_aead.c
index 22fd3da1..e4579e63 100644
--- a/components/service/crypto/client/psa/psa_aead.c
+++ b/components/service/crypto/client/psa/psa_aead.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,37 +8,6 @@
 #include "psa_crypto_client.h"
 #include "crypto_caller_selector.h"

-
-psa_status_t psa_aead_encrypt(psa_key_id_t key,
-	psa_algorithm_t alg,
-	const uint8_t *nonce,
-	size_t nonce_length,
-	const uint8_t *additional_data,
-	size_t additional_data_length,
-	const uint8_t *plaintext,
-	size_t plaintext_length,
-	uint8_t *aeadtext,
-	size_t aeadtext_size,
-	size_t *aeadtext_length)
-{
-	return PSA_ERROR_NOT_SUPPORTED;
-}
-
-psa_status_t psa_aead_decrypt(psa_key_id_t key,
-	psa_algorithm_t alg,
-	const uint8_t *nonce,
-	size_t nonce_length,
-	const uint8_t *additional_data,
-	size_t additional_data_length,
-	const uint8_t *aeadtext,
-	size_t aeadtext_length,
-	uint8_t *plaintext,
-	size_t plaintext_size,
-	size_t *plaintext_length)
-{
-	return PSA_ERROR_NOT_SUPPORTED;
-}
-
 psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation,
 	psa_key_id_t key,
 	psa_algorithm_t alg)
@@ -143,3 +112,191 @@ psa_status_t psa_aead_abort(psa_aead_operation_t *operation)
 	return crypto_caller_aead_abort(&psa_crypto_client_instance.base,
 		operation->handle);
 }
+
+static psa_status_t multi_aead_update_ad(psa_aead_operation_t *operation,
+	const uint8_t *input,
+	size_t input_length)
+{
+	psa_status_t psa_status = PSA_SUCCESS;
+	size_t max_update_size =
+		crypto_caller_aead_max_update_ad_size(&psa_crypto_client_instance.base);
+	size_t bytes_input = 0;
+
+	if (!max_update_size) {
+
+		/* Don't know the max update size so assume that the entire
+		 * input and output can be handled in a single update.  If
+		 * this isn't true, the first aead update operation will fail
+		 * safely.
+		 */
+		max_update_size = input_length;
+	}
+
+	while (bytes_input < input_length) {
+
+		size_t bytes_remaining = input_length - bytes_input;
+		size_t update_len = (bytes_remaining < max_update_size) ?
+			bytes_remaining :
+			max_update_size;
+
+		psa_status = psa_aead_update_ad(operation,
+			&input[bytes_input], update_len);
+
+		if (psa_status != PSA_SUCCESS) break;
+
+		bytes_input += update_len;
+	}
+
+	return psa_status;
+}
+
+static psa_status_t multi_aead_update(psa_aead_operation_t *operation,
+	const uint8_t *input,
+	size_t input_length,
+	uint8_t *output,
+	size_t output_size,
+	size_t *output_length)
+{
+	psa_status_t psa_status = PSA_SUCCESS;
+	size_t max_update_size =
+		crypto_caller_aead_max_update_size(&psa_crypto_client_instance.base);
+	size_t bytes_input = 0;
+	size_t bytes_output = 0;
+
+	*output_length = 0;
+
+	if (!max_update_size) {
+
+		/* Don't know the max update size so assume that the entire
+		 * input and output can be handled in a single update.  If
+		 * this isn't true, the first aead update operation will fail
+		 * safely.
+		 */
+		max_update_size = input_length;
+	}
+
+	while ((bytes_input < input_length) && (bytes_output < output_size)) {
+
+		size_t update_output_len = 0;
+		size_t bytes_remaining = input_length - bytes_input;
+		size_t update_len = (bytes_remaining < max_update_size) ?
+			bytes_remaining :
+			max_update_size;
+
+		psa_status = psa_aead_update(operation,
+			&input[bytes_input], update_len,
+			&output[bytes_output], output_size - bytes_output, &update_output_len);
+
+		if (psa_status != PSA_SUCCESS) break;
+
+		bytes_input += update_len;
+		bytes_output += update_output_len;
+	}
+
+	if (psa_status == PSA_SUCCESS) {
+
+		*output_length = bytes_output;
+	}
+
+	return psa_status;
+}
+
+psa_status_t psa_aead_encrypt(psa_key_id_t key,
+	psa_algorithm_t alg,
+	const uint8_t *nonce,
+	size_t nonce_length,
+	const uint8_t *additional_data,
+	size_t additional_data_length,
+	const uint8_t *plaintext,
+	size_t plaintext_length,
+	uint8_t *aeadtext,
+	size_t aeadtext_size,
+	size_t *aeadtext_length)
+{
+	psa_aead_operation_t operation = psa_aead_operation_init();
+	size_t bytes_output = 0;
+	*aeadtext_length = 0;
+
+	psa_status_t psa_status = psa_aead_encrypt_setup(&operation, key, alg);
+	if (psa_status != PSA_SUCCESS) return psa_status;
+
+	if ((psa_status = psa_aead_set_lengths(&operation, additional_data_length, plaintext_length),
+			psa_status == PSA_SUCCESS) &&
+		(psa_status = psa_aead_set_nonce(&operation, nonce, nonce_length),
+			psa_status == PSA_SUCCESS) &&
+		(psa_status = multi_aead_update_ad(&operation, additional_data, additional_data_length),
+			psa_status == PSA_SUCCESS) &&
+		(psa_status = multi_aead_update(&operation, plaintext, plaintext_length,
+			aeadtext, aeadtext_size, &bytes_output),
+			psa_status == PSA_SUCCESS))
+	{
+		size_t remaining_aead_len = 0;
+		size_t tag_len = 0;
+
+		psa_status = psa_aead_finish(&operation,
+			NULL, 0, &remaining_aead_len,
+			&aeadtext[bytes_output], aeadtext_size - bytes_output, &tag_len);
+
+		if (psa_status == PSA_SUCCESS) {
+
+			*aeadtext_length = bytes_output + remaining_aead_len + tag_len;
+		}
+	}
+	else {
+
+		psa_aead_abort(&operation);
+	}
+
+	return psa_status;
+}
+
+psa_status_t psa_aead_decrypt(psa_key_id_t key,
+	psa_algorithm_t alg,
+	const uint8_t *nonce,
+	size_t nonce_length,
+	const uint8_t *additional_data,
+	size_t additional_data_length,
+	const uint8_t *aeadtext,
+	size_t aeadtext_length,
+	uint8_t *plaintext,
+	size_t plaintext_size,
+	size_t *plaintext_length)
+{
+	psa_aead_operation_t operation = psa_aead_operation_init();
+	size_t bytes_output = 0;
+	*plaintext_length = 0;
+
+	psa_status_t psa_status = psa_aead_decrypt_setup(&operation, key, alg);
+	if (psa_status != PSA_SUCCESS) return psa_status;
+
+	size_t tag_len = PSA_ALG_AEAD_GET_TAG_LENGTH(alg);
+	size_t ciphertext_len = (aeadtext_length > tag_len) ? aeadtext_length - tag_len : 0;
+
+	if ((psa_status = psa_aead_set_lengths(&operation, additional_data_length, ciphertext_len),
+			psa_status == PSA_SUCCESS) &&
+		(psa_status = psa_aead_set_nonce(&operation, nonce, nonce_length),
+			psa_status == PSA_SUCCESS) &&
+		(psa_status = multi_aead_update_ad(&operation, additional_data, additional_data_length),
+			psa_status == PSA_SUCCESS) &&
+		(psa_status = multi_aead_update(&operation, aeadtext, ciphertext_len,
+			plaintext, plaintext_size, &bytes_output),
+			psa_status == PSA_SUCCESS))
+	{
+		size_t remaining_plaintext_len = 0;
+
+		psa_status = psa_aead_verify(&operation,
+			NULL, 0, &remaining_plaintext_len,
+			&aeadtext[bytes_output], aeadtext_length - bytes_output);
+
+		if (psa_status == PSA_SUCCESS) {
+
+			*plaintext_length = bytes_output + remaining_plaintext_len;
+		}
+	}
+	else {
+
+		psa_aead_abort(&operation);
+	}
+
+	return psa_status;
+}
diff --git a/components/service/crypto/factory/full/crypto_provider_factory.c b/components/service/crypto/factory/full/crypto_provider_factory.c
index 2d926eb6..ee2b4473 100644
--- a/components/service/crypto/factory/full/crypto_provider_factory.c
+++ b/components/service/crypto/factory/full/crypto_provider_factory.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -17,6 +17,8 @@
 #include <service/crypto/provider/extension/key_derivation/serializer/packed-c/packedc_key_derivation_provider_serializer.h>
 #include <service/crypto/provider/extension/mac/mac_provider.h>
 #include <service/crypto/provider/extension/mac/serializer/packed-c/packedc_mac_provider_serializer.h>
+#include <service/crypto/provider/extension/aead/aead_provider.h>
+#include <service/crypto/provider/extension/aead/serializer/packed-c/packedc_aead_provider_serializer.h>
 #include <service/discovery/provider/discovery_provider.h>
 #include <service/discovery/provider/serializer/packed-c/packedc_discovery_provider_serializer.h>

@@ -34,6 +36,7 @@ static struct full_crypto_provider
 	struct cipher_provider cipher_provider;
 	struct key_derivation_provider key_derivation_provider;
 	struct mac_provider mac_provider;
+	struct aead_provider aead_provider;

 } instance;

@@ -98,6 +101,17 @@ struct crypto_provider *crypto_provider_factory_create(void)
 	crypto_provider_extend(&instance.crypto_provider,
 		&instance.mac_provider.base_provider);

+	/**
+	 * Extend with aead operations
+	 */
+	aead_provider_init(&instance.aead_provider);
+
+	aead_provider_register_serializer(&instance.aead_provider,
+		TS_RPC_ENCODING_PACKED_C, packedc_aead_provider_serializer_instance());
+
+	crypto_provider_extend(&instance.crypto_provider,
+		&instance.aead_provider.base_provider);
+
 	return &instance.crypto_provider;
 }

diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index a0233c34..c3b015ab 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -85,6 +85,8 @@ add_components(
 		"components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
 		"components/service/crypto/provider/extension/mac"
 		"components/service/crypto/provider/extension/mac/serializer/packed-c"
+		"components/service/crypto/provider/extension/aead"
+		"components/service/crypto/provider/extension/aead/serializer/packed-c"
 		"components/service/crypto/provider/test"
 		"components/service/crypto/backend/mbedcrypto"
 		"components/service/crypto/factory/full"
diff --git a/deployments/crypto/opteesp/CMakeLists.txt b/deployments/crypto/opteesp/CMakeLists.txt
index 8ada74e9..eb5d0847 100644
--- a/deployments/crypto/opteesp/CMakeLists.txt
+++ b/deployments/crypto/opteesp/CMakeLists.txt
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -62,6 +62,8 @@ add_components(TARGET "crypto-sp"
 		"components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
 		"components/service/crypto/provider/extension/mac"
 		"components/service/crypto/provider/extension/mac/serializer/packed-c"
+		"components/service/crypto/provider/extension/aead"
+		"components/service/crypto/provider/extension/aead/serializer/packed-c"
 		"components/service/crypto/factory/full"
 		"components/service/crypto/backend/mbedcrypto"
 		"components/service/crypto/backend/mbedcrypto/trng_adapter/platform"
diff --git a/deployments/libts/linux-pc/CMakeLists.txt b/deployments/libts/linux-pc/CMakeLists.txt
index fc98407c..97eaaa73 100644
--- a/deployments/libts/linux-pc/CMakeLists.txt
+++ b/deployments/libts/linux-pc/CMakeLists.txt
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -71,6 +71,8 @@ add_components(
 		"components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
 		"components/service/crypto/provider/extension/mac"
 		"components/service/crypto/provider/extension/mac/serializer/packed-c"
+		"components/service/crypto/provider/extension/aead"
+		"components/service/crypto/provider/extension/aead/serializer/packed-c"
 		"components/service/crypto/factory/full"
 		"components/service/crypto/backend/mbedcrypto"
 		"components/service/crypto/backend/mbedcrypto/trng_adapter/linux"
diff --git a/deployments/se-proxy/opteesp/CMakeLists.txt b/deployments/se-proxy/opteesp/CMakeLists.txt
index 953bb716..24a8ca65 100644
--- a/deployments/se-proxy/opteesp/CMakeLists.txt
+++ b/deployments/se-proxy/opteesp/CMakeLists.txt
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -70,6 +70,8 @@ add_components(TARGET "se-proxy"
 		"components/service/crypto/provider/extension/key_derivation/serializer/packed-c"
 		"components/service/crypto/provider/extension/mac"
 		"components/service/crypto/provider/extension/mac/serializer/packed-c"
+		"components/service/crypto/provider/extension/aead"
+		"components/service/crypto/provider/extension/aead/serializer/packed-c"
 		"components/service/crypto/factory/full"
 		"components/service/secure_storage/include"
 		"components/service/secure_storage/frontend/secure_storage_provider"
--
2.25.1
