/*! * This function writes the Descriptor Chain to the kernel driver. * * @brief Writes the Descriptor Chain to the kernel driver. * * @param dar A pointer to a Descriptor Chain of type sah_Head_Desc * @param uco The user context object * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t adaptor_Exec_Descriptor_Chain( sah_Head_Desc *dar, fsl_shw_uco_t *uco) { sah_Head_Desc *kernel_space_desc = NULL; fsl_shw_return_t code = FSL_RETURN_OK_S; int os_error_code = 0; unsigned blocking_mode = dar->uco_flags & FSL_UCO_BLOCKING_MODE; #ifdef DIAG_ADAPTOR km_Dump_Chain(&dar->desc); #endif dar->user_info = uco; dar->user_desc = dar; /* This code has been shamelessly copied from sah_driver_interface.c */ /* It needs to be moved somewhere common ... */ kernel_space_desc = sah_Physicalise_Descriptors(dar); if ( kernel_space_desc == NULL ) { /* We may have failed due to a -EFAULT as well, but we will return * -ENOMEM since either way it is a memory related failure. */ code = FSL_RETURN_NO_RESOURCE_S; #ifdef DIAG_DRV_IF LOG_KDIAG("sah_Physicalise_Descriptors() failed\n"); #endif } else { if (blocking_mode) { #ifdef SAHARA_POLL_MODE os_error_code = sah_Handle_Poll(dar); #else os_error_code = sah_blocking_mode(dar); #endif if (os_error_code != 0) { code = FSL_RETURN_ERROR_S; } else { /* status of actual operation */ code = dar->result; } /* free this chain */ if (!(uco->flags & FSL_UCO_SAVE_DESC_CHAIN)) { sah_Descriptor_Chain_Destroy(uco->mem_util, &dar); } } else { #ifdef SAHARA_POLL_MODE sah_Handle_Poll(dar); #else /* just put someting in the DAR */ sah_Queue_Manager_Append_Entry(dar); #endif /* SAHARA_POLL_MODE */ } } return code; }
/*! * Perform any post-processing on non-blocking results. * * For instance, free descriptor chains, compare authentication codes, ... * * @param user_ctx User context object * @param result_info A set of results */ void sah_Postprocess_Results(fsl_shw_uco_t * user_ctx, sah_results * result_info) { unsigned i; /* for each result returned */ for (i = 0; i < *result_info->actual; i++) { sah_Head_Desc *desc = result_info->results[i].user_desc; uint8_t *out1 = desc->out1_ptr; uint8_t *out2 = desc->out2_ptr; uint32_t len = desc->out_len; /* * For now, tne only post-processing besides freeing the * chain is the need to check the auth code for fsl_shw_auth_decrypt(). * * If other uses are required in the future, this code will probably * need a flag in the sah_Head_Desc (or a function pointer!) to * determine what needs to be done. */ if ((out1 != NULL) && (out2 != NULL)) { unsigned j; for (j = 0; j < len; j++) { if (out1[j] != out2[j]) { /* Problem detected. Change result. */ result_info->results[i].code = FSL_RETURN_AUTH_FAILED_S; break; } } /* free allocated 'calced_auth' */ user_ctx->mem_util-> mu_free(user_ctx->mem_util->mu_ref, out1); } /* Free the API-created chain, unless tagged as not-from-API */ if (!(desc->uco_flags & FSL_UCO_SAVE_DESC_CHAIN)) { sah_Descriptor_Chain_Destroy(user_ctx->mem_util, &desc); } } }
/*! * 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; }