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