Branch data Line data Source code
1 : : /*
2 : : * PSA MAC layer on top of Mbed TLS software crypto
3 : : */
4 : : /*
5 : : * Copyright The Mbed TLS Contributors
6 : : * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
7 : : */
8 : :
9 : : #include "common.h"
10 : :
11 : : #if defined(MBEDTLS_PSA_CRYPTO_C)
12 : :
13 : : #include <psa/crypto.h>
14 : : #include "psa_crypto_core.h"
15 : : #include "psa_crypto_cipher.h"
16 : : #include "psa_crypto_mac.h"
17 : : #include <mbedtls/md.h>
18 : :
19 : : #include <mbedtls/error.h>
20 : : #include "mbedtls/constant_time.h"
21 : : #include <string.h>
22 : :
23 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC)
24 : 154 : static psa_status_t psa_hmac_abort_internal(
25 : : mbedtls_psa_hmac_operation_t *hmac)
26 : : {
27 : 154 : mbedtls_platform_zeroize(hmac->opad, sizeof(hmac->opad));
28 : 154 : return psa_hash_abort(&hmac->hash_ctx);
29 : : }
30 : :
31 : 154 : static psa_status_t psa_hmac_setup_internal(
32 : : mbedtls_psa_hmac_operation_t *hmac,
33 : : const uint8_t *key,
34 : : size_t key_length,
35 : : psa_algorithm_t hash_alg)
36 : : {
37 : 154 : uint8_t ipad[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
38 : 154 : size_t i;
39 [ - + ]: 154 : size_t hash_size = PSA_HASH_LENGTH(hash_alg);
40 [ - - - - : 154 : size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg);
+ - - - -
- - - -
- ]
41 : 154 : psa_status_t status;
42 : :
43 : 154 : hmac->alg = hash_alg;
44 : :
45 : : /* Sanity checks on block_size, to guarantee that there won't be a buffer
46 : : * overflow below. This should never trigger if the hash algorithm
47 : : * is implemented correctly. */
48 : : /* The size checks against the ipad and opad buffers cannot be written
49 : : * `block_size > sizeof( ipad ) || block_size > sizeof( hmac->opad )`
50 : : * because that triggers -Wlogical-op on GCC 7.3. */
51 [ - - ]: 154 : if (block_size > sizeof(ipad)) {
52 : 0 : return PSA_ERROR_NOT_SUPPORTED;
53 : : }
54 : 154 : if (block_size > sizeof(hmac->opad)) {
55 : : return PSA_ERROR_NOT_SUPPORTED;
56 : : }
57 [ - + ]: 154 : if (block_size < hash_size) {
58 : : return PSA_ERROR_NOT_SUPPORTED;
59 : : }
60 : :
61 [ - + ]: 154 : if (key_length > block_size) {
62 : 0 : status = psa_hash_compute(hash_alg, key, key_length,
63 : : ipad, sizeof(ipad), &key_length);
64 [ # # ]: 0 : if (status != PSA_SUCCESS) {
65 : 0 : goto cleanup;
66 : : }
67 : : }
68 : : /* A 0-length key is not commonly used in HMAC when used as a MAC,
69 : : * but it is permitted. It is common when HMAC is used in HKDF, for
70 : : * example. Don't call `memcpy` in the 0-length because `key` could be
71 : : * an invalid pointer which would make the behavior undefined. */
72 [ + - ]: 154 : else if (key_length != 0) {
73 : 154 : memcpy(ipad, key, key_length);
74 : : }
75 : :
76 : : /* ipad contains the key followed by garbage. Xor and fill with 0x36
77 : : * to create the ipad value. */
78 [ + + ]: 4434 : for (i = 0; i < key_length; i++) {
79 : 4280 : ipad[i] ^= 0x36;
80 : : }
81 : 154 : memset(ipad + key_length, 0x36, block_size - key_length);
82 : :
83 : : /* Copy the key material from ipad to opad, flipping the requisite bits,
84 : : * and filling the rest of opad with the requisite constant. */
85 [ + + ]: 4434 : for (i = 0; i < key_length; i++) {
86 : 4280 : hmac->opad[i] = ipad[i] ^ 0x36 ^ 0x5C;
87 : : }
88 : 154 : memset(hmac->opad + key_length, 0x5C, block_size - key_length);
89 : :
90 : 154 : status = psa_hash_setup(&hmac->hash_ctx, hash_alg);
91 [ - + ]: 154 : if (status != PSA_SUCCESS) {
92 : 0 : goto cleanup;
93 : : }
94 : :
95 : 154 : status = psa_hash_update(&hmac->hash_ctx, ipad, block_size);
96 : :
97 : 154 : cleanup:
98 : 154 : mbedtls_platform_zeroize(ipad, sizeof(ipad));
99 : :
100 : 154 : return status;
101 : : }
102 : :
103 : 154 : static psa_status_t psa_hmac_update_internal(
104 : : mbedtls_psa_hmac_operation_t *hmac,
105 : : const uint8_t *data,
106 : : size_t data_length)
107 : : {
108 : 154 : return psa_hash_update(&hmac->hash_ctx, data, data_length);
109 : : }
110 : :
111 : 154 : static psa_status_t psa_hmac_finish_internal(
112 : : mbedtls_psa_hmac_operation_t *hmac,
113 : : uint8_t *mac,
114 : : size_t mac_size)
115 : : {
116 : 154 : uint8_t tmp[PSA_HASH_MAX_SIZE];
117 : 154 : psa_algorithm_t hash_alg = hmac->alg;
118 : 154 : size_t hash_size = 0;
119 [ - + ]: 154 : size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg);
120 : 154 : psa_status_t status;
121 : :
122 : 154 : status = psa_hash_finish(&hmac->hash_ctx, tmp, sizeof(tmp), &hash_size);
123 [ + - ]: 154 : if (status != PSA_SUCCESS) {
124 : : return status;
125 : : }
126 : : /* From here on, tmp needs to be wiped. */
127 : :
128 : 154 : status = psa_hash_setup(&hmac->hash_ctx, hash_alg);
129 [ - + ]: 154 : if (status != PSA_SUCCESS) {
130 : 0 : goto exit;
131 : : }
132 : :
133 : 154 : status = psa_hash_update(&hmac->hash_ctx, hmac->opad, block_size);
134 [ - + ]: 154 : if (status != PSA_SUCCESS) {
135 : 0 : goto exit;
136 : : }
137 : :
138 : 154 : status = psa_hash_update(&hmac->hash_ctx, tmp, hash_size);
139 [ - + ]: 154 : if (status != PSA_SUCCESS) {
140 : 0 : goto exit;
141 : : }
142 : :
143 : 154 : status = psa_hash_finish(&hmac->hash_ctx, tmp, sizeof(tmp), &hash_size);
144 [ - + ]: 154 : if (status != PSA_SUCCESS) {
145 : 0 : goto exit;
146 : : }
147 : :
148 : 154 : memcpy(mac, tmp, mac_size);
149 : :
150 : 154 : exit:
151 : 154 : mbedtls_platform_zeroize(tmp, hash_size);
152 : 154 : return status;
153 : : }
154 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
155 : :
156 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
157 : : static psa_status_t cmac_setup(mbedtls_psa_mac_operation_t *operation,
158 : : const psa_key_attributes_t *attributes,
159 : : const uint8_t *key_buffer)
160 : : {
161 : : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
162 : :
163 : : #if defined(PSA_WANT_KEY_TYPE_DES)
164 : : /* Mbed TLS CMAC does not accept 3DES with only two keys, nor does it accept
165 : : * to do CMAC with pure DES, so return NOT_SUPPORTED here. */
166 : : if (psa_get_key_type(attributes) == PSA_KEY_TYPE_DES &&
167 : : (psa_get_key_bits(attributes) == 64 ||
168 : : psa_get_key_bits(attributes) == 128)) {
169 : : return PSA_ERROR_NOT_SUPPORTED;
170 : : }
171 : : #endif
172 : :
173 : : const mbedtls_cipher_info_t *cipher_info =
174 : : mbedtls_cipher_info_from_psa(
175 : : PSA_ALG_CMAC,
176 : : psa_get_key_type(attributes),
177 : : psa_get_key_bits(attributes),
178 : : NULL);
179 : :
180 : : if (cipher_info == NULL) {
181 : : return PSA_ERROR_NOT_SUPPORTED;
182 : : }
183 : :
184 : : ret = mbedtls_cipher_setup(&operation->ctx.cmac, cipher_info);
185 : : if (ret != 0) {
186 : : goto exit;
187 : : }
188 : :
189 : : ret = mbedtls_cipher_cmac_starts(&operation->ctx.cmac,
190 : : key_buffer,
191 : : psa_get_key_bits(attributes));
192 : : exit:
193 : : return mbedtls_to_psa_error(ret);
194 : : }
195 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */
196 : :
197 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) || \
198 : : defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
199 : :
200 : : /* Initialize this driver's MAC operation structure. Once this function has been
201 : : * called, mbedtls_psa_mac_abort can run and will do the right thing. */
202 : 154 : static psa_status_t mac_init(
203 : : mbedtls_psa_mac_operation_t *operation,
204 : : psa_algorithm_t alg)
205 : : {
206 : 154 : psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
207 : :
208 : 154 : operation->alg = alg;
209 : :
210 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
211 : : if (PSA_ALG_FULL_LENGTH_MAC(operation->alg) == PSA_ALG_CMAC) {
212 : : mbedtls_cipher_init(&operation->ctx.cmac);
213 : : status = PSA_SUCCESS;
214 : : } else
215 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */
216 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC)
217 [ + - ]: 154 : if (PSA_ALG_IS_HMAC(operation->alg)) {
218 : : /* We'll set up the hash operation later in psa_hmac_setup_internal. */
219 : 154 : operation->ctx.hmac.alg = 0;
220 : 154 : status = PSA_SUCCESS;
221 : : } else
222 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
223 : : {
224 : : (void) operation;
225 : : status = PSA_ERROR_NOT_SUPPORTED;
226 : : }
227 : :
228 : 154 : if (status != PSA_SUCCESS) {
229 : 0 : memset(operation, 0, sizeof(*operation));
230 : : }
231 : 154 : return status;
232 : : }
233 : :
234 : 154 : psa_status_t mbedtls_psa_mac_abort(mbedtls_psa_mac_operation_t *operation)
235 : : {
236 [ - + ]: 154 : if (operation->alg == 0) {
237 : : /* The object has (apparently) been initialized but it is not
238 : : * in use. It's ok to call abort on such an object, and there's
239 : : * nothing to do. */
240 : : return PSA_SUCCESS;
241 : : } else
242 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
243 : : if (PSA_ALG_FULL_LENGTH_MAC(operation->alg) == PSA_ALG_CMAC) {
244 : : mbedtls_cipher_free(&operation->ctx.cmac);
245 : : } else
246 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */
247 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC)
248 [ + - ]: 154 : if (PSA_ALG_IS_HMAC(operation->alg)) {
249 : 154 : psa_hmac_abort_internal(&operation->ctx.hmac);
250 : : } else
251 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
252 : : {
253 : : /* Sanity check (shouldn't happen: operation->alg should
254 : : * always have been initialized to a valid value). */
255 : 0 : goto bad_state;
256 : : }
257 : :
258 : 154 : operation->alg = 0;
259 : :
260 : 154 : return PSA_SUCCESS;
261 : :
262 : 0 : bad_state:
263 : : /* If abort is called on an uninitialized object, we can't trust
264 : : * anything. Wipe the object in case it contains confidential data.
265 : : * This may result in a memory leak if a pointer gets overwritten,
266 : : * but it's too late to do anything about this. */
267 : 0 : memset(operation, 0, sizeof(*operation));
268 : 0 : return PSA_ERROR_BAD_STATE;
269 : : }
270 : :
271 : 154 : static psa_status_t psa_mac_setup(mbedtls_psa_mac_operation_t *operation,
272 : : const psa_key_attributes_t *attributes,
273 : : const uint8_t *key_buffer,
274 : : size_t key_buffer_size,
275 : : psa_algorithm_t alg)
276 : : {
277 : 154 : psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
278 : :
279 : : /* A context must be freshly initialized before it can be set up. */
280 [ + - ]: 154 : if (operation->alg != 0) {
281 : : return PSA_ERROR_BAD_STATE;
282 : : }
283 : :
284 : 154 : status = mac_init(operation, alg);
285 [ + - ]: 154 : if (status != PSA_SUCCESS) {
286 : : return status;
287 : : }
288 : :
289 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
290 : : if (PSA_ALG_FULL_LENGTH_MAC(alg) == PSA_ALG_CMAC) {
291 : : /* Key buffer size for CMAC is dictated by the key bits set on the
292 : : * attributes, and previously validated by the core on key import. */
293 : : (void) key_buffer_size;
294 : : status = cmac_setup(operation, attributes, key_buffer);
295 : : } else
296 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */
297 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC)
298 [ + - ]: 154 : if (PSA_ALG_IS_HMAC(alg)) {
299 : 154 : status = psa_hmac_setup_internal(&operation->ctx.hmac,
300 : : key_buffer,
301 : : key_buffer_size,
302 : 154 : PSA_ALG_HMAC_GET_HASH(alg));
303 : : } else
304 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
305 : : {
306 : : (void) attributes;
307 : : (void) key_buffer;
308 : : (void) key_buffer_size;
309 : : status = PSA_ERROR_NOT_SUPPORTED;
310 : : }
311 : :
312 [ - + ]: 154 : if (status != PSA_SUCCESS) {
313 : 0 : mbedtls_psa_mac_abort(operation);
314 : : }
315 : :
316 : : return status;
317 : : }
318 : :
319 : 0 : psa_status_t mbedtls_psa_mac_sign_setup(
320 : : mbedtls_psa_mac_operation_t *operation,
321 : : const psa_key_attributes_t *attributes,
322 : : const uint8_t *key_buffer,
323 : : size_t key_buffer_size,
324 : : psa_algorithm_t alg)
325 : : {
326 : 0 : return psa_mac_setup(operation, attributes,
327 : : key_buffer, key_buffer_size, alg);
328 : : }
329 : :
330 : 0 : psa_status_t mbedtls_psa_mac_verify_setup(
331 : : mbedtls_psa_mac_operation_t *operation,
332 : : const psa_key_attributes_t *attributes,
333 : : const uint8_t *key_buffer,
334 : : size_t key_buffer_size,
335 : : psa_algorithm_t alg)
336 : : {
337 : 0 : return psa_mac_setup(operation, attributes,
338 : : key_buffer, key_buffer_size, alg);
339 : : }
340 : :
341 : 154 : psa_status_t mbedtls_psa_mac_update(
342 : : mbedtls_psa_mac_operation_t *operation,
343 : : const uint8_t *input,
344 : : size_t input_length)
345 : : {
346 [ + - ]: 154 : if (operation->alg == 0) {
347 : : return PSA_ERROR_BAD_STATE;
348 : : }
349 : :
350 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
351 : : if (PSA_ALG_FULL_LENGTH_MAC(operation->alg) == PSA_ALG_CMAC) {
352 : : return mbedtls_to_psa_error(
353 : : mbedtls_cipher_cmac_update(&operation->ctx.cmac,
354 : : input, input_length));
355 : : } else
356 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */
357 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC)
358 [ + - ]: 154 : if (PSA_ALG_IS_HMAC(operation->alg)) {
359 : 154 : return psa_hmac_update_internal(&operation->ctx.hmac,
360 : : input, input_length);
361 : : } else
362 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
363 : : {
364 : : /* This shouldn't happen if `operation` was initialized by
365 : : * a setup function. */
366 : : (void) input;
367 : : (void) input_length;
368 : : return PSA_ERROR_BAD_STATE;
369 : : }
370 : : }
371 : :
372 : 154 : static psa_status_t psa_mac_finish_internal(
373 : : mbedtls_psa_mac_operation_t *operation,
374 : : uint8_t *mac, size_t mac_size)
375 : : {
376 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
377 : : if (PSA_ALG_FULL_LENGTH_MAC(operation->alg) == PSA_ALG_CMAC) {
378 : : uint8_t tmp[PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE];
379 : : int ret = mbedtls_cipher_cmac_finish(&operation->ctx.cmac, tmp);
380 : : if (ret == 0) {
381 : : memcpy(mac, tmp, mac_size);
382 : : }
383 : : mbedtls_platform_zeroize(tmp, sizeof(tmp));
384 : : return mbedtls_to_psa_error(ret);
385 : : } else
386 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */
387 : : #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC)
388 [ + - ]: 154 : if (PSA_ALG_IS_HMAC(operation->alg)) {
389 : 154 : return psa_hmac_finish_internal(&operation->ctx.hmac,
390 : : mac, mac_size);
391 : : } else
392 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
393 : : {
394 : : /* This shouldn't happen if `operation` was initialized by
395 : : * a setup function. */
396 : : (void) operation;
397 : : (void) mac;
398 : : (void) mac_size;
399 : : return PSA_ERROR_BAD_STATE;
400 : : }
401 : : }
402 : :
403 : 0 : psa_status_t mbedtls_psa_mac_sign_finish(
404 : : mbedtls_psa_mac_operation_t *operation,
405 : : uint8_t *mac,
406 : : size_t mac_size,
407 : : size_t *mac_length)
408 : : {
409 : 0 : psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
410 : :
411 [ # # ]: 0 : if (operation->alg == 0) {
412 : : return PSA_ERROR_BAD_STATE;
413 : : }
414 : :
415 : 0 : status = psa_mac_finish_internal(operation, mac, mac_size);
416 [ # # ]: 0 : if (status == PSA_SUCCESS) {
417 : 0 : *mac_length = mac_size;
418 : : }
419 : :
420 : : return status;
421 : : }
422 : :
423 : 0 : psa_status_t mbedtls_psa_mac_verify_finish(
424 : : mbedtls_psa_mac_operation_t *operation,
425 : : const uint8_t *mac,
426 : : size_t mac_length)
427 : : {
428 : 0 : uint8_t actual_mac[PSA_MAC_MAX_SIZE];
429 : 0 : psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
430 : :
431 [ # # ]: 0 : if (operation->alg == 0) {
432 : : return PSA_ERROR_BAD_STATE;
433 : : }
434 : :
435 : : /* Consistency check: requested MAC length fits our local buffer */
436 [ # # ]: 0 : if (mac_length > sizeof(actual_mac)) {
437 : : return PSA_ERROR_INVALID_ARGUMENT;
438 : : }
439 : :
440 : 0 : status = psa_mac_finish_internal(operation, actual_mac, mac_length);
441 [ # # ]: 0 : if (status != PSA_SUCCESS) {
442 : 0 : goto cleanup;
443 : : }
444 : :
445 [ # # ]: 0 : if (mbedtls_ct_memcmp(mac, actual_mac, mac_length) != 0) {
446 : 0 : status = PSA_ERROR_INVALID_SIGNATURE;
447 : : }
448 : :
449 : 0 : cleanup:
450 : 0 : mbedtls_platform_zeroize(actual_mac, sizeof(actual_mac));
451 : :
452 : 0 : return status;
453 : : }
454 : :
455 : 154 : psa_status_t mbedtls_psa_mac_compute(
456 : : const psa_key_attributes_t *attributes,
457 : : const uint8_t *key_buffer,
458 : : size_t key_buffer_size,
459 : : psa_algorithm_t alg,
460 : : const uint8_t *input,
461 : : size_t input_length,
462 : : uint8_t *mac,
463 : : size_t mac_size,
464 : : size_t *mac_length)
465 : : {
466 : 154 : psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
467 : 154 : mbedtls_psa_mac_operation_t operation = MBEDTLS_PSA_MAC_OPERATION_INIT;
468 : : /* Make sure the whole operation is zeroed.
469 : : * PSA_MAC_OPERATION_INIT does not necessarily do it fully,
470 : : * since one field is a union and initializing a union does not
471 : : * necessarily initialize all of its members.
472 : : * In multipart operations, this is done in the API functions,
473 : : * before driver dispatch, since it needs to be done before calling
474 : : * the driver entry point. Here, we bypass the multipart API,
475 : : * so it's our job. */
476 : 154 : memset(&operation, 0, sizeof(operation));
477 : :
478 : 154 : status = psa_mac_setup(&operation,
479 : : attributes, key_buffer, key_buffer_size,
480 : : alg);
481 [ - + ]: 154 : if (status != PSA_SUCCESS) {
482 : 0 : goto exit;
483 : : }
484 : :
485 [ + - ]: 154 : if (input_length > 0) {
486 : 154 : status = mbedtls_psa_mac_update(&operation, input, input_length);
487 [ - + ]: 154 : if (status != PSA_SUCCESS) {
488 : 0 : goto exit;
489 : : }
490 : : }
491 : :
492 : 154 : status = psa_mac_finish_internal(&operation, mac, mac_size);
493 [ - + ]: 154 : if (status == PSA_SUCCESS) {
494 : 154 : *mac_length = mac_size;
495 : : }
496 : :
497 : 0 : exit:
498 : 154 : mbedtls_psa_mac_abort(&operation);
499 : :
500 : 154 : return status;
501 : : }
502 : :
503 : : #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC || MBEDTLS_PSA_BUILTIN_ALG_CMAC */
504 : :
505 : : #endif /* MBEDTLS_PSA_CRYPTO_C */
|