/* * Insert descriptors to calculate ICV = HMAC(key=T, data=LEN|ALG|KEY') * * @param user_ctx User's context for this operation * @param desc_chain Descriptor chain to append to * @param t_key_info T's key object * @param black_key Beginning of Black Key region * @param key_length Number of bytes of key' there are in @c black_key * @param[out] hmac Location to store ICV. Will be tagged "USES" so * sf routines will not try to free it. * * @return A return code of type #fsl_shw_return_t. */ static inline fsl_shw_return_t create_icv_calc(fsl_shw_uco_t * user_ctx, sah_Head_Desc ** desc_chain, fsl_shw_sko_t * t_key_info, const uint8_t * black_key, uint32_t key_length, uint8_t * hmac) { fsl_shw_return_t sah_code; uint32_t header; /* Load up T as key for the HMAC */ header = (SAH_HDR_MDHA_SET_MODE_MD_KEY /* #6 */ ^ insert_mdha_algorithm_sha1 ^ insert_mdha_init ^ insert_mdha_hmac ^ insert_mdha_pdata ^ insert_mdha_mac_full); sah_code = add_in_key_desc(header, NULL, 0, t_key_info, /* Reference T in RED */ user_ctx->mem_util, desc_chain); /* Previous step loaded key; Now set up to hash the data */ if (sah_code == FSL_RETURN_OK_S) { sah_Link *link1 = NULL; sah_Link *link2 = NULL; header = SAH_HDR_MDHA_HASH; /* #10 */ /* Input - start with ownerid */ sah_code = sah_Create_Link(user_ctx->mem_util, &link1, (void *)&t_key_info->userid, sizeof(t_key_info->userid), SAH_USES_LINK_DATA); if (sah_code == FSL_RETURN_OK_S) { /* Still input - Append black-key fields len, alg, key' */ sah_code = sah_Append_Link(user_ctx->mem_util, link1, (void *)black_key + LENGTH_OFFSET, (LENGTH_LENGTH + ALGORITHM_LENGTH + key_length), SAH_USES_LINK_DATA); if (sah_code != FSL_RETURN_OK_S) { link1 = NULL; } else { /* Output - computed ICV/HMAC */ sah_code = sah_Create_Link(user_ctx->mem_util, &link2, hmac, ICV_LENGTH, SAH_USES_LINK_DATA | SAH_OUTPUT_LINK); } sah_code = sah_Append_Desc(user_ctx->mem_util, desc_chain, header, link1, link2); } } return sah_code; } /* create_icv_calc */
/*! * 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 */
/*! * Add a Descriptor which will process with CBC the NIST preamble data * * @param desc_chain Current chain * @param user_ctx User's context * @param auth_ctx Inf * @param auth_data Additional auth data for this call * @param auth_data_length Length in bytes of @a auth_data * * @return A return code of type #fsl_shw_return_t. */ static inline fsl_shw_return_t add_assoc_preamble(sah_Head_Desc ** desc_chain, fsl_shw_uco_t * user_ctx, fsl_shw_acco_t * auth_ctx, const uint8_t * auth_data, uint32_t auth_data_length) { uint8_t *temp_buf; sah_Link *link1 = NULL; sah_Link *link2 = NULL; fsl_shw_return_t status = FSL_RETURN_OK_S; uint32_t cbc_data_length = 0; /* Assume AES */ uint32_t header = SAH_HDR_SKHA_ENC_DEC; /* Grab a block big enough for multiple uses so that only one allocate * request needs to be made. */ temp_buf = user_ctx->mem_util->mu_malloc(user_ctx->mem_util->mu_ref, 3 * auth_ctx->auth_info.CCM_ctx_info. block_size_bytes); if (temp_buf == NULL) { status = FSL_RETURN_NO_RESOURCE_S; } else { uint32_t temp_buf_flag; if (auth_ctx->flags & FSL_ACCO_NIST_CCM) { status = process_assoc_from_nist_params(&link1, &cbc_data_length, user_ctx, auth_ctx, auth_data, auth_data_length, &temp_buf); /* temp_buf has been referenced (and incremented). Only 'own' it * once, at its first value. Since the nist routine called above * bumps it... */ temp_buf_flag = SAH_USES_LINK_DATA; } else { /* if NIST */ if (status == FSL_RETURN_OK_S) { status = sah_Create_Link(user_ctx->mem_util, &link1, (uint8_t *) auth_data, auth_data_length, SAH_USES_LINK_DATA); /* for next/first use of temp_buf */ temp_buf_flag = SAH_OWNS_LINK_DATA; } cbc_data_length = auth_data_length; } /* else not NIST */ /* * Auth data links have been created. Now create link for the * useless output of the CBC calculation. */ if (status == FSL_RETURN_OK_S) { status = sah_Create_Link(user_ctx->mem_util, &link2, temp_buf, auth_ctx->auth_info. CCM_ctx_info.block_size_bytes, temp_buf_flag | SAH_OUTPUT_LINK); } temp_buf += auth_ctx->auth_info.CCM_ctx_info.block_size_bytes; cbc_data_length -= auth_ctx->auth_info.CCM_ctx_info.block_size_bytes; if (cbc_data_length != 0) { while ((status == FSL_RETURN_OK_S) && (cbc_data_length != 0)) { uint32_t linklen = (cbc_data_length > CBC_BUF_LEN) ? CBC_BUF_LEN : cbc_data_length; status = sah_Append_Link(user_ctx->mem_util, link2, cbc_buffer, linklen, SAH_USES_LINK_DATA | SAH_OUTPUT_LINK); cbc_data_length -= linklen; } } if (status != FSL_RETURN_OK_S) { if (link1 != NULL) { sah_Destroy_Link(user_ctx->mem_util, link1); } if (link2 != NULL) { sah_Destroy_Link(user_ctx->mem_util, link2); } } else { /* Header to set up crank through auth data */ status = sah_Append_Desc(user_ctx->mem_util, desc_chain, header, link1, link2); } } return status; }
/*! * Append a descriptor chain which will compute CBC over the * formatted associated data blocks. * * @param[in,out] link1 Where to append the new link * @param[in,out] data_len Location of current/updated auth-only data length * @param user_ctx Info for acquiring memory * @param auth_ctx Location of block0 value * @param auth_data Unformatted associated data * @param auth_data_length Length in octets of @a auth_data * @param[in,out] temp_buf Location of in-process data. * * @return A return code of type #fsl_shw_return_t. */ static inline fsl_shw_return_t process_assoc_from_nist_params(sah_Link ** link1, uint32_t * data_len, fsl_shw_uco_t * user_ctx, fsl_shw_acco_t * auth_ctx, const uint8_t * auth_data, uint32_t auth_data_length, uint8_t ** temp_buf) { fsl_shw_return_t status; uint32_t auth_size_length = COMPUTE_NIST_AUTH_LEN_SIZE(auth_data_length); uint32_t auth_pad_length = auth_ctx->auth_info.CCM_ctx_info.block_size_bytes - (auth_data_length + auth_size_length) % auth_ctx->auth_info.CCM_ctx_info.block_size_bytes; if (auth_pad_length == auth_ctx->auth_info.CCM_ctx_info.block_size_bytes) { auth_pad_length = 0; } /* Put in Block0 */ status = sah_Create_Link(user_ctx->mem_util, link1, auth_ctx->auth_info.CCM_ctx_info.context, auth_ctx->auth_info.CCM_ctx_info. block_size_bytes, SAH_USES_LINK_DATA); if (status == FSL_RETURN_OK_S) { /* Add on length preamble to auth data */ STORE_NIST_AUTH_LEN(auth_data_length, *temp_buf); status = sah_Append_Link(user_ctx->mem_util, *link1, *temp_buf, auth_size_length, SAH_OWNS_LINK_DATA); *temp_buf += auth_size_length; /* 2, 6, or 10 bytes */ } if (status == FSL_RETURN_OK_S) { /* Add in auth data */ status = sah_Append_Link(user_ctx->mem_util, *link1, (uint8_t *) auth_data, auth_data_length, SAH_USES_LINK_DATA); } if ((status == FSL_RETURN_OK_S) && (auth_pad_length > 0)) { status = sah_Append_Link(user_ctx->mem_util, *link1, block_zeros, auth_pad_length, SAH_USES_LINK_DATA); } *data_len = auth_ctx->auth_info.CCM_ctx_info.block_size_bytes + auth_data_length + auth_size_length + auth_pad_length; return status; }
/*! * 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) { SAH_SF_DCLS; 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 */ unsigned original_key_length = key_info->key_length; unsigned rounded_key_length; sah_Link *link1; sah_Link *link2; 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; if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_alloc(user_ctx, T_LENGTH, key_info->userid, &T_key_info.handle); } else { /* Key goes in user keystore */ ret = keystore_slot_alloc(key_info->keystore, T_LENGTH, key_info->userid, &T_key_info.handle); } if (ret != FSL_RETURN_OK_S) { goto out; } if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_alloc(user_ctx, KEK_LENGTH, key_info->userid, &KEK_key_info.handle); } else { /* Key goes in user keystore */ ret = keystore_slot_alloc(key_info->keystore, 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 if (key_info->keystore == NULL) { /* Key goes in system keystore */ (void)do_system_keystore_slot_dealloc(user_ctx, key_info->userid, T_key_info.handle); } else { /* Key goes in user keystore */ (void)keystore_slot_dealloc(key_info->keystore, key_info->userid, T_key_info.handle); } } else { slots_allocated = 1; } /* Set up to compute everything except T' ... */ #ifndef DO_REPEATABLE_WRAP /* Compute T = RND() */ header = SAH_HDR_RNG_GENERATE; /* Desc. #18 */ DESC_KEY_OUT(header, &T_key_info, 0, NULL); #else if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_load(user_ctx, T_key_info.userid, T_key_info.handle, T_block, T_key_info.key_length); } else { /* Key goes in user keystore */ ret = keystore_slot_load(key_info->keystore, T_key_info.userid, T_key_info.handle, T_block, T_key_info.key_length); } if (ret != FSL_RETURN_OK_S) { goto out; } #endif /* Compute KEK = SHA256(T | Ownerid) */ header = (SAH_HDR_MDHA_SET_MODE_HASH /* #8 */ ^ sah_insert_mdha_init ^ sah_insert_mdha_algorithm[FSL_HASH_ALG_SHA256] ^ sah_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) { goto out; } /* 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) { goto out; } /* Output - KEK goes into RED slot */ ret = sah_Create_Key_Link(user_ctx->mem_util, &link2, &KEK_key_info); if (ret != FSL_RETURN_OK_S) { goto out; } /* Put the Hash calculation into the chain. */ ret = sah_Append_Desc(user_ctx->mem_util, &desc_chain, header, link1, link2); if (ret != FSL_RETURN_OK_S) { goto out; } #if defined(NEED_CTR_WORKAROUND) rounded_key_length = ROUND_LENGTH(original_key_length); key_info->key_length = rounded_key_length; #else rounded_key_length = original_key_length; #endif /* Compute KEY' = AES-encrypt(KEK, KEY) */ header = (SAH_HDR_SKHA_SET_MODE_IV_KEY /* #1 */ ^ sah_insert_skha_mode[FSL_SYM_MODE_CTR] ^ sah_insert_skha_algorithm[FSL_KEY_ALG_AES] ^ sah_insert_skha_modulus[FSL_CTR_MOD_128]); /* Set up KEK as key to use */ DESC_IN_KEY(header, 0, NULL, &KEK_key_info); header = SAH_HDR_SKHA_ENC_DEC; DESC_KEY_OUT(header, key_info, key_info->key_length, black_key + KEY_PRIME_OFFSET); /* Set up flags info */ black_key[FLAGS_OFFSET] = 0; if (key_info->flags & FSL_SKO_KEY_SW_KEY) { black_key[FLAGS_OFFSET] |= FLAGS_SW_KEY; } /* Compute and store ICV into Black Key */ ret = create_icv_calc(user_ctx, &desc_chain, &T_key_info, black_key, original_key_length, black_key + ICV_OFFSET); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Creation of sah_Key_Link failed due to bad key" " flag!\n"); #endif /*DIAG_SECURITY_FUNC */ goto out; } /* Now get Sahara to do the work. */ #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Encrypting key with KEK"); #endif SAH_SF_EXECUTE(); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("sah_Descriptor_Chain_Execute() failed"); #endif goto out; } /* Compute T' = SLID_encrypt(T); Result goes to Black Key */ if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_encrypt(user_ctx, T_key_info.userid, T_key_info.handle, T_LENGTH, black_key + T_PRIME_OFFSET); } else { /* Key goes in user keystore */ ret = keystore_slot_encrypt(user_ctx, key_info->keystore, T_key_info.userid, T_key_info.handle, T_LENGTH, black_key + T_PRIME_OFFSET); } if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("do_scc_slot_encrypt() failed"); #endif goto out; } out: key_info->key_length = original_key_length; SAH_SF_DESC_CLEAN(); if (slots_allocated) { if (key_info->keystore == NULL) { /* Key goes in system keystore */ (void)do_system_keystore_slot_dealloc(user_ctx, key_info->userid, T_key_info. handle); (void)do_system_keystore_slot_dealloc(user_ctx, key_info->userid, KEK_key_info. handle); } else { /* Key goes in user keystore */ (void)keystore_slot_dealloc(key_info->keystore, key_info->userid, T_key_info.handle); (void)keystore_slot_dealloc(key_info->keystore, 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) { SAH_SF_DCLS; uint8_t *hmac = NULL; fsl_shw_sko_t t_key_info; sah_Link *link1 = NULL; sah_Link *link2 = NULL; unsigned i; unsigned rounded_key_length; unsigned original_key_length = key_info->key_length; hmac = DESC_TEMP_ALLOC(ICV_LENGTH); /* 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; t_key_info.keystore = key_info->keystore; /* Validate SW flags to prevent misuse */ if ((key_info->flags & FSL_SKO_KEY_SW_KEY) && !(black_key[FLAGS_OFFSET] & FLAGS_SW_KEY)) { ret = FSL_RETURN_BAD_FLAG_S; goto out; } /* Compute T = SLID_decrypt(T'); leave in RED slot */ if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_decrypt(user_ctx, key_info->userid, t_key_info.handle, T_LENGTH, black_key + T_PRIME_OFFSET); } else { /* Key goes in user keystore */ ret = keystore_slot_decrypt(user_ctx, key_info->keystore, key_info->userid, t_key_info.handle, T_LENGTH, black_key + T_PRIME_OFFSET); } if (ret != FSL_RETURN_OK_S) { goto out; } /* Compute ICV = HMAC(T, ownerid | len | alg | key' */ ret = create_icv_calc(user_ctx, &desc_chain, &t_key_info, black_key, original_key_length, hmac); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Creation of sah_Key_Link failed due to bad key" " flag!\n"); #endif /*DIAG_SECURITY_FUNC */ goto out; } #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Validating MAC of wrapped key"); #endif SAH_SF_EXECUTE(); if (ret != FSL_RETURN_OK_S) { goto out; } SAH_SF_DESC_CLEAN(); /* Check computed ICV against value in Black Key */ for (i = 0; i < ICV_LENGTH; i++) { if (black_key[ICV_OFFSET + i] != hmac[i]) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG_ARGS("computed ICV fails at offset %i\n", i); { char buff[300]; int a; for (a = 0; a < ICV_LENGTH; a++) sprintf(&(buff[a * 2]), "%02x", black_key[ICV_OFFSET + a]); buff[a * 2 + 1] = 0; LOG_DIAG_ARGS("black key: %s", buff); for (a = 0; a < ICV_LENGTH; a++) sprintf(&(buff[a * 2]), "%02x", hmac[a]); buff[a * 2 + 1] = 0; LOG_DIAG_ARGS("hmac: %s", buff); } #endif ret = FSL_RETURN_AUTH_FAILED_S; goto out; } } /* This is no longer needed. */ DESC_TEMP_FREE(hmac); /* Compute KEK = SHA256(T | ownerid). Rewrite slot with value */ header = (SAH_HDR_MDHA_SET_MODE_HASH /* #8 */ ^ sah_insert_mdha_init ^ sah_insert_mdha_algorithm_sha256 ^ sah_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) { goto out; } /* 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) { goto out; } /* 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) { goto out; } /* Put the Hash calculation into the chain. */ ret = sah_Append_Desc(user_ctx->mem_util, &desc_chain, header, link1, link2); if (ret != FSL_RETURN_OK_S) { goto out; } /* Compute KEY = AES-decrypt(KEK, KEY') */ header = (SAH_HDR_SKHA_SET_MODE_IV_KEY /* #1 */ ^ sah_insert_skha_mode_ctr ^ sah_insert_skha_algorithm_aes ^ sah_insert_skha_modulus_128); /* Load KEK in as the key to use */ DESC_IN_KEY(header, 0, NULL, &t_key_info); rounded_key_length = ROUND_LENGTH(original_key_length); key_info->key_length = rounded_key_length; /* Now set up for computation. Result in RED */ header = SAH_HDR_SKHA_ENC_DEC; /* #4 */ DESC_IN_KEY(header, rounded_key_length, black_key + KEY_PRIME_OFFSET, key_info); /* Perform the operation */ #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Decrypting key with KEK"); #endif SAH_SF_EXECUTE(); out: key_info->key_length = original_key_length; SAH_SF_DESC_CLEAN(); DESC_TEMP_FREE(hmac); /* 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) { SAH_SF_DCLS; uint8_t *sink = NULL; sah_Link *link1 = NULL; sah_Link *link2 = NULL; sah_Oct_Str ptr1; uint32_t size1 = sym_ctx->block_size_bytes; SAH_SF_USER_CHECK(); /* 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 ^ sah_insert_skha_algorithm_arc4; DESC_IN_KEY(header, 0, NULL, key_info); } else { /* load SBox */ /* Desc. #33 w/ARC4 and NO PERMUTE */ header = SAH_HDR_ARC4_SET_MODE_SBOX ^ sah_insert_skha_no_permute ^ sah_insert_skha_algorithm_arc4; DESC_IN_IN(header, 256, sym_ctx->context, 3, sym_ctx->context + 256); } /* load SBox */ /* Add in-out data descriptor to process the data */ if (length != 0) { DESC_IN_OUT(SAH_HDR_SKHA_ENC_DEC, length, in, length, out); } /* 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; DESC_OUT_OUT(header, 256, sym_ctx->context, 3, sym_ctx->context + 256); } } else { /* not ARC4 */ /* Doing 1- or 2- descriptor chain. */ /* Desc. #1 and algorithm and mode */ header = SAH_HDR_SKHA_SET_MODE_IV_KEY ^ sah_insert_skha_mode[sym_ctx->mode] ^ sah_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 ^= sah_insert_skha_no_key_parity; } /* Header by default is decrypting, so... */ if (encrypt == SYM_ENCRYPT) { header ^= sah_insert_skha_encrypt; } if (sym_ctx->mode == FSL_SYM_MODE_CTR) { header ^= sah_insert_skha_modulus[sym_ctx->modulus_exp]; } if (sym_ctx->mode == FSL_SYM_MODE_ECB) { ptr1 = NULL; size1 = 0; } else if (sym_ctx->flags & FSL_SYM_CTX_INIT) { ptr1 = (uint8_t *) block_zeros; } else { ptr1 = sym_ctx->context; } DESC_IN_KEY(header, sym_ctx->block_size_bytes, ptr1, key_info); /* Add in-out data descriptor */ if (length != 0) { header = SAH_HDR_SKHA_ENC_DEC; if (LENGTH_PATCH && (sym_ctx->mode == FSL_SYM_MODE_CTR) && ((length & LENGTH_PATCH_MASK) != 0)) { sink = DESC_TEMP_ALLOC(LENGTH_PATCH); ret = sah_Create_Link(user_ctx->mem_util, &link1, (uint8_t *) in, length, SAH_USES_LINK_DATA); ret = sah_Append_Link(user_ctx->mem_util, link1, (uint8_t *) sink, LENGTH_PATCH - (length & LENGTH_PATCH_MASK), SAH_USES_LINK_DATA); if (ret != FSL_RETURN_OK_S) { goto out; } ret = sah_Create_Link(user_ctx->mem_util, &link2, out, length, SAH_USES_LINK_DATA | SAH_OUTPUT_LINK); if (ret != FSL_RETURN_OK_S) { goto out; } ret = sah_Append_Link(user_ctx->mem_util, link2, sink, LENGTH_PATCH - (length & LENGTH_PATCH_MASK), SAH_USES_LINK_DATA); if (ret != FSL_RETURN_OK_S) { goto out; } ret = sah_Append_Desc(user_ctx->mem_util, &desc_chain, header, link1, link2); if (ret != FSL_RETURN_OK_S) { goto out; } link1 = link2 = NULL; } else { DESC_IN_OUT(header, length, in, length, out); } } /* Unload any desired context */ if (sym_ctx->flags & FSL_SYM_CTX_SAVE) { DESC_OUT_OUT(SAH_HDR_SKHA_READ_CONTEXT_IV, 0, NULL, sym_ctx->block_size_bytes, sym_ctx->context); } } /* not ARC4 */ SAH_SF_EXECUTE(); out: SAH_SF_DESC_CLEAN(); DESC_TEMP_FREE(sink); if (LENGTH_PATCH) { sah_Destroy_Link(user_ctx->mem_util, link1); sah_Destroy_Link(user_ctx->mem_util, link2); } return ret; }