/*! * 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 wrapping of a black key from a RED slot (or the PK register) * * @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 = FSL_RETURN_OK_S; fsl_shw_sko_t t_key_info; /* for holding T */ fsl_shw_scco_t t_key_ctx; fsl_shw_sko_t kek_key_info; fsl_shw_scco_t kek_ctx; unsigned original_key_length = key_info->key_length; unsigned rounded_key_length; uint8_t T[T_LENGTH]; uint8_t kek[KEK_LENGTH + 20]; uint8_t *red_key = 0; int red_key_malloced = 0; /* bool */ int pk_was_held = 0; /* bool */ uint8_t saved_pk[21]; uint8_t pk_needs_restoration; /* bool */ di_return_t di_code; ret = check_wrap_key(user_ctx->wrap_key); if (ret != FSL_RETURN_OK_S) { goto out; } if (black_key == NULL) { ret = FSL_RETURN_ERROR_S; goto out; } if (key_info->flags & FSL_SKO_KEY_SELECT_PF_KEY) { if ((key_info->pf_key != FSL_SHW_PF_KEY_PRG) && (key_info->pf_key != FSL_SHW_PF_KEY_IIM_PRG)) { ret = FSL_RETURN_ERROR_S; goto out; } } else { if (!(key_info->flags & FSL_SKO_KEY_ESTABLISHED)) { ret = FSL_RETURN_BAD_FLAG_S; /* not established! */ goto out; } } black_key[ALGORITHM_OFFSET] = key_info->algorithm; #ifndef DO_REPEATABLE_WRAP /* Compute T = RND() */ ret = fsl_shw_get_random(user_ctx, T_LENGTH, T); if (ret != FSL_RETURN_OK_S) { goto out; } #else memcpy(T, T_block, T_LENGTH); #endif /* Compute KEK = SHA256(T | ownerid). */ ret = calc_kek((uint8_t *) & key_info->userid, sizeof(key_info->userid), T, kek); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Calculation of KEK failed\n"); #endif /*DIAG_SECURITY_FUNC */ goto out; } rounded_key_length = ROUND_LENGTH(original_key_length); di_code = dryice_get_programmed_key(saved_pk, 8 * 21); if (di_code != DI_SUCCESS) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG_ARGS("Could not save current PK: %s\n", di_error_string(di_code)); #endif ret = FSL_RETURN_ERROR_S; goto out; } /* * Load KEK into DI PKR. Note that we are NOT permuting it before loading, * so we are using it as though it is a 168-bit key ready for the SCC. */ di_code = dryice_set_programmed_key(kek, 8 * 21, 0); if (di_code == DI_ERR_INUSE) { /* Temporarily reprogram the PK out from under the user */ pk_was_held = 1; dryice_release_programmed_key(); di_code = dryice_set_programmed_key(kek, 8 * 21, 0); } if (di_code != DI_SUCCESS) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG_ARGS("Could not program KEK: %s\n", di_error_string(di_code)); #endif ret = FSL_RETURN_ERROR_S; goto out; } pk_needs_restoration = 1; dryice_release_programmed_key(); /* Find red key */ if (key_info->flags & FSL_SKO_KEY_SELECT_PF_KEY) { black_key[LENGTH_OFFSET] = 21; rounded_key_length = 24; red_key = saved_pk; } else { black_key[LENGTH_OFFSET] = key_info->key_length; red_key = os_alloc_memory(key_info->key_length, 0); if (red_key == NULL) { ret = FSL_RETURN_NO_RESOURCE_S; goto out; } red_key_malloced = 1; ret = fsl_shw_read_key(user_ctx, key_info, red_key); if (ret != FSL_RETURN_OK_S) { goto out; } } #ifdef DIAG_SECURITY_FUNC dump("KEY", red_key, black_key[LENGTH_OFFSET]); #endif /* Compute KEY' = TDES-encrypt(KEK, KEY) */ fsl_shw_sko_init_pf_key(&kek_key_info, FSL_KEY_ALG_TDES, FSL_SHW_PF_KEY_PRG); fsl_shw_sko_set_key_length(&kek_key_info, KEK_LENGTH); fsl_shw_scco_init(&kek_ctx, FSL_KEY_ALG_TDES, FSL_SYM_MODE_CBC); fsl_shw_scco_set_flags(&kek_ctx, FSL_SYM_CTX_LOAD); fsl_shw_scco_set_context(&kek_ctx, (uint8_t *) & key_info->userid); ret = fsl_shw_symmetric_encrypt(user_ctx, &kek_key_info, &kek_ctx, rounded_key_length, red_key, black_key + KEY_PRIME_OFFSET); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Encryption of KEY failed\n"); #endif /*DIAG_SECURITY_FUNC */ goto out; } /* 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; } #ifdef DIAG_SECURITY_FUNC dump("KEY'", black_key + KEY_PRIME_OFFSET, rounded_key_length); #endif /* Compute and store ICV into Black Key */ ret = calc_icv(T, (uint8_t *) & key_info->userid, sizeof(key_info->userid), black_key, original_key_length, black_key + ICV_OFFSET); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Calculation of ICV failed\n"); #endif /*DIAG_SECURITY_FUNC */ goto out; } /* Compute T' = 3des-enc-ecb(wrap_key, T); Result goes to Black Key */ init_wrap_key(user_ctx->wrap_key, &t_key_info, &t_key_ctx); ret = fsl_shw_symmetric_encrypt(user_ctx, &t_key_info, &t_key_ctx, T_LENGTH, T, black_key + T_PRIME_OFFSET); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Encryption of nonce failed"); #endif goto out; } #ifdef DIAG_SECURITY_FUNC dump("black", black_key, KEY_PRIME_OFFSET + black_key[LENGTH_OFFSET]); #endif out: if (pk_needs_restoration) { dryice_set_programmed_key(saved_pk, 8 * 21, 0); } if (!pk_was_held) { dryice_release_programmed_key(); } if (red_key_malloced) { memset(red_key, 0, key_info->key_length); os_free_memory(red_key); } key_info->key_length = original_key_length; /* Erase tracks of confidential data */ memset(T, 0, T_LENGTH); memset(&t_key_info, 0, sizeof(t_key_info)); memset(&t_key_ctx, 0, sizeof(t_key_ctx)); memset(&kek_key_info, 0, sizeof(kek_key_info)); memset(&kek_ctx, 0, sizeof(kek_ctx)); memset(kek, 0, sizeof(kek)); memset(saved_pk, 0, sizeof(saved_pk)); 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 */
/*! * 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; uint8_t hmac[ICV_LENGTH]; uint8_t T[T_LENGTH]; uint8_t kek[KEK_LENGTH + 20]; int key_length = black_key[LENGTH_OFFSET]; int rounded_key_length = ROUND_LENGTH(key_length); uint8_t key[rounded_key_length]; fsl_shw_sko_t t_key_info; fsl_shw_scco_t t_key_ctx; fsl_shw_sko_t kek_key_info; fsl_shw_scco_t kek_ctx; int unwrapping_sw_key = key_info->flags & FSL_SKO_KEY_SW_KEY; int pk_needs_restoration = 0; /* bool */ unsigned original_key_length = key_info->key_length; int pk_was_held = 0; uint8_t current_pk[21]; di_return_t di_code; ret = check_wrap_key(user_ctx->wrap_key); if (ret != FSL_RETURN_OK_S) { goto out; } if (black_key == NULL) { ret = FSL_RETURN_ERROR_S; goto out; } #ifdef DIAG_SECURITY_FUNC dump("black", black_key, KEY_PRIME_OFFSET + key_length); #endif /* 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 = 3des-dec-ecb(wrap_key, T') */ init_wrap_key(user_ctx->wrap_key, &t_key_info, &t_key_ctx); ret = fsl_shw_symmetric_decrypt(user_ctx, &t_key_info, &t_key_ctx, T_LENGTH, black_key + T_PRIME_OFFSET, T); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Recovery of nonce (T) failed"); #endif /*DIAG_SECURITY_FUNC */ goto out; } /* Compute ICV = HMAC(T, ownerid | len | alg | flags | key' */ ret = calc_icv(T, (uint8_t *) & key_info->userid, sizeof(key_info->userid), black_key, original_key_length, hmac); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Calculation of ICV failed"); #endif /*DIAG_SECURITY_FUNC */ goto out; } #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Validating MAC of wrapped key"); #endif /* Check computed ICV against value in Black Key */ if (memcmp(black_key + ICV_OFFSET, hmac, ICV_LENGTH) != 0) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Computed ICV fails validation\n"); #endif ret = FSL_RETURN_AUTH_FAILED_S; goto out; } /* Compute KEK = SHA256(T | ownerid). */ ret = calc_kek((uint8_t *) & key_info->userid, sizeof(key_info->userid), T, kek); if (ret != FSL_RETURN_OK_S) { goto out; } if (unwrapping_sw_key) { di_code = dryice_get_programmed_key(current_pk, 8 * 21); if (di_code != DI_SUCCESS) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG_ARGS("Could not save current PK: %s\n", di_error_string(di_code)); #endif ret = FSL_RETURN_ERROR_S; goto out; } } /* * "Establish" the KEK in the PK. If the PK was held and unwrapping a * software key, then release it and try again, but remember that we need * to leave it 'held' if we are unwrapping a software key. * * If the PK is held while we are unwrapping a key for the PK, then * the user didn't call release, so gets an error. */ di_code = dryice_set_programmed_key(kek, 8 * 21, 0); if ((di_code == DI_ERR_INUSE) && unwrapping_sw_key) { /* Temporarily reprogram the PK out from under the user */ pk_was_held = 1; dryice_release_programmed_key(); di_code = dryice_set_programmed_key(kek, 8 * 21, 0); } if (di_code != DI_SUCCESS) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG_ARGS("Could not program KEK: %s\n", di_error_string(di_code)); #endif ret = FSL_RETURN_ERROR_S; goto out; } if (unwrapping_sw_key) { pk_needs_restoration = 1; } dryice_release_programmed_key(); /* Because of previous 'set' */ /* Compute KEY = TDES-decrypt(KEK, KEY') */ fsl_shw_sko_init_pf_key(&kek_key_info, FSL_KEY_ALG_TDES, FSL_SHW_PF_KEY_PRG); fsl_shw_sko_set_key_length(&kek_key_info, KEK_LENGTH); fsl_shw_scco_init(&kek_ctx, FSL_KEY_ALG_TDES, FSL_SYM_MODE_CBC); fsl_shw_scco_set_flags(&kek_ctx, FSL_SYM_CTX_LOAD); fsl_shw_scco_set_context(&kek_ctx, (uint8_t *) & key_info->userid); #ifdef DIAG_SECURITY_FUNC dump("KEY'", black_key + KEY_PRIME_OFFSET, rounded_key_length); #endif ret = fsl_shw_symmetric_decrypt(user_ctx, &kek_key_info, &kek_ctx, rounded_key_length, black_key + KEY_PRIME_OFFSET, key); if (ret != FSL_RETURN_OK_S) { goto out; } #ifdef DIAG_SECURITY_FUNC dump("KEY", key, original_key_length); #endif /* Now either put key into PK or into a slot */ if (key_info->flags & FSL_SKO_KEY_SW_KEY) { ret = load_slot(user_ctx, key_info, key); } else { /* * Since we have just unwrapped a program key, it had * to have been wrapped as a program key, so it must * be 168 bytes long and permuted ... */ ret = dryice_set_programmed_key(key, 8 * key_length, 0); if (ret != FSL_RETURN_OK_S) { goto out; } } out: key_info->key_length = original_key_length; if (pk_needs_restoration) { di_code = dryice_set_programmed_key(current_pk, 8 * 21, 0); } if (!pk_was_held) { dryice_release_programmed_key(); } /* Erase tracks of confidential data */ memset(T, 0, T_LENGTH); memset(key, 0, rounded_key_length); memset(current_pk, 0, sizeof(current_pk)); memset(&t_key_info, 0, sizeof(t_key_info)); memset(&t_key_ctx, 0, sizeof(t_key_ctx)); memset(&kek_key_info, 0, sizeof(kek_key_info)); memset(&kek_ctx, 0, sizeof(kek_ctx)); memset(kek, 0, KEK_LENGTH); return ret; } /* unwrap */