diff --git a/Add-ability-to-check-quotes-and-output-PCR-values-fo.patch b/Add-ability-to-check-quotes-and-output-PCR-values-fo.patch deleted file mode 100644 index 5c6cd2a..0000000 --- a/Add-ability-to-check-quotes-and-output-PCR-values-fo.patch +++ /dev/null @@ -1,2007 +0,0 @@ -From 3f9c713d3bff4abf417edf0f74e0b049bfd1b31f Mon Sep 17 00:00:00 2001 -From: jetwhiz -Date: Fri, 3 May 2019 08:03:45 -0400 -Subject: [PATCH] Add ability to check quotes and output PCR values for - quotes - -Add new tpm2_checkquote tool for checking quotes - Pull shared functionality from tpm2_pcrlist into pcr library - is_pcr_select_bit_set moved into tpm2_util library - Add new functionality to openssl, pcr and util libraries -The tpm2_quote tool can now output PCR hash lists - -Signed-off-by: jetwhiz ---- - CHANGELOG.md | 2 + - Makefile.am | 3 + - lib/pcr.c | 232 ++++++++++++++++ - lib/pcr.h | 27 ++ - lib/tpm2_openssl.c | 163 +++++++++++ - lib/tpm2_openssl.h | 57 ++++ - lib/tpm2_util.c | 148 ++++++++++ - lib/tpm2_util.h | 33 +++ - man/tpm2_checkquote.1.md | 95 +++++++ - man/tpm2_quote.1.md | 9 +- - test/system/test_tpm2_checkquote.sh | 86 ++++++ - test/system/test_tpm2_quote.sh | 12 +- - tools/tpm2_checkquote.c | 409 ++++++++++++++++++++++++++++ - tools/tpm2_pcrlist.c | 205 +------------- - tools/tpm2_quote.c | 124 ++++++++- - 15 files changed, 1398 insertions(+), 207 deletions(-) - create mode 100644 man/tpm2_checkquote.1.md - create mode 100755 test/system/test_tpm2_checkquote.sh - create mode 100644 tools/tpm2_checkquote.c - -diff --git a/CHANGELOG.md b/CHANGELOG.md -index a8e4f39afde..7e83c6b7e6f 100644 ---- a/CHANGELOG.md -+++ b/CHANGELOG.md -@@ -1,5 +1,7 @@ - ## Changelog - ### 3.2.0 - next -+* tpm2_checkquote: Introduce new tool for checking validity of quotes. -+* tpm2_quote: Add ability to output PCR values for quotes. - * tpm2_makecredential: add support for executing tool off-TPM. - * tpm2_pcrreset: introduce new tool for resetting PCRs. - * tpm2_quote: Fix AK auth password not being used. -diff --git a/Makefile.am b/Makefile.am -index 2195537ce01..854c24a03e3 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -59,6 +59,7 @@ LDADD = \ - - # keep me sorted - bin_PROGRAMS = \ -+ tools/tpm2_checkquote \ - tools/tpm2_activatecredential \ - tools/tpm2_certify \ - tools/tpm2_create \ -@@ -145,6 +146,7 @@ lib_libcommon_a_SOURCES = \ - - TOOL_SRC := tools/tpm2_tool.c tools/tpm2_tool.h - -+tools_tpm2_checkquote_SOURCES = tools/tpm2_checkquote.c $(TOOL_SRC) - tools_tpm2_create_SOURCES = tools/tpm2_create.c $(TOOL_SRC) - tools_tpm2_createprimary_SOURCES = tools/tpm2_createprimary.c $(TOOL_SRC) - tools_tpm2_getcap_SOURCES = tools/tpm2_getcap.c $(TOOL_SRC) -@@ -259,6 +261,7 @@ if HAVE_MAN_PAGES - man1_MANS := \ - man/man1/tpm2_activatecredential.1 \ - man/man1/tpm2_certify.1 \ -+ man/man1/tpm2_checkquote.1 \ - man/man1/tpm2_create.1 \ - man/man1/tpm2_createpolicy.1 \ - man/man1/tpm2_createprimary.1 \ -diff --git a/lib/pcr.c b/lib/pcr.c -index 5552b336f66..9b00dd6e0e3 100644 ---- a/lib/pcr.c -+++ b/lib/pcr.c -@@ -33,13 +33,21 @@ - #include - - #include -+#include - #include - - #include "pcr.h" - #include "log.h" -+#include "tpm2_tool.h" - #include "tpm2_util.h" - #include "tpm2_alg_util.h" - -+static inline void set_pcr_select_size(TPMS_PCR_SELECTION *pcr_selection, -+ UINT8 size) { -+ -+ pcr_selection->sizeofSelect = size; -+} -+ - static int pcr_get_id(const char *arg, UINT32 *pcrId) - { - UINT32 n = 0; -@@ -96,6 +104,111 @@ static bool pcr_parse_selection(const char *str, size_t len, TPMS_PCR_SELECTION - return true; - } - -+static void shrink_pcr_selection(TPML_PCR_SELECTION *s) { -+ -+ UINT32 i, j; -+ -+ //seek for the first empty item -+ for (i = 0; i < s->count; i++) -+ if (!s->pcrSelections[i].hash) -+ break; -+ j = i + 1; -+ -+ for (; i < s->count; i++) { -+ if (!s->pcrSelections[i].hash) { -+ for (; j < s->count; j++) -+ if (s->pcrSelections[j].hash) -+ break; -+ if (j >= s->count) -+ break; -+ -+ memcpy(&s->pcrSelections[i], &s->pcrSelections[j], sizeof(s->pcrSelections[i])); -+ s->pcrSelections[j].hash = 0; -+ j++; -+ } -+ } -+ -+ s->count = i; -+} -+ -+static void pcr_update_pcr_selections(TPML_PCR_SELECTION *s1, TPML_PCR_SELECTION *s2) { -+ UINT32 i1, i2, j; -+ for (i2 = 0; i2 < s2->count; i2++) { -+ for (i1 = 0; i1 < s1->count; i1++) { -+ if (s2->pcrSelections[i2].hash != s1->pcrSelections[i1].hash) -+ continue; -+ -+ for (j = 0; j < s1->pcrSelections[i1].sizeofSelect; j++) -+ s1->pcrSelections[i1].pcrSelect[j] &= -+ ~s2->pcrSelections[i2].pcrSelect[j]; -+ } -+ } -+} -+ -+static bool pcr_unset_pcr_sections(TPML_PCR_SELECTION *s) { -+ UINT32 i, j; -+ for (i = 0; i < s->count; i++) { -+ for (j = 0; j < s->pcrSelections[i].sizeofSelect; j++) { -+ if (s->pcrSelections[i].pcrSelect[j]) { -+ return false; -+ } -+ } -+ } -+ -+ return true; -+} -+ -+bool pcr_print_pcr_struct(TPML_PCR_SELECTION *pcrSelect, tpm2_pcrs *pcrs) { -+ -+ UINT32 vi = 0, di = 0, i; -+ bool result = true; -+ -+ tpm2_tool_output("pcrs:\n"); -+ -+ // Loop through all PCR/hash banks -+ for (i = 0; i < pcrSelect->count; i++) { -+ const char *alg_name = tpm2_alg_util_algtostr(pcrSelect->pcrSelections[i].hash); -+ -+ tpm2_tool_output(" %s:\n", alg_name); -+ -+ // Loop through all PCRs in this bank -+ UINT8 pcr_id; -+ for (pcr_id = 0; pcr_id < pcrSelect->pcrSelections[i].sizeofSelect * 8; pcr_id++) { -+ if (!tpm2_util_is_pcr_select_bit_set(&pcrSelect->pcrSelections[i], -+ pcr_id)) { -+ // skip non-selected banks -+ continue; -+ } -+ if (vi >= pcrs->count || di >= pcrs->pcr_values[vi].count) { -+ LOG_ERR("Something wrong, trying to print but nothing more"); -+ return false; -+ } -+ -+ // Print out PCR ID -+ tpm2_tool_output(" %-2d: 0x", pcr_id); -+ -+ // Print out current PCR digest value -+ TPM2B_DIGEST *b = &pcrs->pcr_values[vi].digests[di]; -+ int k; -+ for (k = 0; k < b->size; k++) { -+ tpm2_tool_output("%02X", b->buffer[k]); -+ } -+ tpm2_tool_output("\n"); -+ -+ if (++di < pcrs->pcr_values[vi].count) { -+ continue; -+ } -+ -+ di = 0; -+ if (++vi < pcrs->count) { -+ continue; -+ } -+ } -+ } -+ -+ return result; -+} -+ - - bool pcr_parse_selections(const char *arg, TPML_PCR_SELECTION *pcrSels) { - const char *strLeft = arg; -@@ -194,3 +307,122 @@ TSS2_RC get_max_supported_pcrs(TSS2_SYS_CONTEXT *sapi_context, UINT32 *max_pcrs) - - return TPM2_RC_SUCCESS; - } -+ -+bool pcr_get_banks(TSS2_SYS_CONTEXT *sapi_context, TPMS_CAPABILITY_DATA *capability_data, tpm2_algorithm *algs) { -+ -+ TPMI_YES_NO more_data; -+ UINT32 rval; -+ -+ rval = TSS2_RETRY_EXP(Tss2_Sys_GetCapability(sapi_context, no_argument, TPM2_CAP_PCRS, no_argument, required_argument, -+ &more_data, capability_data, 0)); -+ if (rval != TPM2_RC_SUCCESS) { -+ LOG_ERR( -+ "GetCapability: Get PCR allocation status Error. TPM Error:0x%x......", -+ rval); -+ return false; -+ } -+ -+ unsigned i; -+ -+ // If the TPM support more bank algorithm that we currently -+ // able to manage, throw an error -+ if (capability_data->data.assignedPCR.count > sizeof(algs->alg)) { -+ LOG_ERR("Current implementation does not support more than %zu banks, " -+ "got %" PRIu32 " banks supported by TPM", -+ sizeof(algs->alg), -+ capability_data->data.assignedPCR.count); -+ return false; -+ } -+ -+ for (i = 0; i < capability_data->data.assignedPCR.count; i++) { -+ algs->alg[i] = -+ capability_data->data.assignedPCR.pcrSelections[i].hash; -+ } -+ algs->count = capability_data->data.assignedPCR.count; -+ -+ return true; -+} -+ -+bool pcr_init_pcr_selection(TPMS_CAPABILITY_DATA *cap_data, TPML_PCR_SELECTION *pcr_sel, TPMI_ALG_HASH alg_id) { -+ -+ UINT32 i, j; -+ -+ pcr_sel->count = 0; -+ -+ for (i = 0; i < cap_data->data.assignedPCR.count; i++) { -+ if (alg_id && (cap_data->data.assignedPCR.pcrSelections[i].hash != alg_id)) -+ continue; -+ pcr_sel->pcrSelections[pcr_sel->count].hash = cap_data->data.assignedPCR.pcrSelections[i].hash; -+ set_pcr_select_size(&pcr_sel->pcrSelections[pcr_sel->count], cap_data->data.assignedPCR.pcrSelections[i].sizeofSelect); -+ for (j = 0; j < pcr_sel->pcrSelections[pcr_sel->count].sizeofSelect; j++) -+ pcr_sel->pcrSelections[pcr_sel->count].pcrSelect[j] = cap_data->data.assignedPCR.pcrSelections[i].pcrSelect[j]; -+ pcr_sel->count++; -+ } -+ -+ if (pcr_sel->count == 0) -+ return false; -+ -+ return true; -+} -+ -+bool pcr_check_pcr_selection(TPMS_CAPABILITY_DATA *cap_data, TPML_PCR_SELECTION *pcr_sel) { -+ -+ UINT32 i, j, k; -+ -+ for (i = 0; i < pcr_sel->count; i++) { -+ for (j = 0; j < cap_data->data.assignedPCR.count; j++) { -+ if (pcr_sel->pcrSelections[i].hash == cap_data->data.assignedPCR.pcrSelections[j].hash) { -+ for (k = 0; k < pcr_sel->pcrSelections[i].sizeofSelect; k++) -+ pcr_sel->pcrSelections[i].pcrSelect[k] &= cap_data->data.assignedPCR.pcrSelections[j].pcrSelect[k]; -+ break; -+ } -+ } -+ -+ if (j >= cap_data->data.assignedPCR.count) { -+ const char *alg_name = tpm2_alg_util_algtostr(pcr_sel->pcrSelections[i].hash); -+ LOG_WARN("Ignore unsupported bank/algorithm: %s(0x%04x)", alg_name, pcr_sel->pcrSelections[i].hash); -+ pcr_sel->pcrSelections[i].hash = 0; //mark it as to be removed -+ } -+ } -+ -+ shrink_pcr_selection(pcr_sel); -+ if (pcr_sel->count == 0) -+ return false; -+ -+ return true; -+} -+ -+bool pcr_read_pcr_values(TSS2_SYS_CONTEXT *sapi_context, TPML_PCR_SELECTION *pcrSelections, tpm2_pcrs *pcrs) { -+ -+ TPML_PCR_SELECTION pcr_selection_tmp; -+ TPML_PCR_SELECTION pcr_selection_out; -+ UINT32 pcr_update_counter; -+ -+ //1. prepare pcrSelectionIn with g_pcrSelections -+ memcpy(&pcr_selection_tmp, pcrSelections, sizeof(pcr_selection_tmp)); -+ -+ //2. call pcr_read -+ pcrs->count = 0; -+ do { -+ UINT32 rval = TSS2_RETRY_EXP(Tss2_Sys_PCR_Read(sapi_context, no_argument, &pcr_selection_tmp, -+ &pcr_update_counter, &pcr_selection_out, -+ &pcrs->pcr_values[pcrs->count], 0)); -+ -+ if (rval != TPM2_RC_SUCCESS) { -+ LOG_ERR("read pcr failed. tpm error 0x%0x", rval); -+ return -1; -+ } -+ -+ //3. unmask pcrSelectionOut bits from pcrSelectionIn -+ pcr_update_pcr_selections(&pcr_selection_tmp, &pcr_selection_out); -+ -+ //4. goto step 2 if pcrSelctionIn still has bits set -+ } while (++pcrs->count < sizeof(pcrs->pcr_values) && !pcr_unset_pcr_sections(&pcr_selection_tmp)); -+ -+ if (pcrs->count >= sizeof(pcrs->pcr_values) && !pcr_unset_pcr_sections(&pcr_selection_tmp)) { -+ LOG_ERR("too much pcrs to get! try to split into multiple calls..."); -+ return false; -+ } -+ -+ return true; -+} -diff --git a/lib/pcr.h b/lib/pcr.h -index ad6946b3c04..82d5dd696d4 100644 ---- a/lib/pcr.h -+++ b/lib/pcr.h -@@ -35,8 +35,35 @@ - - #include - -+typedef struct tpm2_algorithm tpm2_algorithm; -+struct tpm2_algorithm { -+ int count; -+ TPMI_ALG_HASH alg[TPM2_NUM_PCR_BANKS]; -+}; -+ -+typedef struct tpm2_pcrs tpm2_pcrs; -+struct tpm2_pcrs { -+ size_t count; -+ TPML_DIGEST pcr_values[TPM2_MAX_PCRS]; -+}; -+ -+/** -+ * Echo out all PCR banks according to g_pcrSelection & g_pcrs->. -+ * @param pcrSelect -+ * Description of which PCR registers are selected. -+ * @param pcrs -+ * Struct containing PCR digests. -+ * @return -+ * True on success, false otherwise. -+ */ -+bool pcr_print_pcr_struct(TPML_PCR_SELECTION *pcrSelect, tpm2_pcrs *pcrs); -+ - bool pcr_parse_selections(const char *arg, TPML_PCR_SELECTION *pcrSels); - bool pcr_parse_list(const char *str, size_t len, TPMS_PCR_SELECTION *pcrSel); - TSS2_RC get_max_supported_pcrs(TSS2_SYS_CONTEXT *sapi_context, UINT32 *max_pcrs); -+bool pcr_get_banks(TSS2_SYS_CONTEXT *sapi_context, TPMS_CAPABILITY_DATA *capability_data, tpm2_algorithm *algs); -+bool pcr_init_pcr_selection(TPMS_CAPABILITY_DATA *cap_data, TPML_PCR_SELECTION *pcr_sel, TPMI_ALG_HASH alg_id); -+bool pcr_check_pcr_selection(TPMS_CAPABILITY_DATA *cap_data, TPML_PCR_SELECTION *pcr_sel); -+bool pcr_read_pcr_values(TSS2_SYS_CONTEXT *sapi_context, TPML_PCR_SELECTION *pcrSelections, tpm2_pcrs *pcrs); - - #endif /* SRC_PCR_H_ */ -diff --git a/lib/tpm2_openssl.c b/lib/tpm2_openssl.c -index 0bfc95bd1ef..8d7314cba8e 100644 ---- a/lib/tpm2_openssl.c -+++ b/lib/tpm2_openssl.c -@@ -44,9 +44,26 @@ - #include "files.h" - #include "log.h" - #include "tpm2_alg_util.h" -+#include "tpm_kdfa.h" - #include "tpm2_openssl.h" - #include "tpm2_util.h" - -+int tpm2_openssl_halgid_from_tpmhalg(TPMI_ALG_HASH algorithm) { -+ -+ switch (algorithm) { -+ case TPM2_ALG_SHA1: -+ return NID_sha1; -+ case TPM2_ALG_SHA256: -+ return NID_sha256; -+ case TPM2_ALG_SHA384: -+ return NID_sha384; -+ case TPM2_ALG_SHA512: -+ return NID_sha512; -+ default: -+ return NID_sha256; -+ } -+ /* no return, not possible */ -+} - - const EVP_MD *tpm2_openssl_halg_from_tpmhalg(TPMI_ALG_HASH algorithm) { - -@@ -122,6 +139,127 @@ void tpm2_openssl_cipher_free(EVP_CIPHER_CTX *ctx) { - #endif - } - -+bool tpm2_openssl_hash_compute_data(TPMI_ALG_HASH halg, -+ BYTE *buffer, UINT16 length, TPM2B_DIGEST *digest) { -+ -+ bool result = false; -+ -+ const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(halg); -+ if (!md) { -+ return false; -+ } -+ -+ EVP_MD_CTX *mdctx = EVP_MD_CTX_create(); -+ if (!mdctx) { -+ LOG_ERR("%s", get_openssl_err()); -+ return false; -+ } -+ -+ int rc = EVP_DigestInit_ex(mdctx, md, NULL); -+ if (!rc) { -+ LOG_ERR("%s", get_openssl_err()); -+ goto out; -+ } -+ -+ rc = EVP_DigestUpdate(mdctx, buffer, length); -+ if (!rc) { -+ LOG_ERR("%s", get_openssl_err()); -+ goto out; -+ } -+ -+ unsigned size = EVP_MD_size(md); -+ rc = EVP_DigestFinal_ex(mdctx, digest->buffer, &size); -+ if (!rc) { -+ LOG_ERR("%s", get_openssl_err()); -+ goto out; -+ } -+ -+ digest->size = size; -+ -+ result = true; -+ -+out: -+ EVP_MD_CTX_destroy(mdctx); -+ return result; -+} -+ -+// show all PCR banks according to g_pcrSelection & g_pcrs-> -+bool tpm2_openssl_hash_pcr_banks(TPMI_ALG_HASH hashAlg, -+ TPML_PCR_SELECTION *pcrSelect, -+ tpm2_pcrs *pcrs, TPM2B_DIGEST *digest) { -+ -+ UINT32 vi = 0, di = 0, i; -+ bool result = false; -+ -+ const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(hashAlg); -+ if (!md) { -+ return false; -+ } -+ -+ EVP_MD_CTX *mdctx = EVP_MD_CTX_create(); -+ if (!mdctx) { -+ LOG_ERR("%s", get_openssl_err()); -+ return false; -+ } -+ -+ int rc = EVP_DigestInit_ex(mdctx, md, NULL); -+ if (!rc) { -+ LOG_ERR("%s", get_openssl_err()); -+ goto out; -+ } -+ -+ // Loop through all PCR/hash banks -+ for (i = 0; i < pcrSelect->count; i++) { -+ -+ // Loop through all PCRs in this bank -+ UINT8 pcr_id; -+ for (pcr_id = 0; pcr_id < pcrSelect->pcrSelections[i].sizeofSelect * 8; pcr_id++) { -+ if (!tpm2_util_is_pcr_select_bit_set(&pcrSelect->pcrSelections[i], -+ pcr_id)) { -+ // skip non-selected banks -+ continue; -+ } -+ if (vi >= pcrs->count || di >= pcrs->pcr_values[vi].count) { -+ LOG_ERR("Something wrong, trying to print but nothing more"); -+ goto out; -+ } -+ -+ // Update running digest (to compare with quote) -+ TPM2B_DIGEST *b = &pcrs->pcr_values[vi].digests[di]; -+ rc = EVP_DigestUpdate(mdctx, b->buffer, b->size); -+ if (!rc) { -+ LOG_ERR("%s", get_openssl_err()); -+ goto out; -+ } -+ -+ if (++di < pcrs->pcr_values[vi].count) { -+ continue; -+ } -+ -+ di = 0; -+ if (++vi < pcrs->count) { -+ continue; -+ } -+ } -+ } -+ -+ // Finalize running digest -+ unsigned size = EVP_MD_size(md); -+ rc = EVP_DigestFinal_ex(mdctx, digest->buffer, &size); -+ if (!rc) { -+ LOG_ERR("%s", get_openssl_err()); -+ goto out; -+ } -+ -+ digest->size = size; -+ -+ result = true; -+ -+out: -+ EVP_MD_CTX_destroy(mdctx); -+ return result; -+} -+ - digester tpm2_openssl_halg_to_digester(TPMI_ALG_HASH halg) { - - switch(halg) { -@@ -160,3 +298,28 @@ digester tpm2_openssl_halg_to_digester(TPMI_ALG_HASH halg) { - */ - - typedef bool (*pfn_ossl_pw_handler)(const char *passin, char **pass); -+ -+ -+RSA *tpm2_openssl_get_public_RSA_from_pem(FILE *f, const char *path) { -+ -+ /* -+ * Public PEM files appear in two formats: -+ * 1. PEM format, read with PEM_read_RSA_PUBKEY -+ * 2. PKCS#1 format, read with PEM_read_RSAPublicKey -+ * -+ * See: -+ * - https://stackoverflow.com/questions/7818117/why-i-cant-read-openssl-generated-rsa-pub-key-with-pem-read-rsapublickey -+ */ -+ RSA *pub = PEM_read_RSA_PUBKEY(f, NULL, NULL, NULL); -+ if (!pub) { -+ pub = PEM_read_RSAPublicKey(f, NULL, NULL, NULL); -+ } -+ -+ if (!pub) { -+ ERR_print_errors_fp (stderr); -+ LOG_ERR("Reading public PEM file \"%s\" failed", path); -+ return NULL; -+ } -+ -+ return pub; -+} -diff --git a/lib/tpm2_openssl.h b/lib/tpm2_openssl.h -index d749cb350ac..d3f4a0d7a32 100644 ---- a/lib/tpm2_openssl.h -+++ b/lib/tpm2_openssl.h -@@ -34,6 +34,8 @@ - #include - #include - -+#include "pcr.h" -+ - #if (OPENSSL_VERSION_NUMBER < 0x1010000fL && !defined(LIBRESSL_VERSION_NUMBER)) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) /* OpenSSL 1.1.0 */ - #define LIB_TPM2_OPENSSL_OPENSSL_PRE11 - #endif -@@ -60,6 +62,16 @@ int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d); - */ - typedef unsigned char *(*digester)(const unsigned char *d, size_t n, unsigned char *md); - -+/** -+ -+ * Get an openssl hash algorithm ID from a tpm hashing algorithm ID. -+ * @param algorithm -+ * The tpm algorithm to get the corresponding openssl version of. -+ * @return -+ * The openssl hash algorithm id. -+ */ -+int tpm2_openssl_halgid_from_tpmhalg(TPMI_ALG_HASH algorithm); -+ - /** - * Get an openssl message digest from a tpm hashing algorithm. - * @param algorithm -@@ -86,6 +98,39 @@ EVP_CIPHER_CTX *tpm2_openssl_cipher_new(void); - */ - void tpm2_openssl_cipher_free(EVP_CIPHER_CTX *ctx); - -+/** -+ * Hash a byte buffer. -+ * @param halg -+ * The hashing algorithm to use. -+ * @param buffer -+ * The byte buffer to be hashed. -+ * @param length -+ * The length of the byte buffer to hash. -+^ * @param digest -+^ * The result of hashing digests with halg. -+ * @return -+ * true on success, false on error. -+ */ -+bool tpm2_openssl_hash_compute_data(TPMI_ALG_HASH halg, -+ BYTE *buffer, UINT16 length, TPM2B_DIGEST *digest); -+ -+/** -+ * Hash a list of PCR digests, supporting multiple banks. -+ * @param halg -+ * The hashing algorithm to use. -+ * @param pcrSelect -+ * The list that specifies which PCRs are selected. -+ * @param pcrs -+ * The list of PCR banks, each containing a list of PCR digests to hash. -+^ * @param digest -+^ * The result of hashing digests with halg. -+ * @return -+ * true on success, false on error. -+ */ -+bool tpm2_openssl_hash_pcr_banks(TPMI_ALG_HASH hashAlg, -+ TPML_PCR_SELECTION *pcrSelect, -+ tpm2_pcrs *pcrs, TPM2B_DIGEST *digest); -+ - /** - * Returns a function pointer capable of performing the - * given digest from a TPMI_HASH_ALG. -@@ -105,4 +150,16 @@ enum tpm2_openssl_load_rc { - }; - - -+/** -+ * Retrieves a public portion of an RSA key from a PEM file. -+ * -+ * @param f -+ * The FILE object that is open for reading the path. -+ * @param path -+ * The path to load from. -+ * @return -+ * The public structure. -+ */ -+RSA* tpm2_openssl_get_public_RSA_from_pem(FILE *f, const char *path); -+ - #endif /* LIB_TPM2_OPENSSL_H_ */ -diff --git a/lib/tpm2_util.c b/lib/tpm2_util.c -index 57d6c762a70..edfda4a8b0b 100644 ---- a/lib/tpm2_util.c -+++ b/lib/tpm2_util.c -@@ -41,6 +41,154 @@ - #include "tpm2_tool.h" - #include "tpm2_util.h" - -+ -+bool tpm2_util_get_digest_from_quote(TPM2B_ATTEST *quoted, TPM2B_DIGEST *digest, TPM2B_DATA *extraData) { -+ TPM2_GENERATED magic; -+ TPMI_ST_ATTEST type; -+ UINT16 nameSize = 0; -+ UINT32 i = 0; -+ -+ // Ensure required headers are at least there -+ if (quoted->size < 6) { -+ LOG_ERR("Malformed TPM2B_ATTEST headers"); -+ return false; -+ } -+ -+ memcpy(&magic, "ed->attestationData[i], 4);i += 4; -+ memcpy(&type, "ed->attestationData[i], 2);i += 2; -+ if (!tpm2_util_is_big_endian()) { -+ magic = tpm2_util_endian_swap_32(magic); -+ type = tpm2_util_endian_swap_16(type); -+ } -+ -+ if (magic != TPM2_GENERATED_VALUE) { -+ LOG_ERR("Malformed TPM2_GENERATED magic value"); -+ return false; -+ } -+ -+ if (type != TPM2_ST_ATTEST_QUOTE) { -+ LOG_ERR("Malformed TPMI_ST_ATTEST quote value"); -+ return false; -+ } -+ -+ // Qualified signer name (skip) -+ if (i+2 >= quoted->size) { -+ LOG_ERR("Malformed TPM2B_NAME value"); -+ return false; -+ } -+ memcpy(&nameSize, "ed->attestationData[i], 2);i += 2; -+ if (!tpm2_util_is_big_endian()) { -+ nameSize = tpm2_util_endian_swap_16(nameSize); -+ } -+ i += nameSize; -+ -+ // Extra data (skip) -+ if (i+2 >= quoted->size) { -+ LOG_ERR("Malformed TPM2B_DATA value"); -+ return false; -+ } -+ memcpy(&extraData->size, "ed->attestationData[i], 2);i += 2; -+ if (!tpm2_util_is_big_endian()) { -+ extraData->size = tpm2_util_endian_swap_16(extraData->size); -+ } -+ if (extraData->size+i > quoted->size) { -+ LOG_ERR("Malformed extraData TPM2B_DATA value"); -+ return false; -+ } -+ memcpy(&extraData->buffer, "ed->attestationData[i], extraData->size);i += extraData->size; -+ -+ // Clock info (skip) -+ i += 17; -+ if (i >= quoted->size) { -+ LOG_ERR("Malformed TPMS_CLOCK_INFO value"); -+ return false; -+ } -+ -+ // Firmware info (skip) -+ i += 8; -+ if (i >= quoted->size) { -+ LOG_ERR("Malformed firmware version value"); -+ return false; -+ } -+ -+ // PCR select info -+ UINT8 sos; -+ TPMI_ALG_HASH hashAlg; -+ UINT32 pcrSelCount = 0, j = 0; -+ if (i+4 >= quoted->size) { -+ LOG_ERR("Malformed TPML_PCR_SELECTION value"); -+ return false; -+ } -+ memcpy(&pcrSelCount, "ed->attestationData[i], 4);i += 4; -+ if (!tpm2_util_is_big_endian()) { -+ pcrSelCount = tpm2_util_endian_swap_32(pcrSelCount); -+ } -+ for (j = 0; j < pcrSelCount; j++) { -+ // Hash -+ if (i+2 >= quoted->size) { -+ LOG_ERR("Malformed TPMS_PCR_SELECTION value"); -+ return false; -+ } -+ memcpy(&hashAlg, "ed->attestationData[i], 2);i += 2; -+ if (!tpm2_util_is_big_endian()) { -+ hashAlg = tpm2_util_endian_swap_16(hashAlg); -+ } -+ -+ // SizeOfSelected -+ if (i+1 >= quoted->size) { -+ LOG_ERR("Malformed TPMS_PCR_SELECTION value"); -+ return false; -+ } -+ memcpy(&sos, "ed->attestationData[i], 1);i += 1; -+ -+ // PCR Select (skip) -+ i += sos; -+ if (i >= quoted->size) { -+ LOG_ERR("Malformed TPMS_PCR_SELECTION value"); -+ return false; -+ } -+ } -+ -+ // Digest -+ if (i+2 >= quoted->size) { -+ LOG_ERR("Malformed TPM2B_DIGEST value"); -+ return false; -+ } -+ memcpy(&digest->size, "ed->attestationData[i], 2);i += 2; -+ if (!tpm2_util_is_big_endian()) { -+ digest->size = tpm2_util_endian_swap_16(digest->size); -+ } -+ -+ if (digest->size+i > quoted->size) { -+ LOG_ERR("Malformed TPM2B_DIGEST value"); -+ return false; -+ } -+ memcpy(&digest->buffer, "ed->attestationData[i], digest->size); -+ -+ return true; -+} -+ -+// verify that the quote digest equals the digest we calculated -+bool tpm2_util_verify_digests(TPM2B_DIGEST *quoteDigest, TPM2B_DIGEST *pcrDigest) { -+ -+ // Sanity check -- they should at least be same size! -+ if (quoteDigest->size != pcrDigest->size) { -+ LOG_ERR("FATAL ERROR: PCR values failed to match quote's digest!"); -+ return false; -+ } -+ -+ // Compare running digest with quote's digest -+ int k; -+ for (k = 0; k < quoteDigest->size; k++) { -+ if (quoteDigest->buffer[k] != pcrDigest->buffer[k]) { -+ LOG_ERR("FATAL ERROR: PCR values failed to match quote's digest!"); -+ return false; -+ } -+ } -+ -+ return true; -+} -+ - bool tpm2_util_concat_buffer(TPM2B_MAX_BUFFER *result, TPM2B *append) { - - if (!result || !append) { -diff --git a/lib/tpm2_util.h b/lib/tpm2_util.h -index e803dc1c30e..8b77c9e5374 100644 ---- a/lib/tpm2_util.h -+++ b/lib/tpm2_util.h -@@ -111,6 +111,30 @@ struct TPM2B { - - int tpm2_util_hex_to_byte_structure(const char *inStr, UINT16 *byteLenth, BYTE *byteBuffer); - -+/** -+ * Pulls the TPM2B_DIGEST out of a TPM2B_ATTEST quote. -+ * @param quoted -+ * The attestation quote structure. -+^ * @param digest -+^ * The digest from the quote. -+^ * @param extraData -+^ * The extraData from the quote. -+ * @return -+ * True on success, false otherwise. -+ */ -+bool tpm2_util_get_digest_from_quote(TPM2B_ATTEST *quoted, TPM2B_DIGEST *digest, TPM2B_DATA *extraData); -+ -+/** -+ * Compares two digests to ensure they are equal (for validation). -+ * @param quoteDigest -+ * The digest from the quote. -+ * @param pcrDigest -+ * The digest calculated off-TMP from the PCRs. -+ * @return -+ * True on success, false otherwise. -+ */ -+bool tpm2_util_verify_digests(TPM2B_DIGEST *quoteDigest, TPM2B_DIGEST *pcrDigest); -+ - /** - * Appends a TPM2B_DIGEST buffer to a TPM2B_MAX buffer. - * @param result -@@ -170,6 +194,15 @@ static inline void tpm2_util_print_tpm2b(TPM2B *buffer) { - - void tpm2_util_print_tpm2b(TPM2B *buffer); - -+/** -+ * Determines if given PCR value is selected in TPMS_PCR_SELECTION structure. -+ * @param pcr_selection the TPMS_PCR_SELECTION structure to check pcr against. -+ * @param pcr the PCR ID to check selection status of. -+ */ -+static inline bool tpm2_util_is_pcr_select_bit_set(TPMS_PCR_SELECTION *pcr_selection, UINT32 pcr) { -+ return (pcr_selection->pcrSelect[((pcr) / 8)] & (1 << ((pcr) % 8))); -+} -+ - /** - * Copies a tpm2b from dest to src and clears dest if src is NULL. - * If src is NULL, it is a NOP. -diff --git a/man/tpm2_checkquote.1.md b/man/tpm2_checkquote.1.md -new file mode 100644 -index 00000000000..00bb4bee9a7 ---- /dev/null -+++ b/man/tpm2_checkquote.1.md -@@ -0,0 +1,95 @@ -+% tpm2_checkquote(1) tpm2-tools | General Commands Manual -+% -+% JANUARY 2019 -+ -+# NAME -+ -+**tpm2_checkquote**(1) - Validates a quote provided by a TPM. -+ -+# SYNOPSIS -+ -+**tpm2_checkquote** [*OPTIONS*] -+ -+# DESCRIPTION -+ -+**tpm2_checkquote**(1) - Uses the public portion of the provided key to validate a quote -+generated by a TPM. This will validate the signature against the quote message and, if -+provided, verify that the qualifying data and PCR values match those in the quote. -+ -+# OPTIONS -+ -+ * **-c**, **--key-context**=_KEY\_CONTEXT\_OBJECT_: -+ -+ Context object for the key context used for the operation. Either a file -+ or a handle number. See section "Context Object Format". -+ -+ * **-G**, **--halg**=_HASH\_ALGORITHM_: -+ -+ The hash algorithm used to digest the message. -+ Algorithms should follow the "formatting standards", see section -+ "Algorithm Specifiers". -+ Also, see section "Supported Hash Algorithms" for a list of supported hash -+ algorithms. -+ -+ * **-m**, **--message**=_MSG\_FILE_: -+ -+ The quote message that makes up the data that is signed by the TPM. -+ -+ * **-s**, **--sig**=_SIG\_FILE_: -+ -+ The input signature file of the signature to be validated. -+ -+ * **-f**, **--format**: -+ -+ Set the input signature file to a specified format. The default is the TPM2.0 **TPMT_SIGNATURE** -+ data format, however different schemes can be selected if the data came from an external -+ source like OpenSSL. The tool currently only supports rsassa. -+ -+ Algorithms should follow the "formatting standards", see section -+ "Algorithm Specifiers". -+ Also, see section "Supported Signing Schemes" for a list of supported hash -+ algorithms. -+ -+ * **-p**, **--pcrs**: -+ -+ PCR output file, optional, records the list of PCR values that were included -+ in the quote. -+ -+ * **-q**, **--qualify-data**: -+ -+ Data given as a hex string that was used to qualify the quote. This is typically -+ used to add a nonce against replay attacks. -+ -+[common options](common/options.md) -+ -+[common tcti options](common/tcti.md) -+ -+[context object format](common/ctxobj.md) -+ -+[authorization formatting](common/password.md) -+ -+[supported hash algorithms](common/hash.md) -+ -+[supported signing schemes](common/signschemes.md) -+ -+[algorithm specifiers](common/alg.md) -+ -+# EXAMPLES -+ -+## Generate a quote with a TPM, then verify it -+``` -+tpm2_createprimary -H e -g sha256 -G rsa -C primary.ctx -+tpm2_create -g sha256 -G rsa -u ak.pub -r ak.priv -c primary.ctx -+tpm2_load -c primary.ctx -u ak.pub -r ak.priv -n ak.name -C ak.ctx -+tpm2_readpublic -c ak.ctx -o akpub.pem -f pem -+ -+tpm2_quote -c ak.ctx -L sha256:15,16,22 -q abc123 -m quote.out -s sig.out -p pcrs.out -G sha256 -+ -+tpm2_checkquote -c akpub.pem -m quote.out -s sig.out -p pcrs.out -G sha256 -q abc123 -+``` -+ -+# RETURNS -+ -+0 on success or 1 on failure. -+ -+[footer](common/footer.md) -diff --git a/man/tpm2_quote.1.md b/man/tpm2_quote.1.md -index 88c37e040c1..491848201d9 100644 ---- a/man/tpm2_quote.1.md -+++ b/man/tpm2_quote.1.md -@@ -53,6 +53,13 @@ - - Format selection for the signature output file. See section "Signature Format Specifiers". - -+ * **-p**, **--pcrs**: -+ -+ PCR output file, optional, records the list of PCR values as defined -+ by **-l** or **-L**. Note that only the digest of these values is stored in the -+ signed quote message -- these values themselves are not signed or -+ stored in the message. -+ - * **-q**, **--qualify-data**: - - Data given as a Hex string to qualify the quote, optional. This is typically -@@ -63,7 +70,7 @@ - - * **-G**, **--sig-hash-algorithm**: - -- Hash algorithm for signature. -+ Hash algorithm for signature. Required if **-p** is given. - - [common options](common/options.md) - -diff --git a/test/system/test_tpm2_checkquote.sh b/test/system/test_tpm2_checkquote.sh -new file mode 100755 -index 00000000000..670e3a737d1 ---- /dev/null -+++ b/test/system/test_tpm2_checkquote.sh -@@ -0,0 +1,86 @@ -+#!/bin/bash -+#;**********************************************************************; -+# -+# Copyright (c) 2019 Massachusetts Institute of Technology. -+# 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 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 HOLDER 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. -+#;**********************************************************************; -+ -+source test_helpers.sh -+ -+alg_primary_obj=sha256 -+alg_primary_key=rsa -+alg_create_obj=sha256 -+alg_create_key=rsa -+ -+file_primary_key_ctx=context.p_"$alg_primary_obj"_"$alg_primary_key" -+file_quote_key_pub=opu_"$alg_create_obj"_"$alg_create_key" -+file_quote_key_priv=opr_"$alg_create_obj"_"$alg_create_key" -+file_quote_key_name=name.load_"$alg_primary_obj"_"$alg_primary_key"-"$alg_create_obj"_"$alg_create_key" -+file_quote_key_ctx=ctx_load_out_"$alg_primary_obj"_"$alg_primary_key"-"$alg_create_obj"_"$alg_create_key" -+output_ak_pub_pem=akpub.pem -+output_quote=quote.out -+output_quotesig=quotesig.out -+output_quotepcr=quotepcr.out -+ -+maxdigest=$(tpm2_getcap -c properties-fixed | grep TPM_PT_MAX_DIGEST | sed -r -e 's/.*(0x[0-9a-f]+)/\1/g') -+if ! [[ "$maxdigest" =~ ^(0x)*[0-9]+$ ]] ; then -+ echo "error: not a number, got: \"$maxdigest\"" >&2 -+ exit 1 -+fi -+ -+nonce=12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde -+nonce=${nonce:0:2*$maxdigest} -+ -+cleanup() { -+ rm -f $file_primary_key_ctx $file_quote_key_pub $file_quote_key_priv \ -+ $file_quote_key_name $file_quote_key_ctx $output_ak_pub_pem \ -+ $output_quote $output_quotesig $output_quotepcr -+} -+trap cleanup EXIT -+ -+cleanup -+ -+ -+tpm2_takeownership -c -+ -+# Key generation -+tpm2_createprimary -Q -H e -g $alg_primary_obj -G $alg_primary_key -C $file_primary_key_ctx -+tpm2_create -Q -g $alg_create_obj -G $alg_create_key -u $file_quote_key_pub -r $file_quote_key_priv -c $file_primary_key_ctx -+tpm2_load -Q -c $file_primary_key_ctx -u $file_quote_key_pub -r $file_quote_key_priv -n $file_quote_key_name -C $file_quote_key_ctx -+ -+# Get the PEM version of pub ak cert -+tpm2_readpublic -Q -c $file_quote_key_ctx -o $output_ak_pub_pem -f pem -+ -+# Quoting -+tpm2_quote -Q -c $file_quote_key_ctx -L sha256:15,16,22 -q $nonce -m $output_quote -s $output_quotesig -p $output_quotepcr -G $alg_primary_obj -+ -+# Verify quote -+tpm2_checkquote -Q -c $output_ak_pub_pem -m $output_quote -s $output_quotesig -p $output_quotepcr -G $alg_primary_obj -q $nonce -+ -+exit 0 -diff --git a/test/system/test_tpm2_quote.sh b/test/system/test_tpm2_quote.sh -index 231bed326ec..aa06a3d7040 100755 ---- a/test/system/test_tpm2_quote.sh -+++ b/test/system/test_tpm2_quote.sh -@@ -52,6 +52,8 @@ Handle_ek_quote=0x81010017 - Handle_ak_quote2=0x81010018 - Handle_ak_quote3=0x81010019 - -+toss_out=junk.out -+ - maxdigest=$(tpm2_getcap -c properties-fixed | grep TPM_PT_MAX_DIGEST | sed -r -e 's/.*(0x[0-9a-f]+)/\1/g') - if ! [[ "$maxdigest" =~ ^(0x)*[0-9]+$ ]] ; then - echo "error: not a number, got: \"$maxdigest\"" >&2 -@@ -69,7 +71,7 @@ trap onerror ERR - - cleanup() { - rm -f $file_primary_key_ctx $file_quote_key_pub $file_quote_key_priv \ -- $file_quote_key_name $file_quote_key_ctx ek.pub2 ak.pub2 ak.name_2 \ -+ $file_quote_key_name $file_quote_key_ctx $toss_out ek.pub2 ak.pub2 ak.name_2 \ - - tpm2_evictcontrol -Q -Ao -H $Handle_ek_quote 2>/dev/null || true - tpm2_evictcontrol -Q -Ao -H $Handle_ak_quote 2>/dev/null || true -@@ -90,21 +92,21 @@ tpm2_load -Q -c $file_primary_key_ctx -u $file_quote_key_pub -r $file_quote_ke - - tpm2_quote -Q -c $file_quote_key_ctx -g $alg_quote -l 16,17,18 -q $nonce - --tpm2_quote -Q -c $file_quote_key_ctx -L $alg_quote:16,17,18+$alg_quote1:16,17,18 -q $nonce -+tpm2_quote -Q -c $file_quote_key_ctx -L $alg_quote:16,17,18+$alg_quote1:16,17,18 -q $nonce -m $toss_out -s $toss_out -p $toss_out -G $alg_primary_obj - - #####handle testing - tpm2_evictcontrol -Q -A o -c $file_quote_key_ctx -S $Handle_ak_quote - --tpm2_quote -Q -k $Handle_ak_quote -g $alg_quote -l 16,17,18 -q $nonce -+tpm2_quote -Q -k $Handle_ak_quote -g $alg_quote -l 16,17,18 -q $nonce -m $toss_out -s $toss_out -p $toss_out -G $alg_primary_obj - --tpm2_quote -Q -k $Handle_ak_quote -L $alg_quote:16,17,18+$alg_quote1:16,17,18 -q $nonce -+tpm2_quote -Q -k $Handle_ak_quote -L $alg_quote:16,17,18+$alg_quote1:16,17,18 -q $nonce -m $toss_out -s $toss_out -p $toss_out -G $alg_primary_obj - - #####AK - tpm2_getpubek -Q -H $Handle_ek_quote -g 0x01 -f ek.pub2 - - tpm2_getpubak -Q -E $Handle_ek_quote -k $Handle_ak_quote2 -f ak.pub2 -n ak.name_2 - --tpm2_quote -Q -k $Handle_ak_quote -g $alg_quote -l 16,17,18 -q $nonce -+tpm2_quote -Q -k $Handle_ak_quote -g $alg_quote -l 16,17,18 -q $nonce -m $toss_out -s $toss_out -p $toss_out -G $alg_primary_obj - - #####AK with password - tpm2_getpubak -Q -E $Handle_ek_quote -k $Handle_ak_quote3 -f ak.pub2 -n ak.name_2 -P abc123 -diff --git a/tools/tpm2_checkquote.c b/tools/tpm2_checkquote.c -new file mode 100644 -index 00000000000..0efd7f3ca88 ---- /dev/null -+++ b/tools/tpm2_checkquote.c -@@ -0,0 +1,409 @@ -+//**********************************************************************; -+// Copyright (c) 2019 Massachusetts Institute of Technology. -+// 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 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 HOLDER 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 "files.h" -+#include "log.h" -+#include "pcr.h" -+#include "tpm2_alg_util.h" -+#include "conversion.h" -+#include "tpm_hash.h" -+#include "tpm2_openssl.h" -+#include "tpm2_options.h" -+#include "tpm2_tool.h" -+#include "tpm2_util.h" -+ -+typedef struct tpm2_verifysig_ctx tpm2_verifysig_ctx; -+struct tpm2_verifysig_ctx { -+ union { -+ struct { -+ UINT8 halg :1; -+ UINT8 msg :1; -+ UINT8 sig :1; -+ UINT8 pcr :1; -+ UINT8 extra :1; -+ UINT8 key_context :1; -+ UINT8 fmt; -+ }; -+ UINT8 all; -+ } flags; -+ TPMI_ALG_SIG_SCHEME format; -+ TPMI_ALG_HASH halg; -+ TPM2B_DIGEST msgHash; -+ TPM2B_DIGEST pcrHash; -+ TPM2B_DIGEST quoteHash; -+ TPM2B_DATA quoteExtraData; -+ TPM2B_DATA extraData; -+ TPMT_SIGNATURE signature; -+ char *msg_file_path; -+ char *sig_file_path; -+ char *out_file_path; -+ char *pcr_file_path; -+ const char *pubkey_file_path; -+}; -+ -+tpm2_verifysig_ctx ctx = { -+ .format = TPM2_ALG_ERROR, -+ .halg = TPM2_ALG_SHA1, -+ .msgHash = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer), -+ .pcrHash = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer), -+ .quoteHash = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer), -+ .quoteExtraData = TPM2B_TYPE_INIT(TPM2B_DATA, buffer), -+ .extraData = TPM2B_TYPE_INIT(TPM2B_DATA, buffer), -+}; -+ -+static bool verify_signature() { -+ -+ bool result = false; -+ -+ // Read in the AKpub they provided as an RSA object -+ FILE *pubkey_input = fopen(ctx.pubkey_file_path, "rb"); -+ if (!pubkey_input) { -+ LOG_ERR("Could not open RSA pubkey input file \"%s\" error: \"%s\"", -+ ctx.pubkey_file_path, strerror(errno)); -+ return false; -+ } -+ RSA *pubKey = tpm2_openssl_get_public_RSA_from_pem(pubkey_input, ctx.pubkey_file_path); -+ if (pubKey == NULL) { -+ LOG_ERR("Failed to load RSA public key from file"); -+ goto err; -+ } -+ -+ // Get the signature ready -+ if (ctx.signature.sigAlg != TPM2_ALG_RSASSA) { -+ LOG_ERR("Only RSASSA is supported for signatures"); -+ goto err; -+ } -+ TPM2B_PUBLIC_KEY_RSA sig = ctx.signature.signature.rsassa.sig; -+ tpm2_tool_output("sigBuffer: "); -+ tpm2_util_hexdump(sig.buffer, sig.size, true); -+ tpm2_tool_output("\n"); -+ -+ // Verify the signature matches message digest -+ int opensslHash = tpm2_openssl_halgid_from_tpmhalg(ctx.signature.signature.rsassa.hash); -+ if (!RSA_verify(opensslHash, ctx.msgHash.buffer, ctx.msgHash.size, -+ sig.buffer, sig.size, pubKey)) { -+ LOG_ERR("Error validating signed message with public key provided"); -+ goto err; -+ } -+ -+ // Ensure nonce is the same as given -+ if (ctx.flags.extra) { -+ if ( -+ ctx.quoteExtraData.size != ctx.extraData.size -+ || memcmp(ctx.quoteExtraData.buffer, ctx.extraData.buffer, ctx.extraData.size) != 0 -+ ) { -+ LOG_ERR("Error validating nonce from quote"); -+ goto err; -+ } -+ } -+ -+ // Also ensure digest from quote matches PCR digest -+ if (ctx.flags.pcr) { -+ if (!tpm2_util_verify_digests(&ctx.quoteHash, &ctx.pcrHash)) { -+ LOG_ERR("Error validating PCR composite against signed message"); -+ goto err; -+ } -+ } -+ -+ result = true; -+ -+err: -+ if (pubkey_input) { -+ fclose(pubkey_input); -+ } -+ -+ RSA_free(pubKey); -+ -+ return result; -+} -+ -+static TPM2B_ATTEST *message_from_file(const char *msg_file_path) { -+ -+ unsigned long size; -+ -+ bool result = files_get_file_size_path(msg_file_path, &size); -+ if (!result) { -+ return NULL; -+ } -+ -+ if (!size) { -+ LOG_ERR("The msg file \"%s\" is empty", msg_file_path); -+ return NULL; -+ } -+ -+ TPM2B_ATTEST *msg = (TPM2B_ATTEST *) calloc(1, sizeof(TPM2B_ATTEST) + size); -+ if (!msg) { -+ LOG_ERR("OOM"); -+ return NULL; -+ } -+ -+ UINT16 tmp = msg->size = size; -+ if (!files_load_bytes_from_path(msg_file_path, msg->attestationData, &tmp)) { -+ free(msg); -+ return NULL; -+ } -+ return msg; -+} -+ -+static bool pcrs_from_file(const char *pcr_file_path, -+ TPML_PCR_SELECTION *pcrSel, tpm2_pcrs *pcrs) { -+ -+ bool result = false; -+ unsigned long size; -+ -+ if (!files_get_file_size_path(pcr_file_path, &size)) { -+ return false; -+ } -+ -+ if (!size) { -+ LOG_ERR("The pcr file \"%s\" is empty", pcr_file_path); -+ return false; -+ } -+ -+ FILE *pcr_input = fopen(pcr_file_path, "rb"); -+ if (!pcr_input) { -+ LOG_ERR("Could not open PCRs input file \"%s\" error: \"%s\"", -+ pcr_file_path, strerror(errno)); -+ goto out; -+ } -+ -+ // Import TPML_PCR_SELECTION structure to pcr outfile -+ if (fread(pcrSel, sizeof(TPML_PCR_SELECTION), 1, pcr_input) != 1) { -+ LOG_ERR("Failed to read PCR selection from file"); -+ goto out; -+ } -+ -+ // Import PCR digests to pcr outfile -+ if (fread(&pcrs->count, sizeof(UINT32), 1, pcr_input) != 1) { -+ LOG_ERR("Failed to read PCR digests header from file"); -+ goto out; -+ } -+ -+ UINT32 j; -+ for (j = 0; j < pcrs->count; j++) { -+ if (fread(&pcrs->pcr_values[j], sizeof(TPML_DIGEST), 1, pcr_input) != 1) { -+ LOG_ERR("Failed to read PCR digest from file"); -+ goto out; -+ } -+ } -+ -+ result = true; -+ -+out: -+ if (pcr_input) { -+ fclose(pcr_input); -+ } -+ -+ return result; -+} -+ -+static bool init() { -+ -+ /* check flags for mismatches */ -+ if (!(ctx.pubkey_file_path && ctx.flags.sig && ctx.flags.msg && ctx.flags.halg)) { -+ LOG_ERR( -+ "--pubkey (-c), --msg (-m), --halg (-g) and --sig (-s) are required"); -+ return false; -+ } -+ -+ TPM2B_ATTEST *msg = NULL; -+ TPML_PCR_SELECTION pcrSel; -+ tpm2_pcrs pcrs; -+ bool return_value = false; -+ -+ if (ctx.flags.msg) { -+ msg = message_from_file(ctx.msg_file_path); -+ if (!msg) { -+ /* message_from_file() logs specific error no need to here */ -+ return false; -+ } -+ } -+ -+ if (ctx.flags.sig) { -+ bool res = files_load_signature(ctx.sig_file_path, &ctx.signature); -+ if (!res) { -+ goto err; -+ } -+ } -+ -+ /* If no digest is specified, compute it */ -+ if (!ctx.flags.msg) { -+ /* -+ * This is a redundant check since main() checks this case, but we'll add it here to silence any -+ * complainers. -+ */ -+ LOG_ERR("No digest set and no message file to compute from, cannot compute message hash!"); -+ goto err; -+ } -+ -+ if (ctx.flags.pcr) { -+ if (!pcrs_from_file(ctx.pcr_file_path, &pcrSel, &pcrs)) { -+ /* pcrs_from_file() logs specific error no need to here */ -+ goto err; -+ } -+ -+ if (!tpm2_openssl_hash_pcr_banks(ctx.halg, &pcrSel, &pcrs, &ctx.pcrHash)) { -+ LOG_ERR("Failed to hash PCR values related to quote!"); -+ goto err; -+ } -+ if (!pcr_print_pcr_struct(&pcrSel, &pcrs)) { -+ LOG_ERR("Failed to print PCR values related to quote!"); -+ goto err; -+ } -+ tpm2_tool_output("calcDigest: "); -+ tpm2_util_hexdump(ctx.pcrHash.buffer, ctx.pcrHash.size, true); -+ tpm2_tool_output("\n"); -+ } -+ -+ // Figure out the extra data (nonce) from this message -+ if (!tpm2_util_get_digest_from_quote(msg, &ctx.quoteHash, &ctx.quoteExtraData)) { -+ LOG_ERR("Failed to get digest from quote!"); -+ goto err; -+ } -+ -+ // Figure out the digest for this message -+ bool res = tpm2_openssl_hash_compute_data(ctx.halg, msg->attestationData, -+ msg->size, &ctx.msgHash); -+ if (!res) { -+ LOG_ERR("Compute message hash failed!"); -+ goto err; -+ } -+ tpm2_tool_output("msgDigest: "); -+ tpm2_util_hexdump(ctx.msgHash.buffer, ctx.msgHash.size, true); -+ tpm2_tool_output("\n"); -+ -+ return_value = true; -+ -+err: -+ free(msg); -+ return return_value; -+ -+} -+ -+static bool on_option(char key, char *value) { -+ -+ switch (key) { -+ case 'c': -+ ctx.pubkey_file_path = value; -+ break; -+ case 'G': { -+ ctx.halg = tpm2_alg_util_from_optarg(value); -+ if (ctx.halg == TPM2_ALG_ERROR) { -+ LOG_ERR("Unable to convert algorithm, got: \"%s\"", value); -+ return false; -+ } -+ ctx.flags.halg = 1; -+ } -+ break; -+ case 'm': { -+ ctx.msg_file_path = value; -+ ctx.flags.msg = 1; -+ } -+ break; -+ case 'f': { -+ ctx.format = tpm2_alg_util_from_optarg(value); -+ if (ctx.format == TPM2_ALG_ERROR) { -+ LOG_ERR("Unknown signing scheme, got: \"%s\"", value); -+ return false; -+ } -+ -+ ctx.flags.fmt = 1; -+ } break; -+ case 'q': -+ ctx.extraData.size = sizeof(ctx.extraData) - 2; -+ if(tpm2_util_hex_to_byte_structure(value, &ctx.extraData.size, ctx.extraData.buffer) != 0) -+ { -+ LOG_ERR("Could not convert \"%s\" from a hex string to byte array!", value); -+ return false; -+ } -+ ctx.flags.extra = 1; -+ break; -+ case 's': -+ ctx.sig_file_path = value; -+ ctx.flags.sig = 1; -+ break; -+ case 'p': -+ ctx.pcr_file_path = value; -+ ctx.flags.pcr = 1; -+ break; -+ /* no default */ -+ } -+ -+ return true; -+} -+ -+bool tpm2_tool_onstart(tpm2_options **opts) { -+ -+ const struct option topts[] = { -+ { "halg", required_argument, NULL, 'G' }, -+ { "message", required_argument, NULL, 'm' }, -+ { "format", required_argument, NULL, 'f' }, -+ { "sig", required_argument, NULL, 's' }, -+ { "pcrs", required_argument, NULL, 'p' }, -+ { "pubkey", required_argument, NULL, 'c' }, -+ { "qualify-data", required_argument, NULL, 'q' }, -+ }; -+ -+ -+ *opts = tpm2_options_new("G:m:f:s:t:c:p:q:", ARRAY_LEN(topts), topts, -+ on_option, NULL, TPM2_OPTIONS_NO_SAPI); -+ -+ return *opts != NULL; -+} -+ -+int tpm2_tool_onrun(TSS2_SYS_CONTEXT *sapi_context, tpm2_option_flags flags) { -+ -+ UNUSED(sapi_context); -+ UNUSED(flags); -+ -+ /* initialize and process */ -+ bool res = init(); -+ if (!res) { -+ return 1; -+ } -+ -+ res = verify_signature(); -+ if (!res) { -+ LOG_ERR("Verify signature failed!"); -+ return 1; -+ } -+ -+ return 0; -+} -diff --git a/tools/tpm2_pcrlist.c b/tools/tpm2_pcrlist.c -index 581bcecbd63..9a1ee457ce1 100644 ---- a/tools/tpm2_pcrlist.c -+++ b/tools/tpm2_pcrlist.c -@@ -44,17 +44,6 @@ - #include "tpm2_alg_util.h" - #include "tpm2_tool.h" - --typedef struct tpm2_algorithm tpm2_algorithm; --struct tpm2_algorithm { -- int count; -- TPMI_ALG_HASH alg[8]; //XXX Why 8? --}; -- --typedef struct tpm2_pcrs tpm2_pcrs; --struct tpm2_pcrs { -- size_t count; -- TPML_DIGEST pcr_values[24]; //XXX Why 24? --}; - - typedef struct listpcr_context listpcr_context; - struct listpcr_context { -@@ -85,163 +74,6 @@ static listpcr_context ctx = { - }, - }; - --static inline void set_pcr_select_size(TPMS_PCR_SELECTION *pcr_selection, -- UINT8 size) { -- -- pcr_selection->sizeofSelect = size; --} -- --static bool is_pcr_select_bit_set(TPMS_PCR_SELECTION *pcr_selection, UINT32 pcr) { -- -- return (pcr_selection->pcrSelect[((pcr) / 8)] & (1 << ((pcr) % 8))); --} -- --static void update_pcr_selections(TPML_PCR_SELECTION *s1, TPML_PCR_SELECTION *s2) { -- -- UINT32 i1, i2, j; -- for (i2 = 0; i2 < s2->count; i2++) { -- for (i1 = 0; i1 < s1->count; i1++) { -- if (s2->pcrSelections[i2].hash != s1->pcrSelections[i1].hash) -- continue; -- -- for (j = 0; j < s1->pcrSelections[i1].sizeofSelect; j++) -- s1->pcrSelections[i1].pcrSelect[j] &= -- ~s2->pcrSelections[i2].pcrSelect[j]; -- } -- } --} -- --static bool unset_pcr_sections(TPML_PCR_SELECTION *s) { -- -- UINT32 i, j; -- for (i = 0; i < s->count; i++) { -- for (j = 0; j < s->pcrSelections[i].sizeofSelect; j++) { -- if (s->pcrSelections[i].pcrSelect[j]) { -- return false; -- } -- } -- } -- -- return true; --} -- --static bool read_pcr_values(TSS2_SYS_CONTEXT *sapi_context) { -- -- TPML_PCR_SELECTION pcr_selection_tmp; -- TPML_PCR_SELECTION pcr_selection_out; -- UINT32 pcr_update_counter; -- -- //1. prepare pcrSelectionIn with g_pcrSelections -- memcpy(&pcr_selection_tmp, &ctx.pcr_selections, sizeof(pcr_selection_tmp)); -- -- //2. call pcr_read -- ctx.pcrs.count = 0; -- do { -- UINT32 rval = TSS2_RETRY_EXP(Tss2_Sys_PCR_Read(sapi_context, no_argument, &pcr_selection_tmp, -- &pcr_update_counter, &pcr_selection_out, -- &ctx.pcrs.pcr_values[ctx.pcrs.count], 0)); -- -- if (rval != TPM2_RC_SUCCESS) { -- LOG_ERR("read pcr failed. tpm error 0x%0x", rval); -- return -1; -- } -- -- //3. unmask pcrSelectionOut bits from pcrSelectionIn -- update_pcr_selections(&pcr_selection_tmp, &pcr_selection_out); -- -- //4. goto step 2 if pcrSelctionIn still has bits set -- } while (++ctx.pcrs.count < 24 && !unset_pcr_sections(&pcr_selection_tmp)); -- -- if (ctx.pcrs.count >= 24 && !unset_pcr_sections(&pcr_selection_tmp)) { -- LOG_ERR("too much pcrs to get! try to split into multiple calls..."); -- return false; -- } -- -- return true; --} -- --static bool init_pcr_selection(void) { -- -- TPMS_CAPABILITY_DATA *cap_data = &ctx.cap_data; -- TPML_PCR_SELECTION *pcr_sel = &ctx.pcr_selections; -- UINT32 i, j; -- -- TPMI_ALG_HASH alg_id = ctx.selected_algorithm; -- -- pcr_sel->count = 0; -- -- for (i = 0; i < cap_data->data.assignedPCR.count; i++) { -- if (alg_id && (cap_data->data.assignedPCR.pcrSelections[i].hash != alg_id)) -- continue; -- pcr_sel->pcrSelections[pcr_sel->count].hash = cap_data->data.assignedPCR.pcrSelections[i].hash; -- set_pcr_select_size(&pcr_sel->pcrSelections[pcr_sel->count], cap_data->data.assignedPCR.pcrSelections[i].sizeofSelect); -- for (j = 0; j < pcr_sel->pcrSelections[pcr_sel->count].sizeofSelect; j++) -- pcr_sel->pcrSelections[pcr_sel->count].pcrSelect[j] = cap_data->data.assignedPCR.pcrSelections[i].pcrSelect[j]; -- pcr_sel->count++; -- } -- -- if (pcr_sel->count == 0) -- return false; -- -- return true; --} -- --static void shrink_pcr_selection(TPML_PCR_SELECTION *s) { -- -- UINT32 i, j; -- -- //seek for the first empty item -- for (i = 0; i < s->count; i++) -- if (!s->pcrSelections[i].hash) -- break; -- j = i + 1; -- -- for (; i < s->count; i++) { -- if (!s->pcrSelections[i].hash) { -- for (; j < s->count; j++) -- if (s->pcrSelections[j].hash) -- break; -- if (j >= s->count) -- break; -- -- memcpy(&s->pcrSelections[i], &s->pcrSelections[j], sizeof(s->pcrSelections[i])); -- s->pcrSelections[j].hash = 0; -- j++; -- } -- } -- -- s->count = i; --} -- --static bool check_pcr_selection(void) { -- -- TPMS_CAPABILITY_DATA *cap_data = &ctx.cap_data; -- TPML_PCR_SELECTION *pcr_sel = &ctx.pcr_selections; -- UINT32 i, j, k; -- -- for (i = 0; i < pcr_sel->count; i++) { -- for (j = 0; j < cap_data->data.assignedPCR.count; j++) { -- if (pcr_sel->pcrSelections[i].hash == cap_data->data.assignedPCR.pcrSelections[j].hash) { -- for (k = 0; k < pcr_sel->pcrSelections[i].sizeofSelect; k++) -- pcr_sel->pcrSelections[i].pcrSelect[k] &= cap_data->data.assignedPCR.pcrSelections[j].pcrSelect[k]; -- break; -- } -- } -- -- if (j >= cap_data->data.assignedPCR.count) { -- const char *alg_name = tpm2_alg_util_algtostr(pcr_sel->pcrSelections[i].hash); -- LOG_WARN("Ignore unsupported bank/algorithm: %s(0x%04x)", alg_name, pcr_sel->pcrSelections[i].hash); -- pcr_sel->pcrSelections[i].hash = 0; //mark it as to be removed -- } -- } -- -- shrink_pcr_selection(pcr_sel); -- if (pcr_sel->count == 0) -- return false; -- -- return true; --} -- - // show all PCR banks according to g_pcrSelection & g_pcrs-> - static bool show_pcr_values(void) { - -@@ -255,7 +87,7 @@ static bool show_pcr_values(void) { - - UINT32 pcr_id; - for (pcr_id = 0; pcr_id < ctx.pcr_selections.pcrSelections[i].sizeofSelect * 8; pcr_id++) { -- if (!is_pcr_select_bit_set(&ctx.pcr_selections.pcrSelections[i], -+ if (!tpm2_util_is_pcr_select_bit_set(&ctx.pcr_selections.pcrSelections[i], - pcr_id)) { - continue; - } -@@ -296,10 +128,10 @@ static bool show_pcr_values(void) { - - static bool show_selected_pcr_values(TSS2_SYS_CONTEXT *sapi_context, bool check) { - -- if (check && !check_pcr_selection()) -+ if (check && !pcr_check_pcr_selection(&ctx.cap_data, &ctx.pcr_selections)) - return false; - -- if (!read_pcr_values(sapi_context)) -+ if (!pcr_read_pcr_values(sapi_context, &ctx.pcr_selections, &ctx.pcrs)) - return false; - - if (!show_pcr_values()) -@@ -310,7 +142,7 @@ static bool show_selected_pcr_values(TSS2_SYS_CONTEXT *sapi_context, bool check) - - static bool show_all_pcr_values(TSS2_SYS_CONTEXT *sapi_context) { - -- if (!init_pcr_selection()) -+ if (!pcr_init_pcr_selection(&ctx.cap_data, &ctx.pcr_selections, ctx.selected_algorithm)) - return false; - - return show_selected_pcr_values(sapi_context, false); -@@ -318,37 +150,12 @@ static bool show_all_pcr_values(TSS2_SYS_CONTEXT *sapi_context) { - - static bool show_alg_pcr_values(TSS2_SYS_CONTEXT *sapi_context) { - -- if (!init_pcr_selection()) -+ if (!pcr_init_pcr_selection(&ctx.cap_data, &ctx.pcr_selections, ctx.selected_algorithm)) - return false; - - return show_selected_pcr_values(sapi_context, false); - } - --static bool get_banks(TSS2_SYS_CONTEXT *sapi_context) { -- -- TPMI_YES_NO more_data; -- TPMS_CAPABILITY_DATA *capability_data = &ctx.cap_data; -- UINT32 rval; -- -- rval = TSS2_RETRY_EXP(Tss2_Sys_GetCapability(sapi_context, no_argument, TPM2_CAP_PCRS, no_argument, required_argument, -- &more_data, capability_data, 0)); -- if (rval != TPM2_RC_SUCCESS) { -- LOG_ERR( -- "GetCapability: Get PCR allocation status Error. TPM Error:0x%x......", -- rval); -- return false; -- } -- -- unsigned i; -- for (i = 0; i < capability_data->data.assignedPCR.count; i++) { -- ctx.algs.alg[i] = -- capability_data->data.assignedPCR.pcrSelections[i].hash; -- } -- ctx.algs.count = capability_data->data.assignedPCR.count; -- -- return true; --} -- - static void show_banks(tpm2_algorithm *g_banks) { - - tpm2_tool_output("Supported Bank/Algorithm:"); -@@ -432,7 +239,7 @@ int tpm2_tool_onrun(TSS2_SYS_CONTEXT *sapi_context, tpm2_option_flags flags) { - } - } - -- success = get_banks(sapi_context); -+ success = pcr_get_banks(sapi_context, &ctx.cap_data, &ctx.algs); - if (!success) { - goto error; - } -diff --git a/tools/tpm2_quote.c b/tools/tpm2_quote.c -index 05b6d641656..2efba240340 100644 ---- a/tools/tpm2_quote.c -+++ b/tools/tpm2_quote.c -@@ -42,6 +42,7 @@ - #include "conversion.h" - #include "tpm2_alg_util.h" - #include "tpm2_password_util.h" -+#include "tpm2_openssl.h" - #include "tpm2_tool.h" - #include "tpm2_util.h" - -@@ -54,15 +55,27 @@ static TPMS_AUTH_COMMAND sessionData = TPMS_AUTH_COMMAND_INIT(TPM2_RS_PW); - static char *outFilePath; - static char *signature_path; - static char *message_path; -+static char *pcr_path; -+static FILE *pcr_output; -+static TPMS_CAPABILITY_DATA cap_data; - static signature_format sig_format; - static TPMI_ALG_HASH sig_hash_algorithm; -+static tpm2_algorithm algs = { -+ .count = 3, -+ .alg = { -+ TPM2_ALG_SHA1, -+ TPM2_ALG_SHA256, -+ TPM2_ALG_SHA384 -+ } -+}; - static TPM2B_DATA qualifyingData = TPM2B_EMPTY_INIT; - static TPML_PCR_SELECTION pcrSelections; - static bool is_auth_session; - static TPMI_SH_AUTH_SESSION auth_session_handle; --static int k_flag, c_flag, l_flag, g_flag, L_flag, o_flag, G_flag, P_flag; -+static int k_flag, c_flag, l_flag, g_flag, L_flag, o_flag, G_flag, P_flag, p_flag; - static char *contextFilePath; - static TPM2_HANDLE akHandle; -+static tpm2_pcrs pcrs; - - static void PrintBuffer( UINT8 *buffer, UINT32 size ) - { -@@ -74,6 +87,40 @@ static void PrintBuffer( UINT8 *buffer, UINT32 size ) - tpm2_tool_output("\n"); - } - -+ -+// write all PCR banks according to g_pcrSelection & g_pcrs-> -+static bool write_pcr_values() { -+ -+ // PCR output to file wasn't requested -+ if (pcr_output == NULL) { -+ return true; -+ } -+ -+ // Export TPML_PCR_SELECTION structure to pcr outfile -+ if (fwrite(&pcrSelections, -+ sizeof(TPML_PCR_SELECTION), 1, -+ pcr_output) != 1) { -+ LOG_ERR("write to output file failed: %s", strerror(errno)); -+ return false; -+ } -+ -+ // Export PCR digests to pcr outfile -+ if (fwrite(&pcrs.count, sizeof(UINT32), 1, pcr_output) != 1) { -+ LOG_ERR("write to output file failed: %s", strerror(errno)); -+ return false; -+ } -+ -+ UINT32 j; -+ for (j = 0; j < pcrs.count; j++) { -+ if (fwrite(&pcrs.pcr_values[j], sizeof(TPML_DIGEST), 1, pcr_output) != 1) { -+ LOG_ERR("write to output file failed: %s", strerror(errno)); -+ return false; -+ } -+ } -+ -+ return true; -+} -+ - static bool write_output_files(TPM2B_ATTEST *quoted, TPMT_SIGNATURE *signature) { - - bool res = true; -@@ -87,6 +134,8 @@ static bool write_output_files(TPM2B_ATTEST *quoted, TPMT_SIGNATURE *signature) - quoted->size); - } - -+ res &= write_pcr_values(); -+ - return res; - } - -@@ -125,7 +174,53 @@ static int quote(TSS2_SYS_CONTEXT *sapi_context, TPM2_HANDLE akHandle, TPML_PCR_ - PrintBuffer( (UINT8 *)&signature, sizeof(signature) ); - //PrintTPMT_SIGNATURE(&signature); - -+ if (pcr_output) { -+ // Filter out invalid/unavailable PCR selections -+ if (!pcr_check_pcr_selection(&cap_data, &pcrSelections)) { -+ LOG_ERR("Failed to filter unavailable PCR values for quote!"); -+ return false; -+ } -+ -+ // Gather PCR values from the TPM (the quote doesn't have them!) -+ if (!pcr_read_pcr_values(sapi_context, &pcrSelections, &pcrs)) { -+ LOG_ERR("Failed to retrieve PCR values related to quote!"); -+ return false; -+ } -+ -+ // Grab the digest from the quote -+ TPM2B_DIGEST quoteDigest = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer); -+ TPM2B_DATA extraData = TPM2B_TYPE_INIT(TPM2B_DATA, buffer); -+ if (!tpm2_util_get_digest_from_quote("ed, "eDigest, &extraData)) { -+ LOG_ERR("Failed to get digest from quote!"); -+ return false; -+ } -+ -+ // Print out PCR values as output -+ if (!pcr_print_pcr_struct(&pcrSelections, &pcrs)) { -+ LOG_ERR("Failed to print PCR values related to quote!"); -+ return false; -+ } -+ -+ // Calculate the digest from our selected PCR values (to ensure correctness) -+ TPM2B_DIGEST pcr_digest = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer); -+ if (!tpm2_openssl_hash_pcr_banks(sig_hash_algorithm, &pcrSelections, &pcrs, &pcr_digest)) { -+ LOG_ERR("Failed to hash PCR values related to quote!"); -+ return false; -+ } -+ tpm2_tool_output("calcDigest: "); -+ tpm2_util_hexdump(pcr_digest.buffer, pcr_digest.size, true); -+ tpm2_tool_output("\n"); -+ -+ // Make sure digest from quote matches calculated PCR digest -+ if (!tpm2_util_verify_digests("eDigest, &pcr_digest)) { -+ LOG_ERR("Error validating calculated PCR composite with quote"); -+ return false; -+ } -+ } -+ -+ // Write everything out - bool res = write_output_files("ed, &signature); -+ - return res == true ? 0 : 1; - } - -@@ -206,6 +301,10 @@ static bool on_option(char key, char *value) { - case 'm': - message_path = optarg; - break; -+ case 'p': -+ pcr_path = optarg; -+ p_flag = 1; -+ break; - case 'f': - sig_format = tpm2_parse_signature_format(optarg); - -@@ -239,11 +338,12 @@ bool tpm2_tool_onstart(tpm2_options **opts) { - { "input-session-handle", required_argument, NULL, 'S' }, - { "signature", required_argument, NULL, 's' }, - { "message", required_argument, NULL, 'm' }, -+ { "pcrs", required_argument, NULL, 'p' }, - { "format", required_argument, NULL, 'f' }, - { "sig-hash-algorithm", required_argument, NULL, 'G' } - }; - -- *opts = tpm2_options_new("k:c:P:l:g:L:S:q:s:m:f:G:", ARRAY_LEN(topts), topts, -+ *opts = tpm2_options_new("k:c:P:l:g:L:S:q:s:m:p:f:G:", ARRAY_LEN(topts), topts, - on_option, NULL, TPM2_OPTIONS_SHOW_USAGE); - - return *opts != NULL; -@@ -270,5 +370,25 @@ int tpm2_tool_onrun(TSS2_SYS_CONTEXT *sapi_context, tpm2_option_flags flags) { - sessionData.hmac.size = 0; - } - -+ if (p_flag) { -+ if (!G_flag) { -+ LOG_ERR("Must specify -G if -p is requested."); -+ return -1; -+ } -+ pcr_output = fopen(pcr_path, "wb+"); -+ if (!pcr_output) { -+ LOG_ERR("Could not open PCR output file \"%s\" error: \"%s\"", -+ pcr_path, strerror(errno)); -+ return 1; -+ } -+ } -+ -+ if (!pcr_get_banks(sapi_context, &cap_data, &algs)) { -+ if (pcr_output) { -+ fclose(pcr_output); -+ } -+ return 1; -+ } -+ - return quote(sapi_context, akHandle, &pcrSelections); - } --- -2.21.0 - diff --git a/Add-ability-to-run-tpm2_makecredential-without-a-TPM.patch b/Add-ability-to-run-tpm2_makecredential-without-a-TPM.patch deleted file mode 100644 index 9929d13..0000000 --- a/Add-ability-to-run-tpm2_makecredential-without-a-TPM.patch +++ /dev/null @@ -1,1305 +0,0 @@ -From d74b094191f2e09b29cfad4f03322e0cd64497ab Mon Sep 17 00:00:00 2001 -From: jetwhiz -Date: Tue, 5 Feb 2019 17:24:44 -0500 -Subject: [PATCH] Add ability to run tpm2_makecredential without a TPM - -Used some functions from tpm2_import for off-TPM functionality - - Move needed, overlap code into tpm2_identity_util -Add new global -X/--openssl-backend option for any tools that can operate w/o TPM - -Signed-off-by: jetwhiz ---- - Makefile.am | 6 +- - lib/tpm2_identity_util.c | 480 ++++++++++++++++++++++++ - lib/tpm2_identity_util.h | 141 +++++++ - lib/tpm2_openssl.c | 162 ++++++++ - lib/tpm2_openssl.h | 108 ++++++ - lib/tpm2_options.c | 36 +- - lib/tpm2_options.h | 1 + - man/common/tcti.md | 4 + - man/tpm2_activatecredential.1.md | 2 +- - man/tpm2_certify.1.md | 2 +- - man/tpm2_create.1.md | 2 +- - man/tpm2_encryptdecrypt.1.md | 2 +- - man/tpm2_getpubak.1.md | 2 +- - man/tpm2_makecredential.1.md | 3 +- - test/system/test_tpm2_makecredential.sh | 2 + - tools/tpm2_makecredential.c | 103 ++++- - 16 files changed, 1033 insertions(+), 23 deletions(-) - create mode 100644 lib/tpm2_identity_util.c - create mode 100644 lib/tpm2_identity_util.h - create mode 100644 lib/tpm2_openssl.c - create mode 100644 lib/tpm2_openssl.h - -diff --git a/Makefile.am b/Makefile.am -index ffe22f383e3..2195537ce01 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -119,7 +119,11 @@ lib_libcommon_a_SOURCES = \ - lib/tpm2_errata.c \ - lib/tpm2_errata.h \ - lib/tpm2_header.h \ -+ lib/tpm2_identity_util.c \ -+ lib/tpm2_identity_util.h \ - lib/tpm2_nv_util.h \ -+ lib/tpm2_openssl.c \ -+ lib/tpm2_openssl.h \ - lib/tpm2_password_util.c \ - lib/tpm2_password_util.h \ - lib/tpm2_policy.c \ -@@ -347,4 +351,4 @@ man/man1/%.1 : man/%.1.md $(MARKDOWN_COMMON_DEPS) - -e '/\[object attribute specifiers\]/d' \ - < $< | pandoc -s -t man > $@ - --CLEANFILES = $(man1_MANS) -+CLEANFILES = $(man1_MANS) -\ No newline at end of file -diff --git a/lib/tpm2_identity_util.c b/lib/tpm2_identity_util.c -new file mode 100644 -index 00000000000..70bf03647eb ---- /dev/null -+++ b/lib/tpm2_identity_util.c -@@ -0,0 +1,480 @@ -+//**********************************************************************; -+// Copyright (c) 2017, Intel Corporation -+// Copyright (c) 2019 Massachusetts Institute of Technology -+// 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. -+// -+// 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 HOLDER 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 "files.h" -+#include "log.h" -+#include "tpm2_alg_util.h" -+#include "tpm_kdfa.h" -+#include "tpm2_openssl.h" -+#include "tpm2_identity_util.h" -+#include "tpm2_util.h" -+ -+ -+// Identity-related functionality that the TPM normally does, but using OpenSSL -+ -+#if defined(LIBRESSL_VERSION_NUMBER) -+static int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, -+ const unsigned char *from, int flen, const unsigned char *param, int plen, -+ const EVP_MD *md, const EVP_MD *mgf1md) { -+ -+ int ret = 0; -+ int i, emlen = tlen - 1; -+ unsigned char *db, *seed; -+ unsigned char *dbmask, seedmask[EVP_MAX_MD_SIZE]; -+ int mdlen; -+ -+ if (md == NULL) -+ md = EVP_sha1(); -+ if (mgf1md == NULL) -+ mgf1md = md; -+ -+ mdlen = EVP_MD_size(md); -+ -+ if (flen > emlen - 2 * mdlen - 1) { -+ RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, -+ RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); -+ return 0; -+ } -+ -+ if (emlen < 2 * mdlen + 1) { -+ RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, -+ RSA_R_KEY_SIZE_TOO_SMALL); -+ return 0; -+ } -+ -+ to[0] = 0; -+ seed = to + 1; -+ db = to + mdlen + 1; -+ -+ if (!EVP_Digest((void *)param, plen, db, NULL, md, NULL)) -+ return 0; -+ memset(db + mdlen, 0, emlen - flen - 2 * mdlen - 1); -+ db[emlen - flen - mdlen - 1] = 0x01; -+ memcpy(db + emlen - flen - mdlen, from, (unsigned int)flen); -+ if (RAND_bytes(seed, mdlen) <= 0) -+ return 0; -+ -+ dbmask = OPENSSL_malloc(emlen - mdlen); -+ if (dbmask == NULL) { -+ RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, ERR_R_MALLOC_FAILURE); -+ return 0; -+ } -+ -+ if (PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md) < 0) -+ goto err; -+ for (i = 0; i < emlen - mdlen; i++) -+ db[i] ^= dbmask[i]; -+ -+ if (PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md) < 0) -+ goto err; -+ for (i = 0; i < mdlen; i++) -+ seed[i] ^= seedmask[i]; -+ -+ ret = 1; -+ -+ err: -+ OPENSSL_free(dbmask); -+ -+ return ret; -+} -+#endif -+ -+static TPM2_KEY_BITS get_pub_asym_key_bits(TPM2B_PUBLIC *public) { -+ -+ TPMU_PUBLIC_PARMS *p = &public->publicArea.parameters; -+ switch(public->publicArea.type) { -+ case TPM2_ALG_ECC: -+ /* fall-thru */ -+ case TPM2_ALG_RSA: -+ return p->asymDetail.symmetric.keyBits.sym; -+ /* no default */ -+ } -+ -+ return 0; -+} -+ -+static bool encrypt_seed_with_tpm2_rsa_public_key(TPM2B_DIGEST *protection_seed, -+ TPM2B_PUBLIC *parent_pub, unsigned char *label, int labelLen, -+ TPM2B_ENCRYPTED_SECRET *encrypted_protection_seed) { -+ bool rval = false; -+ RSA *rsa = NULL; -+ -+ // Public modulus (RSA-only!) -+ TPMI_RSA_KEY_BITS mod_size_bits = parent_pub->publicArea.parameters.rsaDetail.keyBits; -+ UINT16 mod_size = mod_size_bits / 8; -+ TPM2B *pub_key_val = (TPM2B *)&parent_pub->publicArea.unique.rsa; -+ unsigned char *pub_modulus = malloc(mod_size); -+ if (pub_modulus == NULL) { -+ LOG_ERR("Failed to allocate memory to store public key's modulus."); -+ return false; -+ } -+ memcpy(pub_modulus, pub_key_val->buffer, mod_size); -+ -+ TPMI_ALG_HASH parent_name_alg = parent_pub->publicArea.nameAlg; -+ -+ /* -+ * This is the biggest buffer value, so it should always be sufficient. -+ */ -+ unsigned char encoded[TPM2_MAX_DIGEST_BUFFER]; -+ int return_code = RSA_padding_add_PKCS1_OAEP_mgf1(encoded, -+ mod_size, protection_seed->buffer, protection_seed->size, label, labelLen, -+ tpm2_openssl_halg_from_tpmhalg(parent_name_alg), NULL); -+ if (return_code != 1) { -+ LOG_ERR("Failed RSA_padding_add_PKCS1_OAEP_mgf1\n"); -+ goto error; -+ } -+ BIGNUM* bne = BN_new(); -+ if (!bne) { -+ LOG_ERR("BN_new for bne failed\n"); -+ goto error; -+ } -+ return_code = BN_set_word(bne, RSA_F4); -+ if (return_code != 1) { -+ LOG_ERR("BN_set_word failed\n"); -+ BN_free(bne); -+ goto error; -+ } -+ rsa = RSA_new(); -+ if (!rsa) { -+ LOG_ERR("RSA_new failed\n"); -+ BN_free(bne); -+ goto error; -+ } -+ return_code = RSA_generate_key_ex(rsa, mod_size_bits, bne, NULL); -+ BN_free(bne); -+ if (return_code != 1) { -+ LOG_ERR("RSA_generate_key_ex failed\n"); -+ goto error; -+ } -+ BIGNUM *n = BN_bin2bn(pub_modulus, mod_size, NULL); -+ if (n == NULL) { -+ LOG_ERR("BN_bin2bn failed\n"); -+ goto error; -+ } -+ if (!RSA_set0_key(rsa, n, NULL, NULL)) { -+ LOG_ERR("RSA_set0_key failed\n"); -+ BN_free(n); -+ goto error; -+ } -+ // Encrypting -+ encrypted_protection_seed->size = mod_size; -+ return_code = RSA_public_encrypt(mod_size, encoded, -+ encrypted_protection_seed->secret, rsa, RSA_NO_PADDING); -+ if (return_code < 0) { -+ LOG_ERR("Failed RSA_public_encrypt\n"); -+ goto error; -+ } -+ -+ rval = true; -+ -+error: -+ free(pub_modulus); -+ RSA_free(rsa); -+ return rval; -+} -+ -+bool tpm2_identity_util_calc_outer_integrity_hmac_key_and_dupsensitive_enc_key( -+ TPM2B_PUBLIC *parent_pub, -+ TPM2B_NAME *pubname, -+ TPM2B_DIGEST *protection_seed, -+ TPM2B_MAX_BUFFER *protection_hmac_key, -+ TPM2B_MAX_BUFFER *protection_enc_key) { -+ -+ TPM2B null_2b = { .size = 0 }; -+ -+ TPMI_ALG_HASH parent_alg = parent_pub->publicArea.nameAlg; -+ UINT16 parent_hash_size = tpm2_alg_util_get_hash_size(parent_alg); -+ -+ TSS2_RC rval = tpm_kdfa(parent_alg, (TPM2B *)protection_seed, "INTEGRITY", -+ &null_2b, &null_2b, parent_hash_size * 8, protection_hmac_key); -+ if (rval != TPM2_RC_SUCCESS) { -+ return false; -+ } -+ -+ TPM2_KEY_BITS pub_key_bits = get_pub_asym_key_bits(parent_pub); -+ -+ rval = tpm_kdfa(parent_alg, (TPM2B *)protection_seed, "STORAGE", -+ (TPM2B *)pubname, &null_2b, pub_key_bits, -+ protection_enc_key); -+ if (rval != TPM2_RC_SUCCESS) { -+ return false; -+ } -+ -+ return true; -+} -+ -+ -+bool tpm2_identity_util_encrypt_seed_with_public_key(TPM2B_DIGEST *protection_seed, -+ TPM2B_PUBLIC *parent_pub, unsigned char *label, int labelLen, -+ TPM2B_ENCRYPTED_SECRET *encrypted_protection_seed) { -+ bool result = false; -+ TPMI_ALG_PUBLIC alg = parent_pub->publicArea.type; -+ -+ switch (alg) { -+ case TPM2_ALG_RSA: -+ result = encrypt_seed_with_tpm2_rsa_public_key(protection_seed, -+ parent_pub, label, labelLen, encrypted_protection_seed); -+ break; -+ case TPM2_ALG_ECC: -+ LOG_ERR("Algorithm '%s' not supported yet", tpm2_alg_util_algtostr(alg)); -+ result = false; -+ break; -+ default: -+ LOG_ERR("Cannot handle algorithm, got: %s", tpm2_alg_util_algtostr(alg)); -+ return false; -+ } -+ -+ return result; -+} -+ -+static const EVP_CIPHER *tpm_alg_to_ossl(TPMT_SYM_DEF_OBJECT *sym) { -+ -+ switch(sym->algorithm) { -+ case TPM2_ALG_AES: { -+ switch (sym->keyBits.aes) { -+ case 128: -+ return EVP_aes_128_cfb(); -+ case 256: -+ return EVP_aes_256_cfb(); -+ /* no default */ -+ } -+ } -+ /* no default */ -+ } -+ -+ LOG_ERR("Unsupported parent key symmetric parameters"); -+ -+ return NULL; -+} -+ -+static bool aes_encrypt_buffers(TPMT_SYM_DEF_OBJECT *sym, uint8_t *encryption_key, -+ uint8_t *buf1, size_t buf1_len, -+ uint8_t *buf2, size_t buf2_len, -+ TPM2B_MAX_BUFFER *cipher_text) { -+ -+ bool result = false; -+ -+ unsigned offset = 0; -+ size_t total_len = buf1_len + buf2_len; -+ -+ if (total_len > sizeof(cipher_text->buffer)) { -+ LOG_ERR("Plaintext too big, got %zu, expected less then %zu", -+ total_len, sizeof(cipher_text->buffer)); -+ return false; -+ } -+ -+ const EVP_CIPHER *cipher = tpm_alg_to_ossl(sym); -+ if (!cipher) { -+ return false; -+ } -+ -+ const unsigned char iv[512] = { 0 }; -+ -+ if (((unsigned long)EVP_CIPHER_iv_length(cipher)) > sizeof(iv)) { -+ LOG_ERR("IV size is bigger then IV buffer size"); -+ return false; -+ } -+ -+ EVP_CIPHER_CTX *ctx = tpm2_openssl_cipher_new(); -+ -+ int rc = EVP_EncryptInit_ex(ctx, cipher, NULL, encryption_key, iv); -+ if (!rc) { -+ return false; -+ } -+ -+ EVP_CIPHER_CTX_set_padding(ctx, 0); -+ -+ uint8_t *bufs[2] = { -+ buf1, -+ buf2 -+ }; -+ -+ size_t lens[ARRAY_LEN(bufs)] = { -+ buf1_len, -+ buf2_len -+ }; -+ -+ unsigned i; -+ for (i=0; i < ARRAY_LEN(bufs); i++) { -+ -+ uint8_t *b = bufs[i]; -+ size_t l = lens[i]; -+ -+ if (!b) { -+ continue; -+ } -+ -+ int output_len = total_len - offset; -+ -+ rc = EVP_EncryptUpdate(ctx, &cipher_text->buffer[offset], &output_len, b, l); -+ if (!rc) { -+ LOG_ERR("Encrypt failed"); -+ goto out; -+ } -+ -+ offset += l; -+ } -+ -+ int tmp_len = 0; -+ rc = EVP_EncryptFinal_ex(ctx, NULL, &tmp_len); -+ if (!rc) { -+ LOG_ERR("Encrypt failed"); -+ goto out; -+ } -+ -+ cipher_text->size = total_len; -+ -+ result = true; -+ -+out: -+ tpm2_openssl_cipher_free(ctx); -+ -+ return result; -+} -+ -+static void hmac_outer_integrity( -+ TPMI_ALG_HASH parent_name_alg, -+ uint8_t *buffer1, uint16_t buffer1_size, -+ uint8_t *buffer2, uint16_t buffer2_size, uint8_t *hmac_key, -+ TPM2B_DIGEST *outer_integrity_hmac) { -+ -+ uint8_t to_hmac_buffer[TPM2_MAX_DIGEST_BUFFER]; -+ memcpy(to_hmac_buffer, buffer1, buffer1_size); -+ memcpy(to_hmac_buffer + buffer1_size, buffer2, buffer2_size); -+ uint32_t size = 0; -+ -+ UINT16 hash_size = tpm2_alg_util_get_hash_size(parent_name_alg); -+ -+ HMAC(tpm2_openssl_halg_from_tpmhalg(parent_name_alg), hmac_key, hash_size, to_hmac_buffer, -+ buffer1_size + buffer2_size, outer_integrity_hmac->buffer, &size); -+ outer_integrity_hmac->size = size; -+} -+ -+bool tpm2_identity_util_calculate_inner_integrity( -+ TPMI_ALG_HASH name_alg, -+ TPM2B_SENSITIVE *sensitive, -+ TPM2B_NAME *pubname, -+ TPM2B_DATA *enc_sensitive_key, -+ TPMT_SYM_DEF_OBJECT *sym_alg, -+ TPM2B_MAX_BUFFER *encrypted_inner_integrity) { -+ -+ //Marshal sensitive area -+ uint8_t buffer_marshalled_sensitiveArea[TPM2_MAX_DIGEST_BUFFER] = { 0 }; -+ size_t marshalled_sensitive_size = 0; -+ Tss2_MU_TPMT_SENSITIVE_Marshal(&sensitive->sensitiveArea, -+ buffer_marshalled_sensitiveArea + sizeof(uint16_t), TPM2_MAX_DIGEST_BUFFER, -+ &marshalled_sensitive_size); -+ size_t marshalled_sensitive_size_info = 0; -+ Tss2_MU_UINT16_Marshal(marshalled_sensitive_size, buffer_marshalled_sensitiveArea, -+ sizeof(uint16_t), &marshalled_sensitive_size_info); -+ -+ //concatenate NAME -+ memcpy( -+ buffer_marshalled_sensitiveArea + marshalled_sensitive_size -+ + marshalled_sensitive_size_info, -+ pubname->name, -+ pubname->size); -+ -+ //Digest marshalled-sensitive || name -+ uint8_t *marshalled_sensitive_and_name_digest = -+ buffer_marshalled_sensitiveArea + marshalled_sensitive_size -+ + marshalled_sensitive_size_info -+ + pubname->size; -+ size_t digest_size_info = 0; -+ UINT16 hash_size = tpm2_alg_util_get_hash_size(name_alg); -+ Tss2_MU_UINT16_Marshal(hash_size, marshalled_sensitive_and_name_digest, -+ sizeof(uint16_t), &digest_size_info); -+ -+ digester d = tpm2_openssl_halg_to_digester(name_alg); -+ d(buffer_marshalled_sensitiveArea, -+ marshalled_sensitive_size_info + marshalled_sensitive_size -+ + pubname->size, -+ marshalled_sensitive_and_name_digest + digest_size_info); -+ -+ //Inner integrity -+ encrypted_inner_integrity->size = marshalled_sensitive_size_info -+ + marshalled_sensitive_size + pubname->size; -+ -+ return aes_encrypt_buffers( -+ sym_alg, -+ enc_sensitive_key->buffer, -+ marshalled_sensitive_and_name_digest, -+ hash_size + digest_size_info, -+ buffer_marshalled_sensitiveArea, -+ marshalled_sensitive_size_info + marshalled_sensitive_size, -+ encrypted_inner_integrity); -+} -+ -+void tpm2_identity_util_calculate_outer_integrity( -+ TPMI_ALG_HASH parent_name_alg, -+ TPM2B_NAME *pubname, -+ TPM2B_MAX_BUFFER *marshalled_sensitive, -+ TPM2B_MAX_BUFFER *protection_hmac_key, -+ TPM2B_MAX_BUFFER *protection_enc_key, -+ TPMT_SYM_DEF_OBJECT *sym_alg, -+ TPM2B_MAX_BUFFER *encrypted_duplicate_sensitive, -+ TPM2B_DIGEST *outer_hmac) { -+ -+ //Calculate dupSensitive -+ encrypted_duplicate_sensitive->size = -+ marshalled_sensitive->size; -+ -+ aes_encrypt_buffers( -+ sym_alg, -+ protection_enc_key->buffer, -+ marshalled_sensitive->buffer, -+ marshalled_sensitive->size, -+ NULL, 0, -+ encrypted_duplicate_sensitive); -+ //Calculate outerHMAC -+ hmac_outer_integrity( -+ parent_name_alg, -+ encrypted_duplicate_sensitive->buffer, -+ encrypted_duplicate_sensitive->size, -+ pubname->name, -+ pubname->size, -+ protection_hmac_key->buffer, -+ outer_hmac); -+} -diff --git a/lib/tpm2_identity_util.h b/lib/tpm2_identity_util.h -new file mode 100644 -index 00000000000..49f231a3347 ---- /dev/null -+++ b/lib/tpm2_identity_util.h -@@ -0,0 +1,141 @@ -+//**********************************************************************; -+// Copyright (c) 2017, Intel Corporation -+// Copyright (c) 2019 Massachusetts Institute of Technology -+// 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. -+// -+// 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 HOLDER 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 LIB_TPM2_IDENTITY_UTIL_H_ -+#define LIB_TPM2_IDENTITY_UTIL_H_ -+ -+#include -+ -+#include -+#include -+#include -+ -+ -+/** -+ * Generates HMAC integrity and symmetric encryption keys for TPM2 identies. -+ * -+ * @param parent_pub -+ * The public key used for seed generation and protection. -+ * @param pubname -+ * The Name object associated with the parent_pub credential. -+ * @param protection_seed -+ * The symmetric seed value used to generate protection keys. -+ * @param protection_hmac_key -+ * The HMAC integrity key to populate. -+ * @param protection_enc_key -+ * The symmetric encryption key to populate. -+ * @return -+ * True on success, false on failure. -+ */ -+bool tpm2_identity_util_calc_outer_integrity_hmac_key_and_dupsensitive_enc_key( -+ TPM2B_PUBLIC *parent_pub, -+ TPM2B_NAME *pubname, -+ TPM2B_DIGEST *protection_seed, -+ TPM2B_MAX_BUFFER *protection_hmac_key, -+ TPM2B_MAX_BUFFER *protection_enc_key); -+ -+/** -+ * Encrypts seed with parent public key for TPM2 credential protection process. -+ * -+ * @param protection_seed -+ * The identity structure protection seed that is to be encrypted. -+ * @param parent_pub -+ * The public key used for encryption. -+ * @param label -+ * Indicates label for the seed, such as "IDENTITY" or "DUPLICATE". -+ * @param labelLen -+ * Length of label. -+ * @param encrypted_protection_seed -+ * The encrypted protection seed to populate. -+ * @return -+ * True on success, false on failure. -+ */ -+bool tpm2_identity_util_encrypt_seed_with_public_key( -+ TPM2B_DIGEST *protection_seed, -+ TPM2B_PUBLIC *parent_pub, -+ unsigned char *label, -+ int labelLen, -+ TPM2B_ENCRYPTED_SECRET *encrypted_protection_seed); -+ -+/** -+ * Marshalls Credential Value and encrypts it with the symmetric encryption key. -+ * -+ * @param name_alg -+ * Hash algorithm used to compute Name of the public key. -+ * @param sensitive -+ * The Credential Value to be marshalled and encrypted with symmetric key. -+ * @param pubname -+ * The Name object corresponding to the public key. -+ * @param enc_sensitive_key -+ * The symmetric encryption key. -+ * @param sym_alg -+ * The algorithm used for the symmetric encryption key. -+ * @param encrypted_inner_integrity -+ * The encrypted, marshalled Credential Value to populate. -+ * @return -+ * True on success, false on failure. -+ */ -+bool tpm2_identity_util_calculate_inner_integrity( -+ TPMI_ALG_HASH name_alg, -+ TPM2B_SENSITIVE *sensitive, -+ TPM2B_NAME *pubname, -+ TPM2B_DATA *enc_sensitive_key, -+ TPMT_SYM_DEF_OBJECT *sym_alg, -+ TPM2B_MAX_BUFFER *encrypted_inner_integrity); -+ -+/** -+ * Encrypts Credential Value with enc key and calculates HMAC with hmac key. -+ * -+ * @param parent_name_alg -+ * Hash algorithm used to compute Name of the public key. -+ * @param pubname -+ * The Name object corresponding to the public key. -+ * @param marshalled_sensitive -+ * Marshalled Credential Value to be encrypted with symmetric encryption key. -+ * @param protection_hmac_key -+ * The HMAC integrity key. -+ * @param protection_enc_key -+ * The symmetric encryption key. -+ * @param sym_alg -+ * The algorithm used for the symmetric encryption key. -+ * @param encrypted_duplicate_sensitive -+ * The encrypted Credential Value to populate. -+ * @param outer_hmac -+ * The outer HMAC structure to populate. -+ */ -+void tpm2_identity_util_calculate_outer_integrity( -+ TPMI_ALG_HASH parent_name_alg, -+ TPM2B_NAME *pubname, -+ TPM2B_MAX_BUFFER *marshalled_sensitive, -+ TPM2B_MAX_BUFFER *protection_hmac_key, -+ TPM2B_MAX_BUFFER *protection_enc_key, -+ TPMT_SYM_DEF_OBJECT *sym_alg, -+ TPM2B_MAX_BUFFER *encrypted_duplicate_sensitive, -+ TPM2B_DIGEST *outer_hmac); -+ -+#endif /* LIB_TPM2_IDENTITY_UTIL_H_ */ -diff --git a/lib/tpm2_openssl.c b/lib/tpm2_openssl.c -new file mode 100644 -index 00000000000..0bfc95bd1ef ---- /dev/null -+++ b/lib/tpm2_openssl.c -@@ -0,0 +1,162 @@ -+//**********************************************************************; -+// Copyright (c) 2017, 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: -+// -+// 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. -+// -+// 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 HOLDER 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 "files.h" -+#include "log.h" -+#include "tpm2_alg_util.h" -+#include "tpm2_openssl.h" -+#include "tpm2_util.h" -+ -+ -+const EVP_MD *tpm2_openssl_halg_from_tpmhalg(TPMI_ALG_HASH algorithm) { -+ -+ switch (algorithm) { -+ case TPM2_ALG_SHA1: -+ return EVP_sha1(); -+ case TPM2_ALG_SHA256: -+ return EVP_sha256(); -+ case TPM2_ALG_SHA384: -+ return EVP_sha384(); -+ case TPM2_ALG_SHA512: -+ return EVP_sha512(); -+ default: -+ return NULL; -+ } -+ /* no return, not possible */ -+} -+ -+#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11) -+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { -+ -+ if ((r->n == NULL && n == NULL) || (r->e == NULL && e == NULL)) { -+ return 0; -+ } -+ -+ if (n != NULL) { -+ BN_free(r->n); -+ r->n = n; -+ } -+ -+ if (e != NULL) { -+ BN_free(r->e); -+ r->e = e; -+ } -+ -+ if (d != NULL) { -+ BN_free(r->d); -+ r->d = d; -+ } -+ -+ return 1; -+} -+#endif -+ -+static inline const char *get_openssl_err(void) { -+ return ERR_error_string(ERR_get_error(), NULL); -+} -+ -+ -+EVP_CIPHER_CTX *tpm2_openssl_cipher_new(void) { -+ EVP_CIPHER_CTX *ctx; -+#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11) -+ ctx = malloc(sizeof(*ctx)); -+#else -+ ctx = EVP_CIPHER_CTX_new(); -+#endif -+ if (!ctx) -+ return NULL; -+ -+#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11) -+ EVP_CIPHER_CTX_init(ctx); -+#endif -+ -+ return ctx; -+} -+ -+void tpm2_openssl_cipher_free(EVP_CIPHER_CTX *ctx) { -+#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11) -+ EVP_CIPHER_CTX_cleanup(ctx); -+ free(ctx); -+#else -+ EVP_CIPHER_CTX_free(ctx); -+#endif -+} -+ -+digester tpm2_openssl_halg_to_digester(TPMI_ALG_HASH halg) { -+ -+ switch(halg) { -+ case TPM2_ALG_SHA1: -+ return SHA1; -+ case TPM2_ALG_SHA256: -+ return SHA256; -+ case TPM2_ALG_SHA384: -+ return SHA384; -+ case TPM2_ALG_SHA512: -+ return SHA512; -+ /* no default */ -+ } -+ -+ return NULL; -+} -+ -+/* -+ * Per man openssl(1), handle the following --passin formats: -+ * pass:password -+ * the actual password is password. Since the password is visible to utilities (like 'ps' under Unix) this form should only be used where security is not -+ * important. -+ * -+ * env:var obtain the password from the environment variable var. Since the environment of other processes is visible on certain platforms (e.g. ps under certain -+ * Unix OSes) this option should be used with caution. -+ * -+ * file:pathname -+ * the first line of pathname is the password. If the same pathname argument is supplied to -passin and -passout arguments then the first line will be used -+ * for the input password and the next line for the output password. pathname need not refer to a regular file: it could for example refer to a device or -+ * named pipe. -+ * -+ * fd:number read the password from the file descriptor number. This can be used to send the data via a pipe for example. -+ * -+ * stdin read the password from standard input. -+ * -+ */ -+ -+typedef bool (*pfn_ossl_pw_handler)(const char *passin, char **pass); -diff --git a/lib/tpm2_openssl.h b/lib/tpm2_openssl.h -new file mode 100644 -index 00000000000..d749cb350ac ---- /dev/null -+++ b/lib/tpm2_openssl.h -@@ -0,0 +1,108 @@ -+//**********************************************************************; -+// Copyright (c) 2017, 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: -+// -+// 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. -+// -+// 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 HOLDER 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 LIB_TPM2_OPENSSL_H_ -+#define LIB_TPM2_OPENSSL_H_ -+ -+#include -+ -+#include -+#include -+#include -+ -+#if (OPENSSL_VERSION_NUMBER < 0x1010000fL && !defined(LIBRESSL_VERSION_NUMBER)) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) /* OpenSSL 1.1.0 */ -+#define LIB_TPM2_OPENSSL_OPENSSL_PRE11 -+#endif -+ -+ -+#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11) -+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d); -+#endif -+ -+ -+/** -+ * Function prototype for a hashing routine. -+ * -+ * This is a wrapper around OSSL SHA256|384 and etc digesters. -+ * -+ * @param d -+ * The data to digest. -+ * @param n -+ * The length of the data to digest. -+ * @param md -+ * The output message digest. -+ * @return -+ * A pointer to the digest or NULL on error. -+ */ -+typedef unsigned char *(*digester)(const unsigned char *d, size_t n, unsigned char *md); -+ -+/** -+ * Get an openssl message digest from a tpm hashing algorithm. -+ * @param algorithm -+ * The tpm algorithm to get the corresponding openssl version of. -+ * @return -+ * A pointer to a message digester or NULL on failure. -+ */ -+const EVP_MD *tpm2_openssl_halg_from_tpmhalg(TPMI_ALG_HASH algorithm); -+ -+/** -+ * Obtains an OpenSSL EVP_CIPHER_CTX dealing with version -+ * API changes in OSSL. -+ * -+ * @return -+ * An Initialized OpenSSL EVP_CIPHER_CTX. -+ */ -+EVP_CIPHER_CTX *tpm2_openssl_cipher_new(void); -+ -+/** -+ * Free's an EVP_CIPHER_CTX obtained via tpm2_openssl_cipher_new() -+ * dealing with OSSL API version changes. -+ * @param ctx -+ * The EVP_CIPHER_CTX to free. -+ */ -+void tpm2_openssl_cipher_free(EVP_CIPHER_CTX *ctx); -+ -+/** -+ * Returns a function pointer capable of performing the -+ * given digest from a TPMI_HASH_ALG. -+ * -+ * @param halg -+ * The hashing algorithm to use. -+ * @return -+ * NULL on failure or a valid digester on success. -+ */ -+digester tpm2_openssl_halg_to_digester(TPMI_ALG_HASH halg); -+ -+typedef enum tpm2_openssl_load_rc tpm2_openssl_load_rc; -+enum tpm2_openssl_load_rc { -+ lprc_error = 0, /* an error has occurred */ -+ lprc_private = 1 << 0, /* successfully loaded a private portion of object */ -+ lprc_public = 1 << 1, /* successfully loaded a public portion of object */ -+}; -+ -+ -+#endif /* LIB_TPM2_OPENSSL_H_ */ -diff --git a/lib/tpm2_options.c b/lib/tpm2_options.c -index c2962ee95d4..8c3f36cacea 100644 ---- a/lib/tpm2_options.c -+++ b/lib/tpm2_options.c -@@ -268,9 +268,8 @@ static char* parse_socket_tcti(void) { - - static tcti_conf tcti_get_config(const char *optstr) { - -- tcti_conf conf = { -- .name = NULL -- }; -+ /* set up the default configuration */ -+ tcti_conf conf = { 0 }; - - /* no tcti config supplied, get it from env */ - if (!optstr) { -@@ -294,6 +293,11 @@ static tcti_conf tcti_get_config(const char *optstr) { - } - } - } else { -+ /* handle case of TCTI set as "-T none" */ -+ if (!strcmp(optstr, "none")) { -+ return conf; -+ } -+ - parse_env_tcti(optstr, &conf); - } - -@@ -400,7 +404,7 @@ tpm2_option_code tpm2_handle_options (int argc, char **argv, - * grep -rn case\ \'[a-zA-Z]\' | awk '{print $3}' | sed s/\'//g | sed s/\://g | sort | uniq | less - */ - struct option long_options [] = { -- { "tcti", required_argument, NULL, 'T' }, -+ { "tcti", optional_argument, NULL, 'T' }, - { "help", no_argument, NULL, 'h' }, - { "verbose", no_argument, NULL, 'V' }, - { "quiet", no_argument, NULL, 'Q' }, -@@ -492,17 +496,23 @@ tpm2_option_code tpm2_handle_options (int argc, char **argv, - if (!tool_opts || !(tool_opts->flags & TPM2_OPTIONS_NO_SAPI)) { - tcti_conf conf = tcti_get_config(tcti_conf_option); - -- *tcti = tpm2_tcti_ldr_load(conf.name, conf.opts); -- if (!*tcti) { -- LOG_ERR("Could not load tcti, got: \"%s\"", conf.name); -- goto out; -- } -+ /* name can be NULL for optional SAPI tools */ -+ if (conf.name) { -+ *tcti = tpm2_tcti_ldr_load(conf.name, conf.opts); -+ if (!*tcti) { -+ LOG_ERR("Could not load tcti, got: \"%s\"", conf.name); -+ goto out; -+ } - -- if (!flags->enable_errata) { -- flags->enable_errata = !!getenv (TPM2TOOLS_ENV_ENABLE_ERRATA); -+ if (!flags->enable_errata) { -+ flags->enable_errata = !!getenv (TPM2TOOLS_ENV_ENABLE_ERRATA); -+ } -+ free(conf.name); -+ free(conf.opts); -+ } else if (!tool_opts || !(tool_opts->flags & TPM2_OPTIONS_OPTIONAL_SAPI)) { -+ LOG_ERR("Requested no tcti, but tool requires TCTI."); -+ goto out; - } -- free(conf.name); -- free(conf.opts); - } - - rc = tpm2_option_code_continue; -diff --git a/lib/tpm2_options.h b/lib/tpm2_options.h -index 860d9b0deee..e16c5205044 100644 ---- a/lib/tpm2_options.h -+++ b/lib/tpm2_options.h -@@ -105,6 +105,7 @@ typedef bool (*tpm2_arg_handler)(int argc, char **argv); - */ - #define TPM2_OPTIONS_SHOW_USAGE 0x1 - #define TPM2_OPTIONS_NO_SAPI 0x2 -+#define TPM2_OPTIONS_OPTIONAL_SAPI 0x4 - - struct tpm2_options { - struct { -diff --git a/man/common/tcti.md b/man/common/tcti.md -index fd5f1683dfe..0cb06e3c403 100644 ---- a/man/common/tcti.md -+++ b/man/common/tcti.md -@@ -18,6 +18,10 @@ The variables respected depend on how the software was configured. - * socket - Typically used with the old resource manager, or talking directly to - a simulator. - * device - Used when talking directly to a TPM device file. -+ * none - Do not initialize a connection with the TPM. Some tools allow for off-tpm -+ options and thus support not using a TCTI. Tools that do not support it -+ will error when attempted to be used without a TCTI connection. Does not -+ support *ANY* options and *MUST BE* presented as the exact text of "none". - - * _TPM2TOOLS\_DEVICE\_FILE_: - When using the device TCTI, specify the TPM device file. The default is -diff --git a/man/tpm2_activatecredential.1.md b/man/tpm2_activatecredential.1.md -index 25478790baf..b15569ae5cf 100644 ---- a/man/tpm2_activatecredential.1.md -+++ b/man/tpm2_activatecredential.1.md -@@ -56,7 +56,7 @@ These options control the object verification: - ``` - tpm2_activatecredential -H 0x81010002 -k 0x81010001 -P abc123 -e abc123 -f -o - tpm2_activatecredential -c ak.context -C ek.context -P abc123 -e abc123 -f -o --tpm2_activatecredential -H 0x81010002 -k 0x81010001 -P 123abc -e 1a1b1c -X -f -o -+tpm2_activatecredential -H 0x81010002 -k 0x81010001 -P 123abc -e 1a1b1c -f -o - ``` - - # RETURNS -diff --git a/man/tpm2_certify.1.md b/man/tpm2_certify.1.md -index fba4a8f7c65..f4a78c70c00 100644 ---- a/man/tpm2_certify.1.md -+++ b/man/tpm2_certify.1.md -@@ -71,7 +71,7 @@ These options control the ceritifcation: - ``` - tpm2_certify -H 0x81010002 -k 0x81010001 -P 0x0011 -K 0x00FF -g 0x00B -a -s - tpm2_certify -C obj.context -c key.context -P 0x0011 -K 0x00FF -g 0x00B -a -s --tpm2_certify -H 0x81010002 -k 0x81010001 -P 0011 -K 00FF -X -g 0x00B -a -s -+tpm2_certify -H 0x81010002 -k 0x81010001 -P 0011 -K 00FF -g 0x00B -a -s - ``` - - # RETURNS -diff --git a/man/tpm2_create.1.md b/man/tpm2_create.1.md -index f6aed4a7756..51d71db2c75 100644 ---- a/man/tpm2_create.1.md -+++ b/man/tpm2_create.1.md -@@ -86,7 +86,7 @@ These options for creating the tpm entity: - ``` - tpm2_create -H 0x81010001 -P abc123 -K def456 -g sha256 -G keyedhash-I data.File - tpm2_create -c parent.context -P abc123 -K def456 -g sha256 -G keyedhash -I data.File --tpm2_create -H 0x81010001 -P 123abc -K 456def -X -g sha256 -G keyedhash -I data.File -+tpm2_create -H 0x81010001 -P 123abc -K 456def -g sha256 -G keyedhash -I data.File - ``` - - # RETURNS -diff --git a/man/tpm2_encryptdecrypt.1.md b/man/tpm2_encryptdecrypt.1.md -index ea349bec1e8..350737182dd 100644 ---- a/man/tpm2_encryptdecrypt.1.md -+++ b/man/tpm2_encryptdecrypt.1.md -@@ -48,7 +48,7 @@ specified symmetric key. - ``` - tpm2_encryptdecrypt -k 0x81010001 -P abc123 -D NO -I -o - tpm2_encryptdecrypt -c key.context -P abc123 -D NO -I -o --tpm2_encryptdecrypt -k 0x81010001 -P 123abca -X -D NO -I -o -+tpm2_encryptdecrypt -k 0x81010001 -P 123abca -D NO -I -o - ``` - - # RETURNS -diff --git a/man/tpm2_getpubak.1.md b/man/tpm2_getpubak.1.md -index 22ade8f0b33..1a71b49c110 100644 ---- a/man/tpm2_getpubak.1.md -+++ b/man/tpm2_getpubak.1.md -@@ -80,7 +80,7 @@ loaded-key: - - ``` - tpm2_getpubak -e abc123 -P abc123 -o passwd -E 0x81010001 -k 0x81010002 -f ./ak.pub -n ./ak.name --tpm2_getpubak -e 1a1b1c -P 123abc -o 1a1b1c -X -E 0x81010001 -k 0x81010002 -f ./ak.pub -n ./ak.name -+tpm2_getpubak -e 1a1b1c -P 123abc -o 1a1b1c -E 0x81010001 -k 0x81010002 -f ./ak.pub -n ./ak.name - ``` - - # RETURNS -diff --git a/man/tpm2_makecredential.1.md b/man/tpm2_makecredential.1.md -index 736ead591b8..1008682fe7f 100644 ---- a/man/tpm2_makecredential.1.md -+++ b/man/tpm2_makecredential.1.md -@@ -14,7 +14,8 @@ TPM. - # DESCRIPTION - - **tpm2_makecredential**(1) - Use a TPM public key to protect a secret that is used --to encrypt the AK certififcate. -+to encrypt the AK certificate. This can be used without a TPM by using -+the **none** TCTI option. - - # OPTIONS - -diff --git a/test/system/test_tpm2_makecredential.sh b/test/system/test_tpm2_makecredential.sh -index cc920ccae07..84f77b3647b 100755 ---- a/test/system/test_tpm2_makecredential.sh -+++ b/test/system/test_tpm2_makecredential.sh -@@ -72,4 +72,6 @@ Loadkeyname=`cat $output_ak_pub_name | xxd -p -c $file_size` - - tpm2_makecredential -Q -e $output_ek_pub -s $file_input_data -n $Loadkeyname -o $output_mkcredential - -+tpm2_makecredential -T none -Q -e $output_ek_pub -s $file_input_data -n $Loadkeyname -o $output_mkcredential -+ - exit 0 -diff --git a/tools/tpm2_makecredential.c b/tools/tpm2_makecredential.c -index c8f49fe0207..259d39f30f3 100644 ---- a/tools/tpm2_makecredential.c -+++ b/tools/tpm2_makecredential.c -@@ -1,5 +1,6 @@ - //**********************************************************************; - // Copyright (c) 2015-2018, Intel Corporation -+// Copyright (c) 2019 Massachusetts Institute of Technology - // All rights reserved. - // - // Redistribution and use in source and binary forms, with or without -@@ -38,12 +39,15 @@ - - #include - #include -+#include - - #include "files.h" - #include "tpm2_options.h" - #include "log.h" - #include "files.h" --#include "tpm2_options.h" -+#include "tpm2_alg_util.h" -+#include "tpm2_openssl.h" -+#include "tpm2_identity_util.h" - #include "tpm2_tool.h" - #include "tpm2_util.h" - -@@ -117,6 +121,93 @@ out: - return result; - } - -+static bool make_external_credential_and_save() { -+ -+ /* -+ * Get name_alg from the public key -+ */ -+ TPMI_ALG_HASH name_alg = ctx.public.publicArea.nameAlg; -+ -+ -+ /* -+ * Generate and encrypt seed -+ */ -+ TPM2B_DIGEST seed = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer); -+ seed.size = tpm2_alg_util_get_hash_size(name_alg); -+ RAND_bytes(seed.buffer, seed.size); -+ -+ TPM2B_ENCRYPTED_SECRET encrypted_seed = TPM2B_EMPTY_INIT; -+ unsigned char label[10] = { 'I', 'D', 'E', 'N', 'T', 'I', 'T', 'Y', 0 }; -+ bool res = tpm2_identity_util_encrypt_seed_with_public_key(&seed, -+ &ctx.public, label, 9, -+ &encrypted_seed); -+ if (!res) { -+ LOG_ERR("Failed Seed Encryption\n"); -+ return false; -+ } -+ -+ /* -+ * Perform identity structure calculations (off of the TPM) -+ */ -+ TPM2B_MAX_BUFFER hmac_key; -+ TPM2B_MAX_BUFFER enc_key; -+ tpm2_identity_util_calc_outer_integrity_hmac_key_and_dupsensitive_enc_key( -+ &ctx.public, -+ &ctx.object_name, -+ &seed, -+ &hmac_key, -+ &enc_key); -+ -+ /* -+ * The ctx.credential needs to be marshalled into struct with -+ * both size and contents together (to be encrypted as a block) -+ */ -+ TPM2B_MAX_BUFFER marshalled_inner_integrity = TPM2B_EMPTY_INIT; -+ marshalled_inner_integrity.size = ctx.credential.size + sizeof(ctx.credential.size); -+ UINT16 credSize = ctx.credential.size; -+ if (!tpm2_util_is_big_endian()) { -+ credSize = tpm2_util_endian_swap_16(credSize); -+ } -+ memcpy(marshalled_inner_integrity.buffer, &credSize, sizeof(credSize)); -+ memcpy(&marshalled_inner_integrity.buffer[2], ctx.credential.buffer, ctx.credential.size); -+ -+ /* -+ * Perform inner encryption (encIdentity) and outer HMAC (outerHMAC) -+ */ -+ TPM2B_DIGEST outer_hmac = TPM2B_EMPTY_INIT; -+ TPM2B_MAX_BUFFER encrypted_sensitive = TPM2B_EMPTY_INIT; -+ tpm2_identity_util_calculate_outer_integrity( -+ name_alg, -+ &ctx.object_name, -+ &marshalled_inner_integrity, -+ &hmac_key, -+ &enc_key, -+ &ctx.public.publicArea.parameters.rsaDetail.symmetric, -+ &encrypted_sensitive, -+ &outer_hmac); -+ -+ /* -+ * Package up the info to save -+ * cred_bloc = outer_hmac || encrypted_sensitive -+ * secret = encrypted_seed (with pubEK) -+ */ -+ TPM2B_ID_OBJECT cred_blob = TPM2B_TYPE_INIT(TPM2B_ID_OBJECT, credential); -+ -+ UINT16 outer_hmac_size = outer_hmac.size; -+ if (!tpm2_util_is_big_endian()) { -+ outer_hmac_size = tpm2_util_endian_swap_16(outer_hmac_size); -+ } -+ int offset = 0; -+ memcpy(cred_blob.credential + offset, &outer_hmac_size, sizeof(outer_hmac.size));offset += sizeof(outer_hmac.size); -+ memcpy(cred_blob.credential + offset, outer_hmac.buffer, outer_hmac.size);offset += outer_hmac.size; -+ //NOTE: do NOT include the encrypted_sensitive size, since it is encrypted with the blob! -+ memcpy(cred_blob.credential + offset, encrypted_sensitive.buffer, encrypted_sensitive.size); -+ -+ cred_blob.size = outer_hmac.size + encrypted_sensitive.size + sizeof(outer_hmac.size); -+ -+ return write_cred_and_secret(ctx.out_file_path, &cred_blob, &encrypted_seed); -+} -+ - static bool make_credential_and_save(TSS2_SYS_CONTEXT *sapi_context) - { - TSS2L_SYS_AUTH_RESPONSE sessions_data_out; -@@ -198,7 +289,8 @@ bool tpm2_tool_onstart(tpm2_options **opts) { - }; - - *opts = tpm2_options_new("e:s:n:o:", ARRAY_LEN(topts), topts, -- on_option, NULL, TPM2_OPTIONS_SHOW_USAGE); -+ on_option, NULL, -+ TPM2_OPTIONS_SHOW_USAGE | TPM2_OPTIONS_OPTIONAL_SAPI); - - return *opts != NULL; - } -@@ -212,5 +304,10 @@ int tpm2_tool_onrun(TSS2_SYS_CONTEXT *sapi_context, tpm2_option_flags flags) { - return false; - } - -- return make_credential_and_save(sapi_context) != true; -+ printf("make credential has SAPI CTX: %p", sapi_context); -+ -+ bool result = sapi_context ? make_credential_and_save(sapi_context) : -+ make_external_credential_and_save(); -+ -+ return result != true; - } --- -2.21.0 - diff --git a/Add-attestation-test-which-ensures-full-attestation-.patch b/Add-attestation-test-which-ensures-full-attestation-.patch deleted file mode 100644 index 2424416..0000000 --- a/Add-attestation-test-which-ensures-full-attestation-.patch +++ /dev/null @@ -1,146 +0,0 @@ -From 70733e919aaa72aa03cccf6cd453bbe0da752de1 Mon Sep 17 00:00:00 2001 -From: jetwhiz -Date: Tue, 9 Apr 2019 17:57:36 -0400 -Subject: [PATCH] Add attestation test, which ensures full attestation - process works - -Signed-off-by: jetwhiz ---- - test/system/test_attestation.sh | 125 ++++++++++++++++++++++++++++++++ - 1 file changed, 125 insertions(+) - create mode 100755 test/system/test_attestation.sh - -diff --git a/test/system/test_attestation.sh b/test/system/test_attestation.sh -new file mode 100755 -index 00000000000..ea9da13a419 ---- /dev/null -+++ b/test/system/test_attestation.sh -@@ -0,0 +1,125 @@ -+#!/bin/bash -+#;**********************************************************************; -+# -+# Copyright (c) 2019 Massachusetts Institute of Technology. -+# 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 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 HOLDER 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. -+#;**********************************************************************; -+ -+source test_helpers.sh -+ -+handle_ek=0x81010007 -+handle_ak=0x81010008 -+handle_nv=0x1500018 -+handle_hier=0x40000001 -+ek_alg=rsa -+ak_alg=rsa -+digestAlg=sha256 -+signAlg=rsassa -+ownerpw=ownerpass -+endorsepw=endorsepass -+ekpw=ekpass -+akpw=akpass -+ -+file_input_data=secret.data -+file_input_key=nv.data -+output_ek_pub_pem=ekpub.pem -+output_ek_pub=ek.pub -+output_ak_pub_pem=akpub.pem -+output_ak_pub=ak.pub -+output_ak_priv=ak.priv -+output_ak_pub_name=ak.name -+output_mkcredential=mkcred.out -+output_actcredential=actcred.out -+output_quote=quote.out -+output_quotesig=quotesig.out -+output_quotepcr=quotepcr.out -+ -+cleanup() { -+ rm -f $output_ak_priv \ -+ $file_input_data $file_input_key $output_ek_pub $output_ek_pub_pem $output_ak_pub \ -+ $output_ak_pub_pem $output_ak_pub_name $output_mkcredential \ -+ $output_actcredential $output_quote $output_quotesig $output_quotepcr rand.out -+ -+ tpm2_pcrreset 16 -+ tpm2_evictcontrol -Q -Ao -c $handle_ek 2>/dev/null || true -+ tpm2_evictcontrol -Q -Ao -c $handle_ak 2>/dev/null || true -+ -+ tpm2_nvrelease -Q -x $handle_nv -a $handle_hier -P "$ownerpw" 2>/dev/null || true -+ -+ tpm2_takeownership -c 2>/dev/null || true -+} -+trap cleanup EXIT -+ -+ -+cleanup -+ -+echo "12345678" > $file_input_data -+echo "1234567890123456789012345678901" > $file_input_key -+ -+getrandom() { -+ tpm2_getrandom -Q -o rand.out $1 -+ local file_size=`stat --printf="%s" rand.out` -+ loaded_randomness=`cat rand.out | xxd -p -c $file_size` -+} -+ -+ -+tpm2_takeownership -o "$ownerpw" -e "$endorsepw" -+ -+# Key generation -+tpm2_getpubek -Q -H $handle_ek -g $ek_alg -f $output_ek_pub -P "$ekpw" -o "$ownerpw" -e "$endorsepw" -+tpm2_readpublic -Q -H $handle_ek -o $output_ek_pub_pem -f pem -+tpm2_getpubak -Q -E $handle_ek -k $handle_ak -g $ak_alg -D $digestAlg -s $signAlg -f $output_ak_pub -n $output_ak_pub_name -e "$endorsepw" -P "$akpw" -o "$ownerpw" -+tpm2_readpublic -Q -H $handle_ak -o $output_ak_pub_pem -f pem -+ -+# Validate keys (registrar) -+file_size=`stat --printf="%s" $output_ak_pub_name` -+loaded_key_name=`cat $output_ak_pub_name | xxd -p -c $file_size` -+tpm2_makecredential -Q -T none -e $output_ek_pub -s $file_input_data -n $loaded_key_name -o $output_mkcredential -+tpm2_activatecredential -Q -H $handle_ak -k $handle_ek -f $output_mkcredential -o $output_actcredential -P "$akpw" -e "$endorsepw" -+diff $file_input_data $output_actcredential -+ -+ -+# Quoting -+tpm2_pcrreset -Q 16 -+tpm2_pcrextend -Q 16:sha256=6ea40aa7267bb71251c1de1c3605a3df759b86b22fa9f62aa298d4197cd88a38 -+tpm2_pcrlist -Q -+getrandom 20 -+tpm2_quote -Q -k $handle_ak -L $digestAlg:15,16,22 -q $loaded_randomness -m $output_quote -s $output_quotesig -p $output_quotepcr -G $digestAlg -P "$akpw" -+ -+ -+# Verify quote -+tpm2_checkquote -Q -c $output_ak_pub_pem -m $output_quote -s $output_quotesig -p $output_quotepcr -G $digestAlg -q $loaded_randomness -+ -+ -+# Save U key from verifier -+tpm2_nvdefine -Q -x $handle_nv -a $handle_hier -s 32 -t "ownerread|policywrite|ownerwrite" -I "indexpass" -P "$ownerpw" -+tpm2_nvwrite -Q -x $handle_nv -a $handle_hier -P "$ownerpw" $file_input_key -+tpm2_nvread -Q -x $handle_nv -a $handle_hier -s 32 -P "$ownerpw" -+ -+exit 0 --- -2.21.0 - diff --git a/Fix-ups-in-tpm2_quote.md.1.patch b/Fix-ups-in-tpm2_quote.md.1.patch deleted file mode 100644 index 00ee2e8..0000000 --- a/Fix-ups-in-tpm2_quote.md.1.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 6c25de22d981d26d0ae80d99706f86c52f713b06 Mon Sep 17 00:00:00 2001 -From: jetwhiz -Date: Fri, 3 May 2019 13:46:41 -0400 -Subject: [PATCH] Fix-ups in tpm2_quote.md.1 - -Capitalization fixes to follow preferred format - -Signed-off-by: jetwhiz ---- - man/tpm2_quote.1.md | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/man/tpm2_quote.1.md b/man/tpm2_quote.1.md -index 491848201d9..c926f4d045d 100644 ---- a/man/tpm2_quote.1.md -+++ b/man/tpm2_quote.1.md -@@ -41,12 +41,12 @@ - - * **-m**, **--message**: - -- message output file, records the quote message that makes up the data that -+ Message output file, records the quote message that makes up the data that - is signed by the TPM. - - * **-s**, **--signature**: - -- signature output file, records the signature in the format specified via the **-f** -+ Signature output file, records the signature in the format specified via the **-f** - option. - - * **-f**, **--format** --- -2.21.0 - diff --git a/Update-CHANGELOG.md.patch b/Update-CHANGELOG.md.patch deleted file mode 100644 index ad330a7..0000000 --- a/Update-CHANGELOG.md.patch +++ /dev/null @@ -1,26 +0,0 @@ -From edbbe53e225bcc68c6ee0a5a85bec82ae6cdc398 Mon Sep 17 00:00:00 2001 -From: William Roberts -Date: Thu, 2 May 2019 08:44:48 -0700 -Subject: [PATCH] Update CHANGELOG.md - ---- - CHANGELOG.md | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/CHANGELOG.md b/CHANGELOG.md -index 19e831d7e7f..a8e4f39afde 100644 ---- a/CHANGELOG.md -+++ b/CHANGELOG.md -@@ -1,4 +1,9 @@ - ## Changelog -+### 3.2.0 - next -+* tpm2_makecredential: add support for executing tool off-TPM. -+* tpm2_pcrreset: introduce new tool for resetting PCRs. -+* tpm2_quote: Fix AK auth password not being used. -+ - ### 3.1.4 - 2019-03-14 - * Fix various man pages - * tpm2_getmanufec: fix OSSL build warnings --- -2.21.0 - diff --git a/Wire-up-support-for-ak-auth-password-in-tpm2_quote-t.patch b/Wire-up-support-for-ak-auth-password-in-tpm2_quote-t.patch deleted file mode 100644 index fbb65db..0000000 --- a/Wire-up-support-for-ak-auth-password-in-tpm2_quote-t.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 993da58a612238bf2dd53a015dfdb2a6c0eb00b9 Mon Sep 17 00:00:00 2001 -From: jetwhiz -Date: Mon, 22 Apr 2019 09:48:56 -0400 -Subject: [PATCH 1/6] Wire up support for ak auth password in tpm2_quote tool - -Add regression test - -Signed-off-by: jetwhiz ---- - test/system/test_tpm2_quote.sh | 9 ++++++++- - tools/tpm2_quote.c | 11 ++++++++--- - 2 files changed, 16 insertions(+), 4 deletions(-) - -diff --git a/test/system/test_tpm2_quote.sh b/test/system/test_tpm2_quote.sh -index d845ea1bdb1..231bed326ec 100755 ---- a/test/system/test_tpm2_quote.sh -+++ b/test/system/test_tpm2_quote.sh -@@ -50,6 +50,7 @@ file_quote_key_ctx=ctx_load_out_"$alg_primary_obj"_"$alg_primary_key"-"$alg_crea - Handle_ak_quote=0x81010016 - Handle_ek_quote=0x81010017 - Handle_ak_quote2=0x81010018 -+Handle_ak_quote3=0x81010019 - - maxdigest=$(tpm2_getcap -c properties-fixed | grep TPM_PT_MAX_DIGEST | sed -r -e 's/.*(0x[0-9a-f]+)/\1/g') - if ! [[ "$maxdigest" =~ ^(0x)*[0-9]+$ ]] ; then -@@ -73,6 +74,7 @@ cleanup() { - tpm2_evictcontrol -Q -Ao -H $Handle_ek_quote 2>/dev/null || true - tpm2_evictcontrol -Q -Ao -H $Handle_ak_quote 2>/dev/null || true - tpm2_evictcontrol -Q -Ao -H $Handle_ak_quote2 2>/dev/null || true -+ tpm2_evictcontrol -Q -Ao -H $Handle_ak_quote3 2>/dev/null || true - } - trap cleanup EXIT - -@@ -104,4 +106,9 @@ tpm2_getpubak -Q -E $Handle_ek_quote -k $Handle_ak_quote2 -f ak.pub2 -n ak.nam - - tpm2_quote -Q -k $Handle_ak_quote -g $alg_quote -l 16,17,18 -q $nonce - --exit 0 -+#####AK with password -+tpm2_getpubak -Q -E $Handle_ek_quote -k $Handle_ak_quote3 -f ak.pub2 -n ak.name_2 -P abc123 -+ -+tpm2_quote -Q -k $Handle_ak_quote3 -g $alg_quote -l 16,17,18 -q $nonce -P abc123 -+ -+exit 0 -\ No newline at end of file -diff --git a/tools/tpm2_quote.c b/tools/tpm2_quote.c -index 3538947db31..05b6d641656 100644 ---- a/tools/tpm2_quote.c -+++ b/tools/tpm2_quote.c -@@ -50,7 +50,7 @@ typedef struct { - UINT32 id[24]; - } PCR_LIST; - --static TPMS_AUTH_COMMAND sessionData; -+static TPMS_AUTH_COMMAND sessionData = TPMS_AUTH_COMMAND_INIT(TPM2_RS_PW); - static char *outFilePath; - static char *signature_path; - static char *message_path; -@@ -60,7 +60,7 @@ static TPM2B_DATA qualifyingData = TPM2B_EMPTY_INIT; - static TPML_PCR_SELECTION pcrSelections; - static bool is_auth_session; - static TPMI_SH_AUTH_SESSION auth_session_handle; --static int k_flag, c_flag, l_flag, g_flag, L_flag, o_flag, G_flag; -+static int k_flag, c_flag, l_flag, g_flag, L_flag, o_flag, G_flag, P_flag; - static char *contextFilePath; - static TPM2_HANDLE akHandle; - -@@ -94,7 +94,7 @@ static int quote(TSS2_SYS_CONTEXT *sapi_context, TPM2_HANDLE akHandle, TPML_PCR_ - { - UINT32 rval; - TPMT_SIG_SCHEME inScheme; -- TSS2L_SYS_AUTH_COMMAND sessionsData = { 1, {{.sessionHandle=TPM2_RS_PW}}}; -+ TSS2L_SYS_AUTH_COMMAND sessionsData = { 1, { sessionData }}; - TSS2L_SYS_AUTH_RESPONSE sessionsDataOut; - TPM2B_ATTEST quoted = TPM2B_TYPE_INIT(TPM2B_ATTEST, attestationData); - TPMT_SIGNATURE signature; -@@ -152,6 +152,7 @@ static bool on_option(char key, char *value) { - LOG_ERR("Invalid AK password, got\"%s\"", value); - return false; - } -+ P_flag = 1; - } break; - case 'l': - if(!pcr_parse_list(value, strlen(value), &pcrSelections.pcrSelections[0])) -@@ -265,5 +266,9 @@ int tpm2_tool_onrun(TSS2_SYS_CONTEXT *sapi_context, tpm2_option_flags flags) { - } - } - -+ if (P_flag == 0) { -+ sessionData.hmac.size = 0; -+ } -+ - return quote(sapi_context, akHandle, &pcrSelections); - } --- -2.21.0 - diff --git a/lib-tpm2_util.c-string_to_uint32-ensure-the-string-d.patch b/lib-tpm2_util.c-string_to_uint32-ensure-the-string-d.patch deleted file mode 100644 index ff0162b..0000000 --- a/lib-tpm2_util.c-string_to_uint32-ensure-the-string-d.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 9685ea263f994537430323fb1681b210395eee7c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?=D0=94=D0=B8=D0=BB=D1=8F=D0=BD=20=D0=9F=D0=B0=D0=BB=D0=B0?= - =?UTF-8?q?=D1=83=D0=B7=D0=BE=D0=B2?= -Date: Tue, 2 Apr 2019 16:18:32 +0000 -Subject: [PATCH] lib/tpm2_util.c:string_to_uint32: ensure the string does not - overflow in uint32 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Before this change input of "4294967295" generated output of 4294967295, which -is UINT32_MAX = 2**32 - 1. But input "4294967296" created output of 0. The -function is supposed to fail if the number is too big, rather than silently -convert unsigned long int to uint32_t, ignoring some bits. - -Signed-Off-By: Дилян Палаузов ---- - lib/tpm2_util.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/lib/tpm2_util.c b/lib/tpm2_util.c -index edfda4a8b0b..ca9d8b7f4d7 100644 ---- a/lib/tpm2_util.c -+++ b/lib/tpm2_util.c -@@ -236,8 +236,8 @@ bool tpm2_util_string_to_uint32(const char *str, uint32_t *value) { - - /* clear errno before the call, should be 0 afterwards */ - errno = 0; -- uint32_t tmp = strtoul(str, &endptr, 0); -- if (errno) { -+ unsigned long int tmp = strtoul(str, &endptr, 0); -+ if (errno || tmp > UINT32_MAX) { - return false; - } - -@@ -250,7 +250,7 @@ bool tpm2_util_string_to_uint32(const char *str, uint32_t *value) { - return false; - } - -- *value = tmp; -+ *value = (uint32_t) tmp; - return true; - } - --- -2.21.0 - diff --git a/sources b/sources index a0560ab..57117aa 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (tpm2-tools-3.1.4.tar.gz) = c5e1be4ffab305ee42a8b4a9c9aa4373158259a58844e273465f97a74f913fb12098b9fd81127148be95ecba7378f6a45b96af256dde3101a237e5e33e8e8ccb +SHA512 (tpm2-tools-3.2.0.tar.gz) = ab8081ee3ac2d7f445522141395198b1c570b9649a42e4b27b11b0e04495f4c935ee3ec73b228a953934f9dbdf3dccd4640eb62c4e0bae6dd11b91260e67c227 diff --git a/tpm2-tools.spec b/tpm2-tools.spec index 41bfef4..e0d68bb 100644 --- a/tpm2-tools.spec +++ b/tpm2-tools.spec @@ -1,21 +1,12 @@ Name: tpm2-tools -Version: 3.1.4 -Release: 2%{?dist} +Version: 3.2.0 +Release: 1%{?dist} Summary: A TPM2.0 testing tool build upon TPM2.0-TSS License: BSD URL: https://github.com/tpm2-software/tpm2-tools Source0: https://github.com/tpm2-software/tpm2-tools/releases/download/%{version}/%{name}-%{version}.tar.gz -Patch0: Wire-up-support-for-ak-auth-password-in-tpm2_quote-t.patch -Patch1: tpm2_pcrreset-new-tools.patch -Patch2: Add-ability-to-run-tpm2_makecredential-without-a-TPM.patch -Patch3: Update-CHANGELOG.md.patch -Patch4: Add-ability-to-check-quotes-and-output-PCR-values-fo.patch -Patch5: Add-attestation-test-which-ensures-full-attestation-.patch -Patch6: Fix-ups-in-tpm2_quote.md.1.patch -Patch7: lib-tpm2_util.c-string_to_uint32-ensure-the-string-d.patch - BuildRequires: gcc-c++ BuildRequires: libtool BuildRequires: autoconf-archive @@ -54,6 +45,10 @@ tpm2-tools is a batch of testing tools for tpm2.0. It is based on tpm2-tss. %{_mandir}/man1/tpm2_*.1.gz %changelog +* Fri Jun 21 2019 Yunying Sun - 3.2.0-1 +- Update to 3.2.0 release +- Removed patches since all have been included in 3.2.0 release + * Fri May 10 2019 Javier Martinez Canillas - 3.1.4-2 - Allow tpm2_makecredential to run without a TPM (jetwhiz) - Add tpm2_pcrreset and tpm2_checkquote tools (jetwhiz) diff --git a/tpm2_pcrreset-new-tools.patch b/tpm2_pcrreset-new-tools.patch deleted file mode 100644 index ba6ca0b..0000000 --- a/tpm2_pcrreset-new-tools.patch +++ /dev/null @@ -1,313 +0,0 @@ -From 016ef077a2e81fab14cbcd5ba6fae10a6681688b Mon Sep 17 00:00:00 2001 -From: jetwhiz -Date: Mon, 1 Oct 2018 17:55:13 -0400 -Subject: [PATCH 2/6] tpm2_pcrreset new tools - -New tool to allow resetting PCR registers, backport from 0ef0f31775 - -Signed-off-by: jetwhiz ---- - Makefile.am | 3 + - man/tpm2_pcrreset.1.md | 58 ++++++++++++++ - test/system/test_tpm2_pcrreset.sh | 59 ++++++++++++++ - tools/tpm2_pcrreset.c | 129 ++++++++++++++++++++++++++++++ - 4 files changed, 249 insertions(+) - create mode 100644 man/tpm2_pcrreset.1.md - create mode 100755 test/system/test_tpm2_pcrreset.sh - create mode 100644 tools/tpm2_pcrreset.c - -diff --git a/Makefile.am b/Makefile.am -index 3856bcb400c..ffe22f383e3 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -87,6 +87,7 @@ bin_PROGRAMS = \ - tools/tpm2_pcrevent \ - tools/tpm2_pcrextend \ - tools/tpm2_pcrlist \ -+ tools/tpm2_pcrreset \ - tools/tpm2_quote \ - tools/tpm2_rc_decode \ - tools/tpm2_readpublic \ -@@ -179,6 +180,7 @@ tools_tpm2_unseal_SOURCES = tools/tpm2_unseal.c $(TOOL_SRC) - tools_tpm2_dictionarylockout_SOURCES = tools/tpm2_dictionarylockout.c $(TOOL_SRC) - tools_tpm2_createpolicy_SOURCES = tools/tpm2_createpolicy.c $(TOOL_SRC) - tools_tpm2_pcrextend_SOURCES = tools/tpm2_pcrextend.c $(TOOL_SRC) -+tools_tpm2_pcrreset_SOURCES = tools/tpm2_pcrreset.c $(TOOL_SRC) - tools_tpm2_pcrevent_SOURCES = tools/tpm2_pcrevent.c $(TOOL_SRC) - tools_tpm2_rc_decode_SOURCES = tools/tpm2_rc_decode.c $(TOOL_SRC) - -@@ -279,6 +281,7 @@ if HAVE_MAN_PAGES - man/man1/tpm2_pcrevent.1 \ - man/man1/tpm2_pcrextend.1 \ - man/man1/tpm2_pcrlist.1 \ -+ man/man1/tpm2_pcrreset.1 \ - man/man1/tpm2_quote.1 \ - man/man1/tpm2_rc_decode.1 \ - man/man1/tpm2_readpublic.1 \ -diff --git a/man/tpm2_pcrreset.1.md b/man/tpm2_pcrreset.1.md -new file mode 100644 -index 00000000000..d5637137796 ---- /dev/null -+++ b/man/tpm2_pcrreset.1.md -@@ -0,0 +1,58 @@ -+% tpm2_pcrreset(1) tpm2-tools | General Commands Manual -+% -+% JANUARY 2019 -+ -+# NAME -+ -+**tpm2_pcrreset**(1) - Reset one or more PCR banks -+ -+# SYNOPSIS -+ -+**tpm2_pcrreset** [*OPTIONS*] _PCR\_INDEX_ ... -+ -+# DESCRIPTION -+ -+**tpm2_pcrreset**(1) - Reset PCR value in all banks for specified index. -+More than one PCR index can be specified. -+ -+The reset value is manufacturer-dependent and is either sequence of 00 or FF -+on the length of the hash algorithm for each supported bank -+ -+_PCR\_INDEX_ is a space separated list of PCR indexes to be reset when issuing -+the command. -+ -+# OPTIONS -+ -+This tool accepts no tool specific options. -+ -+[common options](common/options.md) -+ -+[common tcti options](common/tcti.md) -+ -+# EXAMPLES -+ -+## Reset a single PCR -+``` -+tpm2_pcrreset 23 -+``` -+ -+## Reset multiple PCRs -+``` -+tpm2_pcrreset 16 23 -+``` -+ -+# NOTES -+ -+On operating system's locality (generally locality 0), only PCR 23 can be reset. -+PCR-16 can also be reset on this locality, depending on TPM manufacturers -+which could define this PCR as resettable. -+ -+PCR 0 to 15 are not resettable (being part of SRTM). PCR 16 to 22 are mostly -+reserved for DRTM or dedicated to specific localities and might not -+be resettable depending on current TPM locality. -+ -+# RETURNS -+ -+0 on success or 1 on failure. -+ -+[footer](common/footer.md) -diff --git a/test/system/test_tpm2_pcrreset.sh b/test/system/test_tpm2_pcrreset.sh -new file mode 100755 -index 00000000000..962de780ab4 ---- /dev/null -+++ b/test/system/test_tpm2_pcrreset.sh -@@ -0,0 +1,59 @@ -+#!/bin/bash -+#;**********************************************************************; -+# -+# Copyright (c) 2019, Sebastien LE STUM -+# 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 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 HOLDER 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. -+#;**********************************************************************; -+ -+source test_helpers.sh -+ -+# Reset a resettable PCR -+tpm2_pcrreset 23 -+ -+# Reset more than one resettable PCR -+tpm2_pcrreset 16 23 -+ -+# Get PCR_Reset out of bound index error -+tpm2_pcrreset 999 2>&1 1>/dev/null | grep -q "out of bound PCR" -+ -+# Get PCR_Reset wrong index error -+tpm2_pcrreset toto 2>&1 1>/dev/null | grep -q "invalid PCR" -+ -+# Get PCR_Reset index out of range error -+if tpm2_pcrreset 29 2>&1 1>/dev/null ; then -+ echo "tpm2_pcrreset on out of range PCR index didn't fail" -+ exit 1 -+else -+ true -+fi -+ -+# Get PCR_Reset bad locality error -+tpm2_pcrreset 0 2>&1 1>/dev/null | grep -q "0x907" -+ -+exit 0 -diff --git a/tools/tpm2_pcrreset.c b/tools/tpm2_pcrreset.c -new file mode 100644 -index 00000000000..5fa1de121e7 ---- /dev/null -+++ b/tools/tpm2_pcrreset.c -@@ -0,0 +1,129 @@ -+//**********************************************************************; -+// Copyright (c) 2017, 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: -+// -+// 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 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 HOLDER 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 "log.h" -+#include "pcr.h" -+#include "tpm2_options.h" -+#include "tpm2_tool.h" -+#include "tpm2_util.h" -+ -+typedef struct tpm_pcr_reset_ctx tpm_pcr_reset_ctx; -+struct tpm_pcr_reset_ctx { -+ bool pcr_list[TPM2_MAX_PCRS]; -+}; -+ -+static tpm_pcr_reset_ctx ctx; -+ -+static bool pcr_reset_one(TSS2_SYS_CONTEXT *sapi_context, TPMI_DH_PCR pcr_index) { -+ TSS2L_SYS_AUTH_RESPONSE sessions_data_out; -+ TSS2L_SYS_AUTH_COMMAND sessions_data = { 1, {{ .sessionHandle=TPM2_RS_PW }}}; -+ -+ TSS2_RC rval = TSS2_RETRY_EXP(Tss2_Sys_PCR_Reset(sapi_context, pcr_index, &sessions_data, -+ &sessions_data_out)); -+ if (rval != TSS2_RC_SUCCESS) { -+ LOG_ERR("Could not reset PCR index: %d", pcr_index); -+ return false; -+ } -+ -+ return true; -+} -+ -+static bool pcr_reset(TSS2_SYS_CONTEXT *sapi_context) { -+ size_t i; -+ -+ for (i = 0; i < TPM2_MAX_PCRS; i++) { -+ if(!ctx.pcr_list[i]) -+ continue; -+ -+ bool result = pcr_reset_one(sapi_context, i); -+ if (!result) { -+ return false; -+ } -+ } -+ -+ return true; -+} -+ -+static bool on_arg(int argc, char** argv){ -+ int i; -+ uint32_t pcr; -+ -+ memset(ctx.pcr_list, 0, TPM2_MAX_PCRS); -+ -+ if (argc < 1) { -+ LOG_ERR("Expected at least one PCR index" -+ "ie: , got: 0"); -+ return false; -+ } -+ -+ for(i = 0; i < argc; i++){ -+ if(!tpm2_util_string_to_uint32(argv[i], &pcr)){ -+ LOG_ERR("Got invalid PCR Index: \"%s\"", argv[i]); -+ return false; -+ } -+ -+ /* -+ * If any specified PCR index is greater than the last valid -+ * index supported in the spec, throw an error -+ */ -+ if(pcr > TPM2_MAX_PCRS - 1){ -+ LOG_ERR("Got out of bound PCR Index: \"%s\"", argv[i]); -+ return false; -+ } -+ -+ ctx.pcr_list[pcr] = 1; -+ } -+ -+ return true; -+} -+ -+bool tpm2_tool_onstart(tpm2_options **opts) { -+ -+ *opts = tpm2_options_new(NULL, 0, NULL, NULL, on_arg, 0); -+ -+ return *opts != NULL; -+} -+ -+int tpm2_tool_onrun(TSS2_SYS_CONTEXT *sapi_context, tpm2_option_flags flags) { -+ -+ UNUSED(flags); -+ -+ return pcr_reset(sapi_context) != true; -+} -+ --- -2.21.0 -