diff --git a/MAINTAINERS b/MAINTAINERS index 7a07949e1d..fa9a37704b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -512,6 +512,11 @@ M: Wei Liu S: Supported T: git https://xenbits.xenproject.org/git-http/seabios.git +SECURITY HARDWARE DRIVERS +M: Daniel P. Smith +S: Maintained +F: xen/drivers/security/ + STUB DOMAINS M: Samuel Thibault S: Supported diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 74e3915a4d..47a9d28342 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -951,6 +952,35 @@ static struct domain *__init create_dom0(const module_t *image, write_cr4(read_cr4() & ~X86_CR4_SMAP); } + /* Dom0 can now be measure as the comand line has been finalized. */ + if ( secdev_available(SECDEV_TPM) ) + { + void *image_base = bootstrap_map(image); + secdev_opt_t opts = { 0 }; + + opts.tpm.domain.locality = SECDEV_TPM_DEFAULT_LOCALITY; + opts.tpm.domain.pcr = SECDEV_TPM_DEFAULT_PCR; + + opts.tpm.domain.kern = image_base + headroom; + opts.tpm.domain.kern_size = image->mod_end - headroom; + + opts.tpm.domain.cmdline = cmdline; + + printk(XENLOG_INFO "%pd: measuring kernel%s\n", d, + initrd ? " and ramdisk" : ""); + + if ( initrd ) + { + opts.tpm.domain.initrd = bootstrap_map(initrd); + opts.tpm.domain.initrd_size = initrd->mod_end; + } + + if ( secdev_measure_domain(SECDEV_TPM, &opts) < 0 ) + printk(XENLOG_ERR " Domain measurement failed\n"); + + bootstrap_map(NULL); + } + if ( construct_dom0(d, image, headroom, initrd, cmdline) != 0 ) panic("Could not construct domain 0\n"); @@ -1770,6 +1800,9 @@ void __init noreturn __start_xen(unsigned long mbi_p) tboot_probe(); + if ( secdev_init() == 0 ) + printk("Security Devices initialized\n"); + open_softirq(NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ, new_tlbflush_clock_period); if ( opt_watchdog ) diff --git a/xen/drivers/Kconfig b/xen/drivers/Kconfig index db94393f47..834d0cdc5b 100644 --- a/xen/drivers/Kconfig +++ b/xen/drivers/Kconfig @@ -10,6 +10,8 @@ source "drivers/passthrough/Kconfig" source "drivers/pci/Kconfig" +source "drivers/security/Kconfig" + source "drivers/video/Kconfig" config HAS_VPCI diff --git a/xen/drivers/Makefile b/xen/drivers/Makefile index 2a1ae8ad13..0c2009da8f 100644 --- a/xen/drivers/Makefile +++ b/xen/drivers/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_HAS_VPCI) += vpci/ obj-$(CONFIG_HAS_PASSTHROUGH) += passthrough/ obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_VIDEO) += video/ +obj-$(CONFIG_SECURITY_DEVICES) += security/ diff --git a/xen/drivers/security/Kconfig b/xen/drivers/security/Kconfig new file mode 100644 index 0000000000..ce87ec65b5 --- /dev/null +++ b/xen/drivers/security/Kconfig @@ -0,0 +1,19 @@ + +config SECURITY_DEVICES + bool "Security Devices (UNSUPPORTED)" if UNSUPPORTED + default n + ---help--- + Enable Xen to manage and use platform security hardware. + + Say Y here if your platform has security hardware. + +config TPM_HARDWARE + bool "TPM Support" + default y + depends on SECURITY_DEVICES + select CRYPTO + ---help--- + Xen will take control of a TPM, if present, and make it available + for the hypervisor and domains. + + Say Y here if it is desired for Xen to use the TPM. diff --git a/xen/drivers/security/Makefile b/xen/drivers/security/Makefile new file mode 100644 index 0000000000..87b4a111d1 --- /dev/null +++ b/xen/drivers/security/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_SECURITY_DEVICES) += secdev.o +obj-$(CONFIG_TPM_HARDWARE) += tpm/ diff --git a/xen/drivers/security/secdev.c b/xen/drivers/security/secdev.c new file mode 100644 index 0000000000..b6dc023d25 --- /dev/null +++ b/xen/drivers/security/secdev.c @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Copyright (c) 2023, Apertus Solutions, LLC + * All rights reserved. + */ + +#include +#include + +#include "secdev.h" +#include "tpm/tpm_drv.h" + +static struct { + struct secdev_handle *tpm; +} dev_handles; + +static struct secdev_handle *get_dev_handle(secdev_id_t id) +{ + switch ( id ) + { + case SECDEV_TPM: + if ( dev_handles.tpm != NULL ) + return dev_handles.tpm; + + printk(XENLOG_ERR "Requested TPM but no TPM was registered\n"); + break; + default: + printk(XENLOG_ERR "Unknown device id (%d)\n", id); + } + + return NULL; +} + +ssize_t secdev_getrandom(enum secdev_id dev_id, secdev_opt_t *opts) +{ + struct secdev_handle *h = get_dev_handle(dev_id); + secdev_result_t res; + int ret = 0; + + if ( h == NULL ) + return -EINVAL; + + if ( h->getrandom == NULL ) + { + printk(XENLOG_ERR "getrandom() unsupported by security device (%d) \n", + dev_id); + return -EINVAL; + } + + ret = h->getrandom(opts, &res); + if ( ret < 0 ) + return ret; + + return res.tpm.random.len; +} + +int secdev_measure_buffer(enum secdev_id dev_id, secdev_opt_t *opts) +{ + struct secdev_handle *h = get_dev_handle(dev_id); + secdev_result_t res; + + if ( h == NULL ) + return -EINVAL; + + if ( h->measure_buffer == NULL ) + { + printk(XENLOG_ERR "measure_domain() unsupported by security device (%d) \n", + dev_id); + return -EINVAL; + } + + return h->measure_buffer(opts, &res); +} + +int secdev_measure_domain(enum secdev_id dev_id, secdev_opt_t *opts) +{ + struct secdev_handle *h = get_dev_handle(dev_id); + secdev_result_t res; + + if ( h == NULL ) + return -EINVAL; + + if ( h->measure_domain == NULL ) + { + printk(XENLOG_ERR "measure_domain() unsupported by security device (%d) \n", + dev_id); + return -EINVAL; + } + + return h->measure_domain(opts, &res); +} + +bool secdev_available(enum secdev_id dev_id) +{ + return (get_dev_handle(dev_id) != NULL); +} + +int secdev_init(void) +{ +#ifdef CONFIG_TPM_HARDWARE + dev_handles.tpm = tpm_driver_init(); +#endif + + return 0; +} diff --git a/xen/drivers/security/secdev.h b/xen/drivers/security/secdev.h new file mode 100644 index 0000000000..d67a2e54f4 --- /dev/null +++ b/xen/drivers/security/secdev.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Copyright (c) 2023, Apertus Solutions, LLC + * All rights reserved. + */ + +#ifndef __SECDEV_H__ +#define __SECDEV_H__ + +#include +#include + +struct tpm_dev_result { + union { + struct { + ssize_t len; + } random; + struct { + hash_t digest; + } measure; + }; +}; + +typedef union secdev_result { + struct tpm_dev_result tpm; +} secdev_result_t; + +struct secdev_handle { + int (*getrandom)(secdev_opt_t *opts, secdev_result_t *res); + int (*measure_buffer)(secdev_opt_t *opts, secdev_result_t *res); + int (*register_domain)(secdev_opt_t *opts, secdev_result_t *res); + int (*measure_domain)(secdev_opt_t *opts, secdev_result_t *res); + int (*launch_domain)(secdev_opt_t *opts, secdev_result_t *res); + int (*direct_op)(secdev_opt_t *opts, secdev_result_t *res); +}; + +#endif diff --git a/xen/drivers/security/tpm/Makefile b/xen/drivers/security/tpm/Makefile new file mode 100644 index 0000000000..f074305050 --- /dev/null +++ b/xen/drivers/security/tpm/Makefile @@ -0,0 +1,5 @@ +obj-y += tpm.o +obj-y += tpm_mmio.o +obj-y += tpm_12.o +obj-y += tpm_20.o +obj-y += tpm_drv.o diff --git a/xen/drivers/security/tpm/tpm.c b/xen/drivers/security/tpm/tpm.c new file mode 100644 index 0000000000..762716cdf6 --- /dev/null +++ b/xen/drivers/security/tpm/tpm.c @@ -0,0 +1,162 @@ +/* + * tpm.c: TPM-related support functions + * + * Copyright (c) 2006-2010, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "tpm.h" + +static struct tpm_if __tpm = { + .version = { + .version = TPM_VER_UNKNOWN, + }, + .cur_loc = 0, + .timeout.timeout_a = TIMEOUT_A, + .timeout.timeout_b = TIMEOUT_B, + .timeout.timeout_c = TIMEOUT_C, + .timeout.timeout_d = TIMEOUT_D, +}; + +uint16_t tpm_alg_list[] = {HASH_ALG_SHA1, HASH_ALG_SHA256, HASH_ALG_SHA384, HASH_ALG_SHA512}; +const uint8_t tpm_alg_list_count = ARRAY_SIZE(tpm_alg_list); + +bool tpm_detect(void) +{ +#ifdef __LITTLE_ENDIAN + struct tpm_if *tpm = get_tpm(); /* Don't leave tpm as NULL */ + + /* default to SHA1 */ + tpm->cur_alg = TPM_ALG_SHA1; + + /* Determine MMIO interface type and initial famly guess */ + mmio_detect_interface(tpm); + + if ( tpm->family == TPM_IF_20_CRB) + { + printk(XENLOG_INFO"TPM: appears to be a CRB TPM Family 0x%d\n", + tpm->family); + if ( tpm->hw->validate_locality(0) ) + printk(XENLOG_INFO"TPM: CRB_INF Locality 0 is open\n"); + else + { + printk(XENLOG_INFO"TPM: CRB_INF request access to Locality 0...\n"); + if ( !tpm->hw->request_locality(0) ) + { + printk(XENLOG_ERR"TPM: CRB_INF Locality 0 request failed...\n"); + tpm->cmds = NULL; + return false; + } + } + } + else + { + if ( tpm->hw->validate_locality(0) ) + printk(XENLOG_INFO"TPM: FIFO_INF Locality 0 is open\n"); + else + { + printk(XENLOG_ERR"TPM: FIFO_INF Locality 0 cannot be requested\n"); + tpm->cmds = NULL; + return false; + } + /* determine TPM family from command check */ + if ( tpm_12_cmds.check() ) + { + tpm->family = TPM_IF_12; + printk(XENLOG_INFO"TPM: discrete TPM1.2 Family 0x%d\n", tpm->family); + } + else + { + tpm->family = TPM_IF_20_FIFO; + printk(XENLOG_INFO"TPM: discrete TPM2.0 Family 0x%d\n", tpm->family); + } + } + + if (tpm->family == TPM_IF_12) + { + tpm->version.version = TPM_VER_12; + tpm->cmds = &tpm_12_cmds; + } + else if ( tpm->family == TPM_IF_20_FIFO || tpm->family == TPM_IF_20_CRB ) + { + tpm->version.version = TPM_VER_20; + tpm->cmds = &tpm_20_cmds; + } + else + { + tpm->version.version = TPM_VER_UNKNOWN; + tpm->cmds = NULL; + + return false; + } + + return tpm->cmds->init(tpm); +#else + printk(XENLOG_INFO"TPM: big endian platforms not supported\n"); + return false; +#endif +} + +void tpm_print(struct tpm_if *ti) +{ + if ( ti == NULL ) + return; + + printk(XENLOG_INFO"TPM attribute:\n"); + printk(XENLOG_INFO"\t extend policy: %d\n", ti->extpol); + printk(XENLOG_INFO"\t current alg id: 0x%x\n", ti->cur_alg); + printk(XENLOG_INFO"\t timeout values: A: %u, B: %u, C: %u, D: %u\n", + ti->timeout.timeout_a, ti->timeout.timeout_b, + ti->timeout.timeout_c, ti->timeout.timeout_d); +} + +struct tpm_if *get_tpm(void) +{ + return &__tpm; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/drivers/security/tpm/tpm.h b/xen/drivers/security/tpm/tpm.h new file mode 100644 index 0000000000..3c5fec78c3 --- /dev/null +++ b/xen/drivers/security/tpm/tpm.h @@ -0,0 +1,573 @@ +/* + * tpm.h: TPM-related support functions + * + * Copyright (c) 2006-2009, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __LOCAL_TPM_H__ +#define __LOCAL_TPM_H__ + +#include +#include +#include +#include + +/* un-comment to enable detailed command tracing */ +//#define TPM_TRACE + +#define TPM_NR_PCRS 24 + +#define TPM_IF_12 0 +#define TPM_IF_20_FIFO 1 +#define TPM_IF_20_CRB 2 + +#define TPM_VER_UNKNOWN 0 +#define TPM_VER_12 0x0102 +#define TPM_VER_20 0x0200 + +#define TPM_INTERFACE_ID_FIFO_20 0x0 +#define TPM_INTERFACE_ID_CRB 0x1 +#define TPM_INTERFACE_ID_FIFO_13 0xF + +#define TPM_LOCALITY_BASE 0xfed40000 +#define TPM_LOCALITY_0 TPM_LOCALITY_BASE +#define TPM_LOCALITY_1 (TPM_LOCALITY_BASE | 0x1000) +#define TPM_LOCALITY_2 (TPM_LOCALITY_BASE | 0x2000) +#define TPM_LOCALITY_3 (TPM_LOCALITY_BASE | 0x3000) +#define TPM_LOCALITY_4 (TPM_LOCALITY_BASE | 0x4000) +#define TPM_LOCALITY_BASE_N(n) (TPM_LOCALITY_BASE | ((n) << 12)) +#define TPM_NR_LOCALITIES 5 +#define NR_TPM_LOCALITY_PAGES ((TPM_LOCALITY_1 - TPM_LOCALITY_0) >> PAGE_SHIFT) + +#define TPM_LOCALITY_CRB_BASE 0xfed40000 +#define TPM_LOCALITY_CRB_0 TPM_LOCALITY_CRB_BASE +#define TPM_LOCALITY_CRB_1 (TPM_LOCALITY_CRB_BASE | 0x1000) +#define TPM_LOCALITY_CRB_2 (TPM_LOCALITY_CRB_BASE | 0x2000) +#define TPM_LOCALITY_CRB_3 (TPM_LOCALITY_CRB_BASE | 0x3000) +#define TPM_LOCALITY_CRB_4 (TPM_LOCALITY_CRB_BASE | 0x4000) +#define TPM_LOCALITY_CRB_BASE_N(n) (TPM_LOCALITY_CRB_BASE | ((n) << 12)) +#define TPM_NR_CRB_LOCALITIES 5 +#define NR_TPM_LOCALITY_CRB_PAGES ((TPM_LOCALITY_CRB_1 - TPM_LOCALITY_CRB_0) >> PAGE_SHIFT) +/* + * Command Header Fields: + * 0 1 2 3 4 5 6 7 8 9 10 ... + * ------------------------------------------------------------- + * | TAG | SIZE | COMMAND CODE | other ... + * ------------------------------------------------------------- + * + * Response Header Fields: + * 0 1 2 3 4 5 6 7 8 9 10 ... + * ------------------------------------------------------------- + * | TAG | SIZE | RETURN CODE | other ... + * ------------------------------------------------------------- + */ +#define CMD_HEAD_SIZE 10 +#define RSP_HEAD_SIZE 10 +#define CMD_SIZE_OFFSET 2 +#define CMD_CC_OFFSET 6 +#define RSP_SIZE_OFFSET 2 +#define RSP_RST_OFFSET 6 + +/* + * The term timeout applies to timings between various states + * or transitions within the interface protocol. + */ +#define TIMEOUT_A 750 /* 750ms */ +#define TIMEOUT_B 2000 /* 2s */ +#define TIMEOUT_C 75000 /* 750ms */ +#define TIMEOUT_D 750 /* 750ms */ + +typedef struct __packed { + uint32_t timeout_a; + uint32_t timeout_b; + uint32_t timeout_c; + uint32_t timeout_d; +} tpm_timeout_t; + +/* + * The TCG maintains a registry of all algorithms that have an + * assigned algorithm ID. That registry is the definitive list + * of algorithms that may be supported by a TPM. + */ +#define TPM_ALG_ERROR 0x0000 +#define TPM_ALG_FIRST 0x0001 +#define TPM_ALG_RSA 0x0001 +#define TPM_ALG_DES 0x0002 +#define TPM_ALG__3DES 0x0003 +#define TPM_ALG_SHA 0x0004 +#define TPM_ALG_SHA1 0x0004 +#define TPM_ALG_HMAC 0x0005 +#define TPM_ALG_AES 0x0006 +#define TPM_ALG_MGF1 0x0007 +#define TPM_ALG_KEYEDHASH 0x0008 +#define TPM_ALG_XOR 0x000A +#define TPM_ALG_SHA256 0x000B +#define TPM_ALG_SHA384 0x000C +#define TPM_ALG_SHA512 0x000D +#define TPM_ALG_WHIRLPOOL512 0x000E +#define TPM_ALG_NULL 0x0010 +#define TPM_ALG_SM3_256 0x0012 +#define TPM_ALG_SM4 0x0013 +#define TPM_ALG_RSASSA 0x0014 +#define TPM_ALG_RSAES 0x0015 +#define TPM_ALG_RSAPSS 0x0016 +#define TPM_ALG_OAEP 0x0017 +#define TPM_ALG_ECDSA 0x0018 +#define TPM_ALG_ECDH 0x0019 +#define TPM_ALG_ECDAA 0x001A +#define TPM_ALG_SM2 0x001B +#define TPM_ALG_ECSCHNORR 0x001C +#define TPM_ALG_KDF1_SP800_56a 0x0020 +#define TPM_ALG_KDF2 0x0021 +#define TPM_ALG_KDF1_SP800_108 0x0022 +#define TPM_ALG_ECC 0x0023 +#define TPM_ALG_SYMCIPHER 0x0025 +#define TPM_ALG_CTR 0x0040 +#define TPM_ALG_OFB 0x0041 +#define TPM_ALG_CBC 0x0042 +#define TPM_ALG_CFB 0x0043 +#define TPM_ALG_ECB 0x0044 +#define TPM_ALG_LAST 0x0044 +#define TPM_ALG_MAX_NUM (TPM_ALG_LAST - TPM_ALG_ERROR) + + +// move from tpm.c + +/* + * TPM registers and data structures + * + * register values are offsets from each locality base + * see {read,write}_tpm_reg() for data struct format + */ + +/* TPM_ACCESS_x */ +#define TPM_REG_ACCESS 0x00 +#define TPM_REG_STS 0x18 + +/* TODO: Make these structures endian safe */ + +typedef union { + uint8_t _raw[1]; /* 1-byte reg */ + struct __packed { + uint8_t tpm_establishment : 1; /* RO, 0=T/OS has been established + before */ + uint8_t request_use : 1; /* RW, 1=locality is requesting TPM use */ + uint8_t pending_request : 1; /* RO, 1=other locality is requesting + TPM usage */ + uint8_t seize : 1; /* WO, 1=seize locality */ + uint8_t been_seized : 1; /* RW, 1=locality seized while active */ + uint8_t active_locality : 1; /* RW, 1=locality is active */ + uint8_t reserved : 1; + uint8_t tpm_reg_valid_sts : 1; /* RO, 1=other bits are valid */ + }; +} tpm_reg_access_t; + +/* TPM_STS_x */ + +typedef union { + uint8_t _raw[3]; /* 3-byte reg */ + struct __packed { + uint8_t reserved1 : 1; + uint8_t response_retry : 1; /* WO, 1=re-send response */ + uint8_t self_test_done : 1; /* RO, only for version 2 */ + uint8_t expect : 1; /* RO, 1=more data for command expected */ + uint8_t data_avail : 1; /* RO, 0=no more data for response */ + uint8_t tpm_go : 1; /* WO, 1=execute sent command */ + uint8_t command_ready : 1; /* RW, 1=TPM ready to receive new cmd */ + uint8_t sts_valid : 1; /* RO, 1=data_avail; valid expect bits */ + uint16_t burst_count : 16; /* RO, # read/writes bytes before wait */ + }; +} tpm12_reg_sts_t; + +typedef union { + uint8_t _raw[4]; /* 4-byte reg */ + struct __packed { + uint8_t reserved1 : 1; + uint8_t response_retry : 1; /* WO, 1=re-send response */ + uint8_t self_test_done : 1; /* RO, only for version 2 */ + uint8_t expect : 1; /* RO, 1=more data for command expected */ + uint8_t data_avail : 1; /* RO, 0=no more data for response */ + uint8_t tpm_go : 1; /* WO, 1=execute sent command */ + uint8_t command_ready : 1; /* RW, 1=TPM ready to receive new cmd */ + uint8_t sts_valid : 1; /* RO, 1=data_avail; valid expect bits */ + uint16_t burst_count : 16; /* RO, # read/writes bytes before wait */ + /* version >= 2 */ + uint8_t command_cancel : 1; + uint8_t reset_establishment : 1; + uint8_t tpm_family : 2; + uint8_t reserved2 : 4; + }; +} tpm20_reg_sts_t; + +/* + * CRB I/F related definitions, see TCG PC Client Platform TPM Profile (PTP) + * Specification, Level 00 Revision 00.43 + */ +#define TPM_REG_LOC_STATE 0x00 +#define TPM_REG_LOC_CTRL 0x8 +#define TPM_LOCALITY_STS 0x0C +#define TPM_INTERFACE_ID 0x30 +#define TPM_CONTROL_AREA 0x40 +#define TPM_CRB_CTRL_REQ 0x40 +#define TPM_CRB_CTRL_STS 0x44 +#define TPM_CRB_CTRL_CANCEL 0x48 +#define TPM_CRB_CTRL_START 0x4C +#define TPM_CRB_CTRL_CMD_SIZE 0x58 +#define TPM_CRB_CTRL_CMD_ADDR 0x5C +#define TPM_CRB_CTRL_CMD_HADDR 0x60 +#define TPM_CRB_CTRL_RSP_SIZE 0x64 +#define TPM_CRB_CTRL_RSP_ADDR 0x68 +#define TPM_CRB_DATA_BUFFER 0x80 +#define TPMCRBBUF_LEN 0xF80 //3968 Bytes + +//#define CTRL_AREA_ADDR (uint32_t) (TPM_CRB_BASE + 0x40) +//#define DATA_BUF_ADDR (uint32_t) (TPM_CRB_BASE + 0x80) + +typedef union { + uint8_t _raw[4]; /* 4-byte reg */ + struct __packed { + uint8_t tpm_establishment : 1; + uint8_t loc_assigned : 1; + uint8_t active_locality : 3; + uint8_t reserved : 2; + uint8_t tpm_reg_valid_sts : 1; /* RO, 1=other bits are valid */ + uint8_t reserved1 : 8; + uint16_t reserved2 :16; + }; +} tpm_reg_loc_state_t; + +typedef union { + uint8_t _raw[4]; + struct __packed { + uint32_t requestAccess:1; + uint32_t relinquish:1; + uint32_t seize:1; + uint32_t resetEstablishment:1; + uint32_t reserved1:28; + }; +} tpm_reg_loc_ctrl_t; + +typedef union { + uint8_t _raw[4]; + struct __packed{ + uint32_t Granted:1; + uint32_t BeenSeized:1; + uint32_t R:30; + }; +} tpm_reg_loc_sts_t; + +typedef union { + uint8_t _raw[8]; // 8-byte reg + struct __packed { + uint64_t interface_type:4; + uint64_t interface_version:4; + uint64_t interface_capability:4; + uint64_t interface_selector:4; + uint64_t rid:8; + uint64_t res:8; + uint64_t vid:16; + uint64_t did:16; + }; +} tpm_crb_interface_id_t; + +typedef union { + uint8_t _raw[4]; + struct __packed { + uint32_t cmdReady:1; + uint32_t goIdle:1; + uint32_t Reserved:30; + }; +} tpm_reg_ctrl_request_t; + +typedef union { + uint8_t _raw[4]; + struct __packed{ + uint32_t tpmsts:1; + uint32_t tpmidle:1; + uint32_t reserved:30; + }; +} tpm_reg_ctrl_sts_t; + +typedef union { + uint8_t _raw[4]; + struct __packed{ + uint32_t start; + }; +} tpm_reg_ctrl_start_t; + +typedef union { + uint8_t _raw[4]; + struct __packed{ + uint32_t cancel; + }; +} tpm_reg_ctrl_cancel_t; + +typedef union { + uint8_t _raw[8]; + struct __packed{ + uint32_t cmdladdr; + uint32_t cmdhaddr; + }; +} tpm_reg_ctrl_cmdaddr_t; + +typedef union { + uint8_t _raw[4]; + struct __packed{ + uint32_t cmdsize; + }; +} tpm_reg_ctrl_cmdsize_t; + +typedef union { + uint8_t _raw[8]; + struct __packed{ + uint64_t rspaddr; + }; +} tpm_reg_ctrl_rspaddr_t; + +typedef union { + uint8_t _raw[4]; + struct __packed{ + uint32_t rspsize; + }; +} tpm_reg_ctrl_rspsize_t; + +typedef union { + uint8_t _raw[48]; + struct __packed { + tpm_reg_ctrl_request_t Request; + tpm_reg_ctrl_sts_t Status; + tpm_reg_ctrl_cancel_t Cancel; + tpm_reg_ctrl_start_t Start; + uint64_t R; + tpm_reg_ctrl_cmdsize_t CmdSize; + tpm_reg_ctrl_cmdaddr_t CmdAddr; + tpm_reg_ctrl_rspsize_t RspSize; + tpm_reg_ctrl_rspaddr_t RspAddr; + }; +} tpm_ctrl_area_t; + +// END OF CRB I/F + +/* + * assumes that all reg types follow above format: + * - packed + * - member named '_raw' which is array whose size is that of data to read + */ +#define read_tpm_reg(locality, reg, pdata) \ + _read_tpm_reg(locality, reg, (pdata)->_raw, sizeof(*(pdata))) + +#define write_tpm_reg(locality, reg, pdata) \ + _write_tpm_reg(locality, reg, (pdata)->_raw, sizeof(*(pdata))) + +static inline void _read_tpm_reg( + int locality, uint32_t reg, uint8_t *_raw, size_t size) +{ + void __iomem *va = ioremap(TPM_LOCALITY_BASE_N(locality), PAGE_SIZE); + for ( size_t i = 0; i < size; i++ ) + _raw[i] = readb(_p(((uint64_t) va | reg) + i)); + iounmap(va); +} + +static inline void _write_tpm_reg( + int locality, uint32_t reg, uint8_t *_raw, size_t size) +{ + void __iomem *va = ioremap(TPM_LOCALITY_BASE_N(locality), 1); + for ( size_t i = 0; i < size; i++ ) + writeb(_raw[i], _p(((uint64_t) va | reg) + i)); + iounmap(va); +} + + +/* + * the following inline function reversely copy the bytes from 'in' to + * 'out', the byte number to copy is given in count. + */ +#define reverse_copy(out, in, count) \ + _reverse_copy((uint8_t *)(out), (uint8_t *)(in), count) + +static inline void _reverse_copy(uint8_t *out, uint8_t *in, uint32_t count) +{ + for ( uint32_t i = 0; i < count; i++ ) + out[i] = in[count - i - 1]; +} + +/* alg id list supported by Tboot */ +extern uint16_t tpm_alg_list[]; +extern const uint8_t tpm_alg_list_count; + +#define MAX_ALG_NUM 5 + +typedef struct { + uint16_t alg; + hash_t hash; +} hash_entry_t; + +typedef struct { + uint32_t count; + hash_entry_t entries[MAX_ALG_NUM]; +} hash_list_t; + +typedef hash_t tpm_digest_t; +typedef tpm_digest_t tpm_pcr_value_t; + +struct tpm_if; + +struct tpm_hw_if { + bool (*request_locality)(uint32_t locality); + bool (*validate_locality)(uint32_t locality); + bool (*release_locality)(uint32_t locality); + bool (*submit_cmd)(uint32_t locality, uint8_t *in, u32 in_size, u8 *out, + u32 *out_size); +}; + +struct tpm_cmd_if { + + bool (*init)(struct tpm_if *ti); + + bool (*pcr_read)(struct tpm_if *ti, uint32_t locality, uint32_t pcr, + tpm_pcr_value_t *out); + bool (*pcr_extend)(struct tpm_if *ti, uint32_t locality, uint32_t pcr, + const hash_list_t *in); + bool (*pcr_reset)(struct tpm_if *ti, uint32_t locality, uint32_t pcr); + bool (*hash)(struct tpm_if *ti, uint32_t locality, const uint8_t *data, + uint32_t data_size, hash_list_t *hl); + + bool (*nv_read)(struct tpm_if *ti, uint32_t locality, uint32_t index, + uint32_t offset, uint8_t *data, uint32_t *data_size); + bool (*nv_write)(struct tpm_if *ti, uint32_t locality, uint32_t index, + uint32_t offset, const uint8_t *data, uint32_t data_size); + bool (*get_nvindex_size)(struct tpm_if *ti, uint32_t locality, + uint32_t index, uint32_t *size); + +#define TPM_NV_PER_WRITE_STCLEAR (1<<14) +#define TPM_NV_PER_WRITEDEFINE (1<<13) +#define TPM_NV_PER_WRITEALL (1<<12) +#define TPM_NV_PER_AUTHWRITE (1<<2) +#define TPM_NV_PER_OWNERWRITE (1<<1) +#define TPM_NV_PER_PPWRITE (1<<0) + bool (*get_nvindex_permission)(struct tpm_if *ti, uint32_t locality, + uint32_t index, uint32_t *attribute); + + bool (*seal)(struct tpm_if *ti, uint32_t locality, uint32_t in_data_size, + const uint8_t *in_data, uint32_t *sealed_data_size, + uint8_t *sealed_data); + bool (*unseal)(struct tpm_if *ti, uint32_t locality, + uint32_t sealed_data_size, const uint8_t *sealed_data, + uint32_t *secret_size, uint8_t *secret); + + bool (*get_random)(struct tpm_if *ti, uint32_t locality, + uint8_t *random_data, uint32_t *data_size); + + uint32_t (*save_state)(struct tpm_if *ti, uint32_t locality); + + bool (*context_save)(struct tpm_if *ti, uint32_t locality, uint32_t handle, + void *context_saved); + bool (*context_load)(struct tpm_if *ti, uint32_t locality, + void *context_saved, uint32_t *handle); + bool (*context_flush)(struct tpm_if *ti, uint32_t locality, uint32_t handle); + + bool (*cap_pcrs)(struct tpm_if *ti, uint32_t locality, int pcr); + bool (*check)(void); +}; + +struct tpm_if { +#define TPM12_VER_MAJOR 1 +#define TPM12_VER_MINOR 2 +#define TPM20_VER_MAJOR 2 +#define TPM20_VER_MINOR 0 + union { + uint16_t version; + struct { + uint8_t major; + uint8_t minor; + }; + } version; + uint16_t family; + + tpm_timeout_t timeout; + + uint32_t error; /* last reported error */ + uint32_t cur_loc; + + uint16_t banks; + uint16_t algs_banks[TPM_ALG_MAX_NUM]; + uint16_t alg_count; + uint16_t algs[TPM_ALG_MAX_NUM]; + + /* + * Only for version>=2. PCR extend policy. + */ +#define TPM_EXTPOL_AGILE 0 // deprecated +#define TPM_EXTPOL_EMBEDDED 1 +#define TPM_EXTPOL_FIXED 2 + uint8_t extpol; + uint16_t cur_alg; + + /* NV index to be used */ + uint32_t lcp_own_index; + uint32_t tb_policy_index; + uint32_t tb_err_index; + uint32_t sgx_svn_index; + + const struct tpm_hw_if *hw; + const struct tpm_cmd_if *cmds; +}; + +extern const struct tpm_cmd_if tpm_12_cmds; +extern const struct tpm_cmd_if tpm_20_cmds; + +void mmio_detect_interface(struct tpm_if *tpm); +bool tpm_detect(void); +void tpm_print(struct tpm_if *ti); +struct tpm_if *get_tpm(void); + + +//#define TPM_UNIT_TEST 1 + +#ifdef TPM_UNIT_TEST +void tpm_unit_test(void); +#else +#define tpm_unit_test() +#endif /* TPM_UNIT_TEST */ + + +#endif /* __TPM_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/drivers/security/tpm/tpm_12.c b/xen/drivers/security/tpm/tpm_12.c new file mode 100644 index 0000000000..de7438e4c6 --- /dev/null +++ b/xen/drivers/security/tpm/tpm_12.c @@ -0,0 +1,2009 @@ +/* + * tpm_12.c: TPM1.2-related support functions + * + * Copyright (c) 2006-2013, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +#include "tpm.h" + +/* + * return code: + * The TPM has five types of return code. One indicates successful operation + * and four indicate failure. + * TPM_SUCCESS (00000000) indicates successful execution. + * The failure reports are: + * TPM defined fatal errors (00000001 to 000003FF) + * vendor defined fatal errors (00000400 to 000007FF) + * TPM defined non-fatal errors (00000800 to 00000BFF) + * vendor defined non-fatal errors (00000C00 to 00000FFF). + * Here only give definitions for a few commonly used return code. + */ +#define TPM_BASE 0x00000000 +#define TPM_NON_FATAL 0x00000800 +#define TPM_SUCCESS TPM_BASE +#define TPM_BADINDEX (TPM_BASE + 2) +#define TPM_BAD_PARAMETER (TPM_BASE + 3) +#define TPM_DEACTIVATED (TPM_BASE + 6) +#define TPM_DISABLED (TPM_BASE + 7) +#define TPM_FAIL (TPM_BASE + 9) +#define TPM_BAD_ORDINAL (TPM_BASE + 10) +#define TPM_NOSPACE (TPM_BASE + 17) +#define TPM_NOTRESETABLE (TPM_BASE + 50) +#define TPM_NOTLOCAL (TPM_BASE + 51) +#define TPM_BAD_LOCALITY (TPM_BASE + 61) +#define TPM_READ_ONLY (TPM_BASE + 62) +#define TPM_NOT_FULLWRITE (TPM_BASE + 70) +#define TPM_RETRY (TPM_BASE + TPM_NON_FATAL) + +typedef uint8_t tpm_locality_selection_t; +#define TPM_LOC_ZERO 0x01 +#define TPM_LOC_ONE 0x02 +#define TPM_LOC_TWO 0x04 +#define TPM_LOC_THREE 0x08 +#define TPM_LOC_FOUR 0x10 +#define TPM_LOC_RSVD 0xE0 + +/* ~5 secs are required for Infineon that requires this, so leave some extra */ +#define MAX_SAVESTATE_RETRIES 60 + +#define TPM_TAG_RQU_COMMAND 0x00C1 +#define TPM_TAG_RQU_AUTH1_COMMAND 0x00C2 +#define TPM_TAG_RQU_AUTH2_COMMAND 0x00C3 +#define TPM_ORD_PCR_EXTEND 0x00000014 +#define TPM_ORD_PCR_READ 0x00000015 +#define TPM_ORD_PCR_RESET 0x000000C8 +#define TPM_ORD_NV_READ_VALUE 0x000000CF +#define TPM_ORD_NV_WRITE_VALUE 0x000000CD +#define TPM_ORD_GET_CAPABILITY 0x00000065 +#define TPM_ORD_SEAL 0x00000017 +#define TPM_ORD_UNSEAL 0x00000018 +#define TPM_ORD_OSAP 0x0000000B +#define TPM_ORD_OIAP 0x0000000A +#define TPM_ORD_SAVE_STATE 0x00000098 +#define TPM_ORD_GET_RANDOM 0x00000046 + +#define TPM_TAG_PCR_INFO_LONG 0x0006 +#define TPM_TAG_STORED_DATA12 0x0016 + +/* + * specified as minimum cmd buffer size should be supported by all 1.2 TPM + * device in the TCG_PCClientTPMSpecification_1-20_1-00_FINAL.pdf + */ +#define TPM_CMD_SIZE_MAX 768 +#define TPM_RSP_SIZE_MAX 768 + +/* + * The _tpm12_submit_cmd function comes with 2 global buffers: cmd_buf & rsp_buf. + * Before calling, caller should fill cmd arguements into cmd_buf via + * WRAPPER_IN_BUF macro. After calling, caller should fetch result from + * rsp_buffer via WRAPPER_OUT_BUF macro. + * cmd_buf content: + * 0 1 2 3 4 5 6 7 8 9 10 ... + * ------------------------------------------------------------- + * | TAG | SIZE | ORDINAL | arguments ... + * ------------------------------------------------------------- + * rsp_buf content: + * 0 1 2 3 4 5 6 7 8 9 10 ... + * ------------------------------------------------------------- + * | TAG | SIZE | RETURN CODE | other data ... + * ------------------------------------------------------------- + * + * locality : TPM locality (0 - 4) + * tag : The TPM command tag + * cmd : The TPM command ordinal + * arg_size : Size of argument data. + * out_size : IN/OUT paramter. The IN is the expected size of out data; + * the OUT is the size of output data within out buffer. + * The out_size MUST NOT be NULL. + * return : TPM_SUCCESS for success, for other error code, refer to the .h + */ +static uint8_t cmd_buf[TPM_CMD_SIZE_MAX]; +static uint8_t rsp_buf[TPM_RSP_SIZE_MAX]; +#define WRAPPER_IN_BUF (cmd_buf + CMD_HEAD_SIZE) +#define WRAPPER_OUT_BUF (rsp_buf + RSP_HEAD_SIZE) +#define WRAPPER_IN_MAX_SIZE (TPM_CMD_SIZE_MAX - CMD_HEAD_SIZE) +#define WRAPPER_OUT_MAX_SIZE (TPM_RSP_SIZE_MAX - RSP_HEAD_SIZE) + +static uint32_t _tpm12_submit_cmd( + uint32_t locality, uint16_t tag, uint32_t cmd, uint32_t arg_size, + uint32_t *out_size) +{ + struct tpm_if *tpm = get_tpm(); + uint32_t ret; + uint32_t cmd_size, rsp_size = 0; + + if ( out_size == NULL ) + { + printk(XENLOG_WARNING"TPM: invalid param for _tpm12_submit_cmd()\n"); + return TPM_BAD_PARAMETER; + } + + /* + * real cmd size should add 10 more bytes: + * 2 bytes for tag + * 4 bytes for size + * 4 bytes for ordinal + */ + cmd_size = CMD_HEAD_SIZE + arg_size; + + if ( cmd_size > TPM_CMD_SIZE_MAX ) + { + printk(XENLOG_WARNING"TPM: cmd exceeds the max supported size.\n"); + return TPM_BAD_PARAMETER; + } + + /* copy tag, size & ordinal into buf in a reversed byte order */ + reverse_copy(cmd_buf, &tag, sizeof(tag)); + reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); + reverse_copy(cmd_buf + CMD_CC_OFFSET, &cmd, sizeof(cmd)); + + rsp_size = RSP_HEAD_SIZE + *out_size; + rsp_size = (rsp_size > TPM_RSP_SIZE_MAX) ? TPM_RSP_SIZE_MAX: rsp_size; + if ( !tpm->hw->submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size) ) + return TPM_FAIL; + + /* + * should subtract 10 bytes from real response size: + * 2 bytes for tag + * 4 bytes for size + * 4 bytes for return code + */ + rsp_size -= (rsp_size > RSP_HEAD_SIZE) ? RSP_HEAD_SIZE : rsp_size; + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(uint32_t)); + if ( ret != TPM_SUCCESS ) + return ret; + + if ( *out_size == 0 || rsp_size == 0 ) + *out_size = 0; + else + *out_size = (rsp_size < *out_size) ? rsp_size : *out_size; + + return ret; +} + +static inline uint32_t tpm12_submit_cmd( + uint32_t locality, uint32_t cmd, uint32_t arg_size, uint32_t *out_size) +{ + return _tpm12_submit_cmd(locality, TPM_TAG_RQU_COMMAND, cmd, arg_size, + out_size); +} + +static inline uint32_t tpm12_submit_cmd_auth1( + uint32_t locality, uint32_t cmd, uint32_t arg_size, uint32_t *out_size) +{ + return _tpm12_submit_cmd(locality, TPM_TAG_RQU_AUTH1_COMMAND, cmd, + arg_size, out_size); +} + +static inline uint32_t tpm12_submit_cmd_auth2( + uint32_t locality, uint32_t cmd, uint32_t arg_size, uint32_t *out_size) +{ + return _tpm12_submit_cmd(locality, TPM_TAG_RQU_AUTH2_COMMAND, cmd, + arg_size, out_size); +} + +typedef struct __packed { + uint8_t digest[SHA1_LENGTH]; +} tpm12_digest_t; + +static bool cf_check tpm12_pcr_read( + struct tpm_if *ti, uint32_t locality, uint32_t pcr, tpm_pcr_value_t *out) +{ + uint32_t ret, out_size = sizeof(*out); + + if ( out == NULL || pcr >= TPM_NR_PCRS) + { + ti->error = TPM_BAD_PARAMETER; + return false; + } + + /* copy pcr into buf in reversed byte order */ + reverse_copy(WRAPPER_IN_BUF, &pcr, sizeof(pcr)); + + ret = tpm12_submit_cmd(locality, TPM_ORD_PCR_READ, sizeof(pcr), &out_size); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: Pcr %d Read return value = %08X\n", pcr, ret); +#endif + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: Pcr %d Read return value = %08X\n", + pcr, ret); + ti->error = ret; + return false; + } + + if ( out_size > sizeof(*out) ) + out_size = sizeof(*out); + memcpy((void *)out, WRAPPER_OUT_BUF, out_size); + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO"TPM: \t%*ph\n", out_size, + ((tpm12_digest_t *)out)->digest); + } +#endif + + return true; +} + +static bool _tpm12_pcr_extend( + struct tpm_if *ti, uint32_t locality, uint32_t pcr, const tpm_digest_t* in) +{ + uint32_t ret, in_size = 0, out_size = 0; + + if ( ti == NULL ) + return false; + + if ( in == NULL || pcr >= TPM_NR_PCRS) + { + ti->error = TPM_BAD_PARAMETER; + return false; + } + + /* copy pcr into buf in reversed byte order, then copy in data */ + reverse_copy(WRAPPER_IN_BUF, &pcr, sizeof(pcr)); + in_size += sizeof(pcr); + memcpy(WRAPPER_IN_BUF + in_size, (void *)in, + sizeof(*(tpm12_digest_t *)in)); + in_size += sizeof(*(tpm12_digest_t *)in); + + ret = tpm12_submit_cmd(locality, TPM_ORD_PCR_EXTEND, in_size, &out_size); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: Pcr %d extend, return value = %08X\n", pcr, ret); +#endif + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: Pcr %d extend, return value = %08X\n", + pcr, ret); + ti->error = ret; + return false; + } + + return true; +} + +static bool cf_check tpm12_pcr_extend( + struct tpm_if *ti, uint32_t locality, uint32_t pcr, const hash_list_t *in) +{ + tpm_digest_t digest; + + if ( ti == NULL ) + return false; + + if ( in == NULL || in->count != 1 || + in->entries[0].alg != HASH_ALG_SHA1 ) + { + ti->error = TPM_BAD_PARAMETER; + return false; + } + + digest = in->entries[0].hash; + + return _tpm12_pcr_extend(ti, locality, pcr, &digest); +} + +typedef struct __packed { + uint16_t size_of_select; + uint8_t pcr_select[3]; +} tpm_pcr_selection_t; + +/* PCRs lower than 16 are not resetable */ +#define TPM_PCR_RESETABLE_MIN 16 +static bool cf_check tpm12_pcr_reset(struct tpm_if *ti, uint32_t locality, uint32_t pcr) +{ + uint32_t ret, in_size, out_size = 0; + uint16_t size_of_select; + tpm_pcr_selection_t pcr_sel = {0,{0,}}; + + if ( ti == NULL ) + return false; + + if ( pcr >= TPM_NR_PCRS || pcr < TPM_PCR_RESETABLE_MIN ) + { + ti->error = TPM_BAD_PARAMETER; + return false; + } + + /* the pcr_sel.pcr_select[size_of_select - 1] should not be 0 */ + size_of_select = pcr / 8 + 1; + reverse_copy(&pcr_sel.size_of_select, &size_of_select, + sizeof(size_of_select)); + pcr_sel.pcr_select[pcr / 8] = 1 << (pcr % 8); + + in_size = sizeof(pcr_sel); + memcpy(WRAPPER_IN_BUF, (void *)&pcr_sel, in_size); + + ret = tpm12_submit_cmd(locality, TPM_ORD_PCR_RESET, in_size, &out_size); + if ( ret != TPM_SUCCESS ) + { + ti->error = ret; + return false; + } + + printk(XENLOG_INFO"TPM: Pcr %d reset, return value = %08X\n", pcr, ret); + + return true; +} + +#define TPM_NV_READ_VALUE_DATA_SIZE_MAX (TPM_RSP_SIZE_MAX - 14) +static bool cf_check tpm12_nv_read_value( + struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t offset, + uint8_t *data, uint32_t *data_size) +{ + uint32_t ret, in_size = 0, out_size; + + if ( ti == NULL ) + return false; + + if ( data == NULL || data_size == NULL || *data_size == 0 ) + { + ti->error = TPM_BAD_PARAMETER; + return false; + } + if ( *data_size > TPM_NV_READ_VALUE_DATA_SIZE_MAX ) + *data_size = TPM_NV_READ_VALUE_DATA_SIZE_MAX; + + /* copy the index, offset and *data_size into buf in reversed byte order */ + reverse_copy(WRAPPER_IN_BUF, &index, sizeof(index)); + in_size += sizeof(index); + reverse_copy(WRAPPER_IN_BUF + in_size, &offset, sizeof(offset)); + in_size += sizeof(offset); + reverse_copy(WRAPPER_IN_BUF + in_size, data_size, sizeof(*data_size)); + in_size += sizeof(*data_size); + + out_size = *data_size + sizeof(*data_size); + ret = tpm12_submit_cmd(locality, TPM_ORD_NV_READ_VALUE, in_size, &out_size); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: read nv index %08x from offset %08x, return value = %08X\n", + index, offset, ret); +#endif + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: read nv index %08x offset %08x, return value = %08X\n", + index, offset, ret); + ti->error = ret; + return false; + } + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO"TPM: \t%*ph\n", out_size, WRAPPER_OUT_BUF); + } +#endif + + if ( out_size <= sizeof(*data_size) ) + { + *data_size = 0; + return true; + } + + out_size -= sizeof(*data_size); + reverse_copy(data_size, WRAPPER_OUT_BUF, sizeof(*data_size)); + *data_size = (*data_size > out_size) ? out_size : *data_size; + if( *data_size > 0 ) + memcpy(data, WRAPPER_OUT_BUF + sizeof(*data_size), *data_size); + + return true; +} + +#define TPM_NV_WRITE_VALUE_DATA_SIZE_MAX (TPM_CMD_SIZE_MAX - 22) +static bool cf_check tpm12_nv_write_value( + struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t offset, + const uint8_t *data, uint32_t data_size) +{ + uint32_t ret, in_size = 0, out_size = 0; + + if ( ti == NULL ) + return false; + + if ( data == NULL || data_size == 0 || + data_size > TPM_NV_WRITE_VALUE_DATA_SIZE_MAX ) + { + ti->error = TPM_BAD_PARAMETER; + return false; + } + + /* copy index, offset and *data_size into buf in reversed byte order */ + reverse_copy(WRAPPER_IN_BUF, &index, sizeof(index)); + in_size += sizeof(index); + reverse_copy(WRAPPER_IN_BUF + in_size, &offset, sizeof(offset)); + in_size += sizeof(offset); + reverse_copy(WRAPPER_IN_BUF + in_size, &data_size, sizeof(data_size)); + in_size += sizeof(data_size); + memcpy(WRAPPER_IN_BUF + in_size, data, data_size); + in_size += data_size; + + ret = tpm12_submit_cmd(locality, TPM_ORD_NV_WRITE_VALUE, in_size, + &out_size); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: write nv %08x, offset %08x, %08x bytes, return = %08X\n", + index, offset, data_size, ret); +#endif + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: write nv %08x, offset %08x, %08x bytes, return = %08X\n", + index, offset, data_size, ret); + ti->error = ret; + return false; + } + + return true; +} + +#define TPM_CAP_VERSION_VAL 0x1A + +typedef uint16_t tpm_structure_tag_t; + +typedef struct __packed { + uint8_t major; + uint8_t minor; + uint8_t rev_major; + uint8_t rev_minor; +} tpm_version_t; + +typedef struct __packed { + tpm_structure_tag_t tag; + tpm_version_t version; + uint16_t specLevel; + uint8_t errataRev; + uint8_t tpmVendorID[4]; + uint16_t vendorSpecificSize; + uint8_t vendorSpecific[]; +} tpm_cap_version_info_t; + +#define HMAC_BLOCK_SIZE 64 +#define HMAC_OUTPUT_SIZE 20 + +/* TODO: Update with addition of seall/unseal for Xen */ +#if 0 +static bool hmac( + const uint8_t key[HMAC_OUTPUT_SIZE], const uint8_t *msg, uint32_t len, + uint8_t md[HMAC_OUTPUT_SIZE]) +{ + uint8_t ipad[HMAC_BLOCK_SIZE], opad[HMAC_BLOCK_SIZE]; + uint32_t i; + SHA_CTX ctx; + + ASSERT(HMAC_OUTPUT_SIZE <= HMAC_BLOCK_SIZE); + + for ( i = 0; i < HMAC_BLOCK_SIZE; i++ ) + { + ipad[i] = 0x36; + opad[i] = 0x5C; + } + + for ( i = 0; i < HMAC_OUTPUT_SIZE; i++ ) + { + ipad[i] ^= key[i]; + opad[i] ^= key[i]; + } + + SHA1_Init(&ctx); + SHA1_Update(&ctx, ipad, HMAC_BLOCK_SIZE); + SHA1_Update(&ctx, msg, len); + SHA1_Final(md, &ctx); + + SHA1_Init(&ctx); + SHA1_Update(&ctx, opad, HMAC_BLOCK_SIZE); + SHA1_Update(&ctx, md, HMAC_OUTPUT_SIZE); + SHA1_Final(md, &ctx); + + return true; +} +#endif + +typedef uint16_t tpm_entity_type_t; +typedef uint32_t tpm_authhandle_t; +typedef struct __packed { + uint8_t nonce[20]; +} tpm_nonce_t; + +#define TPM_ET_SRK 0x0004 +#define TPM_KH_SRK 0x40000000 + +typedef uint32_t tpm_key_handle_t; + +typedef tpm12_digest_t tpm_composite_hash_t; +typedef struct __packed { + tpm_structure_tag_t tag; + tpm_locality_selection_t locality_at_creation; + tpm_locality_selection_t locality_at_release; + tpm_pcr_selection_t creation_pcr_selection; + tpm_pcr_selection_t release_pcr_selection; + tpm_composite_hash_t digest_at_creation; + tpm_composite_hash_t digest_at_release; +} tpm_pcr_info_long_t; + +typedef uint8_t tpm_authdata_t[20]; +typedef tpm_authdata_t tpm_encauth_t; + +typedef struct __packed { + tpm_structure_tag_t tag; + tpm_entity_type_t et; + uint32_t seal_info_size; +} tpm_stored_data12_header_t; + +typedef struct __packed { + tpm_stored_data12_header_t header; + uint32_t enc_data_size; + uint8_t enc_data[]; +} tpm_stored_data12_short_t; + +typedef struct __packed { + tpm_stored_data12_header_t header; + tpm_pcr_info_long_t seal_info; + uint32_t enc_data_size; + uint8_t enc_data[]; +} tpm_stored_data12_t; + +#define UNLOAD_INTEGER(buf, offset, var) {\ + reverse_copy(buf + offset, &(var), sizeof(var));\ + offset += sizeof(var);\ +} + +#define UNLOAD_BLOB(buf, offset, blob, size) {\ + memcpy(buf + offset, blob, size);\ + offset += size;\ +} + +#define UNLOAD_BLOB_TYPE(buf, offset, blob) \ + UNLOAD_BLOB(buf, offset, blob, sizeof(*(blob))) + +#define UNLOAD_PCR_SELECTION(buf, offset, sel) {\ + UNLOAD_INTEGER(buf, offset, (sel)->size_of_select);\ + UNLOAD_BLOB(buf, offset, (sel)->pcr_select, (sel)->size_of_select);\ +} + +#define UNLOAD_PCR_INFO_LONG(buf, offset, info) {\ + UNLOAD_INTEGER(buf, offset, (info)->tag);\ + UNLOAD_BLOB_TYPE(buf, offset, &(info)->locality_at_creation);\ + UNLOAD_BLOB_TYPE(buf, offset, &(info)->locality_at_release);\ + UNLOAD_PCR_SELECTION(buf, offset, &(info)->creation_pcr_selection);\ + UNLOAD_PCR_SELECTION(buf, offset, &(info)->release_pcr_selection);\ + UNLOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_creation);\ + UNLOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_release);\ +} + +#define UNLOAD_STORED_DATA12(buf, offset, hdr) {\ + UNLOAD_INTEGER(buf, offset, ((tpm_stored_data12_header_t *)(hdr))->tag);\ + UNLOAD_INTEGER(buf, offset, ((tpm_stored_data12_header_t *)(hdr))->et);\ + UNLOAD_INTEGER(buf, offset,\ + ((tpm_stored_data12_header_t *)(hdr))->seal_info_size);\ + if ( ((tpm_stored_data12_header_t *)(hdr))->seal_info_size == 0 ) {\ + UNLOAD_INTEGER(buf, offset,\ + ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\ + UNLOAD_BLOB(buf, offset,\ + ((tpm_stored_data12_short_t *)hdr)->enc_data,\ + ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\ + }\ + else {\ + UNLOAD_PCR_INFO_LONG(buf, offset,\ + &((tpm_stored_data12_t *)hdr)->seal_info);\ + UNLOAD_INTEGER(buf, offset,\ + ((tpm_stored_data12_t *)hdr)->enc_data_size);\ + UNLOAD_BLOB(buf, offset,\ + ((tpm_stored_data12_t *)hdr)->enc_data,\ + ((tpm_stored_data12_t *)hdr)->enc_data_size);\ + }\ +} + +#define LOAD_INTEGER(buf, offset, var) {\ + reverse_copy(&(var), buf + offset, sizeof(var));\ + offset += sizeof(var);\ +} + +#define LOAD_BLOB(buf, offset, blob, size) {\ + memcpy(blob, buf + offset, size);\ + offset += size;\ +} + +#define LOAD_BLOB_TYPE(buf, offset, blob) \ + LOAD_BLOB(buf, offset, blob, sizeof(*(blob))) + +#define LOAD_PCR_SELECTION(buf, offset, sel, size) while (1) {\ + if ( size < sizeof(tpm_pcr_selection_t) ) {\ + size++;\ + break;\ + }\ + LOAD_INTEGER(buf, offset, (sel)->size_of_select);\ + if ( (sel)->size_of_select > sizeof((sel)->pcr_select) ) {\ + size++;\ + break;\ + }\ + LOAD_BLOB(buf, offset, (sel)->pcr_select, (sel)->size_of_select);\ + size = sizeof(tpm_pcr_selection_t);\ + break;\ +} + +#define LOAD_PCR_INFO_LONG(buf, offset, info, size) while (1) {\ + uint32_t ps_size = sizeof(tpm_pcr_selection_t);\ + if ( size < sizeof(tpm_pcr_info_long_t) ) {\ + size++;\ + break;\ + }\ + LOAD_INTEGER(buf, offset, (info)->tag);\ + LOAD_BLOB_TYPE(buf, offset, &(info)->locality_at_creation);\ + LOAD_BLOB_TYPE(buf, offset, &(info)->locality_at_release);\ + LOAD_PCR_SELECTION(buf, offset, &(info)->creation_pcr_selection, ps_size);\ + if ( ps_size > sizeof(tpm_pcr_selection_t) ) {\ + size++;\ + break;\ + }\ + ps_size = sizeof(tpm_pcr_selection_t);\ + LOAD_PCR_SELECTION(buf, offset, &(info)->release_pcr_selection, ps_size);\ + if ( ps_size > sizeof(tpm_pcr_selection_t) ) {\ + size++;\ + break;\ + }\ + LOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_creation);\ + LOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_release);\ + size=sizeof(tpm_pcr_info_long_t);\ + break;\ +} + +#define LOAD_STORED_DATA12(buf, offset, hdr, size) while (1){\ + uint32_t pil_size = sizeof(tpm_pcr_info_long_t);\ + if ( size < sizeof(tpm_stored_data12_short_t) ) {\ + size++;\ + break;\ + }\ + LOAD_INTEGER(buf, offset, ((tpm_stored_data12_header_t *)(hdr))->tag);\ + LOAD_INTEGER(buf, offset, ((tpm_stored_data12_header_t *)(hdr))->et);\ + LOAD_INTEGER(buf, offset, \ + ((tpm_stored_data12_header_t *)(hdr))->seal_info_size);\ + if ( ((tpm_stored_data12_header_t *)(hdr))->seal_info_size == 0 ) {\ + LOAD_INTEGER(buf, offset,\ + ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\ + if ( size - sizeof(tpm_stored_data12_short_t) <\ + ((tpm_stored_data12_short_t *)hdr)->enc_data_size ) {\ + size++;\ + break;\ + }\ + LOAD_BLOB(buf, offset,\ + ((tpm_stored_data12_short_t *)hdr)->enc_data,\ + ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\ + size = sizeof(tpm_stored_data12_short_t) +\ + ((tpm_stored_data12_short_t *)hdr)->enc_data_size;\ + }\ + else {\ + if ( size < sizeof(tpm_stored_data12_t) ) {\ + size++;\ + break;\ + }\ + LOAD_PCR_INFO_LONG(buf, offset,\ + &((tpm_stored_data12_t *)hdr)->seal_info, pil_size);\ + if ( pil_size > sizeof(tpm_pcr_info_long_t) ) {\ + size++;\ + break;\ + }\ + LOAD_INTEGER(buf, offset,\ + ((tpm_stored_data12_t *)hdr)->enc_data_size);\ + if ( size - sizeof(tpm_stored_data12_t) <\ + ((tpm_stored_data12_t *)hdr)->enc_data_size ) {\ + size++;\ + break;\ + }\ + LOAD_BLOB(buf, offset,\ + ((tpm_stored_data12_t *)hdr)->enc_data,\ + ((tpm_stored_data12_t *)hdr)->enc_data_size);\ + size = sizeof(tpm_stored_data12_t) +\ + ((tpm_stored_data12_t *)hdr)->enc_data_size;\ + }\ + break;\ +} + +/* TODO: Update with addition of seall/unseal for Xen */ +#if 0 +static uint32_t tpm12_oiap( + uint32_t locality, tpm_authhandle_t *hauth, tpm_nonce_t *nonce_even) +{ + uint32_t ret, offset, out_size; + + if ( hauth == NULL || nonce_even == NULL ) + return TPM_BAD_PARAMETER; + + offset = 0; + + out_size = sizeof(*hauth) + sizeof(*nonce_even); + + ret = tpm12_submit_cmd(locality, TPM_ORD_OIAP, offset, &out_size); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: start OIAP, return value = %08X\n", ret); +#endif + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: start OIAP, return value = %08X\n", ret); + return ret; + } + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO"TPM: "); + print_hex(NULL, WRAPPER_OUT_BUF, out_size); + } +#endif + + offset = 0; + LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *hauth); + LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even); + + return ret; +} + +static uint32_t tpm12_osap( + uint32_t locality, tpm_entity_type_t ent_type, uint32_t ent_value, + const tpm_nonce_t *odd_osap, tpm_authhandle_t *hauth, + tpm_nonce_t *nonce_even, tpm_nonce_t *even_osap) +{ + uint32_t ret, offset, out_size; + + if ( odd_osap == NULL || hauth == NULL || + nonce_even == NULL || even_osap == NULL ) + return TPM_BAD_PARAMETER; + + offset = 0; + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ent_type); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ent_value); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, odd_osap); + + out_size = sizeof(*hauth) + sizeof(*nonce_even) + sizeof(*even_osap); + ret = tpm12_submit_cmd(locality, TPM_ORD_OSAP, offset, &out_size); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: start OSAP, return value = %08X\n", ret); +#endif + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: start OSAP, return value = %08X\n", ret); + return ret; + } + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO"TPM: "); + print_hex(NULL, WRAPPER_OUT_BUF, out_size); + } +#endif + + offset = 0; + LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *hauth); + LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even); + LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, even_osap); + + return ret; +} + +static uint32_t _tpm12_seal( + uint32_t locality, tpm_key_handle_t hkey, const tpm_encauth_t *enc_auth, + uint32_t pcr_info_size, const tpm_pcr_info_long_t *pcr_info, + uint32_t in_data_size, const uint8_t *in_data, tpm_authhandle_t hauth, + const tpm_nonce_t *nonce_odd, uint8_t *cont_session, + const tpm_authdata_t *pub_auth, uint32_t *sealed_data_size, + uint8_t *sealed_data, tpm_nonce_t *nonce_even, +tpm_authdata_t *res_auth) +{ + uint32_t ret, offset, out_size, size; + + if ( enc_auth == NULL || pcr_info == NULL || in_data == NULL || + nonce_odd == NULL || cont_session == NULL || pub_auth == NULL || + sealed_data_size == NULL || sealed_data == NULL || + nonce_even == NULL || res_auth == NULL ) + { + printk(XENLOG_WARNING"TPM: _tpm12_seal() bad parameter\n"); + return TPM_BAD_PARAMETER; + } + + offset = 0; + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hkey); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, enc_auth); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, pcr_info_size); + UNLOAD_PCR_INFO_LONG(WRAPPER_IN_BUF, offset, pcr_info); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, in_data_size); + UNLOAD_BLOB(WRAPPER_IN_BUF, offset, in_data, in_data_size); + + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hauth); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, nonce_odd); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, *cont_session); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, pub_auth); + + out_size = WRAPPER_OUT_MAX_SIZE; + + ret = tpm12_submit_cmd_auth1(locality, TPM_ORD_SEAL, offset, &out_size); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: seal data, return value = %08X\n", ret); +#endif + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: seal data, return value = %08X\n", ret); + return ret; + } + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO"TPM: "); + print_hex(NULL, WRAPPER_OUT_BUF, out_size); + } +#endif + + if ( *sealed_data_size < + ( out_size - sizeof(*nonce_even) - sizeof(*cont_session) + - sizeof(*res_auth) ) ) + { + printk(XENLOG_WARNING"TPM: sealed blob is too small\n"); + return TPM_NOSPACE; + } + + offset = 0; + size = *sealed_data_size; + LOAD_STORED_DATA12(WRAPPER_OUT_BUF, offset, sealed_data, size); + if ( *sealed_data_size < size ) + { + printk(XENLOG_WARNING"TPM: sealed blob is too small\n"); + return TPM_NOSPACE; + } + *sealed_data_size = size; + LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even); + LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *cont_session); + LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, res_auth); + + return ret; +} + +static uint32_t _tpm12_unseal( + uint32_t locality, tpm_key_handle_t hkey, const uint8_t *in_data, + tpm_authhandle_t hauth, const tpm_nonce_t *nonce_odd, uint8_t *cont_session, + const tpm_authdata_t *auth, tpm_authhandle_t hauth_d, + const tpm_nonce_t *nonce_odd_d, uint8_t *cont_session_d, + const tpm_authdata_t *auth_d, uint32_t *secret_size, + uint8_t *secret, tpm_nonce_t *nonce_even, tpm_authdata_t *res_auth, + tpm_nonce_t *nonce_even_d, tpm_authdata_t *res_auth_d) +{ + uint32_t ret, offset, out_size, size; + + if ( in_data == NULL || nonce_odd == NULL || cont_session == NULL || + auth == NULL || nonce_odd_d == NULL || cont_session_d == NULL || + auth_d == NULL || secret_size == NULL || secret == NULL || + nonce_even == NULL || res_auth == NULL || nonce_even_d == NULL || + res_auth_d == NULL ) + { + printk(XENLOG_WARNING"TPM: _tpm_unseal() bad parameter\n"); + return TPM_BAD_PARAMETER; + } + + offset = 0; + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hkey); + UNLOAD_STORED_DATA12(WRAPPER_IN_BUF, offset, in_data); + + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hauth); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, nonce_odd); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, *cont_session); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, auth); + + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hauth_d); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, nonce_odd_d); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, *cont_session_d); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, auth_d); + + out_size = WRAPPER_OUT_MAX_SIZE; + + ret = tpm12_submit_cmd_auth2(locality, TPM_ORD_UNSEAL, offset, &out_size); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: unseal data, return value = %08X\n", ret); +#endif + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: unseal data, return value = %08X\n", ret); + return ret; + } + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO"TPM: "); + print_hex(NULL, WRAPPER_OUT_BUF, out_size); + } +#endif + + offset = 0; + LOAD_INTEGER(WRAPPER_OUT_BUF, offset, size); + if ( *secret_size < size || + size != + ( out_size - sizeof(*secret_size) - sizeof(*nonce_even) + - sizeof(*cont_session) - sizeof(*res_auth) - sizeof(*nonce_even_d) + - sizeof(*cont_session_d) - sizeof(*res_auth_d) ) ) + { + printk(XENLOG_WARNING"TPM: unsealed data too small\n"); + return TPM_NOSPACE; + } + *secret_size = size; + LOAD_BLOB(WRAPPER_OUT_BUF, offset, secret, *secret_size); + + LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even); + LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *cont_session); + LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, res_auth); + + LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even_d); + LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *cont_session_d); + LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, res_auth_d); + + return ret; +} + +#define XOR_BLOB_TYPE(data, pad) {\ + for ( uint32_t i = 0; i < sizeof(*(data)); i++ ) \ + ((uint8_t *)data)[i] ^= ((uint8_t *)pad)[i % sizeof(*(pad))];\ +} + +static const tpm_authdata_t srk_authdata = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const tpm_authdata_t blob_authdata = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static uint32_t _tpm12_wrap_seal( + uint32_t locality, const tpm_pcr_info_long_t *pcr_info, + uint32_t in_data_size, const uint8_t *in_data, uint32_t *sealed_data_size, + uint8_t *sealed_data) +{ + uint32_t ret; + tpm_nonce_t odd_osap, even_osap, nonce_even, nonce_odd; + tpm_authhandle_t hauth; + tpm_authdata_t shared_secret, pub_auth, res_auth; + tpm_encauth_t enc_auth; + uint8_t cont_session = false; + tpm_key_handle_t hkey = TPM_KH_SRK; + uint32_t pcr_info_size = sizeof(*pcr_info); + uint32_t offset; + uint32_t ordinal = TPM_ORD_SEAL; + tpm12_digest_t digest; + + /* skip generate nonce for odd_osap, just use the random value in stack */ + + /* establish a osap session */ + ret = tpm12_osap(locality, TPM_ET_SRK, TPM_KH_SRK, &odd_osap, &hauth, + &nonce_even, &even_osap); + if ( ret != TPM_SUCCESS ) + return ret; + + /* calculate the shared secret + shared-secret = HMAC(srk_auth, even_osap || odd_osap) */ + offset = 0; + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &even_osap); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &odd_osap); + hmac((uint8_t *)&srk_authdata, WRAPPER_IN_BUF, offset, + (uint8_t *)&shared_secret); + + /* generate ecrypted authdata for data + enc_auth = XOR(authdata, sha1(shared_secret || last_even_nonce)) */ + offset = 0; + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &shared_secret); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even); + sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)&digest); + memcpy(&enc_auth, &blob_authdata, sizeof(blob_authdata)); + XOR_BLOB_TYPE(&enc_auth, &digest); + + /* skip generate nonce for nonce_odd, just use the random value in stack */ + + /* calculate authdata */ + /* in_param_digest = sha1(1S ~ 6S) */ + offset = 0; + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ordinal); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &enc_auth); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, pcr_info_size); + UNLOAD_PCR_INFO_LONG(WRAPPER_IN_BUF, offset, pcr_info); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, in_data_size); + UNLOAD_BLOB(WRAPPER_IN_BUF, offset, in_data, in_data_size); + sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)&digest); + + /* authdata = hmac(key, in_param_digest || auth_params) */ + offset = 0; + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &digest); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_odd); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cont_session); + hmac((uint8_t *)&shared_secret, WRAPPER_IN_BUF, offset, + (uint8_t *)&pub_auth); + + /* call the simple seal function */ + ret = _tpm12_seal(locality, hkey, (const tpm_encauth_t *)&enc_auth, + pcr_info_size, pcr_info, in_data_size, in_data, + hauth, &nonce_odd, &cont_session, + (const tpm_authdata_t *)&pub_auth, + sealed_data_size, sealed_data, + &nonce_even, &res_auth); + + /* skip check for res_auth */ + + return ret; +} + +static uint32_t _tpm12_wrap_unseal( + uint32_t locality, const uint8_t *in_data, uint32_t *secret_size, + uint8_t *secret) +{ + uint32_t ret; + tpm_nonce_t odd_osap, even_osap; + tpm_nonce_t nonce_even, nonce_odd, nonce_even_d, nonce_odd_d; + tpm_authhandle_t hauth, hauth_d; + tpm_authdata_t shared_secret; + tpm_authdata_t pub_auth, res_auth, pub_auth_d, res_auth_d; + uint8_t cont_session = false, cont_session_d = false; + tpm_key_handle_t hkey = TPM_KH_SRK; + uint32_t offset; + uint32_t ordinal = TPM_ORD_UNSEAL; + tpm12_digest_t digest; + + /* skip generate nonce for odd_osap, just use the random value in stack */ + + /* establish a osap session */ + ret = tpm12_osap(locality, TPM_ET_SRK, TPM_KH_SRK, &odd_osap, &hauth, + &nonce_even, &even_osap); + if ( ret != TPM_SUCCESS ) + return ret; + + /* calculate the shared secret + shared-secret = HMAC(auth, even_osap || odd_osap) */ + offset = 0; + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &even_osap); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &odd_osap); + hmac((uint8_t *)&srk_authdata, WRAPPER_IN_BUF, offset, + (uint8_t *)&shared_secret); + + /* establish a oiap session */ + ret = tpm12_oiap(locality, &hauth_d, &nonce_even_d); + if ( ret != TPM_SUCCESS ) + return ret; + + /* skip generate nonce_odd & nonce_odd_d, just use the random values */ + + /* calculate authdata */ + /* in_param_digest = sha1(1S ~ 6S) */ + offset = 0; + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ordinal); + UNLOAD_STORED_DATA12(WRAPPER_IN_BUF, offset, in_data); + sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)&digest); + + /* authdata1 = hmac(key, in_param_digest || auth_params1) */ + offset = 0; + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &digest); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_odd); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cont_session); + hmac((uint8_t *)&shared_secret, WRAPPER_IN_BUF, offset, + (uint8_t *)&pub_auth); + + /* authdata2 = hmac(key, in_param_digest || auth_params2) */ + offset = 0; + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &digest); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even_d); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_odd_d); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cont_session_d); + hmac((uint8_t *)&blob_authdata, WRAPPER_IN_BUF, offset, + (uint8_t *)&pub_auth_d); + + /* call the simple seal function */ + ret = _tpm12_unseal(locality, hkey, in_data, + hauth, &nonce_odd, &cont_session, + (const tpm_authdata_t *)&pub_auth, + hauth_d, &nonce_odd_d, &cont_session_d, + (const tpm_authdata_t *)&pub_auth_d, + secret_size, secret, + &nonce_even, &res_auth, &nonce_even_d, &res_auth_d); + + /* skip check for res_auth */ + + return ret; +} + +static bool init_pcr_info( + uint32_t locality, tpm_locality_selection_t release_locs, + uint32_t nr_create, const uint8_t indcs_create[], uint32_t nr_release, + const uint8_t indcs_release[], const tpm12_digest_t *values_release[], + tpm_pcr_info_long_t *pcr_info) +{ + uint32_t offset; + uint32_t i, blob_size; + static tpm_locality_selection_t localities[TPM_NR_LOCALITIES] = { + TPM_LOC_ZERO, TPM_LOC_ONE, TPM_LOC_TWO, TPM_LOC_THREE, TPM_LOC_FOUR + }; + + + if ( (release_locs & TPM_LOC_RSVD) != 0 ) + return false; + if ( pcr_info == NULL ) + return false; + if ( locality >= TPM_NR_LOCALITIES ) + return false; + if ( indcs_create == NULL ) + nr_create = 0; + if ( indcs_release == NULL || values_release == NULL ) + nr_release = 0; + for ( i = 0; i < nr_create; i++ ) + if ( indcs_create[i] >= TPM_NR_PCRS ) + return false; + for ( i = 0; i < nr_release; i++ ) + { + if ( indcs_release[i] >= TPM_NR_PCRS || values_release[i] == NULL ) + return false; + } + + memset(pcr_info, 0, sizeof(*pcr_info)); + pcr_info->tag = TPM_TAG_PCR_INFO_LONG; + pcr_info->locality_at_creation = localities[locality]; + pcr_info->locality_at_release = release_locs; + pcr_info->creation_pcr_selection.size_of_select = 3; + for ( i = 0; i < nr_create; i++ ) + pcr_info->creation_pcr_selection.pcr_select[indcs_create[i]/8] |= + 1 << (indcs_create[i] % 8); + pcr_info->release_pcr_selection.size_of_select = 3; + for ( i = 0; i < nr_release; i++ ) + pcr_info->release_pcr_selection.pcr_select[indcs_release[i]/8] |= + 1 << (indcs_release[i] % 8); + + if ( nr_release > 0 ) + { + offset = 0; + UNLOAD_PCR_SELECTION(WRAPPER_IN_BUF, offset, + &pcr_info->release_pcr_selection); + blob_size = sizeof(tpm12_digest_t) * nr_release; + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, blob_size); + for ( i = 0; i < nr_release; i++ ) + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, values_release[i]); + sha1_buffer(WRAPPER_IN_BUF, offset, + (uint8_t *)&pcr_info->digest_at_release); + } + + return true; +} +#endif + +/* TODO: Add an appropriate seal/unseal for Xen */ +#if 0 +static bool cf_check tpm12_seal( + struct tpm_if *ti, uint32_t locality, uint32_t in_data_size, + const uint8_t *in_data, uint32_t *sealed_data_size, uint8_t *sealed_data) +{ + const uint8_t pcr_indcs_create[] = {17, 18}; + const uint8_t pcr_indcs_release[] = {17, 18}; + const tpm12_digest_t *pcr_values_release[] = { + (tpm12_digest_t *)&post_launch_pcr17, (tpm12_digest_t *)&post_launch_pcr18}; + uint32_t pcr_nr_create = ARRAY_SIZE(pcr_indcs_create); + uint32_t pcr_nr_release = ARRAY_SIZE(pcr_indcs_release); + uint32_t ret; + tpm_pcr_info_long_t pcr_info; + tpm_locality_selection_t release_locs = 1 << locality; + + if ( ti == NULL ) + return false; + + if ( locality >= TPM_NR_LOCALITIES || + in_data_size == 0 || in_data == NULL || + sealed_data_size == NULL || sealed_data == NULL || + *sealed_data_size == 0 ) + { + printk(XENLOG_WARNING"TPM: tpm12_seal() bad parameter\n"); + ti->error = TPM_BAD_PARAMETER; + return false; + } + + if ( !init_pcr_info(locality, release_locs, pcr_nr_create, + pcr_indcs_create, pcr_nr_release, pcr_indcs_release, + pcr_values_release, &pcr_info) ) + { + printk(XENLOG_WARNING"TPM: tpm12_seal() bad parameter\n"); + ti->error = TPM_BAD_PARAMETER; + return false; + } + + ret = _tpm12_wrap_seal(locality, &pcr_info, in_data_size, in_data, + sealed_data_size, sealed_data); + if ( ret != TPM_SUCCESS ) + { + ti->error = ret; + return false; + } + + return true; +} + +static bool check_sealed_data(uint32_t size, const uint8_t *data) +{ + if ( size < sizeof(tpm_stored_data12_header_t) ) + return false; + if ( ((tpm_stored_data12_header_t *)data)->tag != TPM_TAG_STORED_DATA12 ) + return false; + + if ( ((tpm_stored_data12_header_t *)data)->seal_info_size == 0 ) + { + tpm_stored_data12_short_t *data12_s; + + if ( size < sizeof(*data12_s) ) + return false; + data12_s = (tpm_stored_data12_short_t *)data; + if ( size != sizeof(*data12_s) + data12_s->enc_data_size ) + return false; + } + else + { + tpm_stored_data12_t *data12; + + if ( size < sizeof(*data12) ) + return false; + data12 = (tpm_stored_data12_t *)data; + if ( size != sizeof(*data12) + data12->enc_data_size ) + return false; + } + + return true; +} + +static bool cf_check tpm12_unseal( + struct tpm_if *ti, uint32_t locality, uint32_t sealed_data_size, + const uint8_t *sealed_data, uint32_t *secret_size, uint8_t *secret) +{ + uint32_t ret; + + if ( ti == NULL ) + return false; + + if ( sealed_data == NULL || + secret_size == NULL || secret == NULL ) + { + printk(XENLOG_WARNING"TPM: tpm12_unseal() bad parameter\n"); + ti->error = TPM_BAD_PARAMETER; + return false; + } + + if ( !check_sealed_data(sealed_data_size, sealed_data) ) + { + printk(XENLOG_WARNING"TPM: tpm12_unseal() blob invalid\n"); + ti->error = TPM_BAD_PARAMETER; + return false; + } + + ret = _tpm12_wrap_unseal(locality, sealed_data, secret_size, secret); + if ( ret != TPM_SUCCESS ) + { + ti->error = ret; + return false; + } + + return true; +} + +#else + +/* Placeholders until proper seal/unseal is implemented */ +static inline bool cf_check tpm12_seal( + struct tpm_if *ti, uint32_t locality, uint32_t in_data_size, + const uint8_t *in_data, uint32_t *sealed_data_size, uint8_t *sealed_data) +{ + return false; +} + +static inline bool check_sealed_data(uint32_t size, const uint8_t *data) +{ + return false; +} + +static inline bool cf_check tpm12_unseal( + struct tpm_if *ti, uint32_t locality, uint32_t sealed_data_size, + const uint8_t *sealed_data, uint32_t *secret_size, uint8_t *secret) +{ + return false; +} + +#endif + +#if 0 +static void calc_pcr_composition( + uint32_t nr, const uint8_t indcs[], const tpm12_digest_t *values[], + tpm_composite_hash_t *composite) +{ + uint32_t i, offset, blob_size; + tpm_pcr_selection_t sel; + + if ( nr == 0 || indcs == NULL || values == NULL || composite == NULL) + return; + + sel.size_of_select = 3; + sel.pcr_select[0] = sel.pcr_select[1] = sel.pcr_select[2] = 0; + for ( i = 0; i < nr; i++ ) + sel.pcr_select[indcs[i]/8] |= 1 << (indcs[i] % 8); + + offset = 0; + UNLOAD_PCR_SELECTION(WRAPPER_IN_BUF, offset, &sel); + blob_size = sizeof(tpm12_digest_t) * nr; + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, blob_size); + for ( i = 0; i < nr; i++ ) + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, values[i]); + sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)composite); +} +#endif + +typedef uint32_t tpm_capability_area_t; + +#define TPM_CAP_NV_INDEX 0x00000011 + +static uint32_t tpm12_get_capability( + uint32_t locality, tpm_capability_area_t cap_area, uint32_t sub_cap_size, + const uint8_t *sub_cap, uint32_t *resp_size, uint8_t *resp) +{ + uint32_t ret, offset, out_size, size; + + if ( sub_cap == NULL || resp_size == NULL || resp == NULL ) + { + printk(XENLOG_WARNING"TPM: tpm12_get_capability() bad parameter\n"); + return TPM_BAD_PARAMETER; + } + + offset = 0; + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cap_area); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, sub_cap_size); + UNLOAD_BLOB(WRAPPER_IN_BUF, offset, sub_cap, sub_cap_size); + + out_size = sizeof(*resp_size) + *resp_size; + + ret = tpm12_submit_cmd(locality, TPM_ORD_GET_CAPABILITY, offset, &out_size); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: get capability, return value = %08X\n", ret); +#endif + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: get capability, return value = %08X\n", ret); + return ret; + } + + offset = 0; + LOAD_INTEGER(WRAPPER_OUT_BUF, offset, size); + if ( *resp_size < size || + size != out_size - sizeof(*resp_size) ) + { + printk(XENLOG_WARNING"TPM: capability response too small\n"); + return TPM_FAIL; + } + *resp_size = size; + LOAD_BLOB(WRAPPER_OUT_BUF, offset, resp, *resp_size); + + return ret; +} + +typedef struct __packed { + tpm_pcr_selection_t pcr_selection; + tpm_locality_selection_t locality_at_release; + tpm_composite_hash_t digest_at_release; +} tpm_pcr_info_short_t; + +typedef struct __packed { + tpm_structure_tag_t tag; + uint32_t attributes; +} tpm_nv_attributes_t; + +typedef struct __packed { + tpm_structure_tag_t tag; + uint32_t nv_index; + tpm_pcr_info_short_t pcr_info_read; + tpm_pcr_info_short_t pcr_info_write; + tpm_nv_attributes_t permission; + uint8_t b_read_st_clear; + uint8_t b_write_st_clear; + uint8_t b_write_define; + uint32_t data_size; +} tpm_nv_data_public_t; + +static bool cf_check tpm12_get_nvindex_size( + struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t *size) +{ + uint32_t ret, offset, resp_size; + uint8_t sub_cap[sizeof(index)]; + uint8_t resp[sizeof(tpm_nv_data_public_t)]; + uint32_t idx; + + if ( ti == NULL ) + return false; + + if ( size == NULL ) + { + printk(XENLOG_WARNING"TPM: tpm12_get_nvindex_size() bad parameter\n"); + ti->error = TPM_BAD_PARAMETER; + return false; + } + + offset = 0; + UNLOAD_INTEGER(sub_cap, offset, index); + + resp_size = sizeof(resp); + ret = tpm12_get_capability(locality, TPM_CAP_NV_INDEX, sizeof(sub_cap), + sub_cap, &resp_size, resp); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: get nvindex size, return value = %08X\n", ret); +#endif + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: fail to get public data of 0x%08X in TPM NV\n", index); + ti->error = ret; + return false; + } + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO"TPM: \t%*ph\n", resp_size, resp); + } +#endif + + /* check size */ + if ( resp_size == 0 ) + { + printk(XENLOG_WARNING"TPM: Index 0x%08X does not exist\n", index); + ti->error = TPM_BADINDEX; + return false; + } + + /* check index */ + offset = sizeof(tpm_structure_tag_t); + LOAD_INTEGER(resp, offset, idx); +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: get index value = %08X\n", idx); +#endif + + if ( idx != index ) + { + printk(XENLOG_WARNING"TPM: Index 0x%08X is not the one expected 0x%08X\n", + idx, index); + ti->error = TPM_BADINDEX; + return false; + } + + if ( resp_size != sizeof(resp) ) + { + printk(XENLOG_WARNING"TPM: public data size of Index 0x%08X responsed incorrect\n", + index); + ti->error = TPM_FAIL; + return false; + } + + offset = resp_size - sizeof(uint32_t); + LOAD_INTEGER(resp, offset, *size); + + return true; +} + +static bool cf_check tpm12_get_nvindex_permission( + struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t *attribute) +{ + uint32_t ret, offset, resp_size; + uint8_t sub_cap[sizeof(index)]; + uint8_t resp[sizeof(tpm_nv_data_public_t)]; + uint32_t idx; + + if ( ti == NULL ) + return false; + + if ( attribute == NULL ) + { + printk(XENLOG_WARNING"TPM: tpm12_get_nvindex_permission() bad parameter\n"); + ti->error = TPM_BAD_PARAMETER; + return false; + } + + offset = 0; + UNLOAD_INTEGER(sub_cap, offset, index); + + resp_size = sizeof(resp); + ret = tpm12_get_capability(locality, TPM_CAP_NV_INDEX, sizeof(sub_cap), + sub_cap, &resp_size, resp); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: get nvindex permission, return value = %08X\n", ret); +#endif + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: fail to get public data of 0x%08X in TPM NV\n", + index); + ti->error = ret; + return false; + } + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO"TPM: \t%*ph\n", resp_size, resp); + } +#endif + + /* check size */ + if ( resp_size == 0 ) + { + printk(XENLOG_WARNING"TPM: Index 0x%08X does not exist\n", index); + ti->error = TPM_BADINDEX; + return false; + } + + /* check index */ + offset = sizeof(tpm_structure_tag_t); + LOAD_INTEGER(resp, offset, idx); +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: get index value = %08X\n", idx); +#endif + + if ( idx != index ) + { + printk(XENLOG_WARNING"TPM: Index 0x%08X is not the one expected 0x%08X\n", + idx, index); + ti->error = TPM_BADINDEX; + return false; + } + + if ( resp_size != sizeof(resp) ) + { + printk(XENLOG_ERR"TPM: public data size of Index 0x%08X responsed incorrect\n", + index); + ti->error = TPM_FAIL; + return false; + } + + offset = resp_size - sizeof(uint32_t) - 3 * sizeof(uint8_t) - sizeof(uint32_t); + LOAD_INTEGER(resp, offset, *attribute); + + return true; +} + +typedef struct __packed { + tpm_structure_tag_t tag; + uint8_t disable; + uint8_t ownership; + uint8_t deactivated; + uint8_t read_pubek; + uint8_t disable_owner_clear; + uint8_t allow_maintenance; + uint8_t physical_presence_lifetime_lock; + uint8_t physical_presence_hw_enable; + uint8_t physical_presence_cmd_enable; + uint8_t cekp_used; + uint8_t tpm_post; + uint8_t tpm_post_lock; + uint8_t fips; + uint8_t operator; + uint8_t enable_revoke_ek; + uint8_t nv_locked; + uint8_t read_srk_pub; + uint8_t tpm_established; + uint8_t maintenance_done; + uint8_t disable_full_da_logic_info; +} tpm_permanent_flags_t; + +typedef struct __packed { + tpm_structure_tag_t tag; + uint8_t deactivated; + uint8_t disable_force_clear; + uint8_t physical_presence; + uint8_t phycical_presence_lock; + uint8_t b_global_lock; +} tpm_stclear_flags_t; + +#define TPM_CAP_FLAG 0x00000004 +#define TPM_CAP_FLAG_PERMANENT 0x00000108 +#define TPM_CAP_FLAG_VOLATILE 0x00000109 + +static uint32_t tpm12_get_flags( + uint32_t locality, uint32_t flag_id, uint8_t *flags, uint32_t flag_size) +{ + uint32_t ret, offset, resp_size; + uint8_t sub_cap[sizeof(flag_id)]; + tpm_structure_tag_t tag; + + if ( flags == NULL ) + { + printk(XENLOG_WARNING"TPM: tpm12_get_flags() bad parameter\n"); + return TPM_BAD_PARAMETER; + } + + offset = 0; + UNLOAD_INTEGER(sub_cap, offset, flag_id); + + resp_size = flag_size; + ret = tpm12_get_capability(locality, TPM_CAP_FLAG, sizeof(sub_cap), + sub_cap, &resp_size, flags); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: get flags %08X, return value = %08X\n", flag_id, ret); +#endif + if ( ret != TPM_SUCCESS ) + return ret; + + /* 1.2 spec, main part 2, rev 103 add one more byte to permanent flags, to + be backward compatible, not assume all expected bytes can be gotten */ + if ( resp_size > flag_size ) + { + printk(XENLOG_WARNING"TPM: tpm12_get_flags() response size too small\n"); + return TPM_FAIL; + } + + offset = 0; + LOAD_INTEGER(flags, offset, tag); + offset = 0; + UNLOAD_BLOB_TYPE(flags, offset, &tag); + + return ret; +} + +#define TPM_CAP_PROPERTY 0x00000005 +#define TPM_CAP_PROP_TIS_TIMEOUT 0x00000115 + +static uint32_t tpm12_get_timeout( + uint32_t locality, uint8_t *prop, uint32_t prop_size) +{ + uint32_t ret, offset, resp_size, prop_id = TPM_CAP_PROP_TIS_TIMEOUT; + uint8_t sub_cap[sizeof(prop_id)]; + uint32_t resp[4]; + + if ( (prop == NULL) || (prop_size < sizeof(resp)) ) + { + printk(XENLOG_WARNING"TPM: tpm12_get_timeout() bad parameter\n"); + return TPM_BAD_PARAMETER; + } + + offset = 0; + UNLOAD_INTEGER(sub_cap, offset, prop_id); + + resp_size = prop_size; + ret = tpm12_get_capability(locality, TPM_CAP_PROPERTY, sizeof(sub_cap), + sub_cap, &resp_size, prop); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: get prop %08X, return value = %08X\n", prop_id, ret); +#endif + if ( ret != TPM_SUCCESS ) + return ret; + + if ( resp_size != prop_size ) + { + printk(XENLOG_WARNING"TPM: tpm_get_property() response size incorrect\n"); + return TPM_FAIL; + } + + offset = 0; + LOAD_INTEGER(prop, offset, resp); + offset = 0; + UNLOAD_BLOB_TYPE(prop, offset, &resp); + + return ret; +} + +/* ensure TPM is ready to accept commands */ +static bool cf_check tpm12_init(struct tpm_if *ti) +{ + tpm_permanent_flags_t pflags; + tpm_stclear_flags_t vflags; + uint32_t timeout[4]; + uint32_t locality; + uint32_t ret; + + if ( ti == NULL ) + return false; + + printk(XENLOG_WARNING"Warning: TPM1.2 detected, SHA1 is selected as hashing algorithm.\n"); + + ti->cur_loc = 0; + + locality = ti->cur_loc; + if ( !ti->hw->validate_locality(locality) ) + { + printk(XENLOG_WARNING"TPM is not available.\n"); + return false; + } + + /* make sure tpm is not disabled/deactivated */ + memset(&pflags, 0, sizeof(pflags)); + ret = tpm12_get_flags(locality, TPM_CAP_FLAG_PERMANENT, + (uint8_t *)&pflags, sizeof(pflags)); + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM is disabled or deactivated.\n"); + ti->error = ret; + return false; + } + if ( pflags.disable ) + { + printk(XENLOG_WARNING"TPM is disabled.\n"); + return false; + } + + memset(&vflags, 0, sizeof(vflags)); + ret = tpm12_get_flags(locality, TPM_CAP_FLAG_VOLATILE, + (uint8_t *)&vflags, sizeof(vflags)); + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM is disabled or deactivated.\n"); + ti->error = ret; + return false; + } + if ( vflags.deactivated ) + { + printk(XENLOG_WARNING"TPM is deactivated.\n"); + return false; + } + + printk(XENLOG_INFO"TPM is ready\n"); + printk(XENLOG_INFO"TPM nv_locked: %s\n", + (pflags.nv_locked != 0) ? "TRUE" : "FALSE"); + + /* get tpm timeout values */ + ret = tpm12_get_timeout(locality, (uint8_t *)&timeout, sizeof(timeout)); + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM timeout values are not achieved, " + "default values will be used.\n"); + ti->error = ret; + } + else + { + /* + * timeout_x represents the number of milliseconds for the timeout + * and timeout[x] represents the number of microseconds. + */ + ti->timeout.timeout_a = timeout[0]/1000; + ti->timeout.timeout_b = timeout[1]/1000; + ti->timeout.timeout_c = timeout[2]/1000; + ti->timeout.timeout_d = timeout[3]/1000; + printk(XENLOG_INFO"TPM timeout values: A: %u, B: %u, C: %u, D: %u\n", + ti->timeout.timeout_a, ti->timeout.timeout_b, ti->timeout.timeout_c, + ti->timeout.timeout_d); + /* + * if any timeout values are less than default values, set to default + * value (due to bug with some TPMs) + */ + if ( ti->timeout.timeout_a < TIMEOUT_A ) + { + ti->timeout.timeout_a = TIMEOUT_A; + printk(XENLOG_WARNING"Wrong timeout A, fallback to %u\n", TIMEOUT_A); + } + if ( ti->timeout.timeout_b < TIMEOUT_B ) + { + ti->timeout.timeout_b = TIMEOUT_B; + printk(XENLOG_WARNING"Wrong timeout B, fallback to %u\n", TIMEOUT_B); + } + if ( ti->timeout.timeout_c < TIMEOUT_C ) + { + ti->timeout.timeout_c = TIMEOUT_C; + printk(XENLOG_WARNING"Wrong timeout C, fallback to %u\n", TIMEOUT_C); + } + if ( ti->timeout.timeout_d < TIMEOUT_D ) + { + ti->timeout.timeout_d = TIMEOUT_D; + printk(XENLOG_WARNING"Wrong timeout D, fallback to %u\n", TIMEOUT_D); + } + } + + /* init version */ + ti->version.major = TPM12_VER_MAJOR; + ti->version.minor = TPM12_VER_MINOR; + + /* init supported alg list */ + ti->banks = 1; + ti->alg_count = 1; + ti->algs[0] = HASH_ALG_SHA1; + ti->extpol = TPM_EXTPOL_FIXED; + ti->cur_alg = HASH_ALG_SHA1; + + /* init NV index */ + ti->tb_policy_index = 0x20000001; + ti->lcp_own_index = 0x40000001; + ti->tb_err_index = 0x20000002; + ti->sgx_svn_index = 0x50000004; + + return true; +} + +static uint32_t cf_check tpm12_save_state(struct tpm_if *ti, uint32_t locality) +{ + uint32_t ret, offset, out_size; + uint32_t retries = 0; + + if ( ti == NULL ) + return TPM_BAD_PARAMETER; + + do { + offset = 0; + out_size = 0; + + ret = tpm12_submit_cmd(locality, TPM_ORD_SAVE_STATE, offset, &out_size); + if ( retries == 0 ) + printk(XENLOG_INFO"TPM: save state, return value = %08X\n", ret); + else if ( retries == 1 ) + printk(XENLOG_INFO"retrying command: ."); + else + printk(XENLOG_INFO"."); + + if ( ret != TPM_RETRY ) + break; + + retries++; + mdelay(100); + } while ( retries < MAX_SAVESTATE_RETRIES ); + if ( retries >= MAX_SAVESTATE_RETRIES ) + printk(XENLOG_INFO"TIMEOUT!"); + if ( retries > 0 ) + printk(XENLOG_INFO"\n"); + + return ret; +} + +static bool cf_check tpm12_get_random( + struct tpm_if *ti, uint32_t locality, uint8_t *random_data, + uint32_t *data_size) +{ + uint32_t ret, in_size = 0, out_size, requested_size; + static bool first_attempt; + + if ( ti == NULL ) + return false; + + if ( random_data == NULL || data_size == NULL || *data_size == 0 ) + { + ti->error = TPM_BAD_PARAMETER; + return false; + } + + first_attempt = true; + requested_size = *data_size; + + /* copy the *data_size into buf in reversed byte order */ + reverse_copy(WRAPPER_IN_BUF + in_size, data_size, sizeof(*data_size)); + in_size += sizeof(*data_size); + + out_size = *data_size + sizeof(*data_size); + ret = tpm12_submit_cmd(locality, TPM_ORD_GET_RANDOM, in_size, &out_size); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: get random %u bytes, return value = %08X\n", + *data_size, ret); +#endif + if ( ret != TPM_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: get random %u bytes, return value = %08X\n", + *data_size, ret); + ti->error = ret; + return false; + } + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO"TPM: \t%*ph\n", out_size, WRAPPER_OUT_BUF); + } +#endif + + if ( out_size <= sizeof(*data_size) ) + { + *data_size = 0; + return true; + } + + out_size -= sizeof(*data_size); + reverse_copy(data_size, WRAPPER_OUT_BUF, sizeof(*data_size)); + if ( *data_size > requested_size ) + { + printk(XENLOG_WARNING"Requeseted %x random bytes but got %x\n", + requested_size, *data_size); + ti->error = TPM_NOSPACE; + return false; + } + if ( *data_size > 0 ) + memcpy(random_data, WRAPPER_OUT_BUF + sizeof(*data_size), *data_size); + + /* data might be used as key, so clear from buffer memory */ + memset(WRAPPER_OUT_BUF + sizeof(*data_size), 0, *data_size); + + /* if TPM doesn't return all requested random bytes, try one more time */ + if ( *data_size < requested_size ) + { + printk(XENLOG_WARNING"requested %x random bytes but only got %x\n", + requested_size, *data_size); + /* we're only going to try twice */ + if ( first_attempt ) + { + uint32_t second_size = requested_size - *data_size; + + first_attempt = false; + printk(XENLOG_INFO"trying one more time to get remaining %x bytes\n", + second_size); + if (!tpm12_get_random(ti, locality, random_data + *data_size, + &second_size)) + return false; + *data_size += second_size; + } + } + + return true; +} + +static bool cf_check tpm12_cap_pcrs(struct tpm_if *ti, uint32_t locality, int pcr) +{ + tpm_pcr_value_t cap_val; /* use whatever val is on stack */ + + if ( ti == NULL || locality >= TPM_NR_LOCALITIES || pcr < 0 || + pcr > TPM_NR_PCRS ) + return false; + + _tpm12_pcr_extend(ti, locality, pcr, &cap_val); + + printk(XENLOG_INFO"cap'ed PCR%d\n", pcr); + return true; +} + +static bool cf_check tpm12_check(void) +{ + uint32_t ret, out_size = 0; + + ret = tpm12_submit_cmd(0, 0xFFFFFFFF, 0, &out_size); + + return ( ret == TPM_BAD_ORDINAL ); +} + +const struct tpm_cmd_if tpm_12_cmds = { + .init = tpm12_init, + .pcr_read = tpm12_pcr_read, + .pcr_extend = tpm12_pcr_extend, + .pcr_reset = tpm12_pcr_reset, + .nv_read = tpm12_nv_read_value, + .nv_write = tpm12_nv_write_value, + .get_nvindex_size = tpm12_get_nvindex_size, + .get_nvindex_permission = tpm12_get_nvindex_permission, + .seal = tpm12_seal, + .unseal = tpm12_unseal, + .get_random = tpm12_get_random, + .save_state = tpm12_save_state, + .cap_pcrs = tpm12_cap_pcrs, + .check = tpm12_check, +}; + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/drivers/security/tpm/tpm_20.c b/xen/drivers/security/tpm/tpm_20.c new file mode 100644 index 0000000000..286f0cec3f --- /dev/null +++ b/xen/drivers/security/tpm/tpm_20.c @@ -0,0 +1,2736 @@ +/* + * tpm_20.c: TPM2.0-related support functions + * + * Copyright (c) 2006-2013, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include "tpm.h" +#include "tpm_20.h" + +static uint8_t cmd_buf[MAX_COMMAND_SIZE]; +static uint8_t rsp_buf[MAX_RESPONSE_SIZE]; + +//extern loader_ctx *g_ldr_ctx; + +#define reverse_copy_in(out, var) {\ + _reverse_copy((uint8_t *)(out), (uint8_t *)&(var), sizeof(var));\ + out += sizeof(var);\ +} + +#define reverse_copy_out(var, out) {\ + _reverse_copy((uint8_t *)&(var), (uint8_t *)(out), sizeof(var));\ + out += sizeof(var);\ +} + +static void reverse_copy_header( + uint32_t cmd_code, TPM_CMD_SESSIONS_IN *sessions_in) +{ + uint16_t tag; + + if (sessions_in == NULL || sessions_in->num_sessions == 0) + tag = TPM_ST_NO_SESSIONS; + else + tag = TPM_ST_SESSIONS; + + reverse_copy(cmd_buf, &tag, sizeof(tag)); + reverse_copy(cmd_buf + CMD_CC_OFFSET, &cmd_code, sizeof(cmd_code)); +} + +static void reverse_copy_pcr_selection_in( + void **other, TPML_PCR_SELECTION *pcr_selection) +{ + uint32_t i, k; + + /* Copy count of pcrs to be read. */ + reverse_copy_in(*other, pcr_selection->count); + + for (i=0; icount; i++) + { + /* Copy alg ID for PCR to be read. */ + reverse_copy_in(*other, pcr_selection->selections[i].hash); + + /* Copy size of select array. */ + reverse_copy_in(*other, pcr_selection->selections[i].size_of_select); + + /* Copy bit field of the PCRs selected. */ + for (k=0; kselections[i].size_of_select; k++) + reverse_copy_in(*other, pcr_selection->selections[i].pcr_select[k]); + } +} + +static bool reverse_copy_pcr_selection_out( + TPML_PCR_SELECTION *pcr_selection, void **other) +{ + uint32_t i, k; + + if (pcr_selection == NULL) + return false; + + /* Copy count of pcrs to be read. */ + reverse_copy_out(pcr_selection->count, *other); + + if ( pcr_selection->count > HASH_COUNT ) + return false; + + for (i=0; icount; i++) + { + /* Copy alg ID for PCR to be read. */ + reverse_copy_out(pcr_selection->selections[i].hash, *other); + + /* Copy size of select array. */ + reverse_copy_out(pcr_selection->selections[i].size_of_select, *other); + + if ( pcr_selection->selections[i].size_of_select > + sizeof(pcr_selection->selections[i].pcr_select) ) + return false; + + /* Copy bit field of the PCRs selected */ + for (k=0; kselections[i].size_of_select; k++) + reverse_copy_out(pcr_selection->selections[i].pcr_select[k], *other); + } + + return true; +} + +/* + * Copy sized byte buffer from source to destination and + * twiddle the bytes in the size field. + * + * This can be used for the any of the following + * TPM 2.0 data structures, but is not limited to these: + * + * ENCRYPTED_SECRET_2B + * TPM2B_DIGEST + * TPM2B_NONCE + * TPM2B_DATA + * etc. (any structures consisting of UINT16 followed by a + * byte buffer whose size is specified by the UINT16. + * + * Inputs: + * + * dest -- pointer to SIZED_BYTE_BUFFER + * src -- pointer to SIZED_BYTE_BUFFER + * + * Outputs: + * + * number of bytes copied + */ +static uint16_t reverse_copy_sized_buf_in(TPM2B *dest, TPM2B *src) +{ + int i; + + if (dest == NULL || src == NULL) + return 0; + + reverse_copy(&dest->size, &src->size, sizeof(uint16_t)); + for (i=0; isize; i++) + dest->buffer[i] = src->buffer[i]; + + return sizeof(uint16_t) + src->size; +} + + +/* + * Inputs: dest->size should contain the buffer size of dest->buffer[] + * Outputs: dest->size should contain the final copied data size + * + * Return: 0, failed; 2+, succeed. + */ +static uint16_t reverse_copy_sized_buf_out(TPM2B *dest, TPM2B *src) +{ + uint16_t i, size; + + if (dest == NULL || src == NULL) + return 0; + + reverse_copy(&size, &src->size, sizeof(uint16_t)); + if ( size > dest->size ) + return 0; + + dest->size = size; + for (i=0; isize; i++) + dest->buffer[i] = src->buffer[i]; + + return sizeof(uint16_t) + dest->size; +} + +static bool reverse_copy_digest_out(TPML_DIGEST *tpml_digest, void **other) +{ + uint32_t i; + uint16_t size; + + if (tpml_digest == NULL) + return false; + + reverse_copy_out(tpml_digest->count, *other); + if ( tpml_digest->count > 8 ) + return false; + + for (i=0; icount; i++) + { + tpml_digest->digests[i].t.size = sizeof(tpml_digest->digests[i].t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&(tpml_digest->digests[i]), + (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + } + + return true; +} + +static void reverse_copy_session_data_in( + void **other, TPM_CMD_SESSION_DATA_IN *session_data, uint32_t *session_size) +{ + *session_size += sizeof(uint32_t) + sizeof( uint16_t ) + + session_data->nonce.t.size + sizeof( uint8_t ) + + sizeof( uint16_t ) + session_data->hmac.t.size; + + /* copy session handle */ + reverse_copy_in(*other, session_data->session_handle); + + /* Copy nonce */ + *other += reverse_copy_sized_buf_in((TPM2B *)*other, + (TPM2B *)&session_data->nonce); + + /* Copy attributes */ + *((uint8_t *)*other) = *(u8 *)(void *)&(session_data->session_attr); + *other += sizeof(uint8_t); + + /* Copy hmac data */ + *other += reverse_copy_sized_buf_in((TPM2B *)*other, + (TPM2B *)&session_data->hmac); +} + +static void reverse_copy_sessions_in(void **other, TPM_CMD_SESSIONS_IN *sessions_in) +{ + int i; + uint32_t session_size = 0; + void *session_size_ptr = *other; + + if (sessions_in == NULL) + return; + + if (sessions_in->num_sessions != 0) + { + *other += sizeof(uint32_t); + for (i=0; inum_sessions; i++) + reverse_copy_session_data_in(other, + &sessions_in->sessions[i], &session_size); + } + + reverse_copy(session_size_ptr, &session_size, sizeof(uint32_t)); +} + +static bool reverse_copy_session_data_out( + TPM_CMD_SESSION_DATA_OUT *session_data, void **other) +{ + uint16_t size; + + if (session_data == NULL) + return false; + + /* Copy nonce */ + session_data->nonce.t.size = sizeof(session_data->nonce.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&(session_data->nonce), + (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + /* Copy sessionAttributes */ + *(uint8_t *)(void *)&(session_data->session_attr) = *((u8 *)*other); + *other += sizeof(uint8_t); + + /* Copy hmac */ + session_data->hmac.t.size = sizeof(session_data->hmac.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&(session_data->hmac), + (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + return true; +} + +static bool reverse_copy_sessions_out( + TPM_CMD_SESSIONS_OUT *sessions_out, void *other, uint16_t rsp_tag, + TPM_CMD_SESSIONS_IN *sessions_in) +{ + int i; + + if (sessions_in == NULL || sessions_out == NULL || rsp_tag != TPM_ST_SESSIONS) + return false; + + sessions_out->num_sessions = sessions_in->num_sessions; + for (i=0; inum_sessions; i++) + if ( !reverse_copy_session_data_out(&sessions_out->sessions[i], &other) ) + return false; + + return true; +} + +typedef struct { + uint16_t alg_id; + uint16_t size; /* Size of digest */ +} HASH_SIZE_INFO; + +HASH_SIZE_INFO hash_sizes[] = { + {TPM_ALG_SHA1, SHA1_DIGEST_SIZE}, + {TPM_ALG_SHA256, SHA256_DIGEST_SIZE}, + {TPM_ALG_SHA384, SHA384_DIGEST_SIZE}, + {TPM_ALG_SHA512, SHA512_DIGEST_SIZE}, + {TPM_ALG_SM3_256, SM3_256_DIGEST_SIZE}, + {TPM_ALG_NULL,0} +}; + +uint16_t get_digest_size(u16 id) +{ + unsigned int i; + for(i=0; i<(sizeof(hash_sizes)/sizeof(HASH_SIZE_INFO)); i++) + { + if(hash_sizes[i].alg_id == id) + return hash_sizes[i].size; + } + + /* If not found, return 0 size, and let TPM handle the error. */ + return 0 ; +} + +static void reverse_copy_digest_value_in( + void **other, TPML_DIGEST_VALUES *tpml_digest) +{ + unsigned int i, k, num_bytes; + + reverse_copy_in(*other, tpml_digest->count); + + for (i=0; icount; i++) { + reverse_copy_in(*other, tpml_digest->digests[i].hash_alg); + + num_bytes = get_digest_size(tpml_digest->digests[i].hash_alg); + + for (k=0; kdigests[i].digest.sha1[k]; + *other += sizeof(uint8_t); + } + } +} + +static bool reverse_copy_digest_values_out( + TPML_DIGEST_VALUES *tpml_digest, void **other) +{ + unsigned int i, k, num_bytes; + + if (tpml_digest == NULL) + return false; + + reverse_copy_out(tpml_digest->count, *other); + if ( tpml_digest->count > HASH_COUNT ) + return false; + + for (i=0; icount; i++) + { + reverse_copy_out(tpml_digest->digests[i].hash_alg, *other); + + num_bytes = get_digest_size(tpml_digest->digests[i].hash_alg); + + for (k=0; kdigests[i].digest.sha1[k] = *((uint8_t *)*other); + *other += sizeof(uint8_t); + } + } + + return true; +} + +/* TODO: utility functions for primary creation, see TODO there. */ +#if 0 +/* + * Copy public data from input data structure into output data stream + * for commands that require it. + * + * Inputs: + * + * pointer to pointer to TPM command area to fill in with public data + * + * pointer to TPM2B_PUBLIC structure + * + * Outputs: + * + * otherData pointer points to end byte past command buffer. This allows + * caller to set the commandSize field for the command. + */ +static void reverse_copy_public_in(void **other, TPM2B_PUBLIC *public) +{ + TPMT_KEYEDHASH_SCHEME *scheme; + TPMT_RSA_SCHEME *rsa_scheme = &(public->t.public_area.param.rsa.scheme); + TPMT_ECC_SCHEME *ecc_scheme = &(public->t.public_area.param.ecc.scheme); + TPMT_KDF_SCHEME *kdf = &(public->t.public_area.param.ecc.kdf); + TPMT_ASYM_SCHEME *asym_scheme = &(public->t.public_area.param.asym.scheme); + void *size_ptr; + uint16_t size; + + size_ptr = *other; + *other += sizeof(uint16_t); + + reverse_copy_in(*other, public->t.public_area.type); + reverse_copy_in(*other, public->t.public_area.name_alg); + + /* Copy public->t.object_attr */ + reverse_copy(*other, (void *)&public->t.public_area.object_attr, + sizeof(uint32_t)); + *other += sizeof(uint32_t); + + /* Copy public->t.auth_policy */ + *other += reverse_copy_sized_buf_in((TPM2B *)*other, + (TPM2B *)&public->t.public_area.auth_policy); + + /* Copy public->t.param */ + switch(public->t.public_area.type) + { + case TPM_ALG_KEYEDHASH: + scheme = &(public->t.public_area.param.keyed_hash.scheme); + + reverse_copy_in(*other, scheme->scheme); + + if(scheme->scheme != TPM_ALG_NULL) + { + /* copy details */ + if(scheme->scheme == TPM_ALG_HMAC) + { + reverse_copy_in(*other, scheme->details.hmac.hash_alg); + } + else + { + reverse_copy_in(*other, scheme->details.xor.hash_alg); + reverse_copy_in(*other, scheme->details.xor.kdf); + } + } + + /* Copy public->t.public_area.unique */ + *other += reverse_copy_sized_buf_in((TPM2B *)*other, + (TPM2B *)&public->t.public_area.unique.keyed_hash); + + break; + + case TPM_ALG_SYMCIPHER: + reverse_copy_in(*other, public->t.public_area.param.sym.alg); + + if (public->t.public_area.param.sym.alg != TPM_ALG_NULL) + { + reverse_copy_in(*other, public->t.public_area.param.sym.key_bits.sym); + + reverse_copy_in(*other, public->t.public_area.param.sym.mode.sym); + } + + /* Copy public->t.public_area.unique */ + *other += reverse_copy_sized_buf_in((TPM2B *)*other, + (TPM2B *)&public->t.public_area.unique.sym); + + break; + + case TPM_ALG_RSA: + /* Copy symmetric fields */ + reverse_copy_in(*other, public->t.public_area.param.rsa.symmetric.alg); + + if (public->t.public_area.param.rsa.symmetric.alg != TPM_ALG_NULL) + { + reverse_copy_in(*other, + public->t.public_area.param.rsa.symmetric.key_bits.sym); + + reverse_copy_in(*other, + public->t.public_area.param.rsa.symmetric.mode.sym); + } + + /* Copy scheme */ + reverse_copy_in(*other, rsa_scheme->scheme); + if (rsa_scheme->scheme != TPM_ALG_NULL) + { + switch (rsa_scheme->scheme) + { + case TPM_ALG_RSASSA: + reverse_copy_in(*other, rsa_scheme->details.rsassa.hash_alg); + break; + + case TPM_ALG_RSAPSS: + reverse_copy_in(*other, rsa_scheme->details.rsapss.hash_alg); + break; + + case TPM_ALG_OAEP: + reverse_copy_in(*other, rsa_scheme->details.oaep.hash_alg); + break; + + case TPM_ALG_ECDSA: + reverse_copy_in(*other, rsa_scheme->details.ecdsa.hash_alg); + break; + + case TPM_ALG_SM2: + reverse_copy_in(*other, rsa_scheme->details.sm2.hash_alg); + break; + + case TPM_ALG_ECDAA: + reverse_copy_in(*other, rsa_scheme->details.ecdaa.hash_alg); + reverse_copy_in(*other, rsa_scheme->details.ecdaa.count); + break; + + case TPM_ALG_ECSCHNORR: + reverse_copy_in(*other, rsa_scheme->details.ec_schnorr.hash_alg); + break; + + default: + reverse_copy_in(*other, rsa_scheme->details.any.hash_alg); + break; + } + } + + /* Copy keybits */ + reverse_copy_in(*other, public->t.public_area.param.rsa.key_bits); + + /* Copy exponent */ + reverse_copy_in(*other, public->t.public_area.param.rsa.exponent); + + /* Copy public->t.public_area.unique */ + *other += reverse_copy_sized_buf_in((TPM2B *)*other, + (TPM2B *)&public->t.public_area.unique.rsa); + + break; + + case TPM_ALG_ECC: + /* Copy symmetric fields */ + reverse_copy_in(*other, public->t.public_area.param.ecc.symmetric.alg); + + if (public->t.public_area.param.ecc.symmetric.alg != TPM_ALG_NULL) + { + reverse_copy_in(*other, + public->t.public_area.param.ecc.symmetric.key_bits.sym); + + reverse_copy_in(*other, + public->t.public_area.param.ecc.symmetric.mode.sym); + } + + /* Copy ECC scheme */ + reverse_copy_in(*other, ecc_scheme->scheme); + if (ecc_scheme->scheme != TPM_ALG_NULL) + { + switch (ecc_scheme->scheme) + { + case TPM_ALG_RSASSA: + reverse_copy_in(*other, ecc_scheme->details.rsassa.hash_alg); + break; + + case TPM_ALG_RSAPSS: + reverse_copy_in(*other, ecc_scheme->details.rsapss.hash_alg); + break; + + case TPM_ALG_ECDSA: + reverse_copy_in(*other, ecc_scheme->details.ecdsa.hash_alg); + break; + + case TPM_ALG_SM2: + reverse_copy_in(*other, ecc_scheme->details.sm2.hash_alg); + break; + + case TPM_ALG_ECDAA: + reverse_copy_in(*other, ecc_scheme->details.ecdaa.hash_alg); + reverse_copy_in(*other, ecc_scheme->details.ecdaa.count); + break; + + case TPM_ALG_ECSCHNORR: + reverse_copy_in(*other, + ecc_scheme->details.ec_schnorr.hash_alg); + break; + + case TPM_ALG_HMAC: + reverse_copy_in(*other, ecc_scheme->details.hmac.hash_alg); + break; + + default: + reverse_copy_in(*other, ecc_scheme->details.any.hash_alg); + break; + } + } + + /* Copy curve_id */ + reverse_copy_in(*other, public->t.public_area.param.ecc.curve_id); + + /* Copy KDF scheme */ + reverse_copy_in(*other, kdf->scheme); + switch (kdf->scheme) + { + case TPM_ALG_MGF1: + reverse_copy_in(*other, kdf->details.mgf1.hash_alg); + break; + + case TPM_ALG_KDF1_SP800_56a: + reverse_copy_in(*other, kdf->details.kdf1_SP800_56a.hash_alg); + break; + + case TPM_ALG_KDF1_SP800_108: + reverse_copy_in(*other, kdf->details.kdf1_sp800_108.hash_alg); + break; + + default: + /* Copy something bogus and let TPM return error code */ + *((uint16_t *)*other) = 0xffff; + *other += sizeof(uint16_t); + break; + } + + /* Copy public->t.public_area.unique */ + *other += reverse_copy_sized_buf_in((TPM2B *)*other, + (TPM2B *)&public->t.public_area.unique.ecc); + + break; + + default: + /* Copy symmetric fields */ + reverse_copy_in(*other, public->t.public_area.param.asym.symmetric.alg); + + if (public->t.public_area.param.asym.symmetric.alg != TPM_ALG_NULL) + { + reverse_copy_in(*other, + public->t.public_area.param.asym.symmetric.key_bits.sym); + + reverse_copy_in(*other, + public->t.public_area.param.asym.symmetric.mode.sym); + } + + /* Copy scheme */ + reverse_copy_in(*other, asym_scheme->scheme); + if (asym_scheme->scheme != TPM_ALG_NULL) + { + switch (asym_scheme->scheme) + { + case TPM_ALG_RSASSA: + reverse_copy_in(*other, asym_scheme->details.rsassa.hash_alg); + break; + + case TPM_ALG_RSAPSS: + reverse_copy_in(*other, asym_scheme->details.rsapss.hash_alg); + break; + + case TPM_ALG_OAEP: + reverse_copy_in(*other, asym_scheme->details.oaep.hash_alg); + break; + + case TPM_ALG_ECDSA: + reverse_copy_in(*other, asym_scheme->details.ecdsa.hash_alg); + break; + + case TPM_ALG_SM2: + reverse_copy_in(*other, asym_scheme->details.sm2.hash_alg); + break; + + case TPM_ALG_ECDAA: + reverse_copy_in(*other, asym_scheme->details.ecdaa.hash_alg); + reverse_copy_in(*other, asym_scheme->details.ecdaa.count); + break; + + case TPM_ALG_ECSCHNORR: + reverse_copy_in(*other, asym_scheme->details.ec_schnorr.hash_alg); + break; + + default: + reverse_copy_in(*other, asym_scheme->details.any.hash_alg); + break; + } + } + + break; + } + + /* Now calculate and write the inPublic size; don't include size field in the size calc */ + size = (uint8_t *)*other - (u8 *)size_ptr - sizeof(uint16_t); + reverse_copy(size_ptr, &size, sizeof(uint16_t)); +} + +/* + * Copy public data from input data structure into output data stream + * for commands that require it. + * + * Inputs: + * + * pointer to TPM2B_PUBLIC structure for returned data + * + * pointer to pointer to TPM command byte stream for the returned data + * + * Outputs: + * + * public contains the de-canonicalized data extracted from the output data stream + */ +static bool reverse_copy_public_out(TPM2B_PUBLIC *public, void **other) +{ + TPMT_KEYEDHASH_SCHEME *scheme; + TPMT_RSA_SCHEME *rsa_scheme = &(public->t.public_area.param.rsa.scheme); + TPMT_ECC_SCHEME *ecc_scheme = &(public->t.public_area.param.ecc.scheme); + TPMT_KDF_SCHEME *kdf = &(public->t.public_area.param.ecc.kdf); + TPMT_ASYM_SCHEME *asym_scheme = &(public->t.public_area.param.asym.scheme); + uint16_t size; + + if (public == NULL) + return false; + + reverse_copy_out(public->t.size, *other); + reverse_copy_out(public->t.public_area.type, *other); + reverse_copy_out(public->t.public_area.name_alg, *other); + + /* Copy public->t.object_attr */ + reverse_copy((void *)&public->t.public_area.object_attr, *other, + sizeof(uint32_t)); + *other += sizeof(uint32_t); + + /* Copy public->t.auth_policy */ + public->t.public_area.auth_policy.t.size = + sizeof(public->t.public_area.auth_policy.t.buffer); + size = reverse_copy_sized_buf_out( + (TPM2B *)&public->t.public_area.auth_policy, (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + /* Copy public->t.param */ + switch(public->t.public_area.type) + { + case TPM_ALG_KEYEDHASH: + scheme = &(public->t.public_area.param.keyed_hash.scheme); + + reverse_copy_out(scheme->scheme, *other); + + if(scheme->scheme != TPM_ALG_NULL) + { + /* copy details */ + if(scheme->scheme == TPM_ALG_HMAC) + { + reverse_copy_out(scheme->details.hmac.hash_alg, *other); + } + else + { + reverse_copy_out(scheme->details.xor.hash_alg, *other); + reverse_copy_out(scheme->details.xor.kdf, *other); + } + } + + /* Copy public->t.public_area.unique */ + public->t.public_area.unique.keyed_hash.t.size = + sizeof(public->t.public_area.unique.keyed_hash.t.buffer); + size = reverse_copy_sized_buf_out( + (TPM2B *)&public->t.public_area.unique.keyed_hash, + (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + break; + + case TPM_ALG_SYMCIPHER: + reverse_copy_out(public->t.public_area.param.sym.alg, *other); + + if (public->t.public_area.param.sym.alg != TPM_ALG_NULL) + { + reverse_copy_out(public->t.public_area.param.sym.key_bits.sym, + *other); + + reverse_copy_out(public->t.public_area.param.sym.mode.sym, *other); + } + + /* Copy public->t.public_area.unique */ + public->t.public_area.unique.sym.t.size = + sizeof(public->t.public_area.unique.sym.t.buffer); + size = reverse_copy_sized_buf_out( + (TPM2B *)&public->t.public_area.unique.sym, + (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + break; + + case TPM_ALG_RSA: + /* Copy symmetric fields */ + reverse_copy_out(public->t.public_area.param.rsa.symmetric.alg, *other); + + if (public->t.public_area.param.rsa.symmetric.alg != TPM_ALG_NULL) + { + reverse_copy_out( + public->t.public_area.param.rsa.symmetric.key_bits.sym, *other); + + reverse_copy_out(public->t.public_area.param.rsa.symmetric.mode.sym, + *other); + } + + /* Copy scheme */ + reverse_copy_out(rsa_scheme->scheme, *other); + if (rsa_scheme->scheme != TPM_ALG_NULL) + { + switch (rsa_scheme->scheme) + { + case TPM_ALG_RSASSA: + reverse_copy_out(rsa_scheme->details.rsassa.hash_alg, *other); + break; + + case TPM_ALG_RSAPSS: + reverse_copy_out(rsa_scheme->details.rsapss.hash_alg, *other); + break; + + case TPM_ALG_OAEP: + reverse_copy_out(rsa_scheme->details.oaep.hash_alg, *other); + break; + + case TPM_ALG_ECDSA: + reverse_copy_out(rsa_scheme->details.ecdsa.hash_alg, *other); + break; + + case TPM_ALG_SM2: + reverse_copy_out(rsa_scheme->details.sm2.hash_alg, *other); + break; + + case TPM_ALG_ECDAA: + reverse_copy_out(rsa_scheme->details.ecdaa.hash_alg, *other); + reverse_copy_out(rsa_scheme->details.ecdaa.count, *other); + break; + + case TPM_ALG_ECSCHNORR: + reverse_copy_out(rsa_scheme->details.ec_schnorr.hash_alg, + *other); + break; + + default: + reverse_copy_out(rsa_scheme->details.any.hash_alg, *other); + break; + } + } + + /* Copy keybits */ + reverse_copy_out(public->t.public_area.param.rsa.key_bits, *other); + + /* Copy exponent */ + reverse_copy_out(public->t.public_area.param.rsa.exponent, *other); + + /* Copy public->t.public_area.unique */ + public->t.public_area.unique.rsa.t.size = + sizeof(public->t.public_area.unique.rsa.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.rsa, + (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + break; + + case TPM_ALG_ECC: + /* Copy symmetric fields */ + reverse_copy_out(public->t.public_area.param.ecc.symmetric.alg, *other); + + if (public->t.public_area.param.ecc.symmetric.alg != TPM_ALG_NULL) + { + reverse_copy_out( + public->t.public_area.param.ecc.symmetric.key_bits.sym, *other); + + reverse_copy_out(public->t.public_area.param.ecc.symmetric.mode.sym, + *other); + } + + /* Copy ECC scheme */ + reverse_copy_out(ecc_scheme->scheme, *other); + if (ecc_scheme->scheme != TPM_ALG_NULL) + { + switch (ecc_scheme->scheme) + { + case TPM_ALG_RSASSA: + reverse_copy_out(ecc_scheme->details.rsassa.hash_alg, *other); + break; + + case TPM_ALG_RSAPSS: + reverse_copy_out(ecc_scheme->details.rsapss.hash_alg, *other); + break; + + case TPM_ALG_ECDSA: + reverse_copy_out(ecc_scheme->details.ecdsa.hash_alg, *other); + break; + + case TPM_ALG_SM2: + reverse_copy_out(ecc_scheme->details.sm2.hash_alg, *other); + break; + + case TPM_ALG_ECDAA: + reverse_copy_out(ecc_scheme->details.ecdaa.hash_alg, *other); + reverse_copy_out(ecc_scheme->details.ecdaa.count, *other); + break; + + case TPM_ALG_ECSCHNORR: + reverse_copy_out(ecc_scheme->details.ec_schnorr.hash_alg, *other); + break; + + case TPM_ALG_HMAC: + reverse_copy_out(ecc_scheme->details.hmac.hash_alg, *other); + break; + + default: + reverse_copy_out(ecc_scheme->details.any.hash_alg, *other); + break; + } + } + + /* Copy curve_id */ + reverse_copy_out(public->t.public_area.param.ecc.curve_id, *other); + + /* Copy KDF scheme */ + reverse_copy_out(kdf->scheme, *other); + switch (kdf->scheme) + { + case TPM_ALG_MGF1: + reverse_copy_out(kdf->details.mgf1.hash_alg, *other); + break; + + case TPM_ALG_KDF1_SP800_56a: + reverse_copy_out(kdf->details.kdf1_SP800_56a.hash_alg, *other); + break; + + case TPM_ALG_KDF1_SP800_108: + reverse_copy_out(kdf->details.kdf1_sp800_108.hash_alg, *other); + break; + + default: + /* Copy something bogus and let TPM return error code */ + *((uint16_t *)*other) = 0xffff; + *other += sizeof(uint16_t); + break; + } + + /* Copy public->t.public_area.unique */ + public->t.public_area.unique.ecc.x.t.size = + sizeof(public->t.public_area.unique.ecc.x.t.buffer); + size = reverse_copy_sized_buf_out( + (TPM2B *)&public->t.public_area.unique.ecc.x, (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + public->t.public_area.unique.ecc.y.t.size = + sizeof(public->t.public_area.unique.ecc.y.t.buffer); + size = reverse_copy_sized_buf_out( + (TPM2B *)&public->t.public_area.unique.ecc.y, (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + break; + + default: + /* Copy symmetric fields */ + reverse_copy_out(public->t.public_area.param.asym.symmetric.alg, + *other); + + if (public->t.public_area.param.asym.symmetric.alg != TPM_ALG_NULL) + { + reverse_copy_out( + public->t.public_area.param.asym.symmetric.key_bits.sym, + *other); + + reverse_copy_out( + public->t.public_area.param.asym.symmetric.mode.sym, *other); + } + + /* Copy scheme */ + reverse_copy_out(asym_scheme->scheme, *other); + if (asym_scheme->scheme != TPM_ALG_NULL) + { + switch (asym_scheme->scheme) + { + case TPM_ALG_RSASSA: + reverse_copy_out(asym_scheme->details.rsassa.hash_alg, *other); + break; + + case TPM_ALG_RSAPSS: + reverse_copy_out(asym_scheme->details.rsapss.hash_alg, *other); + break; + + case TPM_ALG_OAEP: + reverse_copy_out(asym_scheme->details.oaep.hash_alg, *other); + break; + + case TPM_ALG_ECDSA: + reverse_copy_out(asym_scheme->details.ecdsa.hash_alg, *other); + break; + + case TPM_ALG_SM2: + reverse_copy_out(asym_scheme->details.sm2.hash_alg, *other); + break; + + case TPM_ALG_ECDAA: + reverse_copy_out(asym_scheme->details.ecdaa.hash_alg, *other); + reverse_copy_out(asym_scheme->details.ecdaa.count, *other); + break; + + case TPM_ALG_ECSCHNORR: + reverse_copy_out(asym_scheme->details.ec_schnorr.hash_alg, *other); + break; + + default: + reverse_copy_out(asym_scheme->details.any.hash_alg, *other); + break; + } + } + + break; + } + + return true; +} + +static bool reverse_copy_creation_data_out( + TPM2B_CREATION_DATA *data, void **other) +{ + uint16_t size; + + if (data == NULL) + return false; + + reverse_copy_out(data->t.size, *other); + + if ( !reverse_copy_pcr_selection_out(&data->t.data.pcr_select, other) ) + return false; + + data->t.data.pcr_digest.t.size = sizeof(data->t.data.pcr_digest.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.pcr_digest), + (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + *((uint8_t *)(void *)&data->t.data.locality) = *((u8 *)*other); + *other += sizeof(uint8_t); + + reverse_copy_out(data->t.data.parent_name_alg, *other); + + data->t.data.parent_name.t.size = sizeof(data->t.data.parent_name.t.name); + size = reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.parent_name), + (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + data->t.data.parent_qualified_name.t.size = + sizeof(data->t.data.parent_qualified_name.t.name); + size = reverse_copy_sized_buf_out( + (TPM2B *)&(data->t.data.parent_qualified_name), (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + data->t.data.outside_info.t.size = + sizeof(data->t.data.outside_info.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.outside_info), + (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + return true; +} + +static bool reverse_copy_ticket_out(TPMT_TK_CREATION *ticket, void **other) +{ + uint16_t size; + + if (ticket == NULL) + return false; + + reverse_copy_out(ticket->tag, *other); + + reverse_copy_out(ticket->hierarchy, *other); + + ticket->digest.t.size = sizeof(ticket->digest.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&(ticket->digest), + (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + return true; +} +#endif + +static void reverse_copy_context_in(void **other, TPMS_CONTEXT *context) +{ + if (context == NULL) + return; + + reverse_copy_in(*other, context->sequence); + + reverse_copy_in(*other, context->savedHandle); + + reverse_copy_in(*other, context->hierarchy); + + *other += reverse_copy_sized_buf_in((TPM2B *)*other, + (TPM2B *)&context->contextBlob); + +} + +static bool reverse_copy_context_out(TPMS_CONTEXT *context, void **other) +{ + uint16_t size; + + if (context == NULL) + return false; + + reverse_copy_out(context->sequence, *other); + + reverse_copy_out(context->savedHandle, *other); + + reverse_copy_out(context->hierarchy, *other); + + context->contextBlob.t.size = sizeof(context->contextBlob.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&context->contextBlob, + (TPM2B *)*other); + if ( size == 0 ) + return false; + *other += size; + + return true; +} + +static uint32_t _tpm20_send_cmd(void *other, uint32_t locality, uint32_t rsp_size) +{ + struct tpm_if *tpm = get_tpm(); + uint32_t cmd_size; + uint32_t ret; + + /* + * Now set the command size field, now that we know the size of the whole + * command + */ + cmd_size = (uint8_t *)other - cmd_buf; + reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); + + if ( !tpm->hw->submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + + return ret; +} + +static uint32_t _tpm20_pcr_read( + uint32_t locality, tpm_pcr_read_in *in, tpm_pcr_read_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + + reverse_copy_header(TPM_CC_PCR_Read, 0); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_pcr_selection_in(&other, &in->pcr_selection); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); /* Skip past parameter size field */ + + reverse_copy_out(out->pcr_update_counter, other); + + if ( !reverse_copy_pcr_selection_out(&out->pcr_selection, &other) ) + return TPM_RC_FAILURE; + + if ( !reverse_copy_digest_out(&out->pcr_values, &other) ) + return TPM_RC_FAILURE; + + return ret; +} + +static uint32_t _tpm20_pcr_extend( + uint32_t locality, tpm_pcr_extend_in *in, tpm_pcr_extend_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + + reverse_copy_header(TPM_CC_PCR_Extend, &in->sessions); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, in->pcr_handle); + + reverse_copy_sessions_in(&other, &in->sessions); + + reverse_copy_digest_value_in(&other, &in->digests); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions) ) + return TPM_RC_FAILURE; + + return ret; +} + +static uint32_t _tpm20_pcr_event( + uint32_t locality, tpm_pcr_event_in *in, tpm_pcr_event_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + + reverse_copy_header(TPM_CC_PCR_Event, &in->sessions); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, in->pcr_handle); + + reverse_copy_sessions_in(&other, &in->sessions); + + other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->data)); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + if ( !reverse_copy_digest_values_out(&out->digests, &other) ) + return TPM_RC_FAILURE; + + if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, + &in->sessions) ) + return TPM_RC_FAILURE; + + return ret; +} + +static uint32_t _tpm20_pcr_reset( + uint32_t locality, tpm_pcr_reset_in *in, tpm_pcr_reset_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + + reverse_copy_header(TPM_CC_PCR_Reset, &in->sessions); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy(other, &in->pcr_handle, sizeof(uint32_t)); + + other += sizeof(uint32_t); + reverse_copy_sessions_in(&other, &in->sessions); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, + &in->sessions) ) + return TPM_RC_FAILURE; + + return ret; +} + +static uint32_t _tpm20_sequence_start( + uint32_t locality, tpm_sequence_start_in *in, tpm_sequence_start_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + + reverse_copy_header(TPM_CC_HashSequenceStart, 0); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->auth)); + + reverse_copy_in(other, in->hash_alg); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + reverse_copy_out(out->handle, other); + + return ret; +} + +static uint32_t _tpm20_sequence_update( + uint32_t locality, tpm_sequence_update_in *in, tpm_sequence_update_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + + reverse_copy_header(TPM_CC_SequenceUpdate, &in->sessions); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + + reverse_copy_in(other, in->handle); + + reverse_copy_sessions_in(&other, &in->sessions); + + other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->buf)); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, + &in->sessions) ) + return TPM_RC_FAILURE; + + return ret; +} + +static uint32_t _tpm20_sequence_complete( + uint32_t locality, tpm_sequence_complete_in *in, tpm_sequence_complete_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + + reverse_copy_header(TPM_CC_EventSequenceComplete, &in->sessions); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + + reverse_copy_in(other, in->pcr_handle); + reverse_copy_in(other, in->seq_handle); + + reverse_copy_sessions_in(&other, &in->sessions); + + other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->buf)); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + if ( !reverse_copy_digest_values_out(&out->results, &other) ) + return TPM_RC_FAILURE; + + if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, + &in->sessions) ) + return TPM_RC_FAILURE; + + return ret; +} + +static uint32_t _tpm20_nv_read( + uint32_t locality, tpm_nv_read_in *in, tpm_nv_read_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + uint16_t size; + + reverse_copy_header(TPM_CC_NV_Read, &in->sessions); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, in->handle); + reverse_copy_in(other, in->index); + + reverse_copy_sessions_in(&other, &in->sessions); + + reverse_copy_in(other, in->size); + reverse_copy_in(other, in->offset); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + out->data.t.size = sizeof(out->data.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&(out->data), (TPM2B *)other); + if ( size == 0 ) + return TPM_RC_FAILURE; + other += size; + + if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, + &in->sessions) ) + return TPM_RC_FAILURE; + + return ret; +} + +static uint32_t _tpm20_nv_write( + uint32_t locality, tpm_nv_write_in *in, tpm_nv_write_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + + reverse_copy_header(TPM_CC_NV_Write, &in->sessions); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, in->handle); + reverse_copy_in(other, in->index); + + reverse_copy_sessions_in(&other, &in->sessions); + + other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->data)); + + reverse_copy_in(other, in->offset); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, + &in->sessions) ) + return TPM_RC_FAILURE; + + return ret; +} + +static uint32_t _tpm20_nv_read_public( + uint32_t locality, tpm_nv_read_public_in *in, tpm_nv_read_public_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + uint16_t size; + + reverse_copy_header(TPM_CC_NV_ReadPublic, 0); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, in->index); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + reverse_copy_out(out->nv_public.t.size, other); + reverse_copy_out(out->nv_public.t.nv_public.index, other); + reverse_copy_out(out->nv_public.t.nv_public.name_alg, other); + reverse_copy((void *)&(out->nv_public.t.nv_public.attr), other, + sizeof(uint32_t)); + other += sizeof(uint32_t); + + out->nv_public.t.nv_public.auth_policy.t.size = + sizeof(out->nv_public.t.nv_public.auth_policy.t.buffer); + size = reverse_copy_sized_buf_out( + (TPM2B *)&(out->nv_public.t.nv_public.auth_policy), (TPM2B *)other); + if ( size == 0 ) + return TPM_RC_FAILURE; + other += size; + + reverse_copy_out(out->nv_public.t.nv_public.data_size, other); + + out->nv_name.t.size = sizeof(out->nv_name.t.name); + size = reverse_copy_sized_buf_out((TPM2B *)&(out->nv_name), (TPM2B *)other); + if ( size == 0 ) + return TPM_RC_FAILURE; + other += size; + + return ret; +} + +static uint32_t _tpm20_get_random( + uint32_t locality, tpm_get_random_in *in, tpm_get_random_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + uint16_t size; + + reverse_copy_header(TPM_CC_GetRandom, 0); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, in->bytes_req); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + out->random_bytes.t.size = sizeof(out->random_bytes.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&(out->random_bytes), + (TPM2B *)other); + if ( size == 0 ) + return TPM_RC_FAILURE; + other += size; + + return ret; +} + +static uint32_t _tpm20_shutdown(uint32_t locality, uint16_t type) +{ + void *other; + + reverse_copy_header(TPM_CC_Shutdown, 0); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, type); + + return _tpm20_send_cmd(other, locality, RSP_HEAD_SIZE); +} + +//static const char auth_str[] = "test"; + +/* TODO: Add an appropriate per domain key creation */ +#if 0 +static uint32_t _tpm20_create_primary( + uint32_t locality, tpm_create_primary_in *in, tpm_create_primary_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + uint16_t sensitive_size; + void *sensitive_size_ptr; + void *other; + uint16_t size; + + reverse_copy_header(TPM_CC_CreatePrimary, &in->sessions); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, in->primary_handle); + + reverse_copy_sessions_in(&other, &in->sessions); + + /* Copy inSensitive */ + sensitive_size_ptr = other; + other += sizeof(uint16_t); + other += reverse_copy_sized_buf_in((TPM2B *)other, + (TPM2B *)&(in->sensitive.t.sensitive.user_auth)); + other += reverse_copy_sized_buf_in((TPM2B *)other, + (TPM2B *)&(in->sensitive.t.sensitive.data)); + sensitive_size = (uint8_t *)other - (u8 *)sensitive_size_ptr + - sizeof(uint16_t); + reverse_copy(sensitive_size_ptr, &sensitive_size, sizeof(uint16_t)); + + /* Copy inPublic */ + reverse_copy_public_in(&other, &in->public); + + /* Copy outsideInfo */ + other += reverse_copy_sized_buf_in((TPM2B *)other, + (TPM2B *)&(in->outside_info)); + + /* Copy creationPCR */ + reverse_copy_pcr_selection_in(&other, &in->creation_pcr); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + + /* Save objHandle */ + reverse_copy_out(out->obj_handle, other); + + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + /* Save outPublic */ + if ( !reverse_copy_public_out(&out->public, &other) ) + return TPM_RC_FAILURE; + + /* Save creationData */ + if ( !reverse_copy_creation_data_out(&(out->creation_data), &other) ) + return TPM_RC_FAILURE; + + /* Save creationHash */ + out->creation_hash.t.size = sizeof(out->creation_hash.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&(out->creation_hash), + (TPM2B *)other); + if ( size == 0 ) + return TPM_RC_FAILURE; + other += size; + + /* Save creationTicket */ + if ( !reverse_copy_ticket_out(&(out->creation_ticket), &other) ) + return TPM_RC_FAILURE; + + out->name.t.size = sizeof(out->name.t.name); + size = reverse_copy_sized_buf_out((TPM2B *)&(out->name), (TPM2B *)other); + if ( size == 0 ) + return TPM_RC_FAILURE; + other += size; + + if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, + &in->sessions) ) + return TPM_RC_FAILURE; + + return ret; +} +#endif + +/* TODO: Add an appropriate seal/unseal for Xen */ +#if 0 +static uint32_t _tpm20_create( + uint32_t locality, tpm_create_in *in, tpm_create_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + uint16_t sensitive_size; + void *sensitive_size_ptr; + void *other; + uint16_t size; + + reverse_copy_header(TPM_CC_Create, &in->sessions); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, in->parent_handle); + + reverse_copy_sessions_in(&other, &in->sessions); + + /* Copy inSensitive */ + sensitive_size_ptr = other; + other += sizeof(uint16_t); + other += reverse_copy_sized_buf_in((TPM2B *)other, + (TPM2B *)&(in->sensitive.t.sensitive.user_auth)); + other += reverse_copy_sized_buf_in((TPM2B *)other, + (TPM2B *)&(in->sensitive.t.sensitive.data)); + sensitive_size = (uint8_t *)other - (u8 *)sensitive_size_ptr + - sizeof(uint16_t); + reverse_copy(sensitive_size_ptr, &sensitive_size, sizeof(uint16_t)); + + /* Copy inPublic */ + reverse_copy_public_in(&other, &in->public); + + /* Copy outsideInfo */ + other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->outside_info)); + + /* Copy creationPCR */ + reverse_copy_pcr_selection_in(&other, &in->creation_pcr); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + /* Save outPrivate */ + out->private.t.size = sizeof(out->private.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&(out->private), (TPM2B *)other); + if ( size == 0 ) + return TPM_RC_FAILURE; + other += size; + + /* Save outPublic */ + if ( !reverse_copy_public_out(&out->public, &other) ) + return TPM_RC_FAILURE; + + /* Save creationData */ + if ( !reverse_copy_creation_data_out(&(out->creation_data), &other) ) + return TPM_RC_FAILURE; + + /* Save creationHash */ + out->creation_hash.t.size = sizeof(out->creation_hash.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&(out->creation_hash), + (TPM2B *)other); + if ( size == 0 ) + return TPM_RC_FAILURE; + other += size; + + /* Save creationTicket */ + if ( !reverse_copy_ticket_out(&(out->creation_ticket), &other) ) + return TPM_RC_FAILURE; + + if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, + &in->sessions) ) + return TPM_RC_FAILURE; + + return ret; +} + +static uint32_t _tpm20_load( + uint32_t locality, tpm_load_in *in, tpm_load_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + uint16_t size; + + reverse_copy_header(TPM_CC_Load, &in->sessions); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, in->parent_handle); + + reverse_copy_sessions_in(&other, &in->sessions); + + other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->private)); + + reverse_copy_public_in(&other, &in->public); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + + reverse_copy_out(out->obj_handle, other); + + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + out->name.t.size = sizeof(out->name.t.name); + size = reverse_copy_sized_buf_out((TPM2B *)&(out->name), (TPM2B *)other); + if ( size == 0 ) + return TPM_RC_FAILURE; + other += size; + + if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, + &in->sessions) ) + return TPM_RC_FAILURE; + + return ret; +} + +static uint32_t _tpm20_unseal( + uint32_t locality, tpm_unseal_in *in, tpm_unseal_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + uint16_t size; + + reverse_copy_header(TPM_CC_Unseal, &in->sessions); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, in->item_handle); + + reverse_copy_sessions_in(&other, &in->sessions); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + out->data.t.size = sizeof(out->data.t.buffer); + size = reverse_copy_sized_buf_out((TPM2B *)&(out->data), (TPM2B *)other); + if ( size == 0 ) + return TPM_RC_FAILURE; + other += size; + + if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, + &in->sessions) ) + return TPM_RC_FAILURE; + + return ret; +} +#endif + +static uint32_t _tpm20_context_save( + uint32_t locality, tpm_contextsave_in *in, tpm_contextsave_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + + reverse_copy_header(TPM_CC_ContextSave, 0); + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, in->saveHandle); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); /* Skip past parameter size field */ + + if ( !reverse_copy_context_out(&out->context, &other) ) + return TPM_RC_FAILURE; + + return ret; + +} + +static uint32_t _tpm20_context_load( + uint32_t locality, tpm_contextload_in *in, tpm_contextload_out *out) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + + reverse_copy_header(TPM_CC_ContextLoad, 0); + other = (void *)cmd_buf + CMD_HEAD_SIZE; + + reverse_copy_context_in(&other, &in->context); + + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); /* Skip past parameter size field */ + + reverse_copy_out(out->loadedHandle, other); + + return ret; +} + +static uint32_t _tpm20_context_flush(uint32_t locality, tpm_flushcontext_in *in) +{ + uint32_t ret; + uint16_t rsp_tag; + void *other; + + + reverse_copy_header(TPM_CC_FlushContext, 0); + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, in->flushHandle); + + ret = _tpm20_send_cmd(other, locality, RSP_HEAD_SIZE); + if ( ret != TPM_RC_SUCCESS ) + return ret; + + other = (void *)rsp_buf + RSP_HEAD_SIZE; + + reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); + + if ( rsp_tag == TPM_ST_SESSIONS ) + other += sizeof(uint32_t); + + return ret; + +} + +static bool cf_check tpm20_context_flush( + struct tpm_if *ti, uint32_t locality, TPM_HANDLE handle) +{ + tpm_flushcontext_in in; + uint32_t ret; + + if ( ti == NULL || locality >= TPM_NR_LOCALITIES ) + return false; + if ( handle == 0 ) + return false; + in.flushHandle = handle; + ret = _tpm20_context_flush(locality, &in); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING + "TPM: tpm2 context flush returned , return value = %08X\n", ret); + ti->error = ret; + return false; + } + else + printk(XENLOG_WARNING + "TPM: tpm2 context flush successful, return value = %08X\n", ret); + return true; +} + +/* TODO: This is concerning, review if can be done differnt. DPS */ +TPM_CMD_SESSION_DATA_IN pw_session; + +static void create_pw_session(TPM_CMD_SESSION_DATA_IN *ses) +{ + ses->session_handle = TPM_RS_PW; + ses->nonce.t.size = 0; + *((uint8_t *)((void *)&ses->session_attr)) = 0; + ses->hmac.t.size = 0; +} + +#define SET_PCR_SELECT_BIT( pcr_selection, pcr ) \ + (pcr_selection).pcr_select[( (pcr)/8 )] |= ( 1 << ( (pcr) % 8) ); +static bool cf_check tpm20_pcr_read( + struct tpm_if *ti, uint32_t locality, uint32_t pcr, tpm_pcr_value_t *out) +{ + tpm_pcr_read_in read_in; + tpm_pcr_read_out read_out; + uint32_t ret; + + if ( ti == NULL || out == NULL ) + return false; + + read_in.pcr_selection.count = 1; + read_in.pcr_selection.selections[0].hash = ti->cur_alg; + read_in.pcr_selection.selections[0].size_of_select = 3; + read_in.pcr_selection.selections[0].pcr_select[0] = 0; + read_in.pcr_selection.selections[0].pcr_select[1] = 0; + read_in.pcr_selection.selections[0].pcr_select[2] = 0; + SET_PCR_SELECT_BIT( read_in.pcr_selection.selections[0], pcr ); + + ret = _tpm20_pcr_read(locality, &read_in, &read_out); + if (ret != TPM_RC_SUCCESS) { + printk(XENLOG_WARNING"TPM: PCR%d Read return value = %08X\n", pcr, ret); + ti->error = ret; + return false; + } + + copy_hash(out, + (hash_t *)&(read_out.pcr_values.digests[0].t.buffer[0]), + ti->cur_alg); + + return true; +} + +static bool cf_check tpm20_pcr_extend( + struct tpm_if *ti, uint32_t locality, uint32_t pcr, const hash_list_t *in) +{ + tpm_pcr_extend_in extend_in; + tpm_pcr_extend_out extend_out; + uint32_t ret, i; + + if ( ti == NULL || in == NULL ) + return false; + + extend_in.pcr_handle = pcr; + extend_in.sessions.num_sessions = 1; + extend_in.sessions.sessions[0] = pw_session; + + extend_in.digests.count = in->count; + for (i=0; icount; i++) + { + extend_in.digests.digests[i].hash_alg = in->entries[i].alg; + copy_hash((hash_t *)&extend_in.digests.digests[i].digest, + &in->entries[i].hash, in->entries[i].alg); + } + + ret = _tpm20_pcr_extend(locality, &extend_in, &extend_out); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: Pcr %d extend, return value = %08X\n", + pcr, ret); + ti->error = ret; + return false; + } + + return true; +} + +static bool cf_check tpm20_pcr_reset(struct tpm_if *ti, uint32_t locality, uint32_t pcr) +{ + tpm_pcr_reset_in reset_in; + tpm_pcr_reset_out reset_out; + uint32_t ret; + + reset_in.pcr_handle = pcr; + reset_in.sessions.num_sessions = 1; + reset_in.sessions.sessions[0] = pw_session; + + ret = _tpm20_pcr_reset(locality, &reset_in, &reset_out); + if (ret != TPM_RC_SUCCESS) + { + printk(XENLOG_WARNING"TPM: Pcr %d Reset return value = %08X\n", + pcr, ret); + ti->error = ret; + return false; + } + + return true; +} + +static bool cf_check tpm20_hash( + struct tpm_if *ti, uint32_t locality, const uint8_t *data, + uint32_t data_size, hash_list_t *hl) +{ + tpm_sequence_start_in start_in; + tpm_sequence_start_out start_out; + tpm_sequence_update_in update_in; + tpm_sequence_update_out update_out; + tpm_sequence_complete_in complete_in; + tpm_sequence_complete_out complete_out; + TPM2B_MAX_BUFFER buffer; + uint32_t ret, i, j, chunk_size; + + if ( ti == NULL || data == NULL ) + return false; + + start_in.auth.t.size = 2; + start_in.auth.t.buffer[0] = 0; + start_in.auth.t.buffer[1] = 0xff; + start_in.hash_alg = TPM_ALG_NULL; + + ret = _tpm20_sequence_start(locality, &start_in, &start_out); + if (ret != TPM_RC_SUCCESS) + { + printk(XENLOG_WARNING"TPM: HashSequenceStart return value = %08X\n", + ret); + ti->error = ret; + return false; + } + + update_in.sessions.num_sessions = 1; + update_in.sessions.sessions[0] = pw_session; + update_in.sessions.sessions[0].hmac = start_in.auth; + update_in.handle = start_out.handle; + + complete_in.pcr_handle = TPM_RH_NULL; + complete_in.seq_handle = start_out.handle; + complete_in.sessions.num_sessions = 2; + create_pw_session(&complete_in.sessions.sessions[0]); + complete_in.sessions.sessions[1] = pw_session; + complete_in.sessions.sessions[1].hmac = start_in.auth; + + for( i=0; i MAX_DIGEST_BUFFER ) + { + chunk_size = MAX_DIGEST_BUFFER; + } + else + { + chunk_size = data_size - i; + } + + buffer.t.size = chunk_size; + memcpy( &(buffer.t.buffer[0]), &(data[i] ), chunk_size ); + + update_in.buf = buffer; + ret = _tpm20_sequence_update(locality, &update_in, &update_out); + if (ret != TPM_RC_SUCCESS) + { + printk(XENLOG_WARNING"TPM: SequenceUpdate return value = %08X\n", + ret); + ti->error = ret; + return false; + } + } + + buffer.t.size = 0; + complete_in.buf = buffer; + ret = _tpm20_sequence_complete(locality, &complete_in, &complete_out); + if (ret != TPM_RC_SUCCESS) + { + printk(XENLOG_WARNING + "TPM: EventSequenceComplete return value = %08X\n", ret); + ti->error = ret; + return false; + } + + hl->count = complete_out.results.count; + if ( hl->count > MAX_ALG_NUM ) + { + printk(XENLOG_WARNING + "TPM: EventSequenceComplete return %d digests, keep first %d\n", + hl->count, MAX_ALG_NUM); + hl->count = MAX_ALG_NUM; + } + + for ( j=0; jcount; j++ ) + { + hl->entries[j].alg = complete_out.results.digests[j].hash_alg; + memcpy(&hl->entries[j].hash, &complete_out.results.digests[j].digest, + sizeof(hl->entries[j].hash)); + } + + return true; +} + +static bool cf_check tpm20_nv_read( + struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t offset, + uint8_t *data, uint32_t *data_size) +{ + tpm_nv_read_in read_in; + tpm_nv_read_out read_out; + uint32_t ret; + + if ( ti == NULL || data_size == NULL || *data_size == 0 ) + return false; + + if ( *data_size > MAX_NV_INDEX_SIZE ) + *data_size = MAX_NV_INDEX_SIZE; + + read_in.handle = index; + read_in.index = index; + read_in.sessions.num_sessions = 1; + read_in.sessions.sessions[0] = pw_session; + read_in.offset = offset; + read_in.size = *data_size; + + ret = _tpm20_nv_read(locality, &read_in, &read_out); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING + "TPM: read NV index %08x from offset %08x, return value = %08X\n", + index, offset, ret); + ti->error = ret; + return false; + } + + if (read_out.data.t.size == 0 || read_out.data.t.size > *data_size) + { + printk(XENLOG_WARNING"TPM: data_size %x too large for buffer\n", + read_out.data.t.size); + ti->error = TPM_RC_NV_SIZE; + return false; + } + *data_size = read_out.data.t.size; + memcpy(data, &read_out.data.t.buffer[0], *data_size); + + return true; +} + +static bool cf_check tpm20_nv_write( + struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t offset, + const uint8_t *data, uint32_t data_size) +{ + tpm_nv_write_in write_in; + tpm_nv_write_out write_out; + uint32_t ret; + + if ( ti == NULL || data == NULL || data_size == 0 || + data_size > MAX_NV_INDEX_SIZE ) + return false; + + write_in.handle = index; + write_in.index = index; + write_in.sessions.num_sessions = 1; + write_in.sessions.sessions[0] = pw_session; + write_in.offset = offset; + write_in.data.t.size = data_size; + memcpy(&write_in.data.t.buffer[0], data, data_size); + + ret = _tpm20_nv_write(locality, &write_in, &write_out); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING + "TPM: write NV %08x, offset %08x, %08x bytes, return value = %08X\n", + index, offset, data_size, ret); + ti->error = ret; + return false; + } + + return true; +} + +static bool cf_check tpm20_get_nvindex_size( + struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t *size) +{ + tpm_nv_read_public_in public_in; + tpm_nv_read_public_out public_out; + uint32_t ret; + + if ( ti == NULL || size == NULL ) + return false; + + public_in.index = index; + + ret = _tpm20_nv_read_public(locality, &public_in, &public_out); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING + "TPM: fail to get public data of 0x%08X in TPM NV\n", index); + ti->error = ret; + return false; + } + + if (index != public_out.nv_public.t.nv_public.index) + { + printk(XENLOG_WARNING + "TPM: Index 0x%08X is not the one expected 0x%08X\n", index, index); + ti->error = TPM_RC_FAILURE; + return false; + } + + *size = public_out.nv_public.t.nv_public.data_size; + + return true; +} + +static bool cf_check tpm20_get_nvindex_permission( + struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t *attribute) +{ + tpm_nv_read_public_in public_in; + tpm_nv_read_public_out public_out; + uint32_t ret; + + if ( ti == NULL || locality >= TPM_NR_LOCALITIES || + index == 0 || attribute == NULL ) + return false; + + public_in.index = index; + + ret = _tpm20_nv_read_public(locality, &public_in, &public_out); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING + "TPM: fail to get public data of 0x%08X in TPM NV\n", index); + ti->error = ret; + return false; + } + + if (index != public_out.nv_public.t.nv_public.index) + { + printk(XENLOG_WARNING + "TPM: Index 0x%08X is not the one expected 0x%08X\n", index, index); + ti->error = TPM_RC_FAILURE; + return false; + } + + *attribute = *(uint32_t*)(&public_out.nv_public.t.nv_public.attr); + + return true; +} + +/* TODO: Add an appropriate seal/unseal for Xen */ +#if 0 +static bool cf_check tpm20_seal( + struct tpm_if *ti, uint32_t locality, uint32_t in_data_size, + const uint8_t *in_data, uint32_t *sealed_data_size, uint8_t *sealed_data) +{ + tpm_create_in create_in; + tpm_create_out create_out; + uint32_t ret; + + create_in.parent_handle = handle2048; + create_in.sessions.num_sessions = 1; + create_in.sessions.sessions[0] = pw_session; + create_in.sessions.sessions[0].hmac.t.size = 2; + create_in.sessions.sessions[0].hmac.t.buffer[0] = 0x00; + create_in.sessions.sessions[0].hmac.t.buffer[1] = 0xff; + + create_in.public.t.public_area.type = TPM_ALG_KEYEDHASH; + create_in.public.t.public_area.name_alg = ti->cur_alg; + create_in.public.t.public_area.auth_policy.t.size = 0; + *(uint32_t *)&create_in.public.t.public_area.object_attr = 0; + create_in.public.t.public_area.object_attr.userWithAuth = 1; + create_in.public.t.public_area.object_attr.noDA = 1; + create_in.public.t.public_area.param.keyed_hash.scheme.scheme = TPM_ALG_NULL; + create_in.public.t.public_area.unique.keyed_hash.t.size = 0; + + COMPILE_TIME_ASSERT( sizeof(auth_str) - 1 <= + sizeof(create_in.sensitive.t.sensitive.user_auth.t.buffer) ); + create_in.sensitive.t.sensitive.user_auth.t.size = sizeof(auth_str) - 1; + memcpy(&(create_in.sensitive.t.sensitive.user_auth.t.buffer[0]), + auth_str, sizeof(auth_str)-1); + if ( in_data_size > + sizeof(create_in.sensitive.t.sensitive.data.t.buffer) ) + { + printk(XENLOG_WARNING + "TPM: input data size to seal is too large: %08X(%08x)\n", + in_data_size, + sizeof(create_in.sensitive.t.sensitive.data.t.buffer)); + return false; + } + create_in.sensitive.t.sensitive.data.t.size = in_data_size; + memcpy(&(create_in.sensitive.t.sensitive.data.t.buffer[0]), + in_data, in_data_size); + + create_in.outside_info.t.size = 0; + create_in.creation_pcr.count = 0; + memset(&create_out, 0, sizeof(create_out)); + + ret = _tpm20_create(locality, &create_in, &create_out); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: Create return value = %08X\n", ret); + ti->error = ret; + return false; + } + *sealed_data_size = sizeof(create_out); + memcpy(sealed_data, &create_out, *sealed_data_size); + + return true; +} + +static bool cf_check tpm20_unseal( + struct tpm_if *ti, uint32_t locality, uint32_t sealed_data_size, + const uint8_t *sealed_data, uint32_t *secret_size, uint8_t *secret) +{ + tpm_load_in load_in; + tpm_load_out load_out; + tpm_unseal_in unseal_in; + tpm_unseal_out unseal_out; + uint32_t ret; + + if ( ti == NULL || locality >= TPM_NR_LOCALITIES || + sealed_data_size == 0 || sealed_data == NULL ) + return false; + + /* For TPM 2.0, the object will need to be loaded before it may be used.*/ + load_in.parent_handle = handle2048; + load_in.sessions.num_sessions = 1; + load_in.sessions.sessions[0] = pw_session; + load_in.sessions.sessions[0].hmac.t.size = 2; + load_in.sessions.sessions[0].hmac.t.buffer[0] = 0x00; + load_in.sessions.sessions[0].hmac.t.buffer[1] = 0xff; + load_in.private = ((tpm_create_out *)sealed_data)->private; + load_in.public = ((tpm_create_out *)sealed_data)->public; + + ret = _tpm20_load(locality, &load_in, &load_out); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: Load return value = %08X\n", ret); + ti->error = ret; + return false; + } + + unseal_in.sessions.num_sessions = 1; + unseal_in.sessions.sessions[0] = pw_session; + unseal_in.sessions.sessions[0].hmac.t.size = sizeof(auth_str) - 1; + memcpy(&(unseal_in.sessions.sessions[0].hmac.t.buffer[0]), + auth_str, sizeof(auth_str)-1); + unseal_in.item_handle = load_out.obj_handle; + + ret = _tpm20_unseal(locality, &unseal_in, &unseal_out); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: Unseal return value = %08X\n", ret); + ti->error = ret; + return false; + } + + *secret_size = unseal_out.data.t.size; + memcpy(secret, &(unseal_out.data.t.buffer[0]), *secret_size); + + if ( !tpm20_context_flush(ti, locality, load_out.obj_handle) ) + { + printk(XENLOG_WARNING"TPM: Failed to flush context\n"); + ti->error = ret; + return false; + } + + return true; +} + +#else + +/* Placeholders until proper seal/unseal is implemented */ +static inline bool cf_check tpm20_seal( + struct tpm_if *ti, uint32_t locality, uint32_t in_data_size, + const uint8_t *in_data, uint32_t *sealed_data_size, uint8_t *sealed_data) +{ + return false; +} + +static inline bool cf_check tpm20_unseal( + struct tpm_if *ti, uint32_t locality, uint32_t sealed_data_size, + const uint8_t *sealed_data, uint32_t *secret_size, uint8_t *secret) +{ + return false; +} + +#endif + +static bool cf_check tpm20_get_random( + struct tpm_if *ti, uint32_t locality, uint8_t *random_data, + uint32_t *data_size) +{ + tpm_get_random_in random_in; + tpm_get_random_out random_out; + uint32_t ret, out_size, requested_size; + static bool first_attempt; + + if ( random_data == NULL || data_size == NULL || *data_size == 0 ) + return false; + + first_attempt = true; + requested_size = *data_size; + + random_in.bytes_req = *data_size; + + ret = _tpm20_get_random(locality, &random_in, &random_out); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING + "TPM: get random 0x%x bytes, return value = %08X\n", + *data_size, ret); + ti->error = ret; + return false; + } + + out_size = random_out.random_bytes.t.size; + if (out_size > 0) + memcpy(random_data, &(random_out.random_bytes.t.buffer[0]), out_size); + *data_size = out_size; + + /* if TPM doesn't return all requested random bytes, try one more time */ + if ( out_size < requested_size ) + { + printk(XENLOG_WARNING"requested 0x%x random bytes but only got 0x%x\n", + requested_size, out_size); + /* we're only going to try twice */ + if ( first_attempt ) + { + uint32_t second_size = requested_size - out_size; + + first_attempt = false; + printk(XENLOG_WARNING + "trying one more time to get remaining 0x%x bytes\n", + second_size); + random_in.bytes_req = second_size; + + ret = _tpm20_get_random(locality, &random_in, &random_out); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING + "TPM: get random 0x%x bytes, return value = %08X\n", + *data_size, ret); + ti->error = ret; + return false; + } + + out_size = random_out.random_bytes.t.size; + if (out_size > 0) + memcpy(random_data+*data_size, + &(random_out.random_bytes.t.buffer[0]), out_size); + *data_size += out_size; + } + } + + return true; +} + +static uint32_t cf_check tpm20_save_state(struct tpm_if *ti, uint32_t locality) +{ + uint32_t ret; + + if ( ti == NULL ) + return false; + + ret = _tpm20_shutdown(locality, TPM_SU_STATE); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING"TPM: Shutdown, return value = %08X\n", ret); + ti->error = ret; + } + + return ret; +} + +#define TPM_PCR_RESETABLE_MIN 16 +static bool cf_check tpm20_cap_pcrs(struct tpm_if *ti, uint32_t locality, int pcr) +{ + hash_list_t cap_val; /* use whatever val is on stack */ + + if ( ti == NULL || locality >= TPM_NR_LOCALITIES || pcr < 0 || + pcr > TPM_NR_PCRS ) + return false; + + cap_val.count = ti->banks; + for (unsigned int i=0; ibanks; i++) + cap_val.entries[i].alg = ti->algs_banks[i]; + + tpm20_pcr_extend(ti, locality, pcr, &cap_val); + + printk(XENLOG_INFO"cap'ed PCR%d\n", pcr); + return true; +} + +static bool alg_is_supported(uint16_t alg) +{ + for (int i = 0; i < tpm_alg_list_count; i++) + { + if (alg == tpm_alg_list[i]) + return true; + } + + return false; +} + +tpm_contextsave_out tpm2_context_saved; + +static bool cf_check tpm20_context_save( + struct tpm_if *ti, uint32_t locality, TPM_HANDLE handle, + void *context_saved) +{ + tpm_contextsave_in in; + tpm_contextsave_out out; + uint32_t ret; + + if ( ti == NULL || locality >= TPM_NR_LOCALITIES ) + return false; + + if ( handle == 0 ) + return false; + + in.saveHandle = handle; + ret =_tpm20_context_save(locality, &in, &out); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING + "TPM: tpm2 context save failed, return value = %08X\n", ret); + ti->error = ret; + return false; + } + else + { + printk(XENLOG_WARNING + "TPM: tpm2 context save successful, return value = %08X\n", ret); + } + memcpy((tpm_contextsave_out *)context_saved, &out, + sizeof(tpm_contextsave_out)); + return true; +} + +static bool cf_check tpm20_context_load( + struct tpm_if *ti, uint32_t locality, void *context_saved, + TPM_HANDLE *handle) +{ + tpm_contextload_in in; + tpm_contextload_out out; + uint32_t ret; + + if ( ti == NULL || locality >= TPM_NR_LOCALITIES ) + return false; + + memcpy(&in, (tpm_contextsave_out *)context_saved, sizeof(tpm_contextsave_out)); + + ret = _tpm20_context_load(locality, &in, &out); + if ( ret != TPM_RC_SUCCESS ) + { + printk(XENLOG_WARNING + "TPM: tpm2 context load failed, return value = %08X\n", ret); + ti->error = ret; + return false; + } + else + { + printk(XENLOG_WARNING + "TPM: tpm2 context load successful, return value = %08X\n", ret); + } + *handle = out.loadedHandle; + return true; +} + +#if 0 +/* Moving primary logic out of init for use to create a key per domain */ +static bool tpm20_create_key(void) +{ + tpm_create_primary_in primary_in; + tpm_create_primary_out primary_out; + + /* create primary object as parent obj for seal */ + primary_in.primary_handle = TPM_RH_NULL; + primary_in.sessions.num_sessions = 1; + primary_in.sessions.sessions[0].session_handle = TPM_RS_PW; + primary_in.sessions.sessions[0].nonce.t.size = 0; + primary_in.sessions.sessions[0].hmac.t.size = 0; + *((uint8_t *)((void *)&primary_in.sessions.sessions[0].session_attr)) = 0; + + primary_in.sensitive.t.sensitive.user_auth.t.size = 2; + primary_in.sensitive.t.sensitive.user_auth.t.buffer[0] = 0x00; + primary_in.sensitive.t.sensitive.user_auth.t.buffer[1] = 0xff; + primary_in.sensitive.t.sensitive.data.t.size = 0; + + primary_in.public.t.public_area.type = TPM_ALG_RSA; + primary_in.public.t.public_area.name_alg = ti->cur_alg; + *(uint32_t *)&primary_in.public.t.public_area.object_attr = 0; + primary_in.public.t.public_area.object_attr.restricted = 1; + primary_in.public.t.public_area.object_attr.userWithAuth = 1; + primary_in.public.t.public_area.object_attr.decrypt = 1; + primary_in.public.t.public_area.object_attr.fixedTPM = 1; + primary_in.public.t.public_area.object_attr.fixedParent = 1; + primary_in.public.t.public_area.object_attr.noDA = 1; + primary_in.public.t.public_area.object_attr.sensitiveDataOrigin = 1; + primary_in.public.t.public_area.auth_policy.t.size = 0; + primary_in.public.t.public_area.param.rsa.symmetric.alg = TPM_ALG_AES; + primary_in.public.t.public_area.param.rsa.symmetric.key_bits.aes= 128; + primary_in.public.t.public_area.param.rsa.symmetric.mode.aes = TPM_ALG_CFB; + primary_in.public.t.public_area.param.rsa.scheme.scheme = TPM_ALG_NULL; + primary_in.public.t.public_area.param.rsa.key_bits = 2048; + primary_in.public.t.public_area.param.rsa.exponent = 0; + primary_in.public.t.public_area.unique.keyed_hash.t.size = 0; + primary_in.outside_info.t.size = 0; + primary_in.creation_pcr.count = 0; + + printk(XENLOG_INFO"TPM:CreatePrimary creating hierarchy handle = %08X\n", + primary_in.primary_handle); + ret = _tpm20_create_primary(ti->cur_loc, &primary_in, &primary_out); + if (ret != TPM_RC_SUCCESS) { + printk(XENLOG_WARNING"TPM: CreatePrimary return value = %08X\n", ret); + ti->error = ret; + return false; + } + handle2048 = primary_out.obj_handle; + + printk(XENLOG_INFO"TPM:CreatePrimary created object handle = %08X\n", + handle2048); +} +#endif + +static bool cf_check tpm20_init(struct tpm_if *ti) +{ + uint32_t ret; + unsigned int i; + tpm_pcr_event_in event_in; + tpm_pcr_event_out event_out; + + if ( ti == NULL ) + return false; + + ti->cur_loc = 0; + + /* init version */ + ti->version.major = TPM20_VER_MAJOR; + ti->version.minor = TPM20_VER_MINOR; + + /* init timeouts value */ + ti->timeout.timeout_a = TIMEOUT_A; + ti->timeout.timeout_b = TIMEOUT_B; + ti->timeout.timeout_c = TIMEOUT_C; + ti->timeout.timeout_d = TIMEOUT_D; + + /* get pcr extend policy from cmdline */ + //get_tboot_extpol(); + + ti->tb_policy_index = 0x01c10131; + ti->lcp_own_index = 0x01c10106; + ti->tb_err_index = 0x01c10132; + ti->sgx_svn_index = 0x01c10104; + + /* create one common password sesson*/ + create_pw_session(&pw_session); + + /* init supported alg list for banks */ + event_in.pcr_handle = 16; + event_in.sessions.num_sessions = 1; + event_in.sessions.sessions[0] = pw_session; + event_in.data.t.size = 4; + event_in.data.t.buffer[0] = 0; + event_in.data.t.buffer[1] = 0xff; + event_in.data.t.buffer[2] = 0x55; + event_in.data.t.buffer[3] = 0xaa; + ret = _tpm20_pcr_event(ti->cur_loc, &event_in, &event_out); + if (ret != TPM_RC_SUCCESS) + { + printk(XENLOG_WARNING + "TPM: PcrEvent not successful, return value = %08X\n", ret); + ti->error = ret; + return false; + } + ti->banks = event_out.digests.count; + printk(XENLOG_INFO"TPM: supported bank count = %d\n", ti->banks); + for (i=0; ibanks; i++) + { + ti->algs_banks[i] = event_out.digests.digests[i].hash_alg;; + printk(XENLOG_INFO"TPM: bank alg = %08x\n", ti->algs_banks[i]); + } + + /* init supported alg list */ + ti->alg_count = 0; + for (i=0; ibanks; i++) + { + if (alg_is_supported(ti->algs_banks[i])) + { + ti->algs[ti->alg_count] = ti->algs_banks[i]; + ti->alg_count++; + } + } + printk(XENLOG_INFO"TPM: supported alg count = %d\n", ti->alg_count); + for (unsigned int i=0; ialg_count; i++) + printk(XENLOG_INFO"TPM: hash alg = %08X\n", ti->algs[i]); + + /* reset debug PCR 16 */ + if (!tpm20_pcr_reset(ti, ti->cur_loc, 16)) + { + printk(XENLOG_WARNING"TPM: tpm20_pcr_reset failed...\n"); + return false; + } + + tpm_print(ti); + return true; +} + +const struct tpm_cmd_if tpm_20_cmds = { + .init = tpm20_init, + .pcr_read = tpm20_pcr_read, + .pcr_extend = tpm20_pcr_extend, + .hash = tpm20_hash, + .pcr_reset = tpm20_pcr_reset, + .nv_read = tpm20_nv_read, + .nv_write = tpm20_nv_write, + .get_nvindex_size = tpm20_get_nvindex_size, + .get_nvindex_permission = tpm20_get_nvindex_permission, + .seal = tpm20_seal, + .unseal = tpm20_unseal, + .get_random = tpm20_get_random, + .save_state = tpm20_save_state, + .cap_pcrs = tpm20_cap_pcrs, + .context_save = tpm20_context_save, + .context_load = tpm20_context_load, + .context_flush = tpm20_context_flush, +}; + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/drivers/security/tpm/tpm_20.h b/xen/drivers/security/tpm/tpm_20.h new file mode 100644 index 0000000000..8343bb8b00 --- /dev/null +++ b/xen/drivers/security/tpm/tpm_20.h @@ -0,0 +1,1565 @@ +/* + * tpm_20.h: TPM2.0-related structure + * + * Copyright (c) 2006-2013, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __LOCAL_TPM20_H__ +#define __LOCAL_TPM20_H__ + +/* + * tpm2.0 structure defined in spec. + */ + +typedef struct { + uint16_t size; + uint8_t buffer[1]; +} TPM2B; + +// Table 205 -- SHA1 Hash Values +#define SHA1_DIGEST_SIZE 20 +#define SHA1_BLOCK_SIZE 64 +#define SHA1_DER_SIZE 15 +#define SHA1_DER {0x30,0x21,0x30,0x09,0x06, 0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14} + +// Table 206 -- SHA256 Hash Values +#define SHA256_DIGEST_SIZE 32 +#define SHA256_BLOCK_SIZE 64 +#define SHA256_DER_SIZE 19 +#define SHA256_DER {0x30,0x31,0x30,0x0d,0x06, 0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01, 0x05,0x00,0x04,0x20} + +// Table 207 -- SHA384 Hash Values +#define SHA384_DIGEST_SIZE 48 +#define SHA384_BLOCK_SIZE 128 +#define SHA384_DER_SIZE 19 +#define SHA384_DER {0x30,0x41,0x30,0x0d,0x06, 0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02, 0x05,0x00,0x04,0x30} + + +// Table 208 -- SHA512 Hash Values +#define SHA512_DIGEST_SIZE 64 +#define SHA512_BLOCK_SIZE 128 +#define SHA512_DER_SIZE 19 +#define SHA512_DER {0x30,0x51,0x30,0x0d,0x06, \ + 0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,\ + 0x05,0x00,0x04,0x40} + +// Table 210 -- SM3_256 Hash Values +#define SM3_256_DIGEST_SIZE 32 +#define SM3_256_BLOCK_SIZE 64 +#define SM3_256_DER_SIZE 18 +#define SM3_256_DER {0x30,0x30,0x30,0x0c,0x06, \ + 0x08,0x2A,0x81,0x1C,0x81,0x45,0x01,0x83,0x11,0x05,\ + 0x00,0x04,0x20} + +// Table 213 -- Logic Values +#define YES 1 +#define NO 0 +#define TRUE 1 +#define FALSE 0 +#define SET 1 +#define CLEAR 0 + +// Table 215 -- Implemented Algorithms +#define ALG_RSA YES // 1 +#define ALG_SHA1 YES // 1 +#define ALG_HMAC YES // 1 +#define ALG_AES YES // 1 +#define ALG_MGF1 YES // 1 +#define ALG_XOR YES // 1 +#define ALG_KEYEDHASH YES // 1 +#define ALG_SHA256 YES // 1 +#define ALG_SHA384 YES // 0 +#define ALG_SHA512 YES // 0 +#define ALG_SM3_256 YES // 1 +#define ALG_SM4 YES // 1 +#define ALG_RSASSA YES // 1 +#define ALG_RSAES YES // 1 +#define ALG_RSAPSS YES // 1 +#define ALG_OAEP YES // 1 +#define ALG_ECC YES // 1 +#define ALG_ECDH YES // 1 +#define ALG_ECDSA YES // 1 +#define ALG_ECDAA YES // 1 +#define ALG_SM2 YES // 1 +#define ALG_ECSCHNORR YES // 1 +#define ALG_SYMCIPHER YES // 1 +#define ALG_KDF1_SP800_56a YES // 1 +#define ALG_KDF2 NO // 0 +#define ALG_KDF1_SP800_108 YES // 1 +#define ALG_CTR YES // 1 +#define ALG_OFB YES // 1 +#define ALG_CBC YES // 1 +#define ALG_CFB YES // 1 +#define ALG_ECB YES // 1 + +#define HASH_COUNT (ALG_SHA1+ALG_SHA256+ALG_SM3_256+ALG_SHA384+ALG_SHA512) + +// Table 217 -- RSA Algorithm Constants +#define RSA_KEY_SIZES_BITS {1024, 2048} // {1024,2048} +#define MAX_RSA_KEY_BITS 2048 +#define MAX_RSA_KEY_BYTES ((MAX_RSA_KEY_BITS + 7) / 8) // 256 + +// Table 218 -- ECC Algorithm Constants +#define ECC_CURVES {TPM_ECC_NIST_P256,TPM_ECC_BN_P256,TPM_ECC_SM2_P256} +#define ECC_KEY_SIZES_BITS {256} +#define MAX_ECC_KEY_BITS 256 +#define MAX_ECC_KEY_BYTES ((MAX_ECC_KEY_BITS + 7) / 8) // 32 + +// Table 219 -- AES Algorithm Constants +#define AES_KEY_SIZES_BITS {128} +#define MAX_AES_KEY_BITS 128 +#define MAX_AES_BLOCK_SIZE_BYTES 16 +#define MAX_AES_KEY_BYTES ((MAX_AES_KEY_BITS + 7) / 8) // 16 + +// Table 221 -- Symmetric Algorithm Constants +#define MAX_SYM_KEY_BITS MAX_AES_KEY_BITS // 128 +#define MAX_SYM_KEY_BYTES MAX_AES_KEY_BYTES // 16 +#define MAX_SYM_BLOCK_SIZE MAX_AES_BLOCK_SIZE_BYTES // 16 + +// Table 222 -- Implementation Values +#define FIELD_UPGRADE_IMPLEMENTED NO // 0 +typedef uint16_t BSIZE; +#define BUFFER_ALIGNMENT 4 +#define IMPLEMENTATION_PCR 24 +#define PLATFORM_PCR 24 +#define DRTM_PCR 17 +#define NUM_LOCALITIES 5 +#define MAX_HANDLE_NUM 3 +#define MAX_ACTIVE_SESSIONS 64 +typedef uint16_t CONTEXT_SLOT; +typedef uint64_t CONTEXT_COUNTER; +#define MAX_LOADED_SESSIONS 3 +#define MAX_SESSION_NUM 3 +#define MAX_LOADED_OBJECTS 3 +#define MIN_EVICT_OBJECTS 2 +#define PCR_SELECT_MIN ((PLATFORM_PCR+7)/8) // 3 +#define PCR_SELECT_MAX ((IMPLEMENTATION_PCR+7)/8) // 3 +#define NUM_POLICY_PCR_GROUP 1 +#define NUM_AUTHVALUE_PCR_GROUP 1 +#define MAX_CONTEXT_SIZE 4000 +#define MAX_DIGEST_BUFFER 1024 +#define MAX_NV_INDEX_SIZE 1024 +#define MAX_CAP_BUFFER 1024 +#define NV_MEMORY_SIZE 16384 +#define NUM_STATIC_PCR 16 +#define MAX_ALG_LIST_SIZE 64 +#define TIMER_PRESCALE 100000 +#define PRIMARY_SEED_SIZE 32 +#define CONTEXT_ENCRYPT_ALG TPM_ALG_AES +#define CONTEXT_ENCRYPT_KEY_BITS MAX_SYM_KEY_BITS // 128 +#define CONTEXT_ENCRYPT_KEY_BYTES ((CONTEXT_ENCRYPT_KEY_BITS+7)/8) +#define CONTEXT_INTEGRITY_HASH_ALG TPM_ALG_SHA256 +#define CONTEXT_INTEGRITY_HASH_SIZE SHA256_DIGEST_SIZE // 32 +#define PROOF_SIZE CONTEXT_INTEGRITY_HASH_SIZE // 32 +#define NV_CLOCK_UPDATE_INTERVAL 12 +#define NUM_POLICY_PCR 1 +#define MAX_COMMAND_SIZE 4096 +#define MAX_RESPONSE_SIZE 4096 +#define ORDERLY_BITS 8 +#define MAX_ORDERLY_COUNT ((1 << ORDERLY_BITS) - 1) // 255 +#define ALG_ID_FIRST TPM_ALG_FIRST +#define ALG_ID_LAST TPM_ALG_LAST +#define MAX_SYM_DATA 128 +#define MAX_HASH_STATE_SIZE 512 +#define MAX_RNG_ENTROPY_SIZE 64 +#define RAM_INDEX_SPACE 512 +#define RSA_DEFAULT_PUBLIC_EXPONENT 0x00010001 +#define ENABLE_PCR_NO_INCREMENT YES // 1 + +// Table 11 -- TPM_CC Constants +typedef uint32_t TPM_CC; + +#define TPM_CC_FIRST (TPM_CC)(0x0000011F) +#define TPM_CC_PP_FIRST (TPM_CC)(0x0000011F) +#define TPM_CC_NV_UndefineSpaceSpecial (TPM_CC)(0x0000011F) +#define TPM_CC_EvictControl (TPM_CC)(0x00000120) +#define TPM_CC_HierarchyControl (TPM_CC)(0x00000121) +#define TPM_CC_NV_UndefineSpace (TPM_CC)(0x00000122) +#define TPM_CC_ChangeEPS (TPM_CC)(0x00000124) +#define TPM_CC_ChangePPS (TPM_CC)(0x00000125) +#define TPM_CC_Clear (TPM_CC)(0x00000126) +#define TPM_CC_ClearControl (TPM_CC)(0x00000127) +#define TPM_CC_ClockSet (TPM_CC)(0x00000128) +#define TPM_CC_HierarchyChangeAuth (TPM_CC)(0x00000129) +#define TPM_CC_NV_DefineSpace (TPM_CC)(0x0000012A) +#define TPM_CC_PCR_Allocate (TPM_CC)(0x0000012B) +#define TPM_CC_PCR_SetAuthPolicy (TPM_CC)(0x0000012C) +#define TPM_CC_PP_Commands (TPM_CC)(0x0000012D) +#define TPM_CC_SetPrimaryPolicy (TPM_CC)(0x0000012E) +#define TPM_CC_FieldUpgradeStart (TPM_CC)(0x0000012F) +#define TPM_CC_ClockRateAdjust (TPM_CC)(0x00000130) +#define TPM_CC_CreatePrimary (TPM_CC)(0x00000131) +#define TPM_CC_NV_GlobalWriteLock (TPM_CC)(0x00000132) +#define TPM_CC_PP_LAST (TPM_CC)(0x00000132) +#define TPM_CC_GetCommandAuditDigest (TPM_CC)(0x00000133) +#define TPM_CC_NV_Increment (TPM_CC)(0x00000134) +#define TPM_CC_NV_SetBits (TPM_CC)(0x00000135) +#define TPM_CC_NV_Extend (TPM_CC)(0x00000136) +#define TPM_CC_NV_Write (TPM_CC)(0x00000137) +#define TPM_CC_NV_WriteLock (TPM_CC)(0x00000138) +#define TPM_CC_DictionaryAttackLockReset (TPM_CC)(0x00000139) +#define TPM_CC_DictionaryAttackParameters (TPM_CC)(0x0000013A) +#define TPM_CC_NV_ChangeAuth (TPM_CC)(0x0000013B) +#define TPM_CC_PCR_Event (TPM_CC)(0x0000013C) +#define TPM_CC_PCR_Reset (TPM_CC)(0x0000013D) +#define TPM_CC_SequenceComplete (TPM_CC)(0x0000013E) +#define TPM_CC_SetAlgorithmSet (TPM_CC)(0x0000013F) +#define TPM_CC_SetCommandCodeAuditStatus (TPM_CC)(0x00000140) +#define TPM_CC_FieldUpgradeData (TPM_CC)(0x00000141) +#define TPM_CC_IncrementalSelfTest (TPM_CC)(0x00000142) +#define TPM_CC_SelfTest (TPM_CC)(0x00000143) +#define TPM_CC_Startup (TPM_CC)(0x00000144) +#define TPM_CC_Shutdown (TPM_CC)(0x00000145) +#define TPM_CC_StirRandom (TPM_CC)(0x00000146) +#define TPM_CC_ActivateCredential (TPM_CC)(0x00000147) +#define TPM_CC_Certify (TPM_CC)(0x00000148) +#define TPM_CC_PolicyNV (TPM_CC)(0x00000149) +#define TPM_CC_CertifyCreation (TPM_CC)(0x0000014A) +#define TPM_CC_Duplicate (TPM_CC)(0x0000014B) +#define TPM_CC_GetTime (TPM_CC)(0x0000014C) +#define TPM_CC_GetSessionAuditDigest (TPM_CC)(0x0000014D) +#define TPM_CC_NV_Read (TPM_CC)(0x0000014E) +#define TPM_CC_NV_ReadLock (TPM_CC)(0x0000014F) +#define TPM_CC_ObjectChangeAuth (TPM_CC)(0x00000150) +#define TPM_CC_PolicySecret (TPM_CC)(0x00000151) +#define TPM_CC_Rewrap (TPM_CC)(0x00000152) +#define TPM_CC_Create (TPM_CC)(0x00000153) +#define TPM_CC_ECDH_ZGen (TPM_CC)(0x00000154) +#define TPM_CC_HMAC (TPM_CC)(0x00000155) +#define TPM_CC_Import (TPM_CC)(0x00000156) +#define TPM_CC_Load (TPM_CC)(0x00000157) +#define TPM_CC_Quote (TPM_CC)(0x00000158) +#define TPM_CC_RSA_Decrypt (TPM_CC)(0x00000159) +#define TPM_CC_HMAC_Start (TPM_CC)(0x0000015B) +#define TPM_CC_SequenceUpdate (TPM_CC)(0x0000015C) +#define TPM_CC_Sign (TPM_CC)(0x0000015D) +#define TPM_CC_Unseal (TPM_CC)(0x0000015E) +#define TPM_CC_PolicySigned (TPM_CC)(0x00000160) +#define TPM_CC_ContextLoad (TPM_CC)(0x00000161) +#define TPM_CC_ContextSave (TPM_CC)(0x00000162) +#define TPM_CC_ECDH_KeyGen (TPM_CC)(0x00000163) +#define TPM_CC_EncryptDecrypt (TPM_CC)(0x00000164) +#define TPM_CC_FlushContext (TPM_CC)(0x00000165) +#define TPM_CC_LoadExternal (TPM_CC)(0x00000167) +#define TPM_CC_MakeCredential (TPM_CC)(0x00000168) +#define TPM_CC_NV_ReadPublic (TPM_CC)(0x00000169) +#define TPM_CC_PolicyAuthorize (TPM_CC)(0x0000016A) +#define TPM_CC_PolicyAuthValue (TPM_CC)(0x0000016B) +#define TPM_CC_PolicyCommandCode (TPM_CC)(0x0000016C) +#define TPM_CC_PolicyCounterTimer (TPM_CC)(0x0000016D) +#define TPM_CC_PolicyCpHash (TPM_CC)(0x0000016E) +#define TPM_CC_PolicyLocality (TPM_CC)(0x0000016F) +#define TPM_CC_PolicyNameHash (TPM_CC)(0x00000170) +#define TPM_CC_PolicyOR (TPM_CC)(0x00000171) +#define TPM_CC_PolicyTicket (TPM_CC)(0x00000172) +#define TPM_CC_ReadPublic (TPM_CC)(0x00000173) +#define TPM_CC_RSA_Encrypt (TPM_CC)(0x00000174) +#define TPM_CC_StartAuthSession (TPM_CC)(0x00000176) +#define TPM_CC_VerifySignature (TPM_CC)(0x00000177) +#define TPM_CC_ECC_Parameters (TPM_CC)(0x00000178) +#define TPM_CC_FirmwareRead (TPM_CC)(0x00000179) +#define TPM_CC_GetCapability (TPM_CC)(0x0000017A) +#define TPM_CC_GetRandom (TPM_CC)(0x0000017B) +#define TPM_CC_GetTestResult (TPM_CC)(0x0000017C) +#define TPM_CC_Hash (TPM_CC)(0x0000017D) +#define TPM_CC_PCR_Read (TPM_CC)(0x0000017E) +#define TPM_CC_PolicyPCR (TPM_CC)(0x0000017F) +#define TPM_CC_PolicyRestart (TPM_CC)(0x00000180) +#define TPM_CC_ReadClock (TPM_CC)(0x00000181) +#define TPM_CC_PCR_Extend (TPM_CC)(0x00000182) +#define TPM_CC_PCR_SetAuthValue (TPM_CC)(0x00000183) +#define TPM_CC_NV_Certify (TPM_CC)(0x00000184) +#define TPM_CC_EventSequenceComplete (TPM_CC)(0x00000185) +#define TPM_CC_HashSequenceStart (TPM_CC)(0x00000186) +#define TPM_CC_PolicyPhysicalPresence (TPM_CC)(0x00000187) +#define TPM_CC_PolicyDuplicationSelect (TPM_CC)(0x00000188) +#define TPM_CC_PolicyGetDigest (TPM_CC)(0x00000189) +#define TPM_CC_TestParms (TPM_CC)(0x0000018A) +#define TPM_CC_Commit (TPM_CC)(0x0000018B) +#define TPM_CC_PolicyPassword (TPM_CC)(0x0000018C) +#define TPM_CC_SM2_ZGen (TPM_CC)(0x0000018D) +#define TPM_CC_LAST (TPM_CC)(0x0000018D) + +// Table 15 -- TPM_RC Constants +typedef uint32_t TPM_RCS; // The 'safe' error codes +typedef uint32_t TPM_RC; + +#define TPM_RC_SUCCESS (TPM_RC)(0x000) +#define TPM_RC_BAD_TAG (TPM_RC)(0x030) +#define RC_VER1 (TPM_RC)(0x100) +#define TPM_RC_INITIALIZE (TPM_RC)(RC_VER1 + 0x000) +#define TPM_RC_FAILURE (TPM_RC)(RC_VER1 + 0x001) +#define TPM_RC_SEQUENCE (TPM_RC)(RC_VER1 + 0x003) +#define TPM_RC_PRIVATE (TPM_RC)(RC_VER1 + 0x00B) +#define TPM_RC_HMAC (TPM_RC)(RC_VER1 + 0x019) +#define TPM_RC_DISABLED (TPM_RC)(RC_VER1 + 0x020) +#define TPM_RC_EXCLUSIVE (TPM_RC)(RC_VER1 + 0x021) +#define TPM_RC_AUTH_TYPE (TPM_RC)(RC_VER1 + 0x024) +#define TPM_RC_AUTH_MISSING (TPM_RC)(RC_VER1 + 0x025) +#define TPM_RC_POLICY (TPM_RC)(RC_VER1 + 0x026) +#define TPM_RC_PCR (TPM_RC)(RC_VER1 + 0x027) +#define TPM_RC_PCR_CHANGED (TPM_RC)(RC_VER1 + 0x028) +#define TPM_RC_UPGRADE (TPM_RC)(RC_VER1 + 0x02D) +#define TPM_RC_TOO_MANY_CONTEXTS (TPM_RC)(RC_VER1 + 0x02E) +#define TPM_RC_AUTH_UNAVAILABLE (TPM_RC)(RC_VER1 + 0x02F) +#define TPM_RC_REBOOT (TPM_RC)(RC_VER1 + 0x030) +#define TPM_RC_UNBALANCED (TPM_RC)(RC_VER1 + 0x031) +#define TPM_RC_COMMAND_SIZE (TPM_RC)(RC_VER1 + 0x042) +#define TPM_RC_COMMAND_CODE (TPM_RC)(RC_VER1 + 0x043) +#define TPM_RC_AUTHSIZE (TPM_RC)(RC_VER1 + 0x044) +#define TPM_RC_AUTH_CONTEXT (TPM_RC)(RC_VER1 + 0x045) +#define TPM_RC_NV_RANGE (TPM_RC)(RC_VER1 + 0x046) +#define TPM_RC_NV_SIZE (TPM_RC)(RC_VER1 + 0x047) +#define TPM_RC_NV_LOCKED (TPM_RC)(RC_VER1 + 0x048) +#define TPM_RC_NV_AUTHORIZATION (TPM_RC)(RC_VER1 + 0x049) +#define TPM_RC_NV_UNINITIALIZED (TPM_RC)(RC_VER1 + 0x04A) +#define TPM_RC_NV_SPACE (TPM_RC)(RC_VER1 + 0x04B) +#define TPM_RC_NV_DEFINED (TPM_RC)(RC_VER1 + 0x04C) +#define TPM_RC_BAD_CONTEXT (TPM_RC)(RC_VER1 + 0x050) +#define TPM_RC_CPHASH (TPM_RC)(RC_VER1 + 0x051) +#define TPM_RC_PARENT (TPM_RC)(RC_VER1 + 0x052) +#define TPM_RC_NEEDS_TEST (TPM_RC)(RC_VER1 + 0x053) +#define TPM_RC_NO_RESULT (TPM_RC)(RC_VER1 + 0x054) +#define TPM_RC_SENSITIVE (TPM_RC)(RC_VER1 + 0x055) +#define RC_MAX_FM0 (TPM_RC)(RC_VER1 + 0x07F) +#define RC_FMT1 (TPM_RC)(0x080) +#define TPM_RC_ASYMMETRIC (TPM_RC)(RC_FMT1 + 0x001) +#define TPM_RCS_ASYMMETRIC (TPM_RCS)(RC_FMT1 + 0x001) +#define TPM_RC_ATTRIBUTES (TPM_RC)(RC_FMT1 + 0x002) +#define TPM_RCS_ATTRIBUTES (TPM_RCS)(RC_FMT1 + 0x002) +#define TPM_RC_HASH (TPM_RC)(RC_FMT1 + 0x003) +#define TPM_RCS_HASH (TPM_RCS)(RC_FMT1 + 0x003) +#define TPM_RC_VALUE (TPM_RC)(RC_FMT1 + 0x004) +#define TPM_RCS_VALUE (TPM_RCS)(RC_FMT1 + 0x004) +#define TPM_RC_HIERARCHY (TPM_RC)(RC_FMT1 + 0x005) +#define TPM_RCS_HIERARCHY (TPM_RCS)(RC_FMT1 + 0x005) +#define TPM_RC_KEY_SIZE (TPM_RC)(RC_FMT1 + 0x007) +#define TPM_RCS_KEY_SIZE (TPM_RCS)(RC_FMT1 + 0x007) +#define TPM_RC_MGF (TPM_RC)(RC_FMT1 + 0x008) +#define TPM_RCS_MGF (TPM_RCS)(RC_FMT1 + 0x008) +#define TPM_RC_MODE (TPM_RC)(RC_FMT1 + 0x009) +#define TPM_RCS_MODE (TPM_RCS)(RC_FMT1 + 0x009) +#define TPM_RC_TYPE (TPM_RC)(RC_FMT1 + 0x00A) +#define TPM_RCS_TYPE (TPM_RCS)(RC_FMT1 + 0x00A) +#define TPM_RC_HANDLE (TPM_RC)(RC_FMT1 + 0x00B) +#define TPM_RCS_HANDLE (TPM_RCS)(RC_FMT1 + 0x00B) +#define TPM_RC_KDF (TPM_RC)(RC_FMT1 + 0x00C) +#define TPM_RCS_KDF (TPM_RCS)(RC_FMT1 + 0x00C) +#define TPM_RC_RANGE (TPM_RC)(RC_FMT1 + 0x00D) +#define TPM_RCS_RANGE (TPM_RCS)(RC_FMT1 + 0x00D) +#define TPM_RC_AUTH_FAIL (TPM_RC)(RC_FMT1 + 0x00E) +#define TPM_RCS_AUTH_FAIL (TPM_RCS)(RC_FMT1 + 0x00E) +#define TPM_RC_NONCE (TPM_RC)(RC_FMT1 + 0x00F) +#define TPM_RCS_NONCE (TPM_RCS)(RC_FMT1 + 0x00F) +#define TPM_RC_PP (TPM_RC)(RC_FMT1 + 0x010) +#define TPM_RCS_PP (TPM_RCS)(RC_FMT1 + 0x010) +#define TPM_RC_SCHEME (TPM_RC)(RC_FMT1 + 0x012) +#define TPM_RCS_SCHEME (TPM_RCS)(RC_FMT1 + 0x012) +#define TPM_RC_SIZE (TPM_RC)(RC_FMT1 + 0x015) +#define TPM_RCS_SIZE (TPM_RCS)(RC_FMT1 + 0x015) +#define TPM_RC_SYMMETRIC (TPM_RC)(RC_FMT1 + 0x016) +#define TPM_RCS_SYMMETRIC (TPM_RCS)(RC_FMT1 + 0x016) +#define TPM_RC_TAG (TPM_RC)(RC_FMT1 + 0x017) +#define TPM_RCS_TAG (TPM_RCS)(RC_FMT1 + 0x017) +#define TPM_RC_SELECTOR (TPM_RC)(RC_FMT1 + 0x018) +#define TPM_RCS_SELECTOR (TPM_RCS)(RC_FMT1 + 0x018) +#define TPM_RC_INSUFFICIENT (TPM_RC)(RC_FMT1 + 0x01A) +#define TPM_RCS_INSUFFICIENT (TPM_RCS)(RC_FMT1 + 0x01A) +#define TPM_RC_SIGNATURE (TPM_RC)(RC_FMT1 + 0x01B) +#define TPM_RCS_SIGNATURE (TPM_RCS)(RC_FMT1 + 0x01B) +#define TPM_RC_KEY (TPM_RC)(RC_FMT1 + 0x01C) +#define TPM_RCS_KEY (TPM_RCS)(RC_FMT1 + 0x01C) +#define TPM_RC_POLICY_FAIL (TPM_RC)(RC_FMT1 + 0x01D) +#define TPM_RCS_POLICY_FAIL (TPM_RCS)(RC_FMT1 + 0x01D) +#define TPM_RC_INTEGRITY (TPM_RC)(RC_FMT1 + 0x01F) +#define TPM_RCS_INTEGRITY (TPM_RCS)(RC_FMT1 + 0x01F) +#define TPM_RC_TICKET (TPM_RC)(RC_FMT1 + 0x020) +#define TPM_RCS_TICKET (TPM_RCS)(RC_FMT1 + 0x020) +#define TPM_RC_RESERVED_BITS (TPM_RC)(RC_FMT1 + 0x021) +#define TPM_RCS_RESERVED_BITS (TPM_RCS)(RC_FMT1 + 0x021) +#define TPM_RC_BAD_AUTH (TPM_RC)(RC_FMT1 + 0x022) +#define TPM_RCS_BAD_AUTH (TPM_RCS)(RC_FMT1 + 0x022) +#define TPM_RC_EXPIRED (TPM_RC)(RC_FMT1 + 0x023) +#define TPM_RCS_EXPIRED (TPM_RCS)(RC_FMT1 + 0x023) +#define TPM_RC_POLICY_CC (TPM_RC)(RC_FMT1 + 0x024 ) +#define TPM_RCS_POLICY_CC (TPM_RCS)(RC_FMT1 + 0x024 ) +#define TPM_RC_BINDING (TPM_RC)(RC_FMT1 + 0x025) +#define TPM_RCS_BINDING (TPM_RCS)(RC_FMT1 + 0x025) +#define TPM_RC_CURVE (TPM_RC)(RC_FMT1 + 0x026) +#define TPM_RCS_CURVE (TPM_RCS)(RC_FMT1 + 0x026) +#define TPM_RC_ECC_POINT (TPM_RC)(RC_FMT1 + 0x027) +#define TPM_RCS_ECC_POINT (TPM_RCS)(RC_FMT1 + 0x027) +#define RC_WARN (TPM_RC)(0x900) +#define TPM_RC_CONTEXT_GAP (TPM_RC)(RC_WARN + 0x001) +#define TPM_RC_OBJECT_MEMORY (TPM_RC)(RC_WARN + 0x002) +#define TPM_RC_SESSION_MEMORY (TPM_RC)(RC_WARN + 0x003) +#define TPM_RC_MEMORY (TPM_RC)(RC_WARN + 0x004) +#define TPM_RC_SESSION_HANDLES (TPM_RC)(RC_WARN + 0x005) +#define TPM_RC_OBJECT_HANDLES (TPM_RC)(RC_WARN + 0x006) +#define TPM_RC_LOCALITY (TPM_RC)(RC_WARN + 0x007) +#define TPM_RC_YIELDED (TPM_RC)(RC_WARN + 0x008) +#define TPM_RC_CANCELLED (TPM_RC)(RC_WARN + 0x009) +#define TPM_RC_TESTING (TPM_RC)(RC_WARN + 0x00A) +#define TPM_RC_REFERENCE_H0 (TPM_RC)(RC_WARN + 0x010) +#define TPM_RC_REFERENCE_H1 (TPM_RC)(RC_WARN + 0x011) +#define TPM_RC_REFERENCE_H2 (TPM_RC)(RC_WARN + 0x012) +#define TPM_RC_REFERENCE_H3 (TPM_RC)(RC_WARN + 0x013) +#define TPM_RC_REFERENCE_H4 (TPM_RC)(RC_WARN + 0x014) +#define TPM_RC_REFERENCE_H5 (TPM_RC)(RC_WARN + 0x015) +#define TPM_RC_REFERENCE_H6 (TPM_RC)(RC_WARN + 0x016) +#define TPM_RC_REFERENCE_S0 (TPM_RC)(RC_WARN + 0x018) +#define TPM_RC_REFERENCE_S1 (TPM_RC)(RC_WARN + 0x019) +#define TPM_RC_REFERENCE_S2 (TPM_RC)(RC_WARN + 0x01A) +#define TPM_RC_REFERENCE_S3 (TPM_RC)(RC_WARN + 0x01B) +#define TPM_RC_REFERENCE_S4 (TPM_RC)(RC_WARN + 0x01C) +#define TPM_RC_REFERENCE_S5 (TPM_RC)(RC_WARN + 0x01D) +#define TPM_RC_REFERENCE_S6 (TPM_RC)(RC_WARN + 0x01E) +#define TPM_RC_NV_RATE (TPM_RC)(RC_WARN + 0x020) +#define TPM_RC_LOCKOUT (TPM_RC)(RC_WARN + 0x021) +#define TPM_RC_RETRY (TPM_RC)(RC_WARN + 0x022) +#define TPM_RC_NV_UNAVAILABLE (TPM_RC)(RC_WARN + 0x023) +#define TPM_RC_NOT_USED (TPM_RC)(RC_WARN + 0x7F) +#define TPM_RC_H (TPM_RC)(0x000) +#define TPM_RC_P (TPM_RC)(0x040) +#define TPM_RC_S (TPM_RC)(0x800) +#define TPM_RC_1 (TPM_RC)(0x100) +#define TPM_RC_2 (TPM_RC)(0x200) +#define TPM_RC_3 (TPM_RC)(0x300) +#define TPM_RC_4 (TPM_RC)(0x400) +#define TPM_RC_5 (TPM_RC)(0x500) +#define TPM_RC_6 (TPM_RC)(0x600) +#define TPM_RC_7 (TPM_RC)(0x700) +#define TPM_RC_8 (TPM_RC)(0x800) +#define TPM_RC_9 (TPM_RC)(0x900) +#define TPM_RC_A (TPM_RC)(0xA00) +#define TPM_RC_B (TPM_RC)(0xB00) +#define TPM_RC_C (TPM_RC)(0xC00) +#define TPM_RC_D (TPM_RC)(0xD00) +#define TPM_RC_E (TPM_RC)(0xE00) +#define TPM_RC_F (TPM_RC)(0xF00) +#define TPM_RC_N_MASK (TPM_RC)(0xF00) + +// Table 18 -- TPM_ST Constants +typedef uint16_t TPM_ST; + +#define TPM_ST_RSP_COMMAND (TPM_ST)(0x00C4) +#define TPM_ST_NULL (TPM_ST)(0X8000) +#define TPM_ST_NO_SESSIONS (TPM_ST)(0x8001) +#define TPM_ST_SESSIONS (TPM_ST)(0x8002) +#define TPM_ST_ATTEST_NV (TPM_ST)(0x8014) +#define TPM_ST_ATTEST_COMMAND_AUDIT (TPM_ST)(0x8015) +#define TPM_ST_ATTEST_SESSION_AUDIT (TPM_ST)(0x8016) +#define TPM_ST_ATTEST_CERTIFY (TPM_ST)(0x8017) +#define TPM_ST_ATTEST_QUOTE (TPM_ST)(0x8018) +#define TPM_ST_ATTEST_TIME (TPM_ST)(0x8019) +#define TPM_ST_ATTEST_CREATION (TPM_ST)(0x801A) +#define TPM_ST_CREATION (TPM_ST)(0x8021) +#define TPM_ST_VERIFIED (TPM_ST)(0x8022) +#define TPM_ST_AUTH_SECRET (TPM_ST)(0x8023) +#define TPM_ST_HASHCHECK (TPM_ST)(0x8024) +#define TPM_ST_AUTH_SIGNED (TPM_ST)(0x8025) +#define TPM_ST_FU_MANIFEST (TPM_ST)(0x8029) + +// Table 19 -- TPM_SU Constants +typedef uint16_t TPM_SU; + +#define TPM_SU_CLEAR (TPM_SU)(0x0000) +#define TPM_SU_STATE (TPM_SU)(0x0001) + +// Table 21 -- TPM_CAP Constants +typedef uint32_t TPM_CAP; + +#define TPM_CAP_FIRST (TPM_CAP)(0x00000000) +#define TPM_CAP_ALGS (TPM_CAP)(0x00000000) +#define TPM_CAP_HANDLES (TPM_CAP)(0x00000001) +#define TPM_CAP_COMMANDS (TPM_CAP)(0x00000002) +#define TPM_CAP_PP_COMMANDS (TPM_CAP)(0x00000003) +#define TPM_CAP_AUDIT_COMMANDS (TPM_CAP)(0x00000004) +#define TPM_CAP_PCRS (TPM_CAP)(0x00000005) +#define TPM_CAP_TPM_PROPERTIES (TPM_CAP)(0x00000006) +#define TPM_CAP_PCR_PROPERTIES (TPM_CAP)(0x00000007) +#define TPM_CAP_ECC_CURVES (TPM_CAP)(0x00000008) +#define TPM_CAP_LAST (TPM_CAP)(0x00000008) +#define TPM_CAP_VENDOR_PROPERTY (TPM_CAP)(0x00000100) + +// Table 25 -- Handles Types +typedef uint32_t TPM_HANDLE; +typedef uint8_t TPM_HT; + +#define TPM_HT_PCR (TPM_HT)(0x00) +#define TPM_HT_NV_INDEX (TPM_HT)(0x01) +#define TPM_HT_HMAC_SESSION (TPM_HT)(0x02) +#define TPM_HT_LOADED_SESSION (TPM_HT)(0x02) +#define TPM_HT_POLICY_SESSION (TPM_HT)(0x03) +#define TPM_HT_ACTIVE_SESSION (TPM_HT)(0x03) +#define TPM_HT_PERMANENT (TPM_HT)(0x40) +#define TPM_HT_TRANSIENT (TPM_HT)(0x80) +#define TPM_HT_PERSISTENT (TPM_HT)(0x81) + +// Table 27 -- TPM_RH Constants +typedef uint32_t TPM_RH; + +#define TPM_RH_FIRST (TPM_RH)(0x40000000) +#define TPM_RH_SRK (TPM_RH)(0x40000000) +#define TPM_RH_OWNER (TPM_RH)(0x40000001) +#define TPM_RH_REVOKE (TPM_RH)(0x40000002) +#define TPM_RH_TRANSPORT (TPM_RH)(0x40000003) +#define TPM_RH_OPERATOR (TPM_RH)(0x40000004) +#define TPM_RH_ADMIN (TPM_RH)(0x40000005) +#define TPM_RH_EK (TPM_RH)(0x40000006) +#define TPM_RH_NULL (TPM_RH)(0x40000007) +#define TPM_RH_UNASSIGNED (TPM_RH)(0x40000008) +#define TPM_RS_PW (TPM_RH)(0x40000009) +#define TPM_RH_LOCKOUT (TPM_RH)(0x4000000A) +#define TPM_RH_ENDORSEMENT (TPM_RH)(0x4000000B) +#define TPM_RH_PLATFORM (TPM_RH)(0x4000000C) +#define TPM_RH_LAST (TPM_RH)(0x4000000C) + +#define RC_ContextSave_saveHandle (TPM_RC_P + TPM_RC_1) +#define RC_ContextLoad_context (TPM_RC_P + TPM_RC_1) +#define RC_FlushContext_flushHandle (TPM_RC_P + TPM_RC_1) + + +// Table 29 -- TPMA_ALGORITHM Bits +typedef struct { + unsigned int asymmetric : 1; + unsigned int symmetric : 1; + unsigned int hash : 1; + unsigned int object : 1; + unsigned int reserved5 : 4; + unsigned int signing : 1; + unsigned int encrypting : 1; + unsigned int method : 1; + unsigned int reserved9 : 21; +} TPMA_ALGORITHM ; + +// Table 30 -- TPMA_OBJECT Bits +typedef struct { + unsigned int reserved1 : 1; + unsigned int fixedTPM : 1; + unsigned int stClear : 1; + unsigned int reserved4 : 1; + unsigned int fixedParent : 1; + unsigned int sensitiveDataOrigin : 1; + unsigned int userWithAuth : 1; + unsigned int adminWithPolicy : 1; + unsigned int reserved9 : 2; + unsigned int noDA : 1; + unsigned int encryptedDuplication : 1; + unsigned int reserved12 : 4; + unsigned int restricted : 1; // Start of 2nd dword + unsigned int decrypt : 1; + unsigned int sign : 1; + unsigned int reserved16 : 13; +} TPMA_OBJECT ; + +// Table 31 -- TPMA_SESSION Bits +typedef struct { + unsigned int continueSession : 1; + unsigned int auditExclusive : 1; + unsigned int auditReset : 1; + unsigned int reserved4 : 2; + unsigned int decrypt : 1; + unsigned int encrypt : 1; + unsigned int audit : 1; +} TPMA_SESSION; + +// Table 32 -- TPMA_LOCALITY Bits +typedef struct { + unsigned int TPM_LOC_ZERO : 1; + unsigned int TPM_LOC_ONE : 1; + unsigned int TPM_LOC_TWO : 1; + unsigned int TPM_LOC_THREE : 1; + unsigned int TPM_LOC_FOUR : 1; + unsigned int reserved6 : 3; +} TPMA_LOCALITY; +// Table 47 Definition of TPMI_DH_CONTEXT Type +typedef TPM_HANDLE TPMI_DH_CONTEXT; +// Table 48 Definition of TPMI_RH_HIERARCHY Type +typedef TPM_HANDLE TPMI_RH_HIERARCHY; + +// Table 66 -- TPMU_HA Union +typedef union { +#ifdef TPM_ALG_SHA1 + uint8_t sha1[SHA1_DIGEST_SIZE]; +#endif +#ifdef TPM_ALG_SHA256 + uint8_t sha256[SHA256_DIGEST_SIZE]; +#endif +#ifdef TPM_ALG_SM3_256 + uint8_t sm3_256[SM3_256_DIGEST_SIZE]; +#endif +#ifdef TPM_ALG_SHA384 + uint8_t sha384[SHA384_DIGEST_SIZE]; +#endif +#ifdef TPM_ALG_SHA512 + uint8_t sha512[SHA512_DIGEST_SIZE]; +#endif +} TPMU_HA ; + +// Table 67 -- TPMT_HA Structure +typedef struct { + uint16_t hash_alg; + TPMU_HA digest; +} TPMT_HA; + +// Table 68 -- TPM2B_DIGEST Structure +typedef struct { + uint16_t size; + uint8_t buffer[sizeof(TPMU_HA)]; +} DIGEST_2B; + +typedef union { + DIGEST_2B t; + TPM2B b; +} TPM2B_DIGEST; + +// Table 69 -- TPM2B_DATA Structure +typedef struct { + uint16_t size; + uint8_t buffer[sizeof(TPMT_HA)]; +} DATA_2B; + +typedef union { + DATA_2B t; + TPM2B b; +} TPM2B_DATA; + +// Table 70 -- TPM2B_NONCE Types +typedef TPM2B_DIGEST TPM2B_NONCE; + +// Table 71 -- TPM2B_AUTH Types +typedef TPM2B_DIGEST TPM2B_AUTH; + +// Table 73 -- TPM2B_EVENT Structure +typedef struct { + uint16_t size; + uint8_t buffer[1024]; +} EVENT_2B; + +typedef union { + EVENT_2B t; + TPM2B b; +} TPM2B_EVENT; + +// Table 74 -- TPM2B_MAX_BUFFER Structure +typedef struct { + uint16_t size; + uint8_t buffer[MAX_DIGEST_BUFFER]; +} MAX_BUFFER_2B; + +typedef union { + MAX_BUFFER_2B t; + TPM2B b; +} TPM2B_MAX_BUFFER; + +// Table 75 -- TPM2B_MAX_NV_BUFFER Structure +typedef struct { + uint16_t size; + uint8_t buffer[MAX_NV_INDEX_SIZE]; +} MAX_NV_BUFFER_2B; + +typedef union { + MAX_NV_BUFFER_2B t; + TPM2B b; +} TPM2B_MAX_NV_BUFFER; + +// Table 79 -- TPMU_NAME Structure +typedef union { + TPMT_HA digest; + uint32_t handle; +} TPMU_NAME ; + +// Table 79 -- TPM2B_NAME Structure +typedef struct { + uint16_t size; + uint8_t name[sizeof(TPMU_NAME)]; +} NAME_2B; + +typedef union { + NAME_2B t; + TPM2B b; +} TPM2B_NAME; + +// Table 80 -- TPMS_PCR_SELECTION Structure +typedef struct { + uint16_t hash; + uint8_t size_of_select; + uint8_t pcr_select[PCR_SELECT_MAX]; +} TPMS_PCR_SELECTION; + +// Table 84 -- TPMT_TK_CREATION Structure +typedef struct { + uint16_t tag; + uint32_t hierarchy; + TPM2B_DIGEST digest; +} TPMT_TK_CREATION; + +// Table 86 -- TPMT_TK_HASHCHECK Structure +typedef struct { + uint16_t tag; + uint32_t hierarchy; + TPM2B_DIGEST digest; +} TPMT_TK_HASHCHECK; + +// Table 88 -- TPMS_ALG_PROPERTY Structure +typedef struct { + uint16_t alg; + TPMA_ALGORITHM alg_pro; +} TPMS_ALG_PROPERTY; + +// Table 95 -- TPML_DIGEST Structure +typedef struct { + uint32_t count; + TPM2B_DIGEST digests[8]; +} TPML_DIGEST; + +// Table 96 -- TPML_DIGEST_VALUES Structure +typedef struct { + uint32_t count; + TPMT_HA digests[HASH_COUNT]; +} TPML_DIGEST_VALUES; + +// Table 98 -- TPML_PCR_SELECTION Structure +typedef struct { + uint32_t count; + TPMS_PCR_SELECTION selections[HASH_COUNT]; +} TPML_PCR_SELECTION; + +#define MAX_CAP_DATA (MAX_CAP_BUFFER-sizeof(uint32_t)-sizeof(uint32_t)) +#define MAX_CAP_ALGS (MAX_CAP_DATA/sizeof(TPMS_ALG_PROPERTY)) +// Table 99 -- TPML_ALG_PROPERTY Structure +typedef struct { + uint32_t count; + TPMS_ALG_PROPERTY alg_pros[MAX_CAP_ALGS]; +} TPML_ALG_PROPERTY; + +// Table 103 -- TPMU_CAPABILITIES Union +typedef union { + TPML_ALG_PROPERTY algs; +} TPMU_CAPABILITIES; + +// Table 104 -- TPMS_CAPABILITY_DATA Structure +typedef struct { + uint32_t capability; + TPMU_CAPABILITIES data; +} TPMS_CAPABILITY_DATA; + +// Table 122 -- TPMU_SYM_KEY_BITS Union +typedef union { +#ifdef TPM_ALG_AES + uint16_t aes; +#endif +#ifdef TPM_ALG_SM4 + uint16_t sm4; +#endif + uint16_t sym; +#ifdef TPM_ALG_XOR + uint16_t xor; +#endif +} TPMU_SYM_KEY_BITS ; + +// Table 122 -- TPMU_SYM_MODE Union +typedef union { +#ifdef TPM_ALG_AES + uint16_t aes; +#endif +#ifdef TPM_ALG_SM4 + uint16_t sm4; +#endif + uint16_t sym; +} TPMU_SYM_MODE ; + +// Table 126 -- TPMT_SYM_DEF_OBJECT Structure +typedef struct { + uint16_t alg; + TPMU_SYM_KEY_BITS key_bits; + TPMU_SYM_MODE mode; +} TPMT_SYM_DEF_OBJECT; + +// Table 126 -- TPM2B_SYM_KEY Structure +typedef struct { + uint16_t size; + uint8_t buffer[MAX_SYM_KEY_BYTES]; +} SYM_KEY_2B; + +typedef union { + SYM_KEY_2B t; + TPM2B b; +} TPM2B_SYM_KEY; + +// Table 129 -- TPM2B_SENSITIVE_DATA Structure +typedef struct { + uint16_t size; + uint8_t buffer[MAX_SYM_DATA]; +} SENSITIVE_DATA_2B; + +typedef union { + SENSITIVE_DATA_2B t; + TPM2B b; +} TPM2B_SENSITIVE_DATA; + +// Table 130 -- TPMS_SENSITIVE_CREATE Structure +typedef struct { + TPM2B_AUTH user_auth; + TPM2B_SENSITIVE_DATA data; +} TPMS_SENSITIVE_CREATE; + +// Table 131 -- TPM2B_SENSITIVE_CREATE Structure +typedef struct { + uint16_t size; + TPMS_SENSITIVE_CREATE sensitive; +} SENSITIVE_CREATE_2B; + +typedef union { + SENSITIVE_CREATE_2B t; + TPM2B b; +} TPM2B_SENSITIVE_CREATE; + +// Table 132 -- TPMS_SCHEME_SIGHASH Structure +typedef struct { + uint16_t hash_alg; +} TPMS_SCHEME_SIGHASH; + +// Table 134 -- HMAC_SIG_SCHEME Types +typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_HMAC; + +// Table 135 -- TPMS_SCHEME_XOR Structure +typedef struct { + uint16_t hash_alg; + uint16_t kdf; +} TPMS_SCHEME_XOR; + +// Table 136 -- TPMU_SCHEME_KEYEDHASH Union +typedef union { +#ifdef TPM_ALG_HMAC + TPMS_SCHEME_HMAC hmac; +#endif +#ifdef TPM_ALG_XOR + TPMS_SCHEME_XOR xor; +#endif + +} TPMU_SCHEME_KEYEDHASH; + +// Table 137 -- TPMT_KEYEDHASH_SCHEME Structure +typedef struct { + uint16_t scheme; + TPMU_SCHEME_KEYEDHASH details; +} TPMT_KEYEDHASH_SCHEME; + +// Table 138 -- RSA_SIG_SCHEMES Types +typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_RSASSA; +typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_RSAPSS; + +// Table 139 -- ECC_SIG_SCHEMES Types +typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_ECDSA; +typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_SM2; +typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_ECSCHNORR; + +// Table 140 -- TPMS_SCHEME_ECDAA Structure +typedef struct { + uint16_t hash_alg; + uint16_t count; +} TPMS_SCHEME_ECDAA; + +// Table 141 -- TPMU_SIG_SCHEME Union +typedef union { +#ifdef TPM_ALG_RSASSA + TPMS_SCHEME_RSASSA rsassa; +#endif +#ifdef TPM_ALG_RSAPSS + TPMS_SCHEME_RSAPSS rsapss; +#endif +#ifdef TPM_ALG_ECDSA + TPMS_SCHEME_ECDSA ecdsa; +#endif +#ifdef TPM_ALG_SM2 + TPMS_SCHEME_SM2 sm2; +#endif +#ifdef TPM_ALG_ECDAA + TPMS_SCHEME_ECDAA ecdaa; +#endif +#ifdef TPM_ALG_ECSCHNORR + TPMS_SCHEME_ECSCHNORR ec_schnorr; +#endif +#ifdef TPM_ALG_HMAC + TPMS_SCHEME_HMAC hmac; +#endif + TPMS_SCHEME_SIGHASH any; + +} TPMU_SIG_SCHEME ; + +// Table 143 -- TPMS_SCHEME_OAEP Structure +typedef struct { + uint16_t hash_alg; +} TPMS_SCHEME_OAEP; + +// Table 145 -- TPMS_SCHEME_MGF1 Structure +typedef struct { + uint16_t hash_alg; +} TPMS_SCHEME_MGF1; + +// Table 146 -- TPMS_SCHEME_KDF1_SP800_56a Structure +typedef struct { + uint16_t hash_alg; +} TPMS_SCHEME_KDF1_SP800_56a; + +// Table 147 -- TPMS_SCHEME_KDF2 Structure +typedef struct { + uint16_t hash_alg; +} TPMS_SCHEME_KDF2; + +// Table 148 -- TPMS_SCHEME_KDF1_SP800_108 Structure +typedef struct { + uint16_t hash_alg; +} TPMS_SCHEME_KDF1_SP800_108; + +// Table 149 -- TPMU_KDF_SCHEME Union +typedef union { +#ifdef TPM_ALG_MGF1 + TPMS_SCHEME_MGF1 mgf1; +#endif +#ifdef TPM_ALG_KDF1_SP800_56a + TPMS_SCHEME_KDF1_SP800_56a kdf1_SP800_56a; +#endif +#ifdef TPM_ALG_KDF2 + TPMS_SCHEME_KDF2 kdf2; +#endif +#ifdef TPM_ALG_KDF1_SP800_108 + TPMS_SCHEME_KDF1_SP800_108 kdf1_sp800_108; +#endif +} TPMU_KDF_SCHEME ; + +// Table 150 -- TPMT_KDF_SCHEME Structure +typedef struct { + uint16_t scheme; + TPMU_KDF_SCHEME details; +} TPMT_KDF_SCHEME; + +// Table 152 -- TPMU_ASYM_SCHEME Union +typedef union { +#ifdef TPM_ALG_RSASSA + TPMS_SCHEME_RSASSA rsassa; +#endif +#ifdef TPM_ALG_RSAPSS + TPMS_SCHEME_RSAPSS rsapss; +#endif +#ifdef TPM_ALG_OAEP + TPMS_SCHEME_OAEP oaep; +#endif +#ifdef TPM_ALG_ECDSA + TPMS_SCHEME_ECDSA ecdsa; +#endif +#ifdef TPM_ALG_SM2 + TPMS_SCHEME_SM2 sm2; +#endif +#ifdef TPM_ALG_ECDAA + TPMS_SCHEME_ECDAA ecdaa; +#endif +#ifdef TPM_ALG_ECSCHNORR + TPMS_SCHEME_ECSCHNORR ec_schnorr; +#endif + TPMS_SCHEME_SIGHASH any; + +} TPMU_ASYM_SCHEME; + +// Table 153 -- TPMT_ASYM_SCHEME Structure <> +typedef struct { + uint16_t scheme; + TPMU_ASYM_SCHEME details; +} TPMT_ASYM_SCHEME; + +// Table 155 -- TPMT_RSA_SCHEME Structure +typedef struct { + uint16_t scheme; + TPMU_ASYM_SCHEME details; +} TPMT_RSA_SCHEME; + +// Table 158 -- TPM2B_PUBLIC_KEY_RSA Structure +typedef struct { + uint16_t size; + uint8_t buffer[MAX_RSA_KEY_BYTES]; +} PUBLIC_KEY_RSA_2B; + +typedef union { + PUBLIC_KEY_RSA_2B t; + TPM2B b; +} TPM2B_PUBLIC_KEY_RSA; + +// Table 160 -- TPM2B_PRIVATE_KEY_RSA Structure +typedef struct { + uint16_t size; + uint8_t buffer[MAX_RSA_KEY_BYTES/2]; +} PRIVATE_KEY_RSA_2B; + +typedef union { + PRIVATE_KEY_RSA_2B t; + TPM2B b; +} TPM2B_PRIVATE_KEY_RSA; + +// Table 161 -- TPM2B_ECC_PARAMETER Structure +typedef struct { + uint16_t size; + uint8_t buffer[MAX_ECC_KEY_BYTES]; +} ECC_PARAMETER_2B; + +typedef union { + ECC_PARAMETER_2B t; + TPM2B b; +} TPM2B_ECC_PARAMETER; + +// Table 162 -- TPMS_ECC_POINT Structure +typedef struct { + TPM2B_ECC_PARAMETER x; + TPM2B_ECC_PARAMETER y; +} TPMS_ECC_POINT; + +// Table 166 -- TPMT_ECC_SCHEME Structure +typedef struct { + uint16_t scheme; + TPMU_SIG_SCHEME details; +} TPMT_ECC_SCHEME; + +// Table 176 -- TPMU_PUBLIC_ID Union +typedef union { +#ifdef TPM_ALG_KEYEDHASH + TPM2B_DIGEST keyed_hash; +#endif +#ifdef TPM_ALG_SYMCIPHER + TPM2B_DIGEST sym; +#endif +#ifdef TPM_ALG_RSA + TPM2B_PUBLIC_KEY_RSA rsa; +#endif +#ifdef TPM_ALG_ECC + TPMS_ECC_POINT ecc; +#endif +} TPMU_PUBLIC_ID; + +// Table 177 -- TPMS_KEYEDHASH_PARMS Structure +typedef struct { + TPMT_KEYEDHASH_SCHEME scheme; +} TPMS_KEYEDHASH_PARMS; + +// Table 178 -- TPMS_ASYM_PARMS Structure +typedef struct { + TPMT_SYM_DEF_OBJECT symmetric; + TPMT_ASYM_SCHEME scheme; +} TPMS_ASYM_PARMS; + +// Table 179 -- TPMS_RSA_PARMS Structure +typedef struct { + TPMT_SYM_DEF_OBJECT symmetric; + TPMT_RSA_SCHEME scheme; + uint16_t key_bits; + uint32_t exponent; +} TPMS_RSA_PARMS; + +// Table 180 -- TPMS_ECC_PARMS Structure +typedef struct { + TPMT_SYM_DEF_OBJECT symmetric; + TPMT_ECC_SCHEME scheme; + uint16_t curve_id; + TPMT_KDF_SCHEME kdf; +} TPMS_ECC_PARMS; + +// Table 181 -- TPMU_PUBLIC_PARMS Union +typedef union { +#ifdef TPM_ALG_KEYEDHASH + TPMS_KEYEDHASH_PARMS keyed_hash; +#endif +#ifdef TPM_ALG_SYMCIPHER + TPMT_SYM_DEF_OBJECT sym; +#endif +#ifdef TPM_ALG_RSA + TPMS_RSA_PARMS rsa; +#endif +#ifdef TPM_ALG_ECC + TPMS_ECC_PARMS ecc; +#endif + TPMS_ASYM_PARMS asym; + +} TPMU_PUBLIC_PARMS; + +// Table 184 -- TPMT_PUBLIC Structure +typedef struct { + uint16_t type; + uint16_t name_alg; + TPMA_OBJECT object_attr; + TPM2B_DIGEST auth_policy; + TPMU_PUBLIC_PARMS param; + TPMU_PUBLIC_ID unique; +} TPMT_PUBLIC; + +// Table 185 -- TPM2B_PUBLIC Structure +typedef struct { + uint16_t size; + TPMT_PUBLIC public_area; +} PUBLIC_2B; + +typedef union { + PUBLIC_2B t; + TPM2B b; +} TPM2B_PUBLIC; + +// Table 186 -- TPMU_SENSITIVE_COMPOSITE Union +typedef union { +#ifdef TPM_ALG_RSA + TPM2B_PRIVATE_KEY_RSA rsa; +#endif +#ifdef TPM_ALG_ECC + TPM2B_ECC_PARAMETER ecc; +#endif +#ifdef TPM_ALG_KEYEDHASH + TPM2B_SENSITIVE_DATA bits; +#endif +#ifdef TPM_ALG_SYMCIPHER + TPM2B_SYM_KEY sym; +#endif + TPM2B_SENSITIVE_DATA any; + +} TPMU_SENSITIVE_COMPOSITE ; + +// Table 187 -- TPMT_SENSITIVE Structure +typedef struct { + uint16_t type; + TPM2B_AUTH auth_value; + TPM2B_DIGEST seedValue; + TPMU_SENSITIVE_COMPOSITE sensitive; +} TPMT_SENSITIVE; + +// Table 189 -- _PRIVATE Structure <> +typedef struct { + TPM2B_DIGEST integrity_outer; + TPM2B_DIGEST integrity_inner; + TPMT_SENSITIVE sensitive; +} _PRIVATE; + +// Table 190 -- TPM2B_PRIVATE Structure +typedef struct { + uint16_t size; + uint8_t buffer[sizeof(_PRIVATE)]; +} PRIVATE_2B; + +typedef union { + PRIVATE_2B t; + TPM2B b; +} TPM2B_PRIVATE; + +// Table 195 -- TPMA_NV Bits +typedef struct { + unsigned int TPMA_NV_PPWRITE : 1; + unsigned int TPMA_NV_OWNERWRITE : 1; + unsigned int TPMA_NV_AUTHWRITE : 1; + unsigned int TPMA_NV_POLICYWRITE : 1; + unsigned int TPMA_NV_COUNTER : 1; + unsigned int TPMA_NV_BITS : 1; + unsigned int TPMA_NV_EXTEND : 1; + unsigned int reserved8 : 3; + unsigned int TPMA_NV_POLICY_DELETE : 1; + unsigned int TPMA_NV_WRITELOCKED : 1; + unsigned int TPMA_NV_WRITEALL : 1; + unsigned int TPMA_NV_WRITEDEFINE : 1; + unsigned int TPMA_NV_WRITE_STCLEAR : 1; + unsigned int TPMA_NV_GLOBALLOCK : 1; + unsigned int TPMA_NV_PPREAD : 1; + unsigned int TPMA_NV_OWNERREAD : 1; + unsigned int TPMA_NV_AUTHREAD : 1; + unsigned int TPMA_NV_POLICYREAD : 1; + unsigned int reserved19 : 5; + unsigned int TPMA_NV_NO_DA : 1; + unsigned int TPMA_NV_ORDERLY : 1; + unsigned int TPMA_NV_CLEAR_STCLEAR : 1; + unsigned int TPMA_NV_READLOCKED : 1; + unsigned int TPMA_NV_WRITTEN : 1; + unsigned int TPMA_NV_PLATFORMCREATE : 1; + unsigned int TPMA_NV_READ_STCLEAR : 1; +} TPMA_NV ; + +// Table 196 -- TPMS_NV_PUBLIC Structure +typedef struct { + uint32_t index; + uint16_t name_alg; + TPMA_NV attr; + TPM2B_DIGEST auth_policy; + uint16_t data_size; +} TPMS_NV_PUBLIC; + +// Table 197 -- TPM2B_NV_PUBLIC Structure +typedef struct { + uint16_t size; + TPMS_NV_PUBLIC nv_public; +} NV_PUBLIC_2B; + +typedef union { + NV_PUBLIC_2B t; + TPM2B b; +} TPM2B_NV_PUBLIC; + +// Table 198 Definition of TPM2B_CONTEXT_SENSITIVE Structure < IN/OUT> +typedef union { + struct { + uint16_t size; + uint8_t buffer[MAX_CONTEXT_SIZE]; + } t; + TPM2B b; +} TPM2B_CONTEXT_SENSITIVE; + +// Table 199 Definition of TPMS_CONTEXT_DATA Structure < IN/OUT, S> +typedef struct { + TPM2B_DIGEST integrity; + TPM2B_CONTEXT_SENSITIVE encrypted; +} TPMS_CONTEXT_DATA; + +// Table 200 Definition of TPM2B_CONTEXT_DATA Structure < IN/OUT> +typedef union { + struct { + uint16_t size; + uint8_t buffer[sizeof(TPMS_CONTEXT_DATA)]; + } t; + TPM2B b; +} TPM2B_CONTEXT_DATA; + +// Table 201 Definition of TPMS_CONTEXT Structure +typedef struct { + uint64_t sequence; + TPMI_DH_CONTEXT savedHandle; + TPMI_RH_HIERARCHY hierarchy; + TPM2B_CONTEXT_DATA contextBlob; +} TPMS_CONTEXT; + +// Table 203 -- TPMS_CREATION_DATA Structure +typedef struct { + TPML_PCR_SELECTION pcr_select; + TPM2B_DIGEST pcr_digest; + TPMA_LOCALITY locality; + uint16_t parent_name_alg; + TPM2B_NAME parent_name; + TPM2B_NAME parent_qualified_name; + TPM2B_DATA outside_info; +} TPMS_CREATION_DATA; + +// Table 204 -- TPM2B_CREATION_DATA Structure +typedef struct { + uint16_t size; + TPMS_CREATION_DATA data; +} CREATION_DATA_2B; + +typedef union { + CREATION_DATA_2B t; + TPM2B b; +} TPM2B_CREATION_DATA; + + +#define MAX_SESSIONS 3 + +// Input structure for session data for a single session, +typedef struct { + uint32_t session_handle; + TPM2B_NONCE nonce; + TPMA_SESSION session_attr; + TPM2B_AUTH hmac; +} TPM_CMD_SESSION_DATA_IN ; + +// Input structure for sessions data. +typedef struct { + uint8_t num_sessions; + TPM_CMD_SESSION_DATA_IN sessions[MAX_SESSION_NUM]; +} TPM_CMD_SESSIONS_IN; + +// Output structure for session data for a single session. +typedef struct { + TPM2B_NONCE nonce; + TPMA_SESSION session_attr; + TPM2B_AUTH hmac; +} TPM_CMD_SESSION_DATA_OUT; + +// Output structure for sessions data. +typedef struct { + uint8_t num_sessions; + TPM_CMD_SESSION_DATA_OUT sessions[MAX_SESSION_NUM]; +} TPM_CMD_SESSIONS_OUT; + + +/* + * command parameter related structure + */ + +typedef struct { + TPML_PCR_SELECTION pcr_selection; +} tpm_pcr_read_in; + +typedef struct { + uint32_t pcr_update_counter; + TPML_PCR_SELECTION pcr_selection; + TPML_DIGEST pcr_values; +} tpm_pcr_read_out; + +typedef struct { + uint32_t pcr_handle; + TPM_CMD_SESSIONS_IN sessions; + TPML_DIGEST_VALUES digests; +} tpm_pcr_extend_in; + +typedef struct { + TPM_CMD_SESSIONS_OUT sessions; +} tpm_pcr_extend_out; + +typedef struct { + uint32_t pcr_handle; + TPM_CMD_SESSIONS_IN sessions; + TPM2B_EVENT data; +} tpm_pcr_event_in; + +typedef struct { + TPML_DIGEST_VALUES digests; + TPM_CMD_SESSIONS_OUT sessions; +} tpm_pcr_event_out; + +typedef struct { + uint32_t pcr_handle; + TPM_CMD_SESSIONS_IN sessions; +} tpm_pcr_reset_in; + +typedef struct { + TPM_CMD_SESSIONS_OUT sessions; +} tpm_pcr_reset_out; + +typedef struct { + TPM2B_AUTH auth; + uint16_t hash_alg; +} tpm_sequence_start_in; + +typedef struct { + uint32_t handle; +} tpm_sequence_start_out; + +typedef struct { + uint32_t handle; + TPM_CMD_SESSIONS_IN sessions; + TPM2B_MAX_BUFFER buf; +} tpm_sequence_update_in; + +typedef struct { + TPM_CMD_SESSIONS_OUT sessions; +} tpm_sequence_update_out; + +typedef struct { + uint32_t pcr_handle; + uint32_t seq_handle; + TPM_CMD_SESSIONS_IN sessions; + TPM2B_MAX_BUFFER buf; +} tpm_sequence_complete_in; + +typedef struct { + TPML_DIGEST_VALUES results; + TPM_CMD_SESSIONS_OUT sessions; +} tpm_sequence_complete_out; + +typedef struct { + uint32_t seq_handle; + TPM_CMD_SESSIONS_IN sessions; + TPM2B_MAX_BUFFER buf; + uint32_t hierarchy; +} tpm_sequence_complete2_in; + +typedef struct { + TPML_DIGEST_VALUES results; + TPMT_TK_HASHCHECK validation; + TPM_CMD_SESSIONS_OUT sessions; +} tpm_sequence_complete2_out; + +typedef struct { + uint32_t handle; + uint32_t index; + TPM_CMD_SESSIONS_IN sessions; + uint16_t size; + uint16_t offset; +} tpm_nv_read_in; + +typedef struct { + TPM2B_MAX_NV_BUFFER data; + TPM_CMD_SESSIONS_OUT sessions; +} tpm_nv_read_out; + +typedef struct { + uint32_t handle; + uint32_t index; + TPM_CMD_SESSIONS_IN sessions; + TPM2B_MAX_NV_BUFFER data; + uint16_t offset; +} tpm_nv_write_in; + +typedef struct { + TPM_CMD_SESSIONS_OUT sessions; +} tpm_nv_write_out; + +typedef struct { + uint32_t handle; + TPM_CMD_SESSIONS_IN sessions; + TPM2B_AUTH auth; + TPM2B_NV_PUBLIC public_info; +} tpm_nv_define_space_in; + +typedef struct { + TPM_CMD_SESSIONS_OUT sessions; +} tpm_nv_define_space_out; + +typedef struct { + uint32_t handle; + uint32_t index; + TPM_CMD_SESSIONS_IN sessions; +} tpm_nv_undefine_space_in; + +typedef struct { + TPM_CMD_SESSIONS_OUT sessions; +} tpm_nv_undefine_space_out; + +typedef struct { + uint32_t index; +} tpm_nv_read_public_in; + +typedef struct { + TPM2B_NV_PUBLIC nv_public; + TPM2B_NAME nv_name; +} tpm_nv_read_public_out; + +typedef struct { + uint16_t bytes_req; +} tpm_get_random_in; + +typedef struct { + TPM2B_DIGEST random_bytes; +} tpm_get_random_out; + +typedef struct { + uint32_t capability; + uint32_t property; + uint32_t property_count; +} tpm_get_capability_in; + +typedef struct { + uint8_t more_data; + TPMS_CAPABILITY_DATA data; +} tpm_get_capability_out; + +typedef struct { + uint32_t primary_handle; + TPM_CMD_SESSIONS_IN sessions; + TPM2B_SENSITIVE_CREATE sensitive; + TPM2B_PUBLIC public; + TPM2B_DATA outside_info; + TPML_PCR_SELECTION creation_pcr; +} tpm_create_primary_in; + +typedef struct { + uint32_t obj_handle; + TPM2B_PUBLIC public; + TPM2B_CREATION_DATA creation_data; + TPM2B_DIGEST creation_hash; + TPMT_TK_CREATION creation_ticket; + TPM2B_NAME name; + TPM_CMD_SESSIONS_OUT sessions; +} tpm_create_primary_out; + +typedef struct { + uint32_t parent_handle; + TPM_CMD_SESSIONS_IN sessions; + TPM2B_SENSITIVE_CREATE sensitive; + TPM2B_PUBLIC public; + TPM2B_DATA outside_info; + TPML_PCR_SELECTION creation_pcr; +} tpm_create_in; + +typedef struct { + TPM2B_PRIVATE private; + TPM2B_PUBLIC public; + TPM2B_CREATION_DATA creation_data; + TPM2B_DIGEST creation_hash; + TPMT_TK_CREATION creation_ticket; + TPM_CMD_SESSIONS_OUT sessions; +} tpm_create_out; + +typedef struct { + uint32_t parent_handle; + TPM_CMD_SESSIONS_IN sessions; + TPM2B_PRIVATE private; + TPM2B_PUBLIC public; +} tpm_load_in; + +typedef struct { + uint32_t obj_handle; + TPM2B_NAME name; + TPM_CMD_SESSIONS_OUT sessions; +} tpm_load_out; + +typedef struct { + uint32_t item_handle; + TPM_CMD_SESSIONS_IN sessions; +} tpm_unseal_in; + +typedef struct { + TPM2B_SENSITIVE_DATA data; + TPM_CMD_SESSIONS_OUT sessions; +} tpm_unseal_out; + +typedef struct { + TPMI_DH_CONTEXT saveHandle; +} tpm_contextsave_in; + +typedef struct { + TPMS_CONTEXT context; +} tpm_contextsave_out; + +typedef struct { + TPMS_CONTEXT context; +} tpm_contextload_in; + +typedef struct { + TPMI_DH_CONTEXT loadedHandle; +} tpm_contextload_out; + +typedef struct { + TPMI_DH_CONTEXT flushHandle; +} tpm_flushcontext_in; + +#endif /* __TPM20_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/drivers/security/tpm/tpm_drv.c b/xen/drivers/security/tpm/tpm_drv.c new file mode 100644 index 0000000000..2263a31aeb --- /dev/null +++ b/xen/drivers/security/tpm/tpm_drv.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2023, Apertus Solutions, LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include +#include +#include +#include + +#include "../secdev.h" +#include "tpm.h" + +#define TPM_MAX_HASH_ALG 4 +#define TPM_PARAM_SHA1_MASK 1<<0 +#define TPM_PARAM_SHA256_MASK 1<<1 +#define TPM_PARAM_SHA384_MASK 1<<2 +#define TPM_PARAM_SHA512_MASK 1<<3 +#define TPM_PARAM_MAX_ALGO_MASK (TPM_PARAM_SHA1_MASK|TPM_PARAM_SHA256_MASK| \ + TPM_PARAM_SHA384_MASK|TPM_PARAM_SHA512_MASK) +static int16_t param_algo_mask = -1; +static int16_t param_dom_locality = -1; +static int16_t param_dom_pcr = -1; +/* + * [ algo-mask=, dom-locality=, dom-pcr= ] + */ +static int __init cf_check parse_tpm_param(const char *s) +{ + const char *ss; + int rc = 0; + + do { + ss = strchr(s, ','); + if ( !ss ) + ss = strchr(s, '\0'); + + if ( !strncmp(s, "algo-mask", 9) ) + param_algo_mask = simple_strtoul(s+9, &s, 0); + else if ( !strncmp(s, "dom-locality", 12) ) + { + param_dom_locality = simple_strtoul(s+12, &s, 0); + if ( param_dom_locality >= TPM_NR_LOCALITIES ) + { + printk(XENLOG_WARNING"Invalid Locality from commandline.\n"); + param_dom_locality = -1; + } + } + else if ( !strncmp(s, "dom-pcr", 7) ) + { + param_dom_pcr = simple_strtoul(s+7, &s, 0); + if ( param_dom_pcr >= TPM_NR_PCRS ) + { + printk(XENLOG_WARNING"Invalid PCR from commandline.\n"); + param_dom_pcr = -1; + } + } + else + rc = -EINVAL; + + s = ss + 1; + } while ( *ss ); + + return rc; +} +custom_param("tpm", parse_tpm_param); + +/* NOTE: will return the largest hash measured in *res */ +int cf_check tpm_extend_buffer(secdev_opt_t *opts, secdev_result_t *res) +{ + struct tpm_if *t = get_tpm(); + hash_list_t hashes = { 0 }; + uint32_t pcr = param_dom_pcr < 0 ? opts->tpm.buffer.pcr : param_dom_pcr; + uint32_t locality = param_dom_locality < 0 ? opts->tpm.buffer.locality : + param_dom_locality; + int i; + + if ( t == NULL || t->cmds == NULL || t->cmds->pcr_extend != NULL ) + return -EFAULT; + + if ( pcr >= TPM_NR_PCRS || locality >= TPM_NR_LOCALITIES ) + { + printk(XENLOG_ERR"%s: invalid PCR (%d) or Locality (%d) requested.\n", + __func__, pcr, locality); + return -EFAULT; + } + + if ( opts->tpm.buffer.addr == NULL ) + return -EINVAL; + + for ( i = 0; i < TPM_MAX_HASH_ALG; i++ ) + { + uint16_t algo_mask = 1<alg = HASH_ALG_SHA1; + + if ( !hash_buffer(opts->tpm.buffer.addr, opts->tpm.buffer.size, + &entry->hash, entry->alg) ) + return -EFAULT; + + res->tpm.measure.digest = entry->hash; + + /* TPM 1.2 only supports SHA1, break from loop */ + if ( t->version.major < TPM20_VER_MAJOR ) + goto buffer_tpm12_exit; + + break; + case TPM_PARAM_SHA256_MASK: + entry->alg = HASH_ALG_SHA256; + + if ( !hash_buffer(opts->tpm.buffer.addr, opts->tpm.buffer.size, + &entry->hash, entry->alg) ) + return -EFAULT; + + res->tpm.measure.digest = entry->hash; + + break; + case TPM_PARAM_SHA384_MASK: + entry->alg = HASH_ALG_SHA384; + + if ( !hash_buffer(opts->tpm.buffer.addr, opts->tpm.buffer.size, + &entry->hash, entry->alg) ) + return -EFAULT; + + res->tpm.measure.digest = entry->hash; + + break; + case TPM_PARAM_SHA512_MASK: + entry->alg = HASH_ALG_SHA512; + + if ( !hash_buffer(opts->tpm.buffer.addr, opts->tpm.buffer.size, + &entry->hash, entry->alg) ) + return -EFAULT; + + res->tpm.measure.digest = entry->hash; + + break; + default: + return -EFAULT; + } + + hashes.count++; + } + +buffer_tpm12_exit: + if ( !t->cmds->pcr_extend(t, locality, pcr, &hashes) ) + return -EFAULT; + + return 0; +} + +static int hash_domain( + hash_entry_t *entry, const unsigned char *kern, size_t kern_size, + const unsigned char *initrd, size_t initrd_size, char *cmdline) +{ + + if ( !hash_buffer(kern, kern_size, &entry->hash, entry->alg) ) + return -EFAULT; + + if ( initrd != NULL ) + { + hash_t ih; + + if ( !hash_buffer(initrd, initrd_size, &ih, entry->alg) || + !extend_hash(&entry->hash, &ih, entry->alg) ) + return -EFAULT; + } + + if ( cmdline != NULL ) + { + size_t cmdlen = strlen(cmdline); + hash_t ih; + + if ( !hash_buffer((unsigned char *)cmdline, cmdlen, &ih, entry->alg) || + !extend_hash(&entry->hash, &ih, entry->alg) ) + return -EFAULT; + } + + return 0; +} + +/* NOTE: will return the largest hash measured in *res */ +int cf_check tpm_extend_domain(secdev_opt_t *opts, secdev_result_t *res) +{ + struct tpm_if *t = get_tpm(); + hash_list_t hashes = { 0 }; + uint32_t pcr = param_dom_pcr < 0 ? opts->tpm.domain.pcr : param_dom_pcr; + uint32_t locality = param_dom_locality < 0 ? opts->tpm.domain.locality : + param_dom_locality; + int i; + + if ( t == NULL || t->cmds == NULL || t->cmds->pcr_extend != NULL ) + return -EFAULT; + + if ( pcr >= TPM_NR_PCRS || locality >= TPM_NR_LOCALITIES ) + { + printk(XENLOG_ERR"%s: invalid PCR (%d) or Locality (%d) requested.\n", + __func__, pcr, locality); + return -EFAULT; + } + + if ( opts->tpm.domain.kern == NULL ) + return -EINVAL; + + for ( i = 0; i < TPM_MAX_HASH_ALG; i++ ) + { + uint16_t algo_mask = 1<alg = HASH_ALG_SHA1; + + ret = hash_domain(entry, opts->tpm.domain.kern, + opts->tpm.domain.kern_size, opts->tpm.domain.initrd, + opts->tpm.domain.initrd_size, opts->tpm.domain.cmdline); + if ( ret < 0 ) + return ret; + + res->tpm.measure.digest = entry->hash; + + /* TPM 1.2 only supports SHA1, break from loop */ + if ( t->version.major < TPM20_VER_MAJOR ) + goto domain_tpm12_exit; + + break; + case TPM_PARAM_SHA256_MASK: + entry->alg = HASH_ALG_SHA256; + + ret = hash_domain(entry, opts->tpm.domain.kern, + opts->tpm.domain.kern_size, opts->tpm.domain.initrd, + opts->tpm.domain.kern_size, opts->tpm.domain.cmdline); + if ( ret < 0 ) + return ret; + + res->tpm.measure.digest = entry->hash; + + break; + case TPM_PARAM_SHA384_MASK: + entry->alg = HASH_ALG_SHA384; + + ret = hash_domain(entry, opts->tpm.domain.kern, + opts->tpm.domain.kern_size, opts->tpm.domain.initrd, + opts->tpm.domain.kern_size, opts->tpm.domain.cmdline); + if ( ret < 0 ) + return ret; + + res->tpm.measure.digest = entry->hash; + + break; + case TPM_PARAM_SHA512_MASK: + entry->alg = HASH_ALG_SHA512; + + ret = hash_domain(entry, opts->tpm.domain.kern, + opts->tpm.domain.kern_size, opts->tpm.domain.initrd, + opts->tpm.domain.kern_size, opts->tpm.domain.cmdline); + if ( ret < 0 ) + return ret; + + res->tpm.measure.digest = entry->hash; + + break; + default: + return -EFAULT; + } + + hashes.count++; + } + +domain_tpm12_exit: + if ( !t->cmds->pcr_extend(t, locality, pcr, &hashes) ) + return -EFAULT; + + return 0; +} + +static struct secdev_handle tpm_drv_handle = { + .getrandom = NULL, + .register_domain = NULL, + .measure_buffer = tpm_extend_buffer, + .measure_domain = tpm_extend_domain, + .launch_domain = NULL, + .direct_op = NULL, +}; + +struct secdev_handle *tpm_driver_init(void) +{ + struct tpm_if *t = get_tpm(); + + if ( !tpm_detect() ) + return NULL; + + if ( (t->version.version == TPM_VER_12) && + !(param_algo_mask || TPM_PARAM_SHA1_MASK) ) + { + printk(XENLOG_WARNING"Detected TPM1.2 but SHA1 not in requested algorithms.\n"); + param_algo_mask = TPM_PARAM_SHA1_MASK; + } + + /* mask out any undefined bits */ + param_algo_mask &= TPM_PARAM_MAX_ALGO_MASK; + + return &tpm_drv_handle; +} diff --git a/xen/drivers/security/tpm/tpm_drv.h b/xen/drivers/security/tpm/tpm_drv.h new file mode 100644 index 0000000000..016c5c6538 --- /dev/null +++ b/xen/drivers/security/tpm/tpm_drv.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Copyright (c) 2023, Apertus Solutions, LLC + * All rights reserved. + */ + +#ifndef __TPM_H__ +#define __TPM_H__ + +struct secdev_handle *tpm_driver_init(void); + +int tpm_extend_domain( + const unsigned char *kern, size_t kern_size, const unsigned char *initrd, + size_t initrd_size); +#endif diff --git a/xen/drivers/security/tpm/tpm_mmio.c b/xen/drivers/security/tpm/tpm_mmio.c new file mode 100644 index 0000000000..0e58313147 --- /dev/null +++ b/xen/drivers/security/tpm/tpm_mmio.c @@ -0,0 +1,893 @@ +/* + * tpm_mmio.c: TPM MMIO hardware interface + * + * Copyright (c) 2006-2010, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "tpm.h" + +/* Global variables for TPM status register */ +static tpm20_reg_sts_t g_reg_sts, *g_reg_sts_20 = &g_reg_sts; +static tpm12_reg_sts_t *g_reg_sts_12 = (tpm12_reg_sts_t *)&g_reg_sts; + + +/* TPM_DATA_FIFO_x */ +#define TPM_REG_DATA_FIFO 0x24 +typedef union { + uint8_t _raw[1]; /* 1-byte reg */ +} tpm_reg_data_fifo_t; + +typedef union { + uint8_t _raw[1]; +} tpm_reg_data_crb_t; + +#define TPM_ACTIVE_LOCALITY_TIME_OUT \ + (get_tpm()->timeout.timeout_a) /* according to spec */ +#define TPM_CMD_READY_TIME_OUT \ + (get_tpm()->timeout.timeout_b) /* according to spec */ +#define TPM_CMD_WRITE_TIME_OUT \ + (get_tpm()->timeout.timeout_d) /* let it long enough */ +#define TPM_DATA_AVAIL_TIME_OUT \ + (get_tpm()->timeout.timeout_c) /* let it long enough */ +#define TPM_RSP_READ_TIME_OUT \ + (get_tpm()->timeout.timeout_d) /* let it long enough */ +#define TPM_VALIDATE_LOCALITY_TIME_OUT 0x100 + +#define tpm_loop_until_timeout(now, end, timeout) \ + for (now = NOW(), end = now + MILLISECS(timeout); \ + now < end; now = NOW() ) + +#define read_tpm_sts_reg(locality) { \ +if ( get_tpm()->family == TPM_IF_12 ) \ + read_tpm_reg(locality, TPM_REG_STS, g_reg_sts_12); \ +else \ + read_tpm_reg(locality, TPM_REG_STS, g_reg_sts_20); \ +} + +#define write_tpm_sts_reg(locality) { \ +if ( get_tpm()->family == TPM_IF_12 ) \ + write_tpm_reg(locality, TPM_REG_STS, g_reg_sts_12); \ +else \ + write_tpm_reg(locality, TPM_REG_STS, g_reg_sts_20); \ +} + +/* MMIO status register helpers */ + +static void tpm_print_status_register(void) +{ + if ( get_tpm()->family == TPM_IF_12 ) + { + printk(XENLOG_INFO"TPM: status reg content: %02x %02x %02x\n", + (uint32_t)g_reg_sts_12->_raw[0], + (uint32_t)g_reg_sts_12->_raw[1], + (uint32_t)g_reg_sts_12->_raw[2]); + } + else + { + printk(XENLOG_INFO"TPM: status reg content: %02x %02x %02x %02x\n", + (uint32_t)g_reg_sts_20->_raw[0], + (uint32_t)g_reg_sts_20->_raw[1], + (uint32_t)g_reg_sts_20->_raw[2], + (uint32_t)g_reg_sts_20->_raw[3]); + } +} + +static uint16_t tpm_get_burst_count(uint32_t locality) +{ + read_tpm_sts_reg(locality); + return g_reg_sts.burst_count; +} + +static bool tpm_check_expect_status(uint32_t locality) +{ + read_tpm_sts_reg(locality); +#ifdef TPM_TRACE + printk(XENLOG_INFO"Wait on Expect = 0, Status register %02x\n", + g_reg_sts._raw[0]); +#endif + return g_reg_sts.sts_valid == 1 && g_reg_sts.expect == 0; +} + +static bool tpm_check_data_access_status(uint32_t locality) +{ + read_tpm_sts_reg(locality); +#ifdef TPM_TRACE + printk(XENLOG_INFO"Waiting for DA Flag, Status register %02x\n", + g_reg_sts._raw[0]); +#endif + return g_reg_sts.sts_valid == 1 && g_reg_sts.data_avail == 1; +} + +/* FIFO interface commands */ + +bool cf_check fifo_request_locality(uint32_t locality) +{ + s_time_t now, end; + tpm_reg_access_t reg_acc; + + /* request access to the TPM from locality N */ + reg_acc._raw[0] = 0; + reg_acc.request_use = 1; + write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + + tpm_loop_until_timeout(now, end, TPM_ACTIVE_LOCALITY_TIME_OUT); + { + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality == 1 ) + break; + else + cpu_relax(); + now = NOW(); + } + + if ( now > end ) + { + printk(XENLOG_ERR"TPM: FIFO_INF access reg request use timeout\n"); + return false; + } + + return true; +} + +static bool cf_check fifo_validate_locality(uint32_t locality) +{ + s_time_t now, end; + tpm_reg_access_t reg_acc; + + tpm_loop_until_timeout(now, end, TPM_ACTIVE_LOCALITY_TIME_OUT); + { + /* + * TCG spec defines reg_acc.tpm_reg_valid_sts bit to indicate whether + * other bits of access reg are valid.( but this bit will also be 1 + * while this locality is not available, so check seize bit too) + * It also defines that reading reg_acc.seize should always return 0 + */ + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.tpm_reg_valid_sts == 1 && reg_acc.seize == 0) + return true; + cpu_relax(); + } + if ( now > end ) + printk(XENLOG_ERR"TPM: tpm_validate_locality timeout\n"); + + return false; +} + +static bool cf_check fifo_release_locality(uint32_t locality) +{ + s_time_t now, end; + uint32_t i; + tpm_reg_access_t reg_acc; + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: releasing locality %u\n", locality); +#endif + + if ( !fifo_validate_locality(locality) ) + return true; + + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality == 0 ) + return true; + + /* make inactive by writing a 1 */ + reg_acc._raw[0] = 0; + reg_acc.active_locality = 1; + write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + + tpm_loop_until_timeout(now, end, TPM_ACTIVE_LOCALITY_TIME_OUT); + { + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality == 0 ) + return true; + else + cpu_relax(); + i++; + } + + printk(XENLOG_INFO"TPM: access reg release locality timeout\n"); + return false; +} + +static void fifo_quick_release_locality(uint32_t locality) +{ + tpm_reg_access_t reg_acc; + + /* fire and forget deactivate locality */ + reg_acc._raw[0] = 0; + reg_acc.active_locality = 1; + write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); +} + +static void fifo_send_cmd_ready_status(uint32_t locality) +{ + /* write 1 to TPM_STS_x.commandReady to let TPM enter ready state */ + memset((void *)&g_reg_sts, 0, sizeof(g_reg_sts)); + g_reg_sts.command_ready = 1; + write_tpm_sts_reg(locality); +} + +static bool fifo_check_cmd_ready_status(uint32_t locality) +{ + read_tpm_sts_reg(locality); +#ifdef TPM_TRACE + printk(XENLOG_INFO"."); +#endif + return g_reg_sts.command_ready; +} + +static bool fifo_wait_cmd_ready(uint32_t locality) +{ + s_time_t now, end; + + /* request access to the TPM from locality N */ + if ( !fifo_request_locality(locality) ) + return false; + + /* ensure the TPM is ready to accept a command */ +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: wait for cmd ready \n"); +#endif + + tpm_loop_until_timeout(now, end, TPM_CMD_READY_TIME_OUT); + { + fifo_send_cmd_ready_status(locality); + cpu_relax(); + /* then see if it has */ + + if ( fifo_check_cmd_ready_status(locality) ) + break; + else + cpu_relax(); + i++; + } +#ifdef TPM_TRACE + printk(XENLOG_INFO"\n"); +#endif + + if ( now > end ) + { + tpm_print_status_register(); + printk(XENLOG_INFO"TPM: tpm timeout for command_ready\n"); + fifo_quick_release_locality(locality); + return false; + } + + return true; +} + +static void fifo_execute_cmd(uint32_t locality) +{ + memset((void *)&g_reg_sts, 0, sizeof(g_reg_sts)); + g_reg_sts.tpm_go = 1; + write_tpm_sts_reg(locality); +} + +static bool cf_check fifo_submit_cmd( + uint32_t locality, uint8_t *in, u32 in_size, u8 *out, u32 *out_size) +{ + uint32_t rsp_size, offset; + uint16_t row_size; + s_time_t now, end; + + if ( locality >= TPM_NR_LOCALITIES ) + { + printk(XENLOG_WARNING + "TPM: Invalid locality for tpm_write_cmd_fifo()\n"); + return false; + } + if ( in == NULL || out == NULL || out_size == NULL ) + { + printk(XENLOG_WARNING + "TPM: Invalid parameter for tpm_write_cmd_fifo()\n"); + return false; + } + if ( in_size < CMD_HEAD_SIZE || *out_size < RSP_HEAD_SIZE ) + { + printk(XENLOG_WARNING + "TPM: in/out buf size must be larger than 10 bytes\n"); + return false; + } + + if ( !fifo_validate_locality(locality) ) + { + printk(XENLOG_WARNING"TPM: Locality %d is not open\n", locality); + return false; + } + + if ( !fifo_wait_cmd_ready(locality) ) + return false; + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO"TPM: cmd size = 0x%x\nTPM: cmd content: ", in_size); + printk("TPM: \t%*ph\n", in_size, in); + } +#endif + + /* write the command to the TPM FIFO */ + offset = 0; + do { + tpm_loop_until_timeout(now, end, TPM_CMD_WRITE_TIME_OUT); + { + /* find out how many bytes the TPM can accept in a row */ + row_size = tpm_get_burst_count(locality); + if ( row_size > 0 ) + break; + else + cpu_relax(); + } + if ( now > end ) + { + printk(XENLOG_ERR"TPM: write cmd timeout\n"); + fifo_quick_release_locality(locality); + return false; + } + + for ( ; row_size > 0 && offset < in_size; row_size--, offset++ ) + write_tpm_reg(locality, TPM_REG_DATA_FIFO, + (tpm_reg_data_fifo_t *)&in[offset]); + } while ( offset < in_size ); + + tpm_loop_until_timeout(now, end, TPM_DATA_AVAIL_TIME_OUT); + { + if ( tpm_check_expect_status(locality) ) + break; + else + cpu_relax(); + } + if ( now > end ) + { + printk(XENLOG_ERR"TPM: wait for expect becoming 0 timeout\n"); + fifo_quick_release_locality(locality); + return false; + } + + /* command has been written to the TPM, it is time to execute it. */ + fifo_execute_cmd(locality); + + /* check for data available */ + tpm_loop_until_timeout(now, end, TPM_DATA_AVAIL_TIME_OUT); + { + if ( tpm_check_data_access_status(locality) ) + break; + else + cpu_relax(); + i++; + } + if ( now > end ) { + printk(XENLOG_ERR"TPM: wait for data available timeout\n"); + fifo_quick_release_locality(locality); + return false; + } + + rsp_size = 0; + offset = 0; + do { + /* find out how many bytes the TPM returned in a row */ + tpm_loop_until_timeout(now, end, TPM_RSP_READ_TIME_OUT); + { + row_size = tpm_get_burst_count(locality); + if ( row_size > 0 ) + break; + else + cpu_relax(); + i++; + } + if ( now > end ) + { + printk(XENLOG_ERR"TPM: read rsp timeout\n"); + fifo_quick_release_locality(locality); + return false; + } + + for ( ; row_size > 0 && offset < *out_size; row_size--, offset++ ) + { + if ( offset < *out_size ) + { + read_tpm_reg(locality, TPM_REG_DATA_FIFO, + (tpm_reg_data_fifo_t *)&out[offset]); + } + else + { + /* discard the responded bytes exceeding out buf size */ + tpm_reg_data_fifo_t discard; + read_tpm_reg(locality, TPM_REG_DATA_FIFO, + (tpm_reg_data_fifo_t *)&discard); + } + + /* get outgoing data size */ + if ( offset == RSP_RST_OFFSET - 1 ) + reverse_copy(&rsp_size, &out[RSP_SIZE_OFFSET], sizeof(rsp_size)); + } + } while ( offset < RSP_RST_OFFSET || + (offset < rsp_size && offset < *out_size) ); + + *out_size = (*out_size > rsp_size) ? rsp_size : *out_size; + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO"TPM: response size = %d\n", *out_size); + printk(XENLOG_INFO"TPM: response content: "); + printk("TPM: \t%*ph\n", *out_size, out); + } +#endif + + fifo_send_cmd_ready_status(locality); + + return true; +} + + +static const struct tpm_hw_if fifo_hw_intf = { + .request_locality = fifo_request_locality, + .validate_locality = fifo_validate_locality, + .release_locality = fifo_release_locality, + .submit_cmd = fifo_submit_cmd, +}; + + +/* + * CRB interafce commands + */ + +/* Pre-declaration for single loop circular call */ +static bool crb_locality_workaround(void); + +static bool cf_check crb_request_locality(uint32_t locality) +{ + tpm_reg_loc_state_t reg_loc_state; + tpm_reg_loc_ctrl_t reg_loc_ctrl; + s_time_t now, end; + + /* request access to the TPM from locality N */ + memset(®_loc_ctrl,0,sizeof(reg_loc_ctrl)); + reg_loc_ctrl.requestAccess = 1; + write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); + + tpm_loop_until_timeout(now, end, TPM_ACTIVE_LOCALITY_TIME_OUT); + { + read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); + if ( reg_loc_state.active_locality == locality && + reg_loc_state.loc_assigned == 1) + break; + else + cpu_relax(); + } + + if ( now > end ) + { + printk(XENLOG_ERR"TPM: access loc request use timeout\n"); + printk(XENLOG_ERR" attempting workaround\n"); + return crb_locality_workaround(); + } + + return true; +} + +static bool crb_locality_workaround(void) +{ + tpm_reg_ctrl_cmdsize_t CmdSize; + tpm_reg_ctrl_cmdaddr_t CmdAddr; + tpm_reg_ctrl_rspsize_t RspSize; + tpm_reg_ctrl_rspaddr_t RspAddr; + uint32_t locality = 0; + + if ( !crb_request_locality(locality) ) + return false; + + CmdAddr.cmdladdr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER; + CmdAddr.cmdhaddr = 0; + RspAddr.rspaddr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER; + CmdSize.cmdsize = TPMCRBBUF_LEN; + RspSize.rspsize = TPMCRBBUF_LEN; + + write_tpm_reg(locality, TPM_CRB_CTRL_CMD_ADDR, &CmdAddr); + write_tpm_reg(locality, TPM_CRB_CTRL_CMD_SIZE, &CmdSize); + write_tpm_reg(locality, TPM_CRB_CTRL_RSP_ADDR, &RspAddr); + write_tpm_reg(locality, TPM_CRB_CTRL_RSP_SIZE, &RspSize); + + return true; +} + +bool cf_check crb_validate_locality(uint32_t locality) +{ + tpm_reg_loc_state_t reg_loc_state; + s_time_t now, end; + + tpm_loop_until_timeout(now, end, TPM_ACTIVE_LOCALITY_TIME_OUT); + { + /* + * Platfrom Tpm Profile for TPM 2.0 SPEC + */ + read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); + if ( reg_loc_state.tpm_reg_valid_sts == 1 && + reg_loc_state.loc_assigned == 1 && + reg_loc_state.active_locality == locality) + { + printk(XENLOG_INFO"TPM: reg_loc_state._raw[0]: 0x%x\n", + reg_loc_state._raw[0]); + return true; + } + cpu_relax(); + } + + printk(XENLOG_ERR"TPM: tpm_validate_locality_crb timeout\n"); + printk(XENLOG_INFO"TPM: reg_loc_state._raw[0]: 0x%x\n", + reg_loc_state._raw[0]); + return false; +} + +bool cf_check crb_relinquish_locality(uint32_t locality) +{ + tpm_reg_loc_state_t reg_loc_state; + tpm_reg_loc_ctrl_t reg_loc_ctrl; + s_time_t now, end; + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: releasing CRB_INF locality %u\n", locality); +#endif + + if ( !crb_validate_locality(locality) ) + return true; + read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); + if ( reg_loc_state.loc_assigned == 0 ) + return true; + + /* make inactive by writing a 1 */ + memset(®_loc_ctrl,0,sizeof(reg_loc_ctrl)); + reg_loc_ctrl.relinquish = 1; + write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); + + tpm_loop_until_timeout(now, end, TPM_ACTIVE_LOCALITY_TIME_OUT); + { + read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); + if ( reg_loc_state.loc_assigned == 0 ) + return true; + else + cpu_relax(); + } + + printk(XENLOG_INFO"TPM: CRB_INF release locality timeout\n"); + return false; +} + + +static bool crb_send_cmd_ready_status(uint32_t locality) +{ + tpm_reg_ctrl_request_t reg_ctrl_request; + tpm_reg_ctrl_sts_t reg_ctrl_sts; + s_time_t now, end; + + read_tpm_reg(locality, TPM_CRB_CTRL_STS, ®_ctrl_sts); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"1. reg_ctrl_sts.tpmidle: 0x%x\n", reg_ctrl_sts.tpmidle); + printk(XENLOG_INFO"1. reg_ctrl_sts.tpmsts: 0x%x\n", reg_ctrl_sts.tpmsts); +#endif + + if ( reg_ctrl_sts.tpmidle == 1) + { + memset(®_ctrl_request,0,sizeof(reg_ctrl_request)); + reg_ctrl_request.cmdReady = 1; + write_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + + return true; + } + + memset(®_ctrl_request,0,sizeof(reg_ctrl_request)); + reg_ctrl_request.goIdle = 1; + write_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + + tpm_loop_until_timeout(now, end, TPM_DATA_AVAIL_TIME_OUT); + { + read_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + if ( reg_ctrl_request.goIdle == 0) + { + break; + } + else + { + cpu_relax(); + read_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"1. reg_ctrl_request.goIdle: 0x%x\n", + reg_ctrl_request.goIdle); + printk(XENLOG_INFO"1. reg_ctrl_request.cmdReady: 0x%x\n", + reg_ctrl_request.cmdReady); +#endif + + } + i++; + } + + if ( now > end ) + { + printk(XENLOG_ERR"TPM: reg_ctrl_request.goidle timeout!\n"); + return false; + } + + read_tpm_reg(locality, TPM_CRB_CTRL_STS, ®_ctrl_sts); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"2. reg_ctrl_sts.tpmidle: 0x%x\n", reg_ctrl_sts.tpmidle); + printk(XENLOG_INFO"2. reg_ctrl_sts.tpmsts: 0x%x\n", reg_ctrl_sts.tpmsts); +#endif + + memset(®_ctrl_request,0,sizeof(reg_ctrl_request)); + reg_ctrl_request.cmdReady = 1; + write_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"2. reg_ctrl_request.goIdle: 0x%x\n", + reg_ctrl_request.goIdle); + printk(XENLOG_INFO"2. reg_ctrl_request.cmdReady: 0x%x\n", + reg_ctrl_request.cmdReady); +#endif + + read_tpm_reg(locality, TPM_CRB_CTRL_STS, ®_ctrl_sts); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"2. reg_ctrl_sts.tpmidle: 0x%x\n", reg_ctrl_sts.tpmidle); + printk(XENLOG_INFO"2. reg_ctrl_sts.tpmsts: 0x%x\n", reg_ctrl_sts.tpmsts); +#endif + + return true; + +} + +static bool crb_check_cmd_ready_status(uint32_t locality) +{ + tpm_reg_ctrl_request_t reg_ctrl_request; + read_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + +#ifdef TPM_TRACE + printk(XENLOG_INFO"3. reg_ctrl_request.goIdle: 0x%x\n", + reg_ctrl_request.goIdle); + printk(XENLOG_INFO"3. reg_ctrl_request.cmdReady: 0x%x\n", + reg_ctrl_request.cmdReady); +#endif + + if ( reg_ctrl_request.cmdReady == 0) + return true; + else + return false; + +} + +static bool crb_wait_cmd_ready(uint32_t locality) +{ + s_time_t now, end; + + /* ensure the TPM is ready to accept a command */ +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: wait for cmd ready \n"); +#endif + crb_send_cmd_ready_status(locality); + tpm_loop_until_timeout(now, end, TPM_CMD_READY_TIME_OUT); + { + if ( crb_check_cmd_ready_status(locality) ) + break; + else + cpu_relax(); + i++; + } + + if ( now > end ) + { + //tpm_print_status_register(); + printk(XENLOG_INFO"TPM: tpm timeout for command_ready\n"); + return false; + } + + return true; +} + +bool cf_check crb_submit_cmd( + uint32_t locality, uint8_t *in, u32 in_size, u8 *out, u32 *out_size) +{ + uint32_t i; + //tpm_reg_loc_ctrl_t reg_loc_ctrl; + tpm_reg_ctrl_start_t start; + tpm_reg_ctrl_cmdsize_t CmdSize; + tpm_reg_ctrl_cmdaddr_t CmdAddr; + tpm_reg_ctrl_rspsize_t RspSize; + tpm_reg_ctrl_rspaddr_t RspAddr; + uint32_t tpm_crb_data_buffer_base; + s_time_t now, end; + + if ( locality >= TPM_NR_LOCALITIES ) + { + printk(XENLOG_WARNING + "TPM: Invalid locality for tpm_submit_cmd_crb()\n"); + return false; + } + if ( in == NULL || out == NULL || out_size == NULL ) + { + printk(XENLOG_WARNING + "TPM: Invalid parameter for tpm_submit_cmd_crb()\n"); + return false; + } + if ( in_size < CMD_HEAD_SIZE || *out_size < RSP_HEAD_SIZE ) + { + printk(XENLOG_WARNING + "TPM: in/out buf size must be larger than 10 bytes\n"); + return false; + } + + if ( !crb_validate_locality(locality) ) + { + printk(XENLOG_WARNING + "TPM: CRB Interface Locality %d is not open\n", locality); + return false; + } + + if ( !crb_wait_cmd_ready(locality) ) + { + printk(XENLOG_WARNING"TPM: tpm_wait_cmd_read_crb failed\n"); + return false; + } + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO + "TPM: Before submit, cmd size = 0x%x\nTPM: Before submit, cmd content: ", + in_size); + printk("TPM: \t%*ph\n", in_size, in); + } +#endif + + /* write the command to the TPM CRB buffer 01-04-2016 */ +//copy *in and size to crb buffer + + CmdAddr.cmdladdr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER; + CmdAddr.cmdhaddr = 0; + RspAddr.rspaddr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER; + CmdSize.cmdsize = TPMCRBBUF_LEN; + RspSize.rspsize = TPMCRBBUF_LEN; + tpm_crb_data_buffer_base = TPM_CRB_DATA_BUFFER; + + +#ifdef TPM_TRACE + printk(XENLOG_INFO"CmdAddr.cmdladdr is 0x%x\n",CmdAddr.cmdladdr); + printk(XENLOG_INFO"CmdAddr.cmdhaddr is 0x%x\n",CmdAddr.cmdhaddr); + printk(XENLOG_INFO"CmdSize.cmdsize is 0x%x\n",CmdSize.cmdsize); + printk(XENLOG_INFO"RspAddr.rspaddr is 0x%lx\n",RspAddr.rspaddr); + printk(XENLOG_INFO"RspSize.rspsize is 0x%x\n",RspSize.rspsize); +#endif + + write_tpm_reg(locality, TPM_CRB_CTRL_CMD_ADDR, &CmdAddr); + write_tpm_reg(locality, TPM_CRB_CTRL_CMD_SIZE, &CmdSize); + write_tpm_reg(locality, TPM_CRB_CTRL_RSP_ADDR, &RspAddr); + write_tpm_reg(locality, TPM_CRB_CTRL_RSP_SIZE, &RspSize); + // write the command to the buffer + for ( i = 0 ; i< in_size; i++ ) + { + write_tpm_reg(locality, tpm_crb_data_buffer_base++, + (tpm_reg_data_crb_t *)&in[i]); + //tpm_crb_data_buffer_base++; + } + + /* command has been written to the TPM, it is time to execute it. */ + start.start = 1; + write_tpm_reg(locality, TPM_CRB_CTRL_START, &start); + //read_tpm_reg(locality, TPM_CRB_CTRL_START, &start); + printk(XENLOG_INFO"tpm_ctrl_start.start is 0x%x\n",start.start); + + /* check for data available */ + tpm_loop_until_timeout(now, end, TPM_DATA_AVAIL_TIME_OUT); + { + read_tpm_reg(locality, TPM_CRB_CTRL_START, &start); + //printk(XENLOG_INFO"tpm_ctrl_start.start is 0x%x\n",start.start); + if ( start.start == 0 ) + break; + else + cpu_relax(); + i++; + } + + if ( now > end ) { + printk(XENLOG_ERR"TPM: wait for data available timeout\n"); + return false; + } + + tpm_crb_data_buffer_base = TPM_CRB_DATA_BUFFER; + + for ( i = 0 ; i< *out_size; i++ ) + { + read_tpm_reg(locality, tpm_crb_data_buffer_base++, (tpm_reg_data_crb_t *)&out[i]); + //tpm_crb_data_buffer_base++; + } + +#ifdef TPM_TRACE + { + printk(XENLOG_INFO"TPM: After cmd submit, response size = 0x%x\n", + *out_size); + printk(XENLOG_INFO"TPM: After cmd submit, response content: "); + printk("TPM: \t%*ph\n", *out_size, out); + } +#endif + + //tpm_send_cmd_ready_status_crb(locality); + + return true; +} + +static const struct tpm_hw_if crb_hw_intf = { + .request_locality = crb_request_locality, + .validate_locality = crb_validate_locality, + .release_locality = crb_relinquish_locality, + .submit_cmd = crb_submit_cmd, +}; + + +void mmio_detect_interface(struct tpm_if *tpm) +{ + tpm_crb_interface_id_t crb_interface; + read_tpm_reg(0, TPM_INTERFACE_ID, &crb_interface); + if (crb_interface.interface_type == TPM_INTERFACE_ID_CRB ) + { + printk(XENLOG_INFO"TPM: PTP CRB interface is active...\n"); + tpm->family = TPM_IF_20_CRB; + tpm->hw = &crb_hw_intf; + return; + } + if (crb_interface.interface_type == TPM_INTERFACE_ID_FIFO_20) + { + printk(XENLOG_INFO"TPM: TPM 2.0 FIFO interface is active...\n"); + tpm->family = TPM_IF_20_FIFO; + tpm->hw = &fifo_hw_intf; + return; + } + + tpm->family = TPM_IF_12; + tpm->hw = &fifo_hw_intf; + return; +} +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/lib/hash.h b/xen/include/xen/lib/hash.h new file mode 100644 index 0000000000..794add88a9 --- /dev/null +++ b/xen/include/xen/lib/hash.h @@ -0,0 +1,120 @@ +/* + * hash.h: definition of and support fns for hash_t type + * + * Copyright (c) 2006-2007, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __HASH_H__ +#define __HASH_H__ + +#define HASH_ALG_SHA1_LG 0x0000 /* legacy define for SHA1 */ +#define HASH_ALG_SHA1 0x0004 +#define HASH_ALG_SHA256 0x000B +#define HASH_ALG_SM3 0x0012 /* Unsupported */ +#define HASH_ALG_SHA384 0x000C +#define HASH_ALG_SHA512 0x000D +#define HASH_ALG_NULL 0x0010 + +#define SHA1_LENGTH 20 +#define SHA256_LENGTH 32 +#define SHA384_LENGTH 48 +#define SHA512_LENGTH 64 + +#define HASH_MAX_LENGTH SHA512_LENGTH + +typedef uint8_t sha1_hash_t[SHA1_LENGTH]; +typedef uint8_t sha256_hash_t[SHA256_LENGTH]; +typedef uint8_t sha384_hash_t[SHA384_LENGTH]; +typedef uint8_t sha512_hash_t[SHA512_LENGTH]; + +typedef union { + uint8_t sha1[SHA1_LENGTH]; + uint8_t sha256[SHA256_LENGTH]; + uint8_t sha384[SHA384_LENGTH]; + uint8_t sha512[SHA512_LENGTH]; +} hash_t; + +static inline const char *hash_alg_to_string(uint16_t hash_alg) +{ + if ( hash_alg == HASH_ALG_SHA1 || hash_alg == HASH_ALG_SHA1_LG ) + return "HASH_ALG_SHA1"; + else if ( hash_alg == HASH_ALG_SHA256 ) + return "HASH_ALG_SHA256"; + else if ( hash_alg == HASH_ALG_SM3 ) + return "HASH_ALG_SM3"; + else if ( hash_alg == HASH_ALG_SHA384 ) + return "HASH_ALG_SHA384"; + else if ( hash_alg == HASH_ALG_SHA512 ) + return "HASH_ALG_SHA512"; + else + return "unsupported"; +} + +static inline unsigned int get_hash_size(uint16_t hash_alg) +{ + if ( hash_alg == HASH_ALG_SHA1 || hash_alg == HASH_ALG_SHA1_LG ) + return SHA1_LENGTH; + else if ( hash_alg == HASH_ALG_SHA256 ) + return SHA256_LENGTH; + else if ( hash_alg == HASH_ALG_SHA384 ) + return SHA384_LENGTH; + else if ( hash_alg == HASH_ALG_SHA512 ) + return SHA512_LENGTH; + else + return 0; +} + + +bool are_hashes_equal( + const hash_t *hash1, const hash_t *hash2, uint16_t hash_alg); +bool hash_buffer( + const unsigned char* buf, size_t size, hash_t *hash, uint16_t hash_alg); +bool extend_hash( + hash_t *hash1, const hash_t *hash2, uint16_t hash_alg); +void print_hash(const hash_t *hash, uint16_t hash_alg); +bool import_hash(const char *string, hash_t *hash, uint16_t alg); +void copy_hash( + hash_t *dest_hash, const hash_t *src_hash, uint16_t hash_alg); + + +#endif /* __HASH_H__ */ + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/lib/sha1.h b/xen/include/xen/lib/sha1.h new file mode 100644 index 0000000000..fc31ad9085 --- /dev/null +++ b/xen/include/xen/lib/sha1.h @@ -0,0 +1,78 @@ +/*$FreeBSD: src/sys/crypto/sha1.h,v 1.8.36.1.2.1 2009/10/25 01:10:29 kensmith Exp $ */ +/*$KAME: sha1.h,v 1.5 2000/03/27 04:36:23 sumikawa Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Portions copyright (c) 2010, Intel Corporation + */ + +/* + * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) + * based on: http://csrc.nist.gov/fips/fip180-1.txt + * implemented by Jun-ichiro itojun Itoh + */ + +#ifndef __SHA1_H__ +#define __SHA1_H__ + +struct sha1_ctxt { + union { + uint8_t b8[20]; + uint32_t b32[5]; + } h; + union { + uint8_t b8[8]; + uint64_t b64[1]; + } c; + union { + uint8_t b8[64]; + uint32_t b32[16]; + } m; + uint8_t count; +}; + +void sha1_init(struct sha1_ctxt *); +void sha1_pad(struct sha1_ctxt *); +void sha1_loop(struct sha1_ctxt *, const uint8_t *, size_t); +void sha1_result(struct sha1_ctxt *, unsigned char *); +#define SHA1_RESULTLEN (160/8) + +/* compatibilty with other SHA1 source codes */ +typedef struct sha1_ctxt SHA_CTX; +#define SHA1_Init(x) sha1_init((x)) +#define SHA1_Update(x, y, z) sha1_loop((x), (y), (z)) +#define SHA1_Final(x, y) sha1_result((y), (x)) +#define SHA_DIGEST_LENGTH SHA1_RESULTLEN + +int sha1_buffer( + const unsigned char *buffer, size_t len, + unsigned char md[SHA_DIGEST_LENGTH]); + +#endif /* __SHA1_H__ */ diff --git a/xen/include/xen/lib/sha2.h b/xen/include/xen/lib/sha2.h new file mode 100644 index 0000000000..83cd90fae8 --- /dev/null +++ b/xen/include/xen/lib/sha2.h @@ -0,0 +1,83 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +#include + +#define SHA256_BLOCK_SIZE 64 +#define SHA512_BLOCK_SIZE 128 + +#define CONST64(n) n ## ULL + +#define STORE64H(x, y) \ +do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ + (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ + (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ + (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while (0) + +#define LOAD64H(x, y) \ +do { x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \ + (((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \ + (((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \ + (((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); } while(0) + +#define STORE32H(x, y) \ +do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ + (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while (0) + +#define LOAD32H(x, y) \ +do { x = ((uint32_t)((y)[0] & 255)<<24) | \ + ((uint32_t)((y)[1] & 255)<<16) | \ + ((uint32_t)((y)[2] & 255)<<8) | \ + ((uint32_t)((y)[3] & 255)); } while (0) + + +struct sha512_state { + uint64_t length, state[8]; + uint32_t curlen; + unsigned char buf[128]; +}; + +struct sha256_state { + uint64_t length; + uint32_t state[8], curlen; + unsigned char buf[64]; +}; + +typedef union hash_state { + char dummy[1]; + struct sha512_state sha512; + struct sha256_state sha256; + void *data; +} hash_state; + +/* SHA 256 */ +int sha256_init(hash_state * md); +int sha256_process(hash_state * md, const unsigned char *in, uint32_t inlen); +int sha256_done(hash_state * md, unsigned char *out); +int sha256_buffer( + const unsigned char *buffer, size_t len, unsigned char hash[32]); + +/* SHA 384 */ +int sha384_init(hash_state * md); +#define sha384_process sha512_process +int sha384_done(hash_state * md, unsigned char *out); +int sha384_buffer( + const unsigned char *buffer, size_t len, unsigned char hash[48]); + +/* SHA 512 */ +int sha512_init(hash_state * md); +int sha512_process(hash_state * md, const unsigned char *in, uint32_t inlen); +int sha512_done(hash_state * md, unsigned char *out); +int sha512_buffer( + const unsigned char *buffer, size_t len, unsigned char hash[64]); + +#endif /* __SHA2_H__ */ diff --git a/xen/include/xen/secdev.h b/xen/include/xen/secdev.h new file mode 100644 index 0000000000..77a1b733dd --- /dev/null +++ b/xen/include/xen/secdev.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* + * Copyright (c) 2023, Apertus Solutions, LLC + * All rights reserved. + */ + +#ifndef __XEN_SECDEV_H__ +#define __XEN_SECDEV_H__ + +#include + +typedef enum secdev_id { + SECDEV_TPM, + SECDEV_ASP, /* Reserving for AMD PSP/ASP */ + SECDEV_PLTN, /* Reserving for MS Pluton */ +} secdev_id_t; + +#define SECDEV_SHA1_MASK 1<<0 +#define SECDEV_SHA256_MASK 1<<1 +#define SECDEV_SHA384_MASK 1<<2 +#define SECDEV_SHA512_MASK 1<<3 +#define SECDEV_MAX_ALGO_MASK (SECDEV_SHA1_MASK|SECDEV_SHA256_MASK| \ + SECDEV_SHA384_MASK|SECDEV_SHA512_MASK) + +#define SECDEV_TPM_DEFAULT_LOCALITY 0 +#define SECDEV_TPM_DEFAULT_PCR 15 +struct tpm_dev_opt { + union { + struct { + void *buf; + size_t buf_size; + uint32_t flags; + } random; + struct { + uint8_t locality; + uint8_t pcr; + uint16_t algo_mask; + unsigned char *addr; + size_t size; + } buffer; + struct { + uint8_t locality; + uint8_t pcr; + uint16_t algo_mask; + unsigned char *kern; + size_t kern_size; + unsigned char *initrd; + size_t initrd_size; + char *cmdline; + } domain; + }; +}; + +typedef union secdev_opt { + struct tpm_dev_opt tpm; +} secdev_opt_t; + +int secdev_init(void); +bool secdev_available(secdev_id_t dev_id); +ssize_t secdev_getrandom(secdev_id_t dev_id, secdev_opt_t *opts); +int secdev_measure_buffer(secdev_id_t dev_id, secdev_opt_t *opts); +int secdev_measure_domain(secdev_id_t dev_id, secdev_opt_t *opts); + +#endif diff --git a/xen/lib/Makefile b/xen/lib/Makefile index b311ea739c..114433b31b 100644 --- a/xen/lib/Makefile +++ b/xen/lib/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_X86) += x86/ +obj-$(CONFIG_CRYPTO) += crypto/ lib-y += bsearch.o lib-y += ctors.o diff --git a/xen/lib/crypto/Makefile b/xen/lib/crypto/Makefile new file mode 100644 index 0000000000..ca118e4d96 --- /dev/null +++ b/xen/lib/crypto/Makefile @@ -0,0 +1,5 @@ +lib-y += hash.o +lib-y += sha1.o +lib-y += sha256.o +lib-y += sha384.o +lib-y += sha512.o diff --git a/xen/lib/crypto/hash.c b/xen/lib/crypto/hash.c new file mode 100644 index 0000000000..10814c3fb9 --- /dev/null +++ b/xen/lib/crypto/hash.c @@ -0,0 +1,213 @@ +/* + * hash.c: support functions for hash_t type + * + * Copyright (c) 2006-2010, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +/* + * are_hashes_equal + * + * compare whether two hash values are equal. + * + */ +bool are_hashes_equal( + const hash_t *hash1, const hash_t *hash2, uint16_t hash_alg) +{ + unsigned int len; + + if ( ( hash1 == NULL ) || ( hash2 == NULL ) ) + { + printk(XENLOG_ERR"Error: hash pointer is zero.\n"); + return false; + } + + len = get_hash_size(hash_alg); + if ( len > 0 ) + return (memcmp(hash1, hash2, len) == 0); + else + { + printk(XENLOG_ERR"unsupported hash alg (%u)\n", hash_alg); + return false; + } +} + +/* + * hash_buffer + * + * hash the buffer according to the algorithm + * + */ +bool hash_buffer( + const unsigned char* buf, size_t size, hash_t *hash, uint16_t hash_alg) +{ + if ( hash == NULL ) + { + printk(XENLOG_ERR"Error: There is no space for output hash.\n"); + return false; + } + + if ( hash_alg == HASH_ALG_SHA1 ) + { + sha1_buffer(buf, size, hash->sha1); + return true; + } + else if ( hash_alg == HASH_ALG_SHA256 ) + { + sha256_buffer(buf, size, hash->sha256); + return true; + } + else if ( hash_alg == HASH_ALG_SHA384 ) + { + sha384_buffer(buf, size, hash->sha384); + return true; + } + else if ( hash_alg == HASH_ALG_SHA512 ) + { + sha512_buffer(buf, size, hash->sha512); + return true; + } + else + { + printk(XENLOG_ERR"unsupported hash alg (%u)\n", hash_alg); + return false; + } +} + +/* + * extend_hash + * + * perform "extend" of two hashes (i.e. hash1 = SHA(hash1 || hash2) + * + */ +bool extend_hash(hash_t *hash1, const hash_t *hash2, uint16_t hash_alg) +{ + uint8_t buf[2*HASH_MAX_LENGTH]; + + if ( hash1 == NULL || hash2 == NULL ) + { + if ( hash1 == NULL ) + printk(XENLOG_ERR"Error: There is no space for output hash.\n"); + if ( hash2 == NULL ) + printk(XENLOG_ERR"Error: Must provide two hashes.\n"); + return false; + } + + if ( hash_alg == HASH_ALG_SHA1 ) + { + memcpy(buf, &(hash1->sha1), sizeof(hash1->sha1)); + memcpy(buf + sizeof(hash1->sha1), &(hash2->sha1), sizeof(hash1->sha1)); + sha1_buffer(buf, 2*sizeof(hash1->sha1), hash1->sha1); + return true; + } + else if ( hash_alg == HASH_ALG_SHA256 ) + { + memcpy(buf, &(hash1->sha256), sizeof(hash1->sha256)); + memcpy(buf + sizeof(hash1->sha256), &(hash2->sha256), + sizeof(hash1->sha256)); + sha256_buffer(buf, 2*sizeof(hash1->sha256), hash1->sha256); + return true; + } + else if ( hash_alg == HASH_ALG_SHA384 ) + { + memcpy(buf, &(hash1->sha384), sizeof(hash1->sha384)); + memcpy(buf + sizeof(hash1->sha384), &(hash2->sha384), + sizeof(hash1->sha384)); + sha384_buffer(buf, 2*sizeof(hash1->sha384), hash1->sha384); + return true; + } + else if ( hash_alg == HASH_ALG_SHA512 ) + { + memcpy(buf, &(hash1->sha512), sizeof(hash1->sha512)); + memcpy(buf + sizeof(hash1->sha512), &(hash2->sha512), + sizeof(hash1->sha512)); + sha512_buffer(buf, 2*sizeof(hash1->sha512), hash1->sha512); + return true; + } + else + { + printk(XENLOG_ERR"unsupported hash alg (%u)\n", hash_alg); + return false; + } +} + +void print_hash(const hash_t *hash, uint16_t hash_alg) +{ + if ( hash == NULL ) + { + printk(XENLOG_WARNING"NULL"); + return; + } + + if ( hash_alg == HASH_ALG_SHA1 ) + printk(XENLOG_INFO"%*ph\n", get_hash_size(HASH_ALG_SHA1), + (uint8_t *)hash->sha1); + else if ( hash_alg == HASH_ALG_SHA256 ) + printk(XENLOG_INFO"%*ph\n", get_hash_size(HASH_ALG_SHA256), + (uint8_t *)hash->sha256); + else if ( hash_alg == HASH_ALG_SHA384 ) + printk(XENLOG_INFO"%*ph\n", get_hash_size(HASH_ALG_SHA384), + (uint8_t *)hash->sha384); + else + printk(XENLOG_WARNING"unsupported hash alg (%u)\n", hash_alg); +} + +void copy_hash(hash_t *dest_hash, const hash_t *src_hash, uint16_t hash_alg) +{ + unsigned int len; + + if ( dest_hash == NULL || src_hash == NULL ) + { + printk(XENLOG_WARNING"hashes are NULL\n"); + return; + } + + len = get_hash_size(hash_alg); + if ( len > 0 ) + memcpy(dest_hash, src_hash, len); + else + printk(XENLOG_WARNING"unsupported hash alg (%u)\n", hash_alg); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/lib/crypto/sha1.c b/xen/lib/crypto/sha1.c new file mode 100644 index 0000000000..9e67fffc74 --- /dev/null +++ b/xen/lib/crypto/sha1.c @@ -0,0 +1,273 @@ +/*$KAME: sha1.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Portions copyright (c) 2010, Intel Corporation + */ + +/* + * From: FreeBSD sys/crypto/sha1.c + */ + +/* + * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) + * based on: http://csrc.nist.gov/fips/fip180-1.txt + * implemented by Jun-ichiro itojun Itoh + */ + +#include +#include +#include +#include +#include + +#define BIG_ENDIAN \ + (!(__x86_64__ || __i386__ || _M_IX86 || _M_X64 || __ARMEL__ || __MIPSEL__)) +#define LITTLE_ENDIAN !BIG_ENDIAN + +/* constant table */ +static uint32_t _K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; +#define K(t) _K[(t) / 20] +#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d))) +#define F1(b, c, d) (((b) ^ (c)) ^ (d)) +#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) +#define F3(b, c, d) (((b) ^ (c)) ^ (d)) +#define S(n, x) (((x) << (n)) | ((x) >> (32 - n))) +#define H(n) (ctxt->h.b32[(n)]) +#define COUNT (ctxt->count) +#define BCOUNT (ctxt->c.b64[0] / 8) +#define W(n) (ctxt->m.b32[(n)]) +#define PUTBYTE(x){\ + ctxt->m.b8[(COUNT % 64)] = (x);\ + COUNT++;\ + COUNT %= 64;\ + ctxt->c.b64[0] += 8;\ + if (COUNT % 64 == 0)\ + sha1_step(ctxt);\ + } +#define PUTPAD(x){\ + ctxt->m.b8[(COUNT % 64)] = (x);\ + COUNT++;\ + COUNT %= 64;\ + if (COUNT % 64 == 0)\ + sha1_step(ctxt);\ + } +static void sha1_step(struct sha1_ctxt *ctxt) +{ + uint32_t a, b, c, d, e; + size_t t, s; + uint32_t tmp; + +#if LITTLE_ENDIAN + struct sha1_ctxt tctxt; + memcpy(&tctxt.m.b8[0], &ctxt->m.b8[0], 64); + ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2]; + ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0]; + ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6]; + ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4]; + ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10]; + ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8]; + ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14]; + ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12]; + ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18]; + ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16]; + ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22]; + ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20]; + ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26]; + ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24]; + ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30]; + ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28]; + ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34]; + ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32]; + ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38]; + ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36]; + ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42]; + ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40]; + ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46]; + ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44]; + ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50]; + ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48]; + ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54]; + ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52]; + ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58]; + ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56]; + ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62]; + ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60]; +#endif + + a = H(0); b = H(1); c = H(2); d = H(3); e = H(4); + + for ( t = 0; t < 20; t++ ) + { + s = t & 0x0f; + if (t >= 16) + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) + ^ W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for ( t = 20; t < 40; t++ ) + { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) + ^ W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for ( t = 40; t < 60; t++ ) + { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) + ^ W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + for ( t = 60; t < 80; t++ ) + { + s = t & 0x0f; + W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) + ^ W((s+2) & 0x0f) ^ W(s)); + tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t); + e = d; d = c; c = S(30, b); b = a; a = tmp; + } + + H(0) = H(0) + a; + H(1) = H(1) + b; + H(2) = H(2) + c; + H(3) = H(3) + d; + H(4) = H(4) + e; + + memset(&ctxt->m.b8[0],0, 64); +} + +/*------------------------------------------------------------*/ + +void sha1_init(struct sha1_ctxt *ctxt) +{ + memset(ctxt,0, sizeof(struct sha1_ctxt)); + H(0) = 0x67452301; + H(1) = 0xefcdab89; + H(2) = 0x98badcfe; + H(3) = 0x10325476; + H(4) = 0xc3d2e1f0; +} + +void sha1_pad(struct sha1_ctxt *ctxt) +{ + size_t padlen; /*pad length in bytes*/ + size_t padstart; + + PUTPAD(0x80); + + padstart = COUNT % 64; + padlen = 64 - padstart; + if ( padlen < 8 ) + { + memset(&ctxt->m.b8[padstart],0, padlen); + COUNT += padlen; + COUNT %= 64; + sha1_step(ctxt); + padstart = COUNT % 64; /* should be 0 */ + padlen = 64 - padstart; /* should be 64 */ + } + memset(&ctxt->m.b8[padstart],0, padlen - 8); + COUNT += (padlen - 8); + COUNT %= 64; +#if BIG_ENDIAN + PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]); + PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]); + PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]); + PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]); +#else + PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]); + PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]); + PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]); + PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]); +#endif +} + +void sha1_loop(struct sha1_ctxt *ctxt, const uint8_t *input, size_t len) +{ + size_t gaplen; + size_t gapstart; + size_t off; + size_t copysiz; + + off = 0; + + while ( off < len ) + { + gapstart = COUNT % 64; + gaplen = 64 - gapstart; + + copysiz = (gaplen < len - off) ? gaplen : len - off; + memcpy(&ctxt->m.b8[gapstart],&input[off], copysiz); + COUNT += copysiz; + COUNT %= 64; + ctxt->c.b64[0] += copysiz * 8; + if ( COUNT % 64 == 0 ) + sha1_step(ctxt); + off += copysiz; + } +} + +void sha1_result(struct sha1_ctxt *ctxt, unsigned char *digest0) +{ + uint8_t *digest; + + digest = (uint8_t *)digest0; + sha1_pad(ctxt); +#if BIG_ENDIAN + sl_memcpy(digest, &ctxt->h.b8[0],20); +#else + digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2]; + digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0]; + digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6]; + digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4]; + digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10]; + digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8]; + digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14]; + digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12]; + digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18]; + digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16]; +#endif +} + +int sha1_buffer( + const unsigned char *buffer, size_t len, unsigned char md[20]) +{ + SHA_CTX c; + + if (md == NULL) + return -EINVAL; + SHA1_Init(&c); + SHA1_Update(&c,buffer,len); + SHA1_Final(md,&c); + return 0; +} diff --git a/xen/lib/crypto/sha256.c b/xen/lib/crypto/sha256.c new file mode 100644 index 0000000000..903eafe967 --- /dev/null +++ b/xen/lib/crypto/sha256.c @@ -0,0 +1,264 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + */ + +#include +#include +#include +#include + +/* Various logical functions */ +#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) \ + | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) \ + & 0xFFFFFFFFUL) +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) RORc((x),(n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) + +/* compress 512-bits */ +static int sha256_compress(hash_state * md, unsigned char *buf) +{ + uint32_t S[8], W[64], t0, t1; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) + S[i] = md->sha256.state[i]; + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) + LOAD32H(W[i], buf + (4*i)); + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + + /* Compress */ +#define RND(a,b,c,d,e,f,g,h,i,ki) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); + +#undef RND + + /* feedback */ + for (i = 0; i < 8; i++) + md->sha256.state[i] = md->sha256.state[i] + S[i]; + + return 0; +} + +int sha256_process(hash_state * md, const unsigned char *in, uint32_t inlen) +{ + unsigned long n; + int err; + + if (md == NULL || in == NULL) + return -1; + if (md->sha256.curlen > sizeof(md->sha256.buf)) + return -1; + + while (inlen > 0) + { + if (md->sha256.curlen == 0 && inlen >= SHA256_BLOCK_SIZE) + { + if ((err = sha256_compress(md, (unsigned char *)in)) != 0) + return err; + + md->sha256.length += SHA256_BLOCK_SIZE * 8; + in += SHA256_BLOCK_SIZE; + inlen -= SHA256_BLOCK_SIZE; + } + else + { + n = MIN(inlen, (SHA256_BLOCK_SIZE - md->sha256.curlen)); + memcpy(md->sha256.buf + md->sha256.curlen, in, (size_t)n); + md->sha256.curlen += n; + in += n; + inlen -= n; + if (md->sha256.curlen == SHA256_BLOCK_SIZE) + { + if ((err = sha256_compress(md, md->sha256.buf)) != 0) + return err; + + md->sha256.length += 8*SHA256_BLOCK_SIZE; + md->sha256.curlen = 0; + } + } + } + return 0; +} + +/** + Initialize the hash state + @param md The hash state you wish to initialize + @return CRYPT_OK if successful +*/ +int sha256_init(hash_state * md) +{ + if (md == NULL) + return -1; + + md->sha256.curlen = 0; + md->sha256.length = 0; + md->sha256.state[0] = 0x6A09E667UL; + md->sha256.state[1] = 0xBB67AE85UL; + md->sha256.state[2] = 0x3C6EF372UL; + md->sha256.state[3] = 0xA54FF53AUL; + md->sha256.state[4] = 0x510E527FUL; + md->sha256.state[5] = 0x9B05688CUL; + md->sha256.state[6] = 0x1F83D9ABUL; + md->sha256.state[7] = 0x5BE0CD19UL; + + return 0; +} + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (32 bytes) + @return 0 if successful +*/ +int sha256_done(hash_state * md, unsigned char *out) +{ + int i; + + if (md == NULL || out == NULL) + return -1; + + if (md->sha256.curlen >= sizeof(md->sha256.buf)) + return -1; + + /* increase the length of the message */ + md->sha256.length += md->sha256.curlen * 8; + + /* append the '1' bit */ + md->sha256.buf[md->sha256.curlen++] = (unsigned char)0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->sha256.curlen > 56) + { + while (md->sha256.curlen < 64) + md->sha256.buf[md->sha256.curlen++] = (unsigned char)0; + + sha256_compress(md, md->sha256.buf); + md->sha256.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->sha256.curlen < 56) + md->sha256.buf[md->sha256.curlen++] = (unsigned char)0; + + + /* store length */ + STORE64H(md->sha256.length, md->sha256.buf+56); + sha256_compress(md, md->sha256.buf); + + /* copy output */ + for (i = 0; i < 8; i++) + STORE32H(md->sha256.state[i], out+(4*i)); + + return 0; +} + +int sha256_buffer( + const unsigned char *buffer, size_t len, unsigned char hash[32]) +{ + hash_state md; + int ret = 0; + + ret |= sha256_init(&md); + ret |= sha256_process(&md, buffer, len); + ret |= sha256_done(&md, hash); + + return ret; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/lib/crypto/sha384.c b/xen/lib/crypto/sha384.c new file mode 100644 index 0000000000..6dc3f347de --- /dev/null +++ b/xen/lib/crypto/sha384.c @@ -0,0 +1,80 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + */ + +#include +#include + +/** + Initialize the hash state + @param md The hash state you wish to initialize + @return CRYPT_OK if successful +*/ +int sha384_init(hash_state * md) +{ + if (md == NULL) + return -1; + + md->sha512.curlen = 0; + md->sha512.length = 0; + md->sha512.state[0] = CONST64(0xcbbb9d5dc1059ed8); + md->sha512.state[1] = CONST64(0x629a292a367cd507); + md->sha512.state[2] = CONST64(0x9159015a3070dd17); + md->sha512.state[3] = CONST64(0x152fecd8f70e5939); + md->sha512.state[4] = CONST64(0x67332667ffc00b31); + md->sha512.state[5] = CONST64(0x8eb44a8768581511); + md->sha512.state[6] = CONST64(0xdb0c2e0d64f98fa7); + md->sha512.state[7] = CONST64(0x47b5481dbefa4fa4); + + return 0; +} + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (48 bytes) + @return CRYPT_OK if successful +*/ +int sha384_done(hash_state * md, unsigned char *out) +{ + unsigned char buf[64]; + + if (md == NULL || out == NULL) + return -1; + + if (md->sha512.curlen >= sizeof(md->sha512.buf)) + return -1; + + sha512_done(md, buf); + memcpy(out, buf, 48); + + return 0; +} + +int sha384_buffer( + const unsigned char *buffer, size_t len, unsigned char hash[48]) +{ + hash_state md; + int ret = 0; + + ret |= sha384_init(&md); + ret |= sha384_process(&md, buffer, len); + ret |= sha384_done(&md, hash); + + return ret; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/lib/crypto/sha512.c b/xen/lib/crypto/sha512.c new file mode 100644 index 0000000000..cd32700380 --- /dev/null +++ b/xen/lib/crypto/sha512.c @@ -0,0 +1,267 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + */ + +#include +#include +#include + +/* the K array */ +static const uint64_t K[80] = { + CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd), + CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc), + CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019), + CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118), + CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe), + CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2), + CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1), + CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694), + CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3), + CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65), + CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483), + CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5), + CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210), + CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4), + CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725), + CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70), + CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926), + CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df), + CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8), + CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b), + CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001), + CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30), + CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910), + CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8), + CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53), + CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8), + CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb), + CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3), + CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60), + CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec), + CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9), + CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b), + CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207), + CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178), + CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6), + CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b), + CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493), + CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c), + CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a), + CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817) +}; + +/* Various logical functions */ +#define ROR64c(x, y) \ + ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&CONST64(63))) | \ + ((x)<<(((uint64_t)64-((y)&63))&63))) & CONST64(0xFFFFFFFFFFFFFFFF)) + +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) ROR64c(x, n) +#define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n)) +#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) +#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) +#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) +#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) + +/* compress 1024-bits */ +static int sha512_compress(hash_state * md, const unsigned char *buf) +{ + uint64_t S[8], W[80], t0, t1; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) + S[i] = md->sha512.state[i]; + + /* copy the state into 1024-bits into W[0..15] */ + for (i = 0; i < 16; i++) + LOAD64H(W[i], buf + (8*i)); + + /* fill W[16..79] */ + for (i = 16; i < 80; i++) + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + + /* Compress */ +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + for (i = 0; i < 80; i += 8) + { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); + } + + /* feedback */ + for (i = 0; i < 8; i++) + md->sha512.state[i] = md->sha512.state[i] + S[i]; + + return 0; +} + +/** + Initialize the hash state + @param md The hash state you wish to initialize + @return CRYPT_OK if successful +*/ +int sha512_init(hash_state * md) +{ + if (md == NULL) + return -1; + + md->sha512.curlen = 0; + md->sha512.length = 0; + md->sha512.state[0] = CONST64(0x6a09e667f3bcc908); + md->sha512.state[1] = CONST64(0xbb67ae8584caa73b); + md->sha512.state[2] = CONST64(0x3c6ef372fe94f82b); + md->sha512.state[3] = CONST64(0xa54ff53a5f1d36f1); + md->sha512.state[4] = CONST64(0x510e527fade682d1); + md->sha512.state[5] = CONST64(0x9b05688c2b3e6c1f); + md->sha512.state[6] = CONST64(0x1f83d9abfb41bd6b); + md->sha512.state[7] = CONST64(0x5be0cd19137e2179); + + return 0; +} + +/** + Process a block of memory though the hash + @param md The hash state + @param in The data to hash + @param inlen The length of the data (octets) + @return 0 if successful +*/ +int sha512_process(hash_state * md, const unsigned char *in, uint32_t inlen) +{ + unsigned long n; + int err; + + if (md == NULL || in == NULL) + return -1; + + if (md->sha512.curlen > sizeof(md->sha512.buf)) + return -1; + + if ((md->sha512.length + inlen) < md->sha512.length) + return -1; + + while (inlen > 0) + { + if (md->sha512.curlen == 0 && inlen >= SHA512_BLOCK_SIZE) + { + if ((err = sha512_compress (md, in)) != 0) + return err; + + md->sha512.length += SHA512_BLOCK_SIZE * 8; + in += SHA512_BLOCK_SIZE; + inlen -= SHA512_BLOCK_SIZE; + } + else + { + n = MIN(inlen, (SHA512_BLOCK_SIZE - md->sha512.curlen)); + memcpy(md->sha512.buf + md->sha512.curlen, in, (size_t)n); + md->sha512.curlen += n; + in += n; + inlen -= n; + if (md->sha512.curlen == SHA512_BLOCK_SIZE) + { + if ((err = sha512_compress (md, md->sha512.buf)) != 0) + return err; + + md->sha512.length += 8*SHA512_BLOCK_SIZE; + md->sha512.curlen = 0; + } + } + } + return 0; +} + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (64 bytes) + @return CRYPT_OK if successful +*/ +int sha512_done(hash_state * md, unsigned char *out) +{ + int i; + + if (md == NULL || out == NULL) + return -1; + + if (md->sha512.curlen >= sizeof(md->sha512.buf)) + return -1; + + + /* increase the length of the message */ + md->sha512.length += md->sha512.curlen * CONST64(8); + + /* append the '1' bit */ + md->sha512.buf[md->sha512.curlen++] = (unsigned char)0x80; + + /* if the length is currently above 112 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->sha512.curlen > 112) + { + while (md->sha512.curlen < 128) + md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; + + sha512_compress(md, md->sha512.buf); + md->sha512.curlen = 0; + } + + /* pad upto 120 bytes of zeroes + * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash + * > 2^64 bits of data... :-) + */ + while (md->sha512.curlen < 120) + md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; + + /* store length */ + STORE64H(md->sha512.length, md->sha512.buf+120); + sha512_compress(md, md->sha512.buf); + + /* copy output */ + for (i = 0; i < 8; i++) + STORE64H(md->sha512.state[i], out+(8*i)); + + return 0; +} + +int sha512_buffer( + const unsigned char *buffer, size_t len, unsigned char hash[64]) +{ + hash_state md; + int ret = 0; + + ret |= sha512_init(&md); + ret |= sha512_process(&md, buffer, len); + ret |= sha512_done(&md, hash); + + return ret; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */