1f1e9b21bSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2f1e9b21bSJens Wiklander /*
3f1e9b21bSJens Wiklander * Copyright (c) 2014-2019, Linaro Limited
4f1e9b21bSJens Wiklander */
5f1e9b21bSJens Wiklander
6f1e9b21bSJens Wiklander #include <assert.h>
7f1e9b21bSJens Wiklander #include <crypto/crypto.h>
8f1e9b21bSJens Wiklander #include <crypto/crypto_impl.h>
9f1e9b21bSJens Wiklander #include <stdlib.h>
10f1e9b21bSJens Wiklander #include <string.h>
118411e6adSJerome Forissier #include <string_ext.h>
12f1e9b21bSJens Wiklander #include <tee_api_types.h>
135a913ee7SJerome Forissier #include <tomcrypt_private.h>
14f1e9b21bSJens Wiklander #include <util.h>
15f1e9b21bSJens Wiklander
16f1e9b21bSJens Wiklander #define TEE_CCM_KEY_MAX_LENGTH 32
17f1e9b21bSJens Wiklander #define TEE_CCM_NONCE_MAX_LENGTH 13
18f1e9b21bSJens Wiklander #define TEE_CCM_TAG_MAX_LENGTH 16
19f1e9b21bSJens Wiklander
20f1e9b21bSJens Wiklander struct tee_ccm_state {
21f1e9b21bSJens Wiklander struct crypto_authenc_ctx aectx;
22f1e9b21bSJens Wiklander ccm_state ctx; /* the ccm state as defined by LTC */
23f1e9b21bSJens Wiklander size_t tag_len; /* tag length */
24f1e9b21bSJens Wiklander };
25f1e9b21bSJens Wiklander
26f1e9b21bSJens Wiklander static const struct crypto_authenc_ops aes_ccm_ops;
27f1e9b21bSJens Wiklander
crypto_aes_ccm_alloc_ctx(struct crypto_authenc_ctx ** ctx_ret)28f1e9b21bSJens Wiklander TEE_Result crypto_aes_ccm_alloc_ctx(struct crypto_authenc_ctx **ctx_ret)
29f1e9b21bSJens Wiklander {
30f1e9b21bSJens Wiklander struct tee_ccm_state *ctx = calloc(1, sizeof(*ctx));
31f1e9b21bSJens Wiklander
32f1e9b21bSJens Wiklander if (!ctx)
33f1e9b21bSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY;
34f1e9b21bSJens Wiklander ctx->aectx.ops = &aes_ccm_ops;
35f1e9b21bSJens Wiklander
36f1e9b21bSJens Wiklander *ctx_ret = &ctx->aectx;
37f1e9b21bSJens Wiklander return TEE_SUCCESS;
38f1e9b21bSJens Wiklander }
39f1e9b21bSJens Wiklander
to_tee_ccm_state(struct crypto_authenc_ctx * aectx)40f1e9b21bSJens Wiklander static struct tee_ccm_state *to_tee_ccm_state(struct crypto_authenc_ctx *aectx)
41f1e9b21bSJens Wiklander {
42f1e9b21bSJens Wiklander assert(aectx && aectx->ops == &aes_ccm_ops);
43f1e9b21bSJens Wiklander
44f1e9b21bSJens Wiklander return container_of(aectx, struct tee_ccm_state, aectx);
45f1e9b21bSJens Wiklander }
46f1e9b21bSJens Wiklander
crypto_aes_ccm_free_ctx(struct crypto_authenc_ctx * aectx)47f1e9b21bSJens Wiklander static void crypto_aes_ccm_free_ctx(struct crypto_authenc_ctx *aectx)
48f1e9b21bSJens Wiklander {
49f1e9b21bSJens Wiklander free(to_tee_ccm_state(aectx));
50f1e9b21bSJens Wiklander }
51f1e9b21bSJens Wiklander
crypto_aes_ccm_copy_state(struct crypto_authenc_ctx * dst_aectx,struct crypto_authenc_ctx * src_aectx)52f1e9b21bSJens Wiklander static void crypto_aes_ccm_copy_state(struct crypto_authenc_ctx *dst_aectx,
53f1e9b21bSJens Wiklander struct crypto_authenc_ctx *src_aectx)
54f1e9b21bSJens Wiklander {
55f1e9b21bSJens Wiklander struct tee_ccm_state *dst_ctx = to_tee_ccm_state(dst_aectx);
56f1e9b21bSJens Wiklander struct tee_ccm_state *src_ctx = to_tee_ccm_state(src_aectx);
57f1e9b21bSJens Wiklander
58f1e9b21bSJens Wiklander dst_ctx->ctx = src_ctx->ctx;
59f1e9b21bSJens Wiklander dst_ctx->tag_len = src_ctx->tag_len;
60f1e9b21bSJens Wiklander }
61f1e9b21bSJens Wiklander
crypto_aes_ccm_init(struct crypto_authenc_ctx * aectx,TEE_OperationMode mode __unused,const uint8_t * key,size_t key_len,const uint8_t * nonce,size_t nonce_len,size_t tag_len,size_t aad_len,size_t payload_len)62f1e9b21bSJens Wiklander static TEE_Result crypto_aes_ccm_init(struct crypto_authenc_ctx *aectx,
63f1e9b21bSJens Wiklander TEE_OperationMode mode __unused,
64f1e9b21bSJens Wiklander const uint8_t *key, size_t key_len,
65f1e9b21bSJens Wiklander const uint8_t *nonce, size_t nonce_len,
66f1e9b21bSJens Wiklander size_t tag_len, size_t aad_len,
67f1e9b21bSJens Wiklander size_t payload_len)
68f1e9b21bSJens Wiklander {
69f1e9b21bSJens Wiklander int ltc_res = 0;
70f1e9b21bSJens Wiklander int ltc_cipherindex = find_cipher("aes");
71f1e9b21bSJens Wiklander struct tee_ccm_state *ccm = to_tee_ccm_state(aectx);
72f1e9b21bSJens Wiklander
73f1e9b21bSJens Wiklander if (ltc_cipherindex < 0)
74f1e9b21bSJens Wiklander return TEE_ERROR_NOT_SUPPORTED;
75f1e9b21bSJens Wiklander
76f1e9b21bSJens Wiklander /* reset the state */
77f1e9b21bSJens Wiklander memset(&ccm->ctx, 0, sizeof(ccm->ctx));
78f1e9b21bSJens Wiklander ccm->tag_len = tag_len;
79f1e9b21bSJens Wiklander
80f1e9b21bSJens Wiklander /* Check the key length */
81f1e9b21bSJens Wiklander if ((!key) || (key_len > TEE_CCM_KEY_MAX_LENGTH))
82f1e9b21bSJens Wiklander return TEE_ERROR_BAD_PARAMETERS;
83f1e9b21bSJens Wiklander
84f1e9b21bSJens Wiklander /* check the nonce */
85f1e9b21bSJens Wiklander if (nonce_len > TEE_CCM_NONCE_MAX_LENGTH)
86f1e9b21bSJens Wiklander return TEE_ERROR_BAD_PARAMETERS;
87f1e9b21bSJens Wiklander
88*2373e1b9SJens Wiklander /* Check that payload_len and aad_len will fit into ints */
89*2373e1b9SJens Wiklander if (payload_len > INT_MAX || aad_len > INT_MAX)
90*2373e1b9SJens Wiklander return TEE_ERROR_BAD_PARAMETERS;
91*2373e1b9SJens Wiklander
92f1e9b21bSJens Wiklander /* check the tag len */
93f1e9b21bSJens Wiklander if ((tag_len < 4) || (tag_len > TEE_CCM_TAG_MAX_LENGTH) ||
94f1e9b21bSJens Wiklander (tag_len % 2 != 0))
95f1e9b21bSJens Wiklander return TEE_ERROR_NOT_SUPPORTED;
96f1e9b21bSJens Wiklander
97f1e9b21bSJens Wiklander ltc_res = ccm_init(&ccm->ctx, ltc_cipherindex, key, key_len,
98f1e9b21bSJens Wiklander payload_len, tag_len, aad_len);
99f1e9b21bSJens Wiklander if (ltc_res != CRYPT_OK)
100f1e9b21bSJens Wiklander return TEE_ERROR_BAD_STATE;
101f1e9b21bSJens Wiklander
102f1e9b21bSJens Wiklander /* Add the IV */
103f1e9b21bSJens Wiklander ltc_res = ccm_add_nonce(&ccm->ctx, nonce, nonce_len);
104f1e9b21bSJens Wiklander if (ltc_res != CRYPT_OK)
105f1e9b21bSJens Wiklander return TEE_ERROR_BAD_STATE;
106f1e9b21bSJens Wiklander
107f1e9b21bSJens Wiklander return TEE_SUCCESS;
108f1e9b21bSJens Wiklander }
109f1e9b21bSJens Wiklander
crypto_aes_ccm_update_aad(struct crypto_authenc_ctx * aectx,const uint8_t * data,size_t len)110f1e9b21bSJens Wiklander static TEE_Result crypto_aes_ccm_update_aad(struct crypto_authenc_ctx *aectx,
111f1e9b21bSJens Wiklander const uint8_t *data, size_t len)
112f1e9b21bSJens Wiklander {
113f1e9b21bSJens Wiklander struct tee_ccm_state *ccm = to_tee_ccm_state(aectx);
114f1e9b21bSJens Wiklander int ltc_res = 0;
115f1e9b21bSJens Wiklander
116f1e9b21bSJens Wiklander /* Add the AAD (note: aad can be NULL if aadlen == 0) */
117f1e9b21bSJens Wiklander ltc_res = ccm_add_aad(&ccm->ctx, data, len);
118f1e9b21bSJens Wiklander if (ltc_res != CRYPT_OK)
119f1e9b21bSJens Wiklander return TEE_ERROR_BAD_STATE;
120f1e9b21bSJens Wiklander
121f1e9b21bSJens Wiklander return TEE_SUCCESS;
122f1e9b21bSJens Wiklander }
123f1e9b21bSJens Wiklander
124f1e9b21bSJens Wiklander static TEE_Result
crypto_aes_ccm_update_payload(struct crypto_authenc_ctx * aectx,TEE_OperationMode mode,const uint8_t * src_data,size_t len,uint8_t * dst_data)125f1e9b21bSJens Wiklander crypto_aes_ccm_update_payload(struct crypto_authenc_ctx *aectx,
126f1e9b21bSJens Wiklander TEE_OperationMode mode, const uint8_t *src_data,
127f1e9b21bSJens Wiklander size_t len, uint8_t *dst_data)
128f1e9b21bSJens Wiklander {
129f1e9b21bSJens Wiklander int ltc_res = 0;
130f1e9b21bSJens Wiklander int dir = 0;
131f1e9b21bSJens Wiklander struct tee_ccm_state *ccm = to_tee_ccm_state(aectx);
132f1e9b21bSJens Wiklander unsigned char *pt = NULL;
133f1e9b21bSJens Wiklander unsigned char *ct = NULL;
134f1e9b21bSJens Wiklander
135f1e9b21bSJens Wiklander if (mode == TEE_MODE_ENCRYPT) {
136f1e9b21bSJens Wiklander pt = (unsigned char *)src_data;
137f1e9b21bSJens Wiklander ct = dst_data;
138f1e9b21bSJens Wiklander dir = CCM_ENCRYPT;
139f1e9b21bSJens Wiklander } else {
140f1e9b21bSJens Wiklander pt = dst_data;
141f1e9b21bSJens Wiklander ct = (unsigned char *)src_data;
142f1e9b21bSJens Wiklander dir = CCM_DECRYPT;
143f1e9b21bSJens Wiklander }
144f1e9b21bSJens Wiklander ltc_res = ccm_process(&ccm->ctx, pt, len, ct, dir);
145f1e9b21bSJens Wiklander if (ltc_res != CRYPT_OK)
146f1e9b21bSJens Wiklander return TEE_ERROR_BAD_STATE;
147f1e9b21bSJens Wiklander
148f1e9b21bSJens Wiklander return TEE_SUCCESS;
149f1e9b21bSJens Wiklander }
150f1e9b21bSJens Wiklander
crypto_aes_ccm_enc_final(struct crypto_authenc_ctx * aectx,const uint8_t * src_data,size_t len,uint8_t * dst_data,uint8_t * dst_tag,size_t * dst_tag_len)151f1e9b21bSJens Wiklander static TEE_Result crypto_aes_ccm_enc_final(struct crypto_authenc_ctx *aectx,
152f1e9b21bSJens Wiklander const uint8_t *src_data,
153f1e9b21bSJens Wiklander size_t len, uint8_t *dst_data,
154f1e9b21bSJens Wiklander uint8_t *dst_tag,
155f1e9b21bSJens Wiklander size_t *dst_tag_len)
156f1e9b21bSJens Wiklander {
157f1e9b21bSJens Wiklander TEE_Result res = TEE_SUCCESS;
158f1e9b21bSJens Wiklander struct tee_ccm_state *ccm = to_tee_ccm_state(aectx);
159f1e9b21bSJens Wiklander int ltc_res = 0;
160f1e9b21bSJens Wiklander
161f1e9b21bSJens Wiklander /* Finalize the remaining buffer */
162f1e9b21bSJens Wiklander res = crypto_aes_ccm_update_payload(aectx, TEE_MODE_ENCRYPT, src_data,
163f1e9b21bSJens Wiklander len, dst_data);
164f1e9b21bSJens Wiklander if (res != TEE_SUCCESS)
165f1e9b21bSJens Wiklander return res;
166f1e9b21bSJens Wiklander
167f1e9b21bSJens Wiklander /* Check the tag length */
168f1e9b21bSJens Wiklander if (*dst_tag_len < ccm->tag_len) {
169f1e9b21bSJens Wiklander *dst_tag_len = ccm->tag_len;
170f1e9b21bSJens Wiklander return TEE_ERROR_SHORT_BUFFER;
171f1e9b21bSJens Wiklander }
172f1e9b21bSJens Wiklander *dst_tag_len = ccm->tag_len;
173f1e9b21bSJens Wiklander
174f1e9b21bSJens Wiklander /* Compute the tag */
175f1e9b21bSJens Wiklander ltc_res = ccm_done(&ccm->ctx, dst_tag,
176f1e9b21bSJens Wiklander (unsigned long *)dst_tag_len);
177f1e9b21bSJens Wiklander if (ltc_res != CRYPT_OK)
178f1e9b21bSJens Wiklander return TEE_ERROR_BAD_STATE;
179f1e9b21bSJens Wiklander
180f1e9b21bSJens Wiklander return TEE_SUCCESS;
181f1e9b21bSJens Wiklander }
182f1e9b21bSJens Wiklander
crypto_aes_ccm_dec_final(struct crypto_authenc_ctx * aectx,const uint8_t * src_data,size_t len,uint8_t * dst_data,const uint8_t * tag,size_t tag_len)183f1e9b21bSJens Wiklander static TEE_Result crypto_aes_ccm_dec_final(struct crypto_authenc_ctx *aectx,
184f1e9b21bSJens Wiklander const uint8_t *src_data, size_t len,
185f1e9b21bSJens Wiklander uint8_t *dst_data,
186f1e9b21bSJens Wiklander const uint8_t *tag, size_t tag_len)
187f1e9b21bSJens Wiklander {
188f1e9b21bSJens Wiklander TEE_Result res = TEE_ERROR_BAD_STATE;
189f1e9b21bSJens Wiklander struct tee_ccm_state *ccm = to_tee_ccm_state(aectx);
190f1e9b21bSJens Wiklander int ltc_res = 0;
191f1e9b21bSJens Wiklander uint8_t dst_tag[TEE_CCM_TAG_MAX_LENGTH] = { 0 };
192f1e9b21bSJens Wiklander unsigned long ltc_tag_len = tag_len;
193f1e9b21bSJens Wiklander
194f1e9b21bSJens Wiklander if (tag_len == 0)
195f1e9b21bSJens Wiklander return TEE_ERROR_SHORT_BUFFER;
196f1e9b21bSJens Wiklander if (tag_len > TEE_CCM_TAG_MAX_LENGTH)
197f1e9b21bSJens Wiklander return TEE_ERROR_BAD_STATE;
198f1e9b21bSJens Wiklander
199f1e9b21bSJens Wiklander /* Process the last buffer, if any */
200f1e9b21bSJens Wiklander res = crypto_aes_ccm_update_payload(aectx, TEE_MODE_DECRYPT, src_data,
201f1e9b21bSJens Wiklander len, dst_data);
202f1e9b21bSJens Wiklander if (res != TEE_SUCCESS)
203f1e9b21bSJens Wiklander return res;
204f1e9b21bSJens Wiklander
205f1e9b21bSJens Wiklander /* Finalize the authentication */
206f1e9b21bSJens Wiklander ltc_res = ccm_done(&ccm->ctx, dst_tag, <c_tag_len);
207f1e9b21bSJens Wiklander if (ltc_res != CRYPT_OK)
208f1e9b21bSJens Wiklander return TEE_ERROR_BAD_STATE;
209f1e9b21bSJens Wiklander
210f1e9b21bSJens Wiklander if (consttime_memcmp(dst_tag, tag, tag_len) != 0)
211f1e9b21bSJens Wiklander res = TEE_ERROR_MAC_INVALID;
212f1e9b21bSJens Wiklander else
213f1e9b21bSJens Wiklander res = TEE_SUCCESS;
214f1e9b21bSJens Wiklander return res;
215f1e9b21bSJens Wiklander }
216f1e9b21bSJens Wiklander
crypto_aes_ccm_final(struct crypto_authenc_ctx * aectx)217f1e9b21bSJens Wiklander static void crypto_aes_ccm_final(struct crypto_authenc_ctx *aectx)
218f1e9b21bSJens Wiklander {
219f1e9b21bSJens Wiklander ccm_reset(&to_tee_ccm_state(aectx)->ctx);
220f1e9b21bSJens Wiklander }
221f1e9b21bSJens Wiklander
222f1e9b21bSJens Wiklander static const struct crypto_authenc_ops aes_ccm_ops = {
223f1e9b21bSJens Wiklander .init = crypto_aes_ccm_init,
224f1e9b21bSJens Wiklander .update_aad = crypto_aes_ccm_update_aad,
225f1e9b21bSJens Wiklander .update_payload = crypto_aes_ccm_update_payload,
226f1e9b21bSJens Wiklander .enc_final = crypto_aes_ccm_enc_final,
227f1e9b21bSJens Wiklander .dec_final = crypto_aes_ccm_dec_final,
228f1e9b21bSJens Wiklander .final = crypto_aes_ccm_final,
229f1e9b21bSJens Wiklander .free_ctx = crypto_aes_ccm_free_ctx,
230f1e9b21bSJens Wiklander .copy_state = crypto_aes_ccm_copy_state,
231f1e9b21bSJens Wiklander };
232