xref: /optee_os/ta/pkcs11/src/processing_aes.c (revision 63778faac4b7d8917d6170104c2c20a3a78dad9f)
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>
9*63778faaSEtienne 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 
18*63778faaSEtienne Carriere /*
19*63778faaSEtienne Carriere  * Authenticated ciphering: (AES GCM)
20*63778faaSEtienne Carriere  *
21*63778faaSEtienne Carriere  * As per PKCS#11, GCM decryption shall not reveal the data until the
22*63778faaSEtienne Carriere  * decryption is completed and the MAC verified. The pkcs11 TA retains the
23*63778faaSEtienne Carriere  * ciphered data until the operation is completed. Therefore every chunk of
24*63778faaSEtienne Carriere  * decrypted data is saved in a allocated buffer during AE update processing
25*63778faaSEtienne Carriere  * and only copied into the client's output buffer at AE finalization when
26*63778faaSEtienne Carriere  * tag is authenticated.
27*63778faaSEtienne Carriere  *
28*63778faaSEtienne Carriere  * As per PKCS#11, GCM decryption expect the tag data to be provided
29*63778faaSEtienne Carriere  * inside the input data for C_DecryptUpdate() and friends, appended to the
30*63778faaSEtienne Carriere  * input encyprted data hence we do not know which is the last call to
31*63778faaSEtienne Carriere  * C_DecryptUpdate() where last bytes are not ciphered data but the requested
32*63778faaSEtienne Carriere  * tag bytes for message autehntication. To handle this, the TA saves
33*63778faaSEtienne Carriere  * the last input data bytes (length is defined by the tag byte size) in the
34*63778faaSEtienne Carriere  * AE context and waits the C_DecryptFinal() to either treat these as data
35*63778faaSEtienne Carriere  * bytes or tag/MAC bytes. Refer to pending_tag and pending_size in struct
36*63778faaSEtienne Carriere  * ae_aes_context.
37*63778faaSEtienne Carriere  */
38*63778faaSEtienne Carriere 
39*63778faaSEtienne Carriere /*
40*63778faaSEtienne Carriere  * struct out_data_ref - AE decyrption output data chunks
41*63778faaSEtienne Carriere  * @size - byte size of the allocated buffer
42*63778faaSEtienne Carriere  * @data - pointer to allocated data
43*63778faaSEtienne Carriere  */
44*63778faaSEtienne Carriere struct out_data_ref {
45*63778faaSEtienne Carriere 	size_t size;
46*63778faaSEtienne Carriere 	void *data;
47*63778faaSEtienne Carriere };
48*63778faaSEtienne Carriere 
49*63778faaSEtienne Carriere /*
50*63778faaSEtienne Carriere  * struct ae_aes_context - Extra context data got AE operations
51*63778faaSEtienne Carriere  * @tag_byte_len - Tag size in byte
52*63778faaSEtienne Carriere  * @pending_tag - Input data that could be the appended tag
53*63778faaSEtienne Carriere  * @pending_size - Size of pending input data that could be the tag
54*63778faaSEtienne Carriere  * @out_data - Pointer to an array of output data references.
55*63778faaSEtienne Carriere  * @out_count - Number of buffer references in out_data
56*63778faaSEtienne Carriere  */
57*63778faaSEtienne Carriere struct ae_aes_context {
58*63778faaSEtienne Carriere 	size_t tag_byte_len;
59*63778faaSEtienne Carriere 	char *pending_tag;
60*63778faaSEtienne Carriere 	size_t pending_size;
61*63778faaSEtienne Carriere 	struct out_data_ref *out_data;
62*63778faaSEtienne Carriere 	size_t out_count;
63*63778faaSEtienne Carriere };
64*63778faaSEtienne Carriere 
65*63778faaSEtienne Carriere static enum pkcs11_rc init_ae_aes_context(struct ae_aes_context *ctx)
66*63778faaSEtienne Carriere {
67*63778faaSEtienne Carriere 	struct out_data_ref *out_data = NULL;
68*63778faaSEtienne Carriere 	char *pending_tag = NULL;
69*63778faaSEtienne Carriere 
70*63778faaSEtienne Carriere 	assert(!ctx->out_data && !ctx->out_count &&
71*63778faaSEtienne Carriere 	       !ctx->pending_tag && !ctx->pending_size);
72*63778faaSEtienne Carriere 
73*63778faaSEtienne Carriere 	out_data = TEE_Malloc(sizeof(*out_data), TEE_MALLOC_FILL_ZERO);
74*63778faaSEtienne Carriere 	pending_tag = TEE_Malloc(ctx->tag_byte_len, TEE_MALLOC_FILL_ZERO);
75*63778faaSEtienne Carriere 
76*63778faaSEtienne Carriere 	if (!out_data || !pending_tag) {
77*63778faaSEtienne Carriere 		TEE_Free(out_data);
78*63778faaSEtienne Carriere 		TEE_Free(pending_tag);
79*63778faaSEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
80*63778faaSEtienne Carriere 	}
81*63778faaSEtienne Carriere 
82*63778faaSEtienne Carriere 	ctx->pending_tag = pending_tag;
83*63778faaSEtienne Carriere 	ctx->out_data = out_data;
84*63778faaSEtienne Carriere 
85*63778faaSEtienne Carriere 	return PKCS11_CKR_OK;
86*63778faaSEtienne Carriere }
87*63778faaSEtienne Carriere 
88*63778faaSEtienne Carriere static void release_ae_aes_context(struct ae_aes_context *ctx)
89*63778faaSEtienne Carriere {
90*63778faaSEtienne Carriere 	size_t n = 0;
91*63778faaSEtienne Carriere 
92*63778faaSEtienne Carriere 	for (n = 0; n < ctx->out_count; n++)
93*63778faaSEtienne Carriere 		TEE_Free(ctx->out_data[n].data);
94*63778faaSEtienne Carriere 
95*63778faaSEtienne Carriere 	TEE_Free(ctx->out_data);
96*63778faaSEtienne Carriere 	ctx->out_data = NULL;
97*63778faaSEtienne Carriere 	ctx->out_count = 0;
98*63778faaSEtienne Carriere 
99*63778faaSEtienne Carriere 	TEE_Free(ctx->pending_tag);
100*63778faaSEtienne Carriere 	ctx->pending_tag = NULL;
101*63778faaSEtienne Carriere 	ctx->pending_size = 0;
102*63778faaSEtienne Carriere }
103*63778faaSEtienne Carriere 
104*63778faaSEtienne Carriere /*
105*63778faaSEtienne Carriere  * This function feeds the AE decryption processing with client
106*63778faaSEtienne Carriere  * input data. There are 2 constraints to consider.
107*63778faaSEtienne Carriere  *
108*63778faaSEtienne Carriere  * Firstly we don't know yet which are the ciphered data and which are
109*63778faaSEtienne Carriere  * the tag data. GP TEE Internal API function requires we split data and
110*63778faaSEtienne Carriere  * tag when TEE_AEDecryptFinal() will be called.
111*63778faaSEtienne Carriere  *
112*63778faaSEtienne Carriere  * Secondly any generated data must be kept in the TA and only revealed
113*63778faaSEtienne Carriere  * once tag if succefully processed.
114*63778faaSEtienne Carriere  */
115*63778faaSEtienne Carriere enum pkcs11_rc tee_ae_decrypt_update(struct pkcs11_session *session,
116*63778faaSEtienne Carriere 				     void *in, size_t in_size)
117*63778faaSEtienne Carriere {
118*63778faaSEtienne Carriere 	struct ae_aes_context *ctx = session->processing->extra_ctx;
119*63778faaSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
120*63778faaSEtienne Carriere 	enum pkcs11_rc rc = PKCS11_CKR_OK;
121*63778faaSEtienne Carriere 	size_t data_len = 0;
122*63778faaSEtienne Carriere 	size_t ct_size = 0;
123*63778faaSEtienne Carriere 	void *ptr = NULL;
124*63778faaSEtienne Carriere 	char *ct = NULL;
125*63778faaSEtienne Carriere 
126*63778faaSEtienne Carriere 	if (!in_size)
127*63778faaSEtienne Carriere 		return PKCS11_CKR_OK;
128*63778faaSEtienne Carriere 
129*63778faaSEtienne Carriere 	if (!in)
130*63778faaSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
131*63778faaSEtienne Carriere 
132*63778faaSEtienne Carriere 	/*
133*63778faaSEtienne Carriere 	 * Save the last input bytes in case they are the tag
134*63778faaSEtienne Carriere 	 * bytes and not ciphered data bytes to be decrypted.
135*63778faaSEtienne Carriere 	 */
136*63778faaSEtienne Carriere 
137*63778faaSEtienne Carriere 	if (ctx->pending_size + in_size <= ctx->tag_byte_len) {
138*63778faaSEtienne Carriere 		/*
139*63778faaSEtienne Carriere 		 * Data bytes are all potential tag bytes.
140*63778faaSEtienne Carriere 		 * We only need to update the pending_tag buffer,
141*63778faaSEtienne Carriere 		 * and cannot treat any byte as data byte.
142*63778faaSEtienne Carriere 		 */
143*63778faaSEtienne Carriere 		TEE_MemMove(ctx->pending_tag + ctx->pending_size, in, in_size);
144*63778faaSEtienne Carriere 
145*63778faaSEtienne Carriere 		ctx->pending_size += in_size;
146*63778faaSEtienne Carriere 
147*63778faaSEtienne Carriere 		return PKCS11_CKR_OK;
148*63778faaSEtienne Carriere 	}
149*63778faaSEtienne Carriere 
150*63778faaSEtienne Carriere 	/* Size of data that are not potential tag in pending and input data */
151*63778faaSEtienne Carriere 	data_len = in_size + ctx->pending_size - ctx->tag_byte_len;
152*63778faaSEtienne Carriere 
153*63778faaSEtienne Carriere 	/* Process pending bytes that are effective data byte */
154*63778faaSEtienne Carriere 	if (ctx->pending_size &&
155*63778faaSEtienne Carriere 	    (ctx->pending_size + in_size) >= ctx->tag_byte_len) {
156*63778faaSEtienne Carriere 		uint32_t len = MIN(data_len, ctx->pending_size);
157*63778faaSEtienne Carriere 
158*63778faaSEtienne Carriere 		res = TEE_AEUpdate(session->processing->tee_op_handle,
159*63778faaSEtienne Carriere 				   ctx->pending_tag, len, NULL, &ct_size);
160*63778faaSEtienne Carriere 		if (res && res != TEE_ERROR_SHORT_BUFFER) {
161*63778faaSEtienne Carriere 			rc = tee2pkcs_error(res);
162*63778faaSEtienne Carriere 			goto out;
163*63778faaSEtienne Carriere 		}
164*63778faaSEtienne Carriere 		assert(res == TEE_ERROR_SHORT_BUFFER || !ct_size);
165*63778faaSEtienne Carriere 
166*63778faaSEtienne Carriere 		/*
167*63778faaSEtienne Carriere 		 * If output data to store (not revealed yet), redo with
168*63778faaSEtienne Carriere 		 * an allocated temporary reference.
169*63778faaSEtienne Carriere 		 */
170*63778faaSEtienne Carriere 		if (ct_size) {
171*63778faaSEtienne Carriere 			ct = TEE_Malloc(ct_size, TEE_MALLOC_FILL_ZERO);
172*63778faaSEtienne Carriere 			if (!ct) {
173*63778faaSEtienne Carriere 				rc = PKCS11_CKR_DEVICE_MEMORY;
174*63778faaSEtienne Carriere 				goto out;
175*63778faaSEtienne Carriere 			}
176*63778faaSEtienne Carriere 
177*63778faaSEtienne Carriere 			res = TEE_AEUpdate(session->processing->tee_op_handle,
178*63778faaSEtienne Carriere 					   ctx->pending_tag, len, ct, &ct_size);
179*63778faaSEtienne Carriere 			if (res) {
180*63778faaSEtienne Carriere 				rc = tee2pkcs_error(res);
181*63778faaSEtienne Carriere 				goto out;
182*63778faaSEtienne Carriere 			}
183*63778faaSEtienne Carriere 			assert(ct_size);
184*63778faaSEtienne Carriere 		}
185*63778faaSEtienne Carriere 
186*63778faaSEtienne Carriere 		/* Save potential tag bytes for later */
187*63778faaSEtienne Carriere 		TEE_MemMove(ctx->pending_tag, ctx->pending_tag + len,
188*63778faaSEtienne Carriere 			    ctx->pending_size - len);
189*63778faaSEtienne Carriere 
190*63778faaSEtienne Carriere 		ctx->pending_size -= len;
191*63778faaSEtienne Carriere 		data_len -= len;
192*63778faaSEtienne Carriere 	}
193*63778faaSEtienne Carriere 
194*63778faaSEtienne Carriere 	/* Process input data that are not potential tag bytes */
195*63778faaSEtienne Carriere 	if (data_len) {
196*63778faaSEtienne Carriere 		size_t size = 0;
197*63778faaSEtienne Carriere 
198*63778faaSEtienne Carriere 		res = TEE_AEUpdate(session->processing->tee_op_handle,
199*63778faaSEtienne Carriere 				   in, data_len, NULL, &size);
200*63778faaSEtienne Carriere 		if (res != TEE_ERROR_SHORT_BUFFER &&
201*63778faaSEtienne Carriere 		    (res != TEE_SUCCESS || size)) {
202*63778faaSEtienne Carriere 			/* This is not expected */
203*63778faaSEtienne Carriere 			rc = PKCS11_CKR_GENERAL_ERROR;
204*63778faaSEtienne Carriere 			goto out;
205*63778faaSEtienne Carriere 		}
206*63778faaSEtienne Carriere 
207*63778faaSEtienne Carriere 		if (size) {
208*63778faaSEtienne Carriere 			ptr = TEE_Realloc(ct, ct_size + size);
209*63778faaSEtienne Carriere 			if (!ptr) {
210*63778faaSEtienne Carriere 				rc = PKCS11_CKR_DEVICE_MEMORY;
211*63778faaSEtienne Carriere 				goto out;
212*63778faaSEtienne Carriere 			}
213*63778faaSEtienne Carriere 			ct = ptr;
214*63778faaSEtienne Carriere 
215*63778faaSEtienne Carriere 			res = TEE_AEUpdate(session->processing->tee_op_handle,
216*63778faaSEtienne Carriere 					   in, data_len, ct + ct_size, &size);
217*63778faaSEtienne Carriere 			if (res) {
218*63778faaSEtienne Carriere 				rc = tee2pkcs_error(res);
219*63778faaSEtienne Carriere 				goto out;
220*63778faaSEtienne Carriere 			}
221*63778faaSEtienne Carriere 
222*63778faaSEtienne Carriere 			ct_size += size;
223*63778faaSEtienne Carriere 		}
224*63778faaSEtienne Carriere 	}
225*63778faaSEtienne Carriere 
226*63778faaSEtienne Carriere 	/* Update pending tag in context if any */
227*63778faaSEtienne Carriere 	data_len = in_size - data_len;
228*63778faaSEtienne Carriere 	if (data_len > (ctx->tag_byte_len - ctx->pending_size)) {
229*63778faaSEtienne Carriere 		/* This is not expected */
230*63778faaSEtienne Carriere 		rc = PKCS11_CKR_GENERAL_ERROR;
231*63778faaSEtienne Carriere 		goto out;
232*63778faaSEtienne Carriere 	}
233*63778faaSEtienne Carriere 
234*63778faaSEtienne Carriere 	if (data_len) {
235*63778faaSEtienne Carriere 		TEE_MemMove(ctx->pending_tag + ctx->pending_size,
236*63778faaSEtienne Carriere 			    (char *)in + in_size - data_len, data_len);
237*63778faaSEtienne Carriere 
238*63778faaSEtienne Carriere 		ctx->pending_size += data_len;
239*63778faaSEtienne Carriere 	}
240*63778faaSEtienne Carriere 
241*63778faaSEtienne Carriere 	/* Save output data reference in the context */
242*63778faaSEtienne Carriere 	if (ct_size) {
243*63778faaSEtienne Carriere 		ptr = TEE_Realloc(ctx->out_data, (ctx->out_count + 1) *
244*63778faaSEtienne Carriere 				  sizeof(struct out_data_ref));
245*63778faaSEtienne Carriere 		if (!ptr) {
246*63778faaSEtienne Carriere 			rc = PKCS11_CKR_DEVICE_MEMORY;
247*63778faaSEtienne Carriere 			goto out;
248*63778faaSEtienne Carriere 		}
249*63778faaSEtienne Carriere 		ctx->out_data = ptr;
250*63778faaSEtienne Carriere 		ctx->out_data[ctx->out_count].size = ct_size;
251*63778faaSEtienne Carriere 		ctx->out_data[ctx->out_count].data = ct;
252*63778faaSEtienne Carriere 		ctx->out_count++;
253*63778faaSEtienne Carriere 	}
254*63778faaSEtienne Carriere 
255*63778faaSEtienne Carriere 	rc = PKCS11_CKR_OK;
256*63778faaSEtienne Carriere 
257*63778faaSEtienne Carriere out:
258*63778faaSEtienne Carriere 	if (rc)
259*63778faaSEtienne Carriere 		TEE_Free(ct);
260*63778faaSEtienne Carriere 
261*63778faaSEtienne Carriere 	return rc;
262*63778faaSEtienne Carriere }
263*63778faaSEtienne Carriere 
264*63778faaSEtienne Carriere static enum pkcs11_rc reveal_ae_data(struct ae_aes_context *ctx,
265*63778faaSEtienne Carriere 				     void *out, size_t *out_size)
266*63778faaSEtienne Carriere {
267*63778faaSEtienne Carriere 	uint32_t req_size = 0;
268*63778faaSEtienne Carriere 	char *out_ptr = out;
269*63778faaSEtienne Carriere 	size_t n = 0;
270*63778faaSEtienne Carriere 
271*63778faaSEtienne Carriere 	for (req_size = 0, n = 0; n < ctx->out_count; n++)
272*63778faaSEtienne Carriere 		req_size += ctx->out_data[n].size;
273*63778faaSEtienne Carriere 
274*63778faaSEtienne Carriere 	if (*out_size < req_size) {
275*63778faaSEtienne Carriere 		*out_size = req_size;
276*63778faaSEtienne Carriere 		return PKCS11_CKR_BUFFER_TOO_SMALL;
277*63778faaSEtienne Carriere 	}
278*63778faaSEtienne Carriere 
279*63778faaSEtienne Carriere 	if (!out_ptr)
280*63778faaSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
281*63778faaSEtienne Carriere 
282*63778faaSEtienne Carriere 	for (n = 0; n < ctx->out_count; n++) {
283*63778faaSEtienne Carriere 		TEE_MemMove(out_ptr, ctx->out_data[n].data,
284*63778faaSEtienne Carriere 			    ctx->out_data[n].size);
285*63778faaSEtienne Carriere 		out_ptr += ctx->out_data[n].size;
286*63778faaSEtienne Carriere 	}
287*63778faaSEtienne Carriere 
288*63778faaSEtienne Carriere 	release_ae_aes_context(ctx);
289*63778faaSEtienne Carriere 
290*63778faaSEtienne Carriere 	*out_size = req_size;
291*63778faaSEtienne Carriere 
292*63778faaSEtienne Carriere 	return PKCS11_CKR_OK;
293*63778faaSEtienne Carriere }
294*63778faaSEtienne Carriere 
295*63778faaSEtienne Carriere enum pkcs11_rc tee_ae_decrypt_final(struct pkcs11_session *session,
296*63778faaSEtienne Carriere 				    void *out, size_t *out_size)
297*63778faaSEtienne Carriere {
298*63778faaSEtienne Carriere 	struct ae_aes_context *ctx = session->processing->extra_ctx;
299*63778faaSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
300*63778faaSEtienne Carriere 	enum pkcs11_rc rc = 0;
301*63778faaSEtienne Carriere 	void *data_ptr = NULL;
302*63778faaSEtienne Carriere 	size_t data_size = 0;
303*63778faaSEtienne Carriere 
304*63778faaSEtienne Carriere 	if (!out_size) {
305*63778faaSEtienne Carriere 		DMSG("Expect at least a buffer for the output data");
306*63778faaSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
307*63778faaSEtienne Carriere 	}
308*63778faaSEtienne Carriere 
309*63778faaSEtienne Carriere 	/* Final is already completed, only need to output the data */
310*63778faaSEtienne Carriere 	if (!ctx->pending_tag)
311*63778faaSEtienne Carriere 		return reveal_ae_data(ctx, out, out_size);
312*63778faaSEtienne Carriere 
313*63778faaSEtienne Carriere 	if (ctx->pending_size != ctx->tag_byte_len) {
314*63778faaSEtienne Carriere 		DMSG("Not enough samples: %zu/%zu",
315*63778faaSEtienne Carriere 		     ctx->pending_size, ctx->tag_byte_len);
316*63778faaSEtienne Carriere 		return PKCS11_CKR_ENCRYPTED_DATA_LEN_RANGE;
317*63778faaSEtienne Carriere 	}
318*63778faaSEtienne Carriere 
319*63778faaSEtienne Carriere 	/* Query tag size if any */
320*63778faaSEtienne Carriere 	data_size = 0;
321*63778faaSEtienne Carriere 	res = TEE_AEDecryptFinal(session->processing->tee_op_handle,
322*63778faaSEtienne Carriere 				 NULL, 0, NULL, &data_size,
323*63778faaSEtienne Carriere 				 ctx->pending_tag, ctx->tag_byte_len);
324*63778faaSEtienne Carriere 
325*63778faaSEtienne Carriere 	if (res == TEE_ERROR_SHORT_BUFFER) {
326*63778faaSEtienne Carriere 		data_ptr = TEE_Malloc(data_size, TEE_MALLOC_FILL_ZERO);
327*63778faaSEtienne Carriere 		if (!data_ptr) {
328*63778faaSEtienne Carriere 			rc = PKCS11_CKR_DEVICE_MEMORY;
329*63778faaSEtienne Carriere 			goto out;
330*63778faaSEtienne Carriere 		}
331*63778faaSEtienne Carriere 
332*63778faaSEtienne Carriere 		res = TEE_AEDecryptFinal(session->processing->tee_op_handle,
333*63778faaSEtienne Carriere 					 NULL, 0, data_ptr, &data_size,
334*63778faaSEtienne Carriere 					 ctx->pending_tag, ctx->tag_byte_len);
335*63778faaSEtienne Carriere 		assert(res || data_size);
336*63778faaSEtienne Carriere 	}
337*63778faaSEtienne Carriere 
338*63778faaSEtienne Carriere 	/* AE decryption is completed */
339*63778faaSEtienne Carriere 	TEE_Free(ctx->pending_tag);
340*63778faaSEtienne Carriere 	ctx->pending_tag = NULL;
341*63778faaSEtienne Carriere 
342*63778faaSEtienne Carriere 	rc = tee2pkcs_error(res);
343*63778faaSEtienne Carriere 	if (rc)
344*63778faaSEtienne Carriere 		goto out;
345*63778faaSEtienne Carriere 
346*63778faaSEtienne Carriere 	if (data_ptr) {
347*63778faaSEtienne Carriere 		void *tmp_ptr = NULL;
348*63778faaSEtienne Carriere 
349*63778faaSEtienne Carriere 		tmp_ptr = TEE_Realloc(ctx->out_data, (ctx->out_count + 1) *
350*63778faaSEtienne Carriere 				sizeof(struct out_data_ref));
351*63778faaSEtienne Carriere 		if (!tmp_ptr) {
352*63778faaSEtienne Carriere 			rc = PKCS11_CKR_DEVICE_MEMORY;
353*63778faaSEtienne Carriere 			goto out;
354*63778faaSEtienne Carriere 		}
355*63778faaSEtienne Carriere 		ctx->out_data = tmp_ptr;
356*63778faaSEtienne Carriere 		ctx->out_data[ctx->out_count].size = data_size;
357*63778faaSEtienne Carriere 		ctx->out_data[ctx->out_count].data = data_ptr;
358*63778faaSEtienne Carriere 		ctx->out_count++;
359*63778faaSEtienne Carriere 
360*63778faaSEtienne Carriere 		data_ptr = NULL;
361*63778faaSEtienne Carriere 	}
362*63778faaSEtienne Carriere 
363*63778faaSEtienne Carriere 	rc = reveal_ae_data(ctx, out, out_size);
364*63778faaSEtienne Carriere 
365*63778faaSEtienne Carriere out:
366*63778faaSEtienne Carriere 	TEE_Free(data_ptr);
367*63778faaSEtienne Carriere 
368*63778faaSEtienne Carriere 	return rc;
369*63778faaSEtienne Carriere }
370*63778faaSEtienne Carriere 
371*63778faaSEtienne Carriere enum pkcs11_rc tee_ae_encrypt_final(struct pkcs11_session *session,
372*63778faaSEtienne Carriere 				    void *out, size_t *out_size)
373*63778faaSEtienne Carriere {
374*63778faaSEtienne Carriere 	struct ae_aes_context *ctx = session->processing->extra_ctx;
375*63778faaSEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
376*63778faaSEtienne Carriere 	uint8_t *tag = NULL;
377*63778faaSEtienne Carriere 	size_t tag_len = 0;
378*63778faaSEtienne Carriere 	size_t size = 0;
379*63778faaSEtienne Carriere 
380*63778faaSEtienne Carriere 	if (!out || !out_size)
381*63778faaSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
382*63778faaSEtienne Carriere 
383*63778faaSEtienne Carriere 	/* Check the required sizes (warning: 2 output len: data + tag) */
384*63778faaSEtienne Carriere 	res = TEE_AEEncryptFinal(session->processing->tee_op_handle,
385*63778faaSEtienne Carriere 				 NULL, 0, NULL, &size,
386*63778faaSEtienne Carriere 				 &tag, &tag_len);
387*63778faaSEtienne Carriere 
388*63778faaSEtienne Carriere 	if (tag_len != ctx->tag_byte_len ||
389*63778faaSEtienne Carriere 	    (res != TEE_SUCCESS && res != TEE_ERROR_SHORT_BUFFER)) {
390*63778faaSEtienne Carriere 		EMSG("Unexpected tag length %zu/%zu or rc 0x%" PRIx32,
391*63778faaSEtienne Carriere 		     tag_len, ctx->tag_byte_len, res);
392*63778faaSEtienne Carriere 		return PKCS11_CKR_GENERAL_ERROR;
393*63778faaSEtienne Carriere 	}
394*63778faaSEtienne Carriere 
395*63778faaSEtienne Carriere 	if (*out_size < size + tag_len) {
396*63778faaSEtienne Carriere 		*out_size = size + tag_len;
397*63778faaSEtienne Carriere 		return PKCS11_CKR_BUFFER_TOO_SMALL;
398*63778faaSEtienne Carriere 	}
399*63778faaSEtienne Carriere 
400*63778faaSEtienne Carriere 	/* Process data and tag input the client output buffer */
401*63778faaSEtienne Carriere 	tag = (uint8_t *)out + size;
402*63778faaSEtienne Carriere 
403*63778faaSEtienne Carriere 	res = TEE_AEEncryptFinal(session->processing->tee_op_handle,
404*63778faaSEtienne Carriere 				 NULL, 0, out, &size, tag, &tag_len);
405*63778faaSEtienne Carriere 
406*63778faaSEtienne Carriere 	if (tag_len != ctx->tag_byte_len) {
407*63778faaSEtienne Carriere 		EMSG("Unexpected tag length");
408*63778faaSEtienne Carriere 		return PKCS11_CKR_GENERAL_ERROR;
409*63778faaSEtienne Carriere 	}
410*63778faaSEtienne Carriere 
411*63778faaSEtienne Carriere 	if (!res)
412*63778faaSEtienne Carriere 		*out_size = size + tag_len;
413*63778faaSEtienne Carriere 
414*63778faaSEtienne Carriere 	return tee2pkcs_error(res);
415*63778faaSEtienne Carriere }
416*63778faaSEtienne Carriere 
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 }
453*63778faaSEtienne Carriere 
454*63778faaSEtienne Carriere enum pkcs11_rc tee_init_gcm_operation(struct pkcs11_session *session,
455*63778faaSEtienne Carriere 				      void *proc_params, size_t params_size)
456*63778faaSEtienne Carriere {
457*63778faaSEtienne Carriere 	struct ae_aes_context *params = NULL;
458*63778faaSEtienne Carriere 	enum pkcs11_rc rc = PKCS11_CKR_OK;
459*63778faaSEtienne Carriere 	struct serialargs args = { };
460*63778faaSEtienne Carriere 	/* GCM parameters */
461*63778faaSEtienne Carriere 	uint32_t tag_bitlen = 0;
462*63778faaSEtienne Carriere 	uint32_t tag_len = 0;
463*63778faaSEtienne Carriere 	uint32_t iv_len = 0;
464*63778faaSEtienne Carriere 	void *iv = NULL;
465*63778faaSEtienne Carriere 	uint32_t aad_len = 0;
466*63778faaSEtienne Carriere 	void *aad = NULL;
467*63778faaSEtienne Carriere 
468*63778faaSEtienne Carriere 	TEE_MemFill(&args, 0, sizeof(args));
469*63778faaSEtienne Carriere 
470*63778faaSEtienne Carriere 	if (!proc_params)
471*63778faaSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
472*63778faaSEtienne Carriere 
473*63778faaSEtienne Carriere 	serialargs_init(&args, proc_params, params_size);
474*63778faaSEtienne Carriere 
475*63778faaSEtienne Carriere 	rc = serialargs_get(&args, &iv_len, sizeof(uint32_t));
476*63778faaSEtienne Carriere 	if (rc)
477*63778faaSEtienne Carriere 		goto out;
478*63778faaSEtienne Carriere 
479*63778faaSEtienne Carriere 	rc = serialargs_get_ptr(&args, &iv, iv_len);
480*63778faaSEtienne Carriere 	if (rc)
481*63778faaSEtienne Carriere 		goto out;
482*63778faaSEtienne Carriere 
483*63778faaSEtienne Carriere 	rc = serialargs_get(&args, &aad_len, sizeof(uint32_t));
484*63778faaSEtienne Carriere 	if (rc)
485*63778faaSEtienne Carriere 		goto out;
486*63778faaSEtienne Carriere 
487*63778faaSEtienne Carriere 	rc = serialargs_get_ptr(&args, &aad, aad_len);
488*63778faaSEtienne Carriere 	if (rc)
489*63778faaSEtienne Carriere 		goto out;
490*63778faaSEtienne Carriere 
491*63778faaSEtienne Carriere 	rc = serialargs_get(&args, &tag_bitlen, sizeof(uint32_t));
492*63778faaSEtienne Carriere 	if (rc)
493*63778faaSEtienne Carriere 		goto out;
494*63778faaSEtienne Carriere 
495*63778faaSEtienne Carriere 	tag_len = ROUNDUP(tag_bitlen, 8) / 8;
496*63778faaSEtienne Carriere 
497*63778faaSEtienne Carriere 	/* As per pkcs#11 mechanism specification */
498*63778faaSEtienne Carriere 	if (tag_bitlen > 128 || !iv_len || iv_len > 256) {
499*63778faaSEtienne Carriere 		DMSG("Invalid parameters: tag_bit_len %"PRIu32
500*63778faaSEtienne Carriere 		     ", iv_len %"PRIu32, tag_bitlen, iv_len);
501*63778faaSEtienne Carriere 		rc = PKCS11_CKR_MECHANISM_PARAM_INVALID;
502*63778faaSEtienne Carriere 		goto out;
503*63778faaSEtienne Carriere 	}
504*63778faaSEtienne Carriere 
505*63778faaSEtienne Carriere 	params = TEE_Malloc(sizeof(*params), TEE_MALLOC_FILL_ZERO);
506*63778faaSEtienne Carriere 	if (!params) {
507*63778faaSEtienne Carriere 		rc = PKCS11_CKR_DEVICE_MEMORY;
508*63778faaSEtienne Carriere 		goto out;
509*63778faaSEtienne Carriere 	}
510*63778faaSEtienne Carriere 
511*63778faaSEtienne Carriere 	/* Store the byte round up byte length for the tag */
512*63778faaSEtienne Carriere 	params->tag_byte_len = tag_len;
513*63778faaSEtienne Carriere 	rc = init_ae_aes_context(params);
514*63778faaSEtienne Carriere 	if (rc)
515*63778faaSEtienne Carriere 		goto out;
516*63778faaSEtienne Carriere 
517*63778faaSEtienne Carriere 	/* Session processing owns the active processing params */
518*63778faaSEtienne Carriere 	assert(!session->processing->extra_ctx);
519*63778faaSEtienne Carriere 	session->processing->extra_ctx = params;
520*63778faaSEtienne Carriere 
521*63778faaSEtienne Carriere 	TEE_AEInit(session->processing->tee_op_handle,
522*63778faaSEtienne Carriere 		   iv, iv_len, tag_bitlen, 0, 0);
523*63778faaSEtienne Carriere 
524*63778faaSEtienne Carriere 	if (aad_len)
525*63778faaSEtienne Carriere 		TEE_AEUpdateAAD(session->processing->tee_op_handle,
526*63778faaSEtienne Carriere 				aad, aad_len);
527*63778faaSEtienne Carriere 
528*63778faaSEtienne Carriere 	/*
529*63778faaSEtienne Carriere 	 * Save initialized operation state to reset to this state
530*63778faaSEtienne Carriere 	 * on one-shot AE request that queries its output buffer size.
531*63778faaSEtienne Carriere 	 */
532*63778faaSEtienne Carriere 	TEE_CopyOperation(session->processing->tee_op_handle2,
533*63778faaSEtienne Carriere 			  session->processing->tee_op_handle);
534*63778faaSEtienne Carriere 
535*63778faaSEtienne Carriere 	rc = PKCS11_CKR_OK;
536*63778faaSEtienne Carriere 
537*63778faaSEtienne Carriere out:
538*63778faaSEtienne Carriere 	if (rc && params) {
539*63778faaSEtienne Carriere 		release_ae_aes_context(params);
540*63778faaSEtienne Carriere 		TEE_Free(params);
541*63778faaSEtienne Carriere 	}
542*63778faaSEtienne Carriere 
543*63778faaSEtienne Carriere 	return rc;
544*63778faaSEtienne Carriere }
545*63778faaSEtienne Carriere 
546*63778faaSEtienne Carriere /* Release extra resources related to the GCM processing*/
547*63778faaSEtienne Carriere void tee_release_gcm_operation(struct pkcs11_session *session)
548*63778faaSEtienne Carriere {
549*63778faaSEtienne Carriere 	struct ae_aes_context *ctx = session->processing->extra_ctx;
550*63778faaSEtienne Carriere 
551*63778faaSEtienne Carriere 	release_ae_aes_context(ctx);
552*63778faaSEtienne Carriere 	TEE_Free(session->processing->extra_ctx);
553*63778faaSEtienne Carriere 	session->processing->extra_ctx = NULL;
554*63778faaSEtienne Carriere }
555*63778faaSEtienne Carriere 
556*63778faaSEtienne Carriere /* Reset processing state to the state it was after initialization */
557*63778faaSEtienne Carriere enum pkcs11_rc tee_ae_reinit_gcm_operation(struct pkcs11_session *session)
558*63778faaSEtienne Carriere {
559*63778faaSEtienne Carriere 	struct ae_aes_context *ctx = session->processing->extra_ctx;
560*63778faaSEtienne Carriere 
561*63778faaSEtienne Carriere 	TEE_CopyOperation(session->processing->tee_op_handle,
562*63778faaSEtienne Carriere 			  session->processing->tee_op_handle2);
563*63778faaSEtienne Carriere 
564*63778faaSEtienne Carriere 	release_ae_aes_context(ctx);
565*63778faaSEtienne Carriere 
566*63778faaSEtienne Carriere 	return init_ae_aes_context(ctx);
567*63778faaSEtienne Carriere }
568