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