/* * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. */ /* * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License * Version 2 or later at the following locations: * * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html */ /*! * @file fsl_shw_wrap.c * * This file implements Key-Wrap (Black Key) functions of the FSL SHW API for * Sahara. * * - Ownerid is an 8-byte, user-supplied, value to keep KEY confidential. * - KEY is a 1-32 byte value which starts in SCC RED RAM before * wrapping, and ends up there on unwrap. Length is limited because of * size of SCC1 RAM. * - KEY' is the encrypted KEY * - LEN is a 1-byte (for now) byte-length of KEY * - ALG is a 1-byte value for the algorithm which which the key is * associated. Values are defined by the FSL SHW API * - Ownerid, LEN, and ALG come from the user's "key_info" object, as does the * slot number where KEY already is/will be. * - T is a Nonce * - T' is the encrypted T * - KEK is a Key-Encryption Key for the user's Key * - ICV is the "Integrity Check Value" for the wrapped key * - Black Key is the string of bytes returned as the wrapped key
BLACK_KEY =ICV | T' | LEN | ALG | KEY'
 
To Wrap
T = RND()16
KEK=HASHsha256(T | Ownerid)16
KEY'= AESctr-enc(Key=KEK, CTR=0, Data=KEY)
ICV=HMACsha256 (Key=T, Data=Ownerid | LEN | ALG | KEY')16
T'=TDEScbc-enc (Key=SLID, IV=Ownerid, Data=T)
 
To Unwrap
T=TDESecb-dec (Key=SLID, IV=Ownerid, Data=T')
ICV=HMACsha256 (Key=T, Data=Ownerid | LEN | ALG | KEY')16
KEK=HASHsha256 (T | Ownerid)16
KEY=AESctr-dec (Key=KEK, CTR=0, Data=KEY')
*/ #include "sahara.h" #include "fsl_platform.h" #include "fsl_shw_keystore.h" #include "sf_util.h" #include "adaptor.h" #if defined(DIAG_SECURITY_FUNC) #include #endif #if defined(NEED_CTR_WORKAROUND) /* CTR mode needs block-multiple data in/out */ #define LENGTH_PATCH 16 #define LENGTH_PATCH_MASK 0xF #else #define LENGTH_PATCH 4 #define LENGTH_PATCH_MASK 3 #endif #if LENGTH_PATCH #define ROUND_LENGTH(len) \ ({ \ uint32_t orig_len = len; \ uint32_t new_len; \ \ if ((orig_len & LENGTH_PATCH_MASK) != 0) { \ new_len = (orig_len + LENGTH_PATCH \ - (orig_len & LENGTH_PATCH_MASK)); \ } \ else { \ new_len = orig_len; \ } \ new_len; \ }) #else #define ROUND_LENGTH(len) (len) #endif #ifdef __KERNEL__ EXPORT_SYMBOL(fsl_shw_establish_key); EXPORT_SYMBOL(fsl_shw_extract_key); EXPORT_SYMBOL(fsl_shw_release_key); EXPORT_SYMBOL(fsl_shw_read_key); #endif #define ICV_LENGTH 16 #define T_LENGTH 16 #define KEK_LENGTH 16 #define LENGTH_LENGTH 1 #define ALGORITHM_LENGTH 1 #define FLAGS_LENGTH 1 /* ICV | T' | LEN | ALG | KEY' */ #define ICV_OFFSET 0 #define T_PRIME_OFFSET (ICV_OFFSET + ICV_LENGTH) #define LENGTH_OFFSET (T_PRIME_OFFSET + T_LENGTH) #define ALGORITHM_OFFSET (LENGTH_OFFSET + LENGTH_LENGTH) #define FLAGS_OFFSET (ALGORITHM_OFFSET + ALGORITHM_LENGTH) #define KEY_PRIME_OFFSET (FLAGS_OFFSET + FLAGS_LENGTH) #define FLAGS_SW_KEY 0x01 /* * For testing of the algorithm implementation,, the DO_REPEATABLE_WRAP flag * causes the T_block to go into the T field during a wrap operation. This * will make the black key value repeatable (for a given SCC secret key, or * always if the default key is in use). * * Normally, a random sequence is used. */ #ifdef DO_REPEATABLE_WRAP /*! * Block of zeroes which is maximum Symmetric block size, used for * initializing context register, etc. */ static uint8_t T_block_[16] = { 0x42, 0, 0, 0x42, 0x42, 0, 0, 0x42, 0x42, 0, 0, 0x42, 0x42, 0, 0, 0x42 }; #endif /*! * 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; sah_Link *link1 = NULL; sah_Link *link2 = NULL; /* Load up T as key for the HMAC */ header = (SAH_HDR_MDHA_SET_MODE_MD_KEY /* #6 */ ^ sah_insert_mdha_algorithm_sha256 ^ sah_insert_mdha_init ^ sah_insert_mdha_hmac ^ sah_insert_mdha_pdata ^ sah_insert_mdha_mac_full); sah_code = sah_add_in_key_desc(header, NULL, 0, t_key_info, /* Reference T in RED */ user_ctx->mem_util, desc_chain); if (sah_code != FSL_RETURN_OK_S) { goto out; } /* Previous step loaded key; Now set up to hash the data */ 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) { goto out; } /* 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) { goto out; } /* Output - computed ICV/HMAC */ sah_code = sah_Create_Link(user_ctx->mem_util, &link2, hmac, ICV_LENGTH, SAH_USES_LINK_DATA | SAH_OUTPUT_LINK); if (sah_code != FSL_RETURN_OK_S) { goto out; } sah_code = sah_Append_Desc(user_ctx->mem_util, desc_chain, header, link1, link2); out: if (sah_code != FSL_RETURN_OK_S) { (void)sah_Destroy_Link(user_ctx->mem_util, link1); (void)sah_Destroy_Link(user_ctx->mem_util, link2); } return sah_code; } /* create_icv_calc */ /*! * 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 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 */ /*! * 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) { SAH_SF_DCLS; unsigned original_key_length = key_info->key_length; unsigned rounded_key_length; unsigned slot_allocated = 0; uint32_t old_flags; header = SAH_HDR_RNG_GENERATE; /* Desc. #18 for rand */ /* TODO: THIS STILL NEEDS TO BE REFACTORED */ /* 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 (LENGTH_PATCH && (original_key_length & LENGTH_PATCH_MASK) != 0) { rounded_key_length = original_key_length + LENGTH_PATCH - (original_key_length & LENGTH_PATCH_MASK); } else { rounded_key_length = original_key_length; } SAH_SF_USER_CHECK(); if (key_info->flags & FSL_SKO_KEY_ESTABLISHED) { #ifdef DIAG_SECURITY_FUNC ret = FSL_RETURN_BAD_FLAG_S; LOG_DIAG("Key already established\n"); #endif } if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_alloc(user_ctx, key_info->key_length, key_info->userid, &(key_info->handle)); #ifdef DIAG_SECURITY_FUNC LOG_DIAG_ARGS ("key length: %i, handle: %i, rounded key length: %i", key_info->key_length, key_info->handle, rounded_key_length); #endif } else { /* Key goes in user keystore */ ret = keystore_slot_alloc(key_info->keystore, key_info->key_length, key_info->userid, &(key_info->handle)); } if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Slot allocation failed\n"); #endif goto out; } slot_allocated = 1; key_info->flags |= FSL_SKO_KEY_ESTABLISHED; switch (establish_type) { case FSL_KEY_WRAP_CREATE: #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Creating random key\n"); #endif /* Use safe version of key length */ key_info->key_length = rounded_key_length; /* Generate descriptor to put random value into */ DESC_KEY_OUT(header, key_info, 0, NULL); /* Restore actual, desired key length */ key_info->key_length = original_key_length; old_flags = user_ctx->flags; /* Now put random value into key */ SAH_SF_EXECUTE(); /* Restore user's old flag value */ user_ctx->flags = old_flags; #ifdef DIAG_SECURITY_FUNC if (ret == FSL_RETURN_OK_S) { LOG_DIAG("ret is ok"); } else { LOG_DIAG("ret is not ok"); } #endif break; case FSL_KEY_WRAP_ACCEPT: #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Accepting plaintext key\n"); #endif if (key == NULL) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("ACCEPT: Red Key is NULL"); #endif ret = FSL_RETURN_ERROR_S; goto out; } /* Copy in safe number of bytes of Red key */ if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_load(user_ctx, key_info->userid, key_info->handle, key, rounded_key_length); } else { /* Key goes in user keystore */ ret = keystore_slot_load(key_info->keystore, key_info->userid, key_info->handle, key, key_info->key_length); } break; case FSL_KEY_WRAP_UNWRAP: #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Unwrapping wrapped key\n"); #endif /* 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); } break; default: ret = FSL_RETURN_BAD_FLAG_S; break; } /* switch */ out: if (slot_allocated && (ret != FSL_RETURN_OK_S)) { fsl_shw_return_t scc_err; if (key_info->keystore == NULL) { /* Key goes in system keystore */ scc_err = do_system_keystore_slot_dealloc(user_ctx, key_info->userid, key_info->handle); } else { /* Key goes in user keystore */ scc_err = keystore_slot_dealloc(key_info->keystore, key_info->userid, key_info->handle); } key_info->flags &= ~FSL_SKO_KEY_ESTABLISHED; } SAH_SF_DESC_CLEAN(); return ret; } /* fsl_shw_establish_key() */ /*! * Wrap a key and retrieve the wrapped value. * * A wrapped key is a key that has been cryptographically obscured. It is * only able to be used with #fsl_shw_establish_key(). * * This function will also release the key (see #fsl_shw_release_key()) so * that it must be re-established before reuse. * * 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 key_info The information about the key to be deleted. * @param[out] covered_key The location to store the 48-octet wrapped key. * (This size is based upon the maximum key size * of 32 octets). * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_extract_key(fsl_shw_uco_t * user_ctx, fsl_shw_sko_t * key_info, uint8_t * covered_key) { SAH_SF_DCLS; SAH_SF_USER_CHECK(); /* For now, only blocking mode calls are supported */ if (user_ctx->flags & FSL_UCO_BLOCKING_MODE) { if (key_info->flags & FSL_SKO_KEY_ESTABLISHED) { ret = wrap(user_ctx, key_info, covered_key); if (ret != FSL_RETURN_OK_S) { goto out; } /* Verify that a SW key info really belongs to a SW key */ if (key_info->flags & FSL_SKO_KEY_SW_KEY) { /* ret = FSL_RETURN_BAD_FLAG_S; goto out;*/ } /* Need to deallocate on successful extraction */ if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_dealloc(user_ctx, key_info->userid, key_info->handle); } else { /* Key goes in user keystore */ ret = keystore_slot_dealloc(key_info->keystore, key_info->userid, key_info->handle); } /* Mark key not available in the flags */ key_info->flags &= ~(FSL_SKO_KEY_ESTABLISHED | FSL_SKO_KEY_PRESENT); } } out: SAH_SF_DESC_CLEAN(); return ret; } /*! * De-establish a key so that it can no longer be accessed. * * The key will need to be re-established before it can again be used. * * 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 key_info The information about the key to be deleted. * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_release_key(fsl_shw_uco_t * user_ctx, fsl_shw_sko_t * key_info) { SAH_SF_DCLS; SAH_SF_USER_CHECK(); if (key_info->flags & FSL_SKO_KEY_ESTABLISHED) { if (key_info->keystore == NULL) { /* Key goes in system keystore */ do_system_keystore_slot_dealloc(user_ctx, key_info->userid, key_info->handle); } else { /* Key goes in user keystore */ keystore_slot_dealloc(key_info->keystore, key_info->userid, key_info->handle); } key_info->flags &= ~(FSL_SKO_KEY_ESTABLISHED | FSL_SKO_KEY_PRESENT); } out: SAH_SF_DESC_CLEAN(); return ret; } fsl_shw_return_t fsl_shw_read_key(fsl_shw_uco_t * user_ctx, fsl_shw_sko_t * key_info, uint8_t * key) { SAH_SF_DCLS; SAH_SF_USER_CHECK(); if (!(key_info->flags & FSL_SKO_KEY_ESTABLISHED) || !(key_info->flags & FSL_SKO_KEY_SW_KEY)) { ret = FSL_RETURN_BAD_FLAG_S; goto out; } if (key_info->keystore == NULL) { /* Key lives in system keystore */ ret = do_system_keystore_slot_read(user_ctx, key_info->userid, key_info->handle, key_info->key_length, key); } else { /* Key lives in user keystore */ ret = keystore_slot_read(key_info->keystore, key_info->userid, key_info->handle, key_info->key_length, key); } out: SAH_SF_DESC_CLEAN(); return ret; }