quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

psa_crypto_mac.c (15532B)


      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 static 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 
     31 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     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 
     97 cleanup:
     98     mbedtls_platform_zeroize(ipad, sizeof(ipad));
     99 
    100     return status;
    101 }
    102 
    103 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     return psa_hash_update(&hmac->hash_ctx, data, data_length);
    109 }
    110 
    111 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     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 
    150 exit:
    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)
    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 static 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 
    234 psa_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 
    262 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     memset(operation, 0, sizeof(*operation));
    268     return PSA_ERROR_BAD_STATE;
    269 }
    270 
    271 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     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 
    319 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     return psa_mac_setup(operation, attributes,
    327                          key_buffer, key_buffer_size, alg);
    328 }
    329 
    330 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     return psa_mac_setup(operation, attributes,
    338                          key_buffer, key_buffer_size, alg);
    339 }
    340 
    341 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     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 
    372 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     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 
    403 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     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 
    423 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     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 
    449 cleanup:
    450     mbedtls_platform_zeroize(actual_mac, sizeof(actual_mac));
    451 
    452     return status;
    453 }
    454 
    455 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     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
    467     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     memset(&operation, 0, sizeof(operation));
    477 
    478     status = psa_mac_setup(&operation,
    479                            attributes, key_buffer, key_buffer_size,
    480                            alg);
    481     if (status != PSA_SUCCESS) {
    482         goto exit;
    483     }
    484 
    485     if (input_length > 0) {
    486         status = mbedtls_psa_mac_update(&operation, input, input_length);
    487         if (status != PSA_SUCCESS) {
    488             goto exit;
    489         }
    490     }
    491 
    492     status = psa_mac_finish_internal(&operation, mac, mac_size);
    493     if (status == PSA_SUCCESS) {
    494         *mac_length = mac_size;
    495     }
    496 
    497 exit:
    498     mbedtls_psa_mac_abort(&operation);
    499 
    500     return status;
    501 }
    502 
    503 #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC || MBEDTLS_PSA_BUILTIN_ALG_CMAC */
    504 
    505 #endif /* MBEDTLS_PSA_CRYPTO_C */