sftkhmac.c (15105B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "seccomon.h" 6 #include "secerr.h" 7 #include "blapi.h" 8 #include "pkcs11i.h" 9 #include "softoken.h" 10 #include "hmacct.h" 11 12 /* Wrappers to avoid undefined behavior calling functions through a pointer of incorrect type. */ 13 static void 14 SFTKMAC_CMAC_Destroy(void *ctx, PRBool freeit) 15 { 16 CMACContext *cctx = ctx; 17 CMAC_Destroy(cctx, freeit); 18 } 19 20 static void 21 SFTKMAC_HMAC_Destroy(void *ctx, PRBool freeit) 22 { 23 HMACContext *hctx = ctx; 24 HMAC_Destroy(hctx, freeit); 25 } 26 27 /* sftk_HMACMechanismToHash converts a PKCS#11 MAC mechanism into a freebl hash 28 * type. */ 29 HASH_HashType 30 sftk_HMACMechanismToHash(CK_MECHANISM_TYPE mech) 31 { 32 switch (mech) { 33 case CKM_MD2_HMAC: 34 return HASH_AlgMD2; 35 case CKM_MD5_HMAC: 36 case CKM_SSL3_MD5_MAC: 37 return HASH_AlgMD5; 38 case CKM_SHA_1_HMAC: 39 case CKM_SSL3_SHA1_MAC: 40 return HASH_AlgSHA1; 41 case CKM_SHA224_HMAC: 42 return HASH_AlgSHA224; 43 case CKM_SHA256_HMAC: 44 return HASH_AlgSHA256; 45 case CKM_SHA384_HMAC: 46 return HASH_AlgSHA384; 47 case CKM_SHA512_HMAC: 48 return HASH_AlgSHA512; 49 case CKM_SHA3_224_HMAC: 50 return HASH_AlgSHA3_224; 51 case CKM_SHA3_256_HMAC: 52 return HASH_AlgSHA3_256; 53 case CKM_SHA3_384_HMAC: 54 return HASH_AlgSHA3_384; 55 case CKM_SHA3_512_HMAC: 56 return HASH_AlgSHA3_512; 57 } 58 return HASH_AlgNULL; 59 } 60 61 static sftk_MACConstantTimeCtx * 62 SetupMAC(CK_MECHANISM_PTR mech, SFTKObject *key) 63 { 64 CK_NSS_MAC_CONSTANT_TIME_PARAMS *params = 65 (CK_NSS_MAC_CONSTANT_TIME_PARAMS *)mech->pParameter; 66 sftk_MACConstantTimeCtx *ctx; 67 HASH_HashType alg; 68 SFTKAttribute *keyval; 69 unsigned char secret[sizeof(ctx->secret)]; 70 unsigned int secretLength; 71 72 if (mech->ulParameterLen != sizeof(CK_NSS_MAC_CONSTANT_TIME_PARAMS)) { 73 return NULL; 74 } 75 76 alg = sftk_HMACMechanismToHash(params->macAlg); 77 if (alg == HASH_AlgNULL) { 78 return NULL; 79 } 80 81 keyval = sftk_FindAttribute(key, CKA_VALUE); 82 if (keyval == NULL) { 83 return NULL; 84 } 85 secretLength = keyval->attrib.ulValueLen; 86 if (secretLength > sizeof(secret)) { 87 sftk_FreeAttribute(keyval); 88 return NULL; 89 } 90 memcpy(secret, keyval->attrib.pValue, secretLength); 91 sftk_FreeAttribute(keyval); 92 93 ctx = PORT_Alloc(sizeof(sftk_MACConstantTimeCtx)); 94 if (!ctx) { 95 PORT_Memset(secret, 0, secretLength); 96 return NULL; 97 } 98 99 memcpy(ctx->secret, secret, secretLength); 100 ctx->secretLength = secretLength; 101 ctx->hash = HASH_GetRawHashObject(alg); 102 ctx->totalLength = params->ulBodyTotalLen; 103 PORT_Memset(secret, 0, secretLength); 104 105 return ctx; 106 } 107 108 sftk_MACConstantTimeCtx * 109 sftk_HMACConstantTime_New(CK_MECHANISM_PTR mech, SFTKObject *key) 110 { 111 CK_NSS_MAC_CONSTANT_TIME_PARAMS *params = 112 (CK_NSS_MAC_CONSTANT_TIME_PARAMS *)mech->pParameter; 113 sftk_MACConstantTimeCtx *ctx; 114 115 if (params->ulHeaderLen > sizeof(ctx->header)) { 116 return NULL; 117 } 118 ctx = SetupMAC(mech, key); 119 if (!ctx) { 120 return NULL; 121 } 122 123 ctx->headerLength = params->ulHeaderLen; 124 memcpy(ctx->header, params->pHeader, params->ulHeaderLen); 125 return ctx; 126 } 127 128 sftk_MACConstantTimeCtx * 129 sftk_SSLv3MACConstantTime_New(CK_MECHANISM_PTR mech, SFTKObject *key) 130 { 131 CK_NSS_MAC_CONSTANT_TIME_PARAMS *params = 132 (CK_NSS_MAC_CONSTANT_TIME_PARAMS *)mech->pParameter; 133 unsigned int padLength = 40, j; 134 sftk_MACConstantTimeCtx *ctx; 135 136 if (params->macAlg != CKM_SSL3_MD5_MAC && 137 params->macAlg != CKM_SSL3_SHA1_MAC) { 138 return NULL; 139 } 140 ctx = SetupMAC(mech, key); 141 if (!ctx) { 142 return NULL; 143 } 144 145 if (params->macAlg == CKM_SSL3_MD5_MAC) { 146 padLength = 48; 147 } 148 149 ctx->headerLength = 150 ctx->secretLength + 151 padLength + 152 params->ulHeaderLen; 153 154 if (ctx->headerLength > sizeof(ctx->header)) { 155 goto loser; 156 } 157 158 j = 0; 159 memcpy(&ctx->header[j], ctx->secret, ctx->secretLength); 160 j += ctx->secretLength; 161 memset(&ctx->header[j], 0x36, padLength); 162 j += padLength; 163 memcpy(&ctx->header[j], params->pHeader, params->ulHeaderLen); 164 165 return ctx; 166 167 loser: 168 PORT_Free(ctx); 169 return NULL; 170 } 171 172 void 173 sftk_HMACConstantTime_Update(void *pctx, const unsigned char *data, unsigned int len) 174 { 175 sftk_MACConstantTimeCtx *ctx = (sftk_MACConstantTimeCtx *)pctx; 176 PORT_CheckSuccess(HMAC_ConstantTime( 177 ctx->mac, NULL, sizeof(ctx->mac), 178 ctx->hash, 179 ctx->secret, ctx->secretLength, 180 ctx->header, ctx->headerLength, 181 data, len, 182 ctx->totalLength)); 183 } 184 185 void 186 sftk_SSLv3MACConstantTime_Update(void *pctx, const unsigned char *data, unsigned int len) 187 { 188 sftk_MACConstantTimeCtx *ctx = (sftk_MACConstantTimeCtx *)pctx; 189 PORT_CheckSuccess(SSLv3_MAC_ConstantTime( 190 ctx->mac, NULL, sizeof(ctx->mac), 191 ctx->hash, 192 ctx->secret, ctx->secretLength, 193 ctx->header, ctx->headerLength, 194 data, len, 195 ctx->totalLength)); 196 } 197 198 void 199 sftk_MACConstantTime_EndHash(void *pctx, unsigned char *out, unsigned int *outLength, 200 unsigned int maxLength) 201 { 202 const sftk_MACConstantTimeCtx *ctx = (sftk_MACConstantTimeCtx *)pctx; 203 unsigned int toCopy = ctx->hash->length; 204 if (toCopy > maxLength) { 205 toCopy = maxLength; 206 } 207 memcpy(out, ctx->mac, toCopy); 208 if (outLength) { 209 *outLength = toCopy; 210 } 211 } 212 213 void 214 sftk_MACConstantTime_DestroyContext(void *pctx, PRBool free) 215 { 216 PORT_ZFree(pctx, sizeof(sftk_MACConstantTimeCtx)); 217 } 218 219 CK_RV 220 sftk_MAC_Create(CK_MECHANISM_TYPE mech, SFTKObject *key, sftk_MACCtx **ret_ctx) 221 { 222 CK_RV ret; 223 224 if (ret_ctx == NULL || key == NULL) { 225 return CKR_HOST_MEMORY; 226 } 227 228 *ret_ctx = PORT_New(sftk_MACCtx); 229 if (*ret_ctx == NULL) { 230 return CKR_HOST_MEMORY; 231 } 232 233 ret = sftk_MAC_Init(*ret_ctx, mech, key); 234 if (ret != CKR_OK) { 235 sftk_MAC_DestroyContext(*ret_ctx, PR_TRUE); 236 } 237 238 return ret; 239 } 240 241 CK_RV 242 sftk_MAC_Init(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, SFTKObject *key) 243 { 244 SFTKAttribute *keyval = NULL; 245 PRBool isFIPS = sftk_isFIPS(key->slot->slotID); 246 CK_RV ret = CKR_OK; 247 248 /* Find the actual value of the key. */ 249 keyval = sftk_FindAttribute(key, CKA_VALUE); 250 if (keyval == NULL) { 251 ret = CKR_KEY_SIZE_RANGE; 252 goto done; 253 } 254 255 ret = sftk_MAC_InitRaw(ctx, mech, 256 (const unsigned char *)keyval->attrib.pValue, 257 keyval->attrib.ulValueLen, isFIPS); 258 259 done: 260 if (keyval) { 261 sftk_FreeAttribute(keyval); 262 } 263 return ret; 264 } 265 266 CK_RV 267 sftk_MAC_InitRaw(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, const unsigned char *key, unsigned int key_len, PRBool isFIPS) 268 { 269 const SECHashObject *hashObj = NULL; 270 CK_RV ret = CKR_OK; 271 272 if (ctx == NULL) { 273 return CKR_HOST_MEMORY; 274 } 275 276 /* Clear the context before use. */ 277 PORT_Memset(ctx, 0, sizeof(*ctx)); 278 279 /* Save the mech. */ 280 ctx->mech = mech; 281 282 /* Initialize the correct MAC context. */ 283 switch (mech) { 284 case CKM_MD2_HMAC: 285 case CKM_MD5_HMAC: 286 case CKM_SHA_1_HMAC: 287 case CKM_SHA224_HMAC: 288 case CKM_SHA256_HMAC: 289 case CKM_SHA384_HMAC: 290 case CKM_SHA512_HMAC: 291 case CKM_SHA3_224_HMAC: 292 case CKM_SHA3_256_HMAC: 293 case CKM_SHA3_384_HMAC: 294 case CKM_SHA3_512_HMAC: 295 hashObj = HASH_GetRawHashObject(sftk_HMACMechanismToHash(mech)); 296 297 /* Because we condition above only on hashes we know to be valid, 298 * hashObj should never be NULL. This assert is only useful when 299 * adding a new hash function (for which only partial support has 300 * been added); thus there is no need to turn it into an if and 301 * avoid the NULL dereference on the following line. */ 302 PR_ASSERT(hashObj != NULL); 303 ctx->mac_size = hashObj->length; 304 305 goto hmac; 306 case CKM_AES_CMAC: 307 ctx->mac.cmac = CMAC_Create(CMAC_AES, key, key_len); 308 ctx->destroy_func = SFTKMAC_CMAC_Destroy; 309 310 /* Copy the behavior of sftk_doCMACInit here. */ 311 if (ctx->mac.cmac == NULL) { 312 if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) { 313 ret = CKR_KEY_SIZE_RANGE; 314 goto done; 315 } 316 317 ret = CKR_HOST_MEMORY; 318 goto done; 319 } 320 321 ctx->mac_size = AES_BLOCK_SIZE; 322 323 goto done; 324 default: 325 ret = CKR_MECHANISM_PARAM_INVALID; 326 goto done; 327 } 328 329 hmac: 330 ctx->mac.hmac = HMAC_Create(hashObj, key, key_len, isFIPS); 331 ctx->destroy_func = SFTKMAC_HMAC_Destroy; 332 333 /* Copy the behavior of sftk_doHMACInit here. */ 334 if (ctx->mac.hmac == NULL) { 335 if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) { 336 ret = CKR_KEY_SIZE_RANGE; 337 goto done; 338 } 339 ret = CKR_HOST_MEMORY; 340 goto done; 341 } 342 343 /* Semantics: HMAC and CMAC should behave the same. Begin HMAC now. */ 344 HMAC_Begin(ctx->mac.hmac); 345 346 done: 347 /* Handle a failure: ctx->mac.raw should be NULL, but make sure 348 * destroy_func isn't set. */ 349 if (ret != CKR_OK) { 350 ctx->destroy_func = NULL; 351 } 352 353 return ret; 354 } 355 356 CK_RV 357 sftk_MAC_Reset(sftk_MACCtx *ctx) 358 { 359 /* Useful for resetting the state of MAC prior to calling update again 360 * 361 * This lets the caller keep a single MAC instance and re-use it as long 362 * as the key stays the same. */ 363 switch (ctx->mech) { 364 case CKM_MD2_HMAC: 365 case CKM_MD5_HMAC: 366 case CKM_SHA_1_HMAC: 367 case CKM_SHA224_HMAC: 368 case CKM_SHA256_HMAC: 369 case CKM_SHA384_HMAC: 370 case CKM_SHA512_HMAC: 371 case CKM_SHA3_224_HMAC: 372 case CKM_SHA3_256_HMAC: 373 case CKM_SHA3_384_HMAC: 374 case CKM_SHA3_512_HMAC: 375 HMAC_Begin(ctx->mac.hmac); 376 break; 377 case CKM_AES_CMAC: 378 if (CMAC_Begin(ctx->mac.cmac) != SECSuccess) { 379 return CKR_FUNCTION_FAILED; 380 } 381 break; 382 default: 383 /* This shouldn't happen -- asserting indicates partial support 384 * for a new MAC type. */ 385 PR_ASSERT(PR_FALSE); 386 return CKR_FUNCTION_FAILED; 387 } 388 389 return CKR_OK; 390 } 391 392 CK_RV 393 sftk_MAC_Update(sftk_MACCtx *ctx, const CK_BYTE *data, unsigned int data_len) 394 { 395 switch (ctx->mech) { 396 case CKM_MD2_HMAC: 397 case CKM_MD5_HMAC: 398 case CKM_SHA_1_HMAC: 399 case CKM_SHA224_HMAC: 400 case CKM_SHA256_HMAC: 401 case CKM_SHA384_HMAC: 402 case CKM_SHA512_HMAC: 403 case CKM_SHA3_224_HMAC: 404 case CKM_SHA3_256_HMAC: 405 case CKM_SHA3_384_HMAC: 406 case CKM_SHA3_512_HMAC: 407 /* HMAC doesn't indicate failure in the return code. */ 408 HMAC_Update(ctx->mac.hmac, data, data_len); 409 break; 410 case CKM_AES_CMAC: 411 /* CMAC indicates failure in the return code, however this is 412 * unlikely to occur. */ 413 if (CMAC_Update(ctx->mac.cmac, data, data_len) != SECSuccess) { 414 return CKR_FUNCTION_FAILED; 415 } 416 break; 417 default: 418 /* This shouldn't happen -- asserting indicates partial support 419 * for a new MAC type. */ 420 PR_ASSERT(PR_FALSE); 421 return CKR_FUNCTION_FAILED; 422 } 423 return CKR_OK; 424 } 425 426 CK_RV 427 sftk_MAC_End(sftk_MACCtx *ctx, CK_BYTE_PTR result, unsigned int *result_len, unsigned int max_result_len) 428 { 429 unsigned int actual_result_len; 430 431 switch (ctx->mech) { 432 case CKM_MD2_HMAC: 433 case CKM_MD5_HMAC: 434 case CKM_SHA_1_HMAC: 435 case CKM_SHA224_HMAC: 436 case CKM_SHA256_HMAC: 437 case CKM_SHA384_HMAC: 438 case CKM_SHA512_HMAC: 439 case CKM_SHA3_224_HMAC: 440 case CKM_SHA3_256_HMAC: 441 case CKM_SHA3_384_HMAC: 442 case CKM_SHA3_512_HMAC: 443 /* HMAC doesn't indicate failure in the return code. Additionally, 444 * unlike CMAC, it doesn't support partial results. This means that we 445 * need to allocate a buffer if max_result_len < ctx->mac_size. */ 446 if (max_result_len >= ctx->mac_size) { 447 /* Split this into two calls to avoid an unnecessary stack 448 * allocation and memcpy when possible. */ 449 HMAC_Finish(ctx->mac.hmac, result, &actual_result_len, max_result_len); 450 } else { 451 uint8_t tmp_buffer[SFTK_MAX_MAC_LENGTH]; 452 453 /* Assumption: buffer is large enough to hold this HMAC's 454 * output. */ 455 PR_ASSERT(SFTK_MAX_MAC_LENGTH >= ctx->mac_size); 456 457 HMAC_Finish(ctx->mac.hmac, tmp_buffer, &actual_result_len, SFTK_MAX_MAC_LENGTH); 458 459 if (actual_result_len > max_result_len) { 460 /* This should always be true since: 461 * 462 * (SFTK_MAX_MAC_LENGTH >= ctx->mac_size = 463 * actual_result_len) > max_result_len, 464 * 465 * but guard this truncation just in case. */ 466 actual_result_len = max_result_len; 467 } 468 469 PORT_Memcpy(result, tmp_buffer, actual_result_len); 470 } 471 break; 472 case CKM_AES_CMAC: 473 /* CMAC indicates failure in the return code, however this is 474 * unlikely to occur. */ 475 if (CMAC_Finish(ctx->mac.cmac, result, &actual_result_len, max_result_len) != SECSuccess) { 476 return CKR_FUNCTION_FAILED; 477 } 478 break; 479 default: 480 /* This shouldn't happen -- asserting indicates partial support 481 * for a new MAC type. */ 482 PR_ASSERT(PR_FALSE); 483 return CKR_FUNCTION_FAILED; 484 } 485 486 if (result_len) { 487 /* When result length is passed, inform the caller of its value. */ 488 *result_len = actual_result_len; 489 } else if (max_result_len == ctx->mac_size) { 490 /* Validate that the amount requested was what was actually given; the 491 * caller assumes that what they passed was the output size of the 492 * underlying MAC and that they got all the bytes the asked for. */ 493 PR_ASSERT(actual_result_len == max_result_len); 494 } 495 496 return CKR_OK; 497 } 498 499 void 500 sftk_MAC_DestroyContext(sftk_MACCtx *ctx, PRBool free_it) 501 { 502 if (ctx == NULL) { 503 return; 504 } 505 506 if (ctx->mac.raw != NULL && ctx->destroy_func != NULL) { 507 ctx->destroy_func(ctx->mac.raw, PR_TRUE); 508 } 509 510 /* Clean up the struct so we don't double free accidentally. */ 511 PORT_Memset(ctx, 0, sizeof(sftk_MACCtx)); 512 513 if (free_it == PR_TRUE) { 514 PORT_Free(ctx); 515 } 516 }