1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014-2019, Linaro Limited
4  */
5 
6 /*
7  * This is implemented here as being the plain text which is encoded with IV=0.
8  * Result of the CBC-MAC is the last 16-bytes cipher.
9  */
10 
11 #include <assert.h>
12 #include <crypto/crypto.h>
13 #include <crypto/crypto_impl.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <types_ext.h>
17 #include <util.h>
18 
19 #define CBCMAC_MAX_BLOCK_LEN 16
20 
21 struct crypto_cbc_mac_ctx {
22 	struct crypto_mac_ctx ctx;
23 	void *cbc_ctx;
24 	uint32_t cbc_algo;
25 	uint8_t block[CBCMAC_MAX_BLOCK_LEN];
26 	uint8_t digest[CBCMAC_MAX_BLOCK_LEN];
27 	unsigned char current_block_len;
28 	unsigned char block_len;
29 	bool is_computed;
30 	bool pkcs5_pad;
31 };
32 
33 static const struct crypto_mac_ops crypto_cbc_mac_ops;
34 
to_cbc_mac_ctx(struct crypto_mac_ctx * ctx)35 static struct crypto_cbc_mac_ctx *to_cbc_mac_ctx(struct crypto_mac_ctx *ctx)
36 {
37 	assert(ctx && ctx->ops == &crypto_cbc_mac_ops);
38 
39 	return container_of(ctx, struct crypto_cbc_mac_ctx, ctx);
40 }
41 
crypto_cbc_mac_init(struct crypto_mac_ctx * ctx,const uint8_t * key,size_t len)42 static TEE_Result crypto_cbc_mac_init(struct crypto_mac_ctx *ctx,
43 				      const uint8_t *key, size_t len)
44 {
45 	struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx);
46 
47 	memset(mc->block, 0, sizeof(mc->block));
48 	memset(mc->digest, 0, sizeof(mc->digest));
49 	mc->current_block_len = 0;
50 	mc->is_computed = false;
51 
52 	/* IV should be zero and mc->block happens to be zero at this stage */
53 	return crypto_cipher_init(mc->cbc_ctx, TEE_MODE_ENCRYPT, key, len,
54 				  NULL, 0, mc->block, mc->block_len);
55 }
56 
crypto_cbc_mac_update(struct crypto_mac_ctx * ctx,const uint8_t * data,size_t len)57 static TEE_Result crypto_cbc_mac_update(struct crypto_mac_ctx *ctx,
58 					const uint8_t *data, size_t len)
59 {
60 	size_t nblocks = 0;
61 	size_t out_len = 0;
62 	uint8_t *out_tmp = NULL;
63 	uint8_t *out = NULL;
64 	TEE_Result res = TEE_SUCCESS;
65 	struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx);
66 
67 	if ((mc->current_block_len > 0) &&
68 	    (len + mc->current_block_len >= mc->block_len)) {
69 		size_t pad_len = mc->block_len - mc->current_block_len;
70 
71 		memcpy(mc->block + mc->current_block_len, data, pad_len);
72 		data += pad_len;
73 		len -= pad_len;
74 		res = crypto_cipher_update(mc->cbc_ctx, TEE_MODE_ENCRYPT,
75 					   false, mc->block, mc->block_len,
76 					   mc->digest);
77 		if (res)
78 			return res;
79 		mc->is_computed = 1;
80 		mc->current_block_len = 0;
81 	}
82 
83 	nblocks = MIN(len / mc->block_len,
84 		      (size_t)CFG_CRYPTO_CBC_MAC_BUNDLE_BLOCKS);
85 	if (nblocks > 1)
86 		out_tmp = malloc(nblocks * mc->block_len);
87 
88 	while (len >= mc->block_len) {
89 		nblocks = MIN(len / mc->block_len,
90 			      (size_t)CFG_CRYPTO_CBC_MAC_BUNDLE_BLOCKS);
91 
92 		if (nblocks > 1 && out_tmp) {
93 			out_len = nblocks * mc->block_len;
94 			out = out_tmp;
95 		} else {
96 			out_len = mc->block_len;
97 			out = mc->digest;
98 			nblocks = 1;
99 		}
100 
101 		res = crypto_cipher_update(mc->cbc_ctx, TEE_MODE_ENCRYPT,
102 					   false, data, out_len, out);
103 		if (res)
104 			goto out;
105 		mc->is_computed = 1;
106 		data += out_len;
107 		len -= out_len;
108 		if (nblocks > 1 && len < mc->block_len) {
109 			assert(out_tmp);
110 			/* Copy last block of output */
111 			memcpy(mc->digest, out_tmp + out_len - mc->block_len,
112 			       mc->block_len);
113 		}
114 	}
115 
116 	if (len > 0) {
117 		assert(mc->current_block_len + len < mc->block_len);
118 		memcpy(mc->block + mc->current_block_len, data, len);
119 		mc->current_block_len += len;
120 	}
121 
122 out:
123 	free(out_tmp);
124 	return res;
125 }
126 
crypto_cbc_mac_final(struct crypto_mac_ctx * ctx,uint8_t * digest,size_t digest_len)127 static TEE_Result crypto_cbc_mac_final(struct crypto_mac_ctx *ctx,
128 				       uint8_t *digest, size_t digest_len)
129 {
130 	struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx);
131 
132 	if (mc->pkcs5_pad) {
133 		/*
134 		 * Padding is in whole bytes. The value of each added
135 		 * byte is the number of bytes that are added, i.e. N
136 		 * bytes, each of value N are added
137 		 */
138 		size_t pad_len = mc->block_len - mc->current_block_len;
139 
140 		memset(mc->block + mc->current_block_len, pad_len, pad_len);
141 		mc->current_block_len = 0;
142 		if (crypto_cbc_mac_update(ctx, mc->block, mc->block_len))
143 			return TEE_ERROR_BAD_STATE;
144 	}
145 
146 	if (!mc->is_computed || mc->current_block_len)
147 		return TEE_ERROR_BAD_STATE;
148 
149 	memcpy(digest, mc->digest, MIN(digest_len, mc->block_len));
150 	crypto_cipher_final(mc->cbc_ctx);
151 
152 	return TEE_SUCCESS;
153 }
154 
crypto_cbc_mac_free_ctx(struct crypto_mac_ctx * ctx)155 static void crypto_cbc_mac_free_ctx(struct crypto_mac_ctx *ctx)
156 {
157 	struct crypto_cbc_mac_ctx *mc = to_cbc_mac_ctx(ctx);
158 
159 	crypto_cipher_free_ctx(mc->cbc_ctx);
160 	free(mc);
161 }
162 
crypto_cbc_mac_copy_state(struct crypto_mac_ctx * dst_ctx,struct crypto_mac_ctx * src_ctx)163 static void crypto_cbc_mac_copy_state(struct crypto_mac_ctx *dst_ctx,
164 				      struct crypto_mac_ctx *src_ctx)
165 {
166 	struct crypto_cbc_mac_ctx *dst = to_cbc_mac_ctx(dst_ctx);
167 	struct crypto_cbc_mac_ctx *src = to_cbc_mac_ctx(src_ctx);
168 
169 	assert(dst->block_len == src->block_len);
170 	assert(dst->pkcs5_pad == src->pkcs5_pad);
171 	assert(dst->cbc_algo == src->cbc_algo);
172 
173 	crypto_cipher_copy_state(dst->cbc_ctx, src->cbc_ctx);
174 	memcpy(dst->block, src->block, sizeof(dst->block));
175 	memcpy(dst->digest, src->digest, sizeof(dst->digest));
176 	dst->current_block_len = src->current_block_len;
177 	dst->is_computed = src->is_computed;
178 }
179 
180 static const struct crypto_mac_ops crypto_cbc_mac_ops = {
181 	.init = crypto_cbc_mac_init,
182 	.update = crypto_cbc_mac_update,
183 	.final = crypto_cbc_mac_final,
184 	.free_ctx = crypto_cbc_mac_free_ctx,
185 	.copy_state = crypto_cbc_mac_copy_state,
186 };
187 
crypto_cbc_mac_alloc_ctx(struct crypto_mac_ctx ** ctx_ret,uint32_t cbc_algo,bool pkcs5_pad)188 static TEE_Result crypto_cbc_mac_alloc_ctx(struct crypto_mac_ctx **ctx_ret,
189 					   uint32_t cbc_algo, bool pkcs5_pad)
190 {
191 	TEE_Result res;
192 	void *cbc_ctx = NULL;
193 	struct crypto_cbc_mac_ctx *ctx = NULL;
194 	size_t block_size = 0;
195 
196 	res = crypto_cipher_get_block_size(cbc_algo, &block_size);
197 	if (res)
198 		return res;
199 
200 	res = crypto_cipher_alloc_ctx(&cbc_ctx, cbc_algo);
201 	if (res)
202 		return res;
203 
204 	ctx = calloc(1, sizeof(*ctx));
205 	if (!ctx) {
206 		crypto_cipher_free_ctx(cbc_ctx);
207 		return TEE_ERROR_OUT_OF_MEMORY;
208 	}
209 
210 	ctx->cbc_ctx = cbc_ctx;
211 	ctx->cbc_algo = cbc_algo;
212 	ctx->pkcs5_pad = pkcs5_pad;
213 	ctx->block_len = block_size;
214 	ctx->ctx.ops = &crypto_cbc_mac_ops;
215 	*ctx_ret = &ctx->ctx;
216 
217 	return TEE_SUCCESS;
218 }
219 
crypto_aes_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx ** ctx)220 TEE_Result crypto_aes_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx **ctx)
221 {
222 	return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_AES_CBC_NOPAD, false);
223 }
224 
crypto_aes_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx ** ctx)225 TEE_Result crypto_aes_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx **ctx)
226 {
227 	return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_AES_CBC_NOPAD, true);
228 }
229 
crypto_des_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx ** ctx)230 TEE_Result crypto_des_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx **ctx)
231 {
232 	return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES_CBC_NOPAD, false);
233 }
234 
crypto_des_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx ** ctx)235 TEE_Result crypto_des_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx **ctx)
236 {
237 	return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES_CBC_NOPAD, true);
238 }
239 
crypto_des3_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx ** ctx)240 TEE_Result crypto_des3_cbc_mac_nopad_alloc_ctx(struct crypto_mac_ctx **ctx)
241 {
242 	return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES3_CBC_NOPAD, false);
243 }
244 
crypto_des3_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx ** ctx)245 TEE_Result crypto_des3_cbc_mac_pkcs5_alloc_ctx(struct crypto_mac_ctx **ctx)
246 {
247 	return crypto_cbc_mac_alloc_ctx(ctx, TEE_ALG_DES3_CBC_NOPAD, true);
248 }
249