Beispiel #1
0
/*!
 * @brief Authenticate and decrypt a (CCM) stream.
 *
 * @param user_ctx         The user's context
 * @param auth_ctx         Info on this Auth operation
 * @param cipher_key_info  Key to encrypt payload
 * @param auth_key_info    (unused - same key in CCM)
 * @param auth_data_length Length in bytes of @a auth_data
 * @param auth_data        Any auth-only data
 * @param payload_length   Length in bytes of @a payload
 * @param ct               The encrypted data
 * @param auth_value       The authentication code to validate
 * @param[out] payload     The location to store decrypted data
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t fsl_shw_auth_decrypt(fsl_shw_uco_t * user_ctx,
				      fsl_shw_acco_t * auth_ctx,
				      fsl_shw_sko_t * cipher_key_info,
				      fsl_shw_sko_t * auth_key_info,
				      uint32_t auth_data_length,
				      const uint8_t * auth_data,
				      uint32_t payload_length,
				      const uint8_t * ct,
				      const uint8_t * auth_value,
				      uint8_t * payload)
{
	SAH_SF_DCLS;
	uint8_t *calced_auth = NULL;
	unsigned blocking = user_ctx->flags & FSL_UCO_BLOCKING_MODE;

	SAH_SF_USER_CHECK();

	/* Only support INIT and FINALIZE flags right now. */
	if (auth_ctx->mode != FSL_ACC_MODE_CCM) {
		ret = FSL_RETURN_BAD_MODE_S;
		goto out;
	}
	if ((auth_ctx->flags & (FSL_ACCO_CTX_INIT | FSL_ACCO_CTX_LOAD |
				FSL_ACCO_CTX_SAVE | FSL_ACCO_CTX_FINALIZE))
	    != (FSL_ACCO_CTX_INIT | FSL_ACCO_CTX_FINALIZE)) {
		ret = FSL_RETURN_BAD_FLAG_S;
		goto out;
	}
	ret = load_ctr_key(&desc_chain, user_ctx, auth_ctx, cipher_key_info);
	if (ret != FSL_RETURN_OK_S) {
		goto out;
	}

	/* Decrypt the MAC which the user passed in */
	header = SAH_HDR_SKHA_ENC_DEC;
	DESC_IN_OUT(header,
		    auth_ctx->mac_length, auth_value,
		    auth_ctx->mac_length, auth_ctx->unencrypted_mac);

#ifndef NO_ZERO_IV_LOAD
	ret = load_dummy_iv(&desc_chain, user_ctx, 1,
			    auth_ctx->auth_info.CCM_ctx_info.block_size_bytes);
#endif

	if (auth_data_length > 0) {
		ret = add_assoc_preamble(&desc_chain, user_ctx,
					 auth_ctx, auth_data, auth_data_length);
		if (ret != FSL_RETURN_OK_S) {
			goto out;
		}
	}
	/* if auth_data_length > 0 */
	ret = process_payload(&desc_chain, user_ctx, 0,
			      payload_length, ct, payload);
	if (ret != FSL_RETURN_OK_S) {
		goto out;
	}

	/* Now pull CBC context (unencrypted MAC) out for comparison. */
	/* Need to allocate a place for it, to handle non-blocking mode
	 * when this stack frame will disappear!
	 */
	calced_auth = DESC_TEMP_ALLOC(auth_ctx->mac_length);
	ret = extract_mac(&desc_chain, user_ctx,
			  auth_ctx->mac_length, calced_auth);
	if (ret != FSL_RETURN_OK_S) {
		goto out;
	}

	if (!blocking) {
		/* get_results will need this for comparison */
		desc_chain->out1_ptr = calced_auth;
		desc_chain->out2_ptr = auth_ctx->unencrypted_mac;
		desc_chain->out_len = auth_ctx->mac_length;
	}

	SAH_SF_EXECUTE();

	if (blocking && (ret == FSL_RETURN_OK_S)) {
		unsigned i;
		/* Validate the auth code */
		for (i = 0; i < auth_ctx->mac_length; i++) {
			if (calced_auth[i] != auth_ctx->unencrypted_mac[i]) {
				ret = FSL_RETURN_AUTH_FAILED_S;
				break;
			}
		}
	}

      out:
	SAH_SF_DESC_CLEAN();
	DESC_TEMP_FREE(calced_auth);

	(void)auth_key_info;
	return ret;
}				/* fsl_shw_gen_decrypt() */
/*!
 * 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 */
/*!
 * @brief Authenticate and decrypt a (CCM) stream.
 *
 * @param user_ctx         The user's context
 * @param auth_ctx         Info on this Auth operation
 * @param cipher_key_info  Key to encrypt payload
 * @param auth_key_info    (unused - same key in CCM)
 * @param auth_data_length Length in bytes of @a auth_data
 * @param auth_data        Any auth-only data
 * @param payload_length   Length in bytes of @a payload
 * @param ct               The encrypted data
 * @param auth_value       The authentication code to validate
 * @param[out] payload     The location to store decrypted data
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t fsl_shw_auth_decrypt(fsl_shw_uco_t * user_ctx,
				      fsl_shw_acco_t * auth_ctx,
				      fsl_shw_sko_t * cipher_key_info,
				      fsl_shw_sko_t * auth_key_info,
				      uint32_t auth_data_length,
				      const uint8_t * auth_data,
				      uint32_t payload_length,
				      const uint8_t * ct,
				      const uint8_t * auth_value,
				      uint8_t * payload)
{
	SAH_SF_DCLS;
#if defined(FSL_HAVE_SAHARA2) || defined(USE_S2_CCM_DECRYPT_CHAIN)
	uint8_t *calced_auth = NULL;
	unsigned blocking = user_ctx->flags & FSL_UCO_BLOCKING_MODE;
#endif

	SAH_SF_USER_CHECK();

	/* Only support CCM */
	if (auth_ctx->mode != FSL_ACC_MODE_CCM) {
		ret = FSL_RETURN_BAD_MODE_S;
		goto out;
	}
	/* Only support INIT and FINALIZE flags right now. */
	if ((auth_ctx->flags & (FSL_ACCO_CTX_INIT | FSL_ACCO_CTX_LOAD |
				FSL_ACCO_CTX_SAVE | FSL_ACCO_CTX_FINALIZE))
	    != (FSL_ACCO_CTX_INIT | FSL_ACCO_CTX_FINALIZE)) {
		ret = FSL_RETURN_BAD_FLAG_S;
		goto out;
	}

	/* Load CTR0 and Key */
	header = SAH_HDR_SKHA_SET_MODE_IV_KEY
	    ^ sah_insert_skha_mode_ctr ^ sah_insert_skha_modulus_128;
#if defined (FSL_HAVE_SAHARA4) && !defined (USE_S2_CCM_DECRYPT_CHAIN)
	header ^= sah_insert_skha_aux0;
#endif
	DESC_IN_KEY(header,
		    auth_ctx->cipher_ctx_info.block_size_bytes,
		    auth_ctx->cipher_ctx_info.context, cipher_key_info);

	/* Decrypt the MAC which the user passed in */
	header = SAH_HDR_SKHA_ENC_DEC;
	DESC_IN_OUT(header,
		    auth_ctx->mac_length, auth_value,
		    auth_ctx->mac_length, auth_ctx->unencrypted_mac);

#if defined(FSL_HAVE_SAHARA2) || defined(USE_S2_CCM_DECRYPT_CHAIN)
#ifndef NO_ZERO_IV_LOAD
	header = (SAH_HDR_SKHA_SET_MODE_IV_KEY
		  ^ sah_insert_skha_encrypt ^ sah_insert_skha_mode_cbc);
	DESC_IN_IN(header,
		   auth_ctx->auth_info.CCM_ctx_info.block_size_bytes,
		   block_zeros, 0, NULL);
#endif
#endif

	ret = add_assoc_preamble(&desc_chain, user_ctx,
				 auth_ctx, 0, auth_data, auth_data_length);
	if (ret != FSL_RETURN_OK_S) {
		goto out;
	}

	/* Process the payload */
	header = (SAH_HDR_SKHA_SET_MODE_ENC_DEC
		  ^ sah_insert_skha_mode_ccm ^ sah_insert_skha_modulus_128);
#if defined (FSL_HAVE_SAHARA4) && !defined (USE_S2_CCM_DECRYPT_CHAIN)
	header ^= sah_insert_skha_aux0;
#endif
	if (payload_length != 0) {
		DESC_IN_OUT(header, payload_length, ct, payload_length,
			    payload);
	} else {
		DESC_IN_OUT(header, 0, NULL, 0, NULL);
	}

#if defined (FSL_HAVE_SAHARA2) || defined (USE_S2_CCM_DECRYPT_CHAIN)
	/* Now pull CBC context (unencrypted MAC) out for comparison. */
	/* Need to allocate a place for it, to handle non-blocking mode
	 * when this stack frame will disappear!
	 */
	calced_auth = DESC_TEMP_ALLOC(auth_ctx->mac_length);
	header = SAH_HDR_SKHA_READ_CONTEXT_IV;
	DESC_OUT_OUT(header, 0, NULL, auth_ctx->mac_length, calced_auth);
	if (!blocking) {
		/* get_results will need this for comparison */
		desc_chain->out1_ptr = calced_auth;
		desc_chain->out2_ptr = auth_ctx->unencrypted_mac;
		desc_chain->out_len = auth_ctx->mac_length;
	}
#endif

	SAH_SF_EXECUTE();

#if defined (FSL_HAVE_SAHARA2) || defined (USE_S2_CCM_DECRYPT_CHAIN)
	if (blocking && (ret == FSL_RETURN_OK_S)) {
		unsigned i;
		/* Validate the auth code */
		for (i = 0; i < auth_ctx->mac_length; i++) {
			if (calced_auth[i] != auth_ctx->unencrypted_mac[i]) {
				ret = FSL_RETURN_AUTH_FAILED_S;
				break;
			}
		}
	}
#endif

      out:
	SAH_SF_DESC_CLEAN();
#if defined (FSL_HAVE_SAHARA2) || defined (USE_S2_CCM_DECRYPT_CHAIN)
	DESC_TEMP_FREE(calced_auth);
#endif

	(void)auth_key_info;
	return ret;
}				/* fsl_shw_gen_decrypt() */
/*!
 * 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;
}