aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Steffen <andreas.steffen@strongswan.org>2016-06-26 18:40:01 +0200
committerAndreas Steffen <andreas.steffen@strongswan.org>2016-06-26 18:40:01 +0200
commit4b1513ed5973df0c05cd87009acd19dec78a2263 (patch)
tree1ecb249cd7d23120bf79a18b3a5d2fd8f4cd07a5
parent5a09734c2cabe419419496a36445be65f8791e10 (diff)
parentb03159364136de391f71046289ba7e08f687ddb7 (diff)
downloadstrongswan-4b1513ed5973df0c05cd87009acd19dec78a2263.tar.bz2
strongswan-4b1513ed5973df0c05cd87009acd19dec78a2263.tar.xz
Merge branch 'tpm2'
The libtpmtss library supports both TPM 1.2 and TPM 2.0 Trusted Platform Modules. Features comprise capability discovery, listing of PCRs, AIK generation and quote signatures.
-rw-r--r--conf/options/aikpub2.opt2
-rw-r--r--conf/plugins/imc-attestation.opt6
-rw-r--r--configure.ac31
-rw-r--r--src/Makefile.am8
-rw-r--r--src/aikgen/Makefile.am9
-rw-r--r--src/aikgen/aikgen.c216
-rw-r--r--src/aikpub2/.gitignore1
-rw-r--r--src/aikpub2/Makefile.am15
-rw-r--r--src/aikpub2/aikpub2.c305
-rw-r--r--src/checksum/Makefile.am5
-rw-r--r--src/libimcv/Makefile.am10
-rw-r--r--src/libimcv/plugins/imc_attestation/Makefile.am3
-rw-r--r--src/libimcv/plugins/imc_attestation/imc_attestation_process.c33
-rw-r--r--src/libimcv/plugins/imv_attestation/Makefile.am3
-rw-r--r--src/libimcv/plugins/imv_attestation/imv_attestation_agent.c7
-rw-r--r--src/libimcv/plugins/imv_attestation/imv_attestation_process.c37
-rw-r--r--src/libimcv/plugins/imv_hcd/Makefile.am1
-rw-r--r--src/libimcv/plugins/imv_os/Makefile.am3
-rw-r--r--src/libimcv/plugins/imv_scanner/Makefile.am3
-rw-r--r--src/libimcv/plugins/imv_swid/Makefile.am1
-rw-r--r--src/libimcv/pts/components/ita/ita_comp_tgrub.c2
-rw-r--r--src/libimcv/pts/components/pts_comp_func_name.c4
-rw-r--r--src/libimcv/pts/pts.c766
-rw-r--r--src/libimcv/pts/pts.h74
-rw-r--r--src/libimcv/pts/pts_meas_algo.c18
-rw-r--r--src/libimcv/pts/pts_meas_algo.h8
-rw-r--r--src/libimcv/pts/pts_pcr.c22
-rw-r--r--src/libimcv/pts/pts_pcr.h6
-rw-r--r--src/libimcv/pts/pts_simple_evid_final.h47
-rw-r--r--src/libimcv/tcg/pts/tcg_pts_attr_simple_evid_final.c241
-rw-r--r--src/libimcv/tcg/pts/tcg_pts_attr_simple_evid_final.h29
-rw-r--r--src/libpttls/pt_tls.c1
-rw-r--r--src/libtpmtss/Makefile.am25
-rw-r--r--src/libtpmtss/tpm_tss.c54
-rw-r--r--src/libtpmtss/tpm_tss.h138
-rw-r--r--src/libtpmtss/tpm_tss_quote_info.c330
-rw-r--r--src/libtpmtss/tpm_tss_quote_info.h151
-rw-r--r--src/libtpmtss/tpm_tss_trousers.c655
-rw-r--r--src/libtpmtss/tpm_tss_trousers.h52
-rw-r--r--src/libtpmtss/tpm_tss_tss2.c696
-rw-r--r--src/libtpmtss/tpm_tss_tss2.h31
-rw-r--r--src/libtpmtss/tpm_tss_tss2_names.c123
-rw-r--r--src/libtpmtss/tpm_tss_tss2_names.h30
43 files changed, 3198 insertions, 1004 deletions
diff --git a/conf/options/aikpub2.opt b/conf/options/aikpub2.opt
new file mode 100644
index 000000000..6a755d211
--- /dev/null
+++ b/conf/options/aikpub2.opt
@@ -0,0 +1,2 @@
+aikpub2.load =
+ Plugins to load in aikpub2 tool.
diff --git a/conf/plugins/imc-attestation.opt b/conf/plugins/imc-attestation.opt
index 7a40bc962..925ac4eaf 100644
--- a/conf/plugins/imc-attestation.opt
+++ b/conf/plugins/imc-attestation.opt
@@ -7,6 +7,9 @@ libimcv.plugins.imc-attestation.aik_cert =
libimcv.plugins.imc-attestation.aik_pubkey =
AIK public key file.
+libimcv.plugins.imc-attestation.aik_handle =
+ AIK object handle.
+
libimcv.plugins.imc-attestation.mandatory_dh_groups = yes
Enforce mandatory Diffie-Hellman groups.
@@ -16,6 +19,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.
diff --git a/configure.ac b/configure.ac
index 3c6132e5f..7f897c60f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,8 @@
#
# Copyright (C) 2007-2015 Tobias Brunner
-# Copyright (C) 2006-2015 Andreas Steffen
+# Copyright (C) 2006-2016 Andreas Steffen
# Copyright (C) 2006-2014 Martin Willi
-# Hochschule fuer Technik Rapperswil
+# HSR Hochschule fuer Technik Rapperswil
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
@@ -62,8 +62,6 @@ ARG_WITH_SUBST([routing-table], [220], [set routing table to use for IPsec
ARG_WITH_SUBST([routing-table-prio], [220], [set priority for IPsec routing table])
ARG_WITH_SUBST([ipsec-script], [ipsec], [change the name of the ipsec script])
ARG_WITH_SUBST([fips-mode], [0], [set openssl FIPS mode: disabled(0), enabled(1), Suite B enabled(2)])
-
-ARG_WITH_SET([tss], [no], [set implementation of the Trusted Computing Group's Software Stack (TSS). Currently the only supported value is "trousers"])
ARG_WITH_SET([capabilities], [no], [set capability dropping library. Currently supported values are "libcap" and "native"])
ARG_WITH_SET([mpz_powm_sec], [yes], [use the more side-channel resistant mpz_powm_sec in libgmp, if available])
ARG_WITH_SET([dev-headers], [no], [install strongSwan development headers to directory.])
@@ -269,7 +267,8 @@ ARG_ENABL_SET([systime-fix], [enable plugin to handle cert lifetimes with inv
ARG_ENABL_SET([test-vectors], [enable plugin providing crypto test vectors.])
ARG_DISBL_SET([updown], [disable updown firewall script plugin.])
# programs/components
-ARG_ENABL_SET([aikgen], [enable AIK generator.])
+ARG_ENABL_SET([aikgen], [enable AIK generator for TPM 1.2.])
+ARG_ENABL_SET([aikpub2], [enable AIK extractor for TPM 2.0.])
ARG_DISBL_SET([charon], [disable the IKEv1/IKEv2 keying daemon charon.])
ARG_ENABL_SET([cmd], [enable the command line IKE client charon-cmd.])
ARG_ENABL_SET([conftest], [enforce Suite B conformance test framework.])
@@ -302,6 +301,9 @@ ARG_ENABL_SET([python-eggs], [enable build of provided python eggs.])
ARG_ENABL_SET([python-eggs-install],[enable installation of provided python eggs.])
ARG_ENABL_SET([perl-cpan], [enable build of provided perl CPAN module.])
ARG_ENABL_SET([perl-cpan-install],[enable installation of provided CPAN module.])
+ARG_ENABL_SET([tss-trousers], [enable the use of the TrouSerS Trusted Software Stack])
+ARG_ENABL_SET([tss-tss2], [enable the use of the TSS 2.0 Trusted Software Stack])
+
# compile options
ARG_ENABL_SET([coverage], [enable lcov coverage report generation.])
ARG_ENABL_SET([leak-detective], [enable malloc hooks to find memory leaks.])
@@ -960,12 +962,17 @@ if test x$systemd = xtrue; then
)
fi
-if test x$tss = xtrousers; then
+if test x$tss_trousers = xtrue; then
AC_CHECK_LIB([tspi],[main],[LIBS="$LIBS"],[AC_MSG_ERROR([TrouSerS library libtspi not found])],[])
AC_CHECK_HEADER([trousers/tss.h],,[AC_MSG_ERROR([TrouSerS header trousers/tss.h not found!])])
- AC_DEFINE([TSS_TROUSERS], [], [use TrouSerS library libtspi as TSS implementation])
+ AC_DEFINE([TSS_TROUSERS], [], [use TrouSerS library libtspi])
fi
+if test x$tss_tss2 = xtrue; then
+ AC_CHECK_LIB([tss2],[main],[LIBS="$LIBS"],[AC_MSG_ERROR([TTS 2.0 library libtss2 not found])],[])
+ AC_CHECK_HEADER([tss2/tpm20.h],,[AC_MSG_ERROR([TSS 2.0 header tss2/tpm20.h not found!])])
+ AC_DEFINE([TSS_TSS2], [], [use TSS 2.0 library libtss2])
+fi
if test x$imv_swid = xtrue; then
PKG_CHECK_MODULES(json, [json-c], [],
[PKG_CHECK_MODULES(json, [json])])
@@ -1611,12 +1618,13 @@ AM_CONDITIONAL(USE_PKI, test x$pki = xtrue)
AM_CONDITIONAL(USE_SCEPCLIENT, test x$scepclient = xtrue)
AM_CONDITIONAL(USE_SCRIPTS, test x$scripts = xtrue)
AM_CONDITIONAL(USE_CONFTEST, test x$conftest = xtrue)
-AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$pki = xtrue -o x$scepclient = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$tls = xtrue -o x$tnc_tnccs = xtrue -o x$aikgen = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
+AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$pki = xtrue -o x$scepclient = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$tls = xtrue -o x$tnc_tnccs = xtrue -o x$aikgen = xtrue -o x$aikpub2 = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
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 -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)
@@ -1626,7 +1634,8 @@ AM_CONDITIONAL(USE_SIMAKA, test x$simaka = xtrue)
AM_CONDITIONAL(USE_TLS, test x$tls = xtrue)
AM_CONDITIONAL(USE_RADIUS, test x$radius = xtrue)
AM_CONDITIONAL(USE_IMCV, test x$imcv = xtrue)
-AM_CONDITIONAL(USE_TROUSERS, test x$tss = xtrousers -o x$aikgen = xtrue)
+AM_CONDITIONAL(USE_TROUSERS, test x$tss_trousers = xtrue -o x$aikgen = xtrue)
+AM_CONDITIONAL(USE_TSS2, test x$tss_tss2 = xtrue -o x$aikpub2 = xtrue)
AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue)
AM_CONDITIONAL(USE_SILENT_RULES, test x$enable_silent_rules = xyes)
AM_CONDITIONAL(COVERAGE, test x$coverage = xtrue)
@@ -1634,6 +1643,7 @@ AM_CONDITIONAL(USE_DBGHELP, test x$dbghelp_backtraces = xtrue)
AM_CONDITIONAL(USE_TKM, test x$tkm = xtrue)
AM_CONDITIONAL(USE_CMD, test x$cmd = xtrue)
AM_CONDITIONAL(USE_AIKGEN, test x$aikgen = xtrue)
+AM_CONDITIONAL(USE_AIKPUB2, test x$aikpub2 = xtrue)
AM_CONDITIONAL(USE_SWANCTL, test x$swanctl = xtrue)
AM_CONDITIONAL(USE_SVC, test x$svc = xtrue)
AM_CONDITIONAL(USE_SYSTEMD, test x$systemd = xtrue)
@@ -1673,6 +1683,7 @@ fi
strongswan_options=
AM_COND_IF([USE_AIKGEN], [strongswan_options=${strongswan_options}" aikgen"])
+AM_COND_IF([USE_AIKPUB2], [strongswan_options=${strongswan_options}" aikpub2"])
AM_COND_IF([USE_ATTR_SQL], [strongswan_options=${strongswan_options}" pool"])
AM_COND_IF([USE_CHARON], [strongswan_options=${strongswan_options}" charon charon-logging"])
AM_COND_IF([USE_FILE_CONFIG], [strongswan_options=${strongswan_options}" starter"])
@@ -1865,6 +1876,7 @@ AC_CONFIG_FILES([
src/libcharon/plugins/attr/Makefile
src/libcharon/plugins/attr_sql/Makefile
src/libcharon/tests/Makefile
+ src/libtpmtss/Makefile
src/stroke/Makefile
src/ipsec/Makefile
src/starter/Makefile
@@ -1873,6 +1885,7 @@ AC_CONFIG_FILES([
src/_copyright/Makefile
src/scepclient/Makefile
src/aikgen/Makefile
+ src/aikpub2/Makefile
src/pki/Makefile
src/pki/man/Makefile
src/pool/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index a9df10cc6..938335e78 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,6 +32,10 @@ if USE_LIBPTTLS
SUBDIRS += libpttls
endif
+if USE_LIBTPMTSS
+ SUBDIRS += libtpmtss
+endif
+
if USE_IMCV
SUBDIRS += libimcv
endif
@@ -131,3 +135,7 @@ endif
if USE_AIKGEN
SUBDIRS += aikgen
endif
+
+if USE_AIKPUB2
+ SUBDIRS += aikpub2
+endif
diff --git a/src/aikgen/Makefile.am b/src/aikgen/Makefile.am
index dc59d20cf..860a8f7a6 100644
--- a/src/aikgen/Makefile.am
+++ b/src/aikgen/Makefile.am
@@ -2,14 +2,13 @@ bin_PROGRAMS = aikgen
aikgen_SOURCES = aikgen.c
-aikgen_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
-aikgen.o : $(top_builddir)/config.status
+aikgen_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \
+ $(top_builddir)/src/libtpmtss/libtpmtss.la
-if USE_TROUSERS
- aikgen_LDADD += -ltspi
-endif
+aikgen.o : $(top_builddir)/config.status
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libtpmtss \
-DIPSEC_CONFDIR=\"${sysconfdir}\" \
-DPLUGINS=\""${aikgen_plugins}\""
diff --git a/src/aikgen/aikgen.c b/src/aikgen/aikgen.c
index 192636afc..22e80badb 100644
--- a/src/aikgen/aikgen.c
+++ b/src/aikgen/aikgen.c
@@ -1,38 +1,25 @@
/*
- * Copyright (C) 2014 Andreas Steffen
+ * Copyright (C) 2014-2016 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
- * Copyright (c) 2008 Hal Finney
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
*/
+#include "tpm_tss.h"
+
#include <library.h>
#include <utils/debug.h>
#include <utils/optionsfrom.h>
#include <credentials/certificates/x509.h>
#include <credentials/keys/public_key.h>
-#include <asn1/oid.h>
-#include <asn1/asn1.h>
-
-#include <trousers/tss.h>
-#include <trousers/trousers.h>
#include <syslog.h>
#include <getopt.h>
@@ -44,12 +31,9 @@
/* default name of AIK private key blob */
#define DEFAULT_FILENAME_AIKBLOB AIK_DIR "aikBlob.bin"
-/* default name of AIK private key blob */
+/* default name of AIK public key */
#define DEFAULT_FILENAME_AIKPUBKEY AIK_DIR "aikPub.der"
-/* size in bytes of a TSS AIK public key blob */
-#define AIK_PUBKEY_BLOB_SIZE 284
-
/* logging */
static bool log_to_stderr = TRUE;
static bool log_to_syslog = TRUE;
@@ -64,9 +48,7 @@ public_key_t *ca_pubkey;
chunk_t ca_modulus;
chunk_t aik_pubkey;
chunk_t aik_keyid;
-
-/* TPM context */
-TSS_HCONTEXT hContext;
+tpm_tss_t *tpm;
/**
* logging function for aikgen
@@ -128,12 +110,13 @@ static void init_log(const char *program)
/**
* @brief exit aikgen
*
- * @param status 0 = OK, 1 = general discomfort
+ * @param status 0 = OK, -1 = general discomfort
*/
static void exit_aikgen(err_t message, ...)
{
int status = 0;
+ DESTROY_IF(tpm);
DESTROY_IF(cacert);
DESTROY_IF(ca_pubkey);
free(ca_modulus.ptr);
@@ -141,13 +124,6 @@ static void exit_aikgen(err_t message, ...)
free(aik_keyid.ptr);
options->destroy(options);
- /* clean up TPM context */
- if (hContext)
- {
- Tspi_Context_FreeMemory(hContext, NULL);
- Tspi_Context_Close(hContext);
- }
-
/* print any error message to stderr */
if (message != NULL && *message != '\0')
{
@@ -158,7 +134,7 @@ static void exit_aikgen(err_t message, ...)
vsnprintf(m, sizeof(m), message, args);
va_end(args);
- fprintf(stderr, "error: %s\n", m);
+ fprintf(stderr, "aikgen error: %s\n", m);
status = -1;
}
library_deinit();
@@ -178,7 +154,7 @@ static void usage(const char *message)
" [--aikblob <filename>] [--aikpubkey <filename>] \n"
" [--idreq <filename>] [--force]"
" [--quiet] [--debug <level>]\n"
- " aikgen --help\n"
+ " aikgen --help\n"
"\n"
"Options:\n"
" --cacert (-c) certificate of [privacy] CA\n"
@@ -216,25 +192,9 @@ int main(int argc, char *argv[])
bool force = FALSE;
chunk_t identity_req;
chunk_t aik_blob;
- chunk_t aik_pubkey_blob;
chunk_t aik_modulus;
chunk_t aik_exponent;
- /* TPM variables */
- TSS_RESULT result;
- TSS_HTPM hTPM;
- TSS_HKEY hSRK;
- TSS_HKEY hPCAKey;
- TSS_HPOLICY hSrkPolicy;
- TSS_HPOLICY hTPMPolicy;
- TSS_HKEY hIdentKey;
- TSS_UUID SRK_UUID = TSS_UUID_SRK;
- BYTE secret[] = TSS_WELL_KNOWN_SECRET;
- BYTE *IdentityReq;
- UINT32 IdentityReqLen;
- BYTE *blob;
- UINT32 blobLen;
-
atexit(library_deinit);
if (!library_init(NULL, "aikgen"))
{
@@ -370,105 +330,29 @@ int main(int argc, char *argv[])
if (ca_pubkey->get_type(ca_pubkey) != KEY_RSA ||
ca_pubkey->get_keysize(ca_pubkey) != 2048)
{
- exit_aikgen("ca public key must be RSA 2048 but is %N %d",
+ exit_aikgen("CA public key must be RSA 2048 but is %N %d",
key_type_names, ca_pubkey->get_type(ca_pubkey),
ca_pubkey->get_keysize(ca_pubkey));
}
if (!ca_pubkey->get_encoding(ca_pubkey, PUBKEY_RSA_MODULUS, &ca_modulus))
{
- exit_aikgen("could not extract RSA modulus from ca public key");
- }
-
- /* initialize TSS context and connect to it */
- result = Tspi_Context_Create(&hContext);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_Context_Create", result);
- }
- result = Tspi_Context_Connect(hContext, NULL);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_Context_Connect", result);
- }
-
- /* get SRK plus SRK policy and set SRK secret */
- result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM,
- SRK_UUID, &hSRK);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_Context_LoadKeyByUUID for SRK", result);
- }
- result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &hSrkPolicy);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_GetPolicyObject for SRK", result);
- }
- result = Tspi_Policy_SetSecret(hSrkPolicy, TSS_SECRET_MODE_SHA1, 20, secret);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_Policy_SetSecret for SRK", result);
- }
-
- /* get TPM plus TPM policy and set TPM secret */
- result = Tspi_Context_GetTpmObject (hContext, &hTPM);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_Context_GetTpmObject", result);
- }
- result = Tspi_GetPolicyObject(hTPM, TSS_POLICY_USAGE, &hTPMPolicy);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_GetPolicyObject for TPM", result);
- }
- result = Tspi_Policy_SetSecret(hTPMPolicy, TSS_SECRET_MODE_SHA1, 20, secret);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_Policy_SetSecret for TPM", result);
+ exit_aikgen("could not extract RSA modulus from CA public key");
}
- /* create context for a 2048 bit AIK */
- result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY,
- TSS_KEY_TYPE_IDENTITY | TSS_KEY_SIZE_2048 |
- TSS_KEY_VOLATILE | TSS_KEY_NOT_MIGRATABLE, &hIdentKey);
- if (result != TSS_SUCCESS)
+ /* try to find a TPM 1.2 */
+ tpm = tpm_tss_probe(TPM_VERSION_1_2);
+ if (!tpm)
{
- exit_aikgen("tss 0x%x on Tspi_Context_CreateObject for key", result);
+ exit_aikgen("no TPM 1.2 found");
}
- /* create context for the Privacy CA public key and assign modulus */
- result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY,
- TSS_KEY_TYPE_LEGACY|TSS_KEY_SIZE_2048, &hPCAKey);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_Context_CreateObject for PCA", result);
- }
- result = Tspi_SetAttribData (hPCAKey, TSS_TSPATTRIB_RSAKEY_INFO,
- TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, ca_modulus.len,
- ca_modulus.ptr);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_SetAttribData for PCA modulus", result);
- }
- result = Tspi_SetAttribUint32(hPCAKey, TSS_TSPATTRIB_KEY_INFO,
- TSS_TSPATTRIB_KEYINFO_ENCSCHEME, TSS_ES_RSAESPKCSV15);
- if (result != TSS_SUCCESS)
+ if (!tpm->generate_aik(tpm, ca_modulus, &aik_blob, &aik_pubkey,
+ &identity_req))
{
- exit_aikgen("tss 0x%x on Tspi_SetAttribUint32 for PCA "
- "encryption scheme", result);
+ exit_aikgen("could not generate AIK");
}
- /* generate AIK */
- DBG1(DBG_LIB, "Generating identity key...");
- result = Tspi_TPM_CollateIdentityRequest(hTPM, hSRK, hPCAKey, 0, NULL,
- hIdentKey, TSS_ALG_AES, &IdentityReqLen, &IdentityReq);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_TPM_CollateIdentityRequest", result);
- }
- identity_req = chunk_create(IdentityReq, IdentityReqLen);
- DBG3(DBG_LIB, "Identity Request: %B", &identity_req);
-
- /* optionally output identity request encrypted with ca public key */
+ /* optionally output identity request encrypted with CA public key */
if (idreq_filename)
{
if (!chunk_write(identity_req, idreq_filename, 0022, force))
@@ -480,24 +364,7 @@ int main(int argc, char *argv[])
idreq_filename, identity_req.len);
}
- /* load identity key */
- result = Tspi_Key_LoadKey (hIdentKey, hSRK);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_Key_LoadKey for AIK\n", result);
- }
-
- /* output AIK private key in TSS blob format */
- result = Tspi_GetAttribData (hIdentKey, TSS_TSPATTRIB_KEY_BLOB,
- TSS_TSPATTRIB_KEYBLOB_BLOB, &blobLen, &blob);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_GetAttribData for private key blob",
- result);
- }
- aik_blob = chunk_create(blob, blobLen);
- DBG3(DBG_LIB, "AIK private key blob: %B", &aik_blob);
-
+ /* output AIK private key blob */
if (!chunk_write(aik_blob, aikblob_filename, 0022, force))
{
exit_aikgen("could not write AIK blob file '%s': %s",
@@ -506,32 +373,7 @@ int main(int argc, char *argv[])
DBG1(DBG_LIB, "AIK private key blob written to '%s' (%u bytes)",
aikblob_filename, aik_blob.len);
- /* output AIK Public Key in TSS blob format */
- result = Tspi_GetAttribData (hIdentKey, TSS_TSPATTRIB_KEY_BLOB,
- TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, &blobLen, &blob);
- if (result != TSS_SUCCESS)
- {
- exit_aikgen("tss 0x%x on Tspi_GetAttribData for public key blob",
- result);
- }
- aik_pubkey_blob = chunk_create(blob, blobLen);
- DBG3(DBG_LIB, "AIK public key blob: %B", &aik_pubkey_blob);
-
- /* create a trusted AIK public key */
- if (aik_pubkey_blob.len != AIK_PUBKEY_BLOB_SIZE)
- {
- exit_aikgen("AIK public key is not in TSS blob format");
- }
- aik_modulus = chunk_skip(aik_pubkey_blob, AIK_PUBKEY_BLOB_SIZE - 256);
- aik_exponent = chunk_from_chars(0x01, 0x00, 0x01);
-
- /* output subjectPublicKeyInfo encoding of AIK public key */
- if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER, NULL,
- &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus,
- CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
- {
- exit_aikgen("subjectPublicKeyInfo encoding of AIK key failed");
- }
+ /* output AIK public key */
if (!chunk_write(aik_pubkey, aikpubkey_filename, 0022, force))
{
exit_aikgen("could not write AIK public key file '%s': %s",
diff --git a/src/aikpub2/.gitignore b/src/aikpub2/.gitignore
new file mode 100644
index 000000000..42b5e265b
--- /dev/null
+++ b/src/aikpub2/.gitignore
@@ -0,0 +1 @@
+aikpub2
diff --git a/src/aikpub2/Makefile.am b/src/aikpub2/Makefile.am
new file mode 100644
index 000000000..a9ab13870
--- /dev/null
+++ b/src/aikpub2/Makefile.am
@@ -0,0 +1,15 @@
+bin_PROGRAMS = aikpub2
+
+aikpub2_SOURCES = aikpub2.c
+
+aikpub2_LDADD = \
+ $(top_builddir)/src/libstrongswan/libstrongswan.la \
+ $(top_builddir)/src/libtpmtss/libtpmtss.la
+
+aikpub2.o : $(top_builddir)/config.status
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libtpmtss \
+ -DIPSEC_CONFDIR=\"${sysconfdir}\" \
+ -DPLUGINS=\""${aikgen_plugins}\""
diff --git a/src/aikpub2/aikpub2.c b/src/aikpub2/aikpub2.c
new file mode 100644
index 000000000..fea58ed27
--- /dev/null
+++ b/src/aikpub2/aikpub2.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "tpm_tss.h"
+
+#include <library.h>
+#include <utils/debug.h>
+#include <utils/optionsfrom.h>
+
+#include <syslog.h>
+#include <getopt.h>
+#include <errno.h>
+
+/* default directory where AIK keys are stored */
+#define AIK_DIR IPSEC_CONFDIR "/pts/"
+
+/* default name of AIK public key blob */
+#define DEFAULT_FILENAME_AIKPUBKEY AIK_DIR "aikPub.der"
+
+/* logging */
+static bool log_to_stderr = TRUE;
+static bool log_to_syslog = TRUE;
+static level_t default_loglevel = 1;
+
+/* options read by optionsfrom */
+options_t *options;
+
+chunk_t aik_pubkey;
+chunk_t aik_keyid;
+
+/**
+ * logging function for aikpub2
+ */
+static void aikpub2_dbg(debug_t group, level_t level, char *fmt, ...)
+{
+ char buffer[8192];
+ char *current = buffer, *next;
+ va_list args;
+
+ if (level <= default_loglevel)
+ {
+ if (log_to_stderr)
+ {
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ }
+ if (log_to_syslog)
+ {
+ /* write in memory buffer first */
+ va_start(args, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, args);
+ va_end(args);
+
+ /* do a syslog with every line */
+ while (current)
+ {
+ next = strchr(current, '\n');
+ if (next)
+ {
+ *(next++) = '\0';
+ }
+ syslog(LOG_INFO, "%s\n", current);
+ current = next;
+ }
+ }
+ }
+}
+
+/**
+ * Initialize logging to stderr/syslog
+ */
+static void init_log(const char *program)
+{
+ dbg = aikpub2_dbg;
+
+ if (log_to_stderr)
+ {
+ setbuf(stderr, NULL);
+ }
+ if (log_to_syslog)
+ {
+ openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
+ }
+}
+
+/**
+ * @brief exit aikgen
+ *
+ * @param status 0 = OK, -1 = general discomfort
+ */
+static void exit_aikpub2(err_t message, ...)
+{
+ int status = 0;
+
+ free(aik_pubkey.ptr);
+ free(aik_keyid.ptr);
+ options->destroy(options);
+
+ /* print any error message to stderr */
+ if (message != NULL && *message != '\0')
+ {
+ va_list args;
+ char m[8192];
+
+ va_start(args, message);
+ vsnprintf(m, sizeof(m), message, args);
+ va_end(args);
+
+ fprintf(stderr, "aikpub2 error: %s\n", m);
+ status = -1;
+ }
+ library_deinit();
+ exit(status);
+}
+
+/**
+ * @brief prints the usage of the program to the stderr output
+ *
+ * If message is set, program is exited with 1 (error)
+ * @param message message in case of an error
+ */
+static void usage(const char *message)
+{
+ fprintf(stderr,
+ "Usage: aikpub2 --handle <handle> --out <filename>\n"
+ " [--force] [--quiet] [--debug <level>]\n"
+ " aikpub2 --help\n"
+ "\n"
+ "Options:\n"
+ " --handle (-H) TSS 2.0 AIK object handle\n"
+ " --out (-o) AIK public key in PKCS #1 format\n"
+ " --force (-f) force to overwrite existing files\n"
+ " --help (-h) show usage and exit\n"
+ "\n"
+ "Debugging output:\n"
+ " --debug (-l) changes the log level (-1..4, default: 1)\n"
+ " --quiet (-q) do not write log output to stderr\n"
+ );
+ exit_aikpub2(message);
+}
+
+
+/**
+ * @brief main of aikpub2 which extracts an Attestation Identity Key (AIK)
+ *
+ * @param argc number of arguments
+ * @param argv pointer to the argument values
+ */
+int main(int argc, char *argv[])
+{
+ /* external values */
+ extern char * optarg;
+ extern int optind;
+
+ char *aik_out_filename = DEFAULT_FILENAME_AIKPUBKEY;
+ uint32_t aik_handle = 0;
+ bool force = FALSE;
+ hasher_t *hasher;
+ tpm_tss_t *tpm;
+
+ atexit(library_deinit);
+ if (!library_init(NULL, "aikpub2"))
+ {
+ exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
+ }
+ if (lib->integrity &&
+ !lib->integrity->check_file(lib->integrity, "aikpub2", argv[0]))
+ {
+ fprintf(stderr, "integrity check of aikpub2 failed\n");
+ exit(SS_RC_DAEMON_INTEGRITY);
+ }
+
+ /* initialize global variables */
+ options = options_create();
+
+ for (;;)
+ {
+ static const struct option long_opts[] = {
+ /* name, has_arg, flag, val */
+ { "help", no_argument, NULL, 'h' },
+ { "optionsfrom", required_argument, NULL, '+' },
+ { "handle", required_argument, NULL, 'H' },
+ { "in", required_argument, NULL, 'i' },
+ { "out", required_argument, NULL, 'o' },
+ { "force", no_argument, NULL, 'f' },
+ { "quiet", no_argument, NULL, 'q' },
+ { "debug", required_argument, NULL, 'l' },
+ { 0,0,0,0 }
+ };
+
+ /* parse next option */
+ int c = getopt_long(argc, argv, "h+:H:i:o:fql:", long_opts, NULL);
+
+ switch (c)
+ {
+ case EOF: /* end of flags */
+ break;
+
+ case 'h': /* --help */
+ usage(NULL);
+
+ case '+': /* --optionsfrom <filename> */
+ if (!options->from(options, optarg, &argc, &argv, optind))
+ {
+ exit_aikpub2("optionsfrom failed");
+ }
+ continue;
+
+ case 'H': /* --handle <handle> */
+ aik_handle = strtoll(optarg, NULL, 16);
+ continue;
+
+ case 'o': /* --out <filename> */
+ aik_out_filename = optarg;
+ continue;
+
+ case 'f': /* --force */
+ force = TRUE;
+ continue;
+
+ case 'q': /* --quiet */
+ log_to_stderr = FALSE;
+ continue;
+
+ case 'l': /* --debug <level> */
+ default_loglevel = atoi(optarg);
+ continue;
+
+ default:
+ usage("unknown option");
+ }
+ /* break from loop */
+ break;
+ }
+
+ init_log("aikpub2");
+
+ if (!lib->plugins->load(lib->plugins,
+ lib->settings->get_str(lib->settings, "aikpub2.load", PLUGINS)))
+ {
+ exit_aikpub2("plugin loading failed");
+ }
+ if (!aik_handle)
+ {
+ usage("--handle option is required");
+ }
+
+ /* try to find a TPM 2.0 */
+ tpm = tpm_tss_probe(TPM_VERSION_2_0);
+ if (!tpm)
+ {
+ exit_aikpub2("no TPM 2.0 found");
+ }
+
+ /* get AIK public key from TPM */
+ aik_pubkey = tpm->get_public(tpm, aik_handle);
+ tpm->destroy(tpm);
+
+ /* exit if AIK public key retrieval failed */
+ if (aik_pubkey.len == 0)
+ {
+ exit_aikpub2("retrieval of AIK public key failed");
+ }
+
+ /* store AIK subjectPublicKeyInfo to file */
+ if (!chunk_write(aik_pubkey, aik_out_filename, 0022, force))
+ {
+ exit_aikpub2("could not write AIK public key file '%s': %s",
+ aik_out_filename, strerror(errno));
+ }
+ DBG1(DBG_LIB, "AIK public key written to '%s' (%u bytes)",
+ aik_out_filename, aik_pubkey.len);
+
+ /* AIK keyid derived from subjectPublicKeyInfo encoding */
+ hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ if (!hasher)
+ {
+ exit_aikpub2("SHA1 hash algorithm not supported");
+ }
+ if (!hasher->allocate_hash(hasher, aik_pubkey, &aik_keyid))
+ {
+ hasher->destroy(hasher);
+ exit_aikpub2("computing SHA1 fingerprint failed");
+ }
+ hasher->destroy(hasher);
+
+ DBG1(DBG_LIB, "AIK keyid: %#B", &aik_keyid);
+
+ exit_aikpub2(NULL);
+ return -1; /* should never be reached */
+}
diff --git a/src/checksum/Makefile.am b/src/checksum/Makefile.am
index 9cc5fb6b2..87bbf9f28 100644
--- a/src/checksum/Makefile.am
+++ b/src/checksum/Makefile.am
@@ -53,6 +53,11 @@ if USE_LIBPTTLS
libs += $(DESTDIR)$(ipseclibdir)/libpttls.so
endif
+if USE_LIBTPMTSS
+ deps += $(top_builddir)/src/libtpmtss/libtpmtss.la
+ libs += $(DESTDIR)$(ipseclibdir)/libtpmtss.so
+endif
+
if USE_LIBTNCCS
deps += $(top_builddir)/src/libtnccs/libtnccs.la
libs += $(DESTDIR)$(ipseclibdir)/libtnccs.so
diff --git a/src/libimcv/Makefile.am b/src/libimcv/Makefile.am
index 7683da3af..8cde4b7fc 100644
--- a/src/libimcv/Makefile.am
+++ b/src/libimcv/Makefile.am
@@ -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
@@ -66,7 +64,6 @@ libimcv_la_SOURCES = \
pts/pts_pcr.h pts/pts_pcr.c \
pts/pts_proto_caps.h \
pts/pts_req_func_comp_evid.h \
- pts/pts_simple_evid_final.h \
pts/pts_creds.h pts/pts_creds.c \
pts/pts_database.h pts/pts_database.c \
pts/pts_dh_group.h pts/pts_dh_group.c \
@@ -207,5 +204,6 @@ imcv_tests_CFLAGS = \
imcv_tests_LDFLAGS = @COVERAGE_LDFLAGS@
imcv_tests_LDADD = \
$(top_builddir)/src/libimcv/libimcv.la \
+ $(top_builddir)/src/libtpmtss/libtpmtss.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la \
$(top_builddir)/src/libstrongswan/tests/libtest.la
diff --git a/src/libimcv/plugins/imc_attestation/Makefile.am b/src/libimcv/plugins/imc_attestation/Makefile.am
index e7b1f1ce1..14b1646e5 100644
--- a/src/libimcv/plugins/imc_attestation/Makefile.am
+++ b/src/libimcv/plugins/imc_attestation/Makefile.am
@@ -1,7 +1,8 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
- -I$(top_srcdir)/src/libimcv
+ -I$(top_srcdir)/src/libimcv \
+ -I$(top_srcdir)/src/libtpmtss
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation_process.c b/src/libimcv/plugins/imc_attestation/imc_attestation_process.c
index 0e1bc153b..56713bb04 100644
--- a/src/libimcv/plugins/imc_attestation/imc_attestation_process.c
+++ b/src/libimcv/plugins/imc_attestation/imc_attestation_process.c
@@ -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
@@ -420,11 +421,11 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg,
}
case TCG_PTS_GEN_ATTEST_EVID:
{
- pts_simple_evid_final_flag_t flags;
- pts_meas_algorithms_t comp_hash_algorithm;
pts_comp_evidence_t *evid;
- chunk_t pcr_composite, quote_sig;
- bool use_quote2;
+ tpm_quote_mode_t quote_mode;
+ tpm_tss_quote_info_t *quote_info;
+ chunk_t quote_sig;
+ bool use_quote2, use_version_info;
/* Send cached Component Evidence entries */
while (attestation_state->next_evidence(attestation_state, &evid))
@@ -434,21 +435,23 @@ 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);
+ quote_mode = use_quote2 ? (use_version_info ?
+ TPM_QUOTE2_VERSION_INFO :
+ TPM_QUOTE2) :
+ TPM_QUOTE;
+
+ if (!pts->quote(pts, &quote_mode, &quote_info, &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 :
- PTS_SIMPLE_EVID_FINAL_QUOTE_INFO;
- comp_hash_algorithm = PTS_MEAS_ALGO_SHA1;
-
- attr = tcg_pts_attr_simple_evid_final_create(flags,
- comp_hash_algorithm, pcr_composite, quote_sig);
+ attr = tcg_pts_attr_simple_evid_final_create(quote_info, quote_sig);
msg->add_attribute(msg, attr);
break;
}
diff --git a/src/libimcv/plugins/imv_attestation/Makefile.am b/src/libimcv/plugins/imv_attestation/Makefile.am
index 6c5bf8913..f353d30fc 100644
--- a/src/libimcv/plugins/imv_attestation/Makefile.am
+++ b/src/libimcv/plugins/imv_attestation/Makefile.am
@@ -2,6 +2,7 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
-I$(top_srcdir)/src/libimcv \
+ -I$(top_srcdir)/src/libtpmtss \
-DPLUGINS=\""${attest_plugins}\""
AM_CFLAGS = \
@@ -11,6 +12,7 @@ imcv_LTLIBRARIES = imv-attestation.la
imv_attestation_la_LIBADD = \
$(top_builddir)/src/libimcv/libimcv.la \
+ $(top_builddir)/src/libtpmtss/libtpmtss.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la
imv_attestation_la_SOURCES = imv_attestation.c \
@@ -27,6 +29,7 @@ attest_SOURCES = attest.c \
attest_db.h attest_db.c
attest_LDADD = \
$(top_builddir)/src/libimcv/libimcv.la \
+ $(top_builddir)/src/libtpmtss/libtpmtss.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la
attest.o : $(top_builddir)/config.status
diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c b/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c
index 91c12f33b..89ba86930 100644
--- a/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c
+++ b/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c
@@ -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;
}
diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_process.c b/src/libimcv/plugins/imv_attestation/imv_attestation_process.c
index c3e053d9b..b1ee16bf8 100644
--- a/src/libimcv/plugins/imv_attestation/imv_attestation_process.c
+++ b/src/libimcv/plugins/imv_attestation/imv_attestation_process.c
@@ -418,45 +418,31 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg,
case TCG_PTS_SIMPLE_EVID_FINAL:
{
tcg_pts_attr_simple_evid_final_t *attr_cast;
- uint8_t flags;
- pts_meas_algorithms_t comp_hash_algorithm;
- chunk_t pcr_comp, tpm_quote_sig, evid_sig;
- chunk_t pcr_composite, quote_info, result_buf;
+ tpm_tss_quote_info_t *quote_info;
+ chunk_t quoted = chunk_empty, quote_sig, evid_sig, result_buf;
imv_workitem_t *workitem;
imv_reason_string_t *reason_string;
+ hash_algorithm_t digest_alg;
enumerator_t *enumerator;
- bool use_quote2, use_ver_info;
bio_writer_t *result;
attr_cast = (tcg_pts_attr_simple_evid_final_t*)attr;
- flags = attr_cast->get_quote_info(attr_cast, &comp_hash_algorithm,
- &pcr_comp, &tpm_quote_sig);
+ attr_cast->get_quote_info(attr_cast, &quote_info, &quote_sig);
- if (flags != PTS_SIMPLE_EVID_FINAL_NO)
+ if (quote_info->get_quote_mode(quote_info) != TPM_QUOTE_NONE)
{
- use_quote2 = (flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 ||
- flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER);
- use_ver_info = (flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER);
-
/* Construct PCR Composite and TPM Quote Info structures */
- if (!pts->get_quote_info(pts, use_quote2, use_ver_info,
- comp_hash_algorithm, &pcr_composite, &quote_info))
- {
- DBG1(DBG_IMV, "unable to construct TPM Quote Info");
- return FALSE;
- }
-
- if (!chunk_equals_const(pcr_comp, pcr_composite))
+ if (!pts->get_quote(pts, quote_info, &quoted))
{
- DBG1(DBG_IMV, "received PCR Composite does not match "
- "constructed one");
+ DBG1(DBG_IMV, "unable to construct TPM Quote Info digest");
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL);
goto quote_error;
}
- DBG2(DBG_IMV, "received PCR Composite matches constructed one");
+ digest_alg = quote_info->get_pcr_digest_alg(quote_info);
- if (!pts->verify_quote_signature(pts, quote_info, tpm_quote_sig))
+ if (!pts->verify_quote_signature(pts, digest_alg, quoted,
+ quote_sig))
{
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL);
@@ -465,8 +451,7 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg,
DBG2(DBG_IMV, "TPM Quote Info signature verification successful");
quote_error:
- free(pcr_composite.ptr);
- free(quote_info.ptr);
+ chunk_free(&quoted);
/**
* Finalize any pending measurement registrations and check
diff --git a/src/libimcv/plugins/imv_hcd/Makefile.am b/src/libimcv/plugins/imv_hcd/Makefile.am
index 28926d45e..0dce300ef 100644
--- a/src/libimcv/plugins/imv_hcd/Makefile.am
+++ b/src/libimcv/plugins/imv_hcd/Makefile.am
@@ -1,6 +1,7 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
+ -I$(top_srcdir)/src/libtpmtss \
-I$(top_srcdir)/src/libimcv
AM_CFLAGS = \
diff --git a/src/libimcv/plugins/imv_os/Makefile.am b/src/libimcv/plugins/imv_os/Makefile.am
index 3b3f793f1..f5bc9010c 100644
--- a/src/libimcv/plugins/imv_os/Makefile.am
+++ b/src/libimcv/plugins/imv_os/Makefile.am
@@ -1,7 +1,8 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
- -I$(top_srcdir)/src/libimcv
+ -I$(top_srcdir)/src/libimcv \
+ -I$(top_srcdir)/src/libtpmtss
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
diff --git a/src/libimcv/plugins/imv_scanner/Makefile.am b/src/libimcv/plugins/imv_scanner/Makefile.am
index 98814437e..3b3ee818f 100644
--- a/src/libimcv/plugins/imv_scanner/Makefile.am
+++ b/src/libimcv/plugins/imv_scanner/Makefile.am
@@ -1,7 +1,8 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
- -I$(top_srcdir)/src/libimcv
+ -I$(top_srcdir)/src/libimcv \
+ -I$(top_srcdir)/src/libtpmtss
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
diff --git a/src/libimcv/plugins/imv_swid/Makefile.am b/src/libimcv/plugins/imv_swid/Makefile.am
index 3a63b67d2..73da84b55 100644
--- a/src/libimcv/plugins/imv_swid/Makefile.am
+++ b/src/libimcv/plugins/imv_swid/Makefile.am
@@ -1,6 +1,7 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
+ -I$(top_srcdir)/src/libtpmtss \
-I$(top_srcdir)/src/libimcv
AM_CFLAGS = \
diff --git a/src/libimcv/pts/components/ita/ita_comp_tgrub.c b/src/libimcv/pts/components/ita/ita_comp_tgrub.c
index 8c22e9440..a5a1a9b96 100644
--- a/src/libimcv/pts/components/ita/ita_comp_tgrub.c
+++ b/src/libimcv/pts/components/ita/ita_comp_tgrub.c
@@ -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;
diff --git a/src/libimcv/pts/components/pts_comp_func_name.c b/src/libimcv/pts/components/pts_comp_func_name.c
index 257d205ae..00494e1ad 100644
--- a/src/libimcv/pts/components/pts_comp_func_name.c
+++ b/src/libimcv/pts/components/pts_comp_func_name.c
@@ -117,12 +117,12 @@ METHOD(pts_comp_func_name_t, log_, void,
if (names && types)
{
- DBG2(DBG_PTS, "%s%N functional component '%N' [%s] '%N'",
+ DBG3(DBG_PTS, "%s%N functional component '%N' [%s] '%N'",
label, pen_names, this->vid, names, this->name, flags, types, type);
}
else
{
- DBG2(DBG_PTS, "%s0x%06x functional component 0x%08x 0x%02x",
+ DBG3(DBG_PTS, "%s0x%06x functional component 0x%08x 0x%02x",
label, this->vid, this->name, this->qualifier);
}
}
diff --git a/src/libimcv/pts/pts.c b/src/libimcv/pts/pts.c
index 3c5359193..2ba949e40 100644
--- a/src/libimcv/pts/pts.c
+++ b/src/libimcv/pts/pts.c
@@ -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
@@ -21,21 +21,8 @@
#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>
@@ -43,6 +30,13 @@
#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)
{
- DBG2(DBG_PTS, "loaded AIK public key from '%s'", key_path);
- return;
+ 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
+ {
+ 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,312 +600,64 @@ 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)
+METHOD(pts_t, quote, bool,
+ private_pts_t *this, tpm_quote_mode_t *quote_mode,
+ tpm_tss_quote_info_t **quote_info, 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, pcr_computed;
+ uint32_t pcr, pcr_sel = 0;
enumerator_t *enumerator;
- 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 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);
+ pcr_computed = this->pcrs->get(this->pcrs, pcr);
+ DBG2(DBG_PTS, "PCR %2d %#B %s", pcr, &pcr_value,
+ chunk_equals(pcr_value, pcr_computed) ? "ok" : "differs");
+ chunk_free(&pcr_value);
+ };
- if (result != TSS_SUCCESS)
- {
- goto err3;
+ /* add PCR to selection list */
+ pcr_sel |= (1 << pcr);
}
-
- /* Set the Validation Data */
- valData.ulExternalDataLength = this->secret.len;
- valData.rgbExternalData = (BYTE *)this->secret.ptr;
-
+ enumerator->destroy(enumerator);
/* 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;
-}
-
-#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;
+ return this->tpm->quote(this->tpm, this->aik_handle, pcr_sel, HASH_SHA1,
+ this->secret, quote_mode, quote_info, quote_sig);
}
-#endif /* TSS_TROUSERS */
-
-/**
- * TPM_QUOTE_INFO structure:
- * 4 bytes of version
- * 4 bytes 'Q' 'U' 'O' 'T'
- * 20 byte SHA1 of TCPA_PCR_COMPOSITE
- * 20 byte nonce
- *
- * TPM_QUOTE_INFO2 structure:
- * 2 bytes Tag 0x0036 TPM_Tag_Quote_info2
- * 4 bytes 'Q' 'U' 'T' '2'
- * 20 bytes nonce
- * 26 bytes PCR_INFO_SHORT
- */
-
-METHOD(pts_t, get_quote_info, bool,
- private_pts_t *this, bool use_quote2, bool use_ver_info,
- pts_meas_algorithms_t comp_hash_algo,
- chunk_t *out_pcr_comp, chunk_t *out_quote_info)
+METHOD(pts_t, get_quote, bool,
+ private_pts_t *this, tpm_tss_quote_info_t *quote_info, chunk_t *quoted)
{
- chunk_t selection, pcr_comp, hash_pcr_comp;
- bio_writer_t *writer;
- hasher_t *hasher;
+ tpm_tss_pcr_composite_t *pcr_composite;
+ bool success;
if (!this->pcrs->get_count(this->pcrs))
{
@@ -930,128 +671,93 @@ 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)
- {
- DBG1(DBG_PTS, "TPM Version Information unavailable, ",
- "unable to construct TPM Quote Info2");
- return FALSE;
- }
-
- pcr_comp = this->pcrs->get_composite(this->pcrs);
-
-
- /* Output the TPM_PCR_COMPOSITE expected from IMC */
- if (comp_hash_algo)
+ if (quote_info->get_quote_mode(quote_info) == TPM_QUOTE2_VERSION_INFO)
{
- hash_algorithm_t algo;
-
- algo = pts_meas_algo_to_hash(comp_hash_algo);
- hasher = lib->crypto->create_hasher(lib->crypto, algo);
-
- /* Hash the PCR Composite Structure */
- if (!hasher || !hasher->allocate_hash(hasher, pcr_comp, out_pcr_comp))
+ if (!this->tpm_version_info.ptr)
{
- DESTROY_IF(hasher);
- free(pcr_comp.ptr);
+ DBG1(DBG_PTS, "TPM Version Information unavailable, ",
+ "unable to construct TPM Quote Info2");
return FALSE;
}
- DBG3(DBG_PTS, "constructed PCR Composite hash: %#B", out_pcr_comp);
- hasher->destroy(hasher);
+ quote_info->set_version_info(quote_info, this->tpm_version_info);
}
- else
- {
- *out_pcr_comp = chunk_clone(pcr_comp);
- }
-
- /* SHA1 hash of PCR Composite to construct TPM_QUOTE_INFO */
- hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
- if (!hasher || !hasher->allocate_hash(hasher, pcr_comp, &hash_pcr_comp))
- {
- DESTROY_IF(hasher);
- chunk_free(out_pcr_comp);
- free(pcr_comp.ptr);
- return FALSE;
- }
- hasher->destroy(hasher);
-
- /* Construct TPM_QUOTE_INFO/TPM_QUOTE_INFO2 structure */
- writer = bio_writer_create(TPM_QUOTE_INFO_LEN);
-
- if (use_quote2)
- {
- /* TPM Structure Tag */
- writer->write_uint16(writer, TPM_TAG_QUOTE_INFO2);
-
- /* Magic QUT2 value */
- writer->write_data(writer, chunk_create("QUT2", 4));
-
- /* Secret assessment value 20 bytes (nonce) */
- writer->write_data(writer, this->secret);
-
- /* PCR selection */
- selection.ptr = pcr_comp.ptr;
- selection.len = 2 + this->pcrs->get_selection_size(this->pcrs);
- writer->write_data(writer, selection);
-
- /* TPM Locality Selection */
- writer->write_uint8(writer, TPM_LOC_ZERO);
-
- /* PCR Composite Hash */
- writer->write_data(writer, hash_pcr_comp);
-
- if (use_ver_info)
- {
- /* TPM version Info */
- writer->write_data(writer, this->tpm_version_info);
- }
- }
- else
- {
- /* Version number */
- writer->write_data(writer, chunk_from_chars(1, 1, 0, 0));
-
- /* Magic QUOT value */
- writer->write_data(writer, chunk_create("QUOT", 4));
-
- /* PCR Composite Hash */
- writer->write_data(writer, hash_pcr_comp);
-
- /* Secret assessment value 20 bytes (nonce) */
- writer->write_data(writer, this->secret);
- }
-
- /* TPM Quote Info */
- *out_quote_info = writer->extract_buf(writer);
- DBG3(DBG_PTS, "constructed TPM Quote Info: %B", out_quote_info);
+ pcr_composite = this->pcrs->get_composite(this->pcrs);
- writer->destroy(writer);
- free(pcr_comp.ptr);
- free(hash_pcr_comp.ptr);
+ success = quote_info->get_quote(quote_info, this->secret,
+ pcr_composite, quoted);
+ chunk_free(&pcr_composite->pcr_select);
+ chunk_free(&pcr_composite->pcr_composite);
+ free(pcr_composite);
- return TRUE;
+ return success;
}
METHOD(pts_t, verify_quote_signature, bool,
- private_pts_t *this, chunk_t data, chunk_t signature)
+ private_pts_t *this, hash_algorithm_t digest_alg, chunk_t digest,
+ chunk_t signature)
{
- public_key_t *aik_pub_key;
+ public_key_t *aik_pubkey;
+ signature_scheme_t scheme;
- 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,
- data, signature))
+ /* Determine signing scheme */
+ switch (aik_pubkey->get_type(aik_pubkey))
+ {
+ case KEY_RSA:
+ switch (digest_alg)
+ {
+ case HASH_SHA1:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+ break;
+ case HASH_SHA256:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
+ break;
+ case HASH_SHA384:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
+ break;
+ case HASH_SHA512:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
+ break;
+ default:
+ scheme = SIGN_UNKNOWN;
+ }
+ break;
+ case KEY_ECDSA:
+ switch (digest_alg)
+ {
+ case HASH_SHA256:
+ scheme = SIGN_ECDSA_256;
+ break;
+ case HASH_SHA384:
+ scheme = SIGN_ECDSA_384;
+ break;
+ case HASH_SHA512:
+ scheme = SIGN_ECDSA_521;
+ break;
+ default:
+ scheme = SIGN_UNKNOWN;
+ }
+ break;
+ default:
+ DBG1(DBG_PTS, "%N AIK key type not supported", key_type_names,
+ aik_pubkey->get_type(aik_pubkey));
+ return FALSE;
+ }
+
+ if (!aik_pubkey->verify(aik_pubkey, scheme, digest, 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 +770,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
*/
@@ -1174,9 +819,9 @@ pts_t *pts_create(bool is_imc)
.get_metadata = _get_metadata,
.read_pcr = _read_pcr,
.extend_pcr = _extend_pcr,
- .quote_tpm = _quote_tpm,
+ .quote = _quote,
.get_pcrs = _get_pcrs,
- .get_quote_info = _get_quote_info,
+ .get_quote = _get_quote,
.verify_quote_signature = _verify_quote_signature,
.destroy = _destroy,
},
@@ -1189,12 +834,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
diff --git a/src/libimcv/pts/pts.h b/src/libimcv/pts/pts.h
index 1e07c4be3..f3da659dc 100644
--- a/src/libimcv/pts/pts.h
+++ b/src/libimcv/pts/pts.h
@@ -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
@@ -32,9 +32,10 @@ typedef struct pts_t pts_t;
#include "pts_dh_group.h"
#include "pts_pcr.h"
#include "pts_req_func_comp_evid.h"
-#include "pts_simple_evid_final.h"
#include "components/pts_comp_func_name.h"
+#include <tpm_tss_quote_info.h>
+
#include <library.h>
#include <collections/linked_list.h>
@@ -71,11 +72,6 @@ typedef struct pts_t pts_t;
#define ASSESSMENT_SECRET_LEN 20
/**
- * Length of the TPM_QUOTE_INFO structure, TPM Spec 1.2
- */
-#define TPM_QUOTE_INFO_LEN 48
-
-/**
* Hashing algorithm used by tboot and trustedGRUB
*/
#define TRUSTED_HASH_ALGO PTS_MEAS_ALGO_SHA1
@@ -236,39 +232,39 @@ 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 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
+ * @param quote_mode type of Quote signature
+ * @param quote_info returns various info covered by Quote signature
+ * @param quote_sig returns Quote signature
+ * @return FALSE in case of Quote error, TRUE otherwise
*/
- bool (*quote_tpm)(pts_t *this, bool use_quote2, chunk_t *pcr_comp,
- chunk_t *quote_sig);
+ bool (*quote)(pts_t *this, tpm_quote_mode_t *quote_mode,
+ tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig);
/**
* Get the shadow PCR set
@@ -277,28 +273,26 @@ struct pts_t {
*/
pts_pcr_t* (*get_pcrs)(pts_t *this);
- /**
- * Constructs and returns TPM Quote Info structure expected from IMC
+ /**
+ * Computes digest of the constructed TPM Quote Info structure
*
- * @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 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
+ * @param quote_info TPM Quote Info as received from IMC
+ * @param quoted Encoding of 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,
- pts_meas_algorithms_t comp_hash_algo,
- chunk_t *pcr_comp, chunk_t *quote_info);
+ bool (*get_quote)(pts_t *this, tpm_tss_quote_info_t *quote_info,
+ chunk_t *quoted);
/**
* Constructs and returns PCR Quote Digest structure expected from IMC
*
- * @param data Calculated TPM Quote Digest
+ * @param digest_alg Hash algorithm used for TPM Quote Digest
+ * @param digest Calculated TPM Quote Digest
* @param signature TPM Quote Signature received from IMC
* @return FALSE if signature is not verified
*/
- bool (*verify_quote_signature)(pts_t *this, chunk_t data, chunk_t signature);
+ bool (*verify_quote_signature)(pts_t *this, hash_algorithm_t digest_alg,
+ chunk_t digest, chunk_t signature);
/**
* Destroys a pts_t object.
diff --git a/src/libimcv/pts/pts_meas_algo.c b/src/libimcv/pts/pts_meas_algo.c
index c06371123..246c37714 100644
--- a/src/libimcv/pts/pts_meas_algo.c
+++ b/src/libimcv/pts/pts_meas_algo.c
@@ -158,6 +158,24 @@ hash_algorithm_t pts_meas_algo_to_hash(pts_meas_algorithms_t algorithm)
/**
* Described in header.
*/
+pts_meas_algorithms_t pts_meas_algo_from_hash(hash_algorithm_t algorithm)
+{
+ switch (algorithm)
+ {
+ case HASH_SHA1:
+ return PTS_MEAS_ALGO_SHA1;
+ case HASH_SHA256:
+ return PTS_MEAS_ALGO_SHA256;
+ case HASH_SHA384:
+ return PTS_MEAS_ALGO_SHA384;
+ default:
+ return PTS_MEAS_ALGO_NONE;
+ }
+}
+
+/**
+ * Described in header.
+ */
size_t pts_meas_algo_hash_size(pts_meas_algorithms_t algorithm)
{
switch (algorithm)
diff --git a/src/libimcv/pts/pts_meas_algo.h b/src/libimcv/pts/pts_meas_algo.h
index eec7e7981..d70310679 100644
--- a/src/libimcv/pts/pts_meas_algo.h
+++ b/src/libimcv/pts/pts_meas_algo.h
@@ -96,6 +96,14 @@ pts_meas_algorithms_t pts_meas_algo_select(pts_meas_algorithms_t supported_algos
hash_algorithm_t pts_meas_algo_to_hash(pts_meas_algorithms_t algorithm);
/**
+ * Convert hash_algorithm_t to pts_meas_algorithms_t
+ *
+ * @param algorithm PTS measurement algorithm type
+ * @return libstrongswan hash algorithm type
+ */
+pts_meas_algorithms_t pts_meas_algo_from_hash(hash_algorithm_t algorithm);
+
+/**
* Return the hash size of a pts_meas_algorithm
*
* @param algorithm PTS measurement algorithm type
diff --git a/src/libimcv/pts/pts_pcr.c b/src/libimcv/pts/pts_pcr.c
index 895c273bb..d514532c5 100644
--- a/src/libimcv/pts/pts_pcr.c
+++ b/src/libimcv/pts/pts_pcr.c
@@ -200,10 +200,10 @@ METHOD(pts_pcr_t, extend, chunk_t,
return this->pcrs[pcr];
}
-METHOD(pts_pcr_t, get_composite, chunk_t,
+METHOD(pts_pcr_t, get_composite, tpm_tss_pcr_composite_t*,
private_pts_pcr_t *this)
{
- chunk_t composite;
+ tpm_tss_pcr_composite_t *pcr_composite;
enumerator_t *enumerator;
uint16_t selection_size;
uint32_t pcr_field_size, pcr;
@@ -212,14 +212,13 @@ METHOD(pts_pcr_t, get_composite, chunk_t,
selection_size = get_selection_size(this);
pcr_field_size = this->pcr_count * PTS_PCR_LEN;
- composite = chunk_alloc(2 + selection_size + 4 + pcr_field_size);
- pos = composite.ptr;
- htoun16(pos, selection_size);
- pos += 2;
- memcpy(pos, this->pcr_select, selection_size);
- pos += selection_size;
- htoun32(pos, pcr_field_size);
- pos += 4;
+ INIT(pcr_composite,
+ .pcr_select = chunk_alloc(selection_size),
+ .pcr_composite = chunk_alloc(pcr_field_size),
+ );
+
+ memcpy(pcr_composite->pcr_select.ptr, this->pcr_select, selection_size);
+ pos = pcr_composite->pcr_composite.ptr;
enumerator = create_enumerator(this);
while (enumerator->enumerate(enumerator, &pcr))
@@ -229,8 +228,7 @@ METHOD(pts_pcr_t, get_composite, chunk_t,
}
enumerator->destroy(enumerator);
- DBG3(DBG_PTS, "constructed PCR Composite: %B", &composite);
- return composite;
+ return pcr_composite;
}
METHOD(pts_pcr_t, destroy, void,
diff --git a/src/libimcv/pts/pts_pcr.h b/src/libimcv/pts/pts_pcr.h
index b6ca73edc..df84c679f 100644
--- a/src/libimcv/pts/pts_pcr.h
+++ b/src/libimcv/pts/pts_pcr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 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
@@ -25,6 +25,8 @@ typedef struct pts_pcr_t pts_pcr_t;
#include <library.h>
+#include <tpm_tss_quote_info.h>
+
/**
* Maximum number of PCR's of TPM, TPM Spec 1.2
*/
@@ -100,7 +102,7 @@ struct pts_pcr_t {
*
* @return PCR Composite object (must be freed)
*/
- chunk_t (*get_composite)(pts_pcr_t *this);
+ tpm_tss_pcr_composite_t* (*get_composite)(pts_pcr_t *this);
/**
diff --git a/src/libimcv/pts/pts_simple_evid_final.h b/src/libimcv/pts/pts_simple_evid_final.h
deleted file mode 100644
index 0c8dea0cc..000000000
--- a/src/libimcv/pts/pts_simple_evid_final.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2011 Sansar Choinyambuu
- * HSR Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-/**
- * @defgroup pts_simple_evid_final pts_rsimple_evid_final
- * @{ @ingroup pts
- */
-
-#ifndef PTS_SIMPLE_EVID_FINAL_H_
-#define PTS_SIMPLE_EVID_FINAL_H_
-
-typedef enum pts_simple_evid_final_flag_t pts_simple_evid_final_flag_t;
-
-#include <library.h>
-
-/**
- * PTS Simple Evidence Final Flags
- */
-enum pts_simple_evid_final_flag_t {
- /** TPM PCR Composite and TPM Quote Signature not included */
- PTS_SIMPLE_EVID_FINAL_NO = 0x00,
- /** TPM PCR Composite and TPM Quote Signature included
- * using TPM_QUOTE_INFO */
- PTS_SIMPLE_EVID_FINAL_QUOTE_INFO = 0x40,
- /** TPM PCR Composite and TPM Quote Signature included
- * using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO not appended */
- PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 = 0x80,
- /** TPM PCR Composite and TPM Quote Signature included
- * using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO appended */
- PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER = 0xC0,
- /** Evidence Signature included */
- PTS_SIMPLE_EVID_FINAL_EVID_SIG = 0x20,
-};
-
-#endif /** PTS_SIMPLE_EVID_FINAL_H_ @}*/
diff --git a/src/libimcv/tcg/pts/tcg_pts_attr_simple_evid_final.c b/src/libimcv/tcg/pts/tcg_pts_attr_simple_evid_final.c
index a847dcb70..267c85776 100644
--- a/src/libimcv/tcg/pts/tcg_pts_attr_simple_evid_final.c
+++ b/src/libimcv/tcg/pts/tcg_pts_attr_simple_evid_final.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2016 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -15,7 +15,6 @@
*/
#include "tcg_pts_attr_simple_evid_final.h"
-#include "pts/pts_simple_evid_final.h"
#include <pa_tnc/pa_tnc_msg.h>
#include <bio/bio_writer.h>
@@ -27,6 +26,7 @@ typedef struct private_tcg_pts_attr_simple_evid_final_t private_tcg_pts_attr_sim
/**
* Simple Evidence Final
* see section 3.15.2 of PTS Protocol: Binding to TNC IF-M Specification
+ * plus non-standard extensions to cover the TPM 2.0 Quote Info format
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@@ -37,17 +37,57 @@ typedef struct private_tcg_pts_attr_simple_evid_final_t private_tcg_pts_attr_sim
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ Optional TPM PCR Composite (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Opt. TPM Qual. Signer Length | Optional TPM Qualified Signer ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ~ Optional TPM Qualified Signer (Variable Length) ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Opt. TPM Clock Info Length | Optional TPM Clock Info ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ~ Optional TPM Clock Info (Variable Length) ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Opt. TPM Version Info Length | Optional TPM Version Info ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ~ Optional TPM Version Info (Variable Length) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Opt. TPM PCR Selection Length | Opt. TPM PCR Selection ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ~ Optional TPM PCR Selection (Variable Length) ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Optional TPM Quote Signature Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ Optional TPM Quote Signature (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ Optional Evidence Signature (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
+*/
#define PTS_SIMPLE_EVID_FINAL_SIZE 2
#define PTS_SIMPLE_EVID_FINAL_RESERVED 0x00
-#define PTS_SIMPLE_EVID_FINAL_FLAG_MASK 0xC0
+
+/**
+ * PTS Simple Evidence Final Flags
+ */
+enum pts_simple_evid_final_flag_t {
+ /** TPM PCR Composite and TPM Quote Signature not included */
+ PTS_SIMPLE_EVID_FINAL_NO = 0x00,
+ /** TPM Quote Info and TPM Quite Signature included
+ * using TPM 2.0 Quote Info format */
+ PTS_SIMPLE_EVID_FINAL_EVID_QUOTE_INFO_TPM2 = 0x10,
+ /** Evidence Signature included */
+ PTS_SIMPLE_EVID_FINAL_EVID_SIG = 0x20,
+ /** TPM PCR Composite and TPM Quote Signature included
+ * using TPM_QUOTE_INFO */
+ PTS_SIMPLE_EVID_FINAL_QUOTE_INFO = 0x40,
+ /** TPM PCR Composite and TPM Quote Signature included
+ * using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO not appended */
+ PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 = 0x80,
+ /** TPM PCR Composite and TPM Quote Signature included
+ * using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO appended */
+ PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER = 0xC0,
+ /** Mask for the TPM Quote Info flags */
+ PTS_SIMPLE_EVID_FINAL_QUOTE_INFO_MASK = 0xD0
+};
+
/**
* Private data of an tcg_pts_attr_simple_evid_final_t object.
*/
@@ -79,24 +119,14 @@ struct private_tcg_pts_attr_simple_evid_final_t {
bool noskip_flag;
/**
- * Set of flags for Simple Evidence Final
- */
- uint8_t flags;
-
- /**
- * Optional Composite Hash Algorithm
- */
- pts_meas_algorithms_t comp_hash_algorithm;
-
- /**
- * Optional TPM PCR Composite
+ * Optional TPM Quote Info
*/
- chunk_t pcr_comp;
+ tpm_tss_quote_info_t *quote_info;
/**
* Optional TPM Quote Signature
*/
- chunk_t tpm_quote_sig;
+ chunk_t quote_sig;
/**
* Is Evidence Signature included?
@@ -156,9 +186,9 @@ METHOD(pa_tnc_attr_t, destroy, void,
{
if (ref_put(&this->ref))
{
+ DESTROY_IF(this->quote_info);
free(this->value.ptr);
- free(this->pcr_comp.ptr);
- free(this->tpm_quote_sig.ptr);
+ free(this->quote_sig.ptr);
free(this->evid_sig.ptr);
free(this);
}
@@ -167,6 +197,9 @@ METHOD(pa_tnc_attr_t, destroy, void,
METHOD(pa_tnc_attr_t, build, void,
private_tcg_pts_attr_simple_evid_final_t *this)
{
+ chunk_t pcr_digest, pcr_select, qualified_signer, clock_info, version_info;
+ hash_algorithm_t pcr_digest_alg;
+ tpm_quote_mode_t quote_mode;
bio_writer_t *writer;
uint8_t flags;
@@ -174,7 +207,26 @@ METHOD(pa_tnc_attr_t, build, void,
{
return;
}
- flags = this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_MASK;
+
+ quote_mode = this->quote_info->get_quote_mode(this->quote_info);
+ switch (quote_mode)
+ {
+ case TPM_QUOTE:
+ flags = PTS_SIMPLE_EVID_FINAL_QUOTE_INFO;
+ break;
+ case TPM_QUOTE2:
+ flags = PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2;
+ break;
+ case TPM_QUOTE2_VERSION_INFO:
+ flags = PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER;
+ break;
+ case TPM_QUOTE_TPM2:
+ flags = PTS_SIMPLE_EVID_FINAL_EVID_QUOTE_INFO_TPM2;
+ break;
+ case TPM_QUOTE_NONE:
+ default:
+ flags = PTS_SIMPLE_EVID_FINAL_NO;
+ }
if (this->has_evid_sig)
{
@@ -185,25 +237,35 @@ METHOD(pa_tnc_attr_t, build, void,
writer->write_uint8 (writer, flags);
writer->write_uint8 (writer, PTS_SIMPLE_EVID_FINAL_RESERVED);
- /** Optional Composite Hash Algorithm field is always present
- * Field has value of all zeroes if not used.
- * Implemented adhering the suggestion of Paul Sangster 28.Oct.2011
- */
- writer->write_uint16(writer, this->comp_hash_algorithm);
+ pcr_digest_alg = this->quote_info->get_pcr_digest_alg(this->quote_info);
+ pcr_digest = this->quote_info->get_pcr_digest(this->quote_info);
+
+ writer->write_uint16(writer, pts_meas_algo_from_hash(pcr_digest_alg));
/* Optional fields */
- if (this->flags != PTS_SIMPLE_EVID_FINAL_NO)
+ if (quote_mode != TPM_QUOTE_NONE)
{
- writer->write_uint32 (writer, this->pcr_comp.len);
- writer->write_data (writer, this->pcr_comp);
-
- writer->write_uint32 (writer, this->tpm_quote_sig.len);
- writer->write_data (writer, this->tpm_quote_sig);
+ writer->write_data32(writer, pcr_digest);
}
- if (this->has_evid_sig)
+ if (quote_mode == TPM_QUOTE_TPM2)
+ {
+ version_info = this->quote_info->get_version_info(this->quote_info);
+ this->quote_info->get_tpm2_info(this->quote_info, &qualified_signer,
+ &clock_info, &pcr_select);
+ writer->write_data16(writer, qualified_signer);
+ writer->write_data16(writer, clock_info);
+ writer->write_data16(writer, version_info);
+ writer->write_data16(writer, pcr_select);
+ }
+
+ if (quote_mode != TPM_QUOTE_NONE)
{
- writer->write_data (writer, this->evid_sig);
+ writer->write_data32(writer, this->quote_sig);
+ if (this->has_evid_sig)
+ {
+ writer->write_data(writer, this->evid_sig);
+ }
}
this->value = writer->extract_buf(writer);
@@ -214,10 +276,14 @@ METHOD(pa_tnc_attr_t, build, void,
METHOD(pa_tnc_attr_t, process, status_t,
private_tcg_pts_attr_simple_evid_final_t *this, uint32_t *offset)
{
+ hash_algorithm_t pcr_digest_alg;
+ tpm_quote_mode_t quote_mode;
bio_reader_t *reader;
uint8_t flags, reserved;
uint16_t algorithm;
- uint32_t pcr_comp_len, tpm_quote_sig_len, evid_sig_len;
+ uint32_t evid_sig_len;
+ chunk_t pcr_digest = chunk_empty, quote_sig, evid_sig;
+ chunk_t qualified_signer, clock_info, version_info, pcr_select;
status_t status = FAILED;
*offset = 0;
@@ -236,56 +302,99 @@ METHOD(pa_tnc_attr_t, process, status_t,
reader->read_uint8(reader, &flags);
reader->read_uint8(reader, &reserved);
- this->flags = flags & PTS_SIMPLE_EVID_FINAL_FLAG_MASK;
-
this->has_evid_sig = (flags & PTS_SIMPLE_EVID_FINAL_EVID_SIG) != 0;
+ flags &= PTS_SIMPLE_EVID_FINAL_QUOTE_INFO_MASK;
+
+ switch (flags)
+ {
+ case PTS_SIMPLE_EVID_FINAL_QUOTE_INFO:
+ quote_mode = TPM_QUOTE;
+ break;
+ case PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2:
+ quote_mode = TPM_QUOTE2;
+ break;
+ case PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER:
+ quote_mode = TPM_QUOTE2_VERSION_INFO;
+ break;
+ case PTS_SIMPLE_EVID_FINAL_EVID_QUOTE_INFO_TPM2:
+ quote_mode = TPM_QUOTE_TPM2;
+ break;
+ case PTS_SIMPLE_EVID_FINAL_NO:
+ default:
+ quote_mode = TPM_QUOTE_NONE;
+ break;
+ }
+
/** Optional Composite Hash Algorithm field is always present
* Field has value of all zeroes if not used.
* Implemented adhering the suggestion of Paul Sangster 28.Oct.2011
*/
-
reader->read_uint16(reader, &algorithm);
- this->comp_hash_algorithm = algorithm;
+ pcr_digest_alg = pts_meas_algo_to_hash(algorithm);
+
+ /* Optional fields */
+ if (quote_mode != TPM_QUOTE_NONE)
+ {
+ if (!reader->read_data32(reader, &pcr_digest))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final "
+ "PCR Composite");
+ goto end;
+ }
+ }
+ this->quote_info = tpm_tss_quote_info_create(quote_mode, pcr_digest_alg,
+ pcr_digest);
- /* Optional Composite Hash Algorithm and TPM PCR Composite fields */
- if (this->flags != PTS_SIMPLE_EVID_FINAL_NO)
+ if (quote_mode == TPM_QUOTE_TPM2)
{
- if (!reader->read_uint32(reader, &pcr_comp_len))
+ if (!reader->read_data16(reader, &qualified_signer))
{
DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final "
- "PCR Composite Length");
+ "Qualified Signer");
goto end;
}
- if (!reader->read_data(reader, pcr_comp_len, &this->pcr_comp))
+ if (!reader->read_data16(reader, &clock_info))
{
DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final "
- "PCR Composite");
+ "Clock Info");
goto end;
}
- this->pcr_comp = chunk_clone(this->pcr_comp);
-
- if (!reader->read_uint32(reader, &tpm_quote_sig_len))
+ if (!reader->read_data16(reader, &version_info))
{
DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final "
- "TPM Quote Singature Length");
+ "Version Info");
goto end;
}
- if (!reader->read_data(reader, tpm_quote_sig_len, &this->tpm_quote_sig))
+ if (!reader->read_data16(reader, &pcr_select))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final "
+ "PCR select");
+ goto end;
+ }
+ this->quote_info->set_tpm2_info(this->quote_info, qualified_signer,
+ clock_info, pcr_select);
+ this->quote_info->set_version_info(this->quote_info, version_info);
+ }
+
+
+ if (quote_mode != TPM_QUOTE_NONE)
+ {
+ if (!reader->read_data32(reader, &quote_sig))
{
DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final "
"TPM Quote Singature");
goto end;
}
- this->tpm_quote_sig = chunk_clone(this->tpm_quote_sig);
+ this->quote_sig = chunk_clone(quote_sig);
}
/* Optional Evidence Signature field */
if (this->has_evid_sig)
{
evid_sig_len = reader->remaining(reader);
- reader->read_data(reader, evid_sig_len, &this->evid_sig);
- this->evid_sig = chunk_clone(this->evid_sig);
+ reader->read_data(reader, evid_sig_len, &evid_sig);
+ this->evid_sig = chunk_clone(evid_sig);
}
reader->destroy(reader);
@@ -296,23 +405,18 @@ end:
return status;
}
-METHOD(tcg_pts_attr_simple_evid_final_t, get_quote_info, uint8_t,
+METHOD(tcg_pts_attr_simple_evid_final_t, get_quote_info, void,
private_tcg_pts_attr_simple_evid_final_t *this,
- pts_meas_algorithms_t *comp_hash_algo, chunk_t *pcr_comp, chunk_t *tpm_quote_sig)
+ tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig)
{
- if (comp_hash_algo)
- {
- *comp_hash_algo = this->comp_hash_algorithm;
- }
- if (pcr_comp)
+ if (quote_info)
{
- *pcr_comp = this->pcr_comp;
+ *quote_info = this->quote_info;
}
- if (tpm_quote_sig)
+ if (quote_sig)
{
- *tpm_quote_sig = this->tpm_quote_sig;
+ *quote_sig = this->quote_sig;
}
- return this->flags;
}
METHOD(tcg_pts_attr_simple_evid_final_t, get_evid_sig, bool,
@@ -335,9 +439,8 @@ METHOD(tcg_pts_attr_simple_evid_final_t, set_evid_sig, void,
/**
* Described in header.
*/
-pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create(uint8_t flags,
- pts_meas_algorithms_t comp_hash_algorithm,
- chunk_t pcr_comp, chunk_t tpm_quote_sig)
+pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create(
+ tpm_tss_quote_info_t *quote_info, chunk_t quote_sig)
{
private_tcg_pts_attr_simple_evid_final_t *this;
@@ -359,10 +462,8 @@ pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create(uint8_t flags,
.set_evid_sig = _set_evid_sig,
},
.type = { PEN_TCG, TCG_PTS_SIMPLE_EVID_FINAL },
- .flags = flags,
- .comp_hash_algorithm = comp_hash_algorithm,
- .pcr_comp = pcr_comp,
- .tpm_quote_sig = tpm_quote_sig,
+ .quote_info = quote_info,
+ .quote_sig = quote_sig,
.ref = 1,
);
diff --git a/src/libimcv/tcg/pts/tcg_pts_attr_simple_evid_final.h b/src/libimcv/tcg/pts/tcg_pts_attr_simple_evid_final.h
index aed4d941f..c12e520fd 100644
--- a/src/libimcv/tcg/pts/tcg_pts_attr_simple_evid_final.h
+++ b/src/libimcv/tcg/pts/tcg_pts_attr_simple_evid_final.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
- * Copyright (C) 2014 Andreas Steffen
+ * Copyright (C) 2014-2016 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -28,6 +28,8 @@ typedef struct tcg_pts_attr_simple_evid_final_t tcg_pts_attr_simple_evid_final_t
#include "tcg_pts_attr_meas_algo.h"
#include "pa_tnc/pa_tnc_attr.h"
+#include <tpm_tss_quote_info.h>
+
/**
* Class implementing the TCG PTS Simple Evidence Final attribute
*
@@ -40,16 +42,14 @@ struct tcg_pts_attr_simple_evid_final_t {
pa_tnc_attr_t pa_tnc_attribute;
/**
- * Get Optional PCR Composite and TPM Quote Signature
+ * Get Optional TPM Quote Info and TPM Quote Signature
*
- * @param comp_hash_algo Optional Composite Hash Algorithm
- * @param pcr_comp Optional PCR Composite
- * @param tpm_quote sig Optional TPM Quote Signature
- * @return PTS_SIMPLE_EVID_FINAL flags
+ * @param quote_info Optional TPM Quote Info
+ * @param quote sig Optional TPM Quote Signature
*/
- uint8_t (*get_quote_info)(tcg_pts_attr_simple_evid_final_t *this,
- pts_meas_algorithms_t *comp_hash_algo,
- chunk_t *pcr_comp, chunk_t *tpm_quote_sig);
+ void (*get_quote_info)(tcg_pts_attr_simple_evid_final_t *this,
+ tpm_tss_quote_info_t **quote_info,
+ chunk_t *quote_sig);
/**
* Get Optional Evidence Signature
@@ -73,16 +73,11 @@ struct tcg_pts_attr_simple_evid_final_t {
/**
* Creates an tcg_pts_attr_simple_evid_final_t object
*
- * @param flags Set of flags
- * @param comp_hash_algorithm Composite Hash Algorithm
- * @param pcr_comp Optional TPM PCR Composite
- * @param tpm_quote_sign Optional TPM Quote Signature
+ * @param quote_info Optional TPM Quote Info
+ * @param quote_sign Optional TPM Quote Signature
*/
pa_tnc_attr_t* tcg_pts_attr_simple_evid_final_create(
- uint8_t flags,
- pts_meas_algorithms_t comp_hash_algorithm,
- chunk_t pcr_comp,
- chunk_t tpm_quote_sign);
+ tpm_tss_quote_info_t *quote_info, chunk_t quote_sig);
/**
* Creates an tcg_pts_attr_simple_evid_final_t object from received data
diff --git a/src/libpttls/pt_tls.c b/src/libpttls/pt_tls.c
index 1b136a7f0..01493f45c 100644
--- a/src/libpttls/pt_tls.c
+++ b/src/libpttls/pt_tls.c
@@ -17,6 +17,7 @@
#include <utils/debug.h>
#include <pen/pen.h>
+
/**
* Described in header.
*/
diff --git a/src/libtpmtss/Makefile.am b/src/libtpmtss/Makefile.am
new file mode 100644
index 000000000..8fcb44f6a
--- /dev/null
+++ b/src/libtpmtss/Makefile.am
@@ -0,0 +1,25 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan
+
+AM_LDFLAGS = \
+ -no-undefined
+
+ipseclib_LTLIBRARIES = libtpmtss.la
+libtpmtss_la_SOURCES = \
+ tpm_tss.h tpm_tss.c \
+ tpm_tss_quote_info.h tpm_tss_quote_info.c \
+ tpm_tss_trousers.h tpm_tss_trousers.c \
+ tpm_tss_tss2.h tpm_tss_tss2.c \
+ tpm_tss_tss2_names.h tpm_tss_tss2_names.c
+
+libtpmtss_la_LIBADD = \
+ $(top_builddir)/src/libstrongswan/libstrongswan.la
+
+if USE_TSS2
+libtpmtss_la_LIBADD += -ltctisocket -ltss2
+endif
+
+if USE_TROUSERS
+libtpmtss_la_LIBADD += -ltspi
+endif
+
diff --git a/src/libtpmtss/tpm_tss.c b/src/libtpmtss/tpm_tss.c
new file mode 100644
index 000000000..b7b970c8d
--- /dev/null
+++ b/src/libtpmtss/tpm_tss.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "tpm_tss.h"
+#include "tpm_tss_tss2.h"
+#include "tpm_tss_trousers.h"
+
+/**
+ * Described in header.
+ */
+void libtpmtss_init(void)
+{
+ /* empty */
+}
+
+typedef tpm_tss_t*(*tpm_tss_create)();
+
+/**
+ * See header.
+ */
+tpm_tss_t *tpm_tss_probe(tpm_version_t version)
+{
+ tpm_tss_create stacks[] = {
+ tpm_tss_tss2_create,
+ tpm_tss_trousers_create,
+ };
+ tpm_tss_t *tpm;
+ int i;
+
+ for (i = 0; i < countof(stacks); i++)
+ {
+ tpm = stacks[i]();
+ if (tpm)
+ {
+ if (version == TPM_VERSION_ANY || version == tpm->get_version(tpm))
+ {
+ return tpm;
+ }
+ }
+ }
+ return NULL;
+}
diff --git a/src/libtpmtss/tpm_tss.h b/src/libtpmtss/tpm_tss.h
new file mode 100644
index 000000000..9295b2969
--- /dev/null
+++ b/src/libtpmtss/tpm_tss.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup tpm_tss tpm_tss
+ * @{ @ingroup libtpmtss
+ */
+
+#ifndef TPM_TSS_H_
+#define TPM_TSS_H_
+
+#include "tpm_tss_quote_info.h"
+
+#include <library.h>
+#include <crypto/hashers/hasher.h>
+
+typedef enum tpm_version_t tpm_version_t;
+typedef struct tpm_tss_t tpm_tss_t;
+
+/**
+ * TPM Versions
+ */
+enum tpm_version_t {
+ TPM_VERSION_ANY,
+ TPM_VERSION_1_2,
+ TPM_VERSION_2_0,
+};
+
+/**
+ * TPM access via TSS public interface
+ */
+struct tpm_tss_t {
+
+ /**
+ * Get TPM version supported by TSS
+ *
+ * @return TPM version
+ */
+ tpm_version_t (*get_version)(tpm_tss_t *this);
+
+ /**
+ * Get TPM version info (TPM 1.2 only)
+ *
+ * @return TPM version info struct
+ */
+ chunk_t (*get_version_info)(tpm_tss_t *this);
+
+ /**
+ * Generate AIK key pair bound to TPM (TPM 1.2 only)
+ *
+ * @param ca_modulus RSA modulus of CA public key
+ * @param aik_blob AIK private key blob
+ * @param aik_pubkey AIK public key
+ * @return TRUE if AIK key generation succeeded
+ */
+ bool (*generate_aik)(tpm_tss_t *this, chunk_t ca_modulus,
+ chunk_t *aik_blob, chunk_t *aik_pubkey,
+ chunk_t *identity_req);
+
+ /**
+ * Get public key from TPM using its object handle (TPM 2.0 only)
+ *
+ * @param handle key object handle
+ * @return public key in PKCS#1 format
+ */
+ 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 quote_mode define current and legacy TPM quote modes
+ * @param quote_info returns various info covered by quote signature
+ * @param quote_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 *quote_mode,
+ tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig);
+
+ /**
+ * Destroy a tpm_tss_t.
+ */
+ void (*destroy)(tpm_tss_t *this);
+};
+
+/**
+ * Create a tpm_tss instance.
+ *
+ * @param version TPM version that must be supported by TSS
+ */
+tpm_tss_t *tpm_tss_probe(tpm_version_t version);
+
+/**
+ * Dummy libtpmtss initialization function needed for integrity test
+ */
+void libtpmtss_init(void);
+
+#endif /** TPM_TSS_H_ @}*/
diff --git a/src/libtpmtss/tpm_tss_quote_info.c b/src/libtpmtss/tpm_tss_quote_info.c
new file mode 100644
index 000000000..6a58448ee
--- /dev/null
+++ b/src/libtpmtss/tpm_tss_quote_info.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <tpm_tss_quote_info.h>
+
+#include <bio/bio_writer.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_tpm_tss_quote_info_t private_tpm_tss_quote_info_t;
+
+/**
+ * Private data of an tpm_tss_quote_info_t object.
+ */
+struct private_tpm_tss_quote_info_t {
+
+ /**
+ * Public tpm_tss_quote_info_t interface.
+ */
+ tpm_tss_quote_info_t public;
+
+ /**
+ * TPM Quote Mode
+ */
+ tpm_quote_mode_t quote_mode;
+
+ /**
+ * TPM Qualified Signer
+ */
+ chunk_t qualified_signer;
+
+ /**
+ * TPM Clock Info
+ */
+ chunk_t clock_info;
+
+ /**
+ * TPM Version Info
+ */
+ chunk_t version_info;
+
+ /**
+ * TPM PCR Selection
+ */
+ chunk_t pcr_select;
+
+ /**
+ * TPM PCR Composite Hash
+ */
+ chunk_t pcr_digest;
+
+ /**
+ * TPM PCR Composite Hash algoritm
+ */
+ hash_algorithm_t pcr_digest_alg;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
+
+};
+
+METHOD(tpm_tss_quote_info_t, get_quote_mode, tpm_quote_mode_t,
+ private_tpm_tss_quote_info_t *this)
+{
+ return this->quote_mode;
+}
+
+METHOD(tpm_tss_quote_info_t, get_pcr_digest_alg, hash_algorithm_t,
+ private_tpm_tss_quote_info_t *this)
+{
+ return this->pcr_digest_alg;
+}
+
+METHOD(tpm_tss_quote_info_t, get_pcr_digest, chunk_t,
+ private_tpm_tss_quote_info_t *this)
+{
+ return this->pcr_digest;
+}
+
+METHOD(tpm_tss_quote_info_t, get_quote, bool,
+ private_tpm_tss_quote_info_t *this, chunk_t nonce,
+ tpm_tss_pcr_composite_t *composite, chunk_t *quoted)
+{
+ chunk_t pcr_composite, pcr_digest;
+ bio_writer_t *writer;
+ hasher_t *hasher;
+ bool equal_digests;
+
+ /* Construct PCR Composite */
+ writer = bio_writer_create(32);
+
+ switch (this->quote_mode)
+ {
+ case TPM_QUOTE:
+ case TPM_QUOTE2:
+ case TPM_QUOTE2_VERSION_INFO:
+ writer->write_data16(writer, composite->pcr_select);
+ writer->write_data32(writer, composite->pcr_composite);
+
+ break;
+ case TPM_QUOTE_TPM2:
+ writer->write_data(writer, composite->pcr_composite);
+ break;
+ case TPM_QUOTE_NONE:
+ break;
+ }
+
+ pcr_composite = writer->extract_buf(writer);
+ writer->destroy(writer);
+
+ DBG2(DBG_PTS, "constructed PCR Composite: %B", &pcr_composite);
+
+ /* Compute PCR Composite Hash */
+ hasher = lib->crypto->create_hasher(lib->crypto, this->pcr_digest_alg);
+ if (!hasher || !hasher->allocate_hash(hasher, pcr_composite, &pcr_digest))
+ {
+ DESTROY_IF(hasher);
+ chunk_free(&pcr_composite);
+ return FALSE;
+ }
+ hasher->destroy(hasher);
+ chunk_free(&pcr_composite);
+
+ DBG2(DBG_PTS, "constructed PCR Composite digest: %B", &pcr_digest);
+
+ equal_digests = chunk_equals(pcr_digest, this->pcr_digest);
+
+ /* Construct Quote Info */
+ writer = bio_writer_create(32);
+
+ switch (this->quote_mode)
+ {
+ case TPM_QUOTE:
+ /* Version number */
+ writer->write_data(writer, chunk_from_chars(1, 1, 0, 0));
+
+ /* Magic QUOT value */
+ writer->write_data(writer, chunk_from_str("QUOT"));
+
+ /* PCR Composite Hash */
+ writer->write_data(writer, pcr_digest);
+
+ /* Secret assessment value 20 bytes (nonce) */
+ writer->write_data(writer, nonce);
+ break;
+ case TPM_QUOTE2:
+ case TPM_QUOTE2_VERSION_INFO:
+ /* TPM Structure Tag */
+ writer->write_uint16(writer, TPM_TAG_QUOTE_INFO2);
+
+ /* Magic QUT2 value */
+ writer->write_data(writer, chunk_from_str("QUT2"));
+
+ /* Secret assessment value 20 bytes (nonce) */
+ writer->write_data(writer, nonce);
+
+ /* PCR selection */
+ writer->write_data16(writer, composite->pcr_select);
+
+ /* TPM Locality Selection */
+ writer->write_uint8(writer, TPM_LOC_ZERO);
+
+ /* PCR Composite Hash */
+ writer->write_data(writer, pcr_digest);
+
+ if (this->quote_mode == TPM_QUOTE2_VERSION_INFO)
+ {
+ /* TPM version Info */
+ writer->write_data(writer, this->version_info);
+ }
+ break;
+ case TPM_QUOTE_TPM2:
+ /* Magic */
+ writer->write_data(writer, chunk_from_chars(0xff,0x54,0x43,0x47));
+
+ /* Type */
+ writer->write_uint16(writer, 0x8018);
+
+ /* Qualified Signer */
+ writer->write_data16(writer, this->qualified_signer);
+
+ /* Extra Data */
+ writer->write_data16(writer, nonce);
+
+ /* Clock Info */
+ writer->write_data(writer, this->clock_info);
+
+ /* Firmware Version */
+ writer->write_data(writer, this->version_info);
+
+ /* PCR Selection */
+ writer->write_data(writer, this->pcr_select);
+
+ /* PCR Composite Hash */
+ writer->write_data16(writer, pcr_digest);
+ break;
+ case TPM_QUOTE_NONE:
+ break;
+ }
+ chunk_free(&pcr_digest);
+ *quoted = writer->extract_buf(writer);
+ writer->destroy(writer);
+
+ DBG2(DBG_PTS, "constructed TPM Quote Info: %B", quoted);
+
+ if (!equal_digests)
+ {
+ DBG1(DBG_IMV, "received PCR Composite digest does not match "
+ "constructed one");
+ chunk_free(quoted);
+ }
+ return equal_digests;
+}
+
+METHOD(tpm_tss_quote_info_t, set_version_info, void,
+ private_tpm_tss_quote_info_t *this, chunk_t version_info)
+{
+ chunk_free(&this->version_info);
+ this->version_info = chunk_clone(version_info);
+}
+
+METHOD(tpm_tss_quote_info_t, get_version_info, chunk_t,
+ private_tpm_tss_quote_info_t *this)
+{
+ return this->version_info;
+}
+
+METHOD(tpm_tss_quote_info_t, set_tpm2_info, void,
+ private_tpm_tss_quote_info_t *this, chunk_t qualified_signer,
+ chunk_t clock_info, chunk_t pcr_select)
+{
+ chunk_free(&this->qualified_signer);
+ this->qualified_signer = chunk_clone(qualified_signer);
+
+ chunk_free(&this->clock_info);
+ this->clock_info = chunk_clone(clock_info);
+
+ chunk_free(&this->pcr_select);
+ this->pcr_select = chunk_clone(pcr_select);
+}
+
+METHOD(tpm_tss_quote_info_t, get_tpm2_info, void,
+ private_tpm_tss_quote_info_t *this, chunk_t *qualified_signer,
+ chunk_t *clock_info, chunk_t *pcr_select)
+{
+ if (qualified_signer)
+ {
+ *qualified_signer = this->qualified_signer;
+ }
+ if (clock_info)
+ {
+ *clock_info = this->clock_info;
+ }
+ if (pcr_select)
+ {
+ *pcr_select = this->pcr_select;
+ }
+}
+
+METHOD(tpm_tss_quote_info_t, get_ref, tpm_tss_quote_info_t*,
+ private_tpm_tss_quote_info_t *this)
+{
+ ref_get(&this->ref);
+
+ return &this->public;
+}
+
+METHOD(tpm_tss_quote_info_t, destroy, void,
+ private_tpm_tss_quote_info_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ chunk_free(&this->qualified_signer);
+ chunk_free(&this->clock_info);
+ chunk_free(&this->version_info);
+ chunk_free(&this->pcr_select);
+ chunk_free(&this->pcr_digest);
+ free(this);
+ }
+}
+
+/**
+ * See header
+ */
+tpm_tss_quote_info_t *tpm_tss_quote_info_create(tpm_quote_mode_t quote_mode,
+ hash_algorithm_t pcr_digest_alg, chunk_t pcr_digest)
+
+{
+ private_tpm_tss_quote_info_t *this;
+
+ INIT(this,
+ .public = {
+ .get_quote_mode = _get_quote_mode,
+ .get_pcr_digest_alg = _get_pcr_digest_alg,
+ .get_pcr_digest = _get_pcr_digest,
+ .get_quote = _get_quote,
+ .set_version_info = _set_version_info,
+ .get_version_info = _get_version_info,
+ .set_tpm2_info = _set_tpm2_info,
+ .get_tpm2_info = _get_tpm2_info,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .quote_mode = quote_mode,
+ .pcr_digest_alg = pcr_digest_alg,
+ .pcr_digest = chunk_clone(pcr_digest),
+ .ref = 1,
+ );
+
+ return &this->public;
+}
diff --git a/src/libtpmtss/tpm_tss_quote_info.h b/src/libtpmtss/tpm_tss_quote_info.h
new file mode 100644
index 000000000..5b1c45794
--- /dev/null
+++ b/src/libtpmtss/tpm_tss_quote_info.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup tpm_tss_quote_info tpm_tss_quote_info
+ * @{ @ingroup libtpmtss
+ */
+
+#ifndef TPM_TSS_QUOTE_INFO_H_
+#define TPM_TSS_QUOTE_INFO_H_
+
+#include <library.h>
+
+#include <crypto/hashers/hasher.h>
+
+typedef enum tpm_quote_mode_t tpm_quote_mode_t;
+typedef struct tpm_tss_quote_info_t tpm_tss_quote_info_t;
+typedef struct tpm_tss_pcr_composite_t tpm_tss_pcr_composite_t;
+
+/**
+ * TPM Quote Modes
+ */
+enum tpm_quote_mode_t {
+ TPM_QUOTE_NONE,
+ TPM_QUOTE,
+ TPM_QUOTE2,
+ TPM_QUOTE2_VERSION_INFO,
+ TPM_QUOTE_TPM2
+};
+
+struct tpm_tss_pcr_composite_t {
+
+ /**
+ * Bit map of selected PCRs
+ */
+ chunk_t pcr_select;
+
+ /**
+ * Array of selected PCRs
+ */
+ chunk_t pcr_composite;
+
+};
+
+/**
+ * TPM Quote Information needed to verify the Quote Signature
+ */
+struct tpm_tss_quote_info_t {
+
+ /**
+ * Get TPM Quote Mode
+ *
+ * @return TPM Quote Mode
+ */
+ tpm_quote_mode_t (*get_quote_mode)(tpm_tss_quote_info_t *this);
+
+ /**
+ * Get PCR Composite digest algorithm
+ *
+ * @return PCR Composite digest algorithm
+ */
+ hash_algorithm_t (*get_pcr_digest_alg)(tpm_tss_quote_info_t *this);
+
+ /**
+ * Get PCR Composite digest
+ *
+ * @return PCR Composite digest
+ */
+ chunk_t (*get_pcr_digest)(tpm_tss_quote_info_t *this);
+
+ /**
+ * Get TPM Quote Info digest, the basis of the TPM Quote Singature
+ *
+ * @param nonce Derived from the Diffie-Hellman exchange
+ * @param composite PCR Composite as computed by IMV
+ * @param quoted Encoded TPM Quote
+ * @return TRUE if TPM Quote was successfully constructed
+ */
+ bool (*get_quote)(tpm_tss_quote_info_t *this, chunk_t nonce,
+ tpm_tss_pcr_composite_t *composite,
+ chunk_t *quoted);
+
+ /**
+ * Set TPM version info (needed for TPM 1.2)
+ *
+ * @param version_info TPM 1.2 version info
+ */
+ void (*set_version_info)(tpm_tss_quote_info_t *this, chunk_t version_info);
+
+ /**
+ * Get TPM 2.0 version info (needed for TPM 2.0)
+ *
+ * @return TPM 2.0 firmwareVersioin
+ */
+ chunk_t (*get_version_info)(tpm_tss_quote_info_t *this);
+
+ /**
+ * Set TPM 2.0 info parameters (needed for TPM 2.0)
+ *
+ * @param qualified_signer TPM 2.0 qualifiedSigner
+ * @param clock_info TPM 2.0 clockInfo
+ * @param pcr_select TPM 2.0 pcrSelect
+ */
+ void (*set_tpm2_info)(tpm_tss_quote_info_t *this, chunk_t qualified_signer,
+ chunk_t clock_info, chunk_t pcr_select);
+
+
+ /**
+ * Get TPM 2.0 info parameters (needed for TPM 2.0)
+ *
+ * @param qualified_signer TPM 2.0 qualifiedSigner
+ * @param clock_info TPM 2.0 clockInfo
+ * @param pcr_select TPM 2.0 pcrSelect
+ */
+ void (*get_tpm2_info)(tpm_tss_quote_info_t *this, chunk_t *qualified_signer,
+ chunk_t *clock_info, chunk_t *pcr_select);
+
+ /**
+ * Get reference to Quote Info object.
+ */
+ tpm_tss_quote_info_t* (*get_ref)(tpm_tss_quote_info_t *this);
+
+ /**
+ * Destroy a tpm_tss_quote_info_t.
+ */
+ void (*destroy)(tpm_tss_quote_info_t *this);
+};
+
+/**
+ * Create a tpm_tss_quote_info instance.
+ *
+ * @param quote_mode TPM Quote mode
+ * @param pcr_digest_alg PCR Composite digest algorithm
+ * @param pcr_digest PCR Composite digest
+ */
+tpm_tss_quote_info_t *tpm_tss_quote_info_create(tpm_quote_mode_t quote_mode,
+ hash_algorithm_t pcr_digest_alg, chunk_t pcr_digest);
+
+#endif /** TPM_TSS_QUOTE_INFO_H_ @}*/
diff --git a/src/libtpmtss/tpm_tss_trousers.c b/src/libtpmtss/tpm_tss_trousers.c
new file mode 100644
index 000000000..8be3ad877
--- /dev/null
+++ b/src/libtpmtss/tpm_tss_trousers.c
@@ -0,0 +1,655 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * Copyright (c) 2008 Hal Finney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "tpm_tss_trousers.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>
+
+#define LABEL "TPM 1.2 -"
+
+/* size in bytes of a TSS AIK public key blob */
+#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.
+ */
+struct private_tpm_tss_trousers_t {
+
+ /**
+ * Public tpm_tss_trousers_t interface.
+ */
+ tpm_tss_trousers_t interface;
+
+ /**
+ * TSS context
+ */
+ 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
+ *
+ * TPM 1.2 Specification, Part 2 TPM Structures, 21.6 TPM_CAP_VERSION_INFO
+ *
+ * typedef struct tdTPM_VERSION {
+ * TPM_VERSION_BYTE major;
+ * TPM_VERSION_BYTE minor;
+ * BYTE revMajor;
+ * BYTE revMinor;
+ * } TPM_VERSION;
+ *
+ * typedef struct tdTPM_CAP_VERSION_INFO {
+ * TPM_STRUCTURE_TAG tag;
+ * TPM_VERSION version;
+ * UINT16 specLevel;
+ * BYTE errataRev;
+ * BYTE tpmVendorID[4];
+ * UINT16 vendorSpecificSize;
+ * [size_is(vendorSpecificSize)] BYTE* vendorSpecific;
+ * } TPM_CAP_VERSION_INFO;
+ */
+static bool initialize_context(private_tpm_tss_trousers_t *this)
+{
+ uint8_t *version_ptr;
+ uint32_t version_len;
+
+ TSS_RESULT result;
+ TPM_CAP_VERSION_INFO *info;
+
+ result = Tspi_Context_Create(&this->hContext);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s could not created context: 0x%x",
+ LABEL, result);
+ return FALSE;
+ }
+
+ result = Tspi_Context_Connect(this->hContext, NULL);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s could not connect with context: 0x%x",
+ LABEL, result);
+ return FALSE;
+ }
+
+ result = Tspi_Context_GetTpmObject (this->hContext, &this->hTPM);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s could not get TPM object: 0x%x",
+ LABEL, result);
+ return FALSE;
+ }
+
+ 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",
+ LABEL, result);
+ return FALSE;
+ }
+
+ info = (TPM_CAP_VERSION_INFO *)version_ptr;
+ 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);
+
+ this->version_info = chunk_clone(chunk_create(version_ptr, version_len));
+
+ return TRUE;
+}
+
+/**
+ * Finalize TSS context
+ */
+static void finalize_context(private_tpm_tss_trousers_t *this)
+{
+ if (this->hContext)
+ {
+ Tspi_Context_FreeMemory(this->hContext, NULL);
+ Tspi_Context_Close(this->hContext);
+ }
+}
+
+METHOD(tpm_tss_t, get_version, tpm_version_t,
+ private_tpm_tss_trousers_t *this)
+{
+ return TPM_VERSION_1_2;
+}
+
+METHOD(tpm_tss_t, get_version_info, chunk_t,
+ private_tpm_tss_trousers_t *this)
+{
+ return this->version_info;
+}
+
+METHOD(tpm_tss_t, generate_aik, bool,
+ private_tpm_tss_trousers_t *this, chunk_t ca_modulus, chunk_t *aik_blob,
+ chunk_t *aik_pubkey, chunk_t *identity_req)
+{
+ chunk_t aik_pubkey_blob;
+ chunk_t aik_modulus;
+ chunk_t aik_exponent;
+
+ TSS_RESULT result;
+ TSS_HKEY hSRK;
+ TSS_HKEY hPCAKey;
+ TSS_HPOLICY hSrkPolicy;
+ TSS_HPOLICY hTPMPolicy;
+ TSS_HKEY hIdentKey;
+ TSS_UUID SRK_UUID = TSS_UUID_SRK;
+ BYTE secret[] = TSS_WELL_KNOWN_SECRET;
+ BYTE *IdentityReq;
+ UINT32 IdentityReqLen;
+ BYTE *blob;
+ UINT32 blobLen;
+
+ /* get SRK plus SRK policy and set SRK 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, &hSrkPolicy);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s Tspi_GetPolicyObject or SRK failed: 0x%x ",
+ LABEL, result);
+ return FALSE;
+ }
+ result = Tspi_Policy_SetSecret(hSrkPolicy, 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;
+ }
+
+ /* get TPM plus TPM policy and set TPM secret */
+ 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(this->hTPM, TSS_POLICY_USAGE, &hTPMPolicy);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s Tspi_GetPolicyObject for TPM failed: 0x%x",
+ LABEL, result);
+ return FALSE;
+ }
+ result = Tspi_Policy_SetSecret(hTPMPolicy, TSS_SECRET_MODE_SHA1, 20, secret);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS,"%s Tspi_Policy_SetSecret for TPM failed: 0x%x",
+ LABEL, result);
+ return FALSE;
+ }
+
+ /* create context for a 2048 bit AIK */
+ result = Tspi_Context_CreateObject(this->hContext, TSS_OBJECT_TYPE_RSAKEY,
+ TSS_KEY_TYPE_IDENTITY | TSS_KEY_SIZE_2048 |
+ TSS_KEY_VOLATILE | TSS_KEY_NOT_MIGRATABLE, &hIdentKey);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s Tspi_Context_CreateObject for key failed: 0x%x",
+ LABEL, result);
+ return FALSE;
+ }
+
+ /* create context for the Privacy CA public key and assign modulus */
+ result = Tspi_Context_CreateObject(this->hContext, TSS_OBJECT_TYPE_RSAKEY,
+ TSS_KEY_TYPE_LEGACY|TSS_KEY_SIZE_2048, &hPCAKey);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s Tspi_Context_CreateObject for PCA failed: 0x%x",
+ LABEL, result);
+ return FALSE;
+ }
+ result = Tspi_SetAttribData (hPCAKey, TSS_TSPATTRIB_RSAKEY_INFO,
+ TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, ca_modulus.len,
+ ca_modulus.ptr);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s Tspi_SetAttribData for PCA modulus failed: 0x%x",
+ LABEL, result);
+ return FALSE;
+ }
+ result = Tspi_SetAttribUint32(hPCAKey, TSS_TSPATTRIB_KEY_INFO,
+ TSS_TSPATTRIB_KEYINFO_ENCSCHEME, TSS_ES_RSAESPKCSV15);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS,"%s Tspi_SetAttribUint32 for PCA encryption scheme "
+ "failed: 0x%x", LABEL, result);
+ return FALSE;
+ }
+
+ /* generate AIK */
+ DBG1(DBG_LIB, "Generating identity key...");
+ result = Tspi_TPM_CollateIdentityRequest(this->hTPM, hSRK, hPCAKey, 0, NULL,
+ hIdentKey, TSS_ALG_AES, &IdentityReqLen, &IdentityReq);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s Tspi_TPM_CollateIdentityRequest failed: 0x%x",
+ LABEL, result);
+ return FALSE;
+ }
+ *identity_req = chunk_create(IdentityReq, IdentityReqLen);
+ DBG3(DBG_LIB, "%s Identity Request: %B", LABEL, identity_req);
+
+ /* load identity key */
+ result = Tspi_Key_LoadKey (hIdentKey, hSRK);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s Tspi_Key_LoadKey for AIK failed: 0x%x",
+ LABEL, result);
+ return FALSE;
+ }
+
+ /* output AIK private key in TSS blob format */
+ result = Tspi_GetAttribData (hIdentKey, TSS_TSPATTRIB_KEY_BLOB,
+ TSS_TSPATTRIB_KEYBLOB_BLOB, &blobLen, &blob);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s Tspi_GetAttribData for private key blob failed: 0x%x",
+ LABEL, result);
+ return FALSE;
+ }
+ *aik_blob = chunk_create(blob, blobLen);
+ DBG3(DBG_LIB, "%s AIK private key blob: %B", LABEL, aik_blob);
+
+ /* output AIK Public Key in TSS blob format */
+ result = Tspi_GetAttribData (hIdentKey, TSS_TSPATTRIB_KEY_BLOB,
+ TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, &blobLen, &blob);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s Tspi_GetAttribData for public key blob failed: 0x%x",
+ LABEL, result);
+ return FALSE;
+ }
+ aik_pubkey_blob = chunk_create(blob, blobLen);
+ DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_pubkey_blob);
+
+ /* create a trusted AIK public key */
+ if (aik_pubkey_blob.len != AIK_PUBKEY_BLOB_SIZE)
+ {
+ DBG1(DBG_PTS, "%s AIK public key is not in TSS blob format",
+ LABEL);
+ return FALSE;
+ }
+ aik_modulus = chunk_skip(aik_pubkey_blob, AIK_PUBKEY_BLOB_SIZE - 256);
+ aik_exponent = chunk_from_chars(0x01, 0x00, 0x01);
+
+ /* output subjectPublicKeyInfo encoding of AIK public key */
+ if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER, NULL,
+ aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus,
+ CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
+ {
+ DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key failed",
+ LABEL);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(tpm_tss_t, get_public, chunk_t,
+ private_tpm_tss_trousers_t *this, uint32_t handle)
+{
+ 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 *quote_mode,
+ tpm_tss_quote_info_t **quote_info, 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_chunk, pcr_digest;
+ 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,
+ (*quote_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 = (*quote_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 = (*quote_mode == TPM_QUOTE) ?
+ Tspi_TPM_Quote (this->hTPM, hAIK, hPcrComposite, &valData) :
+ Tspi_TPM_Quote2(this->hTPM, hAIK,
+ *quote_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,
+ (*quote_mode == TPM_QUOTE) ? "" : "2", result);
+ goto err2;
+ }
+
+ if (*quote_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;
+ }
+ pcr_digest = chunk_create(comp_hash, HASH_SIZE_SHA1);
+ DBG2(DBG_PTS, "PCR composite digest: %B", &pcr_digest);
+
+ quote_chunk = chunk_create(valData.rgbData, valData.ulDataLength);
+ DBG2(DBG_PTS, "TPM Quote Info: %B", &quote_chunk);
+
+ *quote_info = tpm_tss_quote_info_create(*quote_mode, HASH_SHA1, pcr_digest);
+
+ *quote_sig = chunk_clone(chunk_create(valData.rgbValidationData,
+ valData.ulValidationDataLength));
+ DBG2(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
+ */
+tpm_tss_t *tpm_tss_trousers_create()
+{
+ private_tpm_tss_trousers_t *this;
+ bool available;
+
+ INIT(this,
+ .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);
+ DBG1(DBG_PTS, "TPM 1.2 via TrouSerS %savailable", available ? "" : "not ");
+
+ if (!available)
+ {
+ destroy(this);
+ return NULL;
+ }
+ return &this->interface.public;
+}
+
+#else /* TSS_TROUSERS */
+
+tpm_tss_t *tpm_tss_trousers_create()
+{
+ return NULL;
+}
+
+#endif /* TSS_TROUSERS */
+
+
+
diff --git a/src/libtpmtss/tpm_tss_trousers.h b/src/libtpmtss/tpm_tss_trousers.h
new file mode 100644
index 000000000..3afba0db2
--- /dev/null
+++ b/src/libtpmtss/tpm_tss_trousers.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup tpm_tss_trousers tpm_tss_trousers
+ * @{ @ingroup libtpmtss
+ */
+
+#ifndef TPM_TSS_TROUSERS_H_
+#define TPM_TSS_TROUSERS_H_
+
+#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.
+ */
+tpm_tss_t *tpm_tss_trousers_create();
+
+#endif /** TPM_TSS_TROUSERS_H_ @}*/
diff --git a/src/libtpmtss/tpm_tss_tss2.c b/src/libtpmtss/tpm_tss_tss2.c
new file mode 100644
index 000000000..79db8eeef
--- /dev/null
+++ b/src/libtpmtss/tpm_tss_tss2.c
@@ -0,0 +1,696 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "tpm_tss_tss2.h"
+#include "tpm_tss_tss2_names.h"
+
+#ifdef TSS_TSS2
+
+#include <asn1/asn1.h>
+#include <asn1/oid.h>
+#include <bio/bio_reader.h>
+
+#include <tss2/tpm20.h>
+#include <tcti/tcti_socket.h>
+
+#define LABEL "TPM 2.0 -"
+
+typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t;
+
+/**
+ * Private data of an tpm_tss_tss2_t object.
+ */
+struct private_tpm_tss_tss2_t {
+
+ /**
+ * Public tpm_tss_tss2_t interface.
+ */
+ tpm_tss_t public;
+
+ /**
+ * TCTI context
+ */
+ TSS2_TCTI_CONTEXT *tcti_context;
+
+ /**
+ * SYS context
+ */
+ TSS2_SYS_CONTEXT *sys_context;
+
+ /**
+ * Number of supported algorithms
+ */
+ size_t supported_algs_count;
+
+ /**
+ * List of supported algorithms
+ */
+ TPM_ALG_ID supported_algs[TPM_PT_ALGORITHM_SET];
+};
+
+/**
+ * Some symbols required by libtctisocket
+ */
+FILE *outFp;
+uint8_t simulator = 1;
+
+int TpmClientPrintf (uint8_t type, const char *format, ...)
+{
+ return 0;
+}
+
+/**
+ * Convert hash algorithm to TPM_ALG_ID
+ */
+static TPM_ALG_ID hash_alg_to_tpm_alg_id(hash_algorithm_t alg)
+{
+ switch (alg)
+ {
+ case HASH_SHA1:
+ return TPM_ALG_SHA1;
+ case HASH_SHA256:
+ return TPM_ALG_SHA256;
+ case HASH_SHA384:
+ return TPM_ALG_SHA384;
+ case HASH_SHA512:
+ return TPM_ALG_SHA512;
+ default:
+ return TPM_ALG_ERROR;
+ }
+}
+
+/**
+ * Convert TPM_ALG_ID to hash algorithm
+ */
+static hash_algorithm_t hash_alg_from_tpm_alg_id(TPM_ALG_ID alg)
+{
+ switch (alg)
+ {
+ case TPM_ALG_SHA1:
+ return HASH_SHA1;
+ case TPM_ALG_SHA256:
+ return HASH_SHA256;
+ case TPM_ALG_SHA384:
+ return HASH_SHA384;
+ case TPM_ALG_SHA512:
+ return HASH_SHA512;
+ default:
+ return HASH_UNKNOWN;
+ }
+}
+
+/**
+ * Check if an algorithm given by its TPM_ALG_ID is supported by the TPM
+ */
+static bool is_supported_alg(private_tpm_tss_tss2_t *this, TPM_ALG_ID alg_id)
+{
+ int i;
+
+ if (alg_id == TPM_ALG_ERROR)
+ {
+ return FALSE;
+ }
+
+ for (i = 0; i < this->supported_algs_count; i++)
+ {
+ if (this->supported_algs[i] == alg_id)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ * Get a list of supported algorithms
+ */
+static bool get_algs_capability(private_tpm_tss_tss2_t *this)
+{
+ TPMS_CAPABILITY_DATA cap_data;
+ TPMI_YES_NO more_data;
+ TPM_ALG_ID alg;
+ uint32_t rval, i;
+ size_t len = BUF_LEN;
+ char buf[BUF_LEN];
+ char *pos = buf;
+ int written;
+
+ /* get supported algorithms */
+ rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ALGS,
+ 0, TPM_PT_ALGORITHM_SET, &more_data, &cap_data, 0);
+ if (rval != TPM_RC_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s GetCapability failed for TPM_CAP_ALGS: 0x%06x",
+ LABEL, rval);
+ return FALSE;
+ }
+
+ /* Number of supported algorithms */
+ this->supported_algs_count = cap_data.data.algorithms.count;
+
+ /* store and print supported algorithms */
+ for (i = 0; i < this->supported_algs_count; i++)
+ {
+ alg = cap_data.data.algorithms.algProperties[i].alg;
+ this->supported_algs[i] = alg;
+
+ written = snprintf(pos, len, " %N", tpm_alg_id_names, alg);
+ if (written < 0 || written >= len)
+ {
+ break;
+ }
+ pos += written;
+ len -= written;
+ }
+ DBG2(DBG_PTS, "%s algorithms:%s", LABEL, buf);
+
+ /* get supported ECC curves */
+ rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ECC_CURVES,
+ 0, TPM_PT_LOADED_CURVES, &more_data, &cap_data, 0);
+ if (rval != TPM_RC_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s GetCapability failed for TPM_ECC_CURVES: 0x%06x",
+ LABEL, rval);
+ return FALSE;
+ }
+
+ /* reset print buffer */
+ pos = buf;
+ len = BUF_LEN;
+
+ /* print supported ECC curves */
+ for (i = 0; i < cap_data.data.eccCurves.count; i++)
+ {
+ written = snprintf(pos, len, " %N", tpm_ecc_curve_names,
+ cap_data.data.eccCurves.eccCurves[i]);
+ if (written < 0 || written >= len)
+ {
+ break;
+ }
+ pos += written;
+ len -= written;
+ }
+ DBG2(DBG_PTS, "%s ECC curves:%s", LABEL, buf);
+
+ return TRUE;
+}
+
+/**
+ * Initialize TSS context
+ */
+static bool initialize_context(private_tpm_tss_tss2_t *this)
+{
+ size_t tcti_context_size;
+ uint32_t sys_context_size;
+ uint32_t rval;
+
+ TCTI_SOCKET_CONF rm_if_config = { DEFAULT_HOSTNAME,
+ DEFAULT_RESMGR_TPM_PORT
+ };
+
+ TSS2_ABI_VERSION abi_version = { TSSWG_INTEROP,
+ TSS_SAPI_FIRST_FAMILY,
+ TSS_SAPI_FIRST_LEVEL,
+ TSS_SAPI_FIRST_VERSION
+ };
+
+ /* determine size of tcti context */
+ rval = InitSocketTcti(NULL, &tcti_context_size, &rm_if_config, 0);
+ if (rval != TSS2_RC_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s could not get tcti_context size: 0x%06x",
+ LABEL, rval);
+ return FALSE;
+ }
+
+ /* allocate memory for tcti context */
+ this->tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size);
+
+ /* initialize tcti context */
+ rval = InitSocketTcti(this->tcti_context, &tcti_context_size,
+ &rm_if_config, 0);
+ if (rval != TSS2_RC_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s could not get tcti_context: 0x%06x",
+ LABEL, rval);
+ return FALSE;
+ }
+
+ /* determine size of sys context */
+ sys_context_size = Tss2_Sys_GetContextSize(0);
+
+ /* allocate memory for sys context */
+ this->sys_context = malloc(sys_context_size);
+
+ /* initialize sys context */
+ rval = Tss2_Sys_Initialize(this->sys_context, sys_context_size,
+ this->tcti_context, &abi_version);
+ if (rval != TSS2_RC_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s could not get sys_context: 0x%06x",
+ LABEL, rval);
+ return FALSE;
+ }
+
+ /* get a list of supported algorithms and ECC curves */
+ return get_algs_capability(this);
+}
+
+/**
+ * Finalize TSS context
+ */
+static void finalize_context(private_tpm_tss_tss2_t *this)
+{
+ if (this->tcti_context)
+ {
+ TeardownSocketTcti(this->tcti_context);
+ }
+ if (this->sys_context)
+ {
+ Tss2_Sys_Finalize(this->sys_context);
+ free(this->sys_context);
+ }
+}
+
+METHOD(tpm_tss_t, get_version, tpm_version_t,
+ private_tpm_tss_tss2_t *this)
+{
+ return TPM_VERSION_2_0;
+}
+
+METHOD(tpm_tss_t, get_version_info, chunk_t,
+ private_tpm_tss_tss2_t *this)
+{
+ return chunk_empty;
+}
+
+/**
+ * read the public key portion of a TSS 2.0 AIK key from NVRAM
+ */
+bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle,
+ TPM2B_PUBLIC *public)
+{
+ uint32_t rval;
+
+ TPM2B_NAME name = { { sizeof(TPM2B_NAME)-2, } };
+ TPM2B_NAME qualified_name = { { sizeof(TPM2B_NAME)-2, } };
+
+ TPMS_AUTH_RESPONSE session_data;
+ TSS2_SYS_RSP_AUTHS sessions_data;
+ TPMS_AUTH_RESPONSE *session_data_array[1];
+
+ session_data_array[0] = &session_data;
+ sessions_data.rspAuths = &session_data_array[0];
+ sessions_data.rspAuthsCount = 1;
+
+ /* always send simulator platform command, ignored by true RM */
+ PlatformCommand(this->tcti_context ,MS_SIM_POWER_ON );
+ PlatformCommand(this->tcti_context, MS_SIM_NV_ON );
+
+ /* read public key for a given object handle from TPM 2.0 NVRAM */
+ rval = Tss2_Sys_ReadPublic(this->sys_context, handle, 0, public, &name,
+ &qualified_name, &sessions_data);
+
+ PlatformCommand(this->tcti_context, MS_SIM_POWER_OFF);
+
+ if (rval != TPM_RC_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s could not read public key from handle 0x%08x: 0x%06x",
+ LABEL, handle, rval);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(tpm_tss_t, generate_aik, bool,
+ private_tpm_tss_tss2_t *this, chunk_t ca_modulus, chunk_t *aik_blob,
+ chunk_t *aik_pubkey, chunk_t *identity_req)
+{
+ return FALSE;
+}
+
+METHOD(tpm_tss_t, get_public, chunk_t,
+ private_tpm_tss_tss2_t *this, uint32_t handle)
+{
+ TPM2B_PUBLIC public = { { 0, } };
+ TPM_ALG_ID sig_alg, digest_alg;
+ chunk_t aik_blob, aik_pubkey = chunk_empty;
+
+ if (!read_public(this, handle, &public))
+ {
+ return chunk_empty;
+ }
+
+ aik_blob = chunk_create((u_char*)&public, sizeof(public));
+ DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_blob);
+
+ /* convert TSS 2.0 AIK public key blot into PKCS#1 format */
+ switch (public.t.publicArea.type)
+ {
+ case TPM_ALG_RSA:
+ {
+ TPM2B_PUBLIC_KEY_RSA *rsa;
+ TPMT_RSA_SCHEME *scheme;
+ chunk_t aik_exponent, aik_modulus;
+
+ scheme = &public.t.publicArea.parameters.rsaDetail.scheme;
+ sig_alg = scheme->scheme;
+ digest_alg = scheme->details.anySig.hashAlg;
+
+ rsa = &public.t.publicArea.unique.rsa;
+ aik_modulus = chunk_create(rsa->t.buffer, rsa->t.size);
+ aik_exponent = chunk_from_chars(0x01, 0x00, 0x01);
+
+ /* subjectPublicKeyInfo encoding of AIK RSA key */
+ if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER,
+ NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus,
+ CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
+ {
+ DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key "
+ "failed", LABEL);
+ }
+ break;
+ }
+ case TPM_ALG_ECC:
+ {
+ TPMS_ECC_POINT *ecc;
+ TPMT_ECC_SCHEME *scheme;
+ chunk_t ecc_point;
+ uint8_t *pos;
+
+ scheme = &public.t.publicArea.parameters.eccDetail.scheme;
+ sig_alg = scheme->scheme;
+ digest_alg = scheme->details.anySig.hashAlg;
+
+ ecc = &public.t.publicArea.unique.ecc;
+
+ /* allocate space for bit string */
+ pos = asn1_build_object(&ecc_point, ASN1_BIT_STRING,
+ 2 + ecc->x.t.size + ecc->y.t.size);
+ /* bit string length is a multiple of octets */
+ *pos++ = 0x00;
+ /* uncompressed ECC point format */
+ *pos++ = 0x04;
+ /* copy x coordinate of ECC point */
+ memcpy(pos, ecc->x.t.buffer, ecc->x.t.size);
+ pos += ecc->x.t.size;
+ /* copy y coordinate of ECC point */
+ memcpy(pos, ecc->y.t.buffer, ecc->y.t.size);
+ /* subjectPublicKeyInfo encoding of AIK ECC key */
+ aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_build_known_oid(OID_EC_PUBLICKEY),
+ asn1_build_known_oid(ecc->x.t.size == 32 ?
+ OID_PRIME256V1 : OID_SECT384R1)),
+ ecc_point);
+ break;
+ }
+ default:
+ DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL);
+ return chunk_empty;
+ }
+ DBG1(DBG_PTS, "AIK signature algorithm is %N with %N hash",
+ tpm_alg_id_names, sig_alg, tpm_alg_id_names, digest_alg);
+ return aik_pubkey;
+}
+
+/**
+ * Configure a PCR Selection assuming a maximum of 24 registers
+ */
+static bool init_pcr_selection(private_tpm_tss_tss2_t *this, uint32_t pcrs,
+ hash_algorithm_t alg, TPML_PCR_SELECTION *pcr_sel)
+{
+ TPM_ALG_ID alg_id;
+ uint32_t pcr;
+
+ /* check if hash algorithm is supported by TPM */
+ alg_id = hash_alg_to_tpm_alg_id(alg);
+ if (!is_supported_alg(this, alg_id))
+ {
+ DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
+ LABEL, hash_algorithm_short_names, alg);
+ return FALSE;
+ }
+
+ /* initialize the PCR Selection structure,*/
+ pcr_sel->count = 1;
+ pcr_sel->pcrSelections[0].hash = alg_id;
+ pcr_sel->pcrSelections[0].sizeofSelect = 3;
+ pcr_sel->pcrSelections[0].pcrSelect[0] = 0;
+ pcr_sel->pcrSelections[0].pcrSelect[1] = 0;
+ pcr_sel->pcrSelections[0].pcrSelect[2] = 0;
+
+ /* set the selected PCRs */
+ for (pcr = 0; pcr < PLATFORM_PCR; pcr++)
+ {
+ if (pcrs & (1 << pcr))
+ {
+ pcr_sel->pcrSelections[0].pcrSelect[pcr / 8] |= ( 1 << (pcr % 8) );
+ }
+ }
+ return TRUE;
+}
+
+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)
+{
+ TPML_PCR_SELECTION pcr_selection;
+ TPML_DIGEST pcr_values;
+
+ uint32_t pcr_update_counter, rval;
+ uint8_t *pcr_value_ptr;
+ size_t pcr_value_len;
+
+ if (pcr_num >= PLATFORM_PCR)
+ {
+ DBG1(DBG_PTS, "%s maximum number of supported PCR is %d",
+ LABEL, PLATFORM_PCR);
+ return FALSE;
+ }
+
+ if (!init_pcr_selection(this, (1 << pcr_num), alg, &pcr_selection))
+ {
+ return FALSE;
+ }
+
+ /* initialize the PCR Digest structure */
+ memset(&pcr_values, 0, sizeof(TPML_DIGEST));
+
+ /* read the PCR value */
+ rval = Tss2_Sys_PCR_Read(this->sys_context, 0, &pcr_selection,
+ &pcr_update_counter, &pcr_selection, &pcr_values, 0);
+ if (rval != TPM_RC_SUCCESS)
+ {
+ DBG1(DBG_PTS, "%s PCR bank could not be read: 0x%60x",
+ LABEL, rval);
+ return FALSE;
+ }
+ pcr_value_ptr = (uint8_t *)pcr_values.digests[0].t.buffer;
+ pcr_value_len = (size_t) pcr_values.digests[0].t.size;
+
+ *pcr_value = chunk_clone(chunk_create(pcr_value_ptr, pcr_value_len));
+
+ return TRUE;
+}
+
+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 *quote_mode,
+ tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig)
+{
+ chunk_t quoted_chunk, qualified_signer, extra_data, clock_info,
+ firmware_version, pcr_select, pcr_digest;
+ hash_algorithm_t pcr_digest_alg;
+ bio_reader_t *reader;
+ uint32_t rval;
+
+ TPM2B_DATA qualifying_data;
+ TPML_PCR_SELECTION pcr_selection;
+ TPM2B_ATTEST quoted = { { sizeof(TPM2B_ATTEST)-2, } };
+ TPMT_SIG_SCHEME scheme;
+ TPMT_SIGNATURE sig;
+ TPMI_ALG_HASH hash_alg;
+ TPMS_AUTH_COMMAND session_data_cmd;
+ TPMS_AUTH_RESPONSE session_data_rsp;
+ TSS2_SYS_CMD_AUTHS sessions_data_cmd;
+ TSS2_SYS_RSP_AUTHS sessions_data_rsp;
+ TPMS_AUTH_COMMAND *session_data_cmd_array[1];
+ TPMS_AUTH_RESPONSE *session_data_rsp_array[1];
+
+ session_data_cmd_array[0] = &session_data_cmd;
+ session_data_rsp_array[0] = &session_data_rsp;
+
+ sessions_data_cmd.cmdAuths = &session_data_cmd_array[0];
+ sessions_data_rsp.rspAuths = &session_data_rsp_array[0];
+
+ sessions_data_cmd.cmdAuthsCount = 1;
+ sessions_data_rsp.rspAuthsCount = 1;
+
+ session_data_cmd.sessionHandle = TPM_RS_PW;
+ session_data_cmd.hmac.t.size = 0;
+ session_data_cmd.nonce.t.size = 0;
+
+ *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0;
+
+ qualifying_data.t.size = data.len;
+ memcpy(qualifying_data.t.buffer, data.ptr, data.len);
+
+ scheme.scheme = TPM_ALG_NULL;
+ memset(&sig, 0x00, sizeof(sig));
+
+ /* set Quote mode */
+ *quote_mode = TPM_QUOTE_TPM2;
+
+ if (!init_pcr_selection(this, pcr_sel, alg, &pcr_selection))
+ {
+ return FALSE;
+ }
+
+ rval = Tss2_Sys_Quote(this->sys_context, aik_handle, &sessions_data_cmd,
+ &qualifying_data, &scheme, &pcr_selection, &quoted,
+ &sig, &sessions_data_rsp);
+ if (rval != TPM_RC_SUCCESS)
+ {
+ DBG1(DBG_PTS,"%s Tss2_Sys_Quote failed: 0x%06x", LABEL, rval);
+ return FALSE;
+ }
+ quoted_chunk = chunk_create(quoted.t.attestationData, quoted.t.size);
+
+ reader = bio_reader_create(chunk_skip(quoted_chunk, 6));
+ if (!reader->read_data16(reader, &qualified_signer) ||
+ !reader->read_data16(reader, &extra_data) ||
+ !reader->read_data (reader, 17, &clock_info) ||
+ !reader->read_data (reader, 8, &firmware_version) ||
+ !reader->read_data (reader, 10, &pcr_select) ||
+ !reader->read_data16(reader, &pcr_digest))
+ {
+ DBG1(DBG_PTS, "%s parsing of quoted struct failed", LABEL);
+ reader->destroy(reader);
+ return FALSE;
+ }
+ reader->destroy(reader);
+
+ DBG2(DBG_PTS, "PCR Composite digest: %B", &pcr_digest);
+ DBG2(DBG_PTS, "TPM Quote Info: %B", &quoted_chunk);
+ DBG2(DBG_PTS, "qualifiedSigner: %B", &qualified_signer);
+ DBG2(DBG_PTS, "extraData: %B", &extra_data);
+ DBG2(DBG_PTS, "clockInfo: %B", &clock_info);
+ DBG2(DBG_PTS, "firmwareVersion: %B", &firmware_version);
+ DBG2(DBG_PTS, "pcrSelect: %B", &pcr_select);
+
+ /* extract signature */
+ switch (sig.sigAlg)
+ {
+ case TPM_ALG_RSASSA:
+ case TPM_ALG_RSAPSS:
+ *quote_sig = chunk_clone(
+ chunk_create(
+ sig.signature.rsassa.sig.t.buffer,
+ sig.signature.rsassa.sig.t.size));
+ hash_alg = sig.signature.rsassa.hash;
+ break;
+ case TPM_ALG_ECDSA:
+ case TPM_ALG_ECDAA:
+ case TPM_ALG_SM2:
+ case TPM_ALG_ECSCHNORR:
+ *quote_sig = chunk_cat("cc",
+ chunk_create(
+ sig.signature.ecdsa.signatureR.t.buffer,
+ sig.signature.ecdsa.signatureR.t.size),
+ chunk_create(
+ sig.signature.ecdsa.signatureS.t.buffer,
+ sig.signature.ecdsa.signatureS.t.size));
+ hash_alg = sig.signature.ecdsa.hash;
+ break;
+ default:
+ DBG1(DBG_PTS, "%s unsupported %N signature algorithm",
+ LABEL, tpm_alg_id_names, sig.sigAlg);
+ return FALSE;
+ };
+
+ DBG2(DBG_PTS, "PCR digest algorithm is %N", tpm_alg_id_names, hash_alg);
+ pcr_digest_alg = hash_alg_from_tpm_alg_id(hash_alg);
+
+ DBG2(DBG_PTS, "TPM Quote Signature: %B", quote_sig);
+
+ /* Create and initialize Quote Info object */
+ *quote_info = tpm_tss_quote_info_create(*quote_mode, pcr_digest_alg,
+ pcr_digest);
+ (*quote_info)->set_tpm2_info(*quote_info, qualified_signer, clock_info,
+ pcr_select);
+ (*quote_info)->set_version_info(*quote_info, firmware_version);
+
+ return TRUE;
+}
+
+METHOD(tpm_tss_t, destroy, void,
+ private_tpm_tss_tss2_t *this)
+{
+ finalize_context(this);
+ free(this);
+}
+
+/**
+ * See header
+ */
+tpm_tss_t *tpm_tss_tss2_create()
+{
+ private_tpm_tss_tss2_t *this;
+ bool available;
+
+ INIT(this,
+ .public = {
+ .get_version = _get_version,
+ .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,
+ },
+ );
+
+ available = initialize_context(this);
+ DBG1(DBG_PTS, "TPM 2.0 via TSS2 %savailable", available ? "" : "not ");
+
+ if (!available)
+ {
+ destroy(this);
+ return NULL;
+ }
+ return &this->public;
+}
+
+#else /* TSS_TSS2 */
+
+tpm_tss_t *tpm_tss_tss2_create()
+{
+ return NULL;
+}
+
+#endif /* TSS_TSS2 */
+
+
diff --git a/src/libtpmtss/tpm_tss_tss2.h b/src/libtpmtss/tpm_tss_tss2.h
new file mode 100644
index 000000000..f3a11e5fd
--- /dev/null
+++ b/src/libtpmtss/tpm_tss_tss2.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup tpm_tss_tss2 tpm_tss_tss2
+ * @{ @ingroup libtpmtss
+ */
+
+#ifndef TPM_TSS_TSS2_H_
+#define TPM_TSS_TSS2_H_
+
+#include "tpm_tss.h"
+
+/**
+ * Create a tpm_tss_tss2 instance.
+ */
+tpm_tss_t *tpm_tss_tss2_create();
+
+#endif /** TPM_TSS_TSS2_H_ @}*/
diff --git a/src/libtpmtss/tpm_tss_tss2_names.c b/src/libtpmtss/tpm_tss_tss2_names.c
new file mode 100644
index 000000000..dca1ff121
--- /dev/null
+++ b/src/libtpmtss/tpm_tss_tss2_names.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "tpm_tss_tss2_names.h"
+
+#ifdef TSS_TSS2
+
+#include <tss2/tpm20.h>
+
+#ifndef TPM_ALG_ECMQV
+#define TPM_ALG_ECMQV (TPM_ALG_ID)0x001D
+#endif
+
+#ifndef TPM_ALG_CAMELLIA
+#define TPM_ALG_CAMELLIA (TPM_ALG_ID)0x0026
+#endif
+
+/**
+ * TPM 2.0 algorithm ID names
+ */
+ENUM_BEGIN(tpm_alg_id_names, TPM_ALG_ERROR, TPM_ALG_RSA,
+ "ERROR",
+ "RSA"
+);
+ENUM_NEXT(tpm_alg_id_names, TPM_ALG_SHA1, TPM_ALG_KEYEDHASH, TPM_ALG_RSA,
+ "SHA1",
+ "HMAC",
+ "AES",
+ "MGF1",
+ "KEYEDHASH"
+);
+ENUM_NEXT(tpm_alg_id_names, TPM_ALG_XOR, TPM_ALG_SHA512, TPM_ALG_KEYEDHASH,
+ "XOR",
+ "SHA256",
+ "SHA384",
+ "SHA512"
+);
+ENUM_NEXT(tpm_alg_id_names, TPM_ALG_NULL, TPM_ALG_NULL, TPM_ALG_SHA512,
+ "NULL"
+);
+ENUM_NEXT(tpm_alg_id_names, TPM_ALG_SM3_256, TPM_ALG_ECMQV, TPM_ALG_NULL,
+ "SM3_256",
+ "SM4",
+ "RSASSA",
+ "RSAES",
+ "RSAPSS",
+ "OAEP",
+ "ECDSA",
+ "ECDH",
+ "SM2",
+ "ECSCHNORR",
+ "ECMQV"
+);
+ENUM_NEXT(tpm_alg_id_names, TPM_ALG_KDF1_SP800_56A, TPM_ALG_ECC, TPM_ALG_ECMQV,
+ "KDF1_SP800_56A",
+ "KDF2",
+ "KDF1_SP800_108",
+ "ECC"
+);
+ENUM_NEXT(tpm_alg_id_names, TPM_ALG_SYMCIPHER, TPM_ALG_CAMELLIA, TPM_ALG_ECC,
+ "SYMCIPHER",
+ "CAMELLIA"
+);
+ENUM_NEXT(tpm_alg_id_names, TPM_ALG_CTR, TPM_ALG_ECB, TPM_ALG_CAMELLIA,
+ "CTR",
+ "OFB",
+ "CBC",
+ "CFB",
+ "ECB"
+);
+ENUM_END(tpm_alg_id_names, TPM_ALG_ECB);
+
+/**
+ * TPM 2.0 ECC curve names
+ */
+ENUM_BEGIN(tpm_ecc_curve_names, TPM_ECC_NONE, TPM_ECC_NIST_P521,
+ "NONE",
+ "NIST_P192",
+ "NIST_P224",
+ "NIST_P256",
+ "NIST_P384",
+ "NIST_P521"
+);
+ENUM_NEXT(tpm_ecc_curve_names, TPM_ECC_BN_P256, TPM_ECC_BN_P638, TPM_ECC_NIST_P521,
+ "BN_P256",
+ "BN_P638"
+);
+ENUM_NEXT(tpm_ecc_curve_names, TPM_ECC_SM2_P256, TPM_ECC_SM2_P256, TPM_ECC_BN_P638,
+ "SM2_P256"
+);
+ENUM_END(tpm_ecc_curve_names, TPM_ECC_SM2_P256);
+
+#else /* TSS_TSS2 */
+
+/**
+ * TPM 2.0 algorithm ID names
+ */
+ENUM(tpm_alg_id_names, 0, 0,
+ "ERROR"
+);
+
+/**
+ * TPM 2.0 ECC curve names
+ */
+ENUM(tpm_ecc_curve_names, 0, 0,
+ "NONE"
+);
+
+#endif /* TSS_TSS2 */
+
+
diff --git a/src/libtpmtss/tpm_tss_tss2_names.h b/src/libtpmtss/tpm_tss_tss2_names.h
new file mode 100644
index 000000000..290c51702
--- /dev/null
+++ b/src/libtpmtss/tpm_tss_tss2_names.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup tpm_tss_tss_names tpm_tss_tss_names
+ * @{ @ingroup libtpmtss
+ */
+
+#ifndef TPM_TSS_TSS2_NAMES_H_
+#define TPM_TSS_TSS2_NAMES_H_
+
+#include <library.h>
+
+extern enum_name_t *tpm_alg_id_names;
+
+extern enum_name_t *tpm_ecc_curve_names;
+
+#endif /** TPM_TSS_TSS2_NAMES_H_ @}*/