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)
24static psa_status_t psa_hmac_abort_internal(
25    mbedtls_psa_hmac_operation_t *hmac)
26{
27    mbedtls_platform_zeroize(hmac->opad, sizeof(hmac->opad));
28    return psa_hash_abort(&hmac->hash_ctx);
29}
30
31static 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    uint8_t ipad[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
38    size_t i;
39    size_t hash_size = PSA_HASH_LENGTH(hash_alg);
40    size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg);
41    psa_status_t status;
42
43    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    if (block_size > sizeof(ipad)) {
52        return PSA_ERROR_NOT_SUPPORTED;
53    }
54    if (block_size > sizeof(hmac->opad)) {
55        return PSA_ERROR_NOT_SUPPORTED;
56    }
57    if (block_size < hash_size) {
58        return PSA_ERROR_NOT_SUPPORTED;
59    }
60
61    if (key_length > block_size) {
62        status = psa_hash_compute(hash_alg, key, key_length,
63                                  ipad, sizeof(ipad), &key_length);
64        if (status != PSA_SUCCESS) {
65            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    else if (key_length != 0) {
73        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    for (i = 0; i < key_length; i++) {
79        ipad[i] ^= 0x36;
80    }
81    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    for (i = 0; i < key_length; i++) {
86        hmac->opad[i] = ipad[i] ^ 0x36 ^ 0x5C;
87    }
88    memset(hmac->opad + key_length, 0x5C, block_size - key_length);
89
90    status = psa_hash_setup(&hmac->hash_ctx, hash_alg);
91    if (status != PSA_SUCCESS) {
92        goto cleanup;
93    }
94
95    status = psa_hash_update(&hmac->hash_ctx, ipad, block_size);
96
97cleanup:
98    mbedtls_platform_zeroize(ipad, sizeof(ipad));
99
100    return status;
101}
102
103static 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    return psa_hash_update(&hmac->hash_ctx, data, data_length);
109}
110
111static 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    uint8_t tmp[PSA_HASH_MAX_SIZE];
117    psa_algorithm_t hash_alg = hmac->alg;
118    size_t hash_size = 0;
119    size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg);
120    psa_status_t status;
121
122    status = psa_hash_finish(&hmac->hash_ctx, tmp, sizeof(tmp), &hash_size);
123    if (status != PSA_SUCCESS) {
124        return status;
125    }
126    /* From here on, tmp needs to be wiped. */
127
128    status = psa_hash_setup(&hmac->hash_ctx, hash_alg);
129    if (status != PSA_SUCCESS) {
130        goto exit;
131    }
132
133    status = psa_hash_update(&hmac->hash_ctx, hmac->opad, block_size);
134    if (status != PSA_SUCCESS) {
135        goto exit;
136    }
137
138    status = psa_hash_update(&hmac->hash_ctx, tmp, hash_size);
139    if (status != PSA_SUCCESS) {
140        goto exit;
141    }
142
143    status = psa_hash_finish(&hmac->hash_ctx, tmp, sizeof(tmp), &hash_size);
144    if (status != PSA_SUCCESS) {
145        goto exit;
146    }
147
148    memcpy(mac, tmp, mac_size);
149
150exit:
151    mbedtls_platform_zeroize(tmp, hash_size);
152    return status;
153}
154#endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
155
156#if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
157static 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));
192exit:
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. */
202static psa_status_t mac_init(
203    mbedtls_psa_mac_operation_t *operation,
204    psa_algorithm_t alg)
205{
206    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
207
208    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    if (PSA_ALG_IS_HMAC(operation->alg)) {
218        /* We'll set up the hash operation later in psa_hmac_setup_internal. */
219        operation->ctx.hmac.alg = 0;
220        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    if (status != PSA_SUCCESS) {
229        memset(operation, 0, sizeof(*operation));
230    }
231    return status;
232}
233
234psa_status_t mbedtls_psa_mac_abort(mbedtls_psa_mac_operation_t *operation)
235{
236    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    if (PSA_ALG_IS_HMAC(operation->alg)) {
249        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        goto bad_state;
256    }
257
258    operation->alg = 0;
259
260    return PSA_SUCCESS;
261
262bad_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    memset(operation, 0, sizeof(*operation));
268    return PSA_ERROR_BAD_STATE;
269}
270
271static 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    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
278
279    /* A context must be freshly initialized before it can be set up. */
280    if (operation->alg != 0) {
281        return PSA_ERROR_BAD_STATE;
282    }
283
284    status = mac_init(operation, alg);
285    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    if (PSA_ALG_IS_HMAC(alg)) {
299        status = psa_hmac_setup_internal(&operation->ctx.hmac,
300                                         key_buffer,
301                                         key_buffer_size,
302                                         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    if (status != PSA_SUCCESS) {
313        mbedtls_psa_mac_abort(operation);
314    }
315
316    return status;
317}
318
319psa_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    return psa_mac_setup(operation, attributes,
327                         key_buffer, key_buffer_size, alg);
328}
329
330psa_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    return psa_mac_setup(operation, attributes,
338                         key_buffer, key_buffer_size, alg);
339}
340
341psa_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    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    if (PSA_ALG_IS_HMAC(operation->alg)) {
359        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
372static 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    if (PSA_ALG_IS_HMAC(operation->alg)) {
389        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
403psa_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    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
410
411    if (operation->alg == 0) {
412        return PSA_ERROR_BAD_STATE;
413    }
414
415    status = psa_mac_finish_internal(operation, mac, mac_size);
416    if (status == PSA_SUCCESS) {
417        *mac_length = mac_size;
418    }
419
420    return status;
421}
422
423psa_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    uint8_t actual_mac[PSA_MAC_MAX_SIZE];
429    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
430
431    if (operation->alg == 0) {
432        return PSA_ERROR_BAD_STATE;
433    }
434
435    /* Consistency check: requested MAC length fits our local buffer */
436    if (mac_length > sizeof(actual_mac)) {
437        return PSA_ERROR_INVALID_ARGUMENT;
438    }
439
440    status = psa_mac_finish_internal(operation, actual_mac, mac_length);
441    if (status != PSA_SUCCESS) {
442        goto cleanup;
443    }
444
445    if (mbedtls_ct_memcmp(mac, actual_mac, mac_length) != 0) {
446        status = PSA_ERROR_INVALID_SIGNATURE;
447    }
448
449cleanup:
450    mbedtls_platform_zeroize(actual_mac, sizeof(actual_mac));
451
452    return status;
453}
454
455psa_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    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
467    mbedtls_psa_mac_operation_t operation = MBEDTLS_PSA_MAC_OPERATION_INIT;
468
469    status = psa_mac_setup(&operation,
470                           attributes, key_buffer, key_buffer_size,
471                           alg);
472    if (status != PSA_SUCCESS) {
473        goto exit;
474    }
475
476    if (input_length > 0) {
477        status = mbedtls_psa_mac_update(&operation, input, input_length);
478        if (status != PSA_SUCCESS) {
479            goto exit;
480        }
481    }
482
483    status = psa_mac_finish_internal(&operation, mac, mac_size);
484    if (status == PSA_SUCCESS) {
485        *mac_length = mac_size;
486    }
487
488exit:
489    mbedtls_psa_mac_abort(&operation);
490
491    return status;
492}
493
494#endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC || MBEDTLS_PSA_BUILTIN_ALG_CMAC */
495
496#endif /* MBEDTLS_PSA_CRYPTO_C */
497