static TEE_Result check_shdr(struct shdr *shdr)
{
	struct rsa_public_key key;
	TEE_Result res;
	uint32_t e = TEE_U32_TO_BIG_ENDIAN(ta_pub_key_exponent);
	size_t hash_size;

	if (shdr->magic != SHDR_MAGIC || shdr->img_type != SHDR_TA)
		return TEE_ERROR_SECURITY;

	if (TEE_ALG_GET_MAIN_ALG(shdr->algo) != TEE_MAIN_ALGO_RSA)
		return TEE_ERROR_SECURITY;

	res = tee_hash_get_digest_size(TEE_DIGEST_HASH_TO_ALGO(shdr->algo),
				       &hash_size);
	if (res != TEE_SUCCESS)
		return res;
	if (hash_size != shdr->hash_size)
		return TEE_ERROR_SECURITY;

	if (!crypto_ops.acipher.alloc_rsa_public_key ||
	    !crypto_ops.acipher.free_rsa_public_key ||
	    !crypto_ops.acipher.rsassa_verify ||
	    !crypto_ops.bignum.bin2bn)
		return TEE_ERROR_NOT_SUPPORTED;

	res = crypto_ops.acipher.alloc_rsa_public_key(&key, shdr->sig_size);
	if (res != TEE_SUCCESS)
		return res;

	res = crypto_ops.bignum.bin2bn((uint8_t *)&e, sizeof(e), key.e);
	if (res != TEE_SUCCESS)
		goto out;
	res = crypto_ops.bignum.bin2bn(ta_pub_key_modulus,
				       ta_pub_key_modulus_size, key.n);
	if (res != TEE_SUCCESS)
		goto out;

	res = crypto_ops.acipher.rsassa_verify(shdr->algo, &key, -1,
				SHDR_GET_HASH(shdr), shdr->hash_size,
				SHDR_GET_SIG(shdr), shdr->sig_size);
out:
	crypto_ops.acipher.free_rsa_public_key(&key);
	if (res != TEE_SUCCESS)
		return TEE_ERROR_SECURITY;
	return TEE_SUCCESS;
}
Exemple #2
0
static TEE_Result ree_fs_ta_open(const TEE_UUID *uuid,
				 struct user_ta_store_handle **h)
{
	struct ree_fs_ta_handle *handle;
	struct shdr *shdr = NULL;
	struct mobj *mobj = NULL;
	void *hash_ctx = NULL;
	uint32_t hash_algo = 0;
	struct shdr *ta = NULL;
	size_t ta_size = 0;
	TEE_Result res;
	size_t offs;

	handle = calloc(1, sizeof(*handle));
	if (!handle)
		return TEE_ERROR_OUT_OF_MEMORY;

	/* Request TA from tee-supplicant */
	res = rpc_load(uuid, &ta, &ta_size, &mobj);
	if (res != TEE_SUCCESS)
		goto error;

	/* Make secure copy of signed header */
	shdr = shdr_alloc_and_copy(ta, ta_size);
	if (!shdr) {
		res = TEE_ERROR_SECURITY;
		goto error_free_payload;
	}

	/* Validate header signature */
	res = shdr_verify_signature(shdr);
	if (res != TEE_SUCCESS)
		goto error_free_payload;
	if (shdr->img_type != SHDR_TA && shdr->img_type != SHDR_BOOTSTRAP_TA) {
		res = TEE_ERROR_SECURITY;
		goto error_free_payload;
	}

	/*
	 * Initialize a hash context and run the algorithm over the signed
	 * header (less the final file hash and its signature of course)
	 */
	hash_algo = TEE_DIGEST_HASH_TO_ALGO(shdr->algo);
	res = crypto_hash_alloc_ctx(&hash_ctx, hash_algo);
	if (res != TEE_SUCCESS)
		goto error_free_payload;
	res = crypto_hash_init(hash_ctx, hash_algo);
	if (res != TEE_SUCCESS)
		goto error_free_hash;
	res = crypto_hash_update(hash_ctx, hash_algo, (uint8_t *)shdr,
				     sizeof(*shdr));
	if (res != TEE_SUCCESS)
		goto error_free_hash;
	offs = SHDR_GET_SIZE(shdr);

	if (shdr->img_type == SHDR_BOOTSTRAP_TA) {
		TEE_UUID bs_uuid;
		struct shdr_bootstrap_ta bs_hdr;

		if (ta_size < SHDR_GET_SIZE(shdr) + sizeof(bs_hdr)) {
			res = TEE_ERROR_SECURITY;
			goto error_free_hash;
		}

		memcpy(&bs_hdr, ((uint8_t *)ta + offs), sizeof(bs_hdr));

		/*
		 * There's a check later that the UUID embedded inside the
		 * ELF is matching, but since we now have easy access to
		 * the expected uuid of the TA we check it a bit earlier
		 * here.
		 */
		tee_uuid_from_octets(&bs_uuid, bs_hdr.uuid);
		if (memcmp(&bs_uuid, uuid, sizeof(TEE_UUID))) {
			res = TEE_ERROR_SECURITY;
			goto error_free_hash;
		}

		res = crypto_hash_update(hash_ctx, hash_algo,
					 (uint8_t *)&bs_hdr, sizeof(bs_hdr));
		if (res != TEE_SUCCESS)
			goto error_free_hash;
		offs += sizeof(bs_hdr);
	}

	if (ta_size != offs + shdr->img_size) {
		res = TEE_ERROR_SECURITY;
		goto error_free_hash;
	}

	handle->nw_ta = ta;
	handle->nw_ta_size = ta_size;
	handle->offs = offs;
	handle->hash_algo = hash_algo;
	handle->hash_ctx = hash_ctx;
	handle->shdr = shdr;
	handle->mobj = mobj;
	*h = (struct user_ta_store_handle *)handle;
	return TEE_SUCCESS;

error_free_hash:
	crypto_hash_free_ctx(hash_ctx, hash_algo);
error_free_payload:
	thread_rpc_free_payload(mobj);
error:
	shdr_free(shdr);
	free(handle);
	return res;
}
Exemple #3
0
static TEE_Result install_ta(struct shdr *shdr, const uint8_t *nw,
			     size_t nw_size)
{
	TEE_Result res;
	struct tee_tadb_ta_write *ta;
	uint32_t hash_algo = 0;
	void *hash_ctx = NULL;
	size_t offs;
	const size_t buf_size = 2 * 4096;
	void *buf;
	struct tee_tadb_property property;
	struct shdr_bootstrap_ta bs_ta;

	if (shdr->img_type != SHDR_BOOTSTRAP_TA)
		return TEE_ERROR_SECURITY;

	if (nw_size < (sizeof(struct shdr_bootstrap_ta) + SHDR_GET_SIZE(shdr)))
		return TEE_ERROR_SECURITY;

	if (shdr->hash_size > buf_size)
		return TEE_ERROR_SECURITY;

	buf = malloc(buf_size);
	if (!buf)
		return TEE_ERROR_OUT_OF_MEMORY;

	/*
	 * Initialize a hash context and run the algorithm over the signed
	 * header (less the final file hash and its signature of course)
	 */
	hash_algo = TEE_DIGEST_HASH_TO_ALGO(shdr->algo);
	res = crypto_hash_alloc_ctx(&hash_ctx, hash_algo);
	if (res)
		goto err;
	res = crypto_hash_init(hash_ctx, hash_algo);
	if (res)
		goto err_free_hash_ctx;
	res = crypto_hash_update(hash_ctx, hash_algo, (uint8_t *)shdr,
				     sizeof(*shdr));
	if (res)
		goto err_free_hash_ctx;

	offs = SHDR_GET_SIZE(shdr);
	memcpy(&bs_ta, nw + offs, sizeof(bs_ta));

	/* Check that we're not downgrading a TA */
	res = check_install_conflict(&bs_ta);
	if (res)
		goto err_free_hash_ctx;

	res = crypto_hash_update(hash_ctx, hash_algo, (uint8_t *)&bs_ta,
				     sizeof(bs_ta));
	if (res)
		goto err_free_hash_ctx;
	offs += sizeof(bs_ta);

	memset(&property, 0, sizeof(property));
	COMPILE_TIME_ASSERT(sizeof(property.uuid) == sizeof(bs_ta.uuid));
	tee_uuid_from_octets(&property.uuid, bs_ta.uuid);
	property.version = bs_ta.version;
	property.custom_size = 0;
	property.bin_size = nw_size - offs;
	DMSG("Installing %pUl", (void *)&property.uuid);

	res = tee_tadb_ta_create(&property, &ta);
	if (res)
		goto err_free_hash_ctx;

	while (offs < nw_size) {
		size_t l = MIN(buf_size, nw_size - offs);

		memcpy(buf, nw + offs, l);
		res = crypto_hash_update(hash_ctx, hash_algo, buf, l);
		if (res)
			goto err_ta_finalize;
		res = tee_tadb_ta_write(ta, buf, l);
		if (res)
			goto err_ta_finalize;
		offs += l;
	}

	res = crypto_hash_final(hash_ctx, hash_algo, buf, shdr->hash_size);
	if (res)
		goto err_ta_finalize;
	if (consttime_memcmp(buf, SHDR_GET_HASH(shdr), shdr->hash_size)) {
		res = TEE_ERROR_SECURITY;
		goto err_ta_finalize;
	}

	crypto_hash_free_ctx(hash_ctx, hash_algo);
	free(buf);
	return tee_tadb_ta_close_and_commit(ta);

err_ta_finalize:
	tee_tadb_ta_close_and_delete(ta);
err_free_hash_ctx:
	crypto_hash_free_ctx(hash_ctx, hash_algo);
err:
	free(buf);
	return res;
}