Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 31fe74ce authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "qseecom: Fix issues on key management scheme"

parents f7fc03a5 c16241af
Loading
Loading
Loading
Loading
+22 −8
Original line number Diff line number Diff line
@@ -18,13 +18,15 @@

#define QSEECOM_KEY_ID_SIZE   32

#define	QSEOS_RESULT_FAIL_LOAD_KS         -57
#define	QSEOS_RESULT_FAIL_SAVE_KS         -58
#define	QSEOS_RESULT_FAIL_MAX_KEYS        -59
#define	QSEOS_RESULT_FAIL_KEY_ID_EXISTS   -60
#define	QSEOS_RESULT_FAIL_KEY_ID_DNE      -61
#define	QSEOS_RESULT_FAIL_KS_OP           -62
#define	QSEOS_RESULT_FAIL_CE_PIPE_INVALID -63
#define QSEOS_RESULT_FAIL_UNSUPPORTED_CE_PIPE -63
#define QSEOS_RESULT_FAIL_KS_OP               -64
#define QSEOS_RESULT_FAIL_KEY_ID_EXISTS       -65
#define QSEOS_RESULT_FAIL_MAX_KEYS            -66
#define QSEOS_RESULT_FAIL_SAVE_KS             -67
#define QSEOS_RESULT_FAIL_LOAD_KS             -68
#define QSEOS_RESULT_FAIL_KS_ALREADY_DONE     -69
#define QSEOS_RESULT_FAIL_KEY_ID_DNE          -70
#define QSEOS_RESULT_FAIL_INCORRECT_PSWD      -71

enum qseecom_command_scm_resp_type {
	QSEOS_APP_ID = 0xEE01,
@@ -52,6 +54,7 @@ enum qseecom_qceos_cmd_id {
	QSEOS_DELETE_KEY,
	QSEOS_MAX_KEY_COUNT,
	QSEOS_SET_KEY,
	QSEOS_UPDATE_KEY_USERINFO,
	QSEOS_CMD_MAX     = 0xEFFFFFFF
};

@@ -166,6 +169,7 @@ __packed struct qseecom_key_generate_ireq {
	uint32_t qsee_command_id;
	uint32_t flags;
	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
	uint8_t hash32[QSEECOM_HASH_SIZE];
};

__packed struct qseecom_key_select_ireq {
@@ -175,13 +179,23 @@ __packed struct qseecom_key_select_ireq {
	uint32_t pipe_type;
	uint32_t flags;
	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
	unsigned char hash[QSEECOM_HASH_SIZE];
	uint8_t hash32[QSEECOM_HASH_SIZE];
};

__packed struct qseecom_key_delete_ireq {
	uint32_t qsee_command_id;
	uint32_t flags;
	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
	uint8_t hash32[QSEECOM_HASH_SIZE];

};

__packed struct qseecom_key_userinfo_update_ireq {
	uint32_t qsee_command_id;
	uint32_t flags;
	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
	uint8_t current_hash32[QSEECOM_HASH_SIZE];
	uint8_t new_hash32[QSEECOM_HASH_SIZE];
};

__packed struct qseecom_key_max_count_query_ireq {
+181 −81
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include <linux/firmware.h>
#include <linux/freezer.h>
#include <linux/scatterlist.h>
#include <linux/delay.h>
#include <mach/board.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
@@ -204,25 +205,15 @@ struct qseecom_dev_handle {
	enum qseecom_bandwidth_request_mode mode;
};

enum qseecom_set_clear_key_flag {
	QSEECOM_CLEAR_CE_KEY_CMD = 0,
	QSEECOM_SET_CE_KEY_CMD,
};

struct qseecom_set_key_parameter {
	uint32_t ce_hw;
	uint32_t pipe;
	uint32_t flags;
	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
	unsigned char hash32[QSEECOM_HASH_SIZE];
	enum qseecom_set_clear_key_flag set_clear_key_flag;
};

struct qseecom_sg_entry {
	uint32_t phys_addr;
	uint32_t len;
};

uint8_t *key_id_array[QSEECOM_KEY_ID_SIZE] = {
	"Disk Encryption"
};

/* Function proto types */
static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
@@ -2600,25 +2591,20 @@ static int __qseecom_get_ce_pipe_info(

static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
			enum qseecom_key_management_usage_type usage,
			uint8_t *key_id, uint32_t flags)
			struct qseecom_key_generate_ireq *ireq)
{
	struct qseecom_key_generate_ireq ireq;
	struct qseecom_command_scm_resp resp;
	int ret;

	if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
	if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
		usage >= QSEOS_KM_USAGE_MAX) {
		pr_err("Error:: unsupported usage %d\n", usage);
		return -EFAULT;
	}

	memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
	ireq.flags = flags;
	ireq.qsee_command_id = QSEOS_GENERATE_KEY;

	__qseecom_enable_clk(CLK_QSEE);

	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
				&ireq, sizeof(struct qseecom_key_generate_ireq),
				ireq, sizeof(struct qseecom_key_generate_ireq),
				&resp, sizeof(resp));
	if (ret) {
		pr_err("scm call to generate key failed : %d\n", ret);
@@ -2656,25 +2642,20 @@ static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,

static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
			enum qseecom_key_management_usage_type usage,
			uint8_t *key_id, uint32_t flags)
			struct qseecom_key_delete_ireq *ireq)
{
	struct qseecom_key_delete_ireq ireq;
	struct qseecom_command_scm_resp resp;
	int ret;

	if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
	if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
		usage >= QSEOS_KM_USAGE_MAX) {
		pr_err("Error:: unsupported usage %d\n", usage);
		return -EFAULT;
	}

	memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
	ireq.flags = flags;
	ireq.qsee_command_id = QSEOS_DELETE_KEY;

	__qseecom_enable_clk(CLK_QSEE);

	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
				&ireq, sizeof(struct qseecom_key_delete_ireq),
				ireq, sizeof(struct qseecom_key_delete_ireq),
				&resp, sizeof(struct qseecom_command_scm_resp));
	if (ret) {
		pr_err("scm call to delete key failed : %d\n", ret);
@@ -2704,13 +2685,13 @@ static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,

static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
			enum qseecom_key_management_usage_type usage,
			struct qseecom_set_key_parameter *set_key_para)
			struct qseecom_key_select_ireq *ireq)
{
	struct qseecom_key_select_ireq ireq;
	struct qseecom_command_scm_resp resp;
	int ret;

	if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
	if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
		usage >= QSEOS_KM_USAGE_MAX) {
		pr_err("Error:: unsupported usage %d\n", usage);
		return -EFAULT;
	}
@@ -2719,24 +2700,8 @@ static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
	if (qseecom.qsee.instance != qseecom.ce_drv.instance)
		__qseecom_enable_clk(CLK_CE_DRV);

	memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
	ireq.qsee_command_id = QSEOS_SET_KEY;
	ireq.ce = set_key_para->ce_hw;
	ireq.pipe = set_key_para->pipe;
	ireq.flags = set_key_para->flags;

	/* set both PIPE_ENC and PIPE_ENC_XTS*/
	ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;

	if (set_key_para->set_clear_key_flag ==
			QSEECOM_SET_CE_KEY_CMD)
		memcpy((void *)ireq.hash, (void *)set_key_para->hash32,
				QSEECOM_HASH_SIZE);
	else
		memset((void *)ireq.hash, 0, QSEECOM_HASH_SIZE);

	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
				&ireq, sizeof(struct qseecom_key_select_ireq),
				ireq, sizeof(struct qseecom_key_select_ireq),
				&resp, sizeof(struct qseecom_command_scm_resp));
	if (ret) {
		pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
@@ -2769,16 +2734,63 @@ static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
	return ret;
}

static int __qseecom_update_current_key_user_info(
			struct qseecom_dev_handle *data,
			enum qseecom_key_management_usage_type usage,
			struct qseecom_key_userinfo_update_ireq *ireq)
{
	struct qseecom_command_scm_resp resp;
	int ret;

	if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
		usage >= QSEOS_KM_USAGE_MAX) {
			pr_err("Error:: unsupported usage %d\n", usage);
			return -EFAULT;
	}

	__qseecom_enable_clk(CLK_QSEE);

	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
		ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
		&resp, sizeof(struct qseecom_command_scm_resp));
	if (ret) {
		pr_err("scm call to update key userinfo failed : %d\n", ret);
		__qseecom_disable_clk(CLK_QSEE);
		if (qseecom.qsee.instance != qseecom.ce_drv.instance)
			__qseecom_disable_clk(CLK_CE_DRV);
		return ret;
	}

	switch (resp.result) {
	case QSEOS_RESULT_SUCCESS:
		break;
	case QSEOS_RESULT_INCOMPLETE:
		ret = __qseecom_process_incomplete_cmd(data, &resp);
		if (ret)
			pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
					resp.result);
		break;
	case QSEOS_RESULT_FAILURE:
	default:
		pr_err("Set key scm call failed resp.result %d\n", resp.result);
		ret = -EINVAL;
		break;
	}

	__qseecom_disable_clk(CLK_QSEE);
	return ret;
}

static int qseecom_create_key(struct qseecom_dev_handle *data,
			void __user *argp)
{
	uint32_t ce_hw = 0;
	uint32_t pipe = 0;
	uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
	int ret = 0;
	uint32_t flags = 0;
	struct qseecom_set_key_parameter set_key_para;
	struct qseecom_create_key_req create_key_req;
	struct qseecom_key_generate_ireq generate_key_ireq;
	struct qseecom_key_select_ireq set_key_ireq;

	ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
	if (ret) {
@@ -2786,7 +2798,8 @@ static int qseecom_create_key(struct qseecom_dev_handle *data,
		return ret;
	}

	if (create_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
	if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
		create_key_req.usage >= QSEOS_KM_USAGE_MAX) {
		pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
		return -EFAULT;
	}
@@ -2797,23 +2810,41 @@ static int qseecom_create_key(struct qseecom_dev_handle *data,
		return -EINVAL;
	}

	generate_key_ireq.flags = flags;
	generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
	memset((void *)generate_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
	memset((void *)generate_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
	memcpy((void *)generate_key_ireq.key_id,
			(void *)key_id_array[create_key_req.usage - 1],
			QSEECOM_KEY_ID_SIZE);
	memcpy((void *)generate_key_ireq.hash32,
			(void *)create_key_req.hash32, QSEECOM_HASH_SIZE);

	ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
								key_id, flags);
					&generate_key_ireq);
	if (ret) {
		pr_err("Failed to generate key on storage: %d\n", ret);
		return -EFAULT;
	}

	set_key_para.ce_hw = ce_hw;
	set_key_para.pipe = pipe;
	memcpy(set_key_para.key_id, key_id, QSEECOM_KEY_ID_SIZE);
	set_key_para.flags = flags;
	set_key_para.set_clear_key_flag = QSEECOM_SET_CE_KEY_CMD;
	memcpy((void *)set_key_para.hash32, (void *)create_key_req.hash32,
	set_key_ireq.qsee_command_id = QSEOS_SET_KEY;
	set_key_ireq.ce = ce_hw;
	set_key_ireq.pipe = pipe;
	set_key_ireq.flags = flags;

	/* set both PIPE_ENC and PIPE_ENC_XTS*/
	set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
	memset((void *)set_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
	memset((void *)set_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
	memcpy((void *)set_key_ireq.key_id,
			(void *)key_id_array[create_key_req.usage - 1],
				QSEECOM_KEY_ID_SIZE);
	memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32,
				QSEECOM_HASH_SIZE);

	ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
								&set_key_para);
								&set_key_ireq);
	msleep(2000);
	if (ret) {
		pr_err("Failed to create key: pipe %d, ce %d: %d\n",
			pipe, ce_hw, ret);
@@ -2828,12 +2859,12 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data,
{
	uint32_t ce_hw = 0;
	uint32_t pipe = 0;
	uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
	int ret = 0;
	uint32_t flags = 0;
	int i;
	struct qseecom_wipe_key_req wipe_key_req;
	struct qseecom_set_key_parameter clear_key_para;
	struct qseecom_key_delete_ireq delete_key_ireq;
	struct qseecom_key_select_ireq clear_key_ireq;

	ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
	if (ret) {
@@ -2841,7 +2872,8 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data,
		return ret;
	}

	if (wipe_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
	if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
		wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) {
		pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
		return -EFAULT;
	}
@@ -2852,22 +2884,32 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data,
		return -EINVAL;
	}

	ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, key_id,
									flags);
	delete_key_ireq.flags = flags;
	delete_key_ireq.qsee_command_id = QSEOS_DELETE_KEY;
	memset((void *)delete_key_ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
	memcpy((void *)delete_key_ireq.key_id,
			(void *)key_id_array[wipe_key_req.usage - 1],
			QSEECOM_KEY_ID_SIZE);
	memset((void *)delete_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);

	ret = __qseecom_delete_saved_key(data, wipe_key_req.usage,
					&delete_key_ireq);
	if (ret) {
		pr_err("Failed to delete key from ssd storage: %d\n", ret);
		return -EFAULT;
	}

	/* an invalid key_id 0xff is used to indicate clear key*/
	clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
	clear_key_ireq.ce = ce_hw;
	clear_key_ireq.pipe = pipe;
	clear_key_ireq.flags = flags;
	clear_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
	for (i = 0; i < QSEECOM_KEY_ID_SIZE; i++)
		clear_key_para.key_id[i] = 0xff;
	clear_key_para.ce_hw = ce_hw;
	clear_key_para.pipe = pipe;
	clear_key_para.flags = flags;
	clear_key_para.set_clear_key_flag = QSEECOM_CLEAR_CE_KEY_CMD;
			clear_key_ireq.key_id[i] = 0xff;
	memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);

	ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
							&clear_key_para);
							&clear_key_ireq);
	if (ret) {
		pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
			pipe, ce_hw, ret);
@@ -2877,6 +2919,48 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data,
	return ret;
}

static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
			void __user *argp)
{
	int ret = 0;
	uint32_t flags = 0;
	struct qseecom_update_key_userinfo_req update_key_req;
	struct qseecom_key_userinfo_update_ireq ireq;

	ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req));
	if (ret) {
		pr_err("copy_from_user failed\n");
		return ret;
	}

	if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
		update_key_req.usage >= QSEOS_KM_USAGE_MAX) {
		pr_err("Error:: unsupported usage %d\n", update_key_req.usage);
		return -EFAULT;
	}

	ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO;
	ireq.flags = flags;
	memset(ireq.key_id, 0, QSEECOM_KEY_ID_SIZE);
	memset((void *)ireq.current_hash32, 0, QSEECOM_HASH_SIZE);
	memset((void *)ireq.new_hash32, 0, QSEECOM_HASH_SIZE);
	memcpy(ireq.key_id, key_id_array[update_key_req.usage - 1],
						QSEECOM_KEY_ID_SIZE);
	memcpy((void *)ireq.current_hash32,
		(void *)update_key_req.current_hash32, QSEECOM_HASH_SIZE);
	memcpy((void *)ireq.new_hash32,
		(void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE);

	ret = __qseecom_update_current_key_user_info(data, update_key_req.usage,
						&ireq);
	msleep(2000);
	if (ret) {
		pr_err("Failed to update key info: %d\n", ret);
		return -EFAULT;
	}
	return ret;

}
static int qseecom_is_es_activated(void __user *argp)
{
	struct qseecom_is_es_activated_req req;
@@ -3284,14 +3368,12 @@ static long qseecom_ioctl(struct file *file, unsigned cmd,
			return -EINVAL;
		}
		data->released = true;
		mutex_lock(&app_access_lock);
		atomic_inc(&data->ioctl_count);
		ret = qseecom_create_key(data, argp);
		if (ret)
			pr_err("failed to create encryption key: %d\n", ret);

		atomic_dec(&data->ioctl_count);
		mutex_unlock(&app_access_lock);
		break;
	}
	case QSEECOM_IOCTL_WIPE_KEY_REQ: {
@@ -3307,13 +3389,31 @@ static long qseecom_ioctl(struct file *file, unsigned cmd,
			return -EINVAL;
		}
		data->released = true;
		mutex_lock(&app_access_lock);
		atomic_inc(&data->ioctl_count);
		ret = qseecom_wipe_key(data, argp);
		if (ret)
			pr_err("failed to wipe encryption key: %d\n", ret);
		atomic_dec(&data->ioctl_count);
		mutex_unlock(&app_access_lock);
		break;
	}
	case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: {
		if (data->type != QSEECOM_GENERIC) {
			pr_err("update key req: invalid handle (%d)\n",
								data->type);
			ret = -EINVAL;
			break;
		}
		if (qseecom.qsee_version < QSEE_VERSION_05) {
			pr_err("Update Key feature unsupported in qsee ver %u\n",
				qseecom.qsee_version);
			return -EINVAL;
		}
		data->released = true;
		atomic_inc(&data->ioctl_count);
		ret = qseecom_update_key_user_info(data, argp);
		if (ret)
			pr_err("failed to update key user info: %d\n", ret);
		atomic_dec(&data->ioctl_count);
		break;
	}
	case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
+11 −0
Original line number Diff line number Diff line
@@ -127,6 +127,7 @@ struct qseecom_send_svc_cmd_req {

enum qseecom_key_management_usage_type {
	QSEOS_KM_USAGE_DISK_ENCRYPTION = 0x01,
	QSEOS_KM_USAGE_MAX
};

struct qseecom_create_key_req {
@@ -138,6 +139,12 @@ struct qseecom_wipe_key_req {
	enum qseecom_key_management_usage_type usage;
};

struct qseecom_update_key_userinfo_req {
	unsigned char current_hash32[QSEECOM_HASH_SIZE];
	unsigned char new_hash32[QSEECOM_HASH_SIZE];
	enum qseecom_key_management_usage_type usage;
};

#define SHA256_DIGEST_LENGTH	(256/8)
/*
 * struct qseecom_save_partition_hash_req
@@ -247,4 +254,8 @@ struct qseecom_send_modfd_listener_resp {
#define QSEECOM_IOCTL_SET_BUS_SCALING_REQ \
	_IOWR(QSEECOM_IOC_MAGIC, 23, int)

#define QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ \
	_IOWR(QSEECOM_IOC_MAGIC, 24, struct qseecom_update_key_userinfo_req)


#endif /* _UAPI_QSEECOM_H_ */