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
new file mode 100644
index 0000000..5c6cd2a
--- /dev/null
+++ b/Add-ability-to-check-quotes-and-output-PCR-values-fo.patch
@@ -0,0 +1,2007 @@
+From 3f9c713d3bff4abf417edf0f74e0b049bfd1b31f Mon Sep 17 00:00:00 2001
+From: jetwhiz <Charles.Munson@ll.mit.edu>
+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 <Charles.Munson@ll.mit.edu>
+---
+ 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 <string.h>
+ 
+ #include <tss2/tss2_sys.h>
++#include <inttypes.h>
+ #include <stdbool.h>
+ 
+ #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 <tss2/tss2_sys.h>
+ 
++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 <openssl/hmac.h>
+ #include <openssl/rsa.h>
+ 
++#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, &quoted->attestationData[i], 4);i += 4;
++    memcpy(&type, &quoted->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, &quoted->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, &quoted->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, &quoted->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, &quoted->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, &quoted->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, &quoted->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, &quoted->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, &quoted->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 <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <errno.h>
++
++#include <tss2/tss2_esys.h>
++
++#include <openssl/rsa.h>
++
++#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(&quoted, &quoteDigest, &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(&quoteDigest, &pcr_digest)) {
++            LOG_ERR("Error validating calculated PCR composite with quote");
++            return false;
++        }
++    }
++
++    // Write everything out
+     bool res = write_output_files(&quoted, &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
new file mode 100644
index 0000000..9929d13
--- /dev/null
+++ b/Add-ability-to-run-tpm2_makecredential-without-a-TPM.patch
@@ -0,0 +1,1305 @@
+From d74b094191f2e09b29cfad4f03322e0cd64497ab Mon Sep 17 00:00:00 2001
+From: jetwhiz <charles.munson@ll.mit.edu>
+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 <Charles.Munson@ll.mit.edu>
+---
+ 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 <errno.h>
++#include <stdint.h>
++#include <string.h>
++
++#include <openssl/aes.h>
++#include <openssl/bn.h>
++#include <openssl/evp.h>
++#include <openssl/err.h>
++#include <openssl/hmac.h>
++#include <openssl/obj_mac.h>
++#include <openssl/pem.h>
++#include <openssl/rand.h>
++#include <openssl/rsa.h>
++
++#include <tss2/tss2_mu.h>
++#include <tss2/tss2_sys.h>
++
++#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 <tss2/tss2_sys.h>
++
++#include <openssl/err.h>
++#include <openssl/hmac.h>
++#include <openssl/rsa.h>
++
++
++/**
++ * 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 <errno.h>
++#include <stdint.h>
++#include <string.h>
++
++#include <openssl/aes.h>
++#include <openssl/bn.h>
++#include <openssl/evp.h>
++#include <openssl/err.h>
++#include <openssl/hmac.h>
++#include <openssl/obj_mac.h>
++#include <openssl/pem.h>
++#include <openssl/rand.h>
++#include <openssl/rsa.h>
++
++#include <tss2/tss2_sys.h>
++
++#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 <tss2/tss2_sys.h>
++
++#include <openssl/err.h>
++#include <openssl/hmac.h>
++#include <openssl/rsa.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
++
++
++#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 <filePath> -o <filePath>
+ tpm2_activatecredential -c ak.context -C ek.context -P abc123 -e abc123 -f <filePath> -o <filePath>
+-tpm2_activatecredential -H 0x81010002 -k 0x81010001 -P 123abc -e 1a1b1c -X -f <filePath> -o <filePath>
++tpm2_activatecredential -H 0x81010002 -k 0x81010001 -P 123abc -e 1a1b1c -f <filePath> -o <filePath>
+ ```
+ 
+ # 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 <fileName> -s <fileName>
+ tpm2_certify -C obj.context -c key.context -P 0x0011 -K 0x00FF -g 0x00B -a <fileName> -s <fileName>
+-tpm2_certify -H 0x81010002 -k 0x81010001 -P 0011 -K 00FF -X -g 0x00B -a <fileName> -s <fileName>
++tpm2_certify -H 0x81010002 -k 0x81010001 -P 0011 -K 00FF -g 0x00B -a <fileName> -s <fileName>
+ ```
+ 
+ # 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 <filePath> -o <filePath>
+ tpm2_encryptdecrypt -c key.context -P abc123 -D NO -I <filePath> -o <filePath>
+-tpm2_encryptdecrypt -k 0x81010001 -P 123abca -X -D NO -I <filePath> -o <filePath>
++tpm2_encryptdecrypt -k 0x81010001 -P 123abca -D NO -I <filePath> -o <filePath>
+ ```
+ 
+ # 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 <tss2/tss2_sys.h>
+ #include <tss2/tss2_mu.h>
++#include <openssl/rand.h>
+ 
+ #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
new file mode 100644
index 0000000..2424416
--- /dev/null
+++ b/Add-attestation-test-which-ensures-full-attestation-.patch
@@ -0,0 +1,146 @@
+From 70733e919aaa72aa03cccf6cd453bbe0da752de1 Mon Sep 17 00:00:00 2001
+From: jetwhiz <Charles.Munson@ll.mit.edu>
+Date: Tue, 9 Apr 2019 17:57:36 -0400
+Subject: [PATCH] Add attestation test, which ensures full attestation
+ process works
+
+Signed-off-by: jetwhiz <Charles.Munson@ll.mit.edu>
+---
+ 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
new file mode 100644
index 0000000..00ee2e8
--- /dev/null
+++ b/Fix-ups-in-tpm2_quote.md.1.patch
@@ -0,0 +1,34 @@
+From 6c25de22d981d26d0ae80d99706f86c52f713b06 Mon Sep 17 00:00:00 2001
+From: jetwhiz <Charles.Munson@ll.mit.edu>
+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 <Charles.Munson@ll.mit.edu>
+---
+ 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
new file mode 100644
index 0000000..ad330a7
--- /dev/null
+++ b/Update-CHANGELOG.md.patch
@@ -0,0 +1,26 @@
+From edbbe53e225bcc68c6ee0a5a85bec82ae6cdc398 Mon Sep 17 00:00:00 2001
+From: William Roberts <william.c.roberts@intel.com>
+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
new file mode 100644
index 0000000..fbb65db
--- /dev/null
+++ b/Wire-up-support-for-ak-auth-password-in-tpm2_quote-t.patch
@@ -0,0 +1,97 @@
+From 993da58a612238bf2dd53a015dfdb2a6c0eb00b9 Mon Sep 17 00:00:00 2001
+From: jetwhiz <Charles.Munson@ll.mit.edu>
+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 <Charles.Munson@ll.mit.edu>
+---
+ 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
new file mode 100644
index 0000000..ff0162b
--- /dev/null
+++ b/lib-tpm2_util.c-string_to_uint32-ensure-the-string-d.patch
@@ -0,0 +1,47 @@
+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?= <git-dpa@aegee.org>
+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: Дилян Палаузов <git-dpa@aegee.org>
+---
+ 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/tpm2-tools.spec b/tpm2-tools.spec
index c061d9e..41bfef4 100644
--- a/tpm2-tools.spec
+++ b/tpm2-tools.spec
@@ -1,12 +1,21 @@
 Name: tpm2-tools
 Version: 3.1.4
-Release: 1%{?dist}
+Release: 2%{?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
@@ -45,6 +54,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 May 10 2019 Javier Martinez Canillas <javierm@redhat.com> - 3.1.4-2
+- Allow tpm2_makecredential to run without a TPM (jetwhiz)
+- Add tpm2_pcrreset and tpm2_checkquote tools (jetwhiz)
+
 * Fri Mar 15 2019 Yunying Sun <yunying.sun@intel.com> - 3.1.4-1
 - Update to 3.1.4 release
 - Removed the 4 patches since all have been included in 3.1.4 release
diff --git a/tpm2_pcrreset-new-tools.patch b/tpm2_pcrreset-new-tools.patch
new file mode 100644
index 0000000..ba6ca0b
--- /dev/null
+++ b/tpm2_pcrreset-new-tools.patch
@@ -0,0 +1,313 @@
+From 016ef077a2e81fab14cbcd5ba6fae10a6681688b Mon Sep 17 00:00:00 2001
+From: jetwhiz <charles.munson@ll.mit.edu>
+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 <Charles.Munson@ll.mit.edu>
+---
+ 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 <ctype.h>
++#include <errno.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include <tss2/tss2_sys.h>
++
++#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: <pcr index>, 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
+