From 4c87a1868835d05f1cadae7b8ad6a7c95d9d9c0e Mon Sep 17 00:00:00 2001 From: Ross Philipson Date: Tue, 14 Mar 2017 15:40:33 -0400 Subject: Initial commit of EFI TBOOT work from internal project. Signed-off-by: Ross Philipson --- tboot/tpm_20.c | 2406 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2406 insertions(+) create mode 100644 tboot/tpm_20.c (limited to 'tboot/tpm_20.c') diff --git a/tboot/tpm_20.c b/tboot/tpm_20.c new file mode 100644 index 0000000..87007d0 --- /dev/null +++ b/tboot/tpm_20.c @@ -0,0 +1,2406 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static u8 cmd_buf[MAX_COMMAND_SIZE]; +static u8 rsp_buf[MAX_RESPONSE_SIZE]; + +#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(u32 cmd_code, TPM_CMD_SESSIONS_IN *sessions_in) +{ + u16 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) +{ + u32 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 void reverse_copy_pcr_selection_out(TPML_PCR_SELECTION *pcr_selection, + void **other) +{ + u32 i, k; + + if (pcr_selection == NULL) + return; + + /* Copy count of pcrs to be read. */ + reverse_copy_out(pcr_selection->count, *other); + + 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); + + /* 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); + } +} + +/* + * 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 u16 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(u16)); + for (i=0; isize; i++) + dest->buffer[i] = src->buffer[i]; + + return sizeof(u16) + src->size; +} + +static u16 reverse_copy_sized_buf_out(TPM2B *dest, TPM2B *src) +{ + int i; + + if (dest == NULL || src == NULL) + return 0; + + reverse_copy(&dest->size, &src->size, sizeof(u16)); + for (i=0; isize; i++) + dest->buffer[i] = src->buffer[i]; + + return sizeof(u16) + dest->size; +} + +static void reverse_copy_digest_out(TPML_DIGEST *tpml_digest, void **other) +{ + u32 i; + + if (tpml_digest == NULL) + return; + + reverse_copy_out(tpml_digest->count, *other); + + for (i=0; icount; i++) + *other += reverse_copy_sized_buf_out((TPM2B *)&(tpml_digest->digests[i]), + (TPM2B *)*other); +} + +static void reverse_copy_session_data_in(void **other, + TPM_CMD_SESSION_DATA_IN *session_data, + u32 *session_size) +{ + *session_size += sizeof(u32) + sizeof( u16 ) + + session_data->nonce.t.size + sizeof( u8 ) + + sizeof( u16 ) + 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 */ + *((u8 *)*other) = *(u8 *)(void *)&(session_data->session_attr); + *other += sizeof(u8); + + /* 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; + u32 session_size = 0; + void *session_size_ptr = *other; + + if (sessions_in == NULL) + return; + + if (sessions_in->num_sessions != 0) { + *other += sizeof(u32); + 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(u32)); +} + +static void reverse_copy_session_data_out(TPM_CMD_SESSION_DATA_OUT *session_data, + void **other) +{ + if (session_data == NULL) + return; + + /* Copy nonce */ + *other += reverse_copy_sized_buf_out((TPM2B *)&(session_data->nonce), + (TPM2B *)*other); + + /* Copy sessionAttributes */ + *(u8 *)(void *)&(session_data->session_attr) = *((u8 *)*other); + *other += sizeof(u8); + + /* Copy hmac */ + *other += reverse_copy_sized_buf_out((TPM2B *)&(session_data->hmac), + (TPM2B *)*other); +} + +static void reverse_copy_sessions_out(TPM_CMD_SESSIONS_OUT *sessions_out, + void *other, u16 rsp_tag, + TPM_CMD_SESSIONS_IN *sessions_in) +{ + int i; + + if (sessions_in == NULL || sessions_out == NULL || rsp_tag != TPM_ST_SESSIONS) + return; + + sessions_out->num_sessions = sessions_in->num_sessions; + for (i=0; inum_sessions; i++) + reverse_copy_session_data_out(&sessions_out->sessions[i], &other); +} + +typedef struct { + u16 alg_id; + u16 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} +}; + +u16 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(u8); + } + } +} + +static void reverse_copy_digest_values_out(TPML_DIGEST_VALUES *tpml_digest, + void **other) +{ + unsigned int i, k, num_bytes; + + if (tpml_digest == NULL) + return; + + reverse_copy_out(tpml_digest->count, *other); + + 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] = *((u8 *)*other); + *other += sizeof(u8); + } + } +} + +/* + * 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; + u16 size; + + size_ptr = *other; + *other += sizeof(u16); + + 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(u32)); + *other += sizeof(u32); + + /* 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 */ + *((u16 *)*other) = 0xffff; + *other += sizeof(u16); + 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 = (u8 *)*other - (u8 *)size_ptr - sizeof(u16); + reverse_copy(size_ptr, &size, sizeof(u16)); +} + +/* + * 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 void 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); + + if (public == NULL) + return; + + 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(u32)); + *other += sizeof(u32); + + /* Copy public->t.auth_policy */ + *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.auth_policy, + (TPM2B *)*other); + + /* 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 */ + *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.keyed_hash, + (TPM2B *)*other); + + 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 */ + *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.sym, + (TPM2B *)*other); + + 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 */ + *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.rsa, + (TPM2B *)*other); + + 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 */ + *((u16 *)*other) = 0xffff; + *other += sizeof(u16); + break; + } + + /* Copy public->t.public_area.unique */ + *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.ecc, + (TPM2B *)*other); + + 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; + } +} + +static void reverse_copy_creation_data_out(TPM2B_CREATION_DATA *data, void **other) +{ + if (data == NULL) + return; + + reverse_copy_out(data->t.size, *other); + + reverse_copy_pcr_selection_out(&data->t.data.pcr_select, other); + + *other += reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.pcr_digest), + (TPM2B *)*other); + + *((u8 *)(void *)&data->t.data.locality) = *((u8 *)*other); + *other += sizeof(u8); + + reverse_copy_out(data->t.data.parent_name_alg, *other); + + *other += reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.parent_name), + (TPM2B *)*other); + *other += reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.parent_qualified_name), + (TPM2B *)*other); + *other += reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.outside_info), + (TPM2B *)*other); +} + +static void reverse_copy_ticket_out(TPMT_TK_CREATION *ticket, void **other) +{ + if (ticket == NULL) + return; + + reverse_copy_out(ticket->tag, *other); + + reverse_copy_out(ticket->hierarchy, *other); + + *other += reverse_copy_sized_buf_out((TPM2B *)&(ticket->digest), (TPM2B *)*other); +} + +static uint32_t _tpm20_pcr_read(u32 locality, + tpm_pcr_read_in *in, + tpm_pcr_read_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 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 = (u8 *)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(u32); /* Skip past parameter size field */ + + reverse_copy_out(out->pcr_update_counter, other); + + reverse_copy_pcr_selection_out(&out->pcr_selection, &other); + + reverse_copy_digest_out(&out->pcr_values, &other); + + return ret; +} + +static uint32_t _tpm20_pcr_extend(uint32_t locality, + tpm_pcr_extend_in *in, + tpm_pcr_extend_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 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 = (u8 *)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(u32); + + reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); + + return ret; +} + +static uint32_t _tpm20_pcr_event(uint32_t locality, + tpm_pcr_event_in *in, + tpm_pcr_event_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 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 = (u8 *)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(u32); + + reverse_copy_digest_values_out(&out->digests, &other); + + reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); + + return ret; +} + +static uint32_t _tpm20_pcr_reset(uint32_t locality, + tpm_pcr_reset_in *in, + tpm_pcr_reset_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 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(u32)); + + other += sizeof(u32); + 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 = (u8 *)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(u32); + + reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); + + return ret; +} + +static uint32_t _tpm20_sequence_start(uint32_t locality, + tpm_sequence_start_in *in, + tpm_sequence_start_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 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 = (u8 *)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(u32); + + 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) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 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 = (u8 *)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(u32); + + reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); + + return ret; +} + +static uint32_t _tpm20_sequence_complete(uint32_t locality, + tpm_sequence_complete_in *in, + tpm_sequence_complete_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 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 = (u8 *)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(u32); + + reverse_copy_digest_values_out(&out->results, &other); + + reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); + + return ret; +} + +static uint32_t _tpm20_nv_read(uint32_t locality, + tpm_nv_read_in *in, + tpm_nv_read_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 rsp_tag; + void *other; + + 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 = (u8 *)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(u32); + + other += reverse_copy_sized_buf_out((TPM2B *)&(out->data), (TPM2B *)other); + + reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); + + return ret; +} + +static uint32_t _tpm20_nv_write(uint32_t locality, + tpm_nv_write_in *in, + tpm_nv_write_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 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 = (u8 *)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(u32); + + reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); + + return ret; +} + +static uint32_t _tpm20_nv_read_public(uint32_t locality, + tpm_nv_read_public_in *in, + tpm_nv_read_public_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 rsp_tag; + void *other; + + 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 = (u8 *)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(u32); + + 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(u32)); + other += sizeof(u32); + other += reverse_copy_sized_buf_out((TPM2B *)&(out->nv_public.t.nv_public.auth_policy), + (TPM2B *)other); + reverse_copy_out(out->nv_public.t.nv_public.data_size, other); + + other += reverse_copy_sized_buf_out((TPM2B *)&(out->nv_name), (TPM2B *)other); + + return ret; +} + +static uint32_t _tpm20_get_random(uint32_t locality, + tpm_get_random_in *in, + tpm_get_random_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 rsp_tag; + void *other; + + 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 = (u8 *)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(u32); + + other += reverse_copy_sized_buf_out((TPM2B *)&(out->random_bytes), (TPM2B *)other); + + return ret; +} + +static uint32_t _tpm20_shutdown(uint32_t locality, u16 type) +{ + u32 ret; + u32 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 = (u8 *)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; +} + +static __data u32 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) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 rsp_tag; + u16 sensitive_size; + void *sensitive_size_ptr; + void *other; + + 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(u16); + 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 = (u8 *)other - (u8 *)sensitive_size_ptr - sizeof(u16); + reverse_copy(sensitive_size_ptr, &sensitive_size, sizeof(u16)); + + /* 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 = (u8 *)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(u32); + + /* Save outPublic */ + reverse_copy_public_out(&out->public, &other); + + /* Save creationData */ + reverse_copy_creation_data_out(&(out->creation_data), &other); + + /* Save creationHash */ + other += reverse_copy_sized_buf_out((TPM2B *)&(out->creation_hash), + (TPM2B *)other); + + /* Save creationTicket */ + reverse_copy_ticket_out(&(out->creation_ticket), &other); + + other += reverse_copy_sized_buf_out((TPM2B *)&(out->name), (TPM2B *)other); + + reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); + + return ret; +} + + +static uint32_t _tpm20_create(uint32_t locality, + tpm_create_in *in, + tpm_create_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 rsp_tag; + u16 sensitive_size; + void *sensitive_size_ptr; + void *other; + + 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(u16); + 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 = (u8 *)other - (u8 *)sensitive_size_ptr - sizeof(u16); + reverse_copy(sensitive_size_ptr, &sensitive_size, sizeof(u16)); + + /* 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 = (u8 *)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(u32); + + /* Save outPrivate */ + other += reverse_copy_sized_buf_out((TPM2B *)&(out->private), (TPM2B *)other); + + /* Save outPublic */ + reverse_copy_public_out(&out->public, &other); + + /* Save creationData */ + reverse_copy_creation_data_out(&(out->creation_data), &other); + + /* Save creationHash */ + other += reverse_copy_sized_buf_out((TPM2B *)&(out->creation_hash), + (TPM2B *)other); + + /* Save creationTicket */ + reverse_copy_ticket_out(&(out->creation_ticket), &other); + + reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); + + return ret; +} + +static uint32_t _tpm20_load(uint32_t locality, + tpm_load_in *in, + tpm_load_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 rsp_tag; + void *other; + + 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 = (u8 *)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(u32); + + other += reverse_copy_sized_buf_out((TPM2B *)&(out->name), (TPM2B *)other); + + reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); + + return ret; +} + +static uint32_t _tpm20_unseal(uint32_t locality, + tpm_unseal_in *in, + tpm_unseal_out *out) +{ + u32 ret; + u32 cmd_size, rsp_size; + u16 rsp_tag; + void *other; + + 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 = (u8 *)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(u32); + + other += reverse_copy_sized_buf_out((TPM2B *)&(out->data), (TPM2B *)other); + + reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); + + return ret; +} + +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; + *((u8 *)((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 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; + u32 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(TBOOT_WARN"TPM: Pcr %d Read return value = %08X\n", pcr, ret); + ti->error = ret; + return false; + } + + copy_hash(out, + (tb_hash_t *)&(read_out.pcr_values.digests[0].t.buffer[0]), + ti->cur_alg); + + return true; +} + +static bool 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; + u32 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((tb_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(TBOOT_WARN"TPM: Pcr %d extend, return value = %08X\n", pcr, ret); + ti->error = ret; + return false; + } + + return true; +} + +static bool 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; + u32 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(TBOOT_WARN"TPM: Pcr %d Reset return value = %08X\n", pcr, ret); + ti->error = ret; + return false; + } + + return true; +} + +static bool tpm20_hash(struct tpm_if *ti, u32 locality, const u8 *data, + u32 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; + u32 ret, i, j, chunk_size; + + if ( ti == NULL || data == NULL || data_size == 0 ) + 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(TBOOT_WARN"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 = 1024; + } else { + chunk_size = data_size - i; + } + + buffer.t.size = chunk_size; + memcpy( &(buffer.t.buffer[0]), &(data[i] ), chunk_size ); + + if( chunk_size == 1024 ) { + update_in.buf = buffer; + ret = _tpm20_sequence_update(locality, &update_in, &update_out); + if (ret != TPM_RC_SUCCESS) { + printk(TBOOT_WARN"TPM: SequenceUpdate return value = %08X\n", ret); + ti->error = ret; + return false; + } + } else { + complete_in.buf = buffer; + ret = _tpm20_sequence_complete(locality, &complete_in, &complete_out); + if (ret != TPM_RC_SUCCESS) { + printk(TBOOT_WARN"TPM: EventSequenceComplete return value = %08X\n", ret); + ti->error = ret; + return false; + } + } + } + + hl->count = complete_out.results.count; + 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 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; + u32 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(TBOOT_WARN"TPM: read NV index %08x from offset %08x, return value = %08X\n", + index, offset, ret); + ti->error = ret; + return false; + } + + *data_size = read_out.data.t.size; + if( *data_size > 0 ) + memcpy(data, &read_out.data.t.buffer[0], *data_size); + + return true; +} + +static bool 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; + u32 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(TBOOT_WARN"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 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; + u32 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(TBOOT_WARN"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(TBOOT_WARN"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 tpm20_get_nvindex_permission(struct tpm_if *ti, uint32_t locality, + uint32_t index, uint32_t *attribute) +{ + if ( ti == NULL || locality >= TPM_NR_LOCALITIES + || index == 0 || attribute == NULL ) + return false; + + return true; +} + +static bool 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; + u32 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; + *(u32 *)&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; + + 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); + 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; + + ret = _tpm20_create(locality, &create_in, &create_out); + if ( ret != TPM_RC_SUCCESS ) { + printk(TBOOT_WARN"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 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; + u32 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(TBOOT_WARN"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(TBOOT_WARN"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); + + return true; +} + +static bool tpm20_verify_creation(struct tpm_if *ti, uint32_t sealed_data_size, uint8_t *sealed_data) +{ + if ( ti == NULL || sealed_data_size == 0 || sealed_data == NULL ) + return false; + + return true; +} + +static bool 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; + u32 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(TBOOT_WARN"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(TBOOT_WARN"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 ) { + first_attempt = false; + uint32_t second_size = requested_size - out_size; + printk(TBOOT_WARN"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(TBOOT_WARN"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 tpm20_save_state(struct tpm_if *ti, uint32_t locality) +{ + u32 ret; + + if ( ti == NULL ) + return false; + + ret = _tpm20_shutdown(locality, TPM_SU_STATE); + if ( ret != TPM_RC_SUCCESS ) { + printk(TBOOT_WARN"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 tpm20_cap_pcrs(struct tpm_if *ti, u32 locality, int pcr) +{ + bool was_capped[TPM_NR_PCRS] = {false}; + hash_list_t cap_val; /* use whatever val is on stack */ + + if ( ti == NULL || locality >= TPM_NR_LOCALITIES || pcr == 0 ) + return false; + + cap_val.count = ti->banks; + for (unsigned int i=0; ibanks; i++) + cap_val.entries[i].alg = ti->algs_banks[i]; + + if (pcr >= 0) { + tpm20_pcr_extend(ti, locality, pcr, &cap_val); + return true; + } + + /* ensure PCRs 17 + 18 are always capped */ + tpm20_pcr_extend(ti, locality, 17, &cap_val); + tpm20_pcr_extend(ti, locality, 18, &cap_val); + was_capped[17] = was_capped[18] = true; + + /* also cap every dynamic PCR we extended (only once) */ + /* don't cap static PCRs since then they would be wrong after S3 resume */ + /* TODO + memset(&was_capped, true, TPM_PCR_RESETABLE_MIN*sizeof(bool)); + for ( int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { + if ( !was_capped[g_pre_k_s3_state.vl_entries[i].pcr] ) { + tpm20_pcr_extend(ti, locality, g_pre_k_s3_state.vl_entries[i].pcr, &cap_val); + was_capped[g_pre_k_s3_state.vl_entries[i].pcr] = true; + } + }*/ + + printk(TBOOT_INFO"cap'ed dynamic PCRs\n"); + return true; +} + +static bool alg_is_supported(u16 alg) +{ + for (int i=0; i<2; i++) { + if (alg == tboot_alg_list[i]) + return true; + } + + return false; +} + +static bool tpm20_init(struct tpm_if *ti) +{ + u32 ret; + unsigned int i; + tpm_info_list_t *info_list = get_tpm_info_list(g_sinit); + + if ( ti == NULL ) + return false; +/* TODO + if (!txt_is_launched()) + ti->cur_loc = 0; + else + ti->cur_loc = 2; +*/ + + /* 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 */ + /* TODO get_tboot_extpol(); */ + if (info_list->capabilities.tpm_nv_index_set == 0){ + /* init NV index */ + ti->tb_policy_index = 0x1200001; + ti->lcp_own_index = 0x1400001; + ti->tb_err_index = 0x1200002; + ti->sgx_svn_index = 0x01800004; + } + else { + 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 */ + tpm_pcr_event_in event_in; + tpm_pcr_event_out event_out; + 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(TBOOT_WARN"TPM: PcrEvent not successful, return value = %08X\n", ret); + ti->error = ret; + return false; + } + ti->banks = event_out.digests.count; + printk(TBOOT_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(TBOOT_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(TBOOT_INFO"TPM: supported alg count = %08X\n", ti->alg_count); + for (unsigned int i=0; ialg_count; i++) + printk(TBOOT_INFO"\t\t %08X\n", ti->algs[i]); + + if (handle2048 != 0) + goto out; + + /* create primary object as parent obj for seal */ + tpm_create_primary_in primary_in; + tpm_create_primary_out primary_out; + 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; + *((u8 *)((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; + *(u32 *)&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(TBOOT_DETA"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(TBOOT_WARN"TPM: CreatePrimary return value = %08X\n", ret); + ti->error = ret; + return false; + } + handle2048 = primary_out.obj_handle; + + printk(TBOOT_DETA"TPM:CreatePrimary created object handle = %08X\n", handle2048); +out: + tpm_print(ti); + return true; +} + +struct tpm_if tpm_20_if = { + .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, + .verify_creation = tpm20_verify_creation, + .get_random = tpm20_get_random, + .save_state = tpm20_save_state, + .cap_pcrs = tpm20_cap_pcrs, +}; + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ -- cgit v1.2.3