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