/*! * 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 */
/*! * 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 */