From: Miquel Raynal Date: Tue, 15 May 2018 09:57:06 +0000 (+0200) Subject: tpm: disociate TPMv1.x specific and generic code X-Git-Tag: v2018.07-rc1~83 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=d677bfe2f7914367d1caa6146b34e86d0df1c75d;p=u-boot tpm: disociate TPMv1.x specific and generic code There are no changes in this commit but a new organization of the code as follow. * cmd/ directory: > move existing code from cmd/tpm.c in cmd/tpm-common.c > move specific code in cmd/tpm-v1.c > create a specific header file with generic definitions for commands only called cmd/tpm-user-utils.h * lib/ directory: > move existing code from lib/tpm.c in lib/tpm-common.c > move specific code in lib/tpm-v1.c > create a specific header file with generic definitions for the library itself called lib/tpm-utils.h * include/ directory: > move existing code from include/tpm.h in include/tpm-common.h > move specific code in include/tpm-v1.h Code designated as 'common' is compiled if TPM are used. Code designated as 'specific' is compiled only if the right specification has been selected. All files include tpm-common.h. Files in cmd/ include tpm-user-utils.h. Files in lib/ include tpm-utils.h. Depending on the specification, files may include either (not both) tpm-v1.h or tpm-v2.h. Signed-off-by: Miquel Raynal Reviewed-by: Tom Rini [trini: Fix a few more cases of tpm.h -> tpm-v1.h, some Kconfig logic] Signed-off-by: Tom Rini --- diff --git a/board/gdsys/a38x/controlcenterdc.c b/board/gdsys/a38x/controlcenterdc.c index 320bc100c9..824a08f12a 100644 --- a/board/gdsys/a38x/controlcenterdc.c +++ b/board/gdsys/a38x/controlcenterdc.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/board/gdsys/a38x/hre.c b/board/gdsys/a38x/hre.c index 961316cab7..34c4df71b2 100644 --- a/board/gdsys/a38x/hre.c +++ b/board/gdsys/a38x/hre.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/board/gdsys/a38x/keyprogram.c b/board/gdsys/a38x/keyprogram.c index f6a2747fb2..1fb5306b50 100644 --- a/board/gdsys/a38x/keyprogram.c +++ b/board/gdsys/a38x/keyprogram.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include diff --git a/board/gdsys/p1022/controlcenterd-id.c b/board/gdsys/p1022/controlcenterd-id.c index 87edf92f43..7e082dff05 100644 --- a/board/gdsys/p1022/controlcenterd-id.c +++ b/board/gdsys/p1022/controlcenterd-id.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/cmd/Makefile b/cmd/Makefile index ca6ead8e8e..6164f6e611 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -120,7 +120,8 @@ obj-$(CONFIG_CMD_TERMINAL) += terminal.o obj-$(CONFIG_CMD_TIME) += time.o obj-$(CONFIG_CMD_TRACE) += trace.o obj-$(CONFIG_HUSH_PARSER) += test.o -obj-$(CONFIG_CMD_TPM_V1) += tpm.o +obj-$(CONFIG_CMD_TPM) += tpm-common.o +obj-$(CONFIG_CMD_TPM_V1) += tpm-v1.o obj-$(CONFIG_CMD_TPM_TEST) += tpm_test.o obj-$(CONFIG_CMD_CROS_EC) += cros_ec.o obj-$(CONFIG_CMD_TSI148) += tsi148.o diff --git a/cmd/tpm-common.c b/cmd/tpm-common.c new file mode 100644 index 0000000000..6cf9fcc9ac --- /dev/null +++ b/cmd/tpm-common.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2013 The Chromium OS Authors. + */ + +#include +#include +#include +#include +#include +#include +#include "tpm-user-utils.h" + +/** + * Print a byte string in hexdecimal format, 16-bytes per line. + * + * @param data byte string to be printed + * @param count number of bytes to be printed + */ +void print_byte_string(u8 *data, size_t count) +{ + int i, print_newline = 0; + + for (i = 0; i < count; i++) { + printf(" %02x", data[i]); + print_newline = (i % 16 == 15); + if (print_newline) + putc('\n'); + } + /* Avoid duplicated newline at the end */ + if (!print_newline) + putc('\n'); +} + +/** + * Convert a text string of hexdecimal values into a byte string. + * + * @param bytes text string of hexdecimal values with no space + * between them + * @param data output buffer for byte string. The caller has to make + * sure it is large enough for storing the output. If + * NULL is passed, a large enough buffer will be allocated, + * and the caller must free it. + * @param count_ptr output variable for the length of byte string + * @return pointer to output buffer + */ +void *parse_byte_string(char *bytes, u8 *data, size_t *count_ptr) +{ + char byte[3]; + size_t count, length; + int i; + + if (!bytes) + return NULL; + length = strlen(bytes); + count = length / 2; + + if (!data) + data = malloc(count); + if (!data) + return NULL; + + byte[2] = '\0'; + for (i = 0; i < length; i += 2) { + byte[0] = bytes[i]; + byte[1] = bytes[i + 1]; + data[i / 2] = (u8)simple_strtoul(byte, NULL, 16); + } + + if (count_ptr) + *count_ptr = count; + + return data; +} + +/** + * report_return_code() - Report any error and return failure or success + * + * @param return_code TPM command return code + * @return value of enum command_ret_t + */ +int report_return_code(int return_code) +{ + if (return_code) { + printf("Error: %d\n", return_code); + return CMD_RET_FAILURE; + } else { + return CMD_RET_SUCCESS; + } +} + +/** + * Return number of values defined by a type string. + * + * @param type_str type string + * @return number of values of type string + */ +int type_string_get_num_values(const char *type_str) +{ + return strlen(type_str); +} + +/** + * Return total size of values defined by a type string. + * + * @param type_str type string + * @return total size of values of type string, or 0 if type string + * contains illegal type character. + */ +size_t type_string_get_space_size(const char *type_str) +{ + size_t size; + + for (size = 0; *type_str; type_str++) { + switch (*type_str) { + case 'b': + size += 1; + break; + case 'w': + size += 2; + break; + case 'd': + size += 4; + break; + default: + return 0; + } + } + + return size; +} + +/** + * Allocate a buffer large enough to hold values defined by a type + * string. The caller has to free the buffer. + * + * @param type_str type string + * @param count pointer for storing size of buffer + * @return pointer to buffer or NULL on error + */ +void *type_string_alloc(const char *type_str, u32 *count) +{ + void *data; + size_t size; + + size = type_string_get_space_size(type_str); + if (!size) + return NULL; + data = malloc(size); + if (data) + *count = size; + + return data; +} + +/** + * Pack values defined by a type string into a buffer. The buffer must have + * large enough space. + * + * @param type_str type string + * @param values text strings of values to be packed + * @param data output buffer of values + * @return 0 on success, non-0 on error + */ +int type_string_pack(const char *type_str, char * const values[], + u8 *data) +{ + size_t offset; + u32 value; + + for (offset = 0; *type_str; type_str++, values++) { + value = simple_strtoul(values[0], NULL, 0); + switch (*type_str) { + case 'b': + data[offset] = value; + offset += 1; + break; + case 'w': + put_unaligned_be16(value, data + offset); + offset += 2; + break; + case 'd': + put_unaligned_be32(value, data + offset); + offset += 4; + break; + default: + return -1; + } + } + + return 0; +} + +/** + * Read values defined by a type string from a buffer, and write these values + * to environment variables. + * + * @param type_str type string + * @param data input buffer of values + * @param vars names of environment variables + * @return 0 on success, non-0 on error + */ +int type_string_write_vars(const char *type_str, u8 *data, + char * const vars[]) +{ + size_t offset; + u32 value; + + for (offset = 0; *type_str; type_str++, vars++) { + switch (*type_str) { + case 'b': + value = data[offset]; + offset += 1; + break; + case 'w': + value = get_unaligned_be16(data + offset); + offset += 2; + break; + case 'd': + value = get_unaligned_be32(data + offset); + offset += 4; + break; + default: + return -1; + } + if (env_set_ulong(*vars, value)) + return -1; + } + + return 0; +} + +int get_tpm(struct udevice **devp) +{ + int rc; + + rc = uclass_first_device_err(UCLASS_TPM, devp); + if (rc) { + printf("Could not find TPM (ret=%d)\n", rc); + return CMD_RET_FAILURE; + } + + return 0; +} + +int do_tpm_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + struct udevice *dev; + char buf[80]; + int rc; + + rc = get_tpm(&dev); + if (rc) + return rc; + rc = tpm_get_desc(dev, buf, sizeof(buf)); + if (rc < 0) { + printf("Couldn't get TPM info (%d)\n", rc); + return CMD_RET_FAILURE; + } + printf("%s\n", buf); + + return 0; +} + +int do_tpm_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + if (argc != 1) + return CMD_RET_USAGE; + + return report_return_code(tpm_init()); +} + +int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + cmd_tbl_t *tpm_commands, *cmd; + unsigned int size; + + if (argc < 2) + return CMD_RET_USAGE; + + tpm_commands = get_tpm_commands(&size); + + cmd = find_cmd_tbl(argv[1], tpm_commands, size); + if (!cmd) + return CMD_RET_USAGE; + + return cmd->cmd(cmdtp, flag, argc - 1, argv + 1); +} diff --git a/cmd/tpm-user-utils.h b/cmd/tpm-user-utils.h new file mode 100644 index 0000000000..8ce9861784 --- /dev/null +++ b/cmd/tpm-user-utils.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + */ + +#ifndef __TPM_USER_UTILS_H +#define __TPM_USER_UTILS_H + +void print_byte_string(u8 *data, size_t count); +void *parse_byte_string(char *bytes, u8 *data, size_t *count_ptr); +int report_return_code(int return_code); +int type_string_get_num_values(const char *type_str); +size_t type_string_get_space_size(const char *type_str); +void *type_string_alloc(const char *type_str, u32 *count); +int type_string_pack(const char *type_str, char * const values[], u8 *data); +int type_string_write_vars(const char *type_str, u8 *data, char * const vars[]); +int get_tpm(struct udevice **devp); + +int do_tpm_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]); +int do_tpm_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]); +int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); + +#endif /* __TPM_USER_UTILS_H */ diff --git a/cmd/tpm-v1.c b/cmd/tpm-v1.c new file mode 100644 index 0000000000..0874c4d7ba --- /dev/null +++ b/cmd/tpm-v1.c @@ -0,0 +1,723 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2013 The Chromium OS Authors. + */ + +#include +#include +#include +#include +#include +#include "tpm-user-utils.h" + +static int do_tpm_startup(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + enum tpm_startup_type mode; + + if (argc != 2) + return CMD_RET_USAGE; + if (!strcasecmp("TPM_ST_CLEAR", argv[1])) { + mode = TPM_ST_CLEAR; + } else if (!strcasecmp("TPM_ST_STATE", argv[1])) { + mode = TPM_ST_STATE; + } else if (!strcasecmp("TPM_ST_DEACTIVATED", argv[1])) { + mode = TPM_ST_DEACTIVATED; + } else { + printf("Couldn't recognize mode string: %s\n", argv[1]); + return CMD_RET_FAILURE; + } + + return report_return_code(tpm_startup(mode)); +} + +static int do_tpm_nv_define_space(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 index, perm, size; + + if (argc != 4) + return CMD_RET_USAGE; + index = simple_strtoul(argv[1], NULL, 0); + perm = simple_strtoul(argv[2], NULL, 0); + size = simple_strtoul(argv[3], NULL, 0); + + return report_return_code(tpm_nv_define_space(index, perm, size)); +} + +static int do_tpm_nv_read_value(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 index, count, rc; + void *data; + + if (argc != 4) + return CMD_RET_USAGE; + index = simple_strtoul(argv[1], NULL, 0); + data = (void *)simple_strtoul(argv[2], NULL, 0); + count = simple_strtoul(argv[3], NULL, 0); + + rc = tpm_nv_read_value(index, data, count); + if (!rc) { + puts("area content:\n"); + print_byte_string(data, count); + } + + return report_return_code(rc); +} + +static int do_tpm_nv_write_value(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 index, rc; + size_t count; + void *data; + + if (argc != 3) + return CMD_RET_USAGE; + index = simple_strtoul(argv[1], NULL, 0); + data = parse_byte_string(argv[2], NULL, &count); + if (!data) { + printf("Couldn't parse byte string %s\n", argv[2]); + return CMD_RET_FAILURE; + } + + rc = tpm_nv_write_value(index, data, count); + free(data); + + return report_return_code(rc); +} + +static int do_tpm_extend(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 index, rc; + u8 in_digest[20], out_digest[20]; + + if (argc != 3) + return CMD_RET_USAGE; + index = simple_strtoul(argv[1], NULL, 0); + if (!parse_byte_string(argv[2], in_digest, NULL)) { + printf("Couldn't parse byte string %s\n", argv[2]); + return CMD_RET_FAILURE; + } + + rc = tpm_extend(index, in_digest, out_digest); + if (!rc) { + puts("PCR value after execution of the command:\n"); + print_byte_string(out_digest, sizeof(out_digest)); + } + + return report_return_code(rc); +} + +static int do_tpm_pcr_read(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 index, count, rc; + void *data; + + if (argc != 4) + return CMD_RET_USAGE; + index = simple_strtoul(argv[1], NULL, 0); + data = (void *)simple_strtoul(argv[2], NULL, 0); + count = simple_strtoul(argv[3], NULL, 0); + + rc = tpm_pcr_read(index, data, count); + if (!rc) { + puts("Named PCR content:\n"); + print_byte_string(data, count); + } + + return report_return_code(rc); +} + +static int do_tpm_tsc_physical_presence(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u16 presence; + + if (argc != 2) + return CMD_RET_USAGE; + presence = (u16)simple_strtoul(argv[1], NULL, 0); + + return report_return_code(tpm_tsc_physical_presence(presence)); +} + +static int do_tpm_read_pubek(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 count, rc; + void *data; + + if (argc != 3) + return CMD_RET_USAGE; + data = (void *)simple_strtoul(argv[1], NULL, 0); + count = simple_strtoul(argv[2], NULL, 0); + + rc = tpm_read_pubek(data, count); + if (!rc) { + puts("pubek value:\n"); + print_byte_string(data, count); + } + + return report_return_code(rc); +} + +static int do_tpm_physical_set_deactivated(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u8 state; + + if (argc != 2) + return CMD_RET_USAGE; + state = (u8)simple_strtoul(argv[1], NULL, 0); + + return report_return_code(tpm_physical_set_deactivated(state)); +} + +static int do_tpm_get_capability(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 cap_area, sub_cap, rc; + void *cap; + size_t count; + + if (argc != 5) + return CMD_RET_USAGE; + cap_area = simple_strtoul(argv[1], NULL, 0); + sub_cap = simple_strtoul(argv[2], NULL, 0); + cap = (void *)simple_strtoul(argv[3], NULL, 0); + count = simple_strtoul(argv[4], NULL, 0); + + rc = tpm_get_capability(cap_area, sub_cap, cap, count); + if (!rc) { + puts("capability information:\n"); + print_byte_string(cap, count); + } + + return report_return_code(rc); +} + +static int do_tpm_raw_transfer(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + struct udevice *dev; + void *command; + u8 response[1024]; + size_t count, response_length = sizeof(response); + u32 rc; + + command = parse_byte_string(argv[1], NULL, &count); + if (!command) { + printf("Couldn't parse byte string %s\n", argv[1]); + return CMD_RET_FAILURE; + } + + rc = get_tpm(&dev); + if (rc) + return rc; + + rc = tpm_xfer(dev, command, count, response, &response_length); + free(command); + if (!rc) { + puts("tpm response:\n"); + print_byte_string(response, response_length); + } + + return report_return_code(rc); +} + +static int do_tpm_nv_define(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 index, perm, size; + + if (argc != 4) + return CMD_RET_USAGE; + size = type_string_get_space_size(argv[1]); + if (!size) { + printf("Couldn't parse arguments\n"); + return CMD_RET_USAGE; + } + index = simple_strtoul(argv[2], NULL, 0); + perm = simple_strtoul(argv[3], NULL, 0); + + return report_return_code(tpm_nv_define_space(index, perm, size)); +} + +static int do_tpm_nv_read(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 index, count, err; + void *data; + + if (argc < 3) + return CMD_RET_USAGE; + if (argc != 3 + type_string_get_num_values(argv[1])) + return CMD_RET_USAGE; + index = simple_strtoul(argv[2], NULL, 0); + data = type_string_alloc(argv[1], &count); + if (!data) { + printf("Couldn't parse arguments\n"); + return CMD_RET_USAGE; + } + + err = tpm_nv_read_value(index, data, count); + if (!err) { + if (type_string_write_vars(argv[1], data, argv + 3)) { + printf("Couldn't write to variables\n"); + err = ~0; + } + } + free(data); + + return report_return_code(err); +} + +static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 index, count, err; + void *data; + + if (argc < 3) + return CMD_RET_USAGE; + if (argc != 3 + type_string_get_num_values(argv[1])) + return CMD_RET_USAGE; + index = simple_strtoul(argv[2], NULL, 0); + data = type_string_alloc(argv[1], &count); + if (!data) { + printf("Couldn't parse arguments\n"); + return CMD_RET_USAGE; + } + if (type_string_pack(argv[1], argv + 3, data)) { + printf("Couldn't parse arguments\n"); + free(data); + return CMD_RET_USAGE; + } + + err = tpm_nv_write_value(index, data, count); + free(data); + + return report_return_code(err); +} + +#ifdef CONFIG_TPM_AUTH_SESSIONS + +static int do_tpm_oiap(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 auth_handle, err; + + err = tpm_oiap(&auth_handle); + + return report_return_code(err); +} + +#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 +static int do_tpm_load_key_by_sha1(cmd_tbl_t *cmdtp, int flag, int argc, char * + const argv[]) +{ + u32 parent_handle = 0; + u32 key_len, key_handle, err; + u8 usage_auth[DIGEST_LENGTH]; + u8 parent_hash[DIGEST_LENGTH]; + void *key; + + if (argc < 5) + return CMD_RET_USAGE; + + parse_byte_string(argv[1], parent_hash, NULL); + key = (void *)simple_strtoul(argv[2], NULL, 0); + key_len = simple_strtoul(argv[3], NULL, 0); + if (strlen(argv[4]) != 2 * DIGEST_LENGTH) + return CMD_RET_FAILURE; + parse_byte_string(argv[4], usage_auth, NULL); + + err = tpm_find_key_sha1(usage_auth, parent_hash, &parent_handle); + if (err) { + printf("Could not find matching parent key (err = %d)\n", err); + return CMD_RET_FAILURE; + } + + printf("Found parent key %08x\n", parent_handle); + + err = tpm_load_key2_oiap(parent_handle, key, key_len, usage_auth, + &key_handle); + if (!err) { + printf("Key handle is 0x%x\n", key_handle); + env_set_hex("key_handle", key_handle); + } + + return report_return_code(err); +} +#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ + +static int do_tpm_load_key2_oiap(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 parent_handle, key_len, key_handle, err; + u8 usage_auth[DIGEST_LENGTH]; + void *key; + + if (argc < 5) + return CMD_RET_USAGE; + + parent_handle = simple_strtoul(argv[1], NULL, 0); + key = (void *)simple_strtoul(argv[2], NULL, 0); + key_len = simple_strtoul(argv[3], NULL, 0); + if (strlen(argv[4]) != 2 * DIGEST_LENGTH) + return CMD_RET_FAILURE; + parse_byte_string(argv[4], usage_auth, NULL); + + err = tpm_load_key2_oiap(parent_handle, key, key_len, usage_auth, + &key_handle); + if (!err) + printf("Key handle is 0x%x\n", key_handle); + + return report_return_code(err); +} + +static int do_tpm_get_pub_key_oiap(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + u32 key_handle, err; + u8 usage_auth[DIGEST_LENGTH]; + u8 pub_key_buffer[TPM_PUBKEY_MAX_LENGTH]; + size_t pub_key_len = sizeof(pub_key_buffer); + + if (argc < 3) + return CMD_RET_USAGE; + + key_handle = simple_strtoul(argv[1], NULL, 0); + if (strlen(argv[2]) != 2 * DIGEST_LENGTH) + return CMD_RET_FAILURE; + parse_byte_string(argv[2], usage_auth, NULL); + + err = tpm_get_pub_key_oiap(key_handle, usage_auth, pub_key_buffer, + &pub_key_len); + if (!err) { + printf("dump of received pub key structure:\n"); + print_byte_string(pub_key_buffer, pub_key_len); + } + return report_return_code(err); +} + +TPM_COMMAND_NO_ARG(tpm_end_oiap) + +#endif /* CONFIG_TPM_AUTH_SESSIONS */ + +#ifdef CONFIG_TPM_FLUSH_RESOURCES +static int do_tpm_flush(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + int type = 0; + + if (argc != 3) + return CMD_RET_USAGE; + + if (!strcasecmp(argv[1], "key")) + type = TPM_RT_KEY; + else if (!strcasecmp(argv[1], "auth")) + type = TPM_RT_AUTH; + else if (!strcasecmp(argv[1], "hash")) + type = TPM_RT_HASH; + else if (!strcasecmp(argv[1], "trans")) + type = TPM_RT_TRANS; + else if (!strcasecmp(argv[1], "context")) + type = TPM_RT_CONTEXT; + else if (!strcasecmp(argv[1], "counter")) + type = TPM_RT_COUNTER; + else if (!strcasecmp(argv[1], "delegate")) + type = TPM_RT_DELEGATE; + else if (!strcasecmp(argv[1], "daa_tpm")) + type = TPM_RT_DAA_TPM; + else if (!strcasecmp(argv[1], "daa_v0")) + type = TPM_RT_DAA_V0; + else if (!strcasecmp(argv[1], "daa_v1")) + type = TPM_RT_DAA_V1; + + if (!type) { + printf("Resource type %s unknown.\n", argv[1]); + return -1; + } + + if (!strcasecmp(argv[2], "all")) { + u16 res_count; + u8 buf[288]; + u8 *ptr; + int err; + uint i; + + /* fetch list of already loaded resources in the TPM */ + err = tpm_get_capability(TPM_CAP_HANDLE, type, buf, + sizeof(buf)); + if (err) { + printf("tpm_get_capability returned error %d.\n", err); + return -1; + } + res_count = get_unaligned_be16(buf); + ptr = buf + 2; + for (i = 0; i < res_count; ++i, ptr += 4) + tpm_flush_specific(get_unaligned_be32(ptr), type); + } else { + u32 handle = simple_strtoul(argv[2], NULL, 0); + + if (!handle) { + printf("Illegal resource handle %s\n", argv[2]); + return -1; + } + tpm_flush_specific(cpu_to_be32(handle), type); + } + + return 0; +} +#endif /* CONFIG_TPM_FLUSH_RESOURCES */ + +#ifdef CONFIG_TPM_LIST_RESOURCES +static int do_tpm_list(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + int type = 0; + u16 res_count; + u8 buf[288]; + u8 *ptr; + int err; + uint i; + + if (argc != 2) + return CMD_RET_USAGE; + + if (!strcasecmp(argv[1], "key")) + type = TPM_RT_KEY; + else if (!strcasecmp(argv[1], "auth")) + type = TPM_RT_AUTH; + else if (!strcasecmp(argv[1], "hash")) + type = TPM_RT_HASH; + else if (!strcasecmp(argv[1], "trans")) + type = TPM_RT_TRANS; + else if (!strcasecmp(argv[1], "context")) + type = TPM_RT_CONTEXT; + else if (!strcasecmp(argv[1], "counter")) + type = TPM_RT_COUNTER; + else if (!strcasecmp(argv[1], "delegate")) + type = TPM_RT_DELEGATE; + else if (!strcasecmp(argv[1], "daa_tpm")) + type = TPM_RT_DAA_TPM; + else if (!strcasecmp(argv[1], "daa_v0")) + type = TPM_RT_DAA_V0; + else if (!strcasecmp(argv[1], "daa_v1")) + type = TPM_RT_DAA_V1; + + if (!type) { + printf("Resource type %s unknown.\n", argv[1]); + return -1; + } + + /* fetch list of already loaded resources in the TPM */ + err = tpm_get_capability(TPM_CAP_HANDLE, type, buf, + sizeof(buf)); + if (err) { + printf("tpm_get_capability returned error %d.\n", err); + return -1; + } + res_count = get_unaligned_be16(buf); + ptr = buf + 2; + + printf("Resources of type %s (%02x):\n", argv[1], type); + if (!res_count) { + puts("None\n"); + } else { + for (i = 0; i < res_count; ++i, ptr += 4) + printf("Index %d: %08x\n", i, get_unaligned_be32(ptr)); + } + + return 0; +} +#endif /* CONFIG_TPM_LIST_RESOURCES */ + +TPM_COMMAND_NO_ARG(tpm_self_test_full) +TPM_COMMAND_NO_ARG(tpm_continue_self_test) +TPM_COMMAND_NO_ARG(tpm_force_clear) +TPM_COMMAND_NO_ARG(tpm_physical_enable) +TPM_COMMAND_NO_ARG(tpm_physical_disable) + +static cmd_tbl_t tpm1_commands[] = { + U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""), + U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""), + U_BOOT_CMD_MKENT(startup, 0, 1, + do_tpm_startup, "", ""), + U_BOOT_CMD_MKENT(self_test_full, 0, 1, + do_tpm_self_test_full, "", ""), + U_BOOT_CMD_MKENT(continue_self_test, 0, 1, + do_tpm_continue_self_test, "", ""), + U_BOOT_CMD_MKENT(force_clear, 0, 1, + do_tpm_force_clear, "", ""), + U_BOOT_CMD_MKENT(physical_enable, 0, 1, + do_tpm_physical_enable, "", ""), + U_BOOT_CMD_MKENT(physical_disable, 0, 1, + do_tpm_physical_disable, "", ""), + U_BOOT_CMD_MKENT(nv_define_space, 0, 1, + do_tpm_nv_define_space, "", ""), + U_BOOT_CMD_MKENT(nv_read_value, 0, 1, + do_tpm_nv_read_value, "", ""), + U_BOOT_CMD_MKENT(nv_write_value, 0, 1, + do_tpm_nv_write_value, "", ""), + U_BOOT_CMD_MKENT(extend, 0, 1, + do_tpm_extend, "", ""), + U_BOOT_CMD_MKENT(pcr_read, 0, 1, + do_tpm_pcr_read, "", ""), + U_BOOT_CMD_MKENT(tsc_physical_presence, 0, 1, + do_tpm_tsc_physical_presence, "", ""), + U_BOOT_CMD_MKENT(read_pubek, 0, 1, + do_tpm_read_pubek, "", ""), + U_BOOT_CMD_MKENT(physical_set_deactivated, 0, 1, + do_tpm_physical_set_deactivated, "", ""), + U_BOOT_CMD_MKENT(get_capability, 0, 1, + do_tpm_get_capability, "", ""), + U_BOOT_CMD_MKENT(raw_transfer, 0, 1, + do_tpm_raw_transfer, "", ""), + U_BOOT_CMD_MKENT(nv_define, 0, 1, + do_tpm_nv_define, "", ""), + U_BOOT_CMD_MKENT(nv_read, 0, 1, + do_tpm_nv_read, "", ""), + U_BOOT_CMD_MKENT(nv_write, 0, 1, + do_tpm_nv_write, "", ""), +#ifdef CONFIG_TPM_AUTH_SESSIONS + U_BOOT_CMD_MKENT(oiap, 0, 1, + do_tpm_oiap, "", ""), + U_BOOT_CMD_MKENT(end_oiap, 0, 1, + do_tpm_end_oiap, "", ""), + U_BOOT_CMD_MKENT(load_key2_oiap, 0, 1, + do_tpm_load_key2_oiap, "", ""), +#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 + U_BOOT_CMD_MKENT(load_key_by_sha1, 0, 1, + do_tpm_load_key_by_sha1, "", ""), +#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ + U_BOOT_CMD_MKENT(get_pub_key_oiap, 0, 1, + do_tpm_get_pub_key_oiap, "", ""), +#endif /* CONFIG_TPM_AUTH_SESSIONS */ +#ifdef CONFIG_TPM_FLUSH_RESOURCES + U_BOOT_CMD_MKENT(flush, 0, 1, + do_tpm_flush, "", ""), +#endif /* CONFIG_TPM_FLUSH_RESOURCES */ +#ifdef CONFIG_TPM_LIST_RESOURCES + U_BOOT_CMD_MKENT(list, 0, 1, + do_tpm_list, "", ""), +#endif /* CONFIG_TPM_LIST_RESOURCES */ +}; + +cmd_tbl_t *get_tpm_commands(unsigned int *size) +{ + *size = ARRAY_SIZE(tpm1_commands); + + return tpm1_commands; +} + +U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm, +"Issue a TPMv1.x command", +"cmd args...\n" +" - Issue TPM command with arguments .\n" +"Admin Startup and State Commands:\n" +" info - Show information about the TPM\n" +" init\n" +" - Put TPM into a state where it waits for 'startup' command.\n" +" startup mode\n" +" - Issue TPM_Starup command. is one of TPM_ST_CLEAR,\n" +" TPM_ST_STATE, and TPM_ST_DEACTIVATED.\n" +"Admin Testing Commands:\n" +" self_test_full\n" +" - Test all of the TPM capabilities.\n" +" continue_self_test\n" +" - Inform TPM that it should complete the self-test.\n" +"Admin Opt-in Commands:\n" +" physical_enable\n" +" - Set the PERMANENT disable flag to FALSE using physical presence as\n" +" authorization.\n" +" physical_disable\n" +" - Set the PERMANENT disable flag to TRUE using physical presence as\n" +" authorization.\n" +" physical_set_deactivated 0|1\n" +" - Set deactivated flag.\n" +"Admin Ownership Commands:\n" +" force_clear\n" +" - Issue TPM_ForceClear command.\n" +" tsc_physical_presence flags\n" +" - Set TPM device's Physical Presence flags to .\n" +"The Capability Commands:\n" +" get_capability cap_area sub_cap addr count\n" +" - Read bytes of TPM capability indexed by and\n" +" to memory address .\n" +#if defined(CONFIG_TPM_FLUSH_RESOURCES) || defined(CONFIG_TPM_LIST_RESOURCES) +"Resource management functions\n" +#endif +#ifdef CONFIG_TPM_FLUSH_RESOURCES +" flush resource_type id\n" +" - flushes a resource of type (may be one of key, auth,\n" +" hash, trans, context, counter, delegate, daa_tpm, daa_v0, daa_v1),\n" +" and id from the TPM. Use an of \"all\" to flush all\n" +" resources of that type.\n" +#endif /* CONFIG_TPM_FLUSH_RESOURCES */ +#ifdef CONFIG_TPM_LIST_RESOURCES +" list resource_type\n" +" - lists resources of type (may be one of key, auth,\n" +" hash, trans, context, counter, delegate, daa_tpm, daa_v0, daa_v1),\n" +" contained in the TPM.\n" +#endif /* CONFIG_TPM_LIST_RESOURCES */ +#ifdef CONFIG_TPM_AUTH_SESSIONS +"Storage functions\n" +" loadkey2_oiap parent_handle key_addr key_len usage_auth\n" +" - loads a key data from memory address , bytes\n" +" into TPM using the parent key with authorization\n" +" (20 bytes hex string).\n" +#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 +" load_key_by_sha1 parent_hash key_addr key_len usage_auth\n" +" - loads a key data from memory address , bytes\n" +" into TPM using the parent hash (20 bytes hex string)\n" +" with authorization (20 bytes hex string).\n" +#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ +" get_pub_key_oiap key_handle usage_auth\n" +" - get the public key portion of a loaded key using\n" +" authorization (20 bytes hex string)\n" +#endif /* CONFIG_TPM_AUTH_SESSIONS */ +"Endorsement Key Handling Commands:\n" +" read_pubek addr count\n" +" - Read bytes of the public endorsement key to memory\n" +" address \n" +"Integrity Collection and Reporting Commands:\n" +" extend index digest_hex_string\n" +" - Add a new measurement to a PCR. Update PCR with the 20-bytes\n" +" \n" +" pcr_read index addr count\n" +" - Read bytes from PCR to memory address .\n" +#ifdef CONFIG_TPM_AUTH_SESSIONS +"Authorization Sessions\n" +" oiap\n" +" - setup an OIAP session\n" +" end_oiap\n" +" - terminates an active OIAP session\n" +#endif /* CONFIG_TPM_AUTH_SESSIONS */ +"Non-volatile Storage Commands:\n" +" nv_define_space index permission size\n" +" - Establish a space at index with of bytes.\n" +" nv_read_value index addr count\n" +" - Read bytes from space to memory address .\n" +" nv_write_value index addr count\n" +" - Write bytes from memory address to space .\n" +"Miscellaneous helper functions:\n" +" raw_transfer byte_string\n" +" - Send a byte string to TPM and print the response.\n" +" Non-volatile storage helper functions:\n" +" These helper functions treat a non-volatile space as a non-padded\n" +" sequence of integer values. These integer values are defined by a type\n" +" string, which is a text string of 'bwd' characters: 'b' means a 8-bit\n" +" value, 'w' 16-bit value, 'd' 32-bit value. All helper functions take\n" +" a type string as their first argument.\n" +" nv_define type_string index perm\n" +" - Define a space with permission .\n" +" nv_read types_string index vars...\n" +" - Read from space to environment variables .\n" +" nv_write types_string index values...\n" +" - Write to space from values .\n" +); diff --git a/cmd/tpm.c b/cmd/tpm.c deleted file mode 100644 index e0cd8410f5..0000000000 --- a/cmd/tpm.c +++ /dev/null @@ -1,1001 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2013 The Chromium OS Authors. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* Useful constants */ -enum { - DIGEST_LENGTH = 20, - /* max lengths, valid for RSA keys <= 2048 bits */ - TPM_PUBKEY_MAX_LENGTH = 288, -}; - -/** - * Print a byte string in hexdecimal format, 16-bytes per line. - * - * @param data byte string to be printed - * @param count number of bytes to be printed - */ -static void print_byte_string(u8 *data, size_t count) -{ - int i, print_newline = 0; - - for (i = 0; i < count; i++) { - printf(" %02x", data[i]); - print_newline = (i % 16 == 15); - if (print_newline) - putc('\n'); - } - /* Avoid duplicated newline at the end */ - if (!print_newline) - putc('\n'); -} - -/** - * Convert a text string of hexdecimal values into a byte string. - * - * @param bytes text string of hexdecimal values with no space - * between them - * @param data output buffer for byte string. The caller has to make - * sure it is large enough for storing the output. If - * NULL is passed, a large enough buffer will be allocated, - * and the caller must free it. - * @param count_ptr output variable for the length of byte string - * @return pointer to output buffer - */ -static void *parse_byte_string(char *bytes, u8 *data, size_t *count_ptr) -{ - char byte[3]; - size_t count, length; - int i; - - if (!bytes) - return NULL; - length = strlen(bytes); - count = length / 2; - - if (!data) - data = malloc(count); - if (!data) - return NULL; - - byte[2] = '\0'; - for (i = 0; i < length; i += 2) { - byte[0] = bytes[i]; - byte[1] = bytes[i + 1]; - data[i / 2] = (u8)simple_strtoul(byte, NULL, 16); - } - - if (count_ptr) - *count_ptr = count; - - return data; -} - -/** - * report_return_code() - Report any error and return failure or success - * - * @param return_code TPM command return code - * @return value of enum command_ret_t - */ -static int report_return_code(int return_code) -{ - if (return_code) { - printf("Error: %d\n", return_code); - return CMD_RET_FAILURE; - } else { - return CMD_RET_SUCCESS; - } -} - -/** - * Return number of values defined by a type string. - * - * @param type_str type string - * @return number of values of type string - */ -static int type_string_get_num_values(const char *type_str) -{ - return strlen(type_str); -} - -/** - * Return total size of values defined by a type string. - * - * @param type_str type string - * @return total size of values of type string, or 0 if type string - * contains illegal type character. - */ -static size_t type_string_get_space_size(const char *type_str) -{ - size_t size; - - for (size = 0; *type_str; type_str++) { - switch (*type_str) { - case 'b': - size += 1; - break; - case 'w': - size += 2; - break; - case 'd': - size += 4; - break; - default: - return 0; - } - } - - return size; -} - -/** - * Allocate a buffer large enough to hold values defined by a type - * string. The caller has to free the buffer. - * - * @param type_str type string - * @param count pointer for storing size of buffer - * @return pointer to buffer or NULL on error - */ -static void *type_string_alloc(const char *type_str, u32 *count) -{ - void *data; - size_t size; - - size = type_string_get_space_size(type_str); - if (!size) - return NULL; - data = malloc(size); - if (data) - *count = size; - - return data; -} - -/** - * Pack values defined by a type string into a buffer. The buffer must have - * large enough space. - * - * @param type_str type string - * @param values text strings of values to be packed - * @param data output buffer of values - * @return 0 on success, non-0 on error - */ -static int type_string_pack(const char *type_str, char * const values[], - u8 *data) -{ - size_t offset; - u32 value; - - for (offset = 0; *type_str; type_str++, values++) { - value = simple_strtoul(values[0], NULL, 0); - switch (*type_str) { - case 'b': - data[offset] = value; - offset += 1; - break; - case 'w': - put_unaligned_be16(value, data + offset); - offset += 2; - break; - case 'd': - put_unaligned_be32(value, data + offset); - offset += 4; - break; - default: - return -1; - } - } - - return 0; -} - -/** - * Read values defined by a type string from a buffer, and write these values - * to environment variables. - * - * @param type_str type string - * @param data input buffer of values - * @param vars names of environment variables - * @return 0 on success, non-0 on error - */ -static int type_string_write_vars(const char *type_str, u8 *data, - char * const vars[]) -{ - size_t offset; - u32 value; - - for (offset = 0; *type_str; type_str++, vars++) { - switch (*type_str) { - case 'b': - value = data[offset]; - offset += 1; - break; - case 'w': - value = get_unaligned_be16(data + offset); - offset += 2; - break; - case 'd': - value = get_unaligned_be32(data + offset); - offset += 4; - break; - default: - return -1; - } - if (env_set_ulong(*vars, value)) - return -1; - } - - return 0; -} - -static int do_tpm_startup(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - enum tpm_startup_type mode; - - if (argc != 2) - return CMD_RET_USAGE; - if (!strcasecmp("TPM_ST_CLEAR", argv[1])) { - mode = TPM_ST_CLEAR; - } else if (!strcasecmp("TPM_ST_STATE", argv[1])) { - mode = TPM_ST_STATE; - } else if (!strcasecmp("TPM_ST_DEACTIVATED", argv[1])) { - mode = TPM_ST_DEACTIVATED; - } else { - printf("Couldn't recognize mode string: %s\n", argv[1]); - return CMD_RET_FAILURE; - } - - return report_return_code(tpm_startup(mode)); -} - -static int do_tpm_nv_define_space(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 index, perm, size; - - if (argc != 4) - return CMD_RET_USAGE; - index = simple_strtoul(argv[1], NULL, 0); - perm = simple_strtoul(argv[2], NULL, 0); - size = simple_strtoul(argv[3], NULL, 0); - - return report_return_code(tpm_nv_define_space(index, perm, size)); -} - -static int do_tpm_nv_read_value(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 index, count, rc; - void *data; - - if (argc != 4) - return CMD_RET_USAGE; - index = simple_strtoul(argv[1], NULL, 0); - data = (void *)simple_strtoul(argv[2], NULL, 0); - count = simple_strtoul(argv[3], NULL, 0); - - rc = tpm_nv_read_value(index, data, count); - if (!rc) { - puts("area content:\n"); - print_byte_string(data, count); - } - - return report_return_code(rc); -} - -static int do_tpm_nv_write_value(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 index, rc; - size_t count; - void *data; - - if (argc != 3) - return CMD_RET_USAGE; - index = simple_strtoul(argv[1], NULL, 0); - data = parse_byte_string(argv[2], NULL, &count); - if (!data) { - printf("Couldn't parse byte string %s\n", argv[2]); - return CMD_RET_FAILURE; - } - - rc = tpm_nv_write_value(index, data, count); - free(data); - - return report_return_code(rc); -} - -static int do_tpm_extend(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 index, rc; - u8 in_digest[20], out_digest[20]; - - if (argc != 3) - return CMD_RET_USAGE; - index = simple_strtoul(argv[1], NULL, 0); - if (!parse_byte_string(argv[2], in_digest, NULL)) { - printf("Couldn't parse byte string %s\n", argv[2]); - return CMD_RET_FAILURE; - } - - rc = tpm_extend(index, in_digest, out_digest); - if (!rc) { - puts("PCR value after execution of the command:\n"); - print_byte_string(out_digest, sizeof(out_digest)); - } - - return report_return_code(rc); -} - -static int do_tpm_pcr_read(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 index, count, rc; - void *data; - - if (argc != 4) - return CMD_RET_USAGE; - index = simple_strtoul(argv[1], NULL, 0); - data = (void *)simple_strtoul(argv[2], NULL, 0); - count = simple_strtoul(argv[3], NULL, 0); - - rc = tpm_pcr_read(index, data, count); - if (!rc) { - puts("Named PCR content:\n"); - print_byte_string(data, count); - } - - return report_return_code(rc); -} - -static int do_tpm_tsc_physical_presence(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u16 presence; - - if (argc != 2) - return CMD_RET_USAGE; - presence = (u16)simple_strtoul(argv[1], NULL, 0); - - return report_return_code(tpm_tsc_physical_presence(presence)); -} - -static int do_tpm_read_pubek(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 count, rc; - void *data; - - if (argc != 3) - return CMD_RET_USAGE; - data = (void *)simple_strtoul(argv[1], NULL, 0); - count = simple_strtoul(argv[2], NULL, 0); - - rc = tpm_read_pubek(data, count); - if (!rc) { - puts("pubek value:\n"); - print_byte_string(data, count); - } - - return report_return_code(rc); -} - -static int do_tpm_physical_set_deactivated(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u8 state; - - if (argc != 2) - return CMD_RET_USAGE; - state = (u8)simple_strtoul(argv[1], NULL, 0); - - return report_return_code(tpm_physical_set_deactivated(state)); -} - -static int do_tpm_get_capability(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 cap_area, sub_cap, rc; - void *cap; - size_t count; - - if (argc != 5) - return CMD_RET_USAGE; - cap_area = simple_strtoul(argv[1], NULL, 0); - sub_cap = simple_strtoul(argv[2], NULL, 0); - cap = (void *)simple_strtoul(argv[3], NULL, 0); - count = simple_strtoul(argv[4], NULL, 0); - - rc = tpm_get_capability(cap_area, sub_cap, cap, count); - if (!rc) { - puts("capability information:\n"); - print_byte_string(cap, count); - } - - return report_return_code(rc); -} - -#define TPM_COMMAND_NO_ARG(cmd) \ -static int do_##cmd(cmd_tbl_t *cmdtp, int flag, \ - int argc, char * const argv[]) \ -{ \ - if (argc != 1) \ - return CMD_RET_USAGE; \ - return report_return_code(cmd()); \ -} - -TPM_COMMAND_NO_ARG(tpm_init) -TPM_COMMAND_NO_ARG(tpm_self_test_full) -TPM_COMMAND_NO_ARG(tpm_continue_self_test) -TPM_COMMAND_NO_ARG(tpm_force_clear) -TPM_COMMAND_NO_ARG(tpm_physical_enable) -TPM_COMMAND_NO_ARG(tpm_physical_disable) - -static int get_tpm(struct udevice **devp) -{ - int rc; - - rc = uclass_first_device_err(UCLASS_TPM, devp); - if (rc) { - printf("Could not find TPM (ret=%d)\n", rc); - return CMD_RET_FAILURE; - } - - return 0; -} - -static int do_tpm_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) -{ - struct udevice *dev; - char buf[80]; - int rc; - - rc = get_tpm(&dev); - if (rc) - return rc; - rc = tpm_get_desc(dev, buf, sizeof(buf)); - if (rc < 0) { - printf("Couldn't get TPM info (%d)\n", rc); - return CMD_RET_FAILURE; - } - printf("%s\n", buf); - - return 0; -} - -static int do_tpm_raw_transfer(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - struct udevice *dev; - void *command; - u8 response[1024]; - size_t count, response_length = sizeof(response); - u32 rc; - - command = parse_byte_string(argv[1], NULL, &count); - if (!command) { - printf("Couldn't parse byte string %s\n", argv[1]); - return CMD_RET_FAILURE; - } - - rc = get_tpm(&dev); - if (rc) - return rc; - - rc = tpm_xfer(dev, command, count, response, &response_length); - free(command); - if (!rc) { - puts("tpm response:\n"); - print_byte_string(response, response_length); - } - - return report_return_code(rc); -} - -static int do_tpm_nv_define(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 index, perm, size; - - if (argc != 4) - return CMD_RET_USAGE; - size = type_string_get_space_size(argv[1]); - if (!size) { - printf("Couldn't parse arguments\n"); - return CMD_RET_USAGE; - } - index = simple_strtoul(argv[2], NULL, 0); - perm = simple_strtoul(argv[3], NULL, 0); - - return report_return_code(tpm_nv_define_space(index, perm, size)); -} - -static int do_tpm_nv_read(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 index, count, err; - void *data; - - if (argc < 3) - return CMD_RET_USAGE; - if (argc != 3 + type_string_get_num_values(argv[1])) - return CMD_RET_USAGE; - index = simple_strtoul(argv[2], NULL, 0); - data = type_string_alloc(argv[1], &count); - if (!data) { - printf("Couldn't parse arguments\n"); - return CMD_RET_USAGE; - } - - err = tpm_nv_read_value(index, data, count); - if (!err) { - if (type_string_write_vars(argv[1], data, argv + 3)) { - printf("Couldn't write to variables\n"); - err = ~0; - } - } - free(data); - - return report_return_code(err); -} - -static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 index, count, err; - void *data; - - if (argc < 3) - return CMD_RET_USAGE; - if (argc != 3 + type_string_get_num_values(argv[1])) - return CMD_RET_USAGE; - index = simple_strtoul(argv[2], NULL, 0); - data = type_string_alloc(argv[1], &count); - if (!data) { - printf("Couldn't parse arguments\n"); - return CMD_RET_USAGE; - } - if (type_string_pack(argv[1], argv + 3, data)) { - printf("Couldn't parse arguments\n"); - free(data); - return CMD_RET_USAGE; - } - - err = tpm_nv_write_value(index, data, count); - free(data); - - return report_return_code(err); -} - -#ifdef CONFIG_TPM_AUTH_SESSIONS - -static int do_tpm_oiap(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 auth_handle, err; - - err = tpm_oiap(&auth_handle); - - return report_return_code(err); -} - -#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 -static int do_tpm_load_key_by_sha1(cmd_tbl_t *cmdtp, int flag, int argc, char * - const argv[]) -{ - u32 parent_handle = 0; - u32 key_len, key_handle, err; - u8 usage_auth[DIGEST_LENGTH]; - u8 parent_hash[DIGEST_LENGTH]; - void *key; - - if (argc < 5) - return CMD_RET_USAGE; - - parse_byte_string(argv[1], parent_hash, NULL); - key = (void *)simple_strtoul(argv[2], NULL, 0); - key_len = simple_strtoul(argv[3], NULL, 0); - if (strlen(argv[4]) != 2 * DIGEST_LENGTH) - return CMD_RET_FAILURE; - parse_byte_string(argv[4], usage_auth, NULL); - - err = tpm_find_key_sha1(usage_auth, parent_hash, &parent_handle); - if (err) { - printf("Could not find matching parent key (err = %d)\n", err); - return CMD_RET_FAILURE; - } - - printf("Found parent key %08x\n", parent_handle); - - err = tpm_load_key2_oiap(parent_handle, key, key_len, usage_auth, - &key_handle); - if (!err) { - printf("Key handle is 0x%x\n", key_handle); - env_set_hex("key_handle", key_handle); - } - - return report_return_code(err); -} -#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ - -static int do_tpm_load_key2_oiap(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 parent_handle, key_len, key_handle, err; - u8 usage_auth[DIGEST_LENGTH]; - void *key; - - if (argc < 5) - return CMD_RET_USAGE; - - parent_handle = simple_strtoul(argv[1], NULL, 0); - key = (void *)simple_strtoul(argv[2], NULL, 0); - key_len = simple_strtoul(argv[3], NULL, 0); - if (strlen(argv[4]) != 2 * DIGEST_LENGTH) - return CMD_RET_FAILURE; - parse_byte_string(argv[4], usage_auth, NULL); - - err = tpm_load_key2_oiap(parent_handle, key, key_len, usage_auth, - &key_handle); - if (!err) - printf("Key handle is 0x%x\n", key_handle); - - return report_return_code(err); -} - -static int do_tpm_get_pub_key_oiap(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 key_handle, err; - u8 usage_auth[DIGEST_LENGTH]; - u8 pub_key_buffer[TPM_PUBKEY_MAX_LENGTH]; - size_t pub_key_len = sizeof(pub_key_buffer); - - if (argc < 3) - return CMD_RET_USAGE; - - key_handle = simple_strtoul(argv[1], NULL, 0); - if (strlen(argv[2]) != 2 * DIGEST_LENGTH) - return CMD_RET_FAILURE; - parse_byte_string(argv[2], usage_auth, NULL); - - err = tpm_get_pub_key_oiap(key_handle, usage_auth, pub_key_buffer, - &pub_key_len); - if (!err) { - printf("dump of received pub key structure:\n"); - print_byte_string(pub_key_buffer, pub_key_len); - } - return report_return_code(err); -} - -TPM_COMMAND_NO_ARG(tpm_end_oiap) - -#endif /* CONFIG_TPM_AUTH_SESSIONS */ - -#ifdef CONFIG_TPM_FLUSH_RESOURCES -static int do_tpm_flush(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - int type = 0; - - if (argc != 3) - return CMD_RET_USAGE; - - if (!strcasecmp(argv[1], "key")) - type = TPM_RT_KEY; - else if (!strcasecmp(argv[1], "auth")) - type = TPM_RT_AUTH; - else if (!strcasecmp(argv[1], "hash")) - type = TPM_RT_HASH; - else if (!strcasecmp(argv[1], "trans")) - type = TPM_RT_TRANS; - else if (!strcasecmp(argv[1], "context")) - type = TPM_RT_CONTEXT; - else if (!strcasecmp(argv[1], "counter")) - type = TPM_RT_COUNTER; - else if (!strcasecmp(argv[1], "delegate")) - type = TPM_RT_DELEGATE; - else if (!strcasecmp(argv[1], "daa_tpm")) - type = TPM_RT_DAA_TPM; - else if (!strcasecmp(argv[1], "daa_v0")) - type = TPM_RT_DAA_V0; - else if (!strcasecmp(argv[1], "daa_v1")) - type = TPM_RT_DAA_V1; - - if (!type) { - printf("Resource type %s unknown.\n", argv[1]); - return -1; - } - - if (!strcasecmp(argv[2], "all")) { - u16 res_count; - u8 buf[288]; - u8 *ptr; - int err; - uint i; - - /* fetch list of already loaded resources in the TPM */ - err = tpm_get_capability(TPM_CAP_HANDLE, type, buf, - sizeof(buf)); - if (err) { - printf("tpm_get_capability returned error %d.\n", err); - return -1; - } - res_count = get_unaligned_be16(buf); - ptr = buf + 2; - for (i = 0; i < res_count; ++i, ptr += 4) - tpm_flush_specific(get_unaligned_be32(ptr), type); - } else { - u32 handle = simple_strtoul(argv[2], NULL, 0); - - if (!handle) { - printf("Illegal resource handle %s\n", argv[2]); - return -1; - } - tpm_flush_specific(cpu_to_be32(handle), type); - } - - return 0; -} -#endif /* CONFIG_TPM_FLUSH_RESOURCES */ - -#ifdef CONFIG_TPM_LIST_RESOURCES -static int do_tpm_list(cmd_tbl_t *cmdtp, int flag, int argc, - char * const argv[]) -{ - int type = 0; - u16 res_count; - u8 buf[288]; - u8 *ptr; - int err; - uint i; - - if (argc != 2) - return CMD_RET_USAGE; - - if (!strcasecmp(argv[1], "key")) - type = TPM_RT_KEY; - else if (!strcasecmp(argv[1], "auth")) - type = TPM_RT_AUTH; - else if (!strcasecmp(argv[1], "hash")) - type = TPM_RT_HASH; - else if (!strcasecmp(argv[1], "trans")) - type = TPM_RT_TRANS; - else if (!strcasecmp(argv[1], "context")) - type = TPM_RT_CONTEXT; - else if (!strcasecmp(argv[1], "counter")) - type = TPM_RT_COUNTER; - else if (!strcasecmp(argv[1], "delegate")) - type = TPM_RT_DELEGATE; - else if (!strcasecmp(argv[1], "daa_tpm")) - type = TPM_RT_DAA_TPM; - else if (!strcasecmp(argv[1], "daa_v0")) - type = TPM_RT_DAA_V0; - else if (!strcasecmp(argv[1], "daa_v1")) - type = TPM_RT_DAA_V1; - - if (!type) { - printf("Resource type %s unknown.\n", argv[1]); - return -1; - } - - /* fetch list of already loaded resources in the TPM */ - err = tpm_get_capability(TPM_CAP_HANDLE, type, buf, - sizeof(buf)); - if (err) { - printf("tpm_get_capability returned error %d.\n", err); - return -1; - } - res_count = get_unaligned_be16(buf); - ptr = buf + 2; - - printf("Resources of type %s (%02x):\n", argv[1], type); - if (!res_count) { - puts("None\n"); - } else { - for (i = 0; i < res_count; ++i, ptr += 4) - printf("Index %d: %08x\n", i, get_unaligned_be32(ptr)); - } - - return 0; -} -#endif /* CONFIG_TPM_LIST_RESOURCES */ - -#define MAKE_TPM_CMD_ENTRY(cmd) \ - U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "") - -static cmd_tbl_t tpm_commands[] = { - U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""), - U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""), - U_BOOT_CMD_MKENT(startup, 0, 1, - do_tpm_startup, "", ""), - U_BOOT_CMD_MKENT(self_test_full, 0, 1, - do_tpm_self_test_full, "", ""), - U_BOOT_CMD_MKENT(continue_self_test, 0, 1, - do_tpm_continue_self_test, "", ""), - U_BOOT_CMD_MKENT(force_clear, 0, 1, - do_tpm_force_clear, "", ""), - U_BOOT_CMD_MKENT(physical_enable, 0, 1, - do_tpm_physical_enable, "", ""), - U_BOOT_CMD_MKENT(physical_disable, 0, 1, - do_tpm_physical_disable, "", ""), - U_BOOT_CMD_MKENT(nv_define_space, 0, 1, - do_tpm_nv_define_space, "", ""), - U_BOOT_CMD_MKENT(nv_read_value, 0, 1, - do_tpm_nv_read_value, "", ""), - U_BOOT_CMD_MKENT(nv_write_value, 0, 1, - do_tpm_nv_write_value, "", ""), - U_BOOT_CMD_MKENT(extend, 0, 1, - do_tpm_extend, "", ""), - U_BOOT_CMD_MKENT(pcr_read, 0, 1, - do_tpm_pcr_read, "", ""), - U_BOOT_CMD_MKENT(tsc_physical_presence, 0, 1, - do_tpm_tsc_physical_presence, "", ""), - U_BOOT_CMD_MKENT(read_pubek, 0, 1, - do_tpm_read_pubek, "", ""), - U_BOOT_CMD_MKENT(physical_set_deactivated, 0, 1, - do_tpm_physical_set_deactivated, "", ""), - U_BOOT_CMD_MKENT(get_capability, 0, 1, - do_tpm_get_capability, "", ""), - U_BOOT_CMD_MKENT(raw_transfer, 0, 1, - do_tpm_raw_transfer, "", ""), - U_BOOT_CMD_MKENT(nv_define, 0, 1, - do_tpm_nv_define, "", ""), - U_BOOT_CMD_MKENT(nv_read, 0, 1, - do_tpm_nv_read, "", ""), - U_BOOT_CMD_MKENT(nv_write, 0, 1, - do_tpm_nv_write, "", ""), -#ifdef CONFIG_TPM_AUTH_SESSIONS - U_BOOT_CMD_MKENT(oiap, 0, 1, - do_tpm_oiap, "", ""), - U_BOOT_CMD_MKENT(end_oiap, 0, 1, - do_tpm_end_oiap, "", ""), - U_BOOT_CMD_MKENT(load_key2_oiap, 0, 1, - do_tpm_load_key2_oiap, "", ""), -#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 - U_BOOT_CMD_MKENT(load_key_by_sha1, 0, 1, - do_tpm_load_key_by_sha1, "", ""), -#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ - U_BOOT_CMD_MKENT(get_pub_key_oiap, 0, 1, - do_tpm_get_pub_key_oiap, "", ""), -#endif /* CONFIG_TPM_AUTH_SESSIONS */ -#ifdef CONFIG_TPM_FLUSH_RESOURCES - U_BOOT_CMD_MKENT(flush, 0, 1, - do_tpm_flush, "", ""), -#endif /* CONFIG_TPM_FLUSH_RESOURCES */ -#ifdef CONFIG_TPM_LIST_RESOURCES - U_BOOT_CMD_MKENT(list, 0, 1, - do_tpm_list, "", ""), -#endif /* CONFIG_TPM_LIST_RESOURCES */ -}; - -static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) -{ - cmd_tbl_t *tpm_cmd; - - if (argc < 2) - return CMD_RET_USAGE; - tpm_cmd = find_cmd_tbl(argv[1], tpm_commands, ARRAY_SIZE(tpm_commands)); - if (!tpm_cmd) - return CMD_RET_USAGE; - - return tpm_cmd->cmd(cmdtp, flag, argc - 1, argv + 1); -} - -U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm, -"Issue a TPM command", -"cmd args...\n" -" - Issue TPM command with arguments .\n" -"Admin Startup and State Commands:\n" -" info - Show information about the TPM\n" -" init\n" -" - Put TPM into a state where it waits for 'startup' command.\n" -" startup mode\n" -" - Issue TPM_Starup command. is one of TPM_ST_CLEAR,\n" -" TPM_ST_STATE, and TPM_ST_DEACTIVATED.\n" -"Admin Testing Commands:\n" -" self_test_full\n" -" - Test all of the TPM capabilities.\n" -" continue_self_test\n" -" - Inform TPM that it should complete the self-test.\n" -"Admin Opt-in Commands:\n" -" physical_enable\n" -" - Set the PERMANENT disable flag to FALSE using physical presence as\n" -" authorization.\n" -" physical_disable\n" -" - Set the PERMANENT disable flag to TRUE using physical presence as\n" -" authorization.\n" -" physical_set_deactivated 0|1\n" -" - Set deactivated flag.\n" -"Admin Ownership Commands:\n" -" force_clear\n" -" - Issue TPM_ForceClear command.\n" -" tsc_physical_presence flags\n" -" - Set TPM device's Physical Presence flags to .\n" -"The Capability Commands:\n" -" get_capability cap_area sub_cap addr count\n" -" - Read bytes of TPM capability indexed by and\n" -" to memory address .\n" -#if defined(CONFIG_TPM_FLUSH_RESOURCES) || defined(CONFIG_TPM_LIST_RESOURCES) -"Resource management functions\n" -#endif -#ifdef CONFIG_TPM_FLUSH_RESOURCES -" flush resource_type id\n" -" - flushes a resource of type (may be one of key, auth,\n" -" hash, trans, context, counter, delegate, daa_tpm, daa_v0, daa_v1),\n" -" and id from the TPM. Use an of \"all\" to flush all\n" -" resources of that type.\n" -#endif /* CONFIG_TPM_FLUSH_RESOURCES */ -#ifdef CONFIG_TPM_LIST_RESOURCES -" list resource_type\n" -" - lists resources of type (may be one of key, auth,\n" -" hash, trans, context, counter, delegate, daa_tpm, daa_v0, daa_v1),\n" -" contained in the TPM.\n" -#endif /* CONFIG_TPM_LIST_RESOURCES */ -#ifdef CONFIG_TPM_AUTH_SESSIONS -"Storage functions\n" -" loadkey2_oiap parent_handle key_addr key_len usage_auth\n" -" - loads a key data from memory address , bytes\n" -" into TPM using the parent key with authorization\n" -" (20 bytes hex string).\n" -#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 -" load_key_by_sha1 parent_hash key_addr key_len usage_auth\n" -" - loads a key data from memory address , bytes\n" -" into TPM using the parent hash (20 bytes hex string)\n" -" with authorization (20 bytes hex string).\n" -#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ -" get_pub_key_oiap key_handle usage_auth\n" -" - get the public key portion of a loaded key using\n" -" authorization (20 bytes hex string)\n" -#endif /* CONFIG_TPM_AUTH_SESSIONS */ -"Endorsement Key Handling Commands:\n" -" read_pubek addr count\n" -" - Read bytes of the public endorsement key to memory\n" -" address \n" -"Integrity Collection and Reporting Commands:\n" -" extend index digest_hex_string\n" -" - Add a new measurement to a PCR. Update PCR with the 20-bytes\n" -" \n" -" pcr_read index addr count\n" -" - Read bytes from PCR to memory address .\n" -#ifdef CONFIG_TPM_AUTH_SESSIONS -"Authorization Sessions\n" -" oiap\n" -" - setup an OIAP session\n" -" end_oiap\n" -" - terminates an active OIAP session\n" -#endif /* CONFIG_TPM_AUTH_SESSIONS */ -"Non-volatile Storage Commands:\n" -" nv_define_space index permission size\n" -" - Establish a space at index with of bytes.\n" -" nv_read_value index addr count\n" -" - Read bytes from space to memory address .\n" -" nv_write_value index addr count\n" -" - Write bytes from memory address to space .\n" -"Miscellaneous helper functions:\n" -" raw_transfer byte_string\n" -" - Send a byte string to TPM and print the response.\n" -" Non-volatile storage helper functions:\n" -" These helper functions treat a non-volatile space as a non-padded\n" -" sequence of integer values. These integer values are defined by a type\n" -" string, which is a text string of 'bwd' characters: 'b' means a 8-bit\n" -" value, 'w' 16-bit value, 'd' 32-bit value. All helper functions take\n" -" a type string as their first argument.\n" -" nv_define type_string index perm\n" -" - Define a space with permission .\n" -" nv_read types_string index vars...\n" -" - Read from space to environment variables .\n" -" nv_write types_string index values...\n" -" - Write to space from values .\n" -); diff --git a/cmd/tpm_test.c b/cmd/tpm_test.c index 2e7d133a47..35f3c96e3d 100644 --- a/cmd/tpm_test.c +++ b/cmd/tpm_test.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include /* Prints error and returns on failure */ #define TPM_CHECK(tpm_command) do { \ diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig index 53c34612df..bc11f61e91 100644 --- a/drivers/tpm/Kconfig +++ b/drivers/tpm/Kconfig @@ -46,7 +46,7 @@ config TPM_TIS_INFINEON config TPM_TIS_I2C_BURST_LIMITATION bool "Enable I2C burst length limitation" - depends on TPM_V1 && TPM_TIS_INFINEON + depends on TPM_TIS_INFINEON help Some broken TPMs have a limitation on the number of bytes they can receive in one message. Enable this option to allow you to set this @@ -62,6 +62,7 @@ config TPM_TIS_I2C_BURST_LIMITATION_LEN config TPM_TIS_LPC bool "Enable support for Infineon SLB9635/45 TPMs on LPC" depends on TPM_V1 && X86 + select TPM_DRIVER_SELECTED help This driver supports Infineon TPM devices connected on the LPC bus. The usual tpm operations and the 'tpm' command can be used to talk diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c index e71545235c..9488b091a2 100644 --- a/drivers/tpm/tpm-uclass.c +++ b/drivers/tpm/tpm-uclass.c @@ -6,8 +6,10 @@ #include #include -#include #include +#if defined(CONFIG_TPM_V1) +#include +#endif #include "tpm_internal.h" int tpm_open(struct udevice *dev) diff --git a/drivers/tpm/tpm_atmel_twi.c b/drivers/tpm/tpm_atmel_twi.c index 8547580c24..2079ea913e 100644 --- a/drivers/tpm/tpm_atmel_twi.c +++ b/drivers/tpm/tpm_atmel_twi.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/tpm/tpm_tis_infineon.c b/drivers/tpm/tpm_tis_infineon.c index 9b2a0250e1..b5fe43ee50 100644 --- a/drivers/tpm/tpm_tis_infineon.c +++ b/drivers/tpm/tpm_tis_infineon.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/tpm/tpm_tis_lpc.c b/drivers/tpm/tpm_tis_lpc.c index 572926382e..7664bb1a60 100644 --- a/drivers/tpm/tpm_tis_lpc.c +++ b/drivers/tpm/tpm_tis_lpc.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #define PREFIX "lpc_tpm: " diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c index 44157542a1..8816d55759 100644 --- a/drivers/tpm/tpm_tis_sandbox.c +++ b/drivers/tpm/tpm_tis_sandbox.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/tpm/tpm_tis_st33zp24_i2c.c b/drivers/tpm/tpm_tis_st33zp24_i2c.c index 9cf302caff..0d380375eb 100644 --- a/drivers/tpm/tpm_tis_st33zp24_i2c.c +++ b/drivers/tpm/tpm_tis_st33zp24_i2c.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/tpm/tpm_tis_st33zp24_spi.c b/drivers/tpm/tpm_tis_st33zp24_spi.c index d5fde11a83..f6087e7633 100644 --- a/drivers/tpm/tpm_tis_st33zp24_spi.c +++ b/drivers/tpm/tpm_tis_st33zp24_spi.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/tpm-common.h b/include/tpm-common.h new file mode 100644 index 0000000000..1ca5d28242 --- /dev/null +++ b/include/tpm-common.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + */ + +#ifndef __TPM_COMMON_H +#define __TPM_COMMON_H + +enum tpm_duration { + TPM_SHORT = 0, + TPM_MEDIUM = 1, + TPM_LONG = 2, + TPM_UNDEFINED, + + TPM_DURATION_COUNT, +}; + +/* + * Here is a partial implementation of TPM commands. Please consult TCG Main + * Specification for definitions of TPM commands. + */ + +#define TPM_HEADER_SIZE 10 + +/* Max buffer size supported by our tpm */ +#define TPM_DEV_BUFSIZE 1260 + +/** + * struct tpm_chip_priv - Information about a TPM, stored by the uclass + * + * These values must be set up by the device's probe() method before + * communcation is attempted. If the device has an xfer() method, this is + * not needed. There is no need to set up @buf. + * + * @duration_ms: Length of each duration type in milliseconds + * @retry_time_ms: Time to wait before retrying receive + */ +struct tpm_chip_priv { + uint duration_ms[TPM_DURATION_COUNT]; + uint retry_time_ms; + u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */ +}; + +/** + * struct tpm_ops - low-level TPM operations + * + * These are designed to avoid loops and delays in the driver itself. These + * should be handled in the uclass. + * + * In gneral you should implement everything except xfer(). Where you need + * complete control of the transfer, then xfer() can be provided and will + * override the other methods. + * + * This interface is for low-level TPM access. It does not understand the + * concept of localities or the various TPM messages. That interface is + * defined in the functions later on in this file, but they all translate + * to bytes which are sent and received. + */ +struct tpm_ops { + /** + * open() - Request access to locality 0 for the caller + * + * After all commands have been completed the caller should call + * close(). + * + * @dev: Device to close + * @return 0 ok OK, -ve on error + */ + int (*open)(struct udevice *dev); + + /** + * close() - Close the current session + * + * Releasing the locked locality. Returns 0 on success, -ve 1 on + * failure (in case lock removal did not succeed). + * + * @dev: Device to close + * @return 0 ok OK, -ve on error + */ + int (*close)(struct udevice *dev); + + /** + * get_desc() - Get a text description of the TPM + * + * @dev: Device to check + * @buf: Buffer to put the string + * @size: Maximum size of buffer + * @return length of string, or -ENOSPC it no space + */ + int (*get_desc)(struct udevice *dev, char *buf, int size); + + /** + * send() - send data to the TPM + * + * @dev: Device to talk to + * @sendbuf: Buffer of the data to send + * @send_size: Size of the data to send + * + * Returns 0 on success or -ve on failure. + */ + int (*send)(struct udevice *dev, const u8 *sendbuf, size_t send_size); + + /** + * recv() - receive a response from the TPM + * + * @dev: Device to talk to + * @recvbuf: Buffer to save the response to + * @max_size: Maximum number of bytes to receive + * + * Returns number of bytes received on success, -EAGAIN if the TPM + * response is not ready, -EINTR if cancelled, or other -ve value on + * failure. + */ + int (*recv)(struct udevice *dev, u8 *recvbuf, size_t max_size); + + /** + * cleanup() - clean up after an operation in progress + * + * This is called if receiving times out. The TPM may need to abort + * the current transaction if it did not complete, and make itself + * ready for another. + * + * @dev: Device to talk to + */ + int (*cleanup)(struct udevice *dev); + + /** + * xfer() - send data to the TPM and get response + * + * This method is optional. If it exists it is used in preference + * to send(), recv() and cleanup(). It should handle all aspects of + * TPM communication for a single transfer. + * + * @dev: Device to talk to + * @sendbuf: Buffer of the data to send + * @send_size: Size of the data to send + * @recvbuf: Buffer to save the response to + * @recv_size: Pointer to the size of the response buffer + * + * Returns 0 on success (and places the number of response bytes at + * recv_size) or -ve on failure. + */ + int (*xfer)(struct udevice *dev, const u8 *sendbuf, size_t send_size, + u8 *recvbuf, size_t *recv_size); +}; + +#define tpm_get_ops(dev) ((struct tpm_ops *)device_get_ops(dev)) + +#define MAKE_TPM_CMD_ENTRY(cmd) \ + U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "") + +#define TPM_COMMAND_NO_ARG(cmd) \ +int do_##cmd(cmd_tbl_t *cmdtp, int flag, \ + int argc, char * const argv[]) \ +{ \ + if (argc != 1) \ + return CMD_RET_USAGE; \ + return report_return_code(cmd()); \ +} + +/** + * tpm_get_desc() - Get a text description of the TPM + * + * @dev: Device to check + * @buf: Buffer to put the string + * @size: Maximum size of buffer + * @return length of string, or -ENOSPC it no space + */ +int tpm_get_desc(struct udevice *dev, char *buf, int size); + +/** + * tpm_xfer() - send data to the TPM and get response + * + * This first uses the device's send() method to send the bytes. Then it calls + * recv() to get the reply. If recv() returns -EAGAIN then it will delay a + * short time and then call recv() again. + * + * Regardless of whether recv() completes successfully, it will then call + * cleanup() to finish the transaction. + * + * Note that the outgoing data is inspected to determine command type + * (ordinal) and a timeout is used for that command type. + * + * @sendbuf - buffer of the data to send + * @send_size size of the data to send + * @recvbuf - memory to save the response to + * @recv_len - pointer to the size of the response buffer + * + * Returns 0 on success (and places the number of response bytes at + * recv_len) or -ve on failure. + */ +int tpm_xfer(struct udevice *dev, const u8 *sendbuf, size_t send_size, + u8 *recvbuf, size_t *recv_size); + +/** + * Initialize TPM device. It must be called before any TPM commands. + * + * @return 0 on success, non-0 on error. + */ +int tpm_init(void); + +/** + * Retrieve the array containing all the commands. + * + * @return a cmd_tbl_t array. + */ +cmd_tbl_t *get_tpm_commands(unsigned int *size); + +#endif /* __TPM_COMMON_H */ diff --git a/include/tpm-v1.h b/include/tpm-v1.h new file mode 100644 index 0000000000..6b4941ef9a --- /dev/null +++ b/include/tpm-v1.h @@ -0,0 +1,480 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + */ + +#ifndef __TPM_V1_H +#define __TPM_V1_H + +#include + +/* Useful constants */ +enum { + TPM_REQUEST_HEADER_LENGTH = 10, + TPM_RESPONSE_HEADER_LENGTH = 10, + PCR_DIGEST_LENGTH = 20, + DIGEST_LENGTH = 20, + TPM_REQUEST_AUTH_LENGTH = 45, + TPM_RESPONSE_AUTH_LENGTH = 41, + /* some max lengths, valid for RSA keys <= 2048 bits */ + TPM_KEY12_MAX_LENGTH = 618, + TPM_PUBKEY_MAX_LENGTH = 288, +}; + +enum tpm_startup_type { + TPM_ST_CLEAR = 0x0001, + TPM_ST_STATE = 0x0002, + TPM_ST_DEACTIVATED = 0x0003, +}; + +enum tpm_physical_presence { + TPM_PHYSICAL_PRESENCE_HW_DISABLE = 0x0200, + TPM_PHYSICAL_PRESENCE_CMD_DISABLE = 0x0100, + TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK = 0x0080, + TPM_PHYSICAL_PRESENCE_HW_ENABLE = 0x0040, + TPM_PHYSICAL_PRESENCE_CMD_ENABLE = 0x0020, + TPM_PHYSICAL_PRESENCE_NOTPRESENT = 0x0010, + TPM_PHYSICAL_PRESENCE_PRESENT = 0x0008, + TPM_PHYSICAL_PRESENCE_LOCK = 0x0004, +}; + +enum tpm_nv_index { + TPM_NV_INDEX_LOCK = 0xffffffff, + TPM_NV_INDEX_0 = 0x00000000, + TPM_NV_INDEX_DIR = 0x10000001, +}; + +enum tpm_resource_type { + TPM_RT_KEY = 0x00000001, + TPM_RT_AUTH = 0x00000002, + TPM_RT_HASH = 0x00000003, + TPM_RT_TRANS = 0x00000004, + TPM_RT_CONTEXT = 0x00000005, + TPM_RT_COUNTER = 0x00000006, + TPM_RT_DELEGATE = 0x00000007, + TPM_RT_DAA_TPM = 0x00000008, + TPM_RT_DAA_V0 = 0x00000009, + TPM_RT_DAA_V1 = 0x0000000A, +}; + +enum tpm_capability_areas { + TPM_CAP_ORD = 0x00000001, + TPM_CAP_ALG = 0x00000002, + TPM_CAP_PID = 0x00000003, + TPM_CAP_FLAG = 0x00000004, + TPM_CAP_PROPERTY = 0x00000005, + TPM_CAP_VERSION = 0x00000006, + TPM_CAP_KEY_HANDLE = 0x00000007, + TPM_CAP_CHECK_LOADED = 0x00000008, + TPM_CAP_SYM_MODE = 0x00000009, + TPM_CAP_KEY_STATUS = 0x0000000C, + TPM_CAP_NV_LIST = 0x0000000D, + TPM_CAP_MFR = 0x00000010, + TPM_CAP_NV_INDEX = 0x00000011, + TPM_CAP_TRANS_ALG = 0x00000012, + TPM_CAP_HANDLE = 0x00000014, + TPM_CAP_TRANS_ES = 0x00000015, + TPM_CAP_AUTH_ENCRYPT = 0x00000017, + TPM_CAP_SELECT_SIZE = 0x00000018, + TPM_CAP_DA_LOGIC = 0x00000019, + TPM_CAP_VERSION_VAL = 0x0000001A, +}; + +#define TPM_NV_PER_GLOBALLOCK BIT(15) +#define TPM_NV_PER_PPREAD BIT(16) +#define TPM_NV_PER_PPWRITE BIT(0) +#define TPM_NV_PER_READ_STCLEAR BIT(31) +#define TPM_NV_PER_WRITE_STCLEAR BIT(14) +#define TPM_NV_PER_WRITEDEFINE BIT(13) +#define TPM_NV_PER_WRITEALL BIT(12) + +enum { + TPM_PUBEK_SIZE = 256, +}; + +/** + * TPM return codes as defined in the TCG Main specification + * (TPM Main Part 2 Structures; Specification version 1.2) + */ +enum tpm_return_code { + TPM_BASE = 0x00000000, + TPM_NON_FATAL = 0x00000800, + TPM_SUCCESS = TPM_BASE, + /* TPM-defined fatal error codes */ + TPM_AUTHFAIL = TPM_BASE + 1, + TPM_BADINDEX = TPM_BASE + 2, + TPM_BAD_PARAMETER = TPM_BASE + 3, + TPM_AUDITFAILURE = TPM_BASE + 4, + TPM_CLEAR_DISABLED = TPM_BASE + 5, + TPM_DEACTIVATED = TPM_BASE + 6, + TPM_DISABLED = TPM_BASE + 7, + TPM_DISABLED_CMD = TPM_BASE + 8, + TPM_FAIL = TPM_BASE + 9, + TPM_BAD_ORDINAL = TPM_BASE + 10, + TPM_INSTALL_DISABLED = TPM_BASE + 11, + TPM_INVALID_KEYHANDLE = TPM_BASE + 12, + TPM_KEYNOTFOUND = TPM_BASE + 13, + TPM_INAPPROPRIATE_ENC = TPM_BASE + 14, + TPM_MIGRATE_FAIL = TPM_BASE + 15, + TPM_INVALID_PCR_INFO = TPM_BASE + 16, + TPM_NOSPACE = TPM_BASE + 17, + TPM_NOSRK = TPM_BASE + 18, + TPM_NOTSEALED_BLOB = TPM_BASE + 19, + TPM_OWNER_SET = TPM_BASE + 20, + TPM_RESOURCES = TPM_BASE + 21, + TPM_SHORTRANDOM = TPM_BASE + 22, + TPM_SIZE = TPM_BASE + 23, + TPM_WRONGPCRVAL = TPM_BASE + 24, + TPM_BAD_PARAM_SIZE = TPM_BASE + 25, + TPM_SHA_THREAD = TPM_BASE + 26, + TPM_SHA_ERROR = TPM_BASE + 27, + TPM_FAILEDSELFTEST = TPM_BASE + 28, + TPM_AUTH2FAIL = TPM_BASE + 29, + TPM_BADTAG = TPM_BASE + 30, + TPM_IOERROR = TPM_BASE + 31, + TPM_ENCRYPT_ERROR = TPM_BASE + 32, + TPM_DECRYPT_ERROR = TPM_BASE + 33, + TPM_INVALID_AUTHHANDLE = TPM_BASE + 34, + TPM_NO_ENDORSEMENT = TPM_BASE + 35, + TPM_INVALID_KEYUSAGE = TPM_BASE + 36, + TPM_WRONG_ENTITYTYPE = TPM_BASE + 37, + TPM_INVALID_POSTINIT = TPM_BASE + 38, + TPM_INAPPROPRIATE_SIG = TPM_BASE + 39, + TPM_BAD_KEY_PROPERTY = TPM_BASE + 40, + TPM_BAD_MIGRATION = TPM_BASE + 41, + TPM_BAD_SCHEME = TPM_BASE + 42, + TPM_BAD_DATASIZE = TPM_BASE + 43, + TPM_BAD_MODE = TPM_BASE + 44, + TPM_BAD_PRESENCE = TPM_BASE + 45, + TPM_BAD_VERSION = TPM_BASE + 46, + TPM_NO_WRAP_TRANSPORT = TPM_BASE + 47, + TPM_AUDITFAIL_UNSUCCESSFUL = TPM_BASE + 48, + TPM_AUDITFAIL_SUCCESSFUL = TPM_BASE + 49, + TPM_NOTRESETABLE = TPM_BASE + 50, + TPM_NOTLOCAL = TPM_BASE + 51, + TPM_BAD_TYPE = TPM_BASE + 52, + TPM_INVALID_RESOURCE = TPM_BASE + 53, + TPM_NOTFIPS = TPM_BASE + 54, + TPM_INVALID_FAMILY = TPM_BASE + 55, + TPM_NO_NV_PERMISSION = TPM_BASE + 56, + TPM_REQUIRES_SIGN = TPM_BASE + 57, + TPM_KEY_NOTSUPPORTED = TPM_BASE + 58, + TPM_AUTH_CONFLICT = TPM_BASE + 59, + TPM_AREA_LOCKED = TPM_BASE + 60, + TPM_BAD_LOCALITY = TPM_BASE + 61, + TPM_READ_ONLY = TPM_BASE + 62, + TPM_PER_NOWRITE = TPM_BASE + 63, + TPM_FAMILY_COUNT = TPM_BASE + 64, + TPM_WRITE_LOCKED = TPM_BASE + 65, + TPM_BAD_ATTRIBUTES = TPM_BASE + 66, + TPM_INVALID_STRUCTURE = TPM_BASE + 67, + TPM_KEY_OWNER_CONTROL = TPM_BASE + 68, + TPM_BAD_COUNTER = TPM_BASE + 69, + TPM_NOT_FULLWRITE = TPM_BASE + 70, + TPM_CONTEXT_GAP = TPM_BASE + 71, + TPM_MAXNVWRITES = TPM_BASE + 72, + TPM_NOOPERATOR = TPM_BASE + 73, + TPM_RESOURCEMISSING = TPM_BASE + 74, + TPM_DELEGATE_LOCK = TPM_BASE + 75, + TPM_DELEGATE_FAMILY = TPM_BASE + 76, + TPM_DELEGATE_ADMIN = TPM_BASE + 77, + TPM_TRANSPORT_NOTEXCLUSIVE = TPM_BASE + 78, + TPM_OWNER_CONTROL = TPM_BASE + 79, + TPM_DAA_RESOURCES = TPM_BASE + 80, + TPM_DAA_INPUT_DATA0 = TPM_BASE + 81, + TPM_DAA_INPUT_DATA1 = TPM_BASE + 82, + TPM_DAA_ISSUER_SETTINGS = TPM_BASE + 83, + TPM_DAA_TPM_SETTINGS = TPM_BASE + 84, + TPM_DAA_STAGE = TPM_BASE + 85, + TPM_DAA_ISSUER_VALIDITY = TPM_BASE + 86, + TPM_DAA_WRONG_W = TPM_BASE + 87, + TPM_BAD_HANDLE = TPM_BASE + 88, + TPM_BAD_DELEGATE = TPM_BASE + 89, + TPM_BADCONTEXT = TPM_BASE + 90, + TPM_TOOMANYCONTEXTS = TPM_BASE + 91, + TPM_MA_TICKET_SIGNATURE = TPM_BASE + 92, + TPM_MA_DESTINATION = TPM_BASE + 93, + TPM_MA_SOURCE = TPM_BASE + 94, + TPM_MA_AUTHORITY = TPM_BASE + 95, + TPM_PERMANENTEK = TPM_BASE + 97, + TPM_BAD_SIGNATURE = TPM_BASE + 98, + TPM_NOCONTEXTSPACE = TPM_BASE + 99, + /* TPM-defined non-fatal errors */ + TPM_RETRY = TPM_BASE + TPM_NON_FATAL, + TPM_NEEDS_SELFTEST = TPM_BASE + TPM_NON_FATAL + 1, + TPM_DOING_SELFTEST = TPM_BASE + TPM_NON_FATAL + 2, + TPM_DEFEND_LOCK_RUNNING = TPM_BASE + TPM_NON_FATAL + 3, +}; + +struct tpm_permanent_flags { + __be16 tag; + u8 disable; + u8 ownership; + u8 deactivated; + u8 read_pubek; + u8 disable_owner_clear; + u8 allow_maintenance; + u8 physical_presence_lifetime_lock; + u8 physical_presence_hw_enable; + u8 physical_presence_cmd_enable; + u8 cekp_used; + u8 tpm_post; + u8 tpm_post_lock; + u8 fips; + u8 operator; + u8 enable_revoke_ek; + u8 nv_locked; + u8 read_srk_pub; + u8 tpm_established; + u8 maintenance_done; + u8 disable_full_da_logic_info; +} __packed; + +/** + * Issue a TPM_Startup command. + * + * @param mode TPM startup mode + * @return return code of the operation + */ +u32 tpm_startup(enum tpm_startup_type mode); + +/** + * Issue a TPM_SelfTestFull command. + * + * @return return code of the operation + */ +u32 tpm_self_test_full(void); + +/** + * Issue a TPM_ContinueSelfTest command. + * + * @return return code of the operation + */ +u32 tpm_continue_self_test(void); + +/** + * Issue a TPM_NV_DefineSpace command. The implementation is limited + * to specify TPM_NV_ATTRIBUTES and size of the area. The area index + * could be one of the special value listed in enum tpm_nv_index. + * + * @param index index of the area + * @param perm TPM_NV_ATTRIBUTES of the area + * @param size size of the area + * @return return code of the operation + */ +u32 tpm_nv_define_space(u32 index, u32 perm, u32 size); + +/** + * Issue a TPM_NV_ReadValue command. This implementation is limited + * to read the area from offset 0. The area index could be one of + * the special value listed in enum tpm_nv_index. + * + * @param index index of the area + * @param data output buffer of the area contents + * @param count size of output buffer + * @return return code of the operation + */ +u32 tpm_nv_read_value(u32 index, void *data, u32 count); + +/** + * Issue a TPM_NV_WriteValue command. This implementation is limited + * to write the area from offset 0. The area index could be one of + * the special value listed in enum tpm_nv_index. + * + * @param index index of the area + * @param data input buffer to be wrote to the area + * @param length length of data bytes of input buffer + * @return return code of the operation + */ +u32 tpm_nv_write_value(u32 index, const void *data, u32 length); + +/** + * Issue a TPM_Extend command. + * + * @param index index of the PCR + * @param in_digest 160-bit value representing the event to be + * recorded + * @param out_digest 160-bit PCR value after execution of the + * command + * @return return code of the operation + */ +u32 tpm_extend(u32 index, const void *in_digest, void *out_digest); + +/** + * Issue a TPM_PCRRead command. + * + * @param index index of the PCR + * @param data output buffer for contents of the named PCR + * @param count size of output buffer + * @return return code of the operation + */ +u32 tpm_pcr_read(u32 index, void *data, size_t count); + +/** + * Issue a TSC_PhysicalPresence command. TPM physical presence flag + * is bit-wise OR'ed of flags listed in enum tpm_physical_presence. + * + * @param presence TPM physical presence flag + * @return return code of the operation + */ +u32 tpm_tsc_physical_presence(u16 presence); + +/** + * Issue a TPM_ReadPubek command. + * + * @param data output buffer for the public endorsement key + * @param count size of output buffer + * @return return code of the operation + */ +u32 tpm_read_pubek(void *data, size_t count); + +/** + * Issue a TPM_ForceClear command. + * + * @return return code of the operation + */ +u32 tpm_force_clear(void); + +/** + * Issue a TPM_PhysicalEnable command. + * + * @return return code of the operation + */ +u32 tpm_physical_enable(void); + +/** + * Issue a TPM_PhysicalDisable command. + * + * @return return code of the operation + */ +u32 tpm_physical_disable(void); + +/** + * Issue a TPM_PhysicalSetDeactivated command. + * + * @param state boolean state of the deactivated flag + * @return return code of the operation + */ +u32 tpm_physical_set_deactivated(u8 state); + +/** + * Issue a TPM_GetCapability command. This implementation is limited + * to query sub_cap index that is 4-byte wide. + * + * @param cap_area partition of capabilities + * @param sub_cap further definition of capability, which is + * limited to be 4-byte wide + * @param cap output buffer for capability information + * @param count size of output buffer + * @return return code of the operation + */ +u32 tpm_get_capability(u32 cap_area, u32 sub_cap, void *cap, size_t count); + +/** + * Issue a TPM_FlushSpecific command for a AUTH resource. + * + * @param auth_handle handle of the auth session + * @return return code of the operation + */ +u32 tpm_terminate_auth_session(u32 auth_handle); + +/** + * Issue a TPM_OIAP command to setup an object independent authorization + * session. + * Information about the session is stored internally. + * If there was already an OIAP session active it is terminated and a new + * session is set up. + * + * @param auth_handle pointer to the (new) auth handle or NULL. + * @return return code of the operation + */ +u32 tpm_oiap(u32 *auth_handle); + +/** + * Ends an active OIAP session. + * + * @return return code of the operation + */ +u32 tpm_end_oiap(void); + +/** + * Issue a TPM_LoadKey2 (Auth1) command using an OIAP session for authenticating + * the usage of the parent key. + * + * @param parent_handle handle of the parent key. + * @param key pointer to the key structure (TPM_KEY or TPM_KEY12). + * @param key_length size of the key structure + * @param parent_key_usage_auth usage auth for the parent key + * @param key_handle pointer to the key handle + * @return return code of the operation + */ +u32 tpm_load_key2_oiap(u32 parent_handle, const void *key, size_t key_length, + const void *parent_key_usage_auth, u32 *key_handle); + +/** + * Issue a TPM_GetPubKey (Auth1) command using an OIAP session for + * authenticating the usage of the key. + * + * @param key_handle handle of the key + * @param usage_auth usage auth for the key + * @param pubkey pointer to the pub key buffer; may be NULL if the pubkey + * should not be stored. + * @param pubkey_len pointer to the pub key buffer len. On entry: the size of + * the provided pubkey buffer. On successful exit: the size + * of the stored TPM_PUBKEY structure (iff pubkey != NULL). + * @return return code of the operation + */ +u32 tpm_get_pub_key_oiap(u32 key_handle, const void *usage_auth, void *pubkey, + size_t *pubkey_len); + +/** + * Get the TPM permanent flags value + * + * @param pflags Place to put permanent flags + * @return return code of the operation + */ +u32 tpm_get_permanent_flags(struct tpm_permanent_flags *pflags); + +/** + * Get the TPM permissions + * + * @param perm Returns permissions value + * @return return code of the operation + */ +u32 tpm_get_permissions(u32 index, u32 *perm); + +/** + * Flush a resource with a given handle and type from the TPM + * + * @param key_handle handle of the resource + * @param resource_type type of the resource + * @return return code of the operation + */ +u32 tpm_flush_specific(u32 key_handle, u32 resource_type); + +#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 +/** + * Search for a key by usage AuthData and the hash of the parent's pub key. + * + * @param auth Usage auth of the key to search for + * @param pubkey_digest SHA1 hash of the pub key structure of the key + * @param[out] handle The handle of the key (Non-null iff found) + * @return 0 if key was found in TPM; != 0 if not. + */ +u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20], + u32 *handle); +#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ + +/** + * Read random bytes from the TPM RNG. The implementation deals with the fact + * that the TPM may legally return fewer bytes than requested by retrying + * until @p count bytes have been received. + * + * @param data output buffer for the random bytes + * @param count size of output buffer + * @return return code of the operation + */ +u32 tpm_get_random(void *data, u32 count); + +#endif /* __TPM_V1_H */ diff --git a/include/tpm.h b/include/tpm.h deleted file mode 100644 index 23d925ecaa..0000000000 --- a/include/tpm.h +++ /dev/null @@ -1,664 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 2013 The Chromium OS Authors. - * Coypright (c) 2013 Guntermann & Drunck GmbH - */ - -#ifndef __TPM_H -#define __TPM_H - -/* - * Here is a partial implementation of TPM commands. Please consult TCG Main - * Specification for definitions of TPM commands. - */ - -#define TPM_HEADER_SIZE 10 - -enum tpm_duration { - TPM_SHORT = 0, - TPM_MEDIUM = 1, - TPM_LONG = 2, - TPM_UNDEFINED, - - TPM_DURATION_COUNT, -}; - -enum tpm_startup_type { - TPM_ST_CLEAR = 0x0001, - TPM_ST_STATE = 0x0002, - TPM_ST_DEACTIVATED = 0x0003, -}; - -enum tpm_physical_presence { - TPM_PHYSICAL_PRESENCE_HW_DISABLE = 0x0200, - TPM_PHYSICAL_PRESENCE_CMD_DISABLE = 0x0100, - TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK = 0x0080, - TPM_PHYSICAL_PRESENCE_HW_ENABLE = 0x0040, - TPM_PHYSICAL_PRESENCE_CMD_ENABLE = 0x0020, - TPM_PHYSICAL_PRESENCE_NOTPRESENT = 0x0010, - TPM_PHYSICAL_PRESENCE_PRESENT = 0x0008, - TPM_PHYSICAL_PRESENCE_LOCK = 0x0004, -}; - -enum tpm_nv_index { - TPM_NV_INDEX_LOCK = 0xffffffff, - TPM_NV_INDEX_0 = 0x00000000, - TPM_NV_INDEX_DIR = 0x10000001, -}; - -enum tpm_resource_type { - TPM_RT_KEY = 0x00000001, - TPM_RT_AUTH = 0x00000002, - TPM_RT_HASH = 0x00000003, - TPM_RT_TRANS = 0x00000004, - TPM_RT_CONTEXT = 0x00000005, - TPM_RT_COUNTER = 0x00000006, - TPM_RT_DELEGATE = 0x00000007, - TPM_RT_DAA_TPM = 0x00000008, - TPM_RT_DAA_V0 = 0x00000009, - TPM_RT_DAA_V1 = 0x0000000A, -}; - -enum tpm_capability_areas { - TPM_CAP_ORD = 0x00000001, - TPM_CAP_ALG = 0x00000002, - TPM_CAP_PID = 0x00000003, - TPM_CAP_FLAG = 0x00000004, - TPM_CAP_PROPERTY = 0x00000005, - TPM_CAP_VERSION = 0x00000006, - TPM_CAP_KEY_HANDLE = 0x00000007, - TPM_CAP_CHECK_LOADED = 0x00000008, - TPM_CAP_SYM_MODE = 0x00000009, - TPM_CAP_KEY_STATUS = 0x0000000C, - TPM_CAP_NV_LIST = 0x0000000D, - TPM_CAP_MFR = 0x00000010, - TPM_CAP_NV_INDEX = 0x00000011, - TPM_CAP_TRANS_ALG = 0x00000012, - TPM_CAP_HANDLE = 0x00000014, - TPM_CAP_TRANS_ES = 0x00000015, - TPM_CAP_AUTH_ENCRYPT = 0x00000017, - TPM_CAP_SELECT_SIZE = 0x00000018, - TPM_CAP_DA_LOGIC = 0x00000019, - TPM_CAP_VERSION_VAL = 0x0000001A, -}; - -#define TPM_NV_PER_GLOBALLOCK BIT(15) -#define TPM_NV_PER_PPREAD BIT(16) -#define TPM_NV_PER_PPWRITE BIT(0) -#define TPM_NV_PER_READ_STCLEAR BIT(31) -#define TPM_NV_PER_WRITE_STCLEAR BIT(14) -#define TPM_NV_PER_WRITEDEFINE BIT(13) -#define TPM_NV_PER_WRITEALL BIT(12) - -enum { - TPM_PUBEK_SIZE = 256, -}; - -/** - * TPM return codes as defined in the TCG Main specification - * (TPM Main Part 2 Structures; Specification version 1.2) - */ -enum tpm_return_code { - TPM_BASE = 0x00000000, - TPM_NON_FATAL = 0x00000800, - TPM_SUCCESS = TPM_BASE, - /* TPM-defined fatal error codes */ - TPM_AUTHFAIL = TPM_BASE + 1, - TPM_BADINDEX = TPM_BASE + 2, - TPM_BAD_PARAMETER = TPM_BASE + 3, - TPM_AUDITFAILURE = TPM_BASE + 4, - TPM_CLEAR_DISABLED = TPM_BASE + 5, - TPM_DEACTIVATED = TPM_BASE + 6, - TPM_DISABLED = TPM_BASE + 7, - TPM_DISABLED_CMD = TPM_BASE + 8, - TPM_FAIL = TPM_BASE + 9, - TPM_BAD_ORDINAL = TPM_BASE + 10, - TPM_INSTALL_DISABLED = TPM_BASE + 11, - TPM_INVALID_KEYHANDLE = TPM_BASE + 12, - TPM_KEYNOTFOUND = TPM_BASE + 13, - TPM_INAPPROPRIATE_ENC = TPM_BASE + 14, - TPM_MIGRATE_FAIL = TPM_BASE + 15, - TPM_INVALID_PCR_INFO = TPM_BASE + 16, - TPM_NOSPACE = TPM_BASE + 17, - TPM_NOSRK = TPM_BASE + 18, - TPM_NOTSEALED_BLOB = TPM_BASE + 19, - TPM_OWNER_SET = TPM_BASE + 20, - TPM_RESOURCES = TPM_BASE + 21, - TPM_SHORTRANDOM = TPM_BASE + 22, - TPM_SIZE = TPM_BASE + 23, - TPM_WRONGPCRVAL = TPM_BASE + 24, - TPM_BAD_PARAM_SIZE = TPM_BASE + 25, - TPM_SHA_THREAD = TPM_BASE + 26, - TPM_SHA_ERROR = TPM_BASE + 27, - TPM_FAILEDSELFTEST = TPM_BASE + 28, - TPM_AUTH2FAIL = TPM_BASE + 29, - TPM_BADTAG = TPM_BASE + 30, - TPM_IOERROR = TPM_BASE + 31, - TPM_ENCRYPT_ERROR = TPM_BASE + 32, - TPM_DECRYPT_ERROR = TPM_BASE + 33, - TPM_INVALID_AUTHHANDLE = TPM_BASE + 34, - TPM_NO_ENDORSEMENT = TPM_BASE + 35, - TPM_INVALID_KEYUSAGE = TPM_BASE + 36, - TPM_WRONG_ENTITYTYPE = TPM_BASE + 37, - TPM_INVALID_POSTINIT = TPM_BASE + 38, - TPM_INAPPROPRIATE_SIG = TPM_BASE + 39, - TPM_BAD_KEY_PROPERTY = TPM_BASE + 40, - TPM_BAD_MIGRATION = TPM_BASE + 41, - TPM_BAD_SCHEME = TPM_BASE + 42, - TPM_BAD_DATASIZE = TPM_BASE + 43, - TPM_BAD_MODE = TPM_BASE + 44, - TPM_BAD_PRESENCE = TPM_BASE + 45, - TPM_BAD_VERSION = TPM_BASE + 46, - TPM_NO_WRAP_TRANSPORT = TPM_BASE + 47, - TPM_AUDITFAIL_UNSUCCESSFUL = TPM_BASE + 48, - TPM_AUDITFAIL_SUCCESSFUL = TPM_BASE + 49, - TPM_NOTRESETABLE = TPM_BASE + 50, - TPM_NOTLOCAL = TPM_BASE + 51, - TPM_BAD_TYPE = TPM_BASE + 52, - TPM_INVALID_RESOURCE = TPM_BASE + 53, - TPM_NOTFIPS = TPM_BASE + 54, - TPM_INVALID_FAMILY = TPM_BASE + 55, - TPM_NO_NV_PERMISSION = TPM_BASE + 56, - TPM_REQUIRES_SIGN = TPM_BASE + 57, - TPM_KEY_NOTSUPPORTED = TPM_BASE + 58, - TPM_AUTH_CONFLICT = TPM_BASE + 59, - TPM_AREA_LOCKED = TPM_BASE + 60, - TPM_BAD_LOCALITY = TPM_BASE + 61, - TPM_READ_ONLY = TPM_BASE + 62, - TPM_PER_NOWRITE = TPM_BASE + 63, - TPM_FAMILY_COUNT = TPM_BASE + 64, - TPM_WRITE_LOCKED = TPM_BASE + 65, - TPM_BAD_ATTRIBUTES = TPM_BASE + 66, - TPM_INVALID_STRUCTURE = TPM_BASE + 67, - TPM_KEY_OWNER_CONTROL = TPM_BASE + 68, - TPM_BAD_COUNTER = TPM_BASE + 69, - TPM_NOT_FULLWRITE = TPM_BASE + 70, - TPM_CONTEXT_GAP = TPM_BASE + 71, - TPM_MAXNVWRITES = TPM_BASE + 72, - TPM_NOOPERATOR = TPM_BASE + 73, - TPM_RESOURCEMISSING = TPM_BASE + 74, - TPM_DELEGATE_LOCK = TPM_BASE + 75, - TPM_DELEGATE_FAMILY = TPM_BASE + 76, - TPM_DELEGATE_ADMIN = TPM_BASE + 77, - TPM_TRANSPORT_NOTEXCLUSIVE = TPM_BASE + 78, - TPM_OWNER_CONTROL = TPM_BASE + 79, - TPM_DAA_RESOURCES = TPM_BASE + 80, - TPM_DAA_INPUT_DATA0 = TPM_BASE + 81, - TPM_DAA_INPUT_DATA1 = TPM_BASE + 82, - TPM_DAA_ISSUER_SETTINGS = TPM_BASE + 83, - TPM_DAA_TPM_SETTINGS = TPM_BASE + 84, - TPM_DAA_STAGE = TPM_BASE + 85, - TPM_DAA_ISSUER_VALIDITY = TPM_BASE + 86, - TPM_DAA_WRONG_W = TPM_BASE + 87, - TPM_BAD_HANDLE = TPM_BASE + 88, - TPM_BAD_DELEGATE = TPM_BASE + 89, - TPM_BADCONTEXT = TPM_BASE + 90, - TPM_TOOMANYCONTEXTS = TPM_BASE + 91, - TPM_MA_TICKET_SIGNATURE = TPM_BASE + 92, - TPM_MA_DESTINATION = TPM_BASE + 93, - TPM_MA_SOURCE = TPM_BASE + 94, - TPM_MA_AUTHORITY = TPM_BASE + 95, - TPM_PERMANENTEK = TPM_BASE + 97, - TPM_BAD_SIGNATURE = TPM_BASE + 98, - TPM_NOCONTEXTSPACE = TPM_BASE + 99, - /* TPM-defined non-fatal errors */ - TPM_RETRY = TPM_BASE + TPM_NON_FATAL, - TPM_NEEDS_SELFTEST = TPM_BASE + TPM_NON_FATAL + 1, - TPM_DOING_SELFTEST = TPM_BASE + TPM_NON_FATAL + 2, - TPM_DEFEND_LOCK_RUNNING = TPM_BASE + TPM_NON_FATAL + 3, -}; - -struct tpm_permanent_flags { - __be16 tag; - u8 disable; - u8 ownership; - u8 deactivated; - u8 read_pubek; - u8 disable_owner_clear; - u8 allow_maintenance; - u8 physical_presence_lifetime_lock; - u8 physical_presence_hw_enable; - u8 physical_presence_cmd_enable; - u8 cekp_used; - u8 tpm_post; - u8 tpm_post_lock; - u8 fips; - u8 operator; - u8 enable_revoke_ek; - u8 nv_locked; - u8 read_srk_pub; - u8 tpm_established; - u8 maintenance_done; - u8 disable_full_da_logic_info; -} __packed; - -/* Max buffer size supported by our tpm */ -#define TPM_DEV_BUFSIZE 1260 - -/** - * struct tpm_chip_priv - Information about a TPM, stored by the uclass - * - * These values must be set up by the device's probe() method before - * communcation is attempted. If the device has an xfer() method, this is - * not needed. There is no need to set up @buf. - * - * @duration_ms: Length of each duration type in milliseconds - * @retry_time_ms: Time to wait before retrying receive - */ -struct tpm_chip_priv { - uint duration_ms[TPM_DURATION_COUNT]; - uint retry_time_ms; - u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */ -}; - -/** - * struct tpm_ops - low-level TPM operations - * - * These are designed to avoid loops and delays in the driver itself. These - * should be handled in the uclass. - * - * In gneral you should implement everything except xfer(). Where you need - * complete control of the transfer, then xfer() can be provided and will - * override the other methods. - * - * This interface is for low-level TPM access. It does not understand the - * concept of localities or the various TPM messages. That interface is - * defined in the functions later on in this file, but they all translate - * to bytes which are sent and received. - */ -struct tpm_ops { - /** - * open() - Request access to locality 0 for the caller - * - * After all commands have been completed the caller should call - * close(). - * - * @dev: Device to close - * @return 0 ok OK, -ve on error - */ - int (*open)(struct udevice *dev); - - /** - * close() - Close the current session - * - * Releasing the locked locality. Returns 0 on success, -ve 1 on - * failure (in case lock removal did not succeed). - * - * @dev: Device to close - * @return 0 ok OK, -ve on error - */ - int (*close)(struct udevice *dev); - - /** - * get_desc() - Get a text description of the TPM - * - * @dev: Device to check - * @buf: Buffer to put the string - * @size: Maximum size of buffer - * @return length of string, or -ENOSPC it no space - */ - int (*get_desc)(struct udevice *dev, char *buf, int size); - - /** - * send() - send data to the TPM - * - * @dev: Device to talk to - * @sendbuf: Buffer of the data to send - * @send_size: Size of the data to send - * - * Returns 0 on success or -ve on failure. - */ - int (*send)(struct udevice *dev, const u8 *sendbuf, size_t send_size); - - /** - * recv() - receive a response from the TPM - * - * @dev: Device to talk to - * @recvbuf: Buffer to save the response to - * @max_size: Maximum number of bytes to receive - * - * Returns number of bytes received on success, -EAGAIN if the TPM - * response is not ready, -EINTR if cancelled, or other -ve value on - * failure. - */ - int (*recv)(struct udevice *dev, u8 *recvbuf, size_t max_size); - - /** - * cleanup() - clean up after an operation in progress - * - * This is called if receiving times out. The TPM may need to abort - * the current transaction if it did not complete, and make itself - * ready for another. - * - * @dev: Device to talk to - */ - int (*cleanup)(struct udevice *dev); - - /** - * xfer() - send data to the TPM and get response - * - * This method is optional. If it exists it is used in preference - * to send(), recv() and cleanup(). It should handle all aspects of - * TPM communication for a single transfer. - * - * @dev: Device to talk to - * @sendbuf: Buffer of the data to send - * @send_size: Size of the data to send - * @recvbuf: Buffer to save the response to - * @recv_size: Pointer to the size of the response buffer - * - * Returns 0 on success (and places the number of response bytes at - * recv_size) or -ve on failure. - */ - int (*xfer)(struct udevice *dev, const u8 *sendbuf, size_t send_size, - u8 *recvbuf, size_t *recv_size); -}; - -#define tpm_get_ops(dev) ((struct tpm_ops *)device_get_ops(dev)) - -/** - * tpm_open() - Request access to locality 0 for the caller - * - * After all commands have been completed the caller is supposed to - * call tpm_close(). - * - * Returns 0 on success, -ve on failure. - */ -int tpm_open(struct udevice *dev); - -/** - * tpm_close() - Close the current session - * - * Releasing the locked locality. Returns 0 on success, -ve 1 on - * failure (in case lock removal did not succeed). - */ -int tpm_close(struct udevice *dev); - -/** - * tpm_get_desc() - Get a text description of the TPM - * - * @dev: Device to check - * @buf: Buffer to put the string - * @size: Maximum size of buffer - * @return length of string, or -ENOSPC it no space - */ -int tpm_get_desc(struct udevice *dev, char *buf, int size); - -/** - * tpm_xfer() - send data to the TPM and get response - * - * This first uses the device's send() method to send the bytes. Then it calls - * recv() to get the reply. If recv() returns -EAGAIN then it will delay a - * short time and then call recv() again. - * - * Regardless of whether recv() completes successfully, it will then call - * cleanup() to finish the transaction. - * - * Note that the outgoing data is inspected to determine command type - * (ordinal) and a timeout is used for that command type. - * - * @sendbuf - buffer of the data to send - * @send_size size of the data to send - * @recvbuf - memory to save the response to - * @recv_len - pointer to the size of the response buffer - * - * Returns 0 on success (and places the number of response bytes at - * recv_len) or -ve on failure. - */ -int tpm_xfer(struct udevice *dev, const u8 *sendbuf, size_t send_size, - u8 *recvbuf, size_t *recv_size); - -/** - * Initialize TPM device. It must be called before any TPM commands. - * - * @return 0 on success, non-0 on error. - */ -int tpm_init(void); - -/** - * Issue a TPM_Startup command. - * - * @param mode TPM startup mode - * @return return code of the operation - */ -u32 tpm_startup(enum tpm_startup_type mode); - -/** - * Issue a TPM_SelfTestFull command. - * - * @return return code of the operation - */ -u32 tpm_self_test_full(void); - -/** - * Issue a TPM_ContinueSelfTest command. - * - * @return return code of the operation - */ -u32 tpm_continue_self_test(void); - -/** - * Issue a TPM_NV_DefineSpace command. The implementation is limited - * to specify TPM_NV_ATTRIBUTES and size of the area. The area index - * could be one of the special value listed in enum tpm_nv_index. - * - * @param index index of the area - * @param perm TPM_NV_ATTRIBUTES of the area - * @param size size of the area - * @return return code of the operation - */ -u32 tpm_nv_define_space(u32 index, u32 perm, u32 size); - -/** - * Issue a TPM_NV_ReadValue command. This implementation is limited - * to read the area from offset 0. The area index could be one of - * the special value listed in enum tpm_nv_index. - * - * @param index index of the area - * @param data output buffer of the area contents - * @param count size of output buffer - * @return return code of the operation - */ -u32 tpm_nv_read_value(u32 index, void *data, u32 count); - -/** - * Issue a TPM_NV_WriteValue command. This implementation is limited - * to write the area from offset 0. The area index could be one of - * the special value listed in enum tpm_nv_index. - * - * @param index index of the area - * @param data input buffer to be wrote to the area - * @param length length of data bytes of input buffer - * @return return code of the operation - */ -u32 tpm_nv_write_value(u32 index, const void *data, u32 length); - -/** - * Issue a TPM_Extend command. - * - * @param index index of the PCR - * @param in_digest 160-bit value representing the event to be - * recorded - * @param out_digest 160-bit PCR value after execution of the - * command - * @return return code of the operation - */ -u32 tpm_extend(u32 index, const void *in_digest, void *out_digest); - -/** - * Issue a TPM_PCRRead command. - * - * @param index index of the PCR - * @param data output buffer for contents of the named PCR - * @param count size of output buffer - * @return return code of the operation - */ -u32 tpm_pcr_read(u32 index, void *data, size_t count); - -/** - * Issue a TSC_PhysicalPresence command. TPM physical presence flag - * is bit-wise OR'ed of flags listed in enum tpm_physical_presence. - * - * @param presence TPM physical presence flag - * @return return code of the operation - */ -u32 tpm_tsc_physical_presence(u16 presence); - -/** - * Issue a TPM_ReadPubek command. - * - * @param data output buffer for the public endorsement key - * @param count size of output buffer - * @return return code of the operation - */ -u32 tpm_read_pubek(void *data, size_t count); - -/** - * Issue a TPM_ForceClear command. - * - * @return return code of the operation - */ -u32 tpm_force_clear(void); - -/** - * Issue a TPM_PhysicalEnable command. - * - * @return return code of the operation - */ -u32 tpm_physical_enable(void); - -/** - * Issue a TPM_PhysicalDisable command. - * - * @return return code of the operation - */ -u32 tpm_physical_disable(void); - -/** - * Issue a TPM_PhysicalSetDeactivated command. - * - * @param state boolean state of the deactivated flag - * @return return code of the operation - */ -u32 tpm_physical_set_deactivated(u8 state); - -/** - * Issue a TPM_GetCapability command. This implementation is limited - * to query sub_cap index that is 4-byte wide. - * - * @param cap_area partition of capabilities - * @param sub_cap further definition of capability, which is - * limited to be 4-byte wide - * @param cap output buffer for capability information - * @param count size of output buffer - * @return return code of the operation - */ -u32 tpm_get_capability(u32 cap_area, u32 sub_cap, void *cap, size_t count); - -/** - * Issue a TPM_FlushSpecific command for a AUTH resource. - * - * @param auth_handle handle of the auth session - * @return return code of the operation - */ -u32 tpm_terminate_auth_session(u32 auth_handle); - -/** - * Issue a TPM_OIAP command to setup an object independent authorization - * session. - * Information about the session is stored internally. - * If there was already an OIAP session active it is terminated and a new - * session is set up. - * - * @param auth_handle pointer to the (new) auth handle or NULL. - * @return return code of the operation - */ -u32 tpm_oiap(u32 *auth_handle); - -/** - * Ends an active OIAP session. - * - * @return return code of the operation - */ -u32 tpm_end_oiap(void); - -/** - * Issue a TPM_LoadKey2 (Auth1) command using an OIAP session for authenticating - * the usage of the parent key. - * - * @param parent_handle handle of the parent key. - * @param key pointer to the key structure (TPM_KEY or TPM_KEY12). - * @param key_length size of the key structure - * @param parent_key_usage_auth usage auth for the parent key - * @param key_handle pointer to the key handle - * @return return code of the operation - */ -u32 tpm_load_key2_oiap(u32 parent_handle, const void *key, size_t key_length, - const void *parent_key_usage_auth, u32 *key_handle); - -/** - * Issue a TPM_GetPubKey (Auth1) command using an OIAP session for - * authenticating the usage of the key. - * - * @param key_handle handle of the key - * @param usage_auth usage auth for the key - * @param pubkey pointer to the pub key buffer; may be NULL if the pubkey - * should not be stored. - * @param pubkey_len pointer to the pub key buffer len. On entry: the size of - * the provided pubkey buffer. On successful exit: the size - * of the stored TPM_PUBKEY structure (iff pubkey != NULL). - * @return return code of the operation - */ -u32 tpm_get_pub_key_oiap(u32 key_handle, const void *usage_auth, void *pubkey, - size_t *pubkey_len); - -/** - * Get the TPM permanent flags value - * - * @param pflags Place to put permanent flags - * @return return code of the operation - */ -u32 tpm_get_permanent_flags(struct tpm_permanent_flags *pflags); - -/** - * Get the TPM permissions - * - * @param perm Returns permissions value - * @return return code of the operation - */ -u32 tpm_get_permissions(u32 index, u32 *perm); - -/** - * Flush a resource with a given handle and type from the TPM - * - * @param key_handle handle of the resource - * @param resource_type type of the resource - * @return return code of the operation - */ -u32 tpm_flush_specific(u32 key_handle, u32 resource_type); - -#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 -/** - * Search for a key by usage AuthData and the hash of the parent's pub key. - * - * @param auth Usage auth of the key to search for - * @param pubkey_digest SHA1 hash of the pub key structure of the key - * @param[out] handle The handle of the key (Non-null iff found) - * @return 0 if key was found in TPM; != 0 if not. - */ -u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20], - u32 *handle); -#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ - -/** - * Read random bytes from the TPM RNG. The implementation deals with the fact - * that the TPM may legally return fewer bytes than requested by retrying - * until @p count bytes have been received. - * - * @param data output buffer for the random bytes - * @param count size of output buffer - * @return return code of the operation - */ -u32 tpm_get_random(void *data, u32 count); - -#endif /* __TPM_H */ diff --git a/lib/Makefile b/lib/Makefile index 2a56b3b1c6..72504e7654 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -39,7 +39,8 @@ obj-$(CONFIG_PHYSMEM) += physmem.o obj-y += qsort.o obj-y += rc4.o obj-$(CONFIG_SUPPORT_EMMC_RPMB) += sha256.o -obj-$(CONFIG_TPM_V1) += tpm.o +obj-$(CONFIG_TPM) += tpm-common.o +obj-$(CONFIG_TPM_V1) += tpm-v1.o obj-$(CONFIG_RBTREE) += rbtree.o obj-$(CONFIG_BITREVERSE) += bitrev.o obj-y += list_sort.o diff --git a/lib/tpm-common.c b/lib/tpm-common.c new file mode 100644 index 0000000000..4c2b9393c4 --- /dev/null +++ b/lib/tpm-common.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + */ + +#include +#include +#include +#include +#include "tpm-utils.h" + +int pack_byte_string(u8 *str, size_t size, const char *format, ...) +{ + va_list args; + size_t offset = 0, length = 0; + u8 *data = NULL; + u32 value = 0; + + va_start(args, format); + for (; *format; format++) { + switch (*format) { + case 'b': + offset = va_arg(args, size_t); + value = va_arg(args, int); + length = 1; + break; + case 'w': + offset = va_arg(args, size_t); + value = va_arg(args, int); + length = 2; + break; + case 'd': + offset = va_arg(args, size_t); + value = va_arg(args, u32); + length = 4; + break; + case 's': + offset = va_arg(args, size_t); + data = va_arg(args, u8 *); + length = va_arg(args, u32); + break; + default: + debug("Couldn't recognize format string\n"); + va_end(args); + return -1; + } + + if (offset + length > size) { + va_end(args); + return -1; + } + + switch (*format) { + case 'b': + str[offset] = value; + break; + case 'w': + put_unaligned_be16(value, str + offset); + break; + case 'd': + put_unaligned_be32(value, str + offset); + break; + case 's': + memcpy(str + offset, data, length); + break; + } + } + va_end(args); + + return 0; +} + +int unpack_byte_string(const u8 *str, size_t size, const char *format, ...) +{ + va_list args; + size_t offset = 0, length = 0; + u8 *ptr8 = NULL; + u16 *ptr16 = NULL; + u32 *ptr32 = NULL; + + va_start(args, format); + for (; *format; format++) { + switch (*format) { + case 'b': + offset = va_arg(args, size_t); + ptr8 = va_arg(args, u8 *); + length = 1; + break; + case 'w': + offset = va_arg(args, size_t); + ptr16 = va_arg(args, u16 *); + length = 2; + break; + case 'd': + offset = va_arg(args, size_t); + ptr32 = va_arg(args, u32 *); + length = 4; + break; + case 's': + offset = va_arg(args, size_t); + ptr8 = va_arg(args, u8 *); + length = va_arg(args, u32); + break; + default: + va_end(args); + debug("Couldn't recognize format string\n"); + return -1; + } + + if (offset + length > size) { + va_end(args); + return -1; + } + + switch (*format) { + case 'b': + *ptr8 = str[offset]; + break; + case 'w': + *ptr16 = get_unaligned_be16(str + offset); + break; + case 'd': + *ptr32 = get_unaligned_be32(str + offset); + break; + case 's': + memcpy(ptr8, str + offset, length); + break; + } + } + va_end(args); + + return 0; +} + +u32 tpm_command_size(const void *command) +{ + const size_t command_size_offset = 2; + + return get_unaligned_be32(command + command_size_offset); +} + +u32 tpm_return_code(const void *response) +{ + const size_t return_code_offset = 6; + + return get_unaligned_be32(response + return_code_offset); +} + +u32 tpm_sendrecv_command(const void *command, void *response, size_t *size_ptr) +{ + struct udevice *dev; + int err, ret; + u8 response_buffer[COMMAND_BUFFER_SIZE]; + size_t response_length; + + if (response) { + response_length = *size_ptr; + } else { + response = response_buffer; + response_length = sizeof(response_buffer); + } + + ret = uclass_first_device_err(UCLASS_TPM, &dev); + if (ret) + return ret; + err = tpm_xfer(dev, command, tpm_command_size(command), + response, &response_length); + + if (err < 0) + return TPM_LIB_ERROR; + if (size_ptr) + *size_ptr = response_length; + + return tpm_return_code(response); +} + +int tpm_init(void) +{ + struct udevice *dev; + int err; + + err = uclass_first_device_err(UCLASS_TPM, &dev); + if (err) + return err; + + return tpm_open(dev); +} diff --git a/lib/tpm-utils.h b/lib/tpm-utils.h new file mode 100644 index 0000000000..bc98d1ef8f --- /dev/null +++ b/lib/tpm-utils.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + */ + +#ifndef __TPM_UTILS_H +#define __TPM_UTILS_H + +#define COMMAND_BUFFER_SIZE 256 + +/* Internal error of TPM command library */ +#define TPM_LIB_ERROR ((u32)~0u) + +/** + * tpm_open() - Request access to locality 0 for the caller + * + * After all commands have been completed the caller is supposed to + * call tpm_close(). + * + * Returns 0 on success, -ve on failure. + */ +int tpm_open(struct udevice *dev); + +/** + * tpm_close() - Close the current session + * + * Releasing the locked locality. Returns 0 on success, -ve 1 on + * failure (in case lock removal did not succeed). + */ +int tpm_close(struct udevice *dev); + +/** + * Pack data into a byte string. The data types are specified in + * the format string: 'b' means unsigned byte, 'w' unsigned word, + * 'd' unsigned double word, and 's' byte string. The data are a + * series of offsets and values (for type byte string there are also + * lengths). The data values are packed into the byte string + * sequentially, and so a latter value could over-write a former + * value. + * + * @param str output string + * @param size size of output string + * @param format format string + * @param ... data points + * @return 0 on success, non-0 on error + */ +int pack_byte_string(u8 *str, size_t size, const char *format, ...); + +/** + * Unpack data from a byte string. The data types are specified in + * the format string: 'b' means unsigned byte, 'w' unsigned word, + * 'd' unsigned double word, and 's' byte string. The data are a + * series of offsets and pointers (for type byte string there are also + * lengths). + * + * @param str output string + * @param size size of output string + * @param format format string + * @param ... data points + * @return 0 on success, non-0 on error + */ +int unpack_byte_string(const u8 *str, size_t size, const char *format, ...); + +/** + * Get TPM command size. + * + * @param command byte string of TPM command + * @return command size of the TPM command + */ +u32 tpm_command_size(const void *command); + +/** + * Get TPM response return code, which is one of TPM_RESULT values. + * + * @param response byte string of TPM response + * @return return code of the TPM response + */ +u32 tpm_return_code(const void *response); + +/** + * Send a TPM command and return response's return code, and optionally + * return response to caller. + * + * @param command byte string of TPM command + * @param response output buffer for TPM response, or NULL if the + * caller does not care about it + * @param size_ptr output buffer size (input parameter) and TPM + * response length (output parameter); this parameter + * is a bidirectional + * @return return code of the TPM response + */ +u32 tpm_sendrecv_command(const void *command, void *response, size_t *size_ptr); + +#endif /* __TPM_UTILS_H */ diff --git a/lib/tpm-v1.c b/lib/tpm-v1.c new file mode 100644 index 0000000000..7aecb24f92 --- /dev/null +++ b/lib/tpm-v1.c @@ -0,0 +1,852 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + */ + +#include +#include +#include +#include +#include +#include +#include "tpm-utils.h" + +#ifdef CONFIG_TPM_AUTH_SESSIONS + +#ifndef CONFIG_SHA1 +#error "TPM_AUTH_SESSIONS require SHA1 to be configured, too" +#endif /* !CONFIG_SHA1 */ + +struct session_data { + int valid; + u32 handle; + u8 nonce_even[DIGEST_LENGTH]; + u8 nonce_odd[DIGEST_LENGTH]; +}; + +static struct session_data oiap_session = {0, }; + +#endif /* CONFIG_TPM_AUTH_SESSIONS */ + +u32 tpm_startup(enum tpm_startup_type mode) +{ + const u8 command[12] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0, + }; + const size_t mode_offset = 10; + u8 buf[COMMAND_BUFFER_SIZE]; + + if (pack_byte_string(buf, sizeof(buf), "sw", + 0, command, sizeof(command), + mode_offset, mode)) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(buf, NULL, NULL); +} + +u32 tpm_self_test_full(void) +{ + const u8 command[10] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, + }; + return tpm_sendrecv_command(command, NULL, NULL); +} + +u32 tpm_continue_self_test(void) +{ + const u8 command[10] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53, + }; + return tpm_sendrecv_command(command, NULL, NULL); +} + +u32 tpm_nv_define_space(u32 index, u32 perm, u32 size) +{ + const u8 command[101] = { + 0x0, 0xc1, /* TPM_TAG */ + 0x0, 0x0, 0x0, 0x65, /* parameter size */ + 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */ + /* TPM_NV_DATA_PUBLIC->... */ + 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */ + 0, 0, 0, 0, /* ...->TPM_NV_INDEX */ + /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */ + 0x0, 0x3, + 0, 0, 0, + 0x1f, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */ + 0x0, 0x3, + 0, 0, 0, + 0x1f, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* TPM_NV_ATTRIBUTES->... */ + 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */ + 0, 0, 0, 0, /* ...->attributes */ + /* End of TPM_NV_ATTRIBUTES */ + 0, /* bReadSTClear */ + 0, /* bWriteSTClear */ + 0, /* bWriteDefine */ + 0, 0, 0, 0, /* size */ + }; + const size_t index_offset = 12; + const size_t perm_offset = 70; + const size_t size_offset = 77; + u8 buf[COMMAND_BUFFER_SIZE]; + + if (pack_byte_string(buf, sizeof(buf), "sddd", + 0, command, sizeof(command), + index_offset, index, + perm_offset, perm, + size_offset, size)) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(buf, NULL, NULL); +} + +u32 tpm_nv_read_value(u32 index, void *data, u32 count) +{ + const u8 command[22] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf, + }; + const size_t index_offset = 10; + const size_t length_offset = 18; + const size_t data_size_offset = 10; + const size_t data_offset = 14; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + size_t response_length = sizeof(response); + u32 data_size; + u32 err; + + if (pack_byte_string(buf, sizeof(buf), "sdd", + 0, command, sizeof(command), + index_offset, index, + length_offset, count)) + return TPM_LIB_ERROR; + err = tpm_sendrecv_command(buf, response, &response_length); + if (err) + return err; + if (unpack_byte_string(response, response_length, "d", + data_size_offset, &data_size)) + return TPM_LIB_ERROR; + if (data_size > count) + return TPM_LIB_ERROR; + if (unpack_byte_string(response, response_length, "s", + data_offset, data, data_size)) + return TPM_LIB_ERROR; + + return 0; +} + +u32 tpm_nv_write_value(u32 index, const void *data, u32 length) +{ + const u8 command[256] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd, + }; + const size_t command_size_offset = 2; + const size_t index_offset = 10; + const size_t length_offset = 18; + const size_t data_offset = 22; + const size_t write_info_size = 12; + const u32 total_length = + TPM_REQUEST_HEADER_LENGTH + write_info_size + length; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + size_t response_length = sizeof(response); + u32 err; + + if (pack_byte_string(buf, sizeof(buf), "sddds", + 0, command, sizeof(command), + command_size_offset, total_length, + index_offset, index, + length_offset, length, + data_offset, data, length)) + return TPM_LIB_ERROR; + err = tpm_sendrecv_command(buf, response, &response_length); + if (err) + return err; + + return 0; +} + +u32 tpm_extend(u32 index, const void *in_digest, void *out_digest) +{ + const u8 command[34] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14, + }; + const size_t index_offset = 10; + const size_t in_digest_offset = 14; + const size_t out_digest_offset = 10; + u8 buf[COMMAND_BUFFER_SIZE]; + u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH]; + size_t response_length = sizeof(response); + u32 err; + + if (pack_byte_string(buf, sizeof(buf), "sds", + 0, command, sizeof(command), + index_offset, index, + in_digest_offset, in_digest, + PCR_DIGEST_LENGTH)) + return TPM_LIB_ERROR; + err = tpm_sendrecv_command(buf, response, &response_length); + if (err) + return err; + + if (unpack_byte_string(response, response_length, "s", + out_digest_offset, out_digest, + PCR_DIGEST_LENGTH)) + return TPM_LIB_ERROR; + + return 0; +} + +u32 tpm_pcr_read(u32 index, void *data, size_t count) +{ + const u8 command[14] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15, + }; + const size_t index_offset = 10; + const size_t out_digest_offset = 10; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + size_t response_length = sizeof(response); + u32 err; + + if (count < PCR_DIGEST_LENGTH) + return TPM_LIB_ERROR; + + if (pack_byte_string(buf, sizeof(buf), "sd", + 0, command, sizeof(command), + index_offset, index)) + return TPM_LIB_ERROR; + err = tpm_sendrecv_command(buf, response, &response_length); + if (err) + return err; + if (unpack_byte_string(response, response_length, "s", + out_digest_offset, data, PCR_DIGEST_LENGTH)) + return TPM_LIB_ERROR; + + return 0; +} + +u32 tpm_tsc_physical_presence(u16 presence) +{ + const u8 command[12] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0, + }; + const size_t presence_offset = 10; + u8 buf[COMMAND_BUFFER_SIZE]; + + if (pack_byte_string(buf, sizeof(buf), "sw", + 0, command, sizeof(command), + presence_offset, presence)) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(buf, NULL, NULL); +} + +u32 tpm_read_pubek(void *data, size_t count) +{ + const u8 command[30] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c, + }; + const size_t response_size_offset = 2; + const size_t data_offset = 10; + const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20; + u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE]; + size_t response_length = sizeof(response); + u32 data_size; + u32 err; + + err = tpm_sendrecv_command(command, response, &response_length); + if (err) + return err; + if (unpack_byte_string(response, response_length, "d", + response_size_offset, &data_size)) + return TPM_LIB_ERROR; + if (data_size < header_and_checksum_size) + return TPM_LIB_ERROR; + data_size -= header_and_checksum_size; + if (data_size > count) + return TPM_LIB_ERROR; + if (unpack_byte_string(response, response_length, "s", + data_offset, data, data_size)) + return TPM_LIB_ERROR; + + return 0; +} + +u32 tpm_force_clear(void) +{ + const u8 command[10] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d, + }; + + return tpm_sendrecv_command(command, NULL, NULL); +} + +u32 tpm_physical_enable(void) +{ + const u8 command[10] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f, + }; + + return tpm_sendrecv_command(command, NULL, NULL); +} + +u32 tpm_physical_disable(void) +{ + const u8 command[10] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70, + }; + + return tpm_sendrecv_command(command, NULL, NULL); +} + +u32 tpm_physical_set_deactivated(u8 state) +{ + const u8 command[11] = { + 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72, + }; + const size_t state_offset = 10; + u8 buf[COMMAND_BUFFER_SIZE]; + + if (pack_byte_string(buf, sizeof(buf), "sb", + 0, command, sizeof(command), + state_offset, state)) + return TPM_LIB_ERROR; + + return tpm_sendrecv_command(buf, NULL, NULL); +} + +u32 tpm_get_capability(u32 cap_area, u32 sub_cap, void *cap, size_t count) +{ + const u8 command[22] = { + 0x0, 0xc1, /* TPM_TAG */ + 0x0, 0x0, 0x0, 0x16, /* parameter size */ + 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ + 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */ + 0x0, 0x0, 0x0, 0x4, /* subcap size */ + 0x0, 0x0, 0x0, 0x0, /* subcap value */ + }; + const size_t cap_area_offset = 10; + const size_t sub_cap_offset = 18; + const size_t cap_offset = 14; + const size_t cap_size_offset = 10; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + size_t response_length = sizeof(response); + u32 cap_size; + u32 err; + + if (pack_byte_string(buf, sizeof(buf), "sdd", + 0, command, sizeof(command), + cap_area_offset, cap_area, + sub_cap_offset, sub_cap)) + return TPM_LIB_ERROR; + err = tpm_sendrecv_command(buf, response, &response_length); + if (err) + return err; + if (unpack_byte_string(response, response_length, "d", + cap_size_offset, &cap_size)) + return TPM_LIB_ERROR; + if (cap_size > response_length || cap_size > count) + return TPM_LIB_ERROR; + if (unpack_byte_string(response, response_length, "s", + cap_offset, cap, cap_size)) + return TPM_LIB_ERROR; + + return 0; +} + +u32 tpm_get_permanent_flags(struct tpm_permanent_flags *pflags) +{ + const u8 command[22] = { + 0x0, 0xc1, /* TPM_TAG */ + 0x0, 0x0, 0x0, 0x16, /* parameter size */ + 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ + 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */ + 0x0, 0x0, 0x0, 0x4, /* subcap size */ + 0x0, 0x0, 0x1, 0x8, /* subcap value */ + }; + const size_t data_size_offset = TPM_HEADER_SIZE; + const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32); + u8 response[COMMAND_BUFFER_SIZE]; + size_t response_length = sizeof(response); + u32 err; + u32 data_size; + + err = tpm_sendrecv_command(command, response, &response_length); + if (err) + return err; + if (unpack_byte_string(response, response_length, "d", + data_size_offset, &data_size)) + return TPM_LIB_ERROR; + if (data_size < sizeof(*pflags)) + return TPM_LIB_ERROR; + if (unpack_byte_string(response, response_length, "s", + data_offset, pflags, sizeof(*pflags))) + return TPM_LIB_ERROR; + + return 0; +} + +u32 tpm_get_permissions(u32 index, u32 *perm) +{ + const u8 command[22] = { + 0x0, 0xc1, /* TPM_TAG */ + 0x0, 0x0, 0x0, 0x16, /* parameter size */ + 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ + 0x0, 0x0, 0x0, 0x11, + 0x0, 0x0, 0x0, 0x4, + }; + const size_t index_offset = 18; + const size_t perm_offset = 60; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + size_t response_length = sizeof(response); + u32 err; + + if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command), + index_offset, index)) + return TPM_LIB_ERROR; + err = tpm_sendrecv_command(buf, response, &response_length); + if (err) + return err; + if (unpack_byte_string(response, response_length, "d", + perm_offset, perm)) + return TPM_LIB_ERROR; + + return 0; +} + +#ifdef CONFIG_TPM_FLUSH_RESOURCES +u32 tpm_flush_specific(u32 key_handle, u32 resource_type) +{ + const u8 command[18] = { + 0x00, 0xc1, /* TPM_TAG */ + 0x00, 0x00, 0x00, 0x12, /* parameter size */ + 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */ + 0x00, 0x00, 0x00, 0x00, /* key handle */ + 0x00, 0x00, 0x00, 0x00, /* resource type */ + }; + const size_t key_handle_offset = 10; + const size_t resource_type_offset = 14; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + size_t response_length = sizeof(response); + u32 err; + + if (pack_byte_string(buf, sizeof(buf), "sdd", + 0, command, sizeof(command), + key_handle_offset, key_handle, + resource_type_offset, resource_type)) + return TPM_LIB_ERROR; + + err = tpm_sendrecv_command(buf, response, &response_length); + if (err) + return err; + return 0; +} +#endif /* CONFIG_TPM_FLUSH_RESOURCES */ + +#ifdef CONFIG_TPM_AUTH_SESSIONS + +/** + * Fill an authentication block in a request. + * This func can create the first as well as the second auth block (for + * double authorized commands). + * + * @param request pointer to the request (w/ uninitialised auth data) + * @param request_len0 length of the request without auth data + * @param handles_len length of the handles area in request + * @param auth_session pointer to the (valid) auth session to be used + * @param request_auth pointer to the auth block of the request to be filled + * @param auth authentication data (HMAC key) + */ +static u32 create_request_auth(const void *request, size_t request_len0, + size_t handles_len, + struct session_data *auth_session, + void *request_auth, const void *auth) +{ + u8 hmac_data[DIGEST_LENGTH * 3 + 1]; + sha1_context hash_ctx; + const size_t command_code_offset = 6; + const size_t auth_nonce_odd_offset = 4; + const size_t auth_continue_offset = 24; + const size_t auth_auth_offset = 25; + + if (!auth_session || !auth_session->valid) + return TPM_LIB_ERROR; + + sha1_starts(&hash_ctx); + sha1_update(&hash_ctx, request + command_code_offset, 4); + if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len) + sha1_update(&hash_ctx, + request + TPM_REQUEST_HEADER_LENGTH + handles_len, + request_len0 - TPM_REQUEST_HEADER_LENGTH + - handles_len); + sha1_finish(&hash_ctx, hmac_data); + + sha1_starts(&hash_ctx); + sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH); + sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data)); + sha1_finish(&hash_ctx, auth_session->nonce_odd); + + if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb", + 0, auth_session->handle, + auth_nonce_odd_offset, auth_session->nonce_odd, + DIGEST_LENGTH, + auth_continue_offset, 1)) + return TPM_LIB_ERROR; + if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss", + DIGEST_LENGTH, + auth_session->nonce_even, + DIGEST_LENGTH, + 2 * DIGEST_LENGTH, + request_auth + auth_nonce_odd_offset, + DIGEST_LENGTH + 1)) + return TPM_LIB_ERROR; + sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data), + request_auth + auth_auth_offset); + + return TPM_SUCCESS; +} + +/** + * Verify an authentication block in a response. + * Since this func updates the nonce_even in the session data it has to be + * called when receiving a succesfull AUTH response. + * This func can verify the first as well as the second auth block (for + * double authorized commands). + * + * @param command_code command code of the request + * @param response pointer to the request (w/ uninitialised auth data) + * @param handles_len length of the handles area in response + * @param auth_session pointer to the (valid) auth session to be used + * @param response_auth pointer to the auth block of the response to be verified + * @param auth authentication data (HMAC key) + */ +static u32 verify_response_auth(u32 command_code, const void *response, + size_t response_len0, size_t handles_len, + struct session_data *auth_session, + const void *response_auth, const void *auth) +{ + u8 hmac_data[DIGEST_LENGTH * 3 + 1]; + u8 computed_auth[DIGEST_LENGTH]; + sha1_context hash_ctx; + const size_t return_code_offset = 6; + const size_t auth_continue_offset = 20; + const size_t auth_auth_offset = 21; + u8 auth_continue; + + if (!auth_session || !auth_session->valid) + return TPM_AUTHFAIL; + if (pack_byte_string(hmac_data, sizeof(hmac_data), "d", + 0, command_code)) + return TPM_LIB_ERROR; + if (response_len0 < TPM_RESPONSE_HEADER_LENGTH) + return TPM_LIB_ERROR; + + sha1_starts(&hash_ctx); + sha1_update(&hash_ctx, response + return_code_offset, 4); + sha1_update(&hash_ctx, hmac_data, 4); + if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len) + sha1_update(&hash_ctx, + response + TPM_RESPONSE_HEADER_LENGTH + handles_len, + response_len0 - TPM_RESPONSE_HEADER_LENGTH + - handles_len); + sha1_finish(&hash_ctx, hmac_data); + + memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH); + auth_continue = ((u8 *)response_auth)[auth_continue_offset]; + if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb", + DIGEST_LENGTH, + response_auth, + DIGEST_LENGTH, + 2 * DIGEST_LENGTH, + auth_session->nonce_odd, + DIGEST_LENGTH, + 3 * DIGEST_LENGTH, + auth_continue)) + return TPM_LIB_ERROR; + + sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data), + computed_auth); + + if (memcmp(computed_auth, response_auth + auth_auth_offset, + DIGEST_LENGTH)) + return TPM_AUTHFAIL; + + return TPM_SUCCESS; +} + +u32 tpm_terminate_auth_session(u32 auth_handle) +{ + const u8 command[18] = { + 0x00, 0xc1, /* TPM_TAG */ + 0x00, 0x00, 0x00, 0x00, /* parameter size */ + 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */ + 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */ + 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */ + }; + const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH; + u8 request[COMMAND_BUFFER_SIZE]; + + if (pack_byte_string(request, sizeof(request), "sd", + 0, command, sizeof(command), + req_handle_offset, auth_handle)) + return TPM_LIB_ERROR; + if (oiap_session.valid && oiap_session.handle == auth_handle) + oiap_session.valid = 0; + + return tpm_sendrecv_command(request, NULL, NULL); +} + +u32 tpm_end_oiap(void) +{ + u32 err = TPM_SUCCESS; + + if (oiap_session.valid) + err = tpm_terminate_auth_session(oiap_session.handle); + return err; +} + +u32 tpm_oiap(u32 *auth_handle) +{ + const u8 command[10] = { + 0x00, 0xc1, /* TPM_TAG */ + 0x00, 0x00, 0x00, 0x0a, /* parameter size */ + 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */ + }; + const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH; + const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4; + u8 response[COMMAND_BUFFER_SIZE]; + size_t response_length = sizeof(response); + u32 err; + + if (oiap_session.valid) + tpm_terminate_auth_session(oiap_session.handle); + + err = tpm_sendrecv_command(command, response, &response_length); + if (err) + return err; + if (unpack_byte_string(response, response_length, "ds", + res_auth_handle_offset, &oiap_session.handle, + res_nonce_even_offset, &oiap_session.nonce_even, + (u32)DIGEST_LENGTH)) + return TPM_LIB_ERROR; + oiap_session.valid = 1; + if (auth_handle) + *auth_handle = oiap_session.handle; + return 0; +} + +u32 tpm_load_key2_oiap(u32 parent_handle, const void *key, size_t key_length, + const void *parent_key_usage_auth, u32 *key_handle) +{ + const u8 command[14] = { + 0x00, 0xc2, /* TPM_TAG */ + 0x00, 0x00, 0x00, 0x00, /* parameter size */ + 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */ + 0x00, 0x00, 0x00, 0x00, /* parent handle */ + }; + const size_t req_size_offset = 2; + const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH; + const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4; + const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH; + u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH + + TPM_REQUEST_AUTH_LENGTH]; + u8 response[COMMAND_BUFFER_SIZE]; + size_t response_length = sizeof(response); + u32 err; + + if (!oiap_session.valid) { + err = tpm_oiap(NULL); + if (err) + return err; + } + if (pack_byte_string(request, sizeof(request), "sdds", + 0, command, sizeof(command), + req_size_offset, + sizeof(command) + key_length + + TPM_REQUEST_AUTH_LENGTH, + req_parent_handle_offset, parent_handle, + req_key_offset, key, key_length + )) + return TPM_LIB_ERROR; + + err = create_request_auth(request, sizeof(command) + key_length, 4, + &oiap_session, + request + sizeof(command) + key_length, + parent_key_usage_auth); + if (err) + return err; + err = tpm_sendrecv_command(request, response, &response_length); + if (err) { + if (err == TPM_AUTHFAIL) + oiap_session.valid = 0; + return err; + } + + err = verify_response_auth(0x00000041, response, + response_length - TPM_RESPONSE_AUTH_LENGTH, + 4, &oiap_session, + response + response_length - + TPM_RESPONSE_AUTH_LENGTH, + parent_key_usage_auth); + if (err) + return err; + + if (key_handle) { + if (unpack_byte_string(response, response_length, "d", + res_handle_offset, key_handle)) + return TPM_LIB_ERROR; + } + + return 0; +} + +u32 tpm_get_pub_key_oiap(u32 key_handle, const void *usage_auth, void *pubkey, + size_t *pubkey_len) +{ + const u8 command[14] = { + 0x00, 0xc2, /* TPM_TAG */ + 0x00, 0x00, 0x00, 0x00, /* parameter size */ + 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */ + 0x00, 0x00, 0x00, 0x00, /* key handle */ + }; + const size_t req_size_offset = 2; + const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH; + const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH; + u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH]; + u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH + + TPM_RESPONSE_AUTH_LENGTH]; + size_t response_length = sizeof(response); + u32 err; + + if (!oiap_session.valid) { + err = tpm_oiap(NULL); + if (err) + return err; + } + if (pack_byte_string(request, sizeof(request), "sdd", + 0, command, sizeof(command), + req_size_offset, + (u32)(sizeof(command) + + TPM_REQUEST_AUTH_LENGTH), + req_key_handle_offset, key_handle + )) + return TPM_LIB_ERROR; + err = create_request_auth(request, sizeof(command), 4, &oiap_session, + request + sizeof(command), usage_auth); + if (err) + return err; + err = tpm_sendrecv_command(request, response, &response_length); + if (err) { + if (err == TPM_AUTHFAIL) + oiap_session.valid = 0; + return err; + } + err = verify_response_auth(0x00000021, response, + response_length - TPM_RESPONSE_AUTH_LENGTH, + 0, &oiap_session, + response + response_length - + TPM_RESPONSE_AUTH_LENGTH, + usage_auth); + if (err) + return err; + + if (pubkey) { + if ((response_length - TPM_RESPONSE_HEADER_LENGTH + - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len) + return TPM_LIB_ERROR; + *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH + - TPM_RESPONSE_AUTH_LENGTH; + memcpy(pubkey, response + res_pubkey_offset, + response_length - TPM_RESPONSE_HEADER_LENGTH + - TPM_RESPONSE_AUTH_LENGTH); + } + + return 0; +} + +#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 +u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20], + u32 *handle) +{ + u16 key_count; + u32 key_handles[10]; + u8 buf[288]; + u8 *ptr; + u32 err; + u8 digest[20]; + size_t buf_len; + unsigned int i; + + /* fetch list of already loaded keys in the TPM */ + err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf)); + if (err) + return -1; + key_count = get_unaligned_be16(buf); + ptr = buf + 2; + for (i = 0; i < key_count; ++i, ptr += 4) + key_handles[i] = get_unaligned_be32(ptr); + + /* now search a(/ the) key which we can access with the given auth */ + for (i = 0; i < key_count; ++i) { + buf_len = sizeof(buf); + err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len); + if (err && err != TPM_AUTHFAIL) + return -1; + if (err) + continue; + sha1_csum(buf, buf_len, digest); + if (!memcmp(digest, pubkey_digest, 20)) { + *handle = key_handles[i]; + return 0; + } + } + return 1; +} +#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ + +#endif /* CONFIG_TPM_AUTH_SESSIONS */ + +u32 tpm_get_random(void *data, u32 count) +{ + const u8 command[14] = { + 0x0, 0xc1, /* TPM_TAG */ + 0x0, 0x0, 0x0, 0xe, /* parameter size */ + 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */ + }; + const size_t length_offset = 10; + const size_t data_size_offset = 10; + const size_t data_offset = 14; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + size_t response_length = sizeof(response); + u32 data_size; + u8 *out = data; + + while (count > 0) { + u32 this_bytes = min((size_t)count, + sizeof(response) - data_offset); + u32 err; + + if (pack_byte_string(buf, sizeof(buf), "sd", + 0, command, sizeof(command), + length_offset, this_bytes)) + return TPM_LIB_ERROR; + err = tpm_sendrecv_command(buf, response, &response_length); + if (err) + return err; + if (unpack_byte_string(response, response_length, "d", + data_size_offset, &data_size)) + return TPM_LIB_ERROR; + if (data_size > count) + return TPM_LIB_ERROR; + if (unpack_byte_string(response, response_length, "s", + data_offset, out, data_size)) + return TPM_LIB_ERROR; + + count -= data_size; + out += data_size; + } + + return 0; +} diff --git a/lib/tpm.c b/lib/tpm.c deleted file mode 100644 index 899528e178..0000000000 --- a/lib/tpm.c +++ /dev/null @@ -1,1096 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2013 The Chromium OS Authors. - * Coypright (c) 2013 Guntermann & Drunck GmbH - */ - -#include -#include -#include -#include -#include - -/* Internal error of TPM command library */ -#define TPM_LIB_ERROR ((u32)~0u) - -/* Useful constants */ -enum { - COMMAND_BUFFER_SIZE = 256, - TPM_REQUEST_HEADER_LENGTH = 10, - TPM_RESPONSE_HEADER_LENGTH = 10, - PCR_DIGEST_LENGTH = 20, - DIGEST_LENGTH = 20, - TPM_REQUEST_AUTH_LENGTH = 45, - TPM_RESPONSE_AUTH_LENGTH = 41, - /* some max lengths, valid for RSA keys <= 2048 bits */ - TPM_KEY12_MAX_LENGTH = 618, - TPM_PUBKEY_MAX_LENGTH = 288, -}; - -#ifdef CONFIG_TPM_AUTH_SESSIONS - -#ifndef CONFIG_SHA1 -#error "TPM_AUTH_SESSIONS require SHA1 to be configured, too" -#endif /* !CONFIG_SHA1 */ - -struct session_data { - int valid; - u32 handle; - u8 nonce_even[DIGEST_LENGTH]; - u8 nonce_odd[DIGEST_LENGTH]; -}; - -static struct session_data oiap_session = {0, }; - -#endif /* CONFIG_TPM_AUTH_SESSIONS */ - -/** - * Pack data into a byte string. The data types are specified in - * the format string: 'b' means unsigned byte, 'w' unsigned word, - * 'd' unsigned double word, and 's' byte string. The data are a - * series of offsets and values (for type byte string there are also - * lengths). The data values are packed into the byte string - * sequentially, and so a latter value could over-write a former - * value. - * - * @param str output string - * @param size size of output string - * @param format format string - * @param ... data points - * @return 0 on success, non-0 on error - */ -int pack_byte_string(u8 *str, size_t size, const char *format, ...) -{ - va_list args; - size_t offset = 0, length = 0; - u8 *data = NULL; - u32 value = 0; - - va_start(args, format); - for (; *format; format++) { - switch (*format) { - case 'b': - offset = va_arg(args, size_t); - value = va_arg(args, int); - length = 1; - break; - case 'w': - offset = va_arg(args, size_t); - value = va_arg(args, int); - length = 2; - break; - case 'd': - offset = va_arg(args, size_t); - value = va_arg(args, u32); - length = 4; - break; - case 's': - offset = va_arg(args, size_t); - data = va_arg(args, u8 *); - length = va_arg(args, u32); - break; - default: - debug("Couldn't recognize format string\n"); - va_end(args); - return -1; - } - - if (offset + length > size) { - va_end(args); - return -1; - } - - switch (*format) { - case 'b': - str[offset] = value; - break; - case 'w': - put_unaligned_be16(value, str + offset); - break; - case 'd': - put_unaligned_be32(value, str + offset); - break; - case 's': - memcpy(str + offset, data, length); - break; - } - } - va_end(args); - - return 0; -} - -/** - * Unpack data from a byte string. The data types are specified in - * the format string: 'b' means unsigned byte, 'w' unsigned word, - * 'd' unsigned double word, and 's' byte string. The data are a - * series of offsets and pointers (for type byte string there are also - * lengths). - * - * @param str output string - * @param size size of output string - * @param format format string - * @param ... data points - * @return 0 on success, non-0 on error - */ -int unpack_byte_string(const u8 *str, size_t size, const char *format, ...) -{ - va_list args; - size_t offset = 0, length = 0; - u8 *ptr8 = NULL; - u16 *ptr16 = NULL; - u32 *ptr32 = NULL; - - va_start(args, format); - for (; *format; format++) { - switch (*format) { - case 'b': - offset = va_arg(args, size_t); - ptr8 = va_arg(args, u8 *); - length = 1; - break; - case 'w': - offset = va_arg(args, size_t); - ptr16 = va_arg(args, u16 *); - length = 2; - break; - case 'd': - offset = va_arg(args, size_t); - ptr32 = va_arg(args, u32 *); - length = 4; - break; - case 's': - offset = va_arg(args, size_t); - ptr8 = va_arg(args, u8 *); - length = va_arg(args, u32); - break; - default: - va_end(args); - debug("Couldn't recognize format string\n"); - return -1; - } - - if (offset + length > size) { - va_end(args); - return -1; - } - - switch (*format) { - case 'b': - *ptr8 = str[offset]; - break; - case 'w': - *ptr16 = get_unaligned_be16(str + offset); - break; - case 'd': - *ptr32 = get_unaligned_be32(str + offset); - break; - case 's': - memcpy(ptr8, str + offset, length); - break; - } - } - va_end(args); - - return 0; -} - -/** - * Get TPM command size. - * - * @param command byte string of TPM command - * @return command size of the TPM command - */ -static u32 tpm_command_size(const void *command) -{ - const size_t command_size_offset = 2; - - return get_unaligned_be32(command + command_size_offset); -} - -/** - * Get TPM response return code, which is one of TPM_RESULT values. - * - * @param response byte string of TPM response - * @return return code of the TPM response - */ -static u32 tpm_return_code(const void *response) -{ - const size_t return_code_offset = 6; - - return get_unaligned_be32(response + return_code_offset); -} - -/** - * Send a TPM command and return response's return code, and optionally - * return response to caller. - * - * @param command byte string of TPM command - * @param response output buffer for TPM response, or NULL if the - * caller does not care about it - * @param size_ptr output buffer size (input parameter) and TPM - * response length (output parameter); this parameter - * is a bidirectional - * @return return code of the TPM response - */ -static u32 tpm_sendrecv_command(const void *command, void *response, - size_t *size_ptr) -{ - struct udevice *dev; - int err, ret; - u8 response_buffer[COMMAND_BUFFER_SIZE]; - size_t response_length; - - if (response) { - response_length = *size_ptr; - } else { - response = response_buffer; - response_length = sizeof(response_buffer); - } - - ret = uclass_first_device_err(UCLASS_TPM, &dev); - if (ret) - return ret; - err = tpm_xfer(dev, command, tpm_command_size(command), - response, &response_length); - - if (err < 0) - return TPM_LIB_ERROR; - if (size_ptr) - *size_ptr = response_length; - - return tpm_return_code(response); -} - -int tpm_init(void) -{ - int err; - struct udevice *dev; - - err = uclass_first_device_err(UCLASS_TPM, &dev); - if (err) - return err; - return tpm_open(dev); -} - -u32 tpm_startup(enum tpm_startup_type mode) -{ - const u8 command[12] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0, - }; - const size_t mode_offset = 10; - u8 buf[COMMAND_BUFFER_SIZE]; - - if (pack_byte_string(buf, sizeof(buf), "sw", - 0, command, sizeof(command), - mode_offset, mode)) - return TPM_LIB_ERROR; - - return tpm_sendrecv_command(buf, NULL, NULL); -} - -u32 tpm_self_test_full(void) -{ - const u8 command[10] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, - }; - return tpm_sendrecv_command(command, NULL, NULL); -} - -u32 tpm_continue_self_test(void) -{ - const u8 command[10] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53, - }; - return tpm_sendrecv_command(command, NULL, NULL); -} - -u32 tpm_nv_define_space(u32 index, u32 perm, u32 size) -{ - const u8 command[101] = { - 0x0, 0xc1, /* TPM_TAG */ - 0x0, 0x0, 0x0, 0x65, /* parameter size */ - 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */ - /* TPM_NV_DATA_PUBLIC->... */ - 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */ - 0, 0, 0, 0, /* ...->TPM_NV_INDEX */ - /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */ - 0x0, 0x3, - 0, 0, 0, - 0x1f, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */ - 0x0, 0x3, - 0, 0, 0, - 0x1f, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* TPM_NV_ATTRIBUTES->... */ - 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */ - 0, 0, 0, 0, /* ...->attributes */ - /* End of TPM_NV_ATTRIBUTES */ - 0, /* bReadSTClear */ - 0, /* bWriteSTClear */ - 0, /* bWriteDefine */ - 0, 0, 0, 0, /* size */ - }; - const size_t index_offset = 12; - const size_t perm_offset = 70; - const size_t size_offset = 77; - u8 buf[COMMAND_BUFFER_SIZE]; - - if (pack_byte_string(buf, sizeof(buf), "sddd", - 0, command, sizeof(command), - index_offset, index, - perm_offset, perm, - size_offset, size)) - return TPM_LIB_ERROR; - - return tpm_sendrecv_command(buf, NULL, NULL); -} - -u32 tpm_nv_read_value(u32 index, void *data, u32 count) -{ - const u8 command[22] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf, - }; - const size_t index_offset = 10; - const size_t length_offset = 18; - const size_t data_size_offset = 10; - const size_t data_offset = 14; - u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; - size_t response_length = sizeof(response); - u32 data_size; - u32 err; - - if (pack_byte_string(buf, sizeof(buf), "sdd", - 0, command, sizeof(command), - index_offset, index, - length_offset, count)) - return TPM_LIB_ERROR; - err = tpm_sendrecv_command(buf, response, &response_length); - if (err) - return err; - if (unpack_byte_string(response, response_length, "d", - data_size_offset, &data_size)) - return TPM_LIB_ERROR; - if (data_size > count) - return TPM_LIB_ERROR; - if (unpack_byte_string(response, response_length, "s", - data_offset, data, data_size)) - return TPM_LIB_ERROR; - - return 0; -} - -u32 tpm_nv_write_value(u32 index, const void *data, u32 length) -{ - const u8 command[256] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd, - }; - const size_t command_size_offset = 2; - const size_t index_offset = 10; - const size_t length_offset = 18; - const size_t data_offset = 22; - const size_t write_info_size = 12; - const u32 total_length = - TPM_REQUEST_HEADER_LENGTH + write_info_size + length; - u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; - size_t response_length = sizeof(response); - u32 err; - - if (pack_byte_string(buf, sizeof(buf), "sddds", - 0, command, sizeof(command), - command_size_offset, total_length, - index_offset, index, - length_offset, length, - data_offset, data, length)) - return TPM_LIB_ERROR; - err = tpm_sendrecv_command(buf, response, &response_length); - if (err) - return err; - - return 0; -} - -u32 tpm_extend(u32 index, const void *in_digest, void *out_digest) -{ - const u8 command[34] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14, - }; - const size_t index_offset = 10; - const size_t in_digest_offset = 14; - const size_t out_digest_offset = 10; - u8 buf[COMMAND_BUFFER_SIZE]; - u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH]; - size_t response_length = sizeof(response); - u32 err; - - if (pack_byte_string(buf, sizeof(buf), "sds", - 0, command, sizeof(command), - index_offset, index, - in_digest_offset, in_digest, - PCR_DIGEST_LENGTH)) - return TPM_LIB_ERROR; - err = tpm_sendrecv_command(buf, response, &response_length); - if (err) - return err; - - if (unpack_byte_string(response, response_length, "s", - out_digest_offset, out_digest, - PCR_DIGEST_LENGTH)) - return TPM_LIB_ERROR; - - return 0; -} - -u32 tpm_pcr_read(u32 index, void *data, size_t count) -{ - const u8 command[14] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15, - }; - const size_t index_offset = 10; - const size_t out_digest_offset = 10; - u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; - size_t response_length = sizeof(response); - u32 err; - - if (count < PCR_DIGEST_LENGTH) - return TPM_LIB_ERROR; - - if (pack_byte_string(buf, sizeof(buf), "sd", - 0, command, sizeof(command), - index_offset, index)) - return TPM_LIB_ERROR; - err = tpm_sendrecv_command(buf, response, &response_length); - if (err) - return err; - if (unpack_byte_string(response, response_length, "s", - out_digest_offset, data, PCR_DIGEST_LENGTH)) - return TPM_LIB_ERROR; - - return 0; -} - -u32 tpm_tsc_physical_presence(u16 presence) -{ - const u8 command[12] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0, - }; - const size_t presence_offset = 10; - u8 buf[COMMAND_BUFFER_SIZE]; - - if (pack_byte_string(buf, sizeof(buf), "sw", - 0, command, sizeof(command), - presence_offset, presence)) - return TPM_LIB_ERROR; - - return tpm_sendrecv_command(buf, NULL, NULL); -} - -u32 tpm_read_pubek(void *data, size_t count) -{ - const u8 command[30] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c, - }; - const size_t response_size_offset = 2; - const size_t data_offset = 10; - const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20; - u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE]; - size_t response_length = sizeof(response); - u32 data_size; - u32 err; - - err = tpm_sendrecv_command(command, response, &response_length); - if (err) - return err; - if (unpack_byte_string(response, response_length, "d", - response_size_offset, &data_size)) - return TPM_LIB_ERROR; - if (data_size < header_and_checksum_size) - return TPM_LIB_ERROR; - data_size -= header_and_checksum_size; - if (data_size > count) - return TPM_LIB_ERROR; - if (unpack_byte_string(response, response_length, "s", - data_offset, data, data_size)) - return TPM_LIB_ERROR; - - return 0; -} - -u32 tpm_force_clear(void) -{ - const u8 command[10] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d, - }; - - return tpm_sendrecv_command(command, NULL, NULL); -} - -u32 tpm_physical_enable(void) -{ - const u8 command[10] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f, - }; - - return tpm_sendrecv_command(command, NULL, NULL); -} - -u32 tpm_physical_disable(void) -{ - const u8 command[10] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70, - }; - - return tpm_sendrecv_command(command, NULL, NULL); -} - -u32 tpm_physical_set_deactivated(u8 state) -{ - const u8 command[11] = { - 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72, - }; - const size_t state_offset = 10; - u8 buf[COMMAND_BUFFER_SIZE]; - - if (pack_byte_string(buf, sizeof(buf), "sb", - 0, command, sizeof(command), - state_offset, state)) - return TPM_LIB_ERROR; - - return tpm_sendrecv_command(buf, NULL, NULL); -} - -u32 tpm_get_capability(u32 cap_area, u32 sub_cap, void *cap, size_t count) -{ - const u8 command[22] = { - 0x0, 0xc1, /* TPM_TAG */ - 0x0, 0x0, 0x0, 0x16, /* parameter size */ - 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ - 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */ - 0x0, 0x0, 0x0, 0x4, /* subcap size */ - 0x0, 0x0, 0x0, 0x0, /* subcap value */ - }; - const size_t cap_area_offset = 10; - const size_t sub_cap_offset = 18; - const size_t cap_offset = 14; - const size_t cap_size_offset = 10; - u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; - size_t response_length = sizeof(response); - u32 cap_size; - u32 err; - - if (pack_byte_string(buf, sizeof(buf), "sdd", - 0, command, sizeof(command), - cap_area_offset, cap_area, - sub_cap_offset, sub_cap)) - return TPM_LIB_ERROR; - err = tpm_sendrecv_command(buf, response, &response_length); - if (err) - return err; - if (unpack_byte_string(response, response_length, "d", - cap_size_offset, &cap_size)) - return TPM_LIB_ERROR; - if (cap_size > response_length || cap_size > count) - return TPM_LIB_ERROR; - if (unpack_byte_string(response, response_length, "s", - cap_offset, cap, cap_size)) - return TPM_LIB_ERROR; - - return 0; -} - -u32 tpm_get_permanent_flags(struct tpm_permanent_flags *pflags) -{ - const u8 command[22] = { - 0x0, 0xc1, /* TPM_TAG */ - 0x0, 0x0, 0x0, 0x16, /* parameter size */ - 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ - 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */ - 0x0, 0x0, 0x0, 0x4, /* subcap size */ - 0x0, 0x0, 0x1, 0x8, /* subcap value */ - }; - const size_t data_size_offset = TPM_HEADER_SIZE; - const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32); - u8 response[COMMAND_BUFFER_SIZE]; - size_t response_length = sizeof(response); - u32 err; - u32 data_size; - - err = tpm_sendrecv_command(command, response, &response_length); - if (err) - return err; - if (unpack_byte_string(response, response_length, "d", - data_size_offset, &data_size)) - return TPM_LIB_ERROR; - if (data_size < sizeof(*pflags)) - return TPM_LIB_ERROR; - if (unpack_byte_string(response, response_length, "s", - data_offset, pflags, sizeof(*pflags))) - return TPM_LIB_ERROR; - - return 0; -} - -u32 tpm_get_permissions(u32 index, u32 *perm) -{ - const u8 command[22] = { - 0x0, 0xc1, /* TPM_TAG */ - 0x0, 0x0, 0x0, 0x16, /* parameter size */ - 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ - 0x0, 0x0, 0x0, 0x11, - 0x0, 0x0, 0x0, 0x4, - }; - const size_t index_offset = 18; - const size_t perm_offset = 60; - u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; - size_t response_length = sizeof(response); - u32 err; - - if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command), - index_offset, index)) - return TPM_LIB_ERROR; - err = tpm_sendrecv_command(buf, response, &response_length); - if (err) - return err; - if (unpack_byte_string(response, response_length, "d", - perm_offset, perm)) - return TPM_LIB_ERROR; - - return 0; -} - -#ifdef CONFIG_TPM_FLUSH_RESOURCES -u32 tpm_flush_specific(u32 key_handle, u32 resource_type) -{ - const u8 command[18] = { - 0x00, 0xc1, /* TPM_TAG */ - 0x00, 0x00, 0x00, 0x12, /* parameter size */ - 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */ - 0x00, 0x00, 0x00, 0x00, /* key handle */ - 0x00, 0x00, 0x00, 0x00, /* resource type */ - }; - const size_t key_handle_offset = 10; - const size_t resource_type_offset = 14; - u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; - size_t response_length = sizeof(response); - u32 err; - - if (pack_byte_string(buf, sizeof(buf), "sdd", - 0, command, sizeof(command), - key_handle_offset, key_handle, - resource_type_offset, resource_type)) - return TPM_LIB_ERROR; - - err = tpm_sendrecv_command(buf, response, &response_length); - if (err) - return err; - return 0; -} -#endif /* CONFIG_TPM_FLUSH_RESOURCES */ - -#ifdef CONFIG_TPM_AUTH_SESSIONS - -/** - * Fill an authentication block in a request. - * This func can create the first as well as the second auth block (for - * double authorized commands). - * - * @param request pointer to the request (w/ uninitialised auth data) - * @param request_len0 length of the request without auth data - * @param handles_len length of the handles area in request - * @param auth_session pointer to the (valid) auth session to be used - * @param request_auth pointer to the auth block of the request to be filled - * @param auth authentication data (HMAC key) - */ -static u32 create_request_auth(const void *request, size_t request_len0, - size_t handles_len, - struct session_data *auth_session, - void *request_auth, const void *auth) -{ - u8 hmac_data[DIGEST_LENGTH * 3 + 1]; - sha1_context hash_ctx; - const size_t command_code_offset = 6; - const size_t auth_nonce_odd_offset = 4; - const size_t auth_continue_offset = 24; - const size_t auth_auth_offset = 25; - - if (!auth_session || !auth_session->valid) - return TPM_LIB_ERROR; - - sha1_starts(&hash_ctx); - sha1_update(&hash_ctx, request + command_code_offset, 4); - if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len) - sha1_update(&hash_ctx, - request + TPM_REQUEST_HEADER_LENGTH + handles_len, - request_len0 - TPM_REQUEST_HEADER_LENGTH - - handles_len); - sha1_finish(&hash_ctx, hmac_data); - - sha1_starts(&hash_ctx); - sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH); - sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data)); - sha1_finish(&hash_ctx, auth_session->nonce_odd); - - if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb", - 0, auth_session->handle, - auth_nonce_odd_offset, auth_session->nonce_odd, - DIGEST_LENGTH, - auth_continue_offset, 1)) - return TPM_LIB_ERROR; - if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss", - DIGEST_LENGTH, - auth_session->nonce_even, - DIGEST_LENGTH, - 2 * DIGEST_LENGTH, - request_auth + auth_nonce_odd_offset, - DIGEST_LENGTH + 1)) - return TPM_LIB_ERROR; - sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data), - request_auth + auth_auth_offset); - - return TPM_SUCCESS; -} - -/** - * Verify an authentication block in a response. - * Since this func updates the nonce_even in the session data it has to be - * called when receiving a succesfull AUTH response. - * This func can verify the first as well as the second auth block (for - * double authorized commands). - * - * @param command_code command code of the request - * @param response pointer to the request (w/ uninitialised auth data) - * @param handles_len length of the handles area in response - * @param auth_session pointer to the (valid) auth session to be used - * @param response_auth pointer to the auth block of the response to be verified - * @param auth authentication data (HMAC key) - */ -static u32 verify_response_auth(u32 command_code, const void *response, - size_t response_len0, size_t handles_len, - struct session_data *auth_session, - const void *response_auth, const void *auth) -{ - u8 hmac_data[DIGEST_LENGTH * 3 + 1]; - u8 computed_auth[DIGEST_LENGTH]; - sha1_context hash_ctx; - const size_t return_code_offset = 6; - const size_t auth_continue_offset = 20; - const size_t auth_auth_offset = 21; - u8 auth_continue; - - if (!auth_session || !auth_session->valid) - return TPM_AUTHFAIL; - if (pack_byte_string(hmac_data, sizeof(hmac_data), "d", - 0, command_code)) - return TPM_LIB_ERROR; - if (response_len0 < TPM_RESPONSE_HEADER_LENGTH) - return TPM_LIB_ERROR; - - sha1_starts(&hash_ctx); - sha1_update(&hash_ctx, response + return_code_offset, 4); - sha1_update(&hash_ctx, hmac_data, 4); - if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len) - sha1_update(&hash_ctx, - response + TPM_RESPONSE_HEADER_LENGTH + handles_len, - response_len0 - TPM_RESPONSE_HEADER_LENGTH - - handles_len); - sha1_finish(&hash_ctx, hmac_data); - - memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH); - auth_continue = ((u8 *)response_auth)[auth_continue_offset]; - if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb", - DIGEST_LENGTH, - response_auth, - DIGEST_LENGTH, - 2 * DIGEST_LENGTH, - auth_session->nonce_odd, - DIGEST_LENGTH, - 3 * DIGEST_LENGTH, - auth_continue)) - return TPM_LIB_ERROR; - - sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data), - computed_auth); - - if (memcmp(computed_auth, response_auth + auth_auth_offset, - DIGEST_LENGTH)) - return TPM_AUTHFAIL; - - return TPM_SUCCESS; -} - -u32 tpm_terminate_auth_session(u32 auth_handle) -{ - const u8 command[18] = { - 0x00, 0xc1, /* TPM_TAG */ - 0x00, 0x00, 0x00, 0x00, /* parameter size */ - 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */ - 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */ - 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */ - }; - const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH; - u8 request[COMMAND_BUFFER_SIZE]; - - if (pack_byte_string(request, sizeof(request), "sd", - 0, command, sizeof(command), - req_handle_offset, auth_handle)) - return TPM_LIB_ERROR; - if (oiap_session.valid && oiap_session.handle == auth_handle) - oiap_session.valid = 0; - - return tpm_sendrecv_command(request, NULL, NULL); -} - -u32 tpm_end_oiap(void) -{ - u32 err = TPM_SUCCESS; - - if (oiap_session.valid) - err = tpm_terminate_auth_session(oiap_session.handle); - return err; -} - -u32 tpm_oiap(u32 *auth_handle) -{ - const u8 command[10] = { - 0x00, 0xc1, /* TPM_TAG */ - 0x00, 0x00, 0x00, 0x0a, /* parameter size */ - 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */ - }; - const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH; - const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4; - u8 response[COMMAND_BUFFER_SIZE]; - size_t response_length = sizeof(response); - u32 err; - - if (oiap_session.valid) - tpm_terminate_auth_session(oiap_session.handle); - - err = tpm_sendrecv_command(command, response, &response_length); - if (err) - return err; - if (unpack_byte_string(response, response_length, "ds", - res_auth_handle_offset, &oiap_session.handle, - res_nonce_even_offset, &oiap_session.nonce_even, - (u32)DIGEST_LENGTH)) - return TPM_LIB_ERROR; - oiap_session.valid = 1; - if (auth_handle) - *auth_handle = oiap_session.handle; - return 0; -} - -u32 tpm_load_key2_oiap(u32 parent_handle, const void *key, size_t key_length, - const void *parent_key_usage_auth, u32 *key_handle) -{ - const u8 command[14] = { - 0x00, 0xc2, /* TPM_TAG */ - 0x00, 0x00, 0x00, 0x00, /* parameter size */ - 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */ - 0x00, 0x00, 0x00, 0x00, /* parent handle */ - }; - const size_t req_size_offset = 2; - const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH; - const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4; - const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH; - u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH + - TPM_REQUEST_AUTH_LENGTH]; - u8 response[COMMAND_BUFFER_SIZE]; - size_t response_length = sizeof(response); - u32 err; - - if (!oiap_session.valid) { - err = tpm_oiap(NULL); - if (err) - return err; - } - if (pack_byte_string(request, sizeof(request), "sdds", - 0, command, sizeof(command), - req_size_offset, - sizeof(command) + key_length - + TPM_REQUEST_AUTH_LENGTH, - req_parent_handle_offset, parent_handle, - req_key_offset, key, key_length - )) - return TPM_LIB_ERROR; - - err = create_request_auth(request, sizeof(command) + key_length, 4, - &oiap_session, - request + sizeof(command) + key_length, - parent_key_usage_auth); - if (err) - return err; - err = tpm_sendrecv_command(request, response, &response_length); - if (err) { - if (err == TPM_AUTHFAIL) - oiap_session.valid = 0; - return err; - } - - err = verify_response_auth(0x00000041, response, - response_length - TPM_RESPONSE_AUTH_LENGTH, - 4, &oiap_session, - response + response_length - - TPM_RESPONSE_AUTH_LENGTH, - parent_key_usage_auth); - if (err) - return err; - - if (key_handle) { - if (unpack_byte_string(response, response_length, "d", - res_handle_offset, key_handle)) - return TPM_LIB_ERROR; - } - - return 0; -} - -u32 tpm_get_pub_key_oiap(u32 key_handle, const void *usage_auth, void *pubkey, - size_t *pubkey_len) -{ - const u8 command[14] = { - 0x00, 0xc2, /* TPM_TAG */ - 0x00, 0x00, 0x00, 0x00, /* parameter size */ - 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */ - 0x00, 0x00, 0x00, 0x00, /* key handle */ - }; - const size_t req_size_offset = 2; - const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH; - const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH; - u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH]; - u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH + - TPM_RESPONSE_AUTH_LENGTH]; - size_t response_length = sizeof(response); - u32 err; - - if (!oiap_session.valid) { - err = tpm_oiap(NULL); - if (err) - return err; - } - if (pack_byte_string(request, sizeof(request), "sdd", - 0, command, sizeof(command), - req_size_offset, - (u32)(sizeof(command) - + TPM_REQUEST_AUTH_LENGTH), - req_key_handle_offset, key_handle - )) - return TPM_LIB_ERROR; - err = create_request_auth(request, sizeof(command), 4, &oiap_session, - request + sizeof(command), usage_auth); - if (err) - return err; - err = tpm_sendrecv_command(request, response, &response_length); - if (err) { - if (err == TPM_AUTHFAIL) - oiap_session.valid = 0; - return err; - } - err = verify_response_auth(0x00000021, response, - response_length - TPM_RESPONSE_AUTH_LENGTH, - 0, &oiap_session, - response + response_length - - TPM_RESPONSE_AUTH_LENGTH, - usage_auth); - if (err) - return err; - - if (pubkey) { - if ((response_length - TPM_RESPONSE_HEADER_LENGTH - - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len) - return TPM_LIB_ERROR; - *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH - - TPM_RESPONSE_AUTH_LENGTH; - memcpy(pubkey, response + res_pubkey_offset, - response_length - TPM_RESPONSE_HEADER_LENGTH - - TPM_RESPONSE_AUTH_LENGTH); - } - - return 0; -} - -#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 -u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20], - u32 *handle) -{ - u16 key_count; - u32 key_handles[10]; - u8 buf[288]; - u8 *ptr; - u32 err; - u8 digest[20]; - size_t buf_len; - unsigned int i; - - /* fetch list of already loaded keys in the TPM */ - err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf)); - if (err) - return -1; - key_count = get_unaligned_be16(buf); - ptr = buf + 2; - for (i = 0; i < key_count; ++i, ptr += 4) - key_handles[i] = get_unaligned_be32(ptr); - - /* now search a(/ the) key which we can access with the given auth */ - for (i = 0; i < key_count; ++i) { - buf_len = sizeof(buf); - err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len); - if (err && err != TPM_AUTHFAIL) - return -1; - if (err) - continue; - sha1_csum(buf, buf_len, digest); - if (!memcmp(digest, pubkey_digest, 20)) { - *handle = key_handles[i]; - return 0; - } - } - return 1; -} -#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ - -#endif /* CONFIG_TPM_AUTH_SESSIONS */ - -u32 tpm_get_random(void *data, u32 count) -{ - const u8 command[14] = { - 0x0, 0xc1, /* TPM_TAG */ - 0x0, 0x0, 0x0, 0xe, /* parameter size */ - 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */ - }; - const size_t length_offset = 10; - const size_t data_size_offset = 10; - const size_t data_offset = 14; - u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; - size_t response_length = sizeof(response); - u32 data_size; - u8 *out = data; - - while (count > 0) { - u32 this_bytes = min((size_t)count, - sizeof(response) - data_offset); - u32 err; - - if (pack_byte_string(buf, sizeof(buf), "sd", - 0, command, sizeof(command), - length_offset, this_bytes)) - return TPM_LIB_ERROR; - err = tpm_sendrecv_command(buf, response, &response_length); - if (err) - return err; - if (unpack_byte_string(response, response_length, "d", - data_size_offset, &data_size)) - return TPM_LIB_ERROR; - if (data_size > count) - return TPM_LIB_ERROR; - if (unpack_byte_string(response, response_length, "s", - data_offset, out, data_size)) - return TPM_LIB_ERROR; - - count -= data_size; - out += data_size; - } - - return 0; -}