/*! * Place a key into a protected location for use only by cryptographic * algorithms. * * This only needs to be used to a) unwrap a key, or b) set up a key which * could be wrapped with a later call to #fsl_shw_extract_key(). Normal * cleartext keys can simply be placed into #fsl_shw_sko_t key objects with * #fsl_shw_sko_set_key() and used directly. * * The maximum key size supported for wrapped/unwrapped keys is 32 octets. * (This is the maximum reasonable key length on Sahara - 32 octets for an HMAC * key based on SHA-256.) The key size is determined by the @a key_info. The * expected length of @a key can be determined by * #fsl_shw_sko_calculate_wrapped_size() * * The protected key will not be available for use until this operation * successfully completes. * * This feature is not available for all platforms, nor for all algorithms and * modes. * * @param user_ctx A user context from #fsl_shw_register_user(). * @param[in,out] key_info The information about the key to be which will * be established. In the create case, the key * length must be set. * @param establish_type How @a key will be interpreted to establish a * key for use. * @param key If @a establish_type is #FSL_KEY_WRAP_UNWRAP, * this is the location of a wrapped key. If * @a establish_type is #FSL_KEY_WRAP_CREATE, this * parameter can be @a NULL. If @a establish_type * is #FSL_KEY_WRAP_ACCEPT, this is the location * of a plaintext key. * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_establish_key(fsl_shw_uco_t * user_ctx, fsl_shw_sko_t * key_info, fsl_shw_key_wrap_t establish_type, const uint8_t * key) { fsl_shw_return_t ret; sah_Head_Desc *desc_chain = NULL; uint32_t header = SAH_HDR_RNG_GENERATE; /* Desc. #18 for rand */ unsigned original_key_length = key_info->key_length; unsigned rounded_key_length; /* Write operations into SCC memory require word-multiple number of * bytes. For ACCEPT and CREATE functions, the key length may need * to be rounded up. Calculate. */ if ((original_key_length & 3) != 0) { rounded_key_length = original_key_length + 4 - (original_key_length & 3); } else { rounded_key_length = original_key_length; } /* perform sanity check on the uco */ ret = sah_validate_uco(user_ctx); if (ret != FSL_RETURN_OK_S) { return ret; } ret = do_scc_slot_alloc(user_ctx, key_info->key_length, key_info->userid, &key_info->handle); if (ret == FSL_RETURN_OK_S) { key_info->flags |= FSL_SKO_KEY_ESTABLISHED; switch (establish_type) { case FSL_KEY_WRAP_CREATE: /* Use safe version of key length */ key_info->key_length = rounded_key_length; /* Generate descriptor to put random value into */ ret = add_key_out_desc(header, key_info, NULL, 0, user_ctx->mem_util, &desc_chain); /* Restore actual, desired key length */ key_info->key_length = original_key_length; if (ret == FSL_RETURN_OK_S) { uint32_t old_flags = user_ctx->flags; /* Now put random value into key */ ret = sah_Descriptor_Chain_Execute(desc_chain, user_ctx); /* Restore user's old flag value */ user_ctx->flags = old_flags; } #ifdef DIAG_SECURITY_FUNC else { LOG_DIAG ("Creation of sah_Key_Link failed due to bad" " key flag!\n"); } #endif /*DIAG_SECURITY_FUNC */ break; case FSL_KEY_WRAP_ACCEPT: if (key == NULL) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("ACCEPT: Red Key is NULL"); #endif ret = FSL_RETURN_ERROR_S; } else { /* Copy in safe number of bytes of Red key */ ret = do_scc_slot_load_slot(user_ctx, key_info->userid, key_info->handle, key, rounded_key_length); } break; case FSL_KEY_WRAP_UNWRAP: /* For now, disallow non-blocking calls. */ if (!(user_ctx->flags & FSL_UCO_BLOCKING_MODE)) { ret = FSL_RETURN_BAD_FLAG_S; } else if (key == NULL) { ret = FSL_RETURN_ERROR_S; } else { ret = unwrap(user_ctx, key_info, key); if (ret != FSL_RETURN_OK_S) { } } break; default: ret = FSL_RETURN_BAD_FLAG_S; break; } /* switch */ if (ret != FSL_RETURN_OK_S) { fsl_shw_return_t scc_err; scc_err = do_scc_slot_dealloc(user_ctx, key_info->userid, key_info->handle); key_info->flags &= ~FSL_SKO_KEY_ESTABLISHED; } } return ret; }
/*! * Perform wrapping of a black key from a RED slot * * @param user_ctx A user context from #fsl_shw_register_user(). * @param[in,out] key_info The information about the key to be which will * be wrapped... key length, slot info, etc. * @param black_key Place to store encrypted key * * @return A return code of type #fsl_shw_return_t. */ static fsl_shw_return_t wrap(fsl_shw_uco_t * user_ctx, fsl_shw_sko_t * key_info, uint8_t * black_key) { fsl_shw_return_t ret; sah_Head_Desc *desc_chain = NULL; unsigned slots_allocated = 0; /* boolean */ fsl_shw_sko_t T_key_info; /* for holding T */ fsl_shw_sko_t KEK_key_info; /* for holding KEK */ black_key[LENGTH_OFFSET] = key_info->key_length; black_key[ALGORITHM_OFFSET] = key_info->algorithm; memcpy(&T_key_info, key_info, sizeof(T_key_info)); fsl_shw_sko_set_key_length(&T_key_info, T_LENGTH); T_key_info.algorithm = FSL_KEY_ALG_HMAC; memcpy(&KEK_key_info, &T_key_info, sizeof(KEK_key_info)); KEK_key_info.algorithm = FSL_KEY_ALG_AES; ret = do_scc_slot_alloc(user_ctx, T_LENGTH, key_info->userid, &T_key_info.handle); if (ret == FSL_RETURN_OK_S) { ret = do_scc_slot_alloc(user_ctx, KEK_LENGTH, key_info->userid, &KEK_key_info.handle); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("do_scc_slot_alloc() failed"); #endif do_scc_slot_dealloc(user_ctx, key_info->userid, T_key_info.handle); } else { slots_allocated = 1; } } /* Set up to compute everything except T' ... */ if (ret == FSL_RETURN_OK_S) { uint32_t header; #ifndef DO_REPEATABLE_WRAP /* Compute T = RND() */ header = SAH_HDR_RNG_GENERATE; /* Desc. #18 */ ret = add_key_out_desc(header, &T_key_info, NULL, 0, user_ctx->mem_util, &desc_chain); #else ret = do_scc_slot_load_slot(user_ctx, T_key_info.userid, T_key_info.handle, T_block, T_key_info.key_length); #endif /* Compute KEK = SHA1(T | Ownerid) */ if (ret == FSL_RETURN_OK_S) { sah_Link *link1; sah_Link *link2; header = (SAH_HDR_MDHA_SET_MODE_HASH /* #8 */ ^ insert_mdha_init ^ insert_mdha_algorithm[FSL_HASH_ALG_SHA1] ^ insert_mdha_pdata); /* Input - Start with T */ ret = sah_Create_Key_Link(user_ctx->mem_util, &link1, &T_key_info); if (ret == FSL_RETURN_OK_S) { /* Still input - append ownerid */ ret = sah_Append_Link(user_ctx->mem_util, link1, (void *)&key_info->userid, sizeof(key_info->userid), SAH_USES_LINK_DATA); } if (ret == FSL_RETURN_OK_S) { /* Output - KEK goes into RED slot */ ret = sah_Create_Key_Link(user_ctx->mem_util, &link2, &KEK_key_info); } /* Put the Hash calculation into the chain. */ if (ret == FSL_RETURN_OK_S) { ret = sah_Append_Desc(user_ctx->mem_util, &desc_chain, header, link1, link2); } } /* Compute KEY' = AES-encrypt(KEK, KEY) */ if (ret == FSL_RETURN_OK_S) { header = (SAH_HDR_SKHA_SET_MODE_IV_KEY /* #1 */ ^ insert_skha_mode[FSL_SYM_MODE_CTR] ^ insert_skha_algorithm[FSL_KEY_ALG_AES] ^ insert_skha_modulus[FSL_CTR_MOD_128]); /* Set up KEK as key to use */ ret = add_in_key_desc(header, NULL, 0, &KEK_key_info, user_ctx->mem_util, &desc_chain); /* Set up KEY as input, KEY' as output */ if (ret == FSL_RETURN_OK_S) { header = SAH_HDR_SKHA_ENC_DEC; /* #4 */ ret = add_key_out_desc(header, key_info, black_key + KEY_PRIME_OFFSET, key_info->key_length, user_ctx->mem_util, &desc_chain); } #ifdef DIAG_SECURITY_FUNC if (ret != FSL_RETURN_OK_S) { LOG_DIAG ("Creation of sah_Key_Link failed due to bad key" " flag!\n"); } #endif /*DIAG_SECURITY_FUNC */ } /* Compute and store ICV into Black Key */ if (ret == FSL_RETURN_OK_S) { ret = create_icv_calc(user_ctx, &desc_chain, &T_key_info, black_key, key_info->key_length, black_key + ICV_OFFSET); #ifdef DIAG_SECURITY_FUNC if (ret != FSL_RETURN_OK_S) { LOG_DIAG ("Creation of sah_Key_Link failed due to bad key" " flag!\n"); } #endif /*DIAG_SECURITY_FUNC */ } } /* Now get Sahara to do the work. */ if (ret == FSL_RETURN_OK_S) { ret = sah_Descriptor_Chain_Execute(desc_chain, user_ctx); #ifdef DIAG_SECURITY_FUNC if (ret != FSL_RETURN_OK_S) { LOG_DIAG("sah_Descriptor_Chain_Execute() failed"); } #endif } /* Compute T' = SLID_encrypt(T); Result goes to Black Key */ if (ret == FSL_RETURN_OK_S) { ret = do_scc_slot_encrypt(user_ctx, T_key_info.userid, T_key_info.handle, T_LENGTH, black_key + T_PRIME_OFFSET); #ifdef DIAG_SECURITY_FUNC if (ret != FSL_RETURN_OK_S) { LOG_DIAG("do_scc_slot_encrypt() failed"); } #endif } if (slots_allocated) { do_scc_slot_dealloc(user_ctx, key_info->userid, T_key_info.handle); do_scc_slot_dealloc(user_ctx, key_info->userid, KEK_key_info.handle); } return ret; } /* wrap */
/*! * Perform unwrapping of a black key into a RED slot * * @param user_ctx A user context from #fsl_shw_register_user(). * @param[in,out] key_info The information about the key to be which will * be unwrapped... key length, slot info, etc. * @param black_key Encrypted key * * @return A return code of type #fsl_shw_return_t. */ static fsl_shw_return_t unwrap(fsl_shw_uco_t * user_ctx, fsl_shw_sko_t * key_info, const uint8_t * black_key) { fsl_shw_return_t ret = FSL_RETURN_ERROR_S; sah_Mem_Util *mu = user_ctx->mem_util; uint8_t *hmac = mu->mu_malloc(mu->mu_ref, ICV_LENGTH); if (hmac == NULL) { ret = FSL_RETURN_NO_RESOURCE_S; } else { sah_Head_Desc *desc_chain = NULL; fsl_shw_sko_t t_key_info; unsigned i; /* Set up key_info for "T" - use same slot as eventual key */ fsl_shw_sko_init(&t_key_info, FSL_KEY_ALG_AES); t_key_info.userid = key_info->userid; t_key_info.handle = key_info->handle; t_key_info.flags = key_info->flags; t_key_info.key_length = T_LENGTH; /* Compute T = SLID_decrypt(T'); leave in RED slot */ ret = do_scc_slot_decrypt(user_ctx, key_info->userid, t_key_info.handle, T_LENGTH, black_key + T_PRIME_OFFSET); /* Compute ICV = HMAC(T, ownerid | len | alg | key' */ if (ret == FSL_RETURN_OK_S) { ret = create_icv_calc(user_ctx, &desc_chain, &t_key_info, black_key, key_info->key_length, hmac); if (ret == FSL_RETURN_OK_S) { ret = sah_Descriptor_Chain_Execute(desc_chain, user_ctx); desc_chain = NULL; } #ifdef DIAG_SECURITY_FUNC else { LOG_DIAG ("Creation of sah_Key_Link failed due to bad key" " flag!\n"); } #endif /*DIAG_SECURITY_FUNC */ /* Check computed ICV against value in Black Key */ if (ret == FSL_RETURN_OK_S) { for (i = 0; i < ICV_LENGTH; i++) { if (black_key[ICV_OFFSET + i] != hmac[i]) { ret = FSL_RETURN_AUTH_FAILED_S; break; } } } /* This is no longer needed. */ mu->mu_free(mu->mu_ref, hmac); /* Compute KEK = SHA1(T | ownerid). Rewrite slot with value */ if (ret == FSL_RETURN_OK_S) { sah_Link *link1 = NULL; sah_Link *link2 = NULL; uint32_t header; header = (SAH_HDR_MDHA_SET_MODE_HASH /* #8 */ ^ insert_mdha_init ^ insert_mdha_algorithm_sha1 ^ insert_mdha_pdata); /* Input - Start with T */ ret = sah_Create_Key_Link(user_ctx->mem_util, &link1, &t_key_info); if (ret == FSL_RETURN_OK_S) { /* Still input - append ownerid */ ret = sah_Append_Link(user_ctx->mem_util, link1, (void *)&key_info-> userid, sizeof(key_info-> userid), SAH_USES_LINK_DATA); } if (ret == FSL_RETURN_OK_S) { /* Output - KEK goes into RED slot */ ret = sah_Create_Key_Link(user_ctx-> mem_util, &link2, &t_key_info); } if (ret == FSL_RETURN_OK_S) { /* Put the Hash calculation into the chain. */ ret = sah_Append_Desc(user_ctx->mem_util, &desc_chain, header, link1, link2); } } /* Compute KEY = AES-decrypt(KEK, KEY') */ if (ret == FSL_RETURN_OK_S) { uint32_t header; unsigned rounded_key_length; unsigned original_key_length = key_info->key_length; header = (SAH_HDR_SKHA_SET_MODE_IV_KEY /* #1 */ ^ insert_skha_mode_ctr ^ insert_skha_algorithm_aes ^ insert_skha_modulus_128); /* Load KEK in as the key to use */ ret = add_in_key_desc(header, NULL, 0, &t_key_info, user_ctx->mem_util, &desc_chain); /* Make sure that KEY = AES(KEK, KEY') step writes a multiple of words into the SCC to avoid 'Byte Access errors.' */ if ((original_key_length & 3) != 0) { rounded_key_length = original_key_length + 4 - (original_key_length & 3); } else { rounded_key_length = original_key_length; } key_info->key_length = rounded_key_length; if (ret == FSL_RETURN_OK_S) { /* Now set up for computation. Result in RED */ header = SAH_HDR_SKHA_ENC_DEC; /* #4 */ ret = add_in_key_desc(header, black_key + KEY_PRIME_OFFSET, rounded_key_length, key_info, user_ctx->mem_util, &desc_chain); key_info->key_length = original_key_length; /* Perform the operation */ if (ret == FSL_RETURN_OK_S) { ret = sah_Descriptor_Chain_Execute (desc_chain, user_ctx); } } } /* Erase tracks */ t_key_info.userid = 0xdeadbeef; t_key_info.handle = 0xdeadbeef; } } return ret; } /* unwrap */
/*! * Create and run the chain for a symmetric-key operation. * * @param user_ctx Who the user is * @param key_info What key is to be used * @param sym_ctx Info details about algorithm * @param encrypt 0 = decrypt, non-zero = encrypt * @param length Number of octets at @a in and @a out * @param in Pointer to input data * @param out Location to store output data * * @return The status of handing chain to driver, * or an earlier argument/flag or allocation * error. */ static fsl_shw_return_t do_symmetric(fsl_shw_uco_t * user_ctx, fsl_shw_sko_t * key_info, fsl_shw_scco_t * sym_ctx, cipher_direction_t encrypt, uint32_t length, const uint8_t * in, uint8_t * out) { fsl_shw_return_t status = FSL_RETURN_ERROR_S; uint32_t header; sah_Head_Desc *desc_chain = NULL; sah_Oct_Str ptr1; /* Two different sets of chains, depending on algorithm */ if (key_info->algorithm == FSL_KEY_ALG_ARC4) { if (sym_ctx->flags & FSL_SYM_CTX_INIT) { /* Desc. #35 w/ARC4 - start from key */ header = SAH_HDR_ARC4_SET_MODE_KEY ^ insert_skha_algorithm_arc4; status = add_in_key_desc(header, NULL, 0, key_info, user_ctx->mem_util, &desc_chain); } else { /* load SBox */ /* Desc. #33 w/ARC4 and NO PERMUTE */ header = SAH_HDR_ARC4_SET_MODE_SBOX ^ insert_skha_no_permute ^ insert_skha_algorithm_arc4; status = add_two_in_desc(header, sym_ctx->context, 256, sym_ctx->context + 256, 3, user_ctx->mem_util, &desc_chain); } /* load SBox */ /* Add in-out data descriptor */ if ((status == FSL_RETURN_OK_S) && (length != 0)) { status = add_in_out_desc(SAH_HDR_SKHA_ENC_DEC, in, length, out, length, user_ctx->mem_util, &desc_chain); } /* Operation is done ... save what came out? */ if (sym_ctx->flags & FSL_SYM_CTX_SAVE) { /* Desc. #34 - Read SBox, pointers */ header = SAH_HDR_ARC4_READ_SBOX; if (status == FSL_RETURN_OK_S) { status = add_two_out_desc(header, sym_ctx->context, 256, sym_ctx->context + 256, 3, user_ctx->mem_util, &desc_chain); } } } else { /* not ARC4 */ /* Doing 1- or 2- descriptor chain. */ /* Desc. #1 and algorithm and mode */ header = SAH_HDR_SKHA_SET_MODE_IV_KEY ^ insert_skha_mode[sym_ctx->mode] ^ insert_skha_algorithm[key_info->algorithm]; /* Honor 'no key parity checking' for DES and TDES */ if ((key_info->flags & FSL_SKO_KEY_IGNORE_PARITY) && ((key_info->algorithm == FSL_KEY_ALG_DES) || (key_info->algorithm == FSL_KEY_ALG_TDES))) { header ^= insert_skha_no_key_parity; } /* Header by default is decrypting, so... */ if (encrypt == SYM_ENCRYPT) { header ^= insert_skha_encrypt; } if (sym_ctx->mode == FSL_SYM_MODE_CTR) { header ^= insert_skha_modulus[sym_ctx->modulus_exp]; } if ((sym_ctx->mode == FSL_SYM_MODE_ECB) || (sym_ctx->flags & FSL_SYM_CTX_INIT)) { ptr1 = block_zeros; } else { ptr1 = sym_ctx->context; } status = add_in_key_desc(header, ptr1, sym_ctx->block_size_bytes, key_info, user_ctx->mem_util, &desc_chain); /* Add in-out data descriptor */ if ((length != 0) && (status == FSL_RETURN_OK_S)) { status = add_in_out_desc(SAH_HDR_SKHA_ENC_DEC, in, length, out, length, user_ctx->mem_util, &desc_chain); } /* Unload any desired context */ if ((sym_ctx->flags & FSL_SYM_CTX_SAVE) && (status == FSL_RETURN_OK_S)) { status = add_two_out_desc(SAH_HDR_SKHA_READ_CONTEXT_IV, NULL, 0, sym_ctx->context, sym_ctx->block_size_bytes, user_ctx->mem_util, &desc_chain); } } /* not ARC4 */ if (status != FSL_RETURN_OK_S) { /* Delete possibly-started chain */ sah_Descriptor_Chain_Destroy(user_ctx->mem_util, &desc_chain); } else { status = sah_Descriptor_Chain_Execute(desc_chain, user_ctx); } return status; }
/*! * Get the precompute information * * * @param user_ctx * @param key_info * @param hmac_ctx * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_hmac_precompute( fsl_shw_uco_t* user_ctx, fsl_shw_sko_t* key_info, fsl_shw_hmco_t* hmac_ctx) { fsl_shw_return_t status; sah_Head_Desc* desc_chain = NULL; uint32_t header; /* perform sanity check on uco */ status = sah_validate_uco(user_ctx); if (status != FSL_RETURN_OK_S) { return status; } if ((key_info->algorithm != FSL_KEY_ALG_HMAC) || (key_info->key_length > 64)) { return FSL_RETURN_BAD_ALGORITHM_S; } else if (key_info->key_length == 0) { return FSL_RETURN_BAD_KEY_LENGTH_S; } /* Set up to start the Inner Calculation */ /* Desc. #8 w/IPAD, & INIT */ header = SAH_HDR_MDHA_SET_MODE_HASH ^ insert_mdha_ipad ^ insert_mdha_init ^ insert_mdha_algorithm[hmac_ctx->algorithm]; status = add_key_out_desc(header, key_info, (uint8_t*)hmac_ctx->inner_precompute, hmac_ctx->context_register_length, user_ctx->mem_util, &desc_chain); /* Set up for starting Outer calculation */ if (status == FSL_RETURN_OK_S) { /* exchange IPAD bit for OPAD bit */ header ^= (insert_mdha_ipad ^ insert_mdha_opad); /* Theoretically, we can leave this link out and use the key which is * already in the register... however, if we do, the resulting opad * hash does not have the correct value when using the model. */ status = add_key_out_desc(header, key_info, (uint8_t*)hmac_ctx->outer_precompute, hmac_ctx->context_register_length, user_ctx->mem_util, &desc_chain); } /* Pass the chain to the driver. */ if (status == FSL_RETURN_OK_S) { status = sah_Descriptor_Chain_Execute(desc_chain, user_ctx); if (status == FSL_RETURN_OK_S) { /* flag that precomputes have been entered in this hco * assume it'll first be used for initilizing */ hmac_ctx->flags |= (FSL_HMAC_FLAGS_INIT | FSL_HMAC_FLAGS_PRECOMPUTES_PRESENT); } } else { sah_Descriptor_Chain_Destroy(user_ctx->mem_util, &desc_chain); } return status; }
/*! * Get the hmac * * * @param user_ctx Info for acquiring memory * @param key_info * @param hmac_ctx * @param msg * @param length * @param result * @param result_len * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_hmac( fsl_shw_uco_t* user_ctx, fsl_shw_sko_t* key_info, fsl_shw_hmco_t* hmac_ctx, const uint8_t* msg, uint32_t length, uint8_t* result, uint32_t result_len) { fsl_shw_return_t ret; sah_Head_Desc* desc_chain = NULL; uint32_t header; /* perform sanity check on uco */ ret = sah_validate_uco(user_ctx); /* check flag consistency */ /* Note that Final, Init, and Save are an illegal combination when a key * is being used. Because of the logic flow of this routine, that is * taken care of without being explict */ if (ret == FSL_RETURN_OK_S) { if ( /* nothing to work on */ (((hmac_ctx->flags & FSL_HMAC_FLAGS_INIT) == 0) && ((hmac_ctx->flags & FSL_HMAC_FLAGS_LOAD) == 0)) || /* can't do both */ ((hmac_ctx->flags & FSL_HMAC_FLAGS_INIT) && (hmac_ctx->flags & FSL_HMAC_FLAGS_LOAD)) || /* must be some output */ (((hmac_ctx->flags & FSL_HMAC_FLAGS_SAVE) == 0) && ((hmac_ctx->flags & FSL_HMAC_FLAGS_FINALIZE) == 0))) { ret = FSL_RETURN_BAD_FLAG_S; } } /* build descriptor #6 */ if (ret == FSL_RETURN_OK_S) { /* start building descriptor header */ header = SAH_HDR_MDHA_SET_MODE_MD_KEY ^ insert_mdha_algorithm[hmac_ctx->algorithm] ^ insert_mdha_init; /* if this is to finalize the digest, mark to pad last block */ if (hmac_ctx->flags & FSL_HMAC_FLAGS_FINALIZE) { header ^= insert_mdha_pdata; } /*** Check if this is a one shot ***/ if ((hmac_ctx->flags & FSL_HMAC_FLAGS_INIT) && (hmac_ctx->flags & FSL_HMAC_FLAGS_FINALIZE)) { header ^= insert_mdha_hmac; /*** See if this uses Precomputes ***/ if (hmac_ctx->flags & FSL_HMAC_FLAGS_PRECOMPUTES_PRESENT) { ret = add_two_in_desc(header, (uint8_t *)hmac_ctx->inner_precompute, hmac_ctx->context_register_length, (uint8_t *)hmac_ctx->outer_precompute, hmac_ctx->context_length, user_ctx->mem_util, &desc_chain); } else { /*** Precomputes not requested, try using Key ***/ if (key_info->key != NULL) { /* first, validate the key fields and related flag */ if (key_info->key_length == 0) { ret = FSL_RETURN_BAD_KEY_LENGTH_S; } else { if ((key_info->algorithm != FSL_KEY_ALG_HMAC) || (key_info->key_length > 64)) { ret = FSL_RETURN_BAD_ALGORITHM_S; } } if (ret == FSL_RETURN_OK_S) { /* finish building descriptor header (Key specific) */ header ^= insert_mdha_mac_full; ret = add_in_key_desc(header, NULL, 0, key_info, user_ctx->mem_util, &desc_chain); } } else { /*** not using Key or Precomputes, so die ***/ ret = FSL_RETURN_BAD_FLAG_S; } } } else { /*** it's not a one shot, must be multi-step ***/ /* this the last chunk? */ if (hmac_ctx->flags & FSL_HMAC_FLAGS_FINALIZE) { header ^= insert_mdha_hmac; ret = add_two_in_desc(header, (uint8_t *)hmac_ctx->ongoing_context, hmac_ctx->context_register_length, (uint8_t *)hmac_ctx->outer_precompute, hmac_ctx->context_length, user_ctx->mem_util, &desc_chain); } else { /* not last chunk */ uint8_t *ptr1; if (hmac_ctx->flags & FSL_HMAC_FLAGS_INIT) { /* must be using precomputes, cannot 'chunk' message * starting with a key */ if (hmac_ctx->flags & FSL_HMAC_FLAGS_PRECOMPUTES_PRESENT) { ptr1 = (uint8_t *)hmac_ctx->inner_precompute; } else { ret = FSL_RETURN_NO_RESOURCE_S; } } else { ptr1 = (uint8_t *)hmac_ctx->ongoing_context; } if (ret == FSL_RETURN_OK_S) { ret = add_two_in_desc(header, ptr1, hmac_ctx->context_register_length, NULL, 0, user_ctx->mem_util, &desc_chain); } } } } /* end of building descriptor #6 */ /*** build descriptor #10 & maybe 11 ***/ if (ret == FSL_RETURN_OK_S) { header = SAH_HDR_MDHA_HASH; if (hmac_ctx->flags & FSL_HMAC_FLAGS_FINALIZE) { /* check that the results parameters seem reasonable */ if ((result_len != 0) && (result != NULL)) { if (result_len > hmac_ctx->context_register_length) { result_len = hmac_ctx->context_register_length; } /* message in / digest out (descriptor #10) */ ret = add_in_out_desc(header, msg, length, result, result_len, user_ctx->mem_util, &desc_chain); /*** see if descriptor #11 needs to be built ***/ if ((hmac_ctx->flags & FSL_HMAC_FLAGS_SAVE) && (ret == FSL_RETURN_OK_S)) { header = SAH_HDR_MDHA_STORE_DIGEST; /* nothing in / context out */ ret = add_two_in_desc(header, NULL, 0, (uint8_t *)hmac_ctx->ongoing_context, hmac_ctx->context_register_length, user_ctx->mem_util, &desc_chain); } } else { /* something wrong with result or its length */ ret = FSL_RETURN_BAD_DATA_LENGTH_S; } } else { /* finalize not set, so store in ongoing context field */ if ((length % 64) == 0) { /* message in / context out */ ret = add_in_out_desc(header, msg, length, (uint8_t *)hmac_ctx->ongoing_context, hmac_ctx->context_register_length, user_ctx->mem_util, &desc_chain); } else { ret = FSL_RETURN_BAD_DATA_LENGTH_S; } } } /* Pass the chain to the driver. */ if (ret == FSL_RETURN_OK_S) { ret = sah_Descriptor_Chain_Execute(desc_chain, user_ctx); } else { if (desc_chain != NULL) { /* ignore the destroy function's return value, the destroy * function's return value is not what went wroung with this * routine */ sah_Descriptor_Chain_Destroy(user_ctx->mem_util, &desc_chain); } } return ret; }