diff options
Diffstat (limited to 'src')
40 files changed, 3168 insertions, 995 deletions
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, "e_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, "e_mode, "e_info, "e_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, "e_info, "e_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, "e_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, "ed)) { - 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("ed); /** * 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","e_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, "e_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", "e_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, "ed, + &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", "ed_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_ @}*/ |