diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2016-06-02 23:01:11 +0200 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2016-06-22 15:33:43 +0200 |
commit | c08753bdf4310d91d6fcddede17805f39a9503b2 (patch) | |
tree | 745d102b76f9a6a3a00b630b19578acba3ffa284 | |
parent | 63377708450a9a02be8e06f46e64361402801794 (diff) | |
download | strongswan-c08753bdf4310d91d6fcddede17805f39a9503b2.tar.bz2 strongswan-c08753bdf4310d91d6fcddede17805f39a9503b2.tar.xz |
Created libtpmtss library handling access to v1.2 and v2.0 TPMs
-rw-r--r-- | conf/options/aikgen2.opt | 2 | ||||
-rw-r--r-- | conf/options/aikpub2.opt | 2 | ||||
-rw-r--r-- | configure.ac | 19 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/aikgen/Makefile.am | 9 | ||||
-rw-r--r-- | src/aikgen/aikgen.c | 214 | ||||
-rw-r--r-- | src/aikpub2/Makefile.am | 10 | ||||
-rw-r--r-- | src/aikpub2/aikpub2.c | 219 | ||||
-rw-r--r-- | src/libtpmtss/Makefile.am | 23 | ||||
-rw-r--r-- | src/libtpmtss/tpm_tss.c | 46 | ||||
-rw-r--r-- | src/libtpmtss/tpm_tss.h | 83 | ||||
-rw-r--r-- | src/libtpmtss/tpm_tss_trousers.c | 332 | ||||
-rw-r--r-- | src/libtpmtss/tpm_tss_trousers.h | 31 | ||||
-rw-r--r-- | src/libtpmtss/tpm_tss_tss2.c | 305 | ||||
-rw-r--r-- | src/libtpmtss/tpm_tss_tss2.h | 31 |
15 files changed, 927 insertions, 403 deletions
diff --git a/conf/options/aikgen2.opt b/conf/options/aikgen2.opt deleted file mode 100644 index 2acab4ebf..000000000 --- a/conf/options/aikgen2.opt +++ /dev/null @@ -1,2 +0,0 @@ -aikgen2.load = - Plugins to load in aikgen2 tool. diff --git a/conf/options/aikpub2.opt b/conf/options/aikpub2.opt new file mode 100644 index 000000000..6a755d211 --- /dev/null +++ b/conf/options/aikpub2.opt @@ -0,0 +1,2 @@ +aikpub2.load = + Plugins to load in aikpub2 tool. diff --git a/configure.ac b/configure.ac index f067fa7eb..3777a4841 100644 --- a/configure.ac +++ b/configure.ac @@ -62,8 +62,6 @@ ARG_WITH_SUBST([routing-table], [220], [set routing table to use for IPsec ARG_WITH_SUBST([routing-table-prio], [220], [set priority for IPsec routing table]) ARG_WITH_SUBST([ipsec-script], [ipsec], [change the name of the ipsec script]) ARG_WITH_SUBST([fips-mode], [0], [set openssl FIPS mode: disabled(0), enabled(1), Suite B enabled(2)]) - -ARG_WITH_SET([tss], [no], [set implementation of the Trusted Computing Group's Software Stack (TSS). Currently the only supported value is "trousers"]) ARG_WITH_SET([capabilities], [no], [set capability dropping library. Currently supported values are "libcap" and "native"]) ARG_WITH_SET([mpz_powm_sec], [yes], [use the more side-channel resistant mpz_powm_sec in libgmp, if available]) ARG_WITH_SET([dev-headers], [no], [install strongSwan development headers to directory.]) @@ -303,6 +301,9 @@ ARG_ENABL_SET([python-eggs], [enable build of provided python eggs.]) ARG_ENABL_SET([python-eggs-install],[enable installation of provided python eggs.]) ARG_ENABL_SET([perl-cpan], [enable build of provided perl CPAN module.]) ARG_ENABL_SET([perl-cpan-install],[enable installation of provided CPAN module.]) +ARG_ENABL_SET([tss-trousers], [enable the use of the TrouSerS Trusted Software Stack]) +ARG_ENABL_SET([tss-tss2], [enable the use of the TSS 2.0 Trusted Software Stack]) + # compile options ARG_ENABL_SET([coverage], [enable lcov coverage report generation.]) ARG_ENABL_SET([leak-detective], [enable malloc hooks to find memory leaks.]) @@ -961,16 +962,16 @@ if test x$systemd = xtrue; then ) fi -if test x$tss = xtrousers; then +if test x$tss_trousers = xtrue; then AC_CHECK_LIB([tspi],[main],[LIBS="$LIBS"],[AC_MSG_ERROR([TrouSerS library libtspi not found])],[]) AC_CHECK_HEADER([trousers/tss.h],,[AC_MSG_ERROR([TrouSerS header trousers/tss.h not found!])]) - AC_DEFINE([TSS_TROUSERS], [], [use TrouSerS library libtspi as TSS implementation]) + AC_DEFINE([TSS_TROUSERS], [], [use TrouSerS library libtspi]) fi -if test x$tss = xtss2; then +if test x$tss_tss2 = xtrue; then AC_CHECK_LIB([tss2],[main],[LIBS="$LIBS"],[AC_MSG_ERROR([TTS 2.0 library libtss2 not found])],[]) AC_CHECK_HEADER([tss2/tpm20.h],,[AC_MSG_ERROR([TSS 2.0 header tss2/tpm20.h not found!])]) - AC_DEFINE([TSS_TSS2], [], [use TSS 2.0 library libtss2 as TSS implementation]) + AC_DEFINE([TSS_TSS2], [], [use TSS 2.0 library libtss2]) fi if test x$imv_swid = xtrue; then PKG_CHECK_MODULES(json, [json-c], [], @@ -1623,6 +1624,7 @@ AM_CONDITIONAL(USE_LIBIPSEC, test x$libipsec = xtrue) AM_CONDITIONAL(USE_LIBTNCIF, test x$tnc_tnccs = xtrue -o x$imcv = xtrue) AM_CONDITIONAL(USE_LIBTNCCS, test x$tnc_tnccs = xtrue) AM_CONDITIONAL(USE_LIBPTTLS, test x$tnc_tnccs = xtrue) +AM_CONDITIONAL(USE_LIBTPMTSS, test x$tss_trousers = xtrue -o x$tss_tss2 = xtrue -o x$aikgen = xtrue -o x$aikpub2 = xtrue ) AM_CONDITIONAL(USE_FILE_CONFIG, test x$stroke = xtrue) AM_CONDITIONAL(USE_IPSEC_SCRIPT, test x$stroke = xtrue -o x$scepclient = xtrue -o x$conftest = xtrue) AM_CONDITIONAL(USE_LIBCAP, test x$capabilities = xlibcap) @@ -1632,8 +1634,8 @@ AM_CONDITIONAL(USE_SIMAKA, test x$simaka = xtrue) AM_CONDITIONAL(USE_TLS, test x$tls = xtrue) AM_CONDITIONAL(USE_RADIUS, test x$radius = xtrue) AM_CONDITIONAL(USE_IMCV, test x$imcv = xtrue) -AM_CONDITIONAL(USE_TROUSERS, test x$tss = xtrousers -o x$aikgen = xtrue) -AM_CONDITIONAL(USE_TSS2, test x$tss = xtss2 -o x$aikpub2 = xtrue) +AM_CONDITIONAL(USE_TROUSERS, test x$tss_trousers = xtrue -o x$aikgen = xtrue) +AM_CONDITIONAL(USE_TSS2, test x$tss_tss2 = xtrue -o x$aikpub2 = xtrue) AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue) AM_CONDITIONAL(USE_SILENT_RULES, test x$enable_silent_rules = xyes) AM_CONDITIONAL(COVERAGE, test x$coverage = xtrue) @@ -1874,6 +1876,7 @@ AC_CONFIG_FILES([ src/libcharon/plugins/attr/Makefile src/libcharon/plugins/attr_sql/Makefile src/libcharon/tests/Makefile + src/libtpmtss/Makefile src/stroke/Makefile src/ipsec/Makefile src/starter/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 4e4dfca56..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 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 6d04fc1ca..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> @@ -47,9 +34,6 @@ /* 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"); + 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) + /* 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_Connect", result); + exit_aikgen("no TPM 1.2 found"); } - /* 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) + if (!tpm->generate_aik(tpm, ca_modulus, &aik_blob, &aik_pubkey, + &identity_req)) { - 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); - } - - /* 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) - { - exit_aikgen("tss 0x%x on Tspi_Context_CreateObject for key", result); + exit_aikgen("could not generate AIK"); } - /* 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) - { - exit_aikgen("tss 0x%x on Tspi_SetAttribUint32 for PCA " - "encryption scheme", result); - } - - /* 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/Makefile.am b/src/aikpub2/Makefile.am index c43435f5e..a9ab13870 100644 --- a/src/aikpub2/Makefile.am +++ b/src/aikpub2/Makefile.am @@ -2,14 +2,14 @@ bin_PROGRAMS = aikpub2 aikpub2_SOURCES = aikpub2.c -aikpub2_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -aikpub2.o : $(top_builddir)/config.status +aikpub2_LDADD = \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(top_builddir)/src/libtpmtss/libtpmtss.la -if USE_TSS2 - aikpub2_LDADD += -ltctisocket -ltss2 -endif +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 index feaca72a5..fea58ed27 100644 --- a/src/aikpub2/aikpub2.c +++ b/src/aikpub2/aikpub2.c @@ -13,14 +13,11 @@ * for more details. */ +#include "tpm_tss.h" + #include <library.h> #include <utils/debug.h> #include <utils/optionsfrom.h> -#include <asn1/asn1.h> -#include <asn1/oid.h> - -#include <tss2/tpm20.h> -#include <tcti/tcti_socket.h> #include <syslog.h> #include <getopt.h> @@ -29,7 +26,7 @@ /* default directory where AIK keys are stored */ #define AIK_DIR IPSEC_CONFDIR "/pts/" -/* default name of AIK private key blob */ +/* default name of AIK public key blob */ #define DEFAULT_FILENAME_AIKPUBKEY AIK_DIR "aikPub.der" /* logging */ @@ -40,8 +37,6 @@ static level_t default_loglevel = 1; /* options read by optionsfrom */ options_t *options; -/* global variables */ -chunk_t aik_blob; chunk_t aik_pubkey; chunk_t aik_keyid; @@ -105,13 +100,12 @@ 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_aikpub2(err_t message, ...) { int status = 0; - free(aik_blob.ptr); free(aik_pubkey.ptr); free(aik_keyid.ptr); options->destroy(options); @@ -126,7 +120,7 @@ static void exit_aikpub2(err_t message, ...) vsnprintf(m, sizeof(m), message, args); va_end(args); - fprintf(stderr, "error: %s\n", m); + fprintf(stderr, "aikpub2 error: %s\n", m); status = -1; } library_deinit(); @@ -142,12 +136,11 @@ static void exit_aikpub2(err_t message, ...) static void usage(const char *message) { fprintf(stderr, - "Usage: aikpub2 [--in <filename>|--handle <handle>] --out <filename>\n" + "Usage: aikpub2 --handle <handle> --out <filename>\n" " [--force] [--quiet] [--debug <level>]\n" - " aikpub2 --help\n" + " aikpub2 --help\n" "\n" "Options:\n" - " --in (-i) TSS 2.0 AIK public key blob\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" @@ -160,105 +153,9 @@ static void usage(const char *message) exit_aikpub2(message); } -/** - * Some symbols required by libtctisocket - */ -FILE *outFp; -uint8_t simulator = 1; - -int TpmClientPrintf (uint8_t type, const char *format, ...) -{ - return 0; -} /** - * read the public key portion of a TSS 2.0 AIK key from NVRAM - */ -void read_public(TPMI_DH_OBJECT handle, TPM2B_PUBLIC *public) -{ - size_t tcti_context_size; - uint32_t sys_context_size, 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 - }; - - TPM2B_NAME name = { { sizeof(TPM2B_NAME)-2, } }; - TPM2B_NAME qualified_name = { { sizeof(TPM2B_NAME)-2, } }; - - TSS2_TCTI_CONTEXT *tcti_context; - TSS2_SYS_CONTEXT *sys_context; - - 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; - - /* determine size of tcti context */ - rval = InitSocketTcti(NULL, &tcti_context_size, &rm_if_config, 0); - if (rval != TSS2_RC_SUCCESS) - { - exit_aikpub2("could not get tcti_context size: 0x%06x", rval); - } - - /* allocate memory for tcti context */ - tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size); - - /* initialize tcti context */ - rval = InitSocketTcti(tcti_context, &tcti_context_size, &rm_if_config, 0); - if (rval != TSS2_RC_SUCCESS) - { - exit_aikpub2("could not get tcti_context: 0x%06x", rval); - } - - /* determine size of sys context */ - sys_context_size = Tss2_Sys_GetContextSize(0); - - /* allocate memory for sys context */ - sys_context = malloc(sys_context_size); - - /* initialize sys context */ - rval = Tss2_Sys_Initialize(sys_context, sys_context_size, tcti_context, - &abi_version); - if (rval != TSS2_RC_SUCCESS) - { - TeardownSocketTcti(tcti_context); - exit_aikpub2("could not get sys_context: 0x%06x", rval); - } - - /* always send simulator platform command, ignored by true RM */ - PlatformCommand(tcti_context ,MS_SIM_POWER_ON ); - PlatformCommand(tcti_context, MS_SIM_NV_ON ); - - /* read public key for a given object handle from TPM 2.0 NVRAM */ - rval = Tss2_Sys_ReadPublic(sys_context, handle, 0, public, &name, - &qualified_name, &sessions_data); - - PlatformCommand(tcti_context, MS_SIM_POWER_OFF); - - /* clean up connection to TPM 2.0 */ - TeardownSocketTcti(tcti_context); - Tss2_Sys_Finalize(sys_context); - free(sys_context); - - if (rval != TPM_RC_SUCCESS) - { - exit_aikpub2("could not read TSS 2.0 public key from handle 0x%08x:" - " 0x%06x", handle, rval); - } -} - -/** - * @brief main of aikpub2 which generates an Attestation Identity Key (AIK) + * @brief main of aikpub2 which extracts an Attestation Identity Key (AIK) * * @param argc number of arguments * @param argv pointer to the argument values @@ -269,15 +166,11 @@ int main(int argc, char *argv[]) extern char * optarg; extern int optind; - uint32_t aik_handle = 0; - char *aik_in_filename = NULL; char *aik_out_filename = DEFAULT_FILENAME_AIKPUBKEY; - chunk_t *aik_mapped; + uint32_t aik_handle = 0; bool force = FALSE; hasher_t *hasher; - - /* TSS 2.0 variables */ - TPM2B_PUBLIC public = { { 0, } }; + tpm_tss_t *tpm; atexit(library_deinit); if (!library_init(NULL, "aikpub2")) @@ -331,10 +224,6 @@ int main(int argc, char *argv[]) aik_handle = strtoll(optarg, NULL, 16); continue; - case 'i': /* --in <filename> */ - aik_in_filename = optarg; - continue; - case 'o': /* --out <filename> */ aik_out_filename = optarg; continue; @@ -365,90 +254,26 @@ int main(int argc, char *argv[]) { exit_aikpub2("plugin loading failed"); } - if (!aik_in_filename && !aik_handle) + if (!aik_handle) { - usage("either --in or --handle option is required"); + usage("--handle option is required"); } - if (aik_handle) - { - /* read public key blob directly from TPM 2.0 */ - read_public(aik_handle, &public); - aik_blob = chunk_clone(chunk_create((u_char*)&public, sizeof(public))); - } - else + /* try to find a TPM 2.0 */ + tpm = tpm_tss_probe(TPM_VERSION_2_0); + if (!tpm) { - /* read stored TPM 2.0 public key blob from a file */ - aik_mapped = chunk_map(aik_in_filename, FALSE); - if (!aik_mapped) - { - exit_aikpub2("could not read TSS 2.0 public key file '%s'", - aik_in_filename); - } - aik_blob = chunk_clone(*aik_mapped); - chunk_unmap(aik_mapped); - - if (aik_blob.len != sizeof(TPM2B_PUBLIC)) - { - exit_aikpub2("size of aikblob is not %d bytes", - sizeof(TPM2B_PUBLIC)); - } - public = *(TPM2B_PUBLIC*)aik_blob.ptr; + exit_aikpub2("no TPM 2.0 found"); } - DBG3(DBG_LIB, "TSS 2.0 AIK blob: %B", &aik_blob); + /* get AIK public key from TPM */ + aik_pubkey = tpm->get_public(tpm, aik_handle); + tpm->destroy(tpm); - switch (public.t.publicArea.type) + /* exit if AIK public key retrieval failed */ + if (aik_pubkey.len == 0) { - case TPM_ALG_RSA: - { - TPM2B_PUBLIC_KEY_RSA *rsa; - chunk_t aik_exponent, aik_modulus; - - 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)) - { - exit_aikpub2("subjectPublicKeyInfo encoding of AIK key failed"); - } - break; - } - case TPM_ALG_ECC: - { - TPMS_ECC_POINT *ecc; - chunk_t ecc_point; - uint8_t *pos; - - 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: - exit_aikpub2("unsupported key type"); + exit_aikpub2("retrieval of AIK public key failed"); } /* store AIK subjectPublicKeyInfo to file */ diff --git a/src/libtpmtss/Makefile.am b/src/libtpmtss/Makefile.am new file mode 100644 index 000000000..94058bc18 --- /dev/null +++ b/src/libtpmtss/Makefile.am @@ -0,0 +1,23 @@ +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_trousers.h tpm_tss_trousers.c \ + tpm_tss_tss2.h tpm_tss_tss2.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..687f9f398 --- /dev/null +++ b/src/libtpmtss/tpm_tss.c @@ -0,0 +1,46 @@ +/* + * 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" + +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..1442cc402 --- /dev/null +++ b/src/libtpmtss/tpm_tss.h @@ -0,0 +1,83 @@ +/* + * 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 <library.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); + + /** + * 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); + + /** + * 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); + +#endif /** TPM_TSS_H_ @}*/ diff --git a/src/libtpmtss/tpm_tss_trousers.c b/src/libtpmtss/tpm_tss_trousers.c new file mode 100644 index 000000000..99d413254 --- /dev/null +++ b/src/libtpmtss/tpm_tss_trousers.c @@ -0,0 +1,332 @@ +/* + * 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 + +#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 + +typedef struct private_tpm_tss_trousers_t private_tpm_tss_trousers_t; + +/** + * Private data of an tpm_tss_trousers_t object. + */ +struct private_tpm_tss_trousers_t { + + /** + * Public tpm_tss_trousers_t interface. + */ + tpm_tss_t public; + + /** + * TSS context + */ + TSS_HCONTEXT hContext; + +}; + +/** + * Initialize TSS context + */ +static bool initialize_context(private_tpm_tss_trousers_t *this) +{ + TSS_HTPM hTPM; + TSS_RESULT result; + + 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, &hTPM); + if (result != TSS_SUCCESS) + { + DBG1(DBG_PTS, "%s could not get TPM object: 0x%x", LABEL, result); + return FALSE; + } + 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, 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_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; + + /* 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, &hTPM); + if (result != TSS_SUCCESS) + { + DBG1(DBG_PTS, "%s Tspi_Context_GetTpmObject failed: 0x%x", + LABEL, result); + return FALSE; + } + result = Tspi_GetPolicyObject(hTPM, TSS_POLICY_USAGE, &hTPMPolicy); + 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(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) +{ + return chunk_empty; +} + +METHOD(tpm_tss_t, destroy, void, + private_tpm_tss_trousers_t *this) +{ + finalize_context(this); + free(this); +} + +/** + * See header + */ +tpm_tss_t *tpm_tss_trousers_create() +{ + private_tpm_tss_trousers_t *this; + bool available; + + INIT(this, + .public = { + .get_version = _get_version, + .generate_aik = _generate_aik, + .get_public = _get_public, + .destroy = _destroy, + }, + ); + + available = initialize_context(this); + DBG1(DBG_PTS, "TPM 1.2 via TrouSerS %savailable", available ? "" : "not "); + + if (!available) + { + destroy(this); + return NULL; + } + return &this->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..a52d73afa --- /dev/null +++ b/src/libtpmtss/tpm_tss_trousers.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_trousers tpm_tss_trousers + * @{ @ingroup libtpmtss + */ + +#ifndef TPM_TSS_TROUSERS_H_ +#define TPM_TSS_TROUSERS_H_ + +#include "tpm_tss.h" + +/** + * 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..75d25b073 --- /dev/null +++ b/src/libtpmtss/tpm_tss_tss2.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_tss2.h" + +#ifdef TSS_TSS2 + +#include <asn1/asn1.h> +#include <asn1/oid.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; + +}; + +/** + * Some symbols required by libtctisocket + */ +FILE *outFp; +uint8_t simulator = 1; + +int TpmClientPrintf (uint8_t type, const char *format, ...) +{ + return 0; +} + +/** + * 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; + } + return TRUE; +} + +/** + * 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; +} + +/** + * 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, } }; + 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; + chunk_t aik_exponent, aik_modulus; + + 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; + chunk_t ecc_point; + uint8_t *pos; + + 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 aik_pubkey; +} + +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, + .generate_aik = _generate_aik, + .get_public = _get_public, + .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_ @}*/ |