xref: /optee_os/ta/pkcs11/src/processing_aes.c (revision 04e46975d8f02e25209af552aaea4acb4d70c7f9)
1512cbf1dSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2512cbf1dSJens Wiklander /*
3512cbf1dSJens Wiklander  * Copyright (c) 2018-2020, Linaro Limited
4512cbf1dSJens Wiklander  */
5512cbf1dSJens Wiklander 
6512cbf1dSJens Wiklander #include <assert.h>
7512cbf1dSJens Wiklander #include <compiler.h>
8512cbf1dSJens Wiklander #include <tee_internal_api.h>
963778faaSEtienne Carriere #include <tee_internal_api_extensions.h>
10512cbf1dSJens Wiklander #include <trace.h>
11512cbf1dSJens Wiklander #include <util.h>
12512cbf1dSJens Wiklander 
13512cbf1dSJens Wiklander #include "pkcs11_helpers.h"
14512cbf1dSJens Wiklander #include "pkcs11_token.h"
15512cbf1dSJens Wiklander #include "processing.h"
16512cbf1dSJens Wiklander #include "serializer.h"
17512cbf1dSJens Wiklander 
1863778faaSEtienne Carriere /*
1963778faaSEtienne Carriere  * Authenticated ciphering: (AES GCM)
2063778faaSEtienne Carriere  *
2163778faaSEtienne Carriere  * As per PKCS#11, GCM decryption shall not reveal the data until the
2263778faaSEtienne Carriere  * decryption is completed and the MAC verified. The pkcs11 TA retains the
2363778faaSEtienne Carriere  * ciphered data until the operation is completed. Therefore every chunk of
2463778faaSEtienne Carriere  * decrypted data is saved in a allocated buffer during AE update processing
2563778faaSEtienne Carriere  * and only copied into the client's output buffer at AE finalization when
2663778faaSEtienne Carriere  * tag is authenticated.
2763778faaSEtienne Carriere  *
2863778faaSEtienne Carriere  * As per PKCS#11, GCM decryption expect the tag data to be provided
2963778faaSEtienne Carriere  * inside the input data for C_DecryptUpdate() and friends, appended to the
3063778faaSEtienne Carriere  * input encyprted data hence we do not know which is the last call to
3163778faaSEtienne Carriere  * C_DecryptUpdate() where last bytes are not ciphered data but the requested
3263778faaSEtienne Carriere  * tag bytes for message autehntication. To handle this, the TA saves
3363778faaSEtienne Carriere  * the last input data bytes (length is defined by the tag byte size) in the
3463778faaSEtienne Carriere  * AE context and waits the C_DecryptFinal() to either treat these as data
3563778faaSEtienne Carriere  * bytes or tag/MAC bytes. Refer to pending_tag and pending_size in struct
3663778faaSEtienne Carriere  * ae_aes_context.
3763778faaSEtienne Carriere  */
3863778faaSEtienne Carriere 
3963778faaSEtienne Carriere /*
4063778faaSEtienne Carriere  * struct out_data_ref - AE decyrption output data chunks
4163778faaSEtienne Carriere  * @size - byte size of the allocated buffer
4263778faaSEtienne Carriere  * @data - pointer to allocated data
4363778faaSEtienne Carriere  */
4463778faaSEtienne Carriere struct out_data_ref {
4563778faaSEtienne Carriere 	size_t size;
4663778faaSEtienne Carriere 	void *data;
4763778faaSEtienne Carriere };
4863778faaSEtienne Carriere 
4963778faaSEtienne Carriere /*
5063778faaSEtienne Carriere  * struct ae_aes_context - Extra context data got AE operations
5163778faaSEtienne Carriere  * @tag_byte_len - Tag size in byte
5263778faaSEtienne Carriere  * @pending_tag - Input data that could be the appended tag
5363778faaSEtienne Carriere  * @pending_size - Size of pending input data that could be the tag
5463778faaSEtienne Carriere  * @out_data - Pointer to an array of output data references.
5563778faaSEtienne Carriere  * @out_count - Number of buffer references in out_data
5663778faaSEtienne Carriere  */
5763778faaSEtienne Carriere struct ae_aes_context {
5863778faaSEtienne Carriere 	size_t tag_byte_len;
5963778faaSEtienne Carriere 	char *pending_tag;
6063778faaSEtienne Carriere 	size_t pending_size;
6163778faaSEtienne Carriere 	struct out_data_ref *out_data;
6263778faaSEtienne Carriere 	size_t out_count;
6363778faaSEtienne Carriere };
6463778faaSEtienne Carriere 
init_ae_aes_context(struct ae_aes_context * ctx)6563778faaSEtienne Carriere static enum pkcs11_rc init_ae_aes_context(struct ae_aes_context *ctx)
6663778faaSEtienne Carriere {
6763778faaSEtienne Carriere 	struct out_data_ref *out_data = NULL;
6863778faaSEtienne Carriere 	char *pending_tag = NULL;
6963778faaSEtienne Carriere 
7063778faaSEtienne Carriere 	assert(!ctx->out_data && !ctx->out_count &&
7163778faaSEtienne Carriere 	       !ctx->pending_tag && !ctx->pending_size);
7263778faaSEtienne Carriere 
7363778faaSEtienne Carriere 	out_data = TEE_Malloc(sizeof(*out_data), TEE_MALLOC_FILL_ZERO);
7463778faaSEtienne Carriere 	pending_tag = TEE_Malloc(ctx->tag_byte_len, TEE_MALLOC_FILL_ZERO);
7563778faaSEtienne Carriere 
7663778faaSEtienne Carriere 	if (!out_data || !pending_tag) {
7763778faaSEtienne Carriere 		TEE_Free(out_data);
7863778faaSEtienne Carriere 		TEE_Free(pending_tag);
7963778faaSEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
8063778faaSEtienne Carriere 	}
8163778faaSEtienne Carriere 
8263778faaSEtienne Carriere 	ctx->pending_tag = pending_tag;
8363778faaSEtienne Carriere 	ctx->out_data = out_data;
8463778faaSEtienne Carriere 
8563778faaSEtienne Carriere 	return PKCS11_CKR_OK;
8663778faaSEtienne Carriere }
8763778faaSEtienne Carriere 
release_ae_aes_context(struct ae_aes_context * ctx)8863778faaSEtienne Carriere static void release_ae_aes_context(struct ae_aes_context *ctx)
8963778faaSEtienne Carriere {
9063778faaSEtienne Carriere 	size_t n = 0;
9163778faaSEtienne Carriere 
9263778faaSEtienne Carriere 	for (n = 0; n < ctx->out_count; n++)
9363778faaSEtienne Carriere 		TEE_Free(ctx->out_data[n].data);
9463778faaSEtienne Carriere 
9563778faaSEtienne Carriere 	TEE_Free(ctx->out_data);
9663778faaSEtienne Carriere 	ctx->out_data = NULL;
9763778faaSEtienne Carriere 	ctx->out_count = 0;
9863778faaSEtienne Carriere 
9963778faaSEtienne Carriere 	TEE_Free(ctx->pending_tag);
10063778faaSEtienne Carriere 	ctx->pending_tag = NULL;
10163778faaSEtienne Carriere 	ctx->pending_size = 0;
10263778faaSEtienne Carriere }
10363778faaSEtienne Carriere 
10463778faaSEtienne Carriere /*
10563778faaSEtienne Carriere  * This function feeds the AE decryption processing with client
10663778faaSEtienne Carriere  * input data. There are 2 constraints to consider.
10763778faaSEtienne Carriere  *
10863778faaSEtienne Carriere  * Firstly we don't know yet which are the ciphered data and which are
10963778faaSEtienne Carriere  * the tag data. GP TEE Internal API function requires we split data and
11063778faaSEtienne Carriere  * tag when TEE_AEDecryptFinal() will be called.
11163778faaSEtienne Carriere  *
11263778faaSEtienne Carriere  * Secondly any generated data must be kept in the TA and only revealed
11363778faaSEtienne Carriere  * once tag if succefully processed.
11463778faaSEtienne Carriere  */
tee_ae_decrypt_update(struct pkcs11_session * session,void * in,size_t in_size)11563778faaSEtienne Carriere enum pkcs11_rc tee_ae_decrypt_update(struct pkcs11_session *session,
11663778faaSEtienne Carriere 				     void *in, size_t in_size)
11763778faaSEtienne Carriere {
11863778faaSEtienne Carriere 	struct ae_aes_context *ctx = session->processing->extra_ctx;
11963778faaSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
12063778faaSEtienne Carriere 	enum pkcs11_rc rc = PKCS11_CKR_OK;
12163778faaSEtienne Carriere 	size_t data_len = 0;
12263778faaSEtienne Carriere 	size_t ct_size = 0;
12363778faaSEtienne Carriere 	void *ptr = NULL;
12463778faaSEtienne Carriere 	char *ct = NULL;
12563778faaSEtienne Carriere 
12663778faaSEtienne Carriere 	if (!in_size)
12763778faaSEtienne Carriere 		return PKCS11_CKR_OK;
12863778faaSEtienne Carriere 
12963778faaSEtienne Carriere 	if (!in)
13063778faaSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
13163778faaSEtienne Carriere 
13263778faaSEtienne Carriere 	/*
13363778faaSEtienne Carriere 	 * Save the last input bytes in case they are the tag
13463778faaSEtienne Carriere 	 * bytes and not ciphered data bytes to be decrypted.
13563778faaSEtienne Carriere 	 */
13663778faaSEtienne Carriere 
13763778faaSEtienne Carriere 	if (ctx->pending_size + in_size <= ctx->tag_byte_len) {
13863778faaSEtienne Carriere 		/*
13963778faaSEtienne Carriere 		 * Data bytes are all potential tag bytes.
14063778faaSEtienne Carriere 		 * We only need to update the pending_tag buffer,
14163778faaSEtienne Carriere 		 * and cannot treat any byte as data byte.
14263778faaSEtienne Carriere 		 */
14363778faaSEtienne Carriere 		TEE_MemMove(ctx->pending_tag + ctx->pending_size, in, in_size);
14463778faaSEtienne Carriere 
14563778faaSEtienne Carriere 		ctx->pending_size += in_size;
14663778faaSEtienne Carriere 
14763778faaSEtienne Carriere 		return PKCS11_CKR_OK;
14863778faaSEtienne Carriere 	}
14963778faaSEtienne Carriere 
15063778faaSEtienne Carriere 	/* Size of data that are not potential tag in pending and input data */
15163778faaSEtienne Carriere 	data_len = in_size + ctx->pending_size - ctx->tag_byte_len;
15263778faaSEtienne Carriere 
15363778faaSEtienne Carriere 	/* Process pending bytes that are effective data byte */
15463778faaSEtienne Carriere 	if (ctx->pending_size &&
15563778faaSEtienne Carriere 	    (ctx->pending_size + in_size) >= ctx->tag_byte_len) {
15663778faaSEtienne Carriere 		uint32_t len = MIN(data_len, ctx->pending_size);
15763778faaSEtienne Carriere 
15863778faaSEtienne Carriere 		res = TEE_AEUpdate(session->processing->tee_op_handle,
15963778faaSEtienne Carriere 				   ctx->pending_tag, len, NULL, &ct_size);
16063778faaSEtienne Carriere 		if (res && res != TEE_ERROR_SHORT_BUFFER) {
16163778faaSEtienne Carriere 			rc = tee2pkcs_error(res);
16263778faaSEtienne Carriere 			goto out;
16363778faaSEtienne Carriere 		}
16463778faaSEtienne Carriere 		assert(res == TEE_ERROR_SHORT_BUFFER || !ct_size);
16563778faaSEtienne Carriere 
16663778faaSEtienne Carriere 		/*
16763778faaSEtienne Carriere 		 * If output data to store (not revealed yet), redo with
16863778faaSEtienne Carriere 		 * an allocated temporary reference.
16963778faaSEtienne Carriere 		 */
17063778faaSEtienne Carriere 		if (ct_size) {
17163778faaSEtienne Carriere 			ct = TEE_Malloc(ct_size, TEE_MALLOC_FILL_ZERO);
17263778faaSEtienne Carriere 			if (!ct) {
17363778faaSEtienne Carriere 				rc = PKCS11_CKR_DEVICE_MEMORY;
17463778faaSEtienne Carriere 				goto out;
17563778faaSEtienne Carriere 			}
17663778faaSEtienne Carriere 
17763778faaSEtienne Carriere 			res = TEE_AEUpdate(session->processing->tee_op_handle,
17863778faaSEtienne Carriere 					   ctx->pending_tag, len, ct, &ct_size);
17963778faaSEtienne Carriere 			if (res) {
18063778faaSEtienne Carriere 				rc = tee2pkcs_error(res);
18163778faaSEtienne Carriere 				goto out;
18263778faaSEtienne Carriere 			}
18363778faaSEtienne Carriere 			assert(ct_size);
18463778faaSEtienne Carriere 		}
18563778faaSEtienne Carriere 
18663778faaSEtienne Carriere 		/* Save potential tag bytes for later */
18763778faaSEtienne Carriere 		TEE_MemMove(ctx->pending_tag, ctx->pending_tag + len,
18863778faaSEtienne Carriere 			    ctx->pending_size - len);
18963778faaSEtienne Carriere 
19063778faaSEtienne Carriere 		ctx->pending_size -= len;
19163778faaSEtienne Carriere 		data_len -= len;
19263778faaSEtienne Carriere 	}
19363778faaSEtienne Carriere 
19463778faaSEtienne Carriere 	/* Process input data that are not potential tag bytes */
19563778faaSEtienne Carriere 	if (data_len) {
19663778faaSEtienne Carriere 		size_t size = 0;
19763778faaSEtienne Carriere 
19863778faaSEtienne Carriere 		res = TEE_AEUpdate(session->processing->tee_op_handle,
19963778faaSEtienne Carriere 				   in, data_len, NULL, &size);
20063778faaSEtienne Carriere 		if (res != TEE_ERROR_SHORT_BUFFER &&
20163778faaSEtienne Carriere 		    (res != TEE_SUCCESS || size)) {
20263778faaSEtienne Carriere 			/* This is not expected */
20363778faaSEtienne Carriere 			rc = PKCS11_CKR_GENERAL_ERROR;
20463778faaSEtienne Carriere 			goto out;
20563778faaSEtienne Carriere 		}
20663778faaSEtienne Carriere 
20763778faaSEtienne Carriere 		if (size) {
20863778faaSEtienne Carriere 			ptr = TEE_Realloc(ct, ct_size + size);
20963778faaSEtienne Carriere 			if (!ptr) {
21063778faaSEtienne Carriere 				rc = PKCS11_CKR_DEVICE_MEMORY;
21163778faaSEtienne Carriere 				goto out;
21263778faaSEtienne Carriere 			}
21363778faaSEtienne Carriere 			ct = ptr;
21463778faaSEtienne Carriere 
21563778faaSEtienne Carriere 			res = TEE_AEUpdate(session->processing->tee_op_handle,
21663778faaSEtienne Carriere 					   in, data_len, ct + ct_size, &size);
21763778faaSEtienne Carriere 			if (res) {
21863778faaSEtienne Carriere 				rc = tee2pkcs_error(res);
21963778faaSEtienne Carriere 				goto out;
22063778faaSEtienne Carriere 			}
22163778faaSEtienne Carriere 
22263778faaSEtienne Carriere 			ct_size += size;
22363778faaSEtienne Carriere 		}
22463778faaSEtienne Carriere 	}
22563778faaSEtienne Carriere 
22663778faaSEtienne Carriere 	/* Update pending tag in context if any */
22763778faaSEtienne Carriere 	data_len = in_size - data_len;
22863778faaSEtienne Carriere 	if (data_len > (ctx->tag_byte_len - ctx->pending_size)) {
22963778faaSEtienne Carriere 		/* This is not expected */
23063778faaSEtienne Carriere 		rc = PKCS11_CKR_GENERAL_ERROR;
23163778faaSEtienne Carriere 		goto out;
23263778faaSEtienne Carriere 	}
23363778faaSEtienne Carriere 
23463778faaSEtienne Carriere 	if (data_len) {
23563778faaSEtienne Carriere 		TEE_MemMove(ctx->pending_tag + ctx->pending_size,
23663778faaSEtienne Carriere 			    (char *)in + in_size - data_len, data_len);
23763778faaSEtienne Carriere 
23863778faaSEtienne Carriere 		ctx->pending_size += data_len;
23963778faaSEtienne Carriere 	}
24063778faaSEtienne Carriere 
24163778faaSEtienne Carriere 	/* Save output data reference in the context */
24263778faaSEtienne Carriere 	if (ct_size) {
24363778faaSEtienne Carriere 		ptr = TEE_Realloc(ctx->out_data, (ctx->out_count + 1) *
24463778faaSEtienne Carriere 				  sizeof(struct out_data_ref));
24563778faaSEtienne Carriere 		if (!ptr) {
24663778faaSEtienne Carriere 			rc = PKCS11_CKR_DEVICE_MEMORY;
24763778faaSEtienne Carriere 			goto out;
24863778faaSEtienne Carriere 		}
24963778faaSEtienne Carriere 		ctx->out_data = ptr;
25063778faaSEtienne Carriere 		ctx->out_data[ctx->out_count].size = ct_size;
25163778faaSEtienne Carriere 		ctx->out_data[ctx->out_count].data = ct;
25263778faaSEtienne Carriere 		ctx->out_count++;
25363778faaSEtienne Carriere 	}
25463778faaSEtienne Carriere 
25563778faaSEtienne Carriere 	rc = PKCS11_CKR_OK;
25663778faaSEtienne Carriere 
25763778faaSEtienne Carriere out:
25863778faaSEtienne Carriere 	if (rc)
25963778faaSEtienne Carriere 		TEE_Free(ct);
26063778faaSEtienne Carriere 
26163778faaSEtienne Carriere 	return rc;
26263778faaSEtienne Carriere }
26363778faaSEtienne Carriere 
reveal_ae_data(struct ae_aes_context * ctx,void * out,size_t * out_size)26463778faaSEtienne Carriere static enum pkcs11_rc reveal_ae_data(struct ae_aes_context *ctx,
26563778faaSEtienne Carriere 				     void *out, size_t *out_size)
26663778faaSEtienne Carriere {
26763778faaSEtienne Carriere 	uint32_t req_size = 0;
26863778faaSEtienne Carriere 	char *out_ptr = out;
26963778faaSEtienne Carriere 	size_t n = 0;
27063778faaSEtienne Carriere 
27163778faaSEtienne Carriere 	for (req_size = 0, n = 0; n < ctx->out_count; n++)
27263778faaSEtienne Carriere 		req_size += ctx->out_data[n].size;
27363778faaSEtienne Carriere 
27463778faaSEtienne Carriere 	if (*out_size < req_size) {
27563778faaSEtienne Carriere 		*out_size = req_size;
27663778faaSEtienne Carriere 		return PKCS11_CKR_BUFFER_TOO_SMALL;
27763778faaSEtienne Carriere 	}
27863778faaSEtienne Carriere 
27963778faaSEtienne Carriere 	if (!out_ptr)
28063778faaSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
28163778faaSEtienne Carriere 
28263778faaSEtienne Carriere 	for (n = 0; n < ctx->out_count; n++) {
28363778faaSEtienne Carriere 		TEE_MemMove(out_ptr, ctx->out_data[n].data,
28463778faaSEtienne Carriere 			    ctx->out_data[n].size);
28563778faaSEtienne Carriere 		out_ptr += ctx->out_data[n].size;
28663778faaSEtienne Carriere 	}
28763778faaSEtienne Carriere 
28863778faaSEtienne Carriere 	release_ae_aes_context(ctx);
28963778faaSEtienne Carriere 
29063778faaSEtienne Carriere 	*out_size = req_size;
29163778faaSEtienne Carriere 
29263778faaSEtienne Carriere 	return PKCS11_CKR_OK;
29363778faaSEtienne Carriere }
29463778faaSEtienne Carriere 
tee_ae_decrypt_final(struct pkcs11_session * session,void * out,size_t * out_size)29563778faaSEtienne Carriere enum pkcs11_rc tee_ae_decrypt_final(struct pkcs11_session *session,
29663778faaSEtienne Carriere 				    void *out, size_t *out_size)
29763778faaSEtienne Carriere {
29863778faaSEtienne Carriere 	struct ae_aes_context *ctx = session->processing->extra_ctx;
29963778faaSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
30063778faaSEtienne Carriere 	enum pkcs11_rc rc = 0;
30163778faaSEtienne Carriere 	void *data_ptr = NULL;
30263778faaSEtienne Carriere 	size_t data_size = 0;
30363778faaSEtienne Carriere 
30463778faaSEtienne Carriere 	if (!out_size) {
30563778faaSEtienne Carriere 		DMSG("Expect at least a buffer for the output data");
30663778faaSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
30763778faaSEtienne Carriere 	}
30863778faaSEtienne Carriere 
30963778faaSEtienne Carriere 	/* Final is already completed, only need to output the data */
31063778faaSEtienne Carriere 	if (!ctx->pending_tag)
31163778faaSEtienne Carriere 		return reveal_ae_data(ctx, out, out_size);
31263778faaSEtienne Carriere 
31363778faaSEtienne Carriere 	if (ctx->pending_size != ctx->tag_byte_len) {
31463778faaSEtienne Carriere 		DMSG("Not enough samples: %zu/%zu",
31563778faaSEtienne Carriere 		     ctx->pending_size, ctx->tag_byte_len);
31663778faaSEtienne Carriere 		return PKCS11_CKR_ENCRYPTED_DATA_LEN_RANGE;
31763778faaSEtienne Carriere 	}
31863778faaSEtienne Carriere 
31963778faaSEtienne Carriere 	/* Query tag size if any */
32063778faaSEtienne Carriere 	data_size = 0;
32163778faaSEtienne Carriere 	res = TEE_AEDecryptFinal(session->processing->tee_op_handle,
32263778faaSEtienne Carriere 				 NULL, 0, NULL, &data_size,
32363778faaSEtienne Carriere 				 ctx->pending_tag, ctx->tag_byte_len);
32463778faaSEtienne Carriere 
32563778faaSEtienne Carriere 	if (res == TEE_ERROR_SHORT_BUFFER) {
32663778faaSEtienne Carriere 		data_ptr = TEE_Malloc(data_size, TEE_MALLOC_FILL_ZERO);
32763778faaSEtienne Carriere 		if (!data_ptr) {
32863778faaSEtienne Carriere 			rc = PKCS11_CKR_DEVICE_MEMORY;
32963778faaSEtienne Carriere 			goto out;
33063778faaSEtienne Carriere 		}
33163778faaSEtienne Carriere 
33263778faaSEtienne Carriere 		res = TEE_AEDecryptFinal(session->processing->tee_op_handle,
33363778faaSEtienne Carriere 					 NULL, 0, data_ptr, &data_size,
33463778faaSEtienne Carriere 					 ctx->pending_tag, ctx->tag_byte_len);
33563778faaSEtienne Carriere 		assert(res || data_size);
33663778faaSEtienne Carriere 	}
33763778faaSEtienne Carriere 
33863778faaSEtienne Carriere 	/* AE decryption is completed */
33963778faaSEtienne Carriere 	TEE_Free(ctx->pending_tag);
34063778faaSEtienne Carriere 	ctx->pending_tag = NULL;
34163778faaSEtienne Carriere 
34263778faaSEtienne Carriere 	rc = tee2pkcs_error(res);
34363778faaSEtienne Carriere 	if (rc)
34463778faaSEtienne Carriere 		goto out;
34563778faaSEtienne Carriere 
34663778faaSEtienne Carriere 	if (data_ptr) {
34763778faaSEtienne Carriere 		void *tmp_ptr = NULL;
34863778faaSEtienne Carriere 
34963778faaSEtienne Carriere 		tmp_ptr = TEE_Realloc(ctx->out_data, (ctx->out_count + 1) *
35063778faaSEtienne Carriere 				sizeof(struct out_data_ref));
35163778faaSEtienne Carriere 		if (!tmp_ptr) {
35263778faaSEtienne Carriere 			rc = PKCS11_CKR_DEVICE_MEMORY;
35363778faaSEtienne Carriere 			goto out;
35463778faaSEtienne Carriere 		}
35563778faaSEtienne Carriere 		ctx->out_data = tmp_ptr;
35663778faaSEtienne Carriere 		ctx->out_data[ctx->out_count].size = data_size;
35763778faaSEtienne Carriere 		ctx->out_data[ctx->out_count].data = data_ptr;
35863778faaSEtienne Carriere 		ctx->out_count++;
35963778faaSEtienne Carriere 
36063778faaSEtienne Carriere 		data_ptr = NULL;
36163778faaSEtienne Carriere 	}
36263778faaSEtienne Carriere 
36363778faaSEtienne Carriere 	rc = reveal_ae_data(ctx, out, out_size);
36463778faaSEtienne Carriere 
36563778faaSEtienne Carriere out:
36663778faaSEtienne Carriere 	TEE_Free(data_ptr);
36763778faaSEtienne Carriere 
36863778faaSEtienne Carriere 	return rc;
36963778faaSEtienne Carriere }
37063778faaSEtienne Carriere 
tee_ae_encrypt_final(struct pkcs11_session * session,void * out,size_t * out_size)37163778faaSEtienne Carriere enum pkcs11_rc tee_ae_encrypt_final(struct pkcs11_session *session,
37263778faaSEtienne Carriere 				    void *out, size_t *out_size)
37363778faaSEtienne Carriere {
37463778faaSEtienne Carriere 	struct ae_aes_context *ctx = session->processing->extra_ctx;
37563778faaSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
37663778faaSEtienne Carriere 	uint8_t *tag = NULL;
37763778faaSEtienne Carriere 	size_t tag_len = 0;
37863778faaSEtienne Carriere 	size_t size = 0;
37963778faaSEtienne Carriere 
38063778faaSEtienne Carriere 	if (!out || !out_size)
38163778faaSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
38263778faaSEtienne Carriere 
38363778faaSEtienne Carriere 	/* Check the required sizes (warning: 2 output len: data + tag) */
38463778faaSEtienne Carriere 	res = TEE_AEEncryptFinal(session->processing->tee_op_handle,
38563778faaSEtienne Carriere 				 NULL, 0, NULL, &size,
38663778faaSEtienne Carriere 				 &tag, &tag_len);
38763778faaSEtienne Carriere 
38863778faaSEtienne Carriere 	if (tag_len != ctx->tag_byte_len ||
38963778faaSEtienne Carriere 	    (res != TEE_SUCCESS && res != TEE_ERROR_SHORT_BUFFER)) {
39063778faaSEtienne Carriere 		EMSG("Unexpected tag length %zu/%zu or rc 0x%" PRIx32,
39163778faaSEtienne Carriere 		     tag_len, ctx->tag_byte_len, res);
39263778faaSEtienne Carriere 		return PKCS11_CKR_GENERAL_ERROR;
39363778faaSEtienne Carriere 	}
39463778faaSEtienne Carriere 
39563778faaSEtienne Carriere 	if (*out_size < size + tag_len) {
39663778faaSEtienne Carriere 		*out_size = size + tag_len;
39763778faaSEtienne Carriere 		return PKCS11_CKR_BUFFER_TOO_SMALL;
39863778faaSEtienne Carriere 	}
39963778faaSEtienne Carriere 
40063778faaSEtienne Carriere 	/* Process data and tag input the client output buffer */
40163778faaSEtienne Carriere 	tag = (uint8_t *)out + size;
40263778faaSEtienne Carriere 
40363778faaSEtienne Carriere 	res = TEE_AEEncryptFinal(session->processing->tee_op_handle,
40463778faaSEtienne Carriere 				 NULL, 0, out, &size, tag, &tag_len);
40563778faaSEtienne Carriere 
40663778faaSEtienne Carriere 	if (tag_len != ctx->tag_byte_len) {
40763778faaSEtienne Carriere 		EMSG("Unexpected tag length");
40863778faaSEtienne Carriere 		return PKCS11_CKR_GENERAL_ERROR;
40963778faaSEtienne Carriere 	}
41063778faaSEtienne Carriere 
41163778faaSEtienne Carriere 	if (!res)
41263778faaSEtienne Carriere 		*out_size = size + tag_len;
41363778faaSEtienne Carriere 
41463778faaSEtienne Carriere 	return tee2pkcs_error(res);
41563778faaSEtienne Carriere }
41663778faaSEtienne Carriere 
tee_init_ctr_operation(struct active_processing * processing,void * proc_params,size_t params_size)417512cbf1dSJens Wiklander enum pkcs11_rc tee_init_ctr_operation(struct active_processing *processing,
418512cbf1dSJens Wiklander 				      void *proc_params, size_t params_size)
419512cbf1dSJens Wiklander {
420512cbf1dSJens Wiklander 	struct serialargs args = { };
421512cbf1dSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
422512cbf1dSJens Wiklander 	/* CTR parameters */
423512cbf1dSJens Wiklander 	uint32_t incr_counter = 0;
424512cbf1dSJens Wiklander 	void *counter_bits = NULL;
425512cbf1dSJens Wiklander 
426512cbf1dSJens Wiklander 	if (!proc_params)
427512cbf1dSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
428512cbf1dSJens Wiklander 
429512cbf1dSJens Wiklander 	serialargs_init(&args, proc_params, params_size);
430512cbf1dSJens Wiklander 
431512cbf1dSJens Wiklander 	rc = serialargs_get(&args, &incr_counter, sizeof(uint32_t));
432512cbf1dSJens Wiklander 	if (rc)
433512cbf1dSJens Wiklander 		return rc;
434512cbf1dSJens Wiklander 
435512cbf1dSJens Wiklander 	rc = serialargs_get_ptr(&args, &counter_bits, 16);
436512cbf1dSJens Wiklander 	if (rc)
437512cbf1dSJens Wiklander 		return rc;
438512cbf1dSJens Wiklander 
439512cbf1dSJens Wiklander 	if (serialargs_remaining_bytes(&args))
440512cbf1dSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
441512cbf1dSJens Wiklander 
442512cbf1dSJens Wiklander 	if (incr_counter != 1) {
443512cbf1dSJens Wiklander 		DMSG("Supports only 1 bit increment counter: %"PRIu32,
444512cbf1dSJens Wiklander 		     incr_counter);
445512cbf1dSJens Wiklander 
446512cbf1dSJens Wiklander 		return PKCS11_CKR_MECHANISM_PARAM_INVALID;
447512cbf1dSJens Wiklander 	}
448512cbf1dSJens Wiklander 
449512cbf1dSJens Wiklander 	TEE_CipherInit(processing->tee_op_handle, counter_bits, 16);
450512cbf1dSJens Wiklander 
451512cbf1dSJens Wiklander 	return PKCS11_CKR_OK;
452512cbf1dSJens Wiklander }
45363778faaSEtienne Carriere 
tee_init_gcm_operation(struct pkcs11_session * session,void * proc_params,size_t params_size)45463778faaSEtienne Carriere enum pkcs11_rc tee_init_gcm_operation(struct pkcs11_session *session,
45563778faaSEtienne Carriere 				      void *proc_params, size_t params_size)
45663778faaSEtienne Carriere {
45763778faaSEtienne Carriere 	struct ae_aes_context *params = NULL;
45863778faaSEtienne Carriere 	enum pkcs11_rc rc = PKCS11_CKR_OK;
45963778faaSEtienne Carriere 	struct serialargs args = { };
46063778faaSEtienne Carriere 	/* GCM parameters */
46163778faaSEtienne Carriere 	uint32_t tag_bitlen = 0;
46263778faaSEtienne Carriere 	uint32_t tag_len = 0;
46363778faaSEtienne Carriere 	uint32_t iv_len = 0;
46463778faaSEtienne Carriere 	void *iv = NULL;
46563778faaSEtienne Carriere 	uint32_t aad_len = 0;
46663778faaSEtienne Carriere 	void *aad = NULL;
46763778faaSEtienne Carriere 
46863778faaSEtienne Carriere 	TEE_MemFill(&args, 0, sizeof(args));
46963778faaSEtienne Carriere 
47063778faaSEtienne Carriere 	if (!proc_params)
47163778faaSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
47263778faaSEtienne Carriere 
47363778faaSEtienne Carriere 	serialargs_init(&args, proc_params, params_size);
47463778faaSEtienne Carriere 
47563778faaSEtienne Carriere 	rc = serialargs_get(&args, &iv_len, sizeof(uint32_t));
47663778faaSEtienne Carriere 	if (rc)
47763778faaSEtienne Carriere 		goto out;
47863778faaSEtienne Carriere 
47963778faaSEtienne Carriere 	rc = serialargs_get_ptr(&args, &iv, iv_len);
48063778faaSEtienne Carriere 	if (rc)
48163778faaSEtienne Carriere 		goto out;
48263778faaSEtienne Carriere 
48363778faaSEtienne Carriere 	rc = serialargs_get(&args, &aad_len, sizeof(uint32_t));
48463778faaSEtienne Carriere 	if (rc)
48563778faaSEtienne Carriere 		goto out;
48663778faaSEtienne Carriere 
48763778faaSEtienne Carriere 	rc = serialargs_get_ptr(&args, &aad, aad_len);
48863778faaSEtienne Carriere 	if (rc)
48963778faaSEtienne Carriere 		goto out;
49063778faaSEtienne Carriere 
49163778faaSEtienne Carriere 	rc = serialargs_get(&args, &tag_bitlen, sizeof(uint32_t));
49263778faaSEtienne Carriere 	if (rc)
49363778faaSEtienne Carriere 		goto out;
49463778faaSEtienne Carriere 
495*04e46975SEtienne Carriere 	tag_len = ROUNDUP_DIV(tag_bitlen, 8);
49663778faaSEtienne Carriere 
49763778faaSEtienne Carriere 	/* As per pkcs#11 mechanism specification */
49863778faaSEtienne Carriere 	if (tag_bitlen > 128 || !iv_len || iv_len > 256) {
49963778faaSEtienne Carriere 		DMSG("Invalid parameters: tag_bit_len %"PRIu32
50063778faaSEtienne Carriere 		     ", iv_len %"PRIu32, tag_bitlen, iv_len);
50163778faaSEtienne Carriere 		rc = PKCS11_CKR_MECHANISM_PARAM_INVALID;
50263778faaSEtienne Carriere 		goto out;
50363778faaSEtienne Carriere 	}
50463778faaSEtienne Carriere 
50563778faaSEtienne Carriere 	params = TEE_Malloc(sizeof(*params), TEE_MALLOC_FILL_ZERO);
50663778faaSEtienne Carriere 	if (!params) {
50763778faaSEtienne Carriere 		rc = PKCS11_CKR_DEVICE_MEMORY;
50863778faaSEtienne Carriere 		goto out;
50963778faaSEtienne Carriere 	}
51063778faaSEtienne Carriere 
51163778faaSEtienne Carriere 	/* Store the byte round up byte length for the tag */
51263778faaSEtienne Carriere 	params->tag_byte_len = tag_len;
51363778faaSEtienne Carriere 	rc = init_ae_aes_context(params);
51463778faaSEtienne Carriere 	if (rc)
51563778faaSEtienne Carriere 		goto out;
51663778faaSEtienne Carriere 
51763778faaSEtienne Carriere 	/* Session processing owns the active processing params */
51863778faaSEtienne Carriere 	assert(!session->processing->extra_ctx);
51963778faaSEtienne Carriere 	session->processing->extra_ctx = params;
52063778faaSEtienne Carriere 
52163778faaSEtienne Carriere 	TEE_AEInit(session->processing->tee_op_handle,
52263778faaSEtienne Carriere 		   iv, iv_len, tag_bitlen, 0, 0);
52363778faaSEtienne Carriere 
52463778faaSEtienne Carriere 	if (aad_len)
52563778faaSEtienne Carriere 		TEE_AEUpdateAAD(session->processing->tee_op_handle,
52663778faaSEtienne Carriere 				aad, aad_len);
52763778faaSEtienne Carriere 
52863778faaSEtienne Carriere 	/*
52963778faaSEtienne Carriere 	 * Save initialized operation state to reset to this state
53063778faaSEtienne Carriere 	 * on one-shot AE request that queries its output buffer size.
53163778faaSEtienne Carriere 	 */
53263778faaSEtienne Carriere 	TEE_CopyOperation(session->processing->tee_op_handle2,
53363778faaSEtienne Carriere 			  session->processing->tee_op_handle);
53463778faaSEtienne Carriere 
53563778faaSEtienne Carriere 	rc = PKCS11_CKR_OK;
53663778faaSEtienne Carriere 
53763778faaSEtienne Carriere out:
53863778faaSEtienne Carriere 	if (rc && params) {
53963778faaSEtienne Carriere 		release_ae_aes_context(params);
54063778faaSEtienne Carriere 		TEE_Free(params);
54163778faaSEtienne Carriere 	}
54263778faaSEtienne Carriere 
54363778faaSEtienne Carriere 	return rc;
54463778faaSEtienne Carriere }
54563778faaSEtienne Carriere 
54663778faaSEtienne Carriere /* Release extra resources related to the GCM processing*/
tee_release_gcm_operation(struct pkcs11_session * session)54763778faaSEtienne Carriere void tee_release_gcm_operation(struct pkcs11_session *session)
54863778faaSEtienne Carriere {
54963778faaSEtienne Carriere 	struct ae_aes_context *ctx = session->processing->extra_ctx;
55063778faaSEtienne Carriere 
55163778faaSEtienne Carriere 	release_ae_aes_context(ctx);
55263778faaSEtienne Carriere 	TEE_Free(session->processing->extra_ctx);
55363778faaSEtienne Carriere 	session->processing->extra_ctx = NULL;
55463778faaSEtienne Carriere }
55563778faaSEtienne Carriere 
55663778faaSEtienne Carriere /* Reset processing state to the state it was after initialization */
tee_ae_reinit_gcm_operation(struct pkcs11_session * session)55763778faaSEtienne Carriere enum pkcs11_rc tee_ae_reinit_gcm_operation(struct pkcs11_session *session)
55863778faaSEtienne Carriere {
55963778faaSEtienne Carriere 	struct ae_aes_context *ctx = session->processing->extra_ctx;
56063778faaSEtienne Carriere 
56163778faaSEtienne Carriere 	TEE_CopyOperation(session->processing->tee_op_handle,
56263778faaSEtienne Carriere 			  session->processing->tee_op_handle2);
56363778faaSEtienne Carriere 
56463778faaSEtienne Carriere 	release_ae_aes_context(ctx);
56563778faaSEtienne Carriere 
56663778faaSEtienne Carriere 	return init_ae_aes_context(ctx);
56763778faaSEtienne Carriere }
568