libimcv: migrate pts to tpm_tss
authorAndreas Steffen <andreas.steffen@strongswan.org>
Sun, 5 Jun 2016 18:39:41 +0000 (20:39 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Wed, 22 Jun 2016 13:33:44 +0000 (15:33 +0200)
12 files changed:
conf/plugins/imc-attestation.opt
configure.ac
src/libimcv/Makefile.am
src/libimcv/plugins/imc_attestation/imc_attestation_process.c
src/libimcv/plugins/imv_attestation/imv_attestation_agent.c
src/libimcv/pts/components/ita/ita_comp_tgrub.c
src/libimcv/pts/pts.c
src/libimcv/pts/pts.h
src/libtpmtss/tpm_tss.h
src/libtpmtss/tpm_tss_trousers.c
src/libtpmtss/tpm_tss_trousers.h
src/libtpmtss/tpm_tss_tss2.c

index 7a40bc9..c2dbe42 100644 (file)
@@ -16,6 +16,9 @@ libimcv.plugins.imc-attestation.nonce_len = 20
 libimcv.plugins.imc-attestation.use_quote2 = yes
        Use Quote2 AIK signature instead of Quote signature.
 
+libimcv.plugins.imc-attestation.use_version_info = no
+       Version Info is included in Quote2 signature.
+
 libimcv.plugins.imc-attestation.pcr_info = no
        Whether to send pcr_before and pcr_after info.
 
index 3777a48..7f897c6 100644 (file)
@@ -1624,7 +1624,7 @@ AM_CONDITIONAL(USE_LIBIPSEC, test x$libipsec = xtrue)
 AM_CONDITIONAL(USE_LIBTNCIF, test x$tnc_tnccs = xtrue -o x$imcv = xtrue)
 AM_CONDITIONAL(USE_LIBTNCCS, test x$tnc_tnccs = xtrue)
 AM_CONDITIONAL(USE_LIBPTTLS, test x$tnc_tnccs = xtrue)
-AM_CONDITIONAL(USE_LIBTPMTSS, test x$tss_trousers = xtrue -o x$tss_tss2 = xtrue -o x$aikgen = xtrue -o x$aikpub2 = xtrue )
+AM_CONDITIONAL(USE_LIBTPMTSS, test x$tss_trousers = xtrue -o x$tss_tss2 = xtrue -o x$aikgen = xtrue -o x$aikpub2 = xtrue -o x$imcv = xtrue)
 AM_CONDITIONAL(USE_FILE_CONFIG, test x$stroke = xtrue)
 AM_CONDITIONAL(USE_IPSEC_SCRIPT, test x$stroke = xtrue -o x$scepclient = xtrue -o x$conftest = xtrue)
 AM_CONDITIONAL(USE_LIBCAP, test x$capabilities = xlibcap)
index 7683da3..90993ad 100644 (file)
@@ -1,6 +1,7 @@
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/libstrongswan \
        -I$(top_srcdir)/src/libtncif \
+       -I$(top_srcdir)/src/libtpmtss \
        -DIPSEC_SCRIPT=\"${ipsec_script}\"
 
 ipseclib_LTLIBRARIES = libimcv.la
@@ -10,11 +11,8 @@ libimcv_la_LDFLAGS = \
 
 libimcv_la_LIBADD = \
        $(top_builddir)/src/libstrongswan/libstrongswan.la \
-       $(top_builddir)/src/libtncif/libtncif.la
-
-if USE_TROUSERS
-  libimcv_la_LIBADD += -ltspi
-endif
+       $(top_builddir)/src/libtncif/libtncif.la \
+       $(top_builddir)/src/libtpmtss/libtpmtss.la
 
 if USE_WINDOWS
   libimcv_la_LIBADD += -lws2_32
index 0e1bc15..a877211 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen
+ * Copyright (C) 2011-2012 Sansar Choinyambuu
+ * Copyright (C) 2011-2016 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -424,7 +425,7 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg,
                        pts_meas_algorithms_t comp_hash_algorithm;
                        pts_comp_evidence_t *evid;
                        chunk_t pcr_composite, quote_sig;
-                       bool use_quote2;
+                       bool use_quote2, use_version_info;
 
                        /* Send cached Component Evidence entries */
                        while (attestation_state->next_evidence(attestation_state, &evid))
@@ -434,16 +435,22 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg,
                        }
 
                        use_quote2 = lib->settings->get_bool(lib->settings,
-                                                       "%s.plugins.imc-attestation.use_quote2", TRUE,
-                                                       lib->ns);
-                       if (!pts->quote_tpm(pts, use_quote2, &pcr_composite, &quote_sig))
+                                                       "%s.plugins.imc-attestation.use_quote2",
+                                                       TRUE, lib->ns);
+                       use_version_info = lib->settings->get_bool(lib->settings,
+                                                       "%s.plugins.imc-attestation.use_version_info",
+                                                       FALSE, lib->ns);
+                       if (!pts->quote_tpm(pts, use_quote2, use_version_info,
+                                                               &pcr_composite, &quote_sig))
                        {
                                DBG1(DBG_IMC, "error occurred during TPM quote operation");
                                return FALSE;
                        }
 
                        /* Send Simple Evidence Final attribute */
-                       flags = use_quote2 ? PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 :
+                       flags = use_quote2 ? (use_version_info ?
+                                                                PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER :
+                                                                PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2) :
                                                                 PTS_SIMPLE_EVID_FINAL_QUOTE_INFO;
                        comp_hash_algorithm = PTS_MEAS_ALGO_SHA1;
 
index 91c12f3..89ba869 100644 (file)
@@ -217,7 +217,12 @@ static TNC_Result receive_msg(private_imv_attestation_agent_t *this,
                                                DBG1(DBG_IMV, "received TCG-PTS error '%N'",
                                                         pts_error_code_names, error_code.type);
                                                DBG1(DBG_IMV, "error information: %B", &msg_info);
-                                               fatal_error = TRUE;
+
+                                               /* TPM 2.0 doesn't return TPM Version Information */
+                                               if (error_code.type != TCG_PTS_TPM_VERS_NOT_SUPPORTED)
+                                               {
+                                                       fatal_error =  TRUE;
+                                               }
                                        }
                                        break;
                                }
index 8c22e94..a5a1a9b 100644 (file)
@@ -90,7 +90,7 @@ METHOD(pts_component_t, measure, status_t,
        extended_pcr = PCR_DEBUG;
        time(&measurement_time);
 
-       if (!pts->read_pcr(pts, extended_pcr, &pcr_after))
+       if (!pts->read_pcr(pts, extended_pcr, &pcr_after, HASH_SHA1))
        {
                DBG1(DBG_PTS, "error occurred while reading PCR: %d", extended_pcr);
                return FAILED;
index 3c53591..e21f2d5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2011-2012 Sansar Choinyambuu
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2012-2016 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
 #include <bio/bio_writer.h>
 #include <bio/bio_reader.h>
 
-#ifdef TSS_TROUSERS
-#ifdef _BASETSD_H_
-/* MinGW defines _BASETSD_H_, but TSS checks for _BASETSD_H */
-# define _BASETSD_H
-#endif
-#include <trousers/tss.h>
-#include <trousers/trousers.h>
-#else
-#ifndef TPM_TAG_QUOTE_INFO2
-#define TPM_TAG_QUOTE_INFO2 0x0036
-#endif
-#ifndef TPM_LOC_ZERO
-#define TPM_LOC_ZERO 0x01
-#endif
-#endif
+#include <tpm_tss.h>
+#include <tpm_tss_trousers.h>
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <errno.h>
 
+#ifndef TPM_TAG_QUOTE_INFO2
+#define TPM_TAG_QUOTE_INFO2 0x0036
+#endif
+#ifndef TPM_LOC_ZERO
+#define TPM_LOC_ZERO 0x01
+#endif
+
 typedef struct private_pts_t private_pts_t;
 
 /**
@@ -102,9 +96,9 @@ struct private_pts_t {
        bool is_imc;
 
        /**
-        * Do we have an activated TPM
+        * Active TPM
         */
-       bool has_tpm;
+       tpm_tss_t *tpm;
 
        /**
         * Contains a TPM_CAP_VERSION_INFO struct
@@ -112,14 +106,14 @@ struct private_pts_t {
        chunk_t tpm_version_info;
 
        /**
-        * Contains TSS Blob structure for AIK
+        * AIK object handle
         */
-       chunk_t aik_blob;
+       uint32_t aik_handle;
 
        /**
-        * Contains a Attestation Identity Key or Certificate
+        * Contains an Attestation Identity Key Certificate
         */
-       certificate_t *aik;
+       certificate_t *aik_cert;
 
        /**
         * Primary key referening AIK in database
@@ -191,7 +185,6 @@ METHOD(pts_t, set_dh_hash_algorithm, void,
        }
 }
 
-
 METHOD(pts_t, create_dh_nonce, bool,
        private_pts_t *this, pts_dh_group_t group, int nonce_len)
 {
@@ -306,41 +299,6 @@ METHOD(pts_t, calculate_secret, bool,
        return TRUE;
 }
 
-#ifdef TSS_TROUSERS
-
-/**
- * Print TPM 1.2 Version Info
- */
-static void print_tpm_version_info(private_pts_t *this)
-{
-       TPM_CAP_VERSION_INFO *info;
-
-       info = (TPM_CAP_VERSION_INFO*)this->tpm_version_info.ptr;
-
-       if (this->tpm_version_info.len >=
-                       sizeof(*info) - sizeof(info->vendorSpecific))
-       {
-               DBG2(DBG_PTS, "TPM Version Info: Chip Version: %u.%u.%u.%u, "
-                        "Spec Level: %u, Errata Rev: %u, Vendor ID: %.4s",
-                        info->version.major, info->version.minor,
-                        info->version.revMajor, info->version.revMinor,
-                        untoh16(&info->specLevel), info->errataRev, info->tpmVendorID);
-       }
-       else
-       {
-               DBG1(DBG_PTS, "could not parse tpm version info");
-       }
-}
-
-#else
-
-static void print_tpm_version_info(private_pts_t *this)
-{
-       DBG1(DBG_PTS, "unknown TPM version: no TSS implementation available");
-}
-
-#endif /* TSS_TROUSERS */
-
 METHOD(pts_t, get_platform_id, int,
        private_pts_t *this)
 {
@@ -356,104 +314,135 @@ METHOD(pts_t, set_platform_id, void,
 METHOD(pts_t, get_tpm_version_info, bool,
        private_pts_t *this, chunk_t *info)
 {
-       if (!this->has_tpm)
-       {
-               return FALSE;
-       }
-       *info = this->tpm_version_info;
-       print_tpm_version_info(this);
-       return TRUE;
+       *info = this->tpm ? this->tpm->get_version_info(this->tpm) :
+                                               this->tpm_version_info;
+       return info->len > 0;
 }
 
 METHOD(pts_t, set_tpm_version_info, void,
        private_pts_t *this, chunk_t info)
 {
        this->tpm_version_info = chunk_clone(info);
-       print_tpm_version_info(this);
-}
-
-/**
- * Load an AIK Blob (TSS_TSPATTRIB_KEYBLOB_BLOB attribute)
- */
-static void load_aik_blob(private_pts_t *this)
-{
-       char *path;
-       chunk_t *map;
-
-       path = lib->settings->get_str(lib->settings,
-                                               "%s.plugins.imc-attestation.aik_blob", NULL, lib->ns);
-       if (path)
-       {
-               map = chunk_map(path, FALSE);
-               if (map)
-               {
-                       DBG2(DBG_PTS, "loaded AIK Blob from '%s'", path);
-                       DBG3(DBG_PTS, "AIK Blob: %B", map);
-                       this->aik_blob = chunk_clone(*map);
-                       chunk_unmap(map);
-               }
-               else
-               {
-                       DBG1(DBG_PTS, "unable to map AIK Blob file '%s': %s",
-                                path, strerror(errno));
-               }
-       }
-       else
-       {
-               DBG1(DBG_PTS, "AIK Blob is not available");
-       }
+       /* print_tpm_version_info(this); */
 }
 
 /**
- * Load an AIK certificate or public key
+ * Load an AIK handle and an optional AIK certificate and
+ * in the case of a TPM 1.2 an AIK private key blob plus matching public key,
  * the certificate having precedence over the public key if both are present
  */
 static void load_aik(private_pts_t *this)
 {
-       char *cert_path, *key_path;
+       char *handle_str, *cert_path, *key_path, *blob_path;
+       chunk_t aik_pubkey = chunk_empty;
 
+       handle_str = lib->settings->get_str(lib->settings,
+                                               "%s.plugins.imc-attestation.aik_handle", NULL, lib->ns);
        cert_path = lib->settings->get_str(lib->settings,
                                                "%s.plugins.imc-attestation.aik_cert", NULL, lib->ns);
        key_path = lib->settings->get_str(lib->settings,
                                                "%s.plugins.imc-attestation.aik_pubkey", NULL, lib->ns);
+       blob_path = lib->settings->get_str(lib->settings,
+                                               "%s.plugins.imc-attestation.aik_blob", NULL, lib->ns);
 
+       if (handle_str)
+       {
+               this->aik_handle = strtoll(handle_str, NULL, 16);
+       }
        if (cert_path)
        {
-               this->aik = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+               this->aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
                                                                           CERT_X509, BUILD_FROM_FILE,
                                                                           cert_path, BUILD_END);
-               if (this->aik)
+               if (this->aik_cert)
                {
                        DBG2(DBG_PTS, "loaded AIK certificate from '%s'", cert_path);
-                       return;
                }
        }
-       if (key_path)
+
+       if (this->tpm->get_version(this->tpm) == TPM_VERSION_1_2)
        {
-               this->aik = lib->creds->create(lib->creds, CRED_CERTIFICATE,
-                                                                          CERT_TRUSTED_PUBKEY, BUILD_FROM_FILE,
-                                                                          key_path, BUILD_END);
-               if (this->aik)
+               tpm_tss_trousers_t *tpm_12;
+               chunk_t aik_blob = chunk_empty;
+               chunk_t *map;
+
+               /* get AIK private key blob */
+               if (blob_path)
+               {
+                       map = chunk_map(blob_path, FALSE);
+                       if (map)
+                       {
+                               DBG2(DBG_PTS, "loaded AIK Blob from '%s'", blob_path);
+                               DBG3(DBG_PTS, "AIK Blob: %B", map);
+                               aik_blob = chunk_clone(*map);
+                               chunk_unmap(map);
+                       }
+                       else
+                       {
+                               DBG1(DBG_PTS, "unable to map AIK Blob file '%s': %s",
+                                                          blob_path, strerror(errno));
+                       }
+               }
+               else
+               {
+                       DBG1(DBG_PTS, "AIK Blob is not available");
+               }
+
+               /* get AIK public key */
+               if (key_path)
+               {
+                       map = chunk_map(key_path, FALSE);
+                       if (map)
+                       {
+                               DBG2(DBG_PTS, "loaded AIK public key from '%s'", key_path);
+                               aik_pubkey = chunk_clone(*map);
+                               chunk_unmap(map);
+                       }
+                       else
+                       {
+                               DBG1(DBG_PTS, "unable to map AIK public key file '%s': %s",
+                                                          key_path, strerror(errno));
+                       }
+               }
+               else
                {
-                       DBG2(DBG_PTS, "loaded AIK public key from '%s'", key_path);
-                       return;
+                       DBG1(DBG_PTS, "AIK public key is not available");
                }
+
+               /* Load AIK item into TPM 1.2 object */
+               tpm_12 = (tpm_tss_trousers_t *)this->tpm;
+               tpm_12->load_aik(tpm_12, aik_blob, aik_pubkey, this->aik_handle);
        }
 
-       DBG1(DBG_PTS, "neither AIK certificate nor public key is available");
+       /* if no signed X.509 AIK certificate is available use public key instead */
+       if (!this->aik_cert)
+       {
+               aik_pubkey = this->tpm->get_public(this->tpm, this->aik_handle);
+               if (aik_pubkey.len > 0)
+               {
+                       this->aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+                                                                          CERT_TRUSTED_PUBKEY, BUILD_BLOB,
+                                                                          aik_pubkey, BUILD_END);
+                       chunk_free(&aik_pubkey);
+               }
+               else
+               {
+                       DBG1(DBG_PTS, "neither AIK certificate nor public key is available");
+               }
+       }
 }
 
 METHOD(pts_t, get_aik, certificate_t*,
        private_pts_t *this)
 {
-       return this->aik;
+       return this->aik_cert;
 }
 
 METHOD(pts_t, set_aik, void,
        private_pts_t *this, certificate_t *aik, int aik_id)
 {
-       DESTROY_IF(this->aik);
-       this->aik = aik->get_ref(aik);
+       DESTROY_IF(this->aik_cert);
+       this->aik_cert = aik->get_ref(aik);
        this->aik_id = aik_id;
 }
 
@@ -611,290 +600,61 @@ METHOD(pts_t, get_metadata, pts_file_meta_t*,
        return metadata;
 }
 
-
-#ifdef TSS_TROUSERS
-
 METHOD(pts_t, read_pcr, bool,
-       private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value)
+       private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value,
+       hash_algorithm_t alg)
 {
-       TSS_HCONTEXT hContext;
-       TSS_HTPM hTPM;
-       TSS_RESULT result;
-       BYTE *buf;
-       UINT32 len;
-
-       bool success = FALSE;
-
-       result = Tspi_Context_Create(&hContext);
-       if (result != TSS_SUCCESS)
-       {
-               DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", result);
-               return FALSE;
-       }
-
-       result = Tspi_Context_Connect(hContext, NULL);
-       if (result != TSS_SUCCESS)
-       {
-               goto err;
-       }
-       result = Tspi_Context_GetTpmObject (hContext, &hTPM);
-       if (result != TSS_SUCCESS)
-       {
-               goto err;
-       }
-       result = Tspi_TPM_PcrRead(hTPM, pcr_num, &len, &buf);
-       if (result != TSS_SUCCESS)
-       {
-               goto err;
-       }
-       *pcr_value = chunk_clone(chunk_create(buf, len));
-       DBG3(DBG_PTS, "PCR %d value:%B", pcr_num, pcr_value);
-       success = TRUE;
-
-err:
-       if (!success)
-       {
-               DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
-       }
-       Tspi_Context_FreeMemory(hContext, NULL);
-       Tspi_Context_Close(hContext);
-
-       return success;
+       return this->tpm ? this->tpm->read_pcr(this->tpm, pcr_num, pcr_value, alg)
+                                    : FALSE;
 }
 
 METHOD(pts_t, extend_pcr, bool,
-       private_pts_t *this, uint32_t pcr_num, chunk_t input, chunk_t *output)
+       private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value, chunk_t data,
+       hash_algorithm_t alg)
 {
-       TSS_HCONTEXT hContext;
-       TSS_HTPM hTPM;
-       TSS_RESULT result;
-       uint32_t pcr_length;
-       chunk_t pcr_value = chunk_empty;
-
-       result = Tspi_Context_Create(&hContext);
-       if (result != TSS_SUCCESS)
+       if (!this->tpm->extend_pcr(this->tpm, pcr_num, pcr_value, data, alg))
        {
-               DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
-                        result);
                return FALSE;
        }
-       result = Tspi_Context_Connect(hContext, NULL);
-       if (result != TSS_SUCCESS)
-       {
-               goto err;
-       }
-       result = Tspi_Context_GetTpmObject (hContext, &hTPM);
-       if (result != TSS_SUCCESS)
-       {
-               goto err;
-       }
-
-       pcr_value = chunk_alloc(PTS_PCR_LEN);
-       result = Tspi_TPM_PcrExtend(hTPM, pcr_num, PTS_PCR_LEN, input.ptr,
-                                                               NULL, &pcr_length, &pcr_value.ptr);
-       if (result != TSS_SUCCESS)
-       {
-               goto err;
-       }
-
-       *output = pcr_value;
-       *output = chunk_clone(*output);
-
-       DBG3(DBG_PTS, "PCR %d extended with:      %B", pcr_num, &input);
-       DBG3(DBG_PTS, "PCR %d value after extend: %B", pcr_num, output);
-
-       chunk_clear(&pcr_value);
-       Tspi_Context_FreeMemory(hContext, NULL);
-       Tspi_Context_Close(hContext);
+       DBG3(DBG_PTS, "PCR %d extended with:   %#B", pcr_num, &data);
+       DBG3(DBG_PTS, "PCR %d after extension: %#B", pcr_num, pcr_value);
 
        return TRUE;
-
-err:
-       DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
-
-       chunk_clear(&pcr_value);
-       Tspi_Context_FreeMemory(hContext, NULL);
-       Tspi_Context_Close(hContext);
-
-       return FALSE;
 }
 
 METHOD(pts_t, quote_tpm, bool,
-       private_pts_t *this, bool use_quote2, chunk_t *pcr_comp, chunk_t *quote_sig)
+       private_pts_t *this, bool use_quote2, bool use_version_info,
+       chunk_t *pcr_comp, chunk_t *quote_sig)
 {
-       TSS_HCONTEXT hContext;
-       TSS_HTPM hTPM;
-       TSS_HKEY hAIK;
-       TSS_HKEY hSRK;
-       TSS_HPOLICY srkUsagePolicy;
-       TSS_UUID SRK_UUID = TSS_UUID_SRK;
-       BYTE secret[] = TSS_WELL_KNOWN_SECRET;
-       TSS_HPCRS hPcrComposite;
-       TSS_VALIDATION valData;
-       TSS_RESULT result;
-       chunk_t quote_info;
-       BYTE* versionInfo;
-       uint32_t versionInfoSize, pcr;
+       chunk_t pcr_value;
+       uint32_t pcr, pcr_sel = 0;
        enumerator_t *enumerator;
-       bool success = FALSE;
+       tpm_quote_mode_t quote_mode;
 
-       result = Tspi_Context_Create(&hContext);
-       if (result != TSS_SUCCESS)
-       {
-               DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
-                        result);
-               return FALSE;
-       }
-       result = Tspi_Context_Connect(hContext, NULL);
-       if (result != TSS_SUCCESS)
-       {
-               goto err1;
-       }
-       result = Tspi_Context_GetTpmObject (hContext, &hTPM);
-       if (result != TSS_SUCCESS)
-       {
-               goto err1;
-       }
-
-       /* Retrieve SRK from TPM and set the authentication to well known secret*/
-       result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM,
-                                                                       SRK_UUID, &hSRK);
-       if (result != TSS_SUCCESS)
-       {
-               goto err1;
-       }
-
-       result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &srkUsagePolicy);
-       if (result != TSS_SUCCESS)
-       {
-               goto err1;
-       }
-       result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_SHA1,
-                                       20, secret);
-       if (result != TSS_SUCCESS)
-       {
-               goto err1;
-       }
-
-       result = Tspi_Context_LoadKeyByBlob (hContext, hSRK, this->aik_blob.len,
-                                                                                this->aik_blob.ptr, &hAIK);
-       if (result != TSS_SUCCESS)
-       {
-               goto err1;
-       }
-
-       /* Create PCR composite object */
-       result = use_quote2 ?
-                       Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS,
-                                                       TSS_PCRS_STRUCT_INFO_SHORT, &hPcrComposite) :
-                       Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS,
-                                                       TSS_PCRS_STRUCT_DEFAULT, &hPcrComposite);
-       if (result != TSS_SUCCESS)
-       {
-               goto err2;
-       }
-
-       /* Select PCRs */
+       /* select PCRs */
+       DBG2(DBG_PTS, "PCR values hashed into PCR Composite:");
        enumerator = this->pcrs->create_enumerator(this->pcrs);
        while (enumerator->enumerate(enumerator, &pcr))
        {
-               result = use_quote2 ?
-                               Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr,
-                                                                                       TSS_PCRS_DIRECTION_RELEASE) :
-                               Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcr);
-               if (result != TSS_SUCCESS)
+               if (this->tpm->read_pcr(this->tpm, pcr, &pcr_value, HASH_SHA1))
                {
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
+                       DBG2(DBG_PTS, "PCR %2d %#B", pcr, &pcr_value);
+                       chunk_free(&pcr_value);
+               };
 
-       if (result != TSS_SUCCESS)
-       {
-               goto err3;
+               /* add PCR to selection list */
+               pcr_sel |= (1 << pcr);
        }
+       enumerator->destroy(enumerator);
 
-       /* Set the Validation Data */
-       valData.ulExternalDataLength = this->secret.len;
-       valData.rgbExternalData = (BYTE *)this->secret.ptr;
-
+       quote_mode = use_quote2 ? (use_version_info ? TPM_QUOTE2_VERSION_INFO :
+                                                                                                 TPM_QUOTE2) : TPM_QUOTE;
 
        /* TPM Quote */
-       result = use_quote2 ?
-                       Tspi_TPM_Quote2(hTPM, hAIK, FALSE, hPcrComposite, &valData,
-                                                       &versionInfoSize, &versionInfo):
-                       Tspi_TPM_Quote(hTPM, hAIK, hPcrComposite, &valData);
-       if (result != TSS_SUCCESS)
-       {
-               goto err4;
-       }
-
-       /* Set output chunks */
-       *pcr_comp = chunk_alloc(HASH_SIZE_SHA1);
-
-       if (use_quote2)
-       {
-               /* TPM_Composite_Hash is last 20 bytes of TPM_Quote_Info2 structure */
-               memcpy(pcr_comp->ptr, valData.rgbData + valData.ulDataLength - HASH_SIZE_SHA1,
-                          HASH_SIZE_SHA1);
-       }
-       else
-       {
-               /* TPM_Composite_Hash is 8-28th bytes of TPM_Quote_Info structure */
-               memcpy(pcr_comp->ptr, valData.rgbData + 8, HASH_SIZE_SHA1);
-       }
-       DBG3(DBG_PTS, "Hash of PCR Composite: %#B", pcr_comp);
-
-       quote_info = chunk_create(valData.rgbData, valData.ulDataLength);
-       DBG3(DBG_PTS, "TPM Quote Info: %B",&quote_info);
-
-       *quote_sig = chunk_clone(chunk_create(valData.rgbValidationData,
-                                                                                  valData.ulValidationDataLength));
-       DBG3(DBG_PTS, "TPM Quote Signature: %B",quote_sig);
-
-       success = TRUE;
-
-       /* Cleanup */
-err4:
-       Tspi_Context_FreeMemory(hContext, NULL);
-
-err3:
-       Tspi_Context_CloseObject(hContext, hPcrComposite);
-
-err2:
-       Tspi_Context_CloseObject(hContext, hAIK);
-
-err1:
-       Tspi_Context_Close(hContext);
-       if (!success)
-       {
-               DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
-       }
-       return success;
+       return this->tpm->quote(this->tpm, this->aik_handle, pcr_sel, HASH_SHA1,
+                                                       this->secret, quote_mode, pcr_comp, quote_sig);
 }
 
-#else /* TSS_TROUSERS */
-
-METHOD(pts_t, read_pcr, bool,
-       private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value)
-{
-       return FALSE;
-}
-
-METHOD(pts_t, extend_pcr, bool,
-       private_pts_t *this, uint32_t pcr_num, chunk_t input, chunk_t *output)
-{
-       return FALSE;
-}
-
-METHOD(pts_t, quote_tpm, bool,
-       private_pts_t *this, bool use_quote2, chunk_t *pcr_comp, chunk_t *quote_sig)
-{
-       return FALSE;
-}
-
-#endif /* TSS_TROUSERS */
-
 /**
  * TPM_QUOTE_INFO structure:
  *     4 bytes of version
@@ -910,7 +670,7 @@ METHOD(pts_t, quote_tpm, bool,
  */
 
 METHOD(pts_t, get_quote_info, bool,
-       private_pts_t *this, bool use_quote2, bool use_ver_info,
+       private_pts_t *this, bool use_quote2, bool use_version_info,
        pts_meas_algorithms_t comp_hash_algo,
        chunk_t *out_pcr_comp, chunk_t *out_quote_info)
 {
@@ -930,7 +690,7 @@ METHOD(pts_t, get_quote_info, bool,
                                          "unable to construct TPM Quote Info");
                return FALSE;
        }
-       if (use_quote2 && use_ver_info && !this->tpm_version_info.ptr)
+       if (use_quote2 && use_version_info && !this->tpm_version_info.ptr)
        {
                DBG1(DBG_PTS, "TPM Version Information unavailable, ",
                                          "unable to construct TPM Quote Info2");
@@ -999,7 +759,7 @@ METHOD(pts_t, get_quote_info, bool,
                /* PCR Composite Hash */
                writer->write_data(writer, hash_pcr_comp);
 
-               if (use_ver_info)
+               if (use_version_info)
                {
                        /* TPM version Info */
                        writer->write_data(writer, this->tpm_version_info);
@@ -1034,24 +794,24 @@ METHOD(pts_t, get_quote_info, bool,
 METHOD(pts_t, verify_quote_signature, bool,
                                private_pts_t *this, chunk_t data, chunk_t signature)
 {
-       public_key_t *aik_pub_key;
+       public_key_t *aik_pubkey;
 
-       aik_pub_key = this->aik->get_public_key(this->aik);
-       if (!aik_pub_key)
+       aik_pubkey = this->aik_cert->get_public_key(this->aik_cert);
+       if (!aik_pubkey)
        {
                DBG1(DBG_PTS, "failed to get public key from AIK certificate");
                return FALSE;
        }
 
-       if (!aik_pub_key->verify(aik_pub_key, SIGN_RSA_EMSA_PKCS1_SHA1,
+       if (!aik_pubkey->verify(aik_pubkey, SIGN_RSA_EMSA_PKCS1_SHA1,
                data, signature))
        {
                DBG1(DBG_PTS, "signature verification failed for TPM Quote Info");
-               DESTROY_IF(aik_pub_key);
+               DESTROY_IF(aik_pubkey);
                return FALSE;
        }
 
-       aik_pub_key->destroy(aik_pub_key);
+       aik_pubkey->destroy(aik_pubkey);
        return TRUE;
 }
 
@@ -1064,78 +824,17 @@ METHOD(pts_t, get_pcrs, pts_pcr_t*,
 METHOD(pts_t, destroy, void,
        private_pts_t *this)
 {
+       DESTROY_IF(this->tpm);
        DESTROY_IF(this->pcrs);
-       DESTROY_IF(this->aik);
+       DESTROY_IF(this->aik_cert);
        DESTROY_IF(this->dh);
        free(this->initiator_nonce.ptr);
        free(this->responder_nonce.ptr);
        free(this->secret.ptr);
-       free(this->aik_blob.ptr);
        free(this->tpm_version_info.ptr);
        free(this);
 }
 
-
-#ifdef TSS_TROUSERS
-
-/**
- * Check for a TPM by querying for TPM Version Info
- */
-static bool has_tpm(private_pts_t *this)
-{
-       TSS_HCONTEXT hContext;
-       TSS_HTPM hTPM;
-       TSS_RESULT result;
-       uint32_t version_info_len;
-
-       result = Tspi_Context_Create(&hContext);
-       if (result != TSS_SUCCESS)
-       {
-               DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
-                        result);
-               return FALSE;
-       }
-       result = Tspi_Context_Connect(hContext, NULL);
-       if (result != TSS_SUCCESS)
-       {
-               goto err;
-       }
-       result = Tspi_Context_GetTpmObject (hContext, &hTPM);
-       if (result != TSS_SUCCESS)
-       {
-               goto err;
-       }
-       result = Tspi_TPM_GetCapability(hTPM, TSS_TPMCAP_VERSION_VAL,  0, NULL,
-                                                                       &version_info_len,
-                                                                       &this->tpm_version_info.ptr);
-       this->tpm_version_info.len = version_info_len;
-       if (result != TSS_SUCCESS)
-       {
-               goto err;
-       }
-       this->tpm_version_info = chunk_clone(this->tpm_version_info);
-
-       Tspi_Context_FreeMemory(hContext, NULL);
-       Tspi_Context_Close(hContext);
-       return TRUE;
-
-       err:
-       DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
-       Tspi_Context_FreeMemory(hContext, NULL);
-       Tspi_Context_Close(hContext);
-       return FALSE;
-}
-
-#else /* TSS_TROUSERS */
-
-static bool has_tpm(private_pts_t *this)
-{
-       return FALSE;
-}
-
-#endif /* TSS_TROUSERS */
-
-
 /**
  * See header
  */
@@ -1189,12 +888,11 @@ pts_t *pts_create(bool is_imc)
 
        if (is_imc)
        {
-               if (has_tpm(this))
+               this->tpm = tpm_tss_probe(TPM_VERSION_ANY);
+               if (this->tpm)
                {
-                       this->has_tpm = TRUE;
                        this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
                        load_aik(this);
-                       load_aik_blob(this);
                }
        }
        else
index 1e07c4b..ba9a87a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2011 Sansar Choinyambuu
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2012-2016 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -236,39 +236,41 @@ struct pts_t {
        pts_file_meta_t* (*get_metadata)(pts_t *this, char *pathname, bool is_dir);
 
        /**
-        * Reads given PCR value and returns it
-        * Expects owner secret to be WELL_KNOWN_SECRET
+        * Retrieve the current value of a PCR register in a given PCR bank
         *
-        * @param pcr_num                       Number of PCR to read
-        * @param pcr_value                     Chunk to save pcr read output
-        * @return                                      NULL in case of TSS error, PCR value otherwise
+        * @param pcr_num               PCR number
+        * @param pcr_value             PCR value returned
+        * @param alg                   hash algorithm, selects PCR bank (TPM 2.0 only)
+        * @return                              TRUE if PCR value retrieval succeeded
         */
-       bool (*read_pcr)(pts_t *this, uint32_t pcr_num, chunk_t *pcr_value);
+       bool (*read_pcr)(pts_t *this, uint32_t pcr_num, chunk_t *pcr_value,
+                                        hash_algorithm_t alg);
 
        /**
-        * Extends given PCR with given value
-        * Expects owner secret to be WELL_KNOWN_SECRET
+        * Extend a PCR register in a given PCR bank with a hash value
         *
-        * @param pcr_num                       Number of PCR to extend
-        * @param input                         Value to extend
-        * @param output                        Chunk to save PCR value after extension
-        * @return                                      FALSE in case of TSS error, TRUE otherwise
+        * @param pcr_num               PCR number
+        * @param pcr_value             extended PCR value returned
+        * @param hash                  data to be extended into the PCR
+        * @param alg                   hash algorithm, selects PCR bank (TPM 2.0 only)
+        * @return                              TRUE if PCR extension succeeded
         */
-       bool (*extend_pcr)(pts_t *this, uint32_t pcr_num, chunk_t input,
-                                          chunk_t *output);
+       bool (*extend_pcr)(pts_t *this, uint32_t pcr_num, chunk_t *pcr_value,
+                                          chunk_t data, hash_algorithm_t alg);
 
        /**
         * Quote over PCR's
         * Expects owner and SRK secret to be WELL_KNOWN_SECRET and no password set for AIK
         *
         * @param use_quote2            Version of the Quote function to be used
+        * @param use_version_info      Version info is concatenated to TPM_QUOTE_INFO2
         * @param pcr_comp                      Chunk to save PCR composite structure
         * @param quote_sig                     Chunk to save quote operation output
         *                                                      without external data (anti-replay protection)
         * @return                                      FALSE in case of TSS error, TRUE otherwise
         */
-        bool (*quote_tpm)(pts_t *this, bool use_quote2, chunk_t *pcr_comp,
-                                                                                                        chunk_t *quote_sig);
+        bool (*quote_tpm)(pts_t *this, bool use_quote2, bool use_version_info,
+                                          chunk_t *pcr_comp, chunk_t *quote_sig);
 
        /**
         * Get the shadow PCR set
@@ -281,13 +283,13 @@ struct pts_t {
         * Constructs and returns TPM Quote Info structure expected from IMC
         *
         * @param use_quote2            Version of the TPM_QUOTE_INFO to be constructed
-        * @param use_ver_info          Version info is concatenated to TPM_QUOTE_INFO2
+        * @param use_version_info      Version info is concatenated to TPM_QUOTE_INFO2
         * @param comp_hash_algo        Composite Hash Algorithm
         * @param pcr_comp                      Output variable to store PCR Composite
         * @param quote_info            Output variable to store TPM Quote Info
         * @return                                      FALSE in case of any error, TRUE otherwise
         */
-        bool (*get_quote_info)(pts_t *this, bool use_quote2, bool ver_info_included,
+        bool (*get_quote_info)(pts_t *this, bool use_quote2, bool use_version_info,
                                                        pts_meas_algorithms_t comp_hash_algo,
                                                        chunk_t *pcr_comp, chunk_t *quote_info);
 
index ad630e3..82cb4c6 100644 (file)
@@ -24,6 +24,7 @@
 #include <library.h>
 
 typedef enum tpm_version_t tpm_version_t;
+typedef enum tpm_quote_mode_t tpm_quote_mode_t;
 typedef struct tpm_tss_t tpm_tss_t;
 
 /**
@@ -36,6 +37,15 @@ enum tpm_version_t {
 };
 
 /**
+ * TPM Quote Modes
+ */
+enum tpm_quote_mode_t {
+       TPM_QUOTE,
+       TPM_QUOTE2,
+       TPM_QUOTE2_VERSION_INFO
+};
+
+/**
  * TPM access via TSS public interface
  */
 struct tpm_tss_t {
@@ -75,6 +85,45 @@ struct tpm_tss_t {
        chunk_t (*get_public)(tpm_tss_t *this, uint32_t handle);
 
        /**
+        * Retrieve the current value of a PCR register in a given PCR bank
+        *
+        * @param pcr_num               PCR number
+        * @param pcr_value             PCR value returned
+        * @param alg                   hash algorithm, selects PCR bank (TPM 2.0 only)
+        * @return                              TRUE if PCR value retrieval succeeded
+        */
+       bool (*read_pcr)(tpm_tss_t *this, uint32_t pcr_num, chunk_t *pcr_value,
+                                        hash_algorithm_t alg);
+
+       /**
+        * Extend a PCR register in a given PCR bank with a hash value
+        *
+        * @param pcr_num               PCR number
+        * @param pcr_value             extended PCR value returned
+        * @param hash                  data to be extended into the PCR
+        * @param alg                   hash algorithm, selects PCR bank (TPM 2.0 only)
+        * @return                              TRUE if PCR extension succeeded
+        */
+       bool (*extend_pcr)(tpm_tss_t *this, uint32_t pcr_num, chunk_t *pcr_value,
+                                          chunk_t data, hash_algorithm_t alg);
+
+       /**
+        * Do a quote signature over a selection of PCR registers
+        *
+        * @param aik_handle    object handle of AIK to be used for quote signature
+        * @param pcr_sel               selection of PCR registers
+        * @param alg                   hash algorithm to be used for quote signature
+        * @param data                  additional data to be hashed into the quote
+        * @param mode                  define current and legacy TPM quote modes
+        * @param pcr_comp              returns hash of PCR composite
+        * @param sig                   returns quote signature
+        * @return                              TRUE if quote signature succeeded
+        */
+       bool (*quote)(tpm_tss_t *this, uint32_t aik_handle, uint32_t pcr_sel,
+                                 hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t mode,
+                                 chunk_t *pcr_comp, chunk_t *quote_sig);
+
+       /**
         * Destroy a tpm_tss_t.
         */
        void (*destroy)(tpm_tss_t *this);
index 86e2027..7d39c04 100644 (file)
 
 #ifdef TSS_TROUSERS
 
+#ifdef _BASETSD_H_
+/* MinGW defines _BASETSD_H_, but TSS checks for _BASETSD_H */
+# define _BASETSD_H
+#endif
+
 #include <trousers/tss.h>
 #include <trousers/trousers.h>
 
 #define LABEL  "TPM 1.2 -"
 
 /* size in bytes of a TSS AIK public key blob */
-#define AIK_PUBKEY_BLOB_SIZE                   284
+#define AIK_PUBKEY_BLOB_SIZE           284
+
+/* maximum number of PCR registers */
+#define PCR_NUM_MAX                                    24
 
 typedef struct private_tpm_tss_trousers_t private_tpm_tss_trousers_t;
+typedef struct aik_t aik_t;
 
 /**
  * Private data of an tpm_tss_trousers_t object.
@@ -45,7 +54,7 @@ struct private_tpm_tss_trousers_t {
        /**
         * Public tpm_tss_trousers_t interface.
         */
-       tpm_tss_t public;
+       tpm_tss_trousers_t interface;
 
        /**
         * TSS context
@@ -53,12 +62,40 @@ struct private_tpm_tss_trousers_t {
        TSS_HCONTEXT hContext;
 
        /**
+        * TPM handle
+        */
+       TSS_HTPM hTPM;
+
+       /**
         * TPM version info
         */
        chunk_t version_info;
 
+       /**
+        * List of AIKs retrievable by an object handle
+        */
+       linked_list_t *aik_list;
+
 };
 
+struct aik_t {
+       /** AIK object handle */
+       uint32_t handle;
+
+       /** AIK private key blob */
+       chunk_t blob;
+
+       /** AIK public key */
+       chunk_t pubkey;
+};
+
+static void free_aik(aik_t *this)
+{
+       free(this->blob.ptr);
+       free(this->pubkey.ptr);
+       free(this);
+}
+
 /**
  * Initialize TSS context
  *
@@ -86,7 +123,6 @@ static bool initialize_context(private_tpm_tss_trousers_t *this)
        uint8_t *version_ptr;
        uint32_t version_len;
 
-       TSS_HTPM hTPM;
        TSS_RESULT result;
        TPM_CAP_VERSION_INFO *info;
 
@@ -106,7 +142,7 @@ static bool initialize_context(private_tpm_tss_trousers_t *this)
                return FALSE;
        }
 
-       result = Tspi_Context_GetTpmObject (this->hContext, &hTPM);
+       result = Tspi_Context_GetTpmObject (this->hContext, &this->hTPM);
        if (result != TSS_SUCCESS)
        {
                DBG1(DBG_PTS, "%s could not get TPM object: 0x%x",
@@ -114,8 +150,8 @@ static bool initialize_context(private_tpm_tss_trousers_t *this)
                return FALSE;
        }
 
-       result = Tspi_TPM_GetCapability(hTPM, TSS_TPMCAP_VERSION_VAL,  0, NULL,
-                                                                       &version_len, &version_ptr);
+       result = Tspi_TPM_GetCapability(this->hTPM, TSS_TPMCAP_VERSION_VAL,  0,
+                                                                       NULL, &version_len, &version_ptr);
        if (result != TSS_SUCCESS)
        {
                DBG1(DBG_PTS, "%s Tspi_TPM_GetCapability failed: 0x%x",
@@ -168,7 +204,6 @@ METHOD(tpm_tss_t, generate_aik, bool,
        chunk_t aik_exponent;
 
        TSS_RESULT   result;
-       TSS_HTPM     hTPM;
        TSS_HKEY     hSRK;
        TSS_HKEY     hPCAKey;
        TSS_HPOLICY  hSrkPolicy;
@@ -206,14 +241,14 @@ METHOD(tpm_tss_t, generate_aik, bool,
        }
 
        /* get TPM plus TPM policy and set TPM secret */
-       result = Tspi_Context_GetTpmObject (this->hContext, &hTPM);
+       result = Tspi_Context_GetTpmObject (this->hContext, &this->hTPM);
        if (result != TSS_SUCCESS)
        {
                DBG1(DBG_PTS, "%s Tspi_Context_GetTpmObject failed:  0x%x",
                                           LABEL, result);
                return FALSE;
        }
-       result = Tspi_GetPolicyObject(hTPM, TSS_POLICY_USAGE, &hTPMPolicy);
+       result = Tspi_GetPolicyObject(this->hTPM, TSS_POLICY_USAGE, &hTPMPolicy);
        if (result != TSS_SUCCESS)
        {
                DBG1(DBG_PTS, "%s Tspi_GetPolicyObject for TPM failed: 0x%x",
@@ -268,7 +303,7 @@ METHOD(tpm_tss_t, generate_aik, bool,
 
        /* generate AIK */
        DBG1(DBG_LIB, "Generating identity key...");
-       result = Tspi_TPM_CollateIdentityRequest(hTPM, hSRK, hPCAKey, 0, NULL,
+       result = Tspi_TPM_CollateIdentityRequest(this->hTPM, hSRK, hPCAKey, 0, NULL,
                                        hIdentKey, TSS_ALG_AES, &IdentityReqLen, &IdentityReq);
        if (result != TSS_SUCCESS)
        {
@@ -337,17 +372,240 @@ METHOD(tpm_tss_t, generate_aik, bool,
 METHOD(tpm_tss_t, get_public, chunk_t,
        private_tpm_tss_trousers_t *this, uint32_t handle)
 {
-       return chunk_empty;
+       enumerator_t *enumerator;
+       chunk_t aik_pubkey = chunk_empty;
+       aik_t *aik;
+
+       enumerator = this->aik_list->create_enumerator(this->aik_list);
+       while (enumerator->enumerate(enumerator, &aik))
+       {
+               if (aik->handle == handle)
+               {
+                       aik_pubkey = chunk_clone(aik->pubkey);
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       return aik_pubkey;
+}
+
+METHOD(tpm_tss_t, read_pcr, bool,
+       private_tpm_tss_trousers_t *this, uint32_t pcr_num, chunk_t *pcr_value,
+       hash_algorithm_t alg)
+{
+       TSS_RESULT result;
+       uint8_t *value;
+       uint32_t len;
+
+       result = Tspi_TPM_PcrRead(this->hTPM, pcr_num, &len, &value);
+       if (result != TSS_SUCCESS)
+       {
+               DBG1(DBG_PTS, "%s Tspi_TPM_PcrRead failed: 0x%x", LABEL, result);
+               return FALSE;
+       }
+       *pcr_value = chunk_clone(chunk_create(value, len));
+
+       return TRUE;
+}
+
+METHOD(tpm_tss_t, extend_pcr, bool,
+       private_tpm_tss_trousers_t *this, uint32_t pcr_num, chunk_t *pcr_value,
+       chunk_t data, hash_algorithm_t alg)
+{
+       TSS_RESULT result;
+       uint32_t pcr_len;
+       uint8_t *pcr_ptr;
+
+       result = Tspi_TPM_PcrExtend(this->hTPM, pcr_num, data.len, data.ptr,
+                                                               NULL, &pcr_len, &pcr_ptr);
+       if (result != TSS_SUCCESS)
+       {
+               DBG1(DBG_PTS, "%s Tspi_TPM_PcrExtend failed: 0x%x", LABEL, result);
+               return FALSE;
+       }
+       *pcr_value = chunk_clone(chunk_create(pcr_ptr, pcr_len));
+
+       return TRUE;
+}
+
+METHOD(tpm_tss_t, quote, bool,
+       private_tpm_tss_trousers_t *this, uint32_t aik_handle, uint32_t pcr_sel,
+       hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t mode, chunk_t *pcr_comp,
+       chunk_t *quote_sig)
+{
+       TSS_HKEY hAIK;
+       TSS_HKEY hSRK;
+       TSS_HPOLICY srkUsagePolicy;
+       TSS_UUID SRK_UUID = TSS_UUID_SRK;
+       TSS_HPCRS hPcrComposite;
+       TSS_VALIDATION valData;
+       TSS_RESULT result;
+       uint8_t secret[] = TSS_WELL_KNOWN_SECRET;
+       uint8_t *version_info, *comp_hash;
+       uint32_t version_info_size, pcr;
+       aik_t *aik;
+       chunk_t aik_blob = chunk_empty;
+       chunk_t quote_info;
+       enumerator_t *enumerator;
+       bool success = FALSE;
+
+       /* Retrieve SRK from TPM and set the authentication to well known secret*/
+       result = Tspi_Context_LoadKeyByUUID(this->hContext, TSS_PS_TYPE_SYSTEM,
+                                                                               SRK_UUID, &hSRK);
+       if (result != TSS_SUCCESS)
+       {
+               DBG1(DBG_PTS, "%s Tspi_Context_LoadKeyByUUID for SRK failed: 0x%x",
+                                          LABEL, result);
+               return FALSE;
+       }
+       result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &srkUsagePolicy);
+       if (result != TSS_SUCCESS)
+       {
+               DBG1(DBG_PTS, "%s Tspi_GetPolicyObject for SRK failed: 0x%x",
+                                          LABEL, result);
+               return FALSE;
+       }
+       result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_SHA1,
+                                       20, secret);
+       if (result != TSS_SUCCESS)
+       {
+               DBG1(DBG_PTS, "%s Tspi_Policy_SetSecret for SRK failed: 0x%x",
+                                          LABEL, result);
+               return FALSE;
+       }
+
+       /* Retrieve AIK using its handle and load private key into TPM 1.2 */
+       enumerator = this->aik_list->create_enumerator(this->aik_list);
+       while (enumerator->enumerate(enumerator, &aik))
+       {
+               if (aik->handle == aik_handle)
+               {
+                       aik_blob = aik->blob;
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (aik_blob.len == 0)
+       {
+               DBG1(DBG_PTS, "%s AIK private key for handle 0x%80x not found", LABEL);
+               return FALSE;
+       }
+       result = Tspi_Context_LoadKeyByBlob(this->hContext, hSRK, aik_blob.len,
+                                                                               aik_blob.ptr, &hAIK);
+       if (result != TSS_SUCCESS)
+       {
+               DBG1(DBG_PTS, "%s Tspi_Context_LoadKeyByBlob for AIK failed: 0x%x",
+                                          LABEL, result);
+               return FALSE;
+       }
+
+       /* Create PCR composite object */
+       result = Tspi_Context_CreateObject(this->hContext, TSS_OBJECT_TYPE_PCRS,
+                                       (mode == TPM_QUOTE) ? TSS_PCRS_STRUCT_INFO :
+                                                                                 TSS_PCRS_STRUCT_INFO_SHORT,
+                                       &hPcrComposite);
+       if (result != TSS_SUCCESS)
+       {
+               DBG1(DBG_PTS, "%s Tspi_Context_CreateObject for pcrComposite failed: "
+                                         "0x%x", LABEL, result);
+               goto err1;
+       }
+
+       /* Select PCRs */
+       for (pcr = 0; pcr < PCR_NUM_MAX; pcr++)
+       {
+               if (pcr_sel & (1 << pcr))
+               {
+                       result = (mode == TPM_QUOTE) ?
+                               Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcr) :
+                               Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr,
+                                                                               TSS_PCRS_DIRECTION_RELEASE);
+                       if (result != TSS_SUCCESS)
+                       {
+                               DBG1(DBG_PTS, "%s Tspi_PcrComposite_SelectPcrIndex failed: "
+                                                         "0x%x", LABEL, result);
+                               goto err2;
+                       }
+               }
+       }
+
+       /* Set the Validation Data */
+       valData.ulExternalDataLength = data.len;
+       valData.rgbExternalData      = data.ptr;
+
+       /* TPM Quote */
+       result = (mode == TPM_QUOTE) ?
+                       Tspi_TPM_Quote (this->hTPM, hAIK, hPcrComposite, &valData) :
+                       Tspi_TPM_Quote2(this->hTPM, hAIK, mode == TPM_QUOTE2_VERSION_INFO,
+                                                   hPcrComposite, &valData, &version_info_size,
+                                                       &version_info);
+       if (result != TSS_SUCCESS)
+       {
+               DBG1(DBG_PTS, "%s Tspi_TPM_Quote%s failed: 0x%x", LABEL,
+                                         (mode == TPM_QUOTE) ? "" : "2", result);
+               goto err2;
+       }
+
+       /* Extract TPM_Composite_Hash */
+       *pcr_comp = chunk_alloc(HASH_SIZE_SHA1);
+
+       if (mode == TPM_QUOTE)
+       {
+               /* TPM_Composite_Hash starts at byte 8 of TPM_Quote_Info structure */
+               comp_hash = valData.rgbData + 8;
+       }
+       else
+       {
+               /* TPM_Composite_Hash is last 20 bytes of TPM_Quote_Info2 structure */
+               comp_hash = valData.rgbData + valData.ulDataLength - version_info_size -
+                                       HASH_SIZE_SHA1;
+       }
+       memcpy(pcr_comp->ptr, comp_hash, HASH_SIZE_SHA1);
+       DBG3(DBG_PTS, "Hash of PCR Composite: %#B", pcr_comp);
+
+       quote_info = chunk_create(valData.rgbData, valData.ulDataLength);
+       DBG3(DBG_PTS, "TPM Quote Info: %B",&quote_info);
+
+       *quote_sig = chunk_clone(chunk_create(valData.rgbValidationData,
+                                                                                 valData.ulValidationDataLength));
+       DBG3(DBG_PTS, "TPM Quote Signature: %B",quote_sig);
+
+       success = TRUE;
+
+err2:
+       Tspi_Context_CloseObject(this->hContext, hPcrComposite);
+err1:
+       Tspi_Context_CloseObject(this->hContext, hAIK);
+
+       return success;
 }
 
 METHOD(tpm_tss_t, destroy, void,
        private_tpm_tss_trousers_t *this)
 {
        finalize_context(this);
+       this->aik_list->destroy_function(this->aik_list, (void*)free_aik);
        free(this->version_info.ptr);
        free(this);
 }
 
+METHOD(tpm_tss_trousers_t, load_aik, void,
+       private_tpm_tss_trousers_t *this, chunk_t blob, chunk_t pubkey,
+       uint32_t handle)
+{
+       aik_t *item;
+
+       INIT(item,
+               .handle = handle,
+               .blob = blob,
+               .pubkey = pubkey,
+       );
+
+       this->aik_list->insert_last(this->aik_list, item);
+}
+
 /**
  * See header
  */
@@ -357,13 +615,20 @@ tpm_tss_t *tpm_tss_trousers_create()
        bool available;
 
        INIT(this,
-               .public = {
-                       .get_version = _get_version,
-                       .get_version_info = _get_version_info,
-                       .generate_aik = _generate_aik,
-                       .get_public = _get_public,
-                       .destroy = _destroy,
+               .interface = {
+                       .public = {
+                               .get_version = _get_version,
+                               .get_version_info = _get_version_info,
+                               .generate_aik = _generate_aik,
+                               .get_public = _get_public,
+                               .read_pcr = _read_pcr,
+                               .quote = _quote,
+                               .extend_pcr = _extend_pcr,
+                               .destroy = _destroy,
+                       },
+                       .load_aik = _load_aik,
                },
+               .aik_list = linked_list_create(),
        );
 
        available = initialize_context(this);
@@ -374,7 +639,7 @@ tpm_tss_t *tpm_tss_trousers_create()
                destroy(this);
                return NULL;
        }
-       return &this->public;
+       return &this->interface.public;
 }
 
 #else /* TSS_TROUSERS */
index a52d73a..3afba0d 100644 (file)
 
 #include "tpm_tss.h"
 
+typedef struct tpm_tss_trousers_t tpm_tss_trousers_t;
+
+/**
+ * TPM 1.2 access via TrouSerS public interface
+ */
+struct tpm_tss_trousers_t {
+
+       tpm_tss_t public;
+
+       /**
+        * Load AIK public and private key pair and save it under an object handle
+        *
+        * @param blob          encrypted AIK private key
+        * @param pubkey        AIK public key
+        * @param handle        object handle under which the AIK key is stored
+        */
+       void (*load_aik)(tpm_tss_trousers_t *this, chunk_t blob, chunk_t pubkey,
+                                        uint32_t handle);
+
+};
+
 /**
  * Create a tpm_tss_trousers instance.
  */
index cefdd09..fbda203 100644 (file)
@@ -335,6 +335,31 @@ METHOD(tpm_tss_t, get_public, chunk_t,
        return aik_pubkey;
 }
 
+METHOD(tpm_tss_t, read_pcr, bool,
+       private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
+       hash_algorithm_t alg)
+{
+       /* TODO */
+       return FALSE;
+}
+
+METHOD(tpm_tss_t, extend_pcr, bool,
+       private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
+       chunk_t data, hash_algorithm_t alg)
+{
+       /* TODO */
+       return FALSE;
+}
+
+METHOD(tpm_tss_t, quote, bool,
+       private_tpm_tss_tss2_t *this, uint32_t aik_handle, uint32_t pcr_sel,
+       hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t mode, chunk_t *pcr_comp,
+       chunk_t *quote_sig)
+{
+       /* TODO */
+       return FALSE;
+}
+
 METHOD(tpm_tss_t, destroy, void,
        private_tpm_tss_tss2_t *this)
 {
@@ -356,6 +381,9 @@ tpm_tss_t *tpm_tss_tss2_create()
                        .get_version_info = _get_version_info,
                        .generate_aik = _generate_aik,
                        .get_public = _get_public,
+                       .read_pcr = _read_pcr,
+                       .extend_pcr = _extend_pcr,
+                       .quote = _quote,
                        .destroy = _destroy,
                },
        );