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