From e25fff0ced5de6bec11bb8c8719e0d956dda677e Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Fri, 20 Jan 2023 14:12:04 -0500 Subject: [PATCH 01/10] lib: add hash library This commit adds a hash library containing support for sha1 and sha2. Signed-off-by: Daniel P. Smith --- xen/include/xen/lib/hash.h | 120 ++++++++++++++++ xen/include/xen/lib/sha1.h | 78 +++++++++++ xen/include/xen/lib/sha2.h | 83 +++++++++++ xen/lib/Makefile | 1 + xen/lib/crypto/Makefile | 5 + xen/lib/crypto/hash.c | 213 +++++++++++++++++++++++++++++ xen/lib/crypto/sha1.c | 273 +++++++++++++++++++++++++++++++++++++ xen/lib/crypto/sha256.c | 264 +++++++++++++++++++++++++++++++++++ xen/lib/crypto/sha384.c | 80 +++++++++++ xen/lib/crypto/sha512.c | 267 ++++++++++++++++++++++++++++++++++++ 10 files changed, 1384 insertions(+) create mode 100644 xen/include/xen/lib/hash.h create mode 100644 xen/include/xen/lib/sha1.h create mode 100644 xen/include/xen/lib/sha2.h create mode 100644 xen/lib/crypto/Makefile create mode 100644 xen/lib/crypto/hash.c create mode 100644 xen/lib/crypto/sha1.c create mode 100644 xen/lib/crypto/sha256.c create mode 100644 xen/lib/crypto/sha384.c create mode 100644 xen/lib/crypto/sha512.c diff --git a/xen/include/xen/lib/hash.h b/xen/include/xen/lib/hash.h new file mode 100644 index 00000000000..794add88a98 --- /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 00000000000..fc31ad90856 --- /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 00000000000..83cd90fae87 --- /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/lib/Makefile b/xen/lib/Makefile index b311ea739c5..114433b31b0 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 00000000000..ca118e4d96f --- /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 00000000000..10814c3fb96 --- /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 00000000000..9e67fffc748 --- /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 00000000000..903eafe9674 --- /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 00000000000..6dc3f347de6 --- /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 00000000000..cd327003804 --- /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: + */ From ff59e7ee09b608d68bef5ea79782f9e37f8d3c09 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Fri, 20 Jan 2023 12:11:34 -0500 Subject: [PATCH 02/10] drivers: introduce kconfig for secdev framework This commit adds the Kconfig for selecting the security hardware (secdev) framework. Signed-off-by: Daniel P. Smith --- MAINTAINERS | 5 +++++ xen/drivers/Kconfig | 2 ++ xen/drivers/security/Kconfig | 8 ++++++++ 3 files changed, 15 insertions(+) create mode 100644 xen/drivers/security/Kconfig diff --git a/MAINTAINERS b/MAINTAINERS index 7a07949e1dd..fa9a37704b6 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/drivers/Kconfig b/xen/drivers/Kconfig index db94393f47a..834d0cdc5b0 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/security/Kconfig b/xen/drivers/security/Kconfig new file mode 100644 index 00000000000..6c038d91e8d --- /dev/null +++ b/xen/drivers/security/Kconfig @@ -0,0 +1,8 @@ + +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. From 28db758986a6ffcefff2a5658f3d2dcf132969a6 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Mon, 23 Jan 2023 13:34:41 -0500 Subject: [PATCH 03/10] drivers: import of tpm driver into security hw drivers This commit bring in the TPM driver code from tboot, commit 4a904a6, apply Xen coding style, and integrates with Xen's build. Signed-off-by: Daniel P. Smith --- xen/drivers/security/tpm/Makefile | 3 + xen/drivers/security/tpm/tpm.c | 1000 +++++++++ xen/drivers/security/tpm/tpm.h | 573 ++++++ xen/drivers/security/tpm/tpm_12.c | 2008 +++++++++++++++++++ xen/drivers/security/tpm/tpm_20.c | 3122 +++++++++++++++++++++++++++++ xen/drivers/security/tpm/tpm_20.h | 1565 +++++++++++++++ 6 files changed, 8271 insertions(+) create mode 100644 xen/drivers/security/tpm/Makefile create mode 100644 xen/drivers/security/tpm/tpm.c create mode 100644 xen/drivers/security/tpm/tpm.h create mode 100644 xen/drivers/security/tpm/tpm_12.c create mode 100644 xen/drivers/security/tpm/tpm_20.c create mode 100644 xen/drivers/security/tpm/tpm_20.h diff --git a/xen/drivers/security/tpm/Makefile b/xen/drivers/security/tpm/Makefile new file mode 100644 index 00000000000..2655abff33f --- /dev/null +++ b/xen/drivers/security/tpm/Makefile @@ -0,0 +1,3 @@ +obj-y += tpm.o +obj-y += tpm_12.o +obj-y += tpm_20.o diff --git a/xen/drivers/security/tpm/tpm.c b/xen/drivers/security/tpm/tpm.c new file mode 100644 index 00000000000..1b23e6ab190 --- /dev/null +++ b/xen/drivers/security/tpm/tpm.c @@ -0,0 +1,1000 @@ +/* + * 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 "tpm.h" + +uint8_t g_tpm_ver = TPM_VER_UNKNOWN; +struct tpm_if g_tpm = { + .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); + +/* 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; + +uint8_t g_tpm_family = 0; + +/* 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 \ + (TIMEOUT_UNIT *get_tpm()->timeout.timeout_a) /* according to spec */ +#define TPM_CMD_READY_TIME_OUT \ + (TIMEOUT_UNIT *get_tpm()->timeout.timeout_b) /* according to spec */ +#define TPM_CMD_WRITE_TIME_OUT \ + (TIMEOUT_UNIT *get_tpm()->timeout.timeout_d) /* let it long enough */ +#define TPM_DATA_AVAIL_TIME_OUT \ + (TIMEOUT_UNIT *get_tpm()->timeout.timeout_c) /* let it long enough */ +#define TPM_RSP_READ_TIME_OUT \ + (TIMEOUT_UNIT *get_tpm()->timeout.timeout_d) /* let it long enough */ +#define TPM_VALIDATE_LOCALITY_TIME_OUT 0x100 + +#define read_tpm_sts_reg(locality) { \ +if ( g_tpm_family == 0 ) \ + 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 ( g_tpm_family == 0 ) \ + write_tpm_reg(locality, TPM_REG_STS, g_reg_sts_12); \ +else \ + write_tpm_reg(locality, TPM_REG_STS, g_reg_sts_20); \ +} + +static void tpm_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 tpm_send_cmd_ready_status_crb(uint32_t locality) +{ + uint32_t i = 0; + tpm_reg_ctrl_request_t reg_ctrl_request; + tpm_reg_ctrl_sts_t reg_ctrl_sts; + + 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); + + do { + 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++; + } while ( i <= TPM_DATA_AVAIL_TIME_OUT); + + if ( i > TPM_DATA_AVAIL_TIME_OUT ) + { + 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 tpm_check_cmd_ready_status_crb(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 tpm_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 void tpm_print_status_register(void) +{ + if ( g_tpm_family == 0 ) + { + 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_da_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; +} + +static void tpm_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); +} + +bool tpm_validate_locality(uint32_t locality) +{ + uint32_t i; + tpm_reg_access_t reg_acc; + + for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) + { + /* + * 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 ( i <= 0 ) + printk(XENLOG_ERR"TPM: tpm_validate_locality timeout\n"); + + return false; +} + +bool tpm_validate_locality_crb(uint32_t locality) +{ + uint32_t i; + tpm_reg_loc_state_t reg_loc_state; + + for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) + { + /* + * 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 tpm_wait_cmd_ready(uint32_t locality) +{ + uint32_t i; + tpm_reg_access_t reg_acc; + +/* + * some tpms doesn't always return 1 for reg_acc.tpm_reg_valid_sts + * and this bit was checked in tpm_validate_locality() already, + * so safe to skip the check here + */ +#if 0 + /* ensure the contents of the ACCESS register are valid */ + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: Access reg content: 0x%02x\n", (uint32_t)reg_acc._raw[0]); +#endif + if ( reg_acc.tpm_reg_valid_sts == 0 ) + { + printk(XENLOG_ERR"TPM: Access reg not valid\n"); + return false; + } +#endif + /* 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); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality == 1 ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT); + + if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) + { + printk(XENLOG_ERR"TPM: FIFO_INF access reg request use timeout\n"); + return false; + } + + /* ensure the TPM is ready to accept a command */ +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: wait for cmd ready \n"); +#endif + i = 0; + do { + tpm_send_cmd_ready_status(locality); + cpu_relax(); + /* then see if it has */ + + if ( tpm_check_cmd_ready_status(locality) ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_CMD_READY_TIME_OUT ); +#ifdef TPM_TRACE + printk(XENLOG_INFO"\n"); +#endif + + if ( i > TPM_CMD_READY_TIME_OUT ) + { + tpm_print_status_register(); + printk(XENLOG_INFO"TPM: tpm timeout for command_ready\n"); + goto RelinquishControl; + } + + return true; + +RelinquishControl: + /* deactivate current locality */ + reg_acc._raw[0] = 0; + reg_acc.active_locality = 1; + write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + + return false; +} + +static bool tpm_wait_cmd_ready_crb(uint32_t locality) +{ + uint32_t i; + + /* ensure the TPM is ready to accept a command */ +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: wait for cmd ready \n"); +#endif + tpm_send_cmd_ready_status_crb(locality); + i = 0; + do { + if ( tpm_check_cmd_ready_status_crb(locality) ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_CMD_READY_TIME_OUT ); + + if ( i > TPM_CMD_READY_TIME_OUT ) + { + //tpm_print_status_register(); + printk(XENLOG_INFO"TPM: tpm timeout for command_ready\n"); + goto RelinquishControl; + } + + return true; + +RelinquishControl: + /* deactivate current locality */ + //tpm_reg_loc_ctrl_t reg_loc_ctrl; + //reg_loc_ctrl._raw[0] = 0; + //reg_loc_ctrl.relinquish = 1; + //write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); + + return false; +} + +bool tpm_submit_cmd( + uint32_t locality, uint8_t *in, u32 in_size, u8 *out, u32 *out_size) +{ + uint32_t i, rsp_size, offset; + uint16_t row_size; + tpm_reg_access_t reg_acc; + bool ret = true; + + 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 ( !tpm_validate_locality(locality) ) + { + printk(XENLOG_WARNING"TPM: Locality %d is not open\n", locality); + return false; + } + + if ( !tpm_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 { + i = 0; + do { + /* 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(); + i++; + } while ( i <= TPM_CMD_WRITE_TIME_OUT ); + if ( i > TPM_CMD_WRITE_TIME_OUT ) + { + printk(XENLOG_ERR"TPM: write cmd timeout\n"); + ret = false; + goto RelinquishControl; + } + + 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 ); + + i = 0; + do { + if ( tpm_check_expect_status(locality) ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); + if ( i > TPM_DATA_AVAIL_TIME_OUT ) + { + printk(XENLOG_ERR"TPM: wait for expect becoming 0 timeout\n"); + ret = false; + goto RelinquishControl; + } + + /* command has been written to the TPM, it is time to execute it. */ + tpm_execute_cmd(locality); + + /* check for data available */ + i = 0; + do { + if ( tpm_check_da_status(locality) ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); + if ( i > TPM_DATA_AVAIL_TIME_OUT ) { + printk(XENLOG_ERR"TPM: wait for data available timeout\n"); + ret = false; + goto RelinquishControl; + } + + rsp_size = 0; + offset = 0; + do { + /* find out how many bytes the TPM returned in a row */ + i = 0; + do { + row_size = tpm_get_burst_count(locality); + if ( row_size > 0 ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_RSP_READ_TIME_OUT ); + if ( i > TPM_RSP_READ_TIME_OUT ) + { + printk(XENLOG_ERR"TPM: read rsp timeout\n"); + ret = false; + goto RelinquishControl; + } + + 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 + + tpm_send_cmd_ready_status(locality); + +RelinquishControl: + /* deactivate current locality */ + reg_acc._raw[0] = 0; + reg_acc.active_locality = 1; + write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + + return ret; +} + + +bool tpm_submit_cmd_crb( + uint32_t locality, uint8_t *in, u32 in_size, u8 *out, u32 *out_size) +{ + uint32_t i; + bool ret = true; + //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; + + 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 ( !tpm_validate_locality_crb(locality) ) + { + printk(XENLOG_WARNING + "TPM: CRB Interface Locality %d is not open\n", locality); + return false; + } + + if ( !tpm_wait_cmd_ready_crb(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 */ + i = 0; + do { + 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++; + } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); + + if ( i > TPM_DATA_AVAIL_TIME_OUT ) { + printk(XENLOG_ERR"TPM: wait for data available timeout\n"); + ret = false; + goto RelinquishControl; + } + + 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); + +RelinquishControl: + /* deactivate current locality */ + // reg_loc_ctrl._raw[0] = 0; + //reg_loc_ctrl.relinquish = 1; + //write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); + + return ret; + +} + +bool release_locality(uint32_t locality) +{ + uint32_t i; + tpm_reg_access_t reg_acc; + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: releasing locality %u\n", locality); +#endif + + if ( !tpm_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); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality == 0 ) + return true; + else + cpu_relax(); + i++; + } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); + + printk(XENLOG_INFO"TPM: access reg release locality timeout\n"); + return false; +} + +bool tpm_relinquish_locality_crb(uint32_t locality) +{ + uint32_t i; + tpm_reg_loc_state_t reg_loc_state; + tpm_reg_loc_ctrl_t reg_loc_ctrl; + +#ifdef TPM_TRACE + printk(XENLOG_INFO"TPM: releasing CRB_INF locality %u\n", locality); +#endif + + if ( !tpm_validate_locality_crb(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); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); + if ( reg_loc_state.loc_assigned == 0 ) + return true; + else + cpu_relax(); + i++; + } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); + + printk(XENLOG_INFO"TPM: CRB_INF release locality timeout\n"); + return false; +} + + + +bool is_tpm_crb(void) +{ + 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"); + if (g_tpm_family != TPM_IF_20_CRB ) g_tpm_family = TPM_IF_20_CRB; + return true; + } + if (crb_interface.interface_type == TPM_INTERFACE_ID_FIFO_20) + { + printk(XENLOG_INFO"TPM: TPM 2.0 FIFO interface is active...\n"); + if (g_tpm_family != TPM_IF_20_FIFO) + g_tpm_family = TPM_IF_20_FIFO; + } + return false; +} + + +bool prepare_tpm(void) +{ + /* + * must ensure TPM_ACCESS_0.activeLocality bit is clear + * (: locality is not active) + */ + if ( is_tpm_crb() ) + { + return tpm_relinquish_locality_crb(0); + } + else + { + return release_locality(0); + } +} + +bool tpm_request_locality_crb(uint32_t locality){ + + uint32_t i; + tpm_reg_loc_state_t reg_loc_state; + tpm_reg_loc_ctrl_t reg_loc_ctrl; + + /* 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); + + i = 0; + do { + 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(); + i++; + } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT); + + if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) + { + printk(XENLOG_ERR"TPM: access loc request use timeout\n"); + return false; + } + + return true; + +} + +bool tpm_workaround_crb(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 (!tpm_request_locality_crb(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 tpm_detect(void) +{ + struct tpm_if *tpm = get_tpm(); /* Don't leave tpm as NULL */ + const struct tpm_if_fp *tpm_fp; + + if (is_tpm_crb()) + { + printk(XENLOG_INFO"TPM: This is Intel PTT, TPM Family 0x%d\n", + g_tpm_family); + if ( tpm_validate_locality_crb(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_request_locality_crb(0)) + { + printk(XENLOG_ERR"TPM: CRB_INF Locality 0 request failed...\n"); + return false; + } + } + } + else + { + g_tpm_ver = TPM_VER_12; + tpm_fp = get_tpm_fp(); /* Don't leave tpm_fp as NULL */ + + if ( tpm_validate_locality(0) ) + printk(XENLOG_INFO"TPM: FIFO_INF Locality 0 is open\n"); + else + { + printk(XENLOG_ERR"TPM: FIFO_INF Locality 0 is not open\n"); + return false; + } + /* determine TPM family from command check */ + if ( tpm_fp->check() ) + { + g_tpm_family = TPM_IF_12; + printk(XENLOG_INFO"TPM: discrete TPM1.2 Family 0x%d\n", g_tpm_family); + } + else + { + g_tpm_family = TPM_IF_20_FIFO; + printk(XENLOG_INFO"TPM: discrete TPM2.0 Family 0x%d\n", g_tpm_family); + } + } + + if (g_tpm_family == TPM_IF_12) + g_tpm_ver = TPM_VER_12; + if (g_tpm_family == TPM_IF_20_FIFO) + g_tpm_ver = TPM_VER_20; + if (g_tpm_family == TPM_IF_20_CRB) + g_tpm_ver = TPM_VER_20; + + tpm_fp = get_tpm_fp(); + return tpm_fp->init(tpm); +} + +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 &g_tpm; +} + +const struct tpm_if_fp *get_tpm_fp(void) +{ + if ( g_tpm_ver == TPM_VER_12 ) + return &tpm_12_if_fp; + else if ( g_tpm_ver == TPM_VER_20) + return &tpm_20_if_fp; + + return NULL; + +} +/* + * 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 00000000000..2e43421f92b --- /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_IF_12 0 +#define TPM_IF_20_FIFO 1 +#define TPM_IF_20_CRB 2 + +#define TPM_VER_UNKNOWN 0 +#define TPM_VER_12 1 +#define TPM_VER_20 2 + +#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_UNIT (0x100000 / 330) /* ~1ms, 1 tpm r/w need > 330ns */ +#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 + +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 and expect bits are valid */ + 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 and expect bits are + valid */ + 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_if_fp; + +struct tpm_if { +#define TPM12_VER_MAJOR 1 +#define TPM12_VER_MINOR 2 +#define TPM20_VER_MAJOR 2 +#define TPM20_VER_MINOR 0 + uint8_t major; + uint8_t minor; + 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; +}; + +struct tpm_if_fp { + + 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); +}; + +extern const struct tpm_if_fp tpm_12_if_fp; +extern const struct tpm_if_fp tpm_20_if_fp; +extern uint8_t g_tpm_ver; +extern uint8_t g_tpm_family; + +bool tpm_validate_locality(uint32_t locality); +bool tpm_validate_locality_crb(uint32_t locality); +bool release_locality(uint32_t locality); +bool prepare_tpm(void); +bool tpm_detect(void); +void tpm_print(struct tpm_if *ti); +bool tpm_submit_cmd( + uint32_t locality, uint8_t *in, uint32_t in_size, uint8_t *out, + uint32_t *out_size); +bool tpm_submit_cmd_crb( + uint32_t locality, uint8_t *in, uint32_t in_size, uint8_t *out, + uint32_t *out_size); +bool tpm_wait_cmd_ready(uint32_t locality); +bool tpm_request_locality_crb(uint32_t locality); +bool tpm_relinquish_locality_crb(uint32_t locality); +bool txt_is_launched(void); +bool tpm_workaround_crb(void); +struct tpm_if *get_tpm(void); +const struct tpm_if_fp *get_tpm_fp(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 00000000000..9d0c9dcc3a0 --- /dev/null +++ b/xen/drivers/security/tpm/tpm_12.c @@ -0,0 +1,2008 @@ +/* + * 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) +{ + 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_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 ( !tpm_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->major = TPM12_VER_MAJOR; + ti->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_if_fp tpm_12_if_fp = { + .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 00000000000..94920c06351 --- /dev/null +++ b/xen/drivers/security/tpm/tpm_20.c @@ -0,0 +1,3122 @@ +/* + * 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; +} + +/* + * 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; +} + +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_pcr_read( + uint32_t locality, tpm_pcr_read_in *in, tpm_pcr_read_out *out) +{ + uint32_t ret; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = sizeof(*out); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = sizeof(*out); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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)); + + /* + * 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)); + + rsp_size = sizeof(*out); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = sizeof(*out); + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = RSP_HEAD_SIZE + sizeof(*out); + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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)); + + /* + * 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)); + + rsp_size = sizeof(*out); + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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)); + + /* + * 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)); + + rsp_size = sizeof(*out); + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = sizeof(rsp_buf); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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); + + /* 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)); + + rsp_size = sizeof(*out); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = sizeof(*out); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = sizeof(*out); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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) +{ + uint32_t ret; + uint32_t cmd_size, rsp_size; + void *other; + + reverse_copy_header(TPM_CC_Shutdown, 0); + + other = (void *)cmd_buf + CMD_HEAD_SIZE; + reverse_copy_in(other, type); + + /* + * 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)); + + rsp_size = RSP_HEAD_SIZE; + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(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; +} + +uint32_t handle2048 = 0; +//static const char auth_str[] = "test"; + +static uint32_t _tpm20_create_primary( + uint32_t locality, tpm_create_primary_in *in, tpm_create_primary_out *out) +{ + uint32_t ret; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = sizeof(*out); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; +} + + +/* 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; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = sizeof(rsp_buf); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = sizeof(*out); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = sizeof(*out); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = sizeof(*out); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = RSP_HEAD_SIZE + sizeof(*out); + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + 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; + uint32_t cmd_size, rsp_size; + 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); + + /* + * 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)); + + rsp_size = RSP_HEAD_SIZE; + + if (g_tpm_family == TPM_IF_20_FIFO) + { + if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) + return TPM_RC_FAILURE; + } + if (g_tpm_family == TPM_IF_20_CRB) + { + if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, + &rsp_size)) + return TPM_RC_FAILURE; + } + + reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + + 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_NR_PCRS 24 +#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; +} + +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; + tpm_create_primary_in primary_in; + tpm_create_primary_out primary_out; + + if ( ti == NULL ) + return false; + + ti->cur_loc = 0; + + /* init version */ + ti->major = TPM20_VER_MAJOR; + ti->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; + } + + if (handle2048 != 0) + goto 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); +out: + tpm_print(ti); + return true; +} + +const struct tpm_if_fp tpm_20_if_fp = { + .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 00000000000..8343bb8b00c --- /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: + */ From ba0a1e2b4cc4a47b7994a47a44f4abcdc1f74bd1 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Fri, 27 Jan 2023 09:27:50 -0500 Subject: [PATCH 04/10] tpm: an initial abstractiong of hw interface Tboot, from which the code came, is only concerned for x86 systems. Typically on x86 systems, the TPM is accessed using the MMIO hardware interface for which there are two ABIs, FIFO and CRB. This commit looks to refactor the hardware interface logic to enable the ability to support other hardware interfaces, such as the Mobile TPM interface typically used on Arm. Signed-off-by: Daniel P. Smith --- xen/drivers/security/tpm/Makefile | 1 + xen/drivers/security/tpm/tpm.c | 930 ++-------------------------- xen/drivers/security/tpm/tpm.h | 119 ++-- xen/drivers/security/tpm/tpm_12.c | 11 +- xen/drivers/security/tpm/tpm_20.c | 480 ++------------ xen/drivers/security/tpm/tpm_mmio.c | 886 ++++++++++++++++++++++++++ 6 files changed, 1038 insertions(+), 1389 deletions(-) create mode 100644 xen/drivers/security/tpm/tpm_mmio.c diff --git a/xen/drivers/security/tpm/Makefile b/xen/drivers/security/tpm/Makefile index 2655abff33f..96f032c5336 100644 --- a/xen/drivers/security/tpm/Makefile +++ b/xen/drivers/security/tpm/Makefile @@ -1,3 +1,4 @@ obj-y += tpm.o +obj-y += tpm_mmio.o obj-y += tpm_12.o obj-y += tpm_20.o diff --git a/xen/drivers/security/tpm/tpm.c b/xen/drivers/security/tpm/tpm.c index 1b23e6ab190..37f2e2f5097 100644 --- a/xen/drivers/security/tpm/tpm.c +++ b/xen/drivers/security/tpm/tpm.c @@ -42,8 +42,10 @@ #include "tpm.h" -uint8_t g_tpm_ver = TPM_VER_UNKNOWN; -struct tpm_if g_tpm = { +static struct tpm_if __tpm = { + .version = { + .version = TPM_VER_UNKNOWN, + }, .cur_loc = 0, .timeout.timeout_a = TIMEOUT_A, .timeout.timeout_b = TIMEOUT_B, @@ -54,911 +56,75 @@ struct tpm_if g_tpm = { 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); -/* 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; - -uint8_t g_tpm_family = 0; - -/* 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 \ - (TIMEOUT_UNIT *get_tpm()->timeout.timeout_a) /* according to spec */ -#define TPM_CMD_READY_TIME_OUT \ - (TIMEOUT_UNIT *get_tpm()->timeout.timeout_b) /* according to spec */ -#define TPM_CMD_WRITE_TIME_OUT \ - (TIMEOUT_UNIT *get_tpm()->timeout.timeout_d) /* let it long enough */ -#define TPM_DATA_AVAIL_TIME_OUT \ - (TIMEOUT_UNIT *get_tpm()->timeout.timeout_c) /* let it long enough */ -#define TPM_RSP_READ_TIME_OUT \ - (TIMEOUT_UNIT *get_tpm()->timeout.timeout_d) /* let it long enough */ -#define TPM_VALIDATE_LOCALITY_TIME_OUT 0x100 - -#define read_tpm_sts_reg(locality) { \ -if ( g_tpm_family == 0 ) \ - 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 ( g_tpm_family == 0 ) \ - write_tpm_reg(locality, TPM_REG_STS, g_reg_sts_12); \ -else \ - write_tpm_reg(locality, TPM_REG_STS, g_reg_sts_20); \ -} - -static void tpm_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 tpm_send_cmd_ready_status_crb(uint32_t locality) -{ - uint32_t i = 0; - tpm_reg_ctrl_request_t reg_ctrl_request; - tpm_reg_ctrl_sts_t reg_ctrl_sts; - - 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); - - do { - 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++; - } while ( i <= TPM_DATA_AVAIL_TIME_OUT); - - if ( i > TPM_DATA_AVAIL_TIME_OUT ) - { - 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 tpm_check_cmd_ready_status_crb(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 tpm_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 void tpm_print_status_register(void) -{ - if ( g_tpm_family == 0 ) - { - 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_da_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; -} - -static void tpm_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); -} - -bool tpm_validate_locality(uint32_t locality) -{ - uint32_t i; - tpm_reg_access_t reg_acc; - - for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) - { - /* - * 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 ( i <= 0 ) - printk(XENLOG_ERR"TPM: tpm_validate_locality timeout\n"); - - return false; -} - -bool tpm_validate_locality_crb(uint32_t locality) -{ - uint32_t i; - tpm_reg_loc_state_t reg_loc_state; - - for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) - { - /* - * 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 tpm_wait_cmd_ready(uint32_t locality) -{ - uint32_t i; - tpm_reg_access_t reg_acc; - -/* - * some tpms doesn't always return 1 for reg_acc.tpm_reg_valid_sts - * and this bit was checked in tpm_validate_locality() already, - * so safe to skip the check here - */ -#if 0 - /* ensure the contents of the ACCESS register are valid */ - read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); -#ifdef TPM_TRACE - printk(XENLOG_INFO"TPM: Access reg content: 0x%02x\n", (uint32_t)reg_acc._raw[0]); -#endif - if ( reg_acc.tpm_reg_valid_sts == 0 ) - { - printk(XENLOG_ERR"TPM: Access reg not valid\n"); - return false; - } -#endif - /* 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); - - i = 0; - do { - read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); - if ( reg_acc.active_locality == 1 ) - break; - else - cpu_relax(); - i++; - } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT); - - if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) - { - printk(XENLOG_ERR"TPM: FIFO_INF access reg request use timeout\n"); - return false; - } - - /* ensure the TPM is ready to accept a command */ -#ifdef TPM_TRACE - printk(XENLOG_INFO"TPM: wait for cmd ready \n"); -#endif - i = 0; - do { - tpm_send_cmd_ready_status(locality); - cpu_relax(); - /* then see if it has */ - - if ( tpm_check_cmd_ready_status(locality) ) - break; - else - cpu_relax(); - i++; - } while ( i <= TPM_CMD_READY_TIME_OUT ); -#ifdef TPM_TRACE - printk(XENLOG_INFO"\n"); -#endif - - if ( i > TPM_CMD_READY_TIME_OUT ) - { - tpm_print_status_register(); - printk(XENLOG_INFO"TPM: tpm timeout for command_ready\n"); - goto RelinquishControl; - } - - return true; - -RelinquishControl: - /* deactivate current locality */ - reg_acc._raw[0] = 0; - reg_acc.active_locality = 1; - write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); - - return false; -} - -static bool tpm_wait_cmd_ready_crb(uint32_t locality) -{ - uint32_t i; - - /* ensure the TPM is ready to accept a command */ -#ifdef TPM_TRACE - printk(XENLOG_INFO"TPM: wait for cmd ready \n"); -#endif - tpm_send_cmd_ready_status_crb(locality); - i = 0; - do { - if ( tpm_check_cmd_ready_status_crb(locality) ) - break; - else - cpu_relax(); - i++; - } while ( i <= TPM_CMD_READY_TIME_OUT ); - - if ( i > TPM_CMD_READY_TIME_OUT ) - { - //tpm_print_status_register(); - printk(XENLOG_INFO"TPM: tpm timeout for command_ready\n"); - goto RelinquishControl; - } - - return true; - -RelinquishControl: - /* deactivate current locality */ - //tpm_reg_loc_ctrl_t reg_loc_ctrl; - //reg_loc_ctrl._raw[0] = 0; - //reg_loc_ctrl.relinquish = 1; - //write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); - - return false; -} - -bool tpm_submit_cmd( - uint32_t locality, uint8_t *in, u32 in_size, u8 *out, u32 *out_size) -{ - uint32_t i, rsp_size, offset; - uint16_t row_size; - tpm_reg_access_t reg_acc; - bool ret = true; - - 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 ( !tpm_validate_locality(locality) ) - { - printk(XENLOG_WARNING"TPM: Locality %d is not open\n", locality); - return false; - } - - if ( !tpm_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 { - i = 0; - do { - /* 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(); - i++; - } while ( i <= TPM_CMD_WRITE_TIME_OUT ); - if ( i > TPM_CMD_WRITE_TIME_OUT ) - { - printk(XENLOG_ERR"TPM: write cmd timeout\n"); - ret = false; - goto RelinquishControl; - } - - 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 ); - - i = 0; - do { - if ( tpm_check_expect_status(locality) ) - break; - else - cpu_relax(); - i++; - } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); - if ( i > TPM_DATA_AVAIL_TIME_OUT ) - { - printk(XENLOG_ERR"TPM: wait for expect becoming 0 timeout\n"); - ret = false; - goto RelinquishControl; - } - - /* command has been written to the TPM, it is time to execute it. */ - tpm_execute_cmd(locality); - - /* check for data available */ - i = 0; - do { - if ( tpm_check_da_status(locality) ) - break; - else - cpu_relax(); - i++; - } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); - if ( i > TPM_DATA_AVAIL_TIME_OUT ) { - printk(XENLOG_ERR"TPM: wait for data available timeout\n"); - ret = false; - goto RelinquishControl; - } - - rsp_size = 0; - offset = 0; - do { - /* find out how many bytes the TPM returned in a row */ - i = 0; - do { - row_size = tpm_get_burst_count(locality); - if ( row_size > 0 ) - break; - else - cpu_relax(); - i++; - } while ( i <= TPM_RSP_READ_TIME_OUT ); - if ( i > TPM_RSP_READ_TIME_OUT ) - { - printk(XENLOG_ERR"TPM: read rsp timeout\n"); - ret = false; - goto RelinquishControl; - } - - 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 - - tpm_send_cmd_ready_status(locality); - -RelinquishControl: - /* deactivate current locality */ - reg_acc._raw[0] = 0; - reg_acc.active_locality = 1; - write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); - - return ret; -} - - -bool tpm_submit_cmd_crb( - uint32_t locality, uint8_t *in, u32 in_size, u8 *out, u32 *out_size) -{ - uint32_t i; - bool ret = true; - //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; - - 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 ( !tpm_validate_locality_crb(locality) ) - { - printk(XENLOG_WARNING - "TPM: CRB Interface Locality %d is not open\n", locality); - return false; - } - - if ( !tpm_wait_cmd_ready_crb(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 */ - i = 0; - do { - 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++; - } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); - - if ( i > TPM_DATA_AVAIL_TIME_OUT ) { - printk(XENLOG_ERR"TPM: wait for data available timeout\n"); - ret = false; - goto RelinquishControl; - } - - 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); - -RelinquishControl: - /* deactivate current locality */ - // reg_loc_ctrl._raw[0] = 0; - //reg_loc_ctrl.relinquish = 1; - //write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); - - return ret; - -} - -bool release_locality(uint32_t locality) -{ - uint32_t i; - tpm_reg_access_t reg_acc; - -#ifdef TPM_TRACE - printk(XENLOG_INFO"TPM: releasing locality %u\n", locality); -#endif - - if ( !tpm_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); - - i = 0; - do { - read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); - if ( reg_acc.active_locality == 0 ) - return true; - else - cpu_relax(); - i++; - } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); - - printk(XENLOG_INFO"TPM: access reg release locality timeout\n"); - return false; -} - -bool tpm_relinquish_locality_crb(uint32_t locality) -{ - uint32_t i; - tpm_reg_loc_state_t reg_loc_state; - tpm_reg_loc_ctrl_t reg_loc_ctrl; - -#ifdef TPM_TRACE - printk(XENLOG_INFO"TPM: releasing CRB_INF locality %u\n", locality); -#endif - - if ( !tpm_validate_locality_crb(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); - - i = 0; - do { - read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); - if ( reg_loc_state.loc_assigned == 0 ) - return true; - else - cpu_relax(); - i++; - } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); - - printk(XENLOG_INFO"TPM: CRB_INF release locality timeout\n"); - return false; -} - - - -bool is_tpm_crb(void) -{ - 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"); - if (g_tpm_family != TPM_IF_20_CRB ) g_tpm_family = TPM_IF_20_CRB; - return true; - } - if (crb_interface.interface_type == TPM_INTERFACE_ID_FIFO_20) - { - printk(XENLOG_INFO"TPM: TPM 2.0 FIFO interface is active...\n"); - if (g_tpm_family != TPM_IF_20_FIFO) - g_tpm_family = TPM_IF_20_FIFO; - } - return false; -} - - -bool prepare_tpm(void) -{ - /* - * must ensure TPM_ACCESS_0.activeLocality bit is clear - * (: locality is not active) - */ - if ( is_tpm_crb() ) - { - return tpm_relinquish_locality_crb(0); - } - else - { - return release_locality(0); - } -} - -bool tpm_request_locality_crb(uint32_t locality){ - - uint32_t i; - tpm_reg_loc_state_t reg_loc_state; - tpm_reg_loc_ctrl_t reg_loc_ctrl; - - /* 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); - - i = 0; - do { - 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(); - i++; - } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT); - - if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) - { - printk(XENLOG_ERR"TPM: access loc request use timeout\n"); - return false; - } - - return true; - -} - -bool tpm_workaround_crb(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 (!tpm_request_locality_crb(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 tpm_detect(void) { struct tpm_if *tpm = get_tpm(); /* Don't leave tpm as NULL */ - const struct tpm_if_fp *tpm_fp; - if (is_tpm_crb()) + /* 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: This is Intel PTT, TPM Family 0x%d\n", - g_tpm_family); - if ( tpm_validate_locality_crb(0) ) + 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_request_locality_crb(0)) + if ( !tpm->hw->request_locality(0) ) { printk(XENLOG_ERR"TPM: CRB_INF Locality 0 request failed...\n"); + tpm->cmds = NULL; return false; } } } else { - g_tpm_ver = TPM_VER_12; - tpm_fp = get_tpm_fp(); /* Don't leave tpm_fp as NULL */ - - if ( tpm_validate_locality(0) ) + 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 is not open\n"); + 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_fp->check() ) + if ( tpm_12_cmds.check() ) { - g_tpm_family = TPM_IF_12; - printk(XENLOG_INFO"TPM: discrete TPM1.2 Family 0x%d\n", g_tpm_family); + tpm->family = TPM_IF_12; + printk(XENLOG_INFO"TPM: discrete TPM1.2 Family 0x%d\n", tpm->family); } else { - g_tpm_family = TPM_IF_20_FIFO; - printk(XENLOG_INFO"TPM: discrete TPM2.0 Family 0x%d\n", g_tpm_family); + tpm->family = TPM_IF_20_FIFO; + printk(XENLOG_INFO"TPM: discrete TPM2.0 Family 0x%d\n", tpm->family); } } - if (g_tpm_family == TPM_IF_12) - g_tpm_ver = TPM_VER_12; - if (g_tpm_family == TPM_IF_20_FIFO) - g_tpm_ver = TPM_VER_20; - if (g_tpm_family == TPM_IF_20_CRB) - g_tpm_ver = TPM_VER_20; + 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; + } - tpm_fp = get_tpm_fp(); - return tpm_fp->init(tpm); + return tpm->cmds->init(tpm); } void tpm_print(struct tpm_if *ti) @@ -976,19 +142,9 @@ void tpm_print(struct tpm_if *ti) struct tpm_if *get_tpm(void) { - return &g_tpm; + return &__tpm; } -const struct tpm_if_fp *get_tpm_fp(void) -{ - if ( g_tpm_ver == TPM_VER_12 ) - return &tpm_12_if_fp; - else if ( g_tpm_ver == TPM_VER_20) - return &tpm_20_if_fp; - - return NULL; - -} /* * Local variables: * mode: C diff --git a/xen/drivers/security/tpm/tpm.h b/xen/drivers/security/tpm/tpm.h index 2e43421f92b..bb928b9c190 100644 --- a/xen/drivers/security/tpm/tpm.h +++ b/xen/drivers/security/tpm/tpm.h @@ -44,13 +44,15 @@ /* 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 1 -#define TPM_VER_20 2 +#define TPM_VER_12 0x0102 +#define TPM_VER_20 0x0200 #define TPM_INTERFACE_ID_FIFO_20 0x0 #define TPM_INTERFACE_ID_CRB 0x1 @@ -200,7 +202,7 @@ typedef union { 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 and expect bits are valid */ + 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; @@ -215,8 +217,7 @@ typedef union { 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 and expect bits are - valid */ + 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; @@ -438,44 +439,16 @@ typedef hash_t tpm_digest_t; typedef tpm_digest_t tpm_pcr_value_t; struct tpm_if; -struct tpm_if_fp; -struct tpm_if { -#define TPM12_VER_MAJOR 1 -#define TPM12_VER_MINOR 2 -#define TPM20_VER_MAJOR 2 -#define TPM20_VER_MINOR 0 - uint8_t major; - uint8_t minor; - 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; +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_if_fp { +struct tpm_cmd_if { bool (*init)(struct tpm_if *ti); @@ -525,30 +498,56 @@ struct tpm_if_fp { bool (*check)(void); }; -extern const struct tpm_if_fp tpm_12_if_fp; -extern const struct tpm_if_fp tpm_20_if_fp; -extern uint8_t g_tpm_ver; -extern uint8_t g_tpm_family; +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; -bool tpm_validate_locality(uint32_t locality); -bool tpm_validate_locality_crb(uint32_t locality); -bool release_locality(uint32_t locality); -bool prepare_tpm(void); +void mmio_detect_interface(struct tpm_if *tpm); bool tpm_detect(void); void tpm_print(struct tpm_if *ti); -bool tpm_submit_cmd( - uint32_t locality, uint8_t *in, uint32_t in_size, uint8_t *out, - uint32_t *out_size); -bool tpm_submit_cmd_crb( - uint32_t locality, uint8_t *in, uint32_t in_size, uint8_t *out, - uint32_t *out_size); -bool tpm_wait_cmd_ready(uint32_t locality); -bool tpm_request_locality_crb(uint32_t locality); -bool tpm_relinquish_locality_crb(uint32_t locality); -bool txt_is_launched(void); -bool tpm_workaround_crb(void); struct tpm_if *get_tpm(void); -const struct tpm_if_fp *get_tpm_fp(void); //#define TPM_UNIT_TEST 1 diff --git a/xen/drivers/security/tpm/tpm_12.c b/xen/drivers/security/tpm/tpm_12.c index 9d0c9dcc3a0..de7438e4c61 100644 --- a/xen/drivers/security/tpm/tpm_12.c +++ b/xen/drivers/security/tpm/tpm_12.c @@ -142,6 +142,7 @@ 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; @@ -172,7 +173,7 @@ static uint32_t _tpm12_submit_cmd( rsp_size = RSP_HEAD_SIZE + *out_size; rsp_size = (rsp_size > TPM_RSP_SIZE_MAX) ? TPM_RSP_SIZE_MAX: rsp_size; - if ( !tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size) ) + if ( !tpm->hw->submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size) ) return TPM_FAIL; /* @@ -1727,7 +1728,7 @@ static bool cf_check tpm12_init(struct tpm_if *ti) ti->cur_loc = 0; locality = ti->cur_loc; - if ( !tpm_validate_locality(locality) ) + if ( !ti->hw->validate_locality(locality) ) { printk(XENLOG_WARNING"TPM is not available.\n"); return false; @@ -1816,8 +1817,8 @@ static bool cf_check tpm12_init(struct tpm_if *ti) } /* init version */ - ti->major = TPM12_VER_MAJOR; - ti->minor = TPM12_VER_MINOR; + ti->version.major = TPM12_VER_MAJOR; + ti->version.minor = TPM12_VER_MINOR; /* init supported alg list */ ti->banks = 1; @@ -1980,7 +1981,7 @@ static bool cf_check tpm12_check(void) return ( ret == TPM_BAD_ORDINAL ); } -const struct tpm_if_fp tpm_12_if_fp = { +const struct tpm_cmd_if tpm_12_cmds = { .init = tpm12_init, .pcr_read = tpm12_pcr_read, .pcr_extend = tpm12_pcr_extend, diff --git a/xen/drivers/security/tpm/tpm_20.c b/xen/drivers/security/tpm/tpm_20.c index 94920c06351..95235d66d38 100644 --- a/xen/drivers/security/tpm/tpm_20.c +++ b/xen/drivers/security/tpm/tpm_20.c @@ -1122,18 +1122,11 @@ static bool reverse_copy_context_out(TPMS_CONTEXT *context, void **other) return true; } -static uint32_t _tpm20_pcr_read( - uint32_t locality, tpm_pcr_read_in *in, tpm_pcr_read_out *out) +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; - uint32_t cmd_size, rsp_size; - 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); /* * Now set the command size field, now that we know the size of the whole @@ -1142,21 +1135,27 @@ static uint32_t _tpm20_pcr_read( cmd_size = (uint8_t *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); - rsp_size = sizeof(*out); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } + 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; @@ -1181,7 +1180,6 @@ static uint32_t _tpm20_pcr_extend( uint32_t locality, tpm_pcr_extend_in *in, tpm_pcr_extend_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; @@ -1194,28 +1192,7 @@ static uint32_t _tpm20_pcr_extend( reverse_copy_digest_value_in(&other, &in->digests); - /* - * 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)); - - rsp_size = sizeof(*out); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -1234,7 +1211,6 @@ static uint32_t _tpm20_pcr_event( uint32_t locality, tpm_pcr_event_in *in, tpm_pcr_event_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; @@ -1247,28 +1223,7 @@ static uint32_t _tpm20_pcr_event( other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->data)); - /* - * 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)); - - rsp_size = sizeof(*out); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -1291,7 +1246,6 @@ static uint32_t _tpm20_pcr_reset( uint32_t locality, tpm_pcr_reset_in *in, tpm_pcr_reset_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; @@ -1303,27 +1257,7 @@ static uint32_t _tpm20_pcr_reset( other += sizeof(uint32_t); reverse_copy_sessions_in(&other, &in->sessions); - /* - * 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)); - - rsp_size = sizeof(*out); - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -1343,7 +1277,6 @@ static uint32_t _tpm20_sequence_start( uint32_t locality, tpm_sequence_start_in *in, tpm_sequence_start_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; @@ -1354,27 +1287,7 @@ static uint32_t _tpm20_sequence_start( reverse_copy_in(other, in->hash_alg); - /* - * 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)); - - rsp_size = RSP_HEAD_SIZE + sizeof(*out); - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -1392,7 +1305,6 @@ static uint32_t _tpm20_sequence_update( uint32_t locality, tpm_sequence_update_in *in, tpm_sequence_update_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; @@ -1406,27 +1318,7 @@ static uint32_t _tpm20_sequence_update( other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->buf)); - /* - * 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)); - - rsp_size = sizeof(*out); - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -1446,7 +1338,6 @@ static uint32_t _tpm20_sequence_complete( uint32_t locality, tpm_sequence_complete_in *in, tpm_sequence_complete_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; @@ -1461,27 +1352,7 @@ static uint32_t _tpm20_sequence_complete( other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->buf)); - /* - * 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)); - - rsp_size = sizeof(*out); - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -1504,7 +1375,6 @@ static uint32_t _tpm20_nv_read( uint32_t locality, tpm_nv_read_in *in, tpm_nv_read_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; uint16_t size; @@ -1520,28 +1390,7 @@ static uint32_t _tpm20_nv_read( reverse_copy_in(other, in->size); reverse_copy_in(other, in->offset); - /* - * 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)); - - rsp_size = sizeof(rsp_buf); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -1567,7 +1416,6 @@ static uint32_t _tpm20_nv_write( uint32_t locality, tpm_nv_write_in *in, tpm_nv_write_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; @@ -1583,25 +1431,7 @@ static uint32_t _tpm20_nv_write( reverse_copy_in(other, in->offset); - /* 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)); - - rsp_size = sizeof(*out); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -1621,7 +1451,6 @@ 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; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; uint16_t size; @@ -1631,28 +1460,7 @@ static uint32_t _tpm20_nv_read_public( other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->index); - /* - * 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)); - - rsp_size = sizeof(*out); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -1691,7 +1499,6 @@ static uint32_t _tpm20_get_random( uint32_t locality, tpm_get_random_in *in, tpm_get_random_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; uint16_t size; @@ -1701,28 +1508,7 @@ static uint32_t _tpm20_get_random( other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->bytes_req); - /* - * 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)); - - rsp_size = sizeof(*out); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -1743,8 +1529,6 @@ static uint32_t _tpm20_get_random( static uint32_t _tpm20_shutdown(uint32_t locality, uint16_t type) { - uint32_t ret; - uint32_t cmd_size, rsp_size; void *other; reverse_copy_header(TPM_CC_Shutdown, 0); @@ -1752,29 +1536,7 @@ static uint32_t _tpm20_shutdown(uint32_t locality, uint16_t type) other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, type); - /* - * 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)); - - rsp_size = RSP_HEAD_SIZE; - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(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; + return _tpm20_send_cmd(other, locality, RSP_HEAD_SIZE); } uint32_t handle2048 = 0; @@ -1784,7 +1546,6 @@ static uint32_t _tpm20_create_primary( uint32_t locality, tpm_create_primary_in *in, tpm_create_primary_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; uint16_t sensitive_size; void *sensitive_size_ptr; @@ -1819,28 +1580,7 @@ static uint32_t _tpm20_create_primary( /* Copy creationPCR */ reverse_copy_pcr_selection_in(&other, &in->creation_pcr); - /* - * 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)); - - rsp_size = sizeof(*out); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -1893,7 +1633,6 @@ static uint32_t _tpm20_create( uint32_t locality, tpm_create_in *in, tpm_create_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; uint16_t sensitive_size; void *sensitive_size_ptr; @@ -1927,28 +1666,7 @@ static uint32_t _tpm20_create( /* Copy creationPCR */ reverse_copy_pcr_selection_in(&other, &in->creation_pcr); - /* - * 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)); - - rsp_size = sizeof(rsp_buf); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -1995,7 +1713,6 @@ static uint32_t _tpm20_load( uint32_t locality, tpm_load_in *in, tpm_load_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; uint16_t size; @@ -2011,28 +1728,7 @@ static uint32_t _tpm20_load( reverse_copy_public_in(&other, &in->public); - /* - * 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)); - - rsp_size = sizeof(*out); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -2061,7 +1757,6 @@ static uint32_t _tpm20_unseal( uint32_t locality, tpm_unseal_in *in, tpm_unseal_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; uint16_t size; @@ -2073,28 +1768,7 @@ static uint32_t _tpm20_unseal( reverse_copy_sessions_in(&other, &in->sessions); - /* - * 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)); - - rsp_size = sizeof(*out); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -2121,7 +1795,6 @@ static uint32_t _tpm20_context_save( uint32_t locality, tpm_contextsave_in *in, tpm_contextsave_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; @@ -2129,28 +1802,7 @@ static uint32_t _tpm20_context_save( other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->saveHandle); - /* - * 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)); - - rsp_size = sizeof(*out); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -2171,7 +1823,6 @@ static uint32_t _tpm20_context_load( uint32_t locality, tpm_contextload_in *in, tpm_contextload_out *out) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; @@ -2180,28 +1831,7 @@ static uint32_t _tpm20_context_load( reverse_copy_context_in(&other, &in->context); - /* - * 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)); - - rsp_size = RSP_HEAD_SIZE + sizeof(*out); - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); + ret = _tpm20_send_cmd(other, locality, sizeof(*out)); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -2219,7 +1849,6 @@ static uint32_t _tpm20_context_load( static uint32_t _tpm20_context_flush(uint32_t locality, tpm_flushcontext_in *in) { uint32_t ret; - uint32_t cmd_size, rsp_size; uint16_t rsp_tag; void *other; @@ -2228,29 +1857,7 @@ static uint32_t _tpm20_context_flush(uint32_t locality, tpm_flushcontext_in *in) other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->flushHandle); - /* - * 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)); - - rsp_size = RSP_HEAD_SIZE; - - if (g_tpm_family == TPM_IF_20_FIFO) - { - if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) - return TPM_RC_FAILURE; - } - if (g_tpm_family == TPM_IF_20_CRB) - { - if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, - &rsp_size)) - return TPM_RC_FAILURE; - } - - reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); - + ret = _tpm20_send_cmd(other, locality, RSP_HEAD_SIZE); if ( ret != TPM_RC_SUCCESS ) return ret; @@ -2860,7 +2467,6 @@ static uint32_t cf_check tpm20_save_state(struct tpm_if *ti, uint32_t locality) return ret; } -#define TPM_NR_PCRS 24 #define TPM_PCR_RESETABLE_MIN 16 static bool cf_check tpm20_cap_pcrs(struct tpm_if *ti, uint32_t locality, int pcr) { @@ -2971,8 +2577,8 @@ static bool cf_check tpm20_init(struct tpm_if *ti) ti->cur_loc = 0; /* init version */ - ti->major = TPM20_VER_MAJOR; - ti->minor = TPM20_VER_MINOR; + ti->version.major = TPM20_VER_MAJOR; + ti->version.minor = TPM20_VER_MINOR; /* init timeouts value */ ti->timeout.timeout_a = TIMEOUT_A; @@ -3091,7 +2697,7 @@ static bool cf_check tpm20_init(struct tpm_if *ti) return true; } -const struct tpm_if_fp tpm_20_if_fp = { +const struct tpm_cmd_if tpm_20_cmds = { .init = tpm20_init, .pcr_read = tpm20_pcr_read, .pcr_extend = tpm20_pcr_extend, diff --git a/xen/drivers/security/tpm/tpm_mmio.c b/xen/drivers/security/tpm/tpm_mmio.c new file mode 100644 index 00000000000..a23202c690b --- /dev/null +++ b/xen/drivers/security/tpm/tpm_mmio.c @@ -0,0 +1,886 @@ +/* + * 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 "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 \ + (TIMEOUT_UNIT *get_tpm()->timeout.timeout_a) /* according to spec */ +#define TPM_CMD_READY_TIME_OUT \ + (TIMEOUT_UNIT *get_tpm()->timeout.timeout_b) /* according to spec */ +#define TPM_CMD_WRITE_TIME_OUT \ + (TIMEOUT_UNIT *get_tpm()->timeout.timeout_d) /* let it long enough */ +#define TPM_DATA_AVAIL_TIME_OUT \ + (TIMEOUT_UNIT *get_tpm()->timeout.timeout_c) /* let it long enough */ +#define TPM_RSP_READ_TIME_OUT \ + (TIMEOUT_UNIT *get_tpm()->timeout.timeout_d) /* let it long enough */ +#define TPM_VALIDATE_LOCALITY_TIME_OUT 0x100 + +#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_da_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) +{ + uint32_t i; + 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); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality == 1 ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT); + + if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) + { + 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) +{ + uint32_t i; + tpm_reg_access_t reg_acc; + + for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) + { + /* + * 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 ( i <= 0 ) + printk(XENLOG_ERR"TPM: tpm_validate_locality timeout\n"); + + return false; +} + +static bool cf_check fifo_release_locality(uint32_t locality) +{ + 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); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality == 0 ) + return true; + else + cpu_relax(); + i++; + } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); + + 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) +{ + uint32_t i; + + /* 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 + + i = 0; + do { + 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++; + } while ( i <= TPM_CMD_READY_TIME_OUT ); +#ifdef TPM_TRACE + printk(XENLOG_INFO"\n"); +#endif + + if ( i > TPM_CMD_READY_TIME_OUT ) + { + 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 i, rsp_size, offset; + uint16_t row_size; + + 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 { + i = 0; + do { + /* 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(); + i++; + } while ( i <= TPM_CMD_WRITE_TIME_OUT ); + if ( i > TPM_CMD_WRITE_TIME_OUT ) + { + 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 ); + + i = 0; + do { + if ( tpm_check_expect_status(locality) ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); + if ( i > TPM_DATA_AVAIL_TIME_OUT ) + { + 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 */ + i = 0; + do { + if ( tpm_check_da_status(locality) ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); + if ( i > TPM_DATA_AVAIL_TIME_OUT ) { + 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 */ + i = 0; + do { + row_size = tpm_get_burst_count(locality); + if ( row_size > 0 ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_RSP_READ_TIME_OUT ); + if ( i > TPM_RSP_READ_TIME_OUT ) + { + 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) +{ + uint32_t i; + tpm_reg_loc_state_t reg_loc_state; + tpm_reg_loc_ctrl_t reg_loc_ctrl; + + /* 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); + + i = 0; + do { + 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(); + i++; + } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); + + if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) + { + 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) +{ + uint32_t i; + tpm_reg_loc_state_t reg_loc_state; + + for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) + { + /* + * 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) +{ + uint32_t i; + tpm_reg_loc_state_t reg_loc_state; + tpm_reg_loc_ctrl_t reg_loc_ctrl; + +#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); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); + if ( reg_loc_state.loc_assigned == 0 ) + return true; + else + cpu_relax(); + i++; + } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); + + printk(XENLOG_INFO"TPM: CRB_INF release locality timeout\n"); + return false; +} + + +static bool crb_send_cmd_ready_status(uint32_t locality) +{ + uint32_t i = 0; + tpm_reg_ctrl_request_t reg_ctrl_request; + tpm_reg_ctrl_sts_t reg_ctrl_sts; + + 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); + + do { + 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++; + } while ( i <= TPM_DATA_AVAIL_TIME_OUT); + + if ( i > TPM_DATA_AVAIL_TIME_OUT ) + { + 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) +{ + uint32_t i; + + /* 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); + i = 0; + do { + if ( crb_check_cmd_ready_status(locality) ) + break; + else + cpu_relax(); + i++; + } while ( i <= TPM_CMD_READY_TIME_OUT ); + + if ( i > TPM_CMD_READY_TIME_OUT ) + { + //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; + + 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 */ + i = 0; + do { + 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++; + } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); + + if ( i > TPM_DATA_AVAIL_TIME_OUT ) { + 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: + */ From 4d7b6e099dca12028acfb4684023eb13dc38d572 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Tue, 13 Jun 2023 16:24:11 -0400 Subject: [PATCH 05/10] tpm: fixing up the time out loops The tboot environment did not have an accurate way of tracking time outs on access to the TPM hardware. As such, it relied on counting loops and using a multiplier factor to estimate amount of time a loop would take. Now that the code is under Xen, it can use the time functions to determine an accurate(ly) time out. Signed-off-by: Daniel P. Smith --- xen/drivers/security/tpm/tpm.c | 6 ++ xen/drivers/security/tpm/tpm.h | 3 +- xen/drivers/security/tpm/tpm_mmio.c | 149 +++++++++++++++------------- 3 files changed, 86 insertions(+), 72 deletions(-) diff --git a/xen/drivers/security/tpm/tpm.c b/xen/drivers/security/tpm/tpm.c index 37f2e2f5097..762716cdf63 100644 --- a/xen/drivers/security/tpm/tpm.c +++ b/xen/drivers/security/tpm/tpm.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "tpm.h" @@ -58,6 +59,7 @@ 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 */ @@ -125,6 +127,10 @@ bool tpm_detect(void) } 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) diff --git a/xen/drivers/security/tpm/tpm.h b/xen/drivers/security/tpm/tpm.h index bb928b9c190..3c5fec78c33 100644 --- a/xen/drivers/security/tpm/tpm.h +++ b/xen/drivers/security/tpm/tpm.h @@ -101,7 +101,6 @@ * The term timeout applies to timings between various states * or transitions within the interface protocol. */ -#define TIMEOUT_UNIT (0x100000 / 330) /* ~1ms, 1 tpm r/w need > 330ns */ #define TIMEOUT_A 750 /* 750ms */ #define TIMEOUT_B 2000 /* 2s */ #define TIMEOUT_C 75000 /* 750ms */ @@ -174,6 +173,8 @@ typedef struct __packed { #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 { diff --git a/xen/drivers/security/tpm/tpm_mmio.c b/xen/drivers/security/tpm/tpm_mmio.c index a23202c690b..0e583131479 100644 --- a/xen/drivers/security/tpm/tpm_mmio.c +++ b/xen/drivers/security/tpm/tpm_mmio.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "tpm.h" @@ -58,17 +59,21 @@ typedef union { } tpm_reg_data_crb_t; #define TPM_ACTIVE_LOCALITY_TIME_OUT \ - (TIMEOUT_UNIT *get_tpm()->timeout.timeout_a) /* according to spec */ + (get_tpm()->timeout.timeout_a) /* according to spec */ #define TPM_CMD_READY_TIME_OUT \ - (TIMEOUT_UNIT *get_tpm()->timeout.timeout_b) /* according to spec */ + (get_tpm()->timeout.timeout_b) /* according to spec */ #define TPM_CMD_WRITE_TIME_OUT \ - (TIMEOUT_UNIT *get_tpm()->timeout.timeout_d) /* let it long enough */ + (get_tpm()->timeout.timeout_d) /* let it long enough */ #define TPM_DATA_AVAIL_TIME_OUT \ - (TIMEOUT_UNIT *get_tpm()->timeout.timeout_c) /* let it long enough */ + (get_tpm()->timeout.timeout_c) /* let it long enough */ #define TPM_RSP_READ_TIME_OUT \ - (TIMEOUT_UNIT *get_tpm()->timeout.timeout_d) /* let it long enough */ + (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); \ @@ -120,7 +125,7 @@ static bool tpm_check_expect_status(uint32_t locality) return g_reg_sts.sts_valid == 1 && g_reg_sts.expect == 0; } -static bool tpm_check_da_status(uint32_t locality) +static bool tpm_check_data_access_status(uint32_t locality) { read_tpm_sts_reg(locality); #ifdef TPM_TRACE @@ -134,7 +139,7 @@ static bool tpm_check_da_status(uint32_t locality) bool cf_check fifo_request_locality(uint32_t locality) { - uint32_t i; + s_time_t now, end; tpm_reg_access_t reg_acc; /* request access to the TPM from locality N */ @@ -142,17 +147,17 @@ bool cf_check fifo_request_locality(uint32_t locality) reg_acc.request_use = 1; write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); - i = 0; - do { + 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(); - i++; - } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT); + now = NOW(); + } - if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) + if ( now > end ) { printk(XENLOG_ERR"TPM: FIFO_INF access reg request use timeout\n"); return false; @@ -163,10 +168,10 @@ bool cf_check fifo_request_locality(uint32_t locality) static bool cf_check fifo_validate_locality(uint32_t locality) { - uint32_t i; + s_time_t now, end; tpm_reg_access_t reg_acc; - for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) + tpm_loop_until_timeout(now, end, TPM_ACTIVE_LOCALITY_TIME_OUT); { /* * TCG spec defines reg_acc.tpm_reg_valid_sts bit to indicate whether @@ -179,7 +184,7 @@ static bool cf_check fifo_validate_locality(uint32_t locality) return true; cpu_relax(); } - if ( i <= 0 ) + if ( now > end ) printk(XENLOG_ERR"TPM: tpm_validate_locality timeout\n"); return false; @@ -187,6 +192,7 @@ static bool cf_check fifo_validate_locality(uint32_t locality) static bool cf_check fifo_release_locality(uint32_t locality) { + s_time_t now, end; uint32_t i; tpm_reg_access_t reg_acc; @@ -206,15 +212,15 @@ static bool cf_check fifo_release_locality(uint32_t locality) reg_acc.active_locality = 1; write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); - i = 0; - do { + 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++; - } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); + } printk(XENLOG_INFO"TPM: access reg release locality timeout\n"); return false; @@ -249,7 +255,7 @@ static bool fifo_check_cmd_ready_status(uint32_t locality) static bool fifo_wait_cmd_ready(uint32_t locality) { - uint32_t i; + s_time_t now, end; /* request access to the TPM from locality N */ if ( !fifo_request_locality(locality) ) @@ -260,8 +266,8 @@ static bool fifo_wait_cmd_ready(uint32_t locality) printk(XENLOG_INFO"TPM: wait for cmd ready \n"); #endif - i = 0; - do { + tpm_loop_until_timeout(now, end, TPM_CMD_READY_TIME_OUT); + { fifo_send_cmd_ready_status(locality); cpu_relax(); /* then see if it has */ @@ -271,12 +277,12 @@ static bool fifo_wait_cmd_ready(uint32_t locality) else cpu_relax(); i++; - } while ( i <= TPM_CMD_READY_TIME_OUT ); + } #ifdef TPM_TRACE printk(XENLOG_INFO"\n"); #endif - if ( i > TPM_CMD_READY_TIME_OUT ) + if ( now > end ) { tpm_print_status_register(); printk(XENLOG_INFO"TPM: tpm timeout for command_ready\n"); @@ -297,8 +303,9 @@ static void fifo_execute_cmd(uint32_t locality) static bool cf_check fifo_submit_cmd( uint32_t locality, uint8_t *in, u32 in_size, u8 *out, u32 *out_size) { - uint32_t i, rsp_size, offset; + uint32_t rsp_size, offset; uint16_t row_size; + s_time_t now, end; if ( locality >= TPM_NR_LOCALITIES ) { @@ -338,15 +345,16 @@ static bool cf_check fifo_submit_cmd( /* write the command to the TPM FIFO */ offset = 0; do { - i = 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(); - i++; - } while ( i <= TPM_CMD_WRITE_TIME_OUT ); - if ( i > TPM_CMD_WRITE_TIME_OUT ) + if ( row_size > 0 ) + break; + else + cpu_relax(); + } + if ( now > end ) { printk(XENLOG_ERR"TPM: write cmd timeout\n"); fifo_quick_release_locality(locality); @@ -358,15 +366,14 @@ static bool cf_check fifo_submit_cmd( (tpm_reg_data_fifo_t *)&in[offset]); } while ( offset < in_size ); - i = 0; - do { + tpm_loop_until_timeout(now, end, TPM_DATA_AVAIL_TIME_OUT); + { if ( tpm_check_expect_status(locality) ) break; else cpu_relax(); - i++; - } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); - if ( i > TPM_DATA_AVAIL_TIME_OUT ) + } + if ( now > end ) { printk(XENLOG_ERR"TPM: wait for expect becoming 0 timeout\n"); fifo_quick_release_locality(locality); @@ -377,15 +384,15 @@ static bool cf_check fifo_submit_cmd( fifo_execute_cmd(locality); /* check for data available */ - i = 0; - do { - if ( tpm_check_da_status(locality) ) + tpm_loop_until_timeout(now, end, TPM_DATA_AVAIL_TIME_OUT); + { + if ( tpm_check_data_access_status(locality) ) break; else cpu_relax(); i++; - } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); - if ( i > TPM_DATA_AVAIL_TIME_OUT ) { + } + if ( now > end ) { printk(XENLOG_ERR"TPM: wait for data available timeout\n"); fifo_quick_release_locality(locality); return false; @@ -395,16 +402,16 @@ static bool cf_check fifo_submit_cmd( offset = 0; do { /* find out how many bytes the TPM returned in a row */ - i = 0; - do { + 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++; - } while ( i <= TPM_RSP_READ_TIME_OUT ); - if ( i > TPM_RSP_READ_TIME_OUT ) + } + if ( now > end ) { printk(XENLOG_ERR"TPM: read rsp timeout\n"); fifo_quick_release_locality(locality); @@ -466,27 +473,26 @@ static bool crb_locality_workaround(void); static bool cf_check crb_request_locality(uint32_t locality) { - uint32_t i; 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); - i = 0; - do { + 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(); - i++; - } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); + } - if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) + if ( now > end ) { printk(XENLOG_ERR"TPM: access loc request use timeout\n"); printk(XENLOG_ERR" attempting workaround\n"); @@ -523,10 +529,10 @@ static bool crb_locality_workaround(void) bool cf_check crb_validate_locality(uint32_t locality) { - uint32_t i; tpm_reg_loc_state_t reg_loc_state; + s_time_t now, end; - for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) + tpm_loop_until_timeout(now, end, TPM_ACTIVE_LOCALITY_TIME_OUT); { /* * Platfrom Tpm Profile for TPM 2.0 SPEC @@ -551,9 +557,9 @@ bool cf_check crb_validate_locality(uint32_t locality) bool cf_check crb_relinquish_locality(uint32_t locality) { - uint32_t i; 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); @@ -570,15 +576,14 @@ bool cf_check crb_relinquish_locality(uint32_t locality) reg_loc_ctrl.relinquish = 1; write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); - i = 0; - do { + 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(); - i++; - } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); + } printk(XENLOG_INFO"TPM: CRB_INF release locality timeout\n"); return false; @@ -587,9 +592,9 @@ bool cf_check crb_relinquish_locality(uint32_t locality) static bool crb_send_cmd_ready_status(uint32_t locality) { - uint32_t i = 0; 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); @@ -611,7 +616,8 @@ static bool crb_send_cmd_ready_status(uint32_t locality) reg_ctrl_request.goIdle = 1; write_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); - do { + 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) { @@ -631,9 +637,9 @@ static bool crb_send_cmd_ready_status(uint32_t locality) } i++; - } while ( i <= TPM_DATA_AVAIL_TIME_OUT); + } - if ( i > TPM_DATA_AVAIL_TIME_OUT ) + if ( now > end ) { printk(XENLOG_ERR"TPM: reg_ctrl_request.goidle timeout!\n"); return false; @@ -689,23 +695,23 @@ static bool crb_check_cmd_ready_status(uint32_t locality) static bool crb_wait_cmd_ready(uint32_t locality) { - uint32_t i; + 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); - i = 0; - do { + tpm_loop_until_timeout(now, end, TPM_CMD_READY_TIME_OUT); + { if ( crb_check_cmd_ready_status(locality) ) break; else cpu_relax(); i++; - } while ( i <= TPM_CMD_READY_TIME_OUT ); + } - if ( i > TPM_CMD_READY_TIME_OUT ) + if ( now > end ) { //tpm_print_status_register(); printk(XENLOG_INFO"TPM: tpm timeout for command_ready\n"); @@ -726,6 +732,7 @@ bool cf_check crb_submit_cmd( 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 ) { @@ -806,8 +813,8 @@ bool cf_check crb_submit_cmd( printk(XENLOG_INFO"tpm_ctrl_start.start is 0x%x\n",start.start); /* check for data available */ - i = 0; - do { + 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 ) @@ -815,9 +822,9 @@ bool cf_check crb_submit_cmd( else cpu_relax(); i++; - } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); + } - if ( i > TPM_DATA_AVAIL_TIME_OUT ) { + if ( now > end ) { printk(XENLOG_ERR"TPM: wait for data available timeout\n"); return false; } From 417be69dbd39cd9bb667f97b4f8da7b1dcda35d4 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Sat, 25 Mar 2023 07:30:08 -0400 Subject: [PATCH 06/10] secdev: introduce security device interfaces Adds secdev headers. Signed-off-by: Daniel P. Smith --- xen/drivers/security/secdev.h | 38 ++++++++++++++++++++ xen/include/xen/secdev.h | 65 +++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 xen/drivers/security/secdev.h create mode 100644 xen/include/xen/secdev.h diff --git a/xen/drivers/security/secdev.h b/xen/drivers/security/secdev.h new file mode 100644 index 00000000000..d67a2e54f4c --- /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/include/xen/secdev.h b/xen/include/xen/secdev.h new file mode 100644 index 00000000000..77a1b733ddc --- /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 From fcd89482a8af1c96b2dfeafc3d688c33f012a888 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Fri, 27 Jan 2023 17:03:27 -0500 Subject: [PATCH 07/10] tpm: add driver interface This commit adds a secdev interface callable by the secdev framework to detect the tpm and extend a commandline selectable PCR with a domain's measurements. Signed-off-by: Daniel P. Smith --- xen/drivers/security/Kconfig | 11 + xen/drivers/security/tpm/Makefile | 1 + xen/drivers/security/tpm/tpm_drv.c | 345 +++++++++++++++++++++++++++++ xen/drivers/security/tpm/tpm_drv.h | 16 ++ 4 files changed, 373 insertions(+) create mode 100644 xen/drivers/security/tpm/tpm_drv.c create mode 100644 xen/drivers/security/tpm/tpm_drv.h diff --git a/xen/drivers/security/Kconfig b/xen/drivers/security/Kconfig index 6c038d91e8d..ce87ec65b5e 100644 --- a/xen/drivers/security/Kconfig +++ b/xen/drivers/security/Kconfig @@ -6,3 +6,14 @@ config SECURITY_DEVICES 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/tpm/Makefile b/xen/drivers/security/tpm/Makefile index 96f032c5336..f0743050509 100644 --- a/xen/drivers/security/tpm/Makefile +++ b/xen/drivers/security/tpm/Makefile @@ -2,3 +2,4 @@ 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_drv.c b/xen/drivers/security/tpm/tpm_drv.c new file mode 100644 index 00000000000..2263a31aeb6 --- /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 00000000000..016c5c65384 --- /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 From ca5997f80b93d7f40c110a7d4a6e4a7b341feb69 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Mon, 27 Mar 2023 13:32:17 -0400 Subject: [PATCH 08/10] tpm: move tpm2.0 primary logic This commits move the initialization of a global primary into an commented out function. This is to reserve the logic for later use to create per domain key hierarchy. Signed-off-by: Daniel P. Smith --- xen/drivers/security/tpm/tpm_20.c | 116 ++++++++++++++++-------------- 1 file changed, 62 insertions(+), 54 deletions(-) diff --git a/xen/drivers/security/tpm/tpm_20.c b/xen/drivers/security/tpm/tpm_20.c index 95235d66d38..286f0cec3f0 100644 --- a/xen/drivers/security/tpm/tpm_20.c +++ b/xen/drivers/security/tpm/tpm_20.c @@ -378,6 +378,8 @@ static bool reverse_copy_digest_values_out( 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. @@ -1082,6 +1084,7 @@ static bool reverse_copy_ticket_out(TPMT_TK_CREATION *ticket, void **other) return true; } +#endif static void reverse_copy_context_in(void **other, TPMS_CONTEXT *context) { @@ -1539,9 +1542,10 @@ static uint32_t _tpm20_shutdown(uint32_t locality, uint16_t type) return _tpm20_send_cmd(other, locality, RSP_HEAD_SIZE); } -uint32_t handle2048 = 0; //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) { @@ -1625,7 +1629,7 @@ static uint32_t _tpm20_create_primary( return ret; } - +#endif /* TODO: Add an appropriate seal/unseal for Xen */ #if 0 @@ -2562,14 +2566,68 @@ static bool cf_check tpm20_context_load( 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; - tpm_create_primary_in primary_in; - tpm_create_primary_out primary_out; if ( ti == NULL ) return false; @@ -2643,56 +2701,6 @@ static bool cf_check tpm20_init(struct tpm_if *ti) return false; } - if (handle2048 != 0) - goto 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); -out: tpm_print(ti); return true; } From 0fdb12756b5b5166af466f6fc66f4d6c4cc698f3 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Mon, 20 Mar 2023 14:21:25 -0400 Subject: [PATCH 09/10] secdev: introduce the security device framework Introduces the secdev framework with TPM being the first supported device. Signed-off-by: Daniel P. Smith --- xen/drivers/Makefile | 1 + xen/drivers/security/Makefile | 2 + xen/drivers/security/secdev.c | 106 ++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 xen/drivers/security/Makefile create mode 100644 xen/drivers/security/secdev.c diff --git a/xen/drivers/Makefile b/xen/drivers/Makefile index 2a1ae8ad130..0c2009da8f1 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/Makefile b/xen/drivers/security/Makefile new file mode 100644 index 00000000000..87b4a111d19 --- /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 00000000000..b6dc023d25e --- /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; +} From dbafab6afd0d621aa8c01a57b00b157d2adc9513 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Thu, 2 Feb 2023 07:50:05 -0500 Subject: [PATCH 10/10] x86: add support for measuring Dom0 at boot This commit leverages the TPM driver to measure Dom0's kernel and initrd before the domain is contstructed. Signed-off-by: Daniel P. Smith --- xen/arch/x86/setup.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 74e3915a4dc..47a9d283427 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 )