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