Linux debugging

Check our new training course

Linux debugging, tracing, profiling & perf. analysis

Check our new training course
with Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2015, Linaro Limited
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <user_ta_header.h>
#include <trace.h>
#include <kernel/tee_common_unpg.h>
#include <tee/tee_enc_fs_key_manager.h>


#define TA_NAME		"enc_fs_key_manager_tests.ta"

#define CMD_SELF_TESTS	0

#define ENC_FS_KEY_MANAGER_TEST_UUID \
		{ 0x17E5E280, 0xD12E, 0x11E4,  \
		{ 0xA4, 0x1A, 0x00, 0x02, 0xA5, 0xD5, 0xC5, 0x1B } }

#define DUMP_BUF_MAX	256

static uint8_t test_data[] = {
	0x00, 0x6E, 0x04, 0x57, 0x08, 0xFB, 0x71, 0x96,
	0x00, 0x2E, 0x55, 0x3D, 0x02, 0xC3, 0xA6, 0x92,
	0x00, 0xC3, 0xEF, 0x8A, 0xB2, 0x34, 0x53, 0xE6,
	0x00, 0x74, 0x9C, 0xD6, 0x36, 0xE7, 0xA8, 0x00
};

static char *print_buf(char *buf, size_t *remain_size, const char *fmt, ...)
	__attribute__((__format__(__printf__, 3, 4)));

static char *print_buf(char *buf, size_t *remain_size, const char *fmt, ...)
{
	va_list ap;
	size_t len;

	va_start(ap, fmt);
	len = vsnprintf(buf, *remain_size, fmt, ap);
	buf += len;
	*remain_size -= len;
	va_end(ap);
	return buf;
}

static void dump_hex(char *buf, size_t *remain_size, uint8_t *input_buf,
		size_t input_size)
{
	size_t i;

	for (i = 0; i < input_size; i++)
		buf = print_buf(buf, remain_size, "%02X ", input_buf[i]);
}

static void print_hex(uint8_t *input_buf, size_t input_size)
{
	char buf[DUMP_BUF_MAX];
	size_t remain = sizeof(buf);

	dump_hex(buf, &remain, input_buf, input_size);
	DMSG("%s", buf);
}

/*
 * Trusted Application Entry Points
 */

static TEE_Result create_ta(void)
{
	DMSG("create entry point for static ta \"%s\"", TA_NAME);
	return TEE_SUCCESS;
}

static void destroy_ta(void)
{
	DMSG("destroy entry point for static ta \"%s\"", TA_NAME);
}

static TEE_Result open_session(uint32_t nParamTypes __unused,
		TEE_Param pParams[4] __unused, void **ppSessionContext __unused)
{
	DMSG("open entry point for static ta \"%s\"", TA_NAME);
	return TEE_SUCCESS;
}

static void close_session(void *pSessionContext __unused)
{
	DMSG("close entry point for static ta \"%s\"", TA_NAME);
}


static TEE_Result test_file_decrypt_with_invalid_content(void)
{
	TEE_Result res = TEE_SUCCESS;
	size_t header_size;
	size_t encrypt_data_out_size;
	uint8_t *encrypt_data_out = NULL;
	size_t decrypt_data_out_size;
	uint8_t *decrypt_data_out = NULL;
	uint8_t tmp_byte;

	DMSG("Start");

	/* data encryption */
	header_size = tee_enc_fs_get_file_header_size();

	encrypt_data_out_size = header_size + sizeof(test_data);
	encrypt_data_out = malloc(encrypt_data_out_size);
	if (!encrypt_data_out) {
		EMSG("malloc for encrypt data buffer failed");
		res = TEE_ERROR_OUT_OF_MEMORY;
		goto exit;
	}

	res = tee_enc_fs_file_encryption(test_data, sizeof(test_data),
			encrypt_data_out, &encrypt_data_out_size);
	if (res != TEE_SUCCESS) {
		EMSG("file encryption failed");
		goto exit;
	}

	/* data decryption */
	decrypt_data_out_size = sizeof(test_data);
	decrypt_data_out = malloc(decrypt_data_out_size);
	if (!decrypt_data_out) {
		EMSG("malloc for decrypt data buffer failed");
		res = TEE_ERROR_OUT_OF_MEMORY;
		goto exit;
	}

	/* case1: data decryption with modified encrypted_key */
	tmp_byte = *(encrypt_data_out + 4);
	*(encrypt_data_out + 4) = ~tmp_byte;

	DMSG("case1: decryption with modified encrypted FEK");

	res = tee_enc_fs_file_decryption(
			encrypt_data_out, encrypt_data_out_size,
			decrypt_data_out, &decrypt_data_out_size);
	if (res == TEE_ERROR_MAC_INVALID) {
		DMSG("case1: passed, return code=%x", res);
	} else {
		EMSG("case1: failed, return code=%x", res);
		res = TEE_ERROR_GENERIC;
		goto exit;
	}

	*(encrypt_data_out + 4) = tmp_byte;

	/* case2: data decryption with modified iv */
	tmp_byte = *(encrypt_data_out + 20);
	*(encrypt_data_out + 20) = ~tmp_byte;

	DMSG("case2: decryption with modified IV");

	res = tee_enc_fs_file_decryption(
			encrypt_data_out, encrypt_data_out_size,
			decrypt_data_out, &decrypt_data_out_size);
	if (res == TEE_ERROR_MAC_INVALID) {
		DMSG("case2: passed, return code=%x", res);
	} else {
		EMSG("case2: failed, return code=%x", res);
		res = TEE_ERROR_GENERIC;
		goto exit;
	}

	*(encrypt_data_out + 20) = tmp_byte;

	/* case3: data decryption with modified cipher text */
	tmp_byte = *(encrypt_data_out + encrypt_data_out_size - 5);
	*(encrypt_data_out + encrypt_data_out_size - 5) = ~tmp_byte;

	DMSG("case3: decryption with modified cipher text");

	res = tee_enc_fs_file_decryption(
			encrypt_data_out, encrypt_data_out_size,
			decrypt_data_out, &decrypt_data_out_size);
	if (res == TEE_ERROR_MAC_INVALID) {
		DMSG("case3: passed, return code=%x", res);
	} else {
		EMSG("case3: failed, return code=%x", res);
		res = TEE_ERROR_GENERIC;
		goto exit;
	}

	*(encrypt_data_out + encrypt_data_out_size - 5) = tmp_byte;

	/* case4: data decryption with shorter cipher text length */
	DMSG("case4: decryption with shorter cipher text length");

	res = tee_enc_fs_file_decryption(
			encrypt_data_out, encrypt_data_out_size - 1,
			decrypt_data_out, &decrypt_data_out_size);
	if (res == TEE_ERROR_SHORT_BUFFER) {
		DMSG("case4: passed, return code=%x", res);
	} else {
		EMSG("case4: failed, return code=%x", res);
		res = TEE_ERROR_GENERIC;
		goto exit;
	}

	*(encrypt_data_out + encrypt_data_out_size - 5) = tmp_byte;

	/* data decryption with correct encrypted data */
	DMSG("good path test - decryption with correct data");

	res = tee_enc_fs_file_decryption(
			encrypt_data_out, encrypt_data_out_size,
			decrypt_data_out, &decrypt_data_out_size);
	if (res != TEE_SUCCESS) {
		EMSG("failed to decrypted data, return code=%x", res);
		goto exit;
	}

	/* data comparison */
	if (memcmp(test_data, decrypt_data_out, sizeof(test_data)) != 0) {
		EMSG("decrypted data doest not correct");
		res = TEE_ERROR_GENERIC;
	} else {
		DMSG("good path test - passed");
	}

exit:
	if (encrypt_data_out != NULL)
		free(encrypt_data_out);

	if (decrypt_data_out != NULL)
		free(decrypt_data_out);

	DMSG("Finish");

	return res;
}

static TEE_Result test_file_decrypt_success(void)
{
	TEE_Result res = TEE_SUCCESS;
	size_t header_size;
	size_t encrypt_data_out_size;
	uint8_t *encrypt_data_out = NULL;
	size_t decrypt_data_out_size;
	uint8_t *decrypt_data_out = NULL;

	DMSG("Start");

	/* data encryption */
	header_size = tee_enc_fs_get_file_header_size();

	encrypt_data_out_size = header_size + sizeof(test_data);
	encrypt_data_out = malloc(encrypt_data_out_size);
	if (!encrypt_data_out) {
		EMSG("malloc for encrypt data buffer failed");
		res = TEE_ERROR_OUT_OF_MEMORY;
		goto exit;
	}

	res = tee_enc_fs_file_encryption(test_data, sizeof(test_data),
			encrypt_data_out, &encrypt_data_out_size);
	if (res != TEE_SUCCESS) {
		EMSG("file encryption failed");
		goto exit;
	}


	/* data decryption */
	decrypt_data_out_size = sizeof(test_data);
	decrypt_data_out = malloc(decrypt_data_out_size);
	if (!decrypt_data_out) {
		EMSG("malloc for decrypt data buffer failed");
		res = TEE_ERROR_OUT_OF_MEMORY;
		goto exit;
	}

	res = tee_enc_fs_file_decryption(
			encrypt_data_out, encrypt_data_out_size,
			decrypt_data_out, &decrypt_data_out_size);
	if (res != TEE_SUCCESS)
		goto exit;

	/* data comparison */
	if (memcmp(test_data, decrypt_data_out, sizeof(test_data)) != 0) {
		EMSG("Data compare failed");
		res = TEE_ERROR_GENERIC;
	}

exit:
	/* dump data for debug */
	if (res != TEE_SUCCESS)
		DMSG("return code = %x", res);
	else {
		DMSG("Test Data (%zu bytes)", sizeof(test_data));
		print_hex(test_data, sizeof(test_data));
		DMSG("Encrypted Data (%zu bytes)", encrypt_data_out_size);
		print_hex(encrypt_data_out, encrypt_data_out_size);
		DMSG("Decrypted Data (%zu bytes)", decrypt_data_out_size);
		print_hex(decrypt_data_out, decrypt_data_out_size);
	}

	if (encrypt_data_out != NULL)
		free(encrypt_data_out);

	if (decrypt_data_out != NULL)
		free(decrypt_data_out);

	DMSG("Finish");

	return res;
}

static TEE_Result self_tests(
			uint32_t nParamTypes __unused,
			TEE_Param pParams[TEE_NUM_PARAMS] __unused)
{
	TEE_Result res;

	res = test_file_decrypt_success();
	if (res != TEE_SUCCESS)
		return res;

	res = test_file_decrypt_with_invalid_content();
	if (res != TEE_SUCCESS)
		return res;

	return TEE_SUCCESS;
}

static TEE_Result invoke_command(void *pSessionContext __unused,
		uint32_t nCommandID, uint32_t nParamTypes, TEE_Param pParams[4])
{
	DMSG("command entry point for static ta \"%s\"", TA_NAME);

	switch (nCommandID) {
	case CMD_SELF_TESTS:
		return self_tests(nParamTypes, pParams);
	default:
		break;
	}
	return TEE_ERROR_BAD_PARAMETERS;
}

__attribute__ ((section("ta_head_section")))
	const ta_static_head_t enc_fs_key_manager_self_test_head = {

	.uuid = ENC_FS_KEY_MANAGER_TEST_UUID,
	.name = (char *)TA_NAME,
	.create_entry_point = create_ta,
	.destroy_entry_point = destroy_ta,
	.open_session_entry_point = open_session,
	.close_session_entry_point = close_session,
	.invoke_command_entry_point = invoke_command,

};