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