From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Yael Samet Date: Mon, 14 Aug 2017 11:23:38 +0300 Subject: [PATCH] mei: dal: add acp parser code The ACP (Admin Command Pack) file represents a Java trusted application (JTA) image to be downloaded to the DAL firmware. This patch adds ACP file parser. Change-Id: Ibc71f438b248cc9fc696db22289ad7d4962ea41c Signed-off-by: Yael Samet Signed-off-by: Tomas Winkler --- drivers/misc/mei/dal/acp_format.h | 198 ++++++++++++ drivers/misc/mei/dal/acp_parser.c | 507 ++++++++++++++++++++++++++++++ drivers/misc/mei/dal/acp_parser.h | 38 +++ 3 files changed, 743 insertions(+) create mode 100644 drivers/misc/mei/dal/acp_format.h create mode 100644 drivers/misc/mei/dal/acp_parser.c create mode 100644 drivers/misc/mei/dal/acp_parser.h diff --git a/drivers/misc/mei/dal/acp_format.h b/drivers/misc/mei/dal/acp_format.h new file mode 100644 index 000000000000..7fdef3407152 --- /dev/null +++ b/drivers/misc/mei/dal/acp_format.h @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ +/* + * Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. + */ + +#ifndef _ACP_FORMAT_H +#define _ACP_FORMAT_H + +#include + +#define AC_MAX_INS_REASONS_LENGTH 1024 +#define AC_MAX_USED_SERVICES 20 +#define AC_MAX_PROPS_LENGTH 2048 +#define AC_MAX_PACK_HASH_LEN 32 + +/** + * enum ac_cmd_id - acp file command (acp type) + * + * @AC_CMD_INVALID: invalid command + * @AC_INSTALL_SD: install new sub security domain + * @AC_UNINSTALL_SD: uninstall sub security domain + * @AC_INSTALL_JTA: install java ta + * @AC_UNINSTALL_JTA: uninstall java ta + * @AC_INSTALL_NTA: install native ta (currently NOT SUPPORTED) + * @AC_UNINSTALL_NTA: uninstall native ta (currently NOT SUPPORTED) + * @AC_UPDATE_SVL: update the security version list + * @AC_INSTALL_JTA_PROP: ta properties for installation + * @AC_CMD_NUM: number of acp commands + */ +enum ac_cmd_id { + AC_CMD_INVALID, + AC_INSTALL_SD, + AC_UNINSTALL_SD, + AC_INSTALL_JTA, + AC_UNINSTALL_JTA, + AC_INSTALL_NTA, + AC_UNINSTALL_NTA, + AC_UPDATE_SVL, + AC_INSTALL_JTA_PROP, + AC_CMD_NUM +}; + +/** + * struct ac_pack_hash - ta pack hash + * + * @data: ta hash + */ +struct ac_pack_hash { + u8 data[AC_MAX_PACK_HASH_LEN]; +} __packed; + +/** + * struct ac_pack_header - admin comman pack header + * + * @magic: magic string which represents an ACP + * @version: package format version + * @byte_order: byte order of package (0 big endian, 1 little endian) + * @reserved: reserved bytes + * @size: total package size + * @cmd_id: acp command (acp file type) + * @svn: security version number + * + * @idx_num: the number of the indexed sections + * @idx_condition: condition section offset + * @idx_data: data section offset + */ +struct ac_pack_header { + /*ACP Header*/ + u8 magic[4]; + u8 version; + u8 byte_order; + u16 reserved; + u32 size; + u32 cmd_id; + u32 svn; + + /* Index Section */ + u32 idx_num; + u32 idx_condition; + u32 idx_data; +} __packed; + +/** + * struct ac_ta_id_list - A list of ta ids which the ta + * is allowed to communicate with. + * + * @num: ta ids count + * @list: ta ids list + */ +struct ac_ta_id_list { + u32 num; + uuid_t list[0]; +} __packed; + +/** + * struct ac_prop_list - TLV list of acp properties + * + * @num: number of properties + * @len: size of all properties + * @data: acp properties. TLV format is "type\0key\0value\0" + * (e.g. string\0name\0Tom\0int\0Age\013\0) + */ +struct ac_prop_list { + u32 num; + u32 len; + s8 data[0]; +} __packed; + +/** + * struct ac_ins_reasons - list of event codes that can be + * received or posted by ta + * + * @len: event codes count + * @data: event codes list + */ +struct ac_ins_reasons { + u32 len; + u32 data[0]; +} __packed; + +/** + * struct ac_pack - general struct to hold parsed acp content + * + * @head: acp pack header + * @data: acp parsed content + */ +struct ac_pack { + struct ac_pack_header *head; + char data[0]; +} __packed; + +/** + * struct ac_ins_ta_header - ta installation header + * + * @ta_id: ta id + * @ta_svn: ta security version number + * @hash_alg_type: ta hash algorithm type + * @ta_reserved: reserved bytes + * @hash: ta pack hash + */ +struct ac_ins_ta_header { + uuid_t ta_id; + u32 ta_svn; + u8 hash_alg_type; + u8 ta_reserved[3]; + struct ac_pack_hash hash; +} __packed; + +/** + * struct ac_ins_jta_pack - ta installation information + * + * @ins_cond: ta install conditions (contains some of the manifest data, + * including security.version, applet.version, applet.platform, + * applet.api.level) + * @head: ta installation header + */ +struct ac_ins_jta_pack { + struct ac_prop_list *ins_cond; + struct ac_ins_ta_header *head; +} __packed; + +/** + * struct ac_ins_jta_prop_header - ta manifest header + * + * @mem_quota: ta heap size + * @ta_encrypted: ta encrypted by provider flag + * @padding: padding + * @allowed_inter_session_num: allowed internal session count + * @ac_groups: ta permission groups + * @timeout: ta timeout in milliseconds + */ +struct ac_ins_jta_prop_header { + u32 mem_quota; + u8 ta_encrypted; + u8 padding; + u16 allowed_inter_session_num; + u64 ac_groups; + u32 timeout; +} __packed; + +/** + * struct ac_ins_jta_prop - ta manifest + * + * @head: manifest header + * @post_reasons: list of event codes that can be posted by ta + * @reg_reasons: list of event codes that can be received by ta + * @prop: all other manifest fields (acp properties) + * @used_service_list: list of ta ids which ta is allowed to communicate with + */ +struct ac_ins_jta_prop { + struct ac_ins_jta_prop_header *head; + struct ac_ins_reasons *post_reasons; + struct ac_ins_reasons *reg_reasons; + struct ac_prop_list *prop; + struct ac_ta_id_list *used_service_list; +} __packed; + +#endif /* _ACP_FORMAT_H */ diff --git a/drivers/misc/mei/dal/acp_parser.c b/drivers/misc/mei/dal/acp_parser.c new file mode 100644 index 000000000000..462bd4860692 --- /dev/null +++ b/drivers/misc/mei/dal/acp_parser.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* + * Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. + */ + +#include +#include + +#include "acp_format.h" +#include "acp_parser.h" + +/* CSS Header + CSS Crypto Block + * Prefixes each signed ACP package + */ +#define AC_CSS_HEADER_LENGTH (128 + 520) + +/** + * struct ac_pr_state - admin command pack reader state + * + * @cur : current read position + * @head : acp file head + * @total : size of acp file + */ +struct ac_pr_state { + const char *cur; + const char *head; + unsigned int total; +}; + +/** + * ac_pr_init - init pack reader + * + * @pr: pack reader + * @data: acp file content (without CSS header) + * @n: acp file size (without CSS header) + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int ac_pr_init(struct ac_pr_state *pr, const char *data, + unsigned int n) +{ + /* check integer overflow */ + if ((size_t)data > SIZE_MAX - n) + return -EINVAL; + + pr->cur = data; + pr->head = data; + pr->total = n; + return 0; +} + +/** + * ac_pr_8b_align_move - update pack reader cur pointer after reading n_move + * bytes. Leave cur aligned to 8 bytes. + * (e.g. when n_move is 3, increase cur by 8) + * + * @pr: pack reader + * @n_move: number of bytes to move cur pointer ahead + * will be rounded up to keep cur 8 bytes aligned + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int ac_pr_8b_align_move(struct ac_pr_state *pr, size_t n_move) +{ + unsigned long offset; + const char *new_cur = pr->cur + n_move; + size_t len_from_head = new_cur - pr->head; + + if ((size_t)pr->cur > SIZE_MAX - n_move || new_cur < pr->head) + return -EINVAL; + + offset = ((8 - (len_from_head & 7)) & 7); + if ((size_t)new_cur > SIZE_MAX - offset) + return -EINVAL; + + new_cur = new_cur + offset; + if (new_cur > pr->head + pr->total) + return -EINVAL; + + pr->cur = new_cur; + return 0; +} + +/** + * ac_pr_align_move - update pack reader cur pointer after reading n_move bytes + * Leave cur aligned to 4 bytes. + * (e.g. when n_move is 1, increase cur by 4) + * + * @pr: pack reader + * @n_move: number of bytes to move cur pointer ahead + * will be rounded up to keep cur 4 bytes aligned + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int ac_pr_align_move(struct ac_pr_state *pr, size_t n_move) +{ + const char *new_cur = pr->cur + n_move; + size_t len_from_head = new_cur - pr->head; + size_t offset; + + if ((size_t)pr->cur > SIZE_MAX - n_move || new_cur < pr->head) + return -EINVAL; + + offset = ((4 - (len_from_head & 3)) & 3); + if ((size_t)new_cur > SIZE_MAX - offset) + return -EINVAL; + + new_cur = new_cur + offset; + if (new_cur > pr->head + pr->total) + return -EINVAL; + + pr->cur = new_cur; + return 0; +} + +/** + * ac_pr_move - update pack reader cur pointer after reading n_move bytes + * + * @pr: pack reader + * @n_move: number of bytes to move cur pointer ahead + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int ac_pr_move(struct ac_pr_state *pr, size_t n_move) +{ + const char *new_cur = pr->cur + n_move; + + /* integer overflow or out of acp pkg size */ + if ((size_t)pr->cur > SIZE_MAX - n_move || + new_cur > pr->head + pr->total) + return -EINVAL; + + pr->cur = new_cur; + + return 0; +} + +/** + * ac_pr_is_safe_to_read - check whether it is safe to read more n_move + * bytes from the acp file + * + * @pr: pack reader + * @n_move: number of bytes to check if it is safe to read + * + * Return: true when it is safe to read more n_move bytes + * false otherwise + */ +static bool ac_pr_is_safe_to_read(const struct ac_pr_state *pr, size_t n_move) +{ + /* pointer overflow */ + if ((size_t)pr->cur > SIZE_MAX - n_move) + return false; + + if (pr->cur + n_move > pr->head + pr->total) + return false; + + return true; +} + +/** + * ac_pr_is_end - check if cur is at the end of the acp file + * + * @pr: pack reader + * + * Return: true when cur is at the end of the acp + * false otherwise + */ +static bool ac_pr_is_end(const struct ac_pr_state *pr) +{ + return (pr->cur == pr->head + pr->total); +} + +/** + * acp_load_reasons - load list of event codes that can be + * received or posted by ta + * + * @pr: pack reader + * @reasons: out param to hold the list of event codes + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int acp_load_reasons(struct ac_pr_state *pr, + struct ac_ins_reasons **reasons) +{ + size_t len; + struct ac_ins_reasons *r; + + if (!ac_pr_is_safe_to_read(pr, sizeof(*r))) + return -EINVAL; + + r = (struct ac_ins_reasons *)pr->cur; + + if (r->len > AC_MAX_INS_REASONS_LENGTH) + return -EINVAL; + + len = sizeof(*r) + r->len * sizeof(r->data[0]); + if (!ac_pr_is_safe_to_read(pr, len)) + return -EINVAL; + + *reasons = r; + return ac_pr_align_move(pr, len); +} + +/** + * acp_load_taid_list - load list of ta ids which ta is allowed + * to communicate with + * + * @pr: pack reader + * @taid_list: out param to hold the loaded ta ids + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int acp_load_taid_list(struct ac_pr_state *pr, + struct ac_ta_id_list **taid_list) +{ + size_t len; + struct ac_ta_id_list *t; + + if (!ac_pr_is_safe_to_read(pr, sizeof(*t))) + return -EINVAL; + + t = (struct ac_ta_id_list *)pr->cur; + if (t->num > AC_MAX_USED_SERVICES) + return -EINVAL; + + len = sizeof(*t) + t->num * sizeof(t->list[0]); + + if (!ac_pr_is_safe_to_read(pr, len)) + return -EINVAL; + + *taid_list = t; + return ac_pr_align_move(pr, len); +} + +/** + * acp_load_prop - load property from acp + * + * @pr: pack reader + * @prop: out param to hold the loaded property + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int acp_load_prop(struct ac_pr_state *pr, struct ac_prop_list **prop) +{ + size_t len; + struct ac_prop_list *p; + + if (!ac_pr_is_safe_to_read(pr, sizeof(*p))) + return -EINVAL; + + p = (struct ac_prop_list *)pr->cur; + if (p->len > AC_MAX_PROPS_LENGTH) + return -EINVAL; + + len = sizeof(*p) + p->len * sizeof(p->data[0]); + + if (!ac_pr_is_safe_to_read(pr, len)) + return -EINVAL; + + *prop = p; + return ac_pr_align_move(pr, len); +} + +/** + * acp_load_ta_pack - load ta pack from acp + * + * @pr: pack reader + * @ta_pack: out param to hold the ta pack + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int acp_load_ta_pack(struct ac_pr_state *pr, char **ta_pack) +{ + size_t len; + char *t; + + /*8 byte align to obey jeff rule*/ + if (ac_pr_8b_align_move(pr, 0)) + return -EINVAL; + + t = (char *)pr->cur; + + /* + *assume ta pack is the last item of one package, + *move cursor to the end directly + */ + if (pr->cur > pr->head + pr->total) + return -EINVAL; + + len = pr->head + pr->total - pr->cur; + if (!ac_pr_is_safe_to_read(pr, len)) + return -EINVAL; + + *ta_pack = t; + return ac_pr_move(pr, len); +} + +/** + * acp_load_ins_jta_prop_head - load ta manifest header + * + * @pr: pack reader + * @head: out param to hold manifest header + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int acp_load_ins_jta_prop_head(struct ac_pr_state *pr, + struct ac_ins_jta_prop_header **head) +{ + if (!ac_pr_is_safe_to_read(pr, sizeof(**head))) + return -EINVAL; + + *head = (struct ac_ins_jta_prop_header *)pr->cur; + return ac_pr_align_move(pr, sizeof(**head)); +} + +/** + * acp_load_ins_jta_prop - load ta properties information (ta manifest) + * + * @pr: pack reader + * @pack: out param to hold ta manifest + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int acp_load_ins_jta_prop(struct ac_pr_state *pr, + struct ac_ins_jta_prop *pack) +{ + int ret; + + ret = acp_load_ins_jta_prop_head(pr, &pack->head); + if (ret) + return ret; + + ret = acp_load_reasons(pr, &pack->post_reasons); + if (ret) + return ret; + + ret = acp_load_reasons(pr, &pack->reg_reasons); + if (ret) + return ret; + + ret = acp_load_prop(pr, &pack->prop); + if (ret) + return ret; + + ret = acp_load_taid_list(pr, &pack->used_service_list); + + return ret; +} + +/** + * acp_load_ins_jta_head - load ta installation header + * + * @pr: pack reader + * @head: out param to hold the installation header + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int acp_load_ins_jta_head(struct ac_pr_state *pr, + struct ac_ins_ta_header **head) +{ + if (!ac_pr_is_safe_to_read(pr, sizeof(**head))) + return -EINVAL; + + *head = (struct ac_ins_ta_header *)pr->cur; + return ac_pr_align_move(pr, sizeof(**head)); +} + +/** + * acp_load_ins_jta - load ta installation information from acp + * + * @pr: pack reader + * @pack: out param to hold install information + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int acp_load_ins_jta(struct ac_pr_state *pr, + struct ac_ins_jta_pack *pack) +{ + int ret; + + ret = acp_load_prop(pr, &pack->ins_cond); + if (ret) + return ret; + + ret = acp_load_ins_jta_head(pr, &pack->head); + + return ret; +} + +/** + * acp_load_pack_head - load acp pack header + * + * @pr: pack reader + * @head: out param to hold the acp header + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int acp_load_pack_head(struct ac_pr_state *pr, + struct ac_pack_header **head) +{ + if (!ac_pr_is_safe_to_read(pr, sizeof(**head))) + return -EINVAL; + + *head = (struct ac_pack_header *)pr->cur; + return ac_pr_align_move(pr, sizeof(**head)); +} + +/** + * acp_load_pack - load and parse pack from acp file + * + * @raw_pack: acp file content, without the acp CSS header + * @size: acp file size (without CSS header) + * @cmd_id: command id + * @pack: out param to hold the loaded pack + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +static int acp_load_pack(const char *raw_pack, unsigned int size, + unsigned int cmd_id, struct ac_pack *pack) +{ + int ret; + struct ac_pr_state pr; + struct ac_ins_jta_pack_ext *pack_ext; + struct ac_ins_jta_prop_ext *prop_ext; + + ret = ac_pr_init(&pr, raw_pack, size); + if (ret) + return ret; + + if (cmd_id != AC_INSTALL_JTA_PROP) { + ret = acp_load_pack_head(&pr, &pack->head); + if (ret) + return ret; + } + + if (cmd_id != AC_INSTALL_JTA_PROP && cmd_id != pack->head->cmd_id) + return -EINVAL; + + switch (cmd_id) { + case AC_INSTALL_JTA: + pack_ext = (struct ac_ins_jta_pack_ext *)pack; + ret = acp_load_ins_jta(&pr, &pack_ext->cmd_pack); + if (ret) + break; + ret = acp_load_ta_pack(&pr, &pack_ext->ta_pack); + break; + case AC_INSTALL_JTA_PROP: + prop_ext = (struct ac_ins_jta_prop_ext *)pack; + ret = acp_load_ins_jta_prop(&pr, &prop_ext->cmd_pack); + if (ret) + break; + /* Note: the next section is JEFF file, + * and not ta_pack(JTA_properties+JEFF file), + * but we could reuse the ACP_load_ta_pack() here. + */ + ret = acp_load_ta_pack(&pr, &prop_ext->jeff_pack); + break; + default: + return -EINVAL; + } + + if (!ac_pr_is_end(&pr)) + return -EINVAL; + + return ret; +} + +/** + * acp_pload_ins_jta - load and parse ta pack from acp file + * + * Exported function in acp parser API + * + * @raw_data: acp file content + * @size: acp file size + * @pack: out param to hold the ta pack + * + * Return: 0 on success + * -EINVAL on invalid parameters + */ +int acp_pload_ins_jta(const void *raw_data, unsigned int size, + struct ac_ins_jta_pack_ext *pack) +{ + int ret; + + if (!raw_data || size <= AC_CSS_HEADER_LENGTH || !pack) + return -EINVAL; + + ret = acp_load_pack((const char *)raw_data + AC_CSS_HEADER_LENGTH, + size - AC_CSS_HEADER_LENGTH, + AC_INSTALL_JTA, (struct ac_pack *)pack); + + return ret; +} diff --git a/drivers/misc/mei/dal/acp_parser.h b/drivers/misc/mei/dal/acp_parser.h new file mode 100644 index 000000000000..1de625de54f2 --- /dev/null +++ b/drivers/misc/mei/dal/acp_parser.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ +/* + * Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. + */ +#ifndef _ACP_PARSER_H +#define _ACP_PARSER_H + +#include "acp_format.h" + +/** + * struct ac_ins_jta_pack_ext - parsed ta pack from acp file + * + * @head: acp pack header + * @cmd_pack: ta installation information pack + * @ta_pack: raw ta pack + */ +struct ac_ins_jta_pack_ext { + struct ac_pack_header *head; + struct ac_ins_jta_pack cmd_pack; + char *ta_pack; +} __packed; + +/** + * struct ac_ins_jta_prop_ext - parsed ta properties information + * from acp file + * + * @cmd_pack: ta installation properties pack + * @jeff_pack: ta jeff pack + */ +struct ac_ins_jta_prop_ext { + struct ac_ins_jta_prop cmd_pack; + char *jeff_pack; +} __packed; + +int acp_pload_ins_jta(const void *raw_data, unsigned int size, + struct ac_ins_jta_pack_ext *pack); + +#endif /* _ACP_PARSER_H */ -- https://clearlinux.org