aikgen generates AIK private/public key pairs
authorAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 2 May 2014 18:10:53 +0000 (20:10 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 3 May 2014 13:28:17 +0000 (15:28 +0200)
aikgen outputs a binary AIK private key blob and the AIK public key.
Optionally the Identity Request encrypted with the public key of
the Privacy CA can be output.

configure.ac
src/Makefile.am
src/aikgen/.gitignore [new file with mode: 0644]
src/aikgen/Makefile.am [new file with mode: 0644]
src/aikgen/aikgen.c [new file with mode: 0644]
src/ipsec/_ipsec.in

index 1db7da5..4aae79d 100644 (file)
@@ -266,6 +266,7 @@ ARG_ENABL_SET([nm],             [enable NetworkManager backend.])
 ARG_DISBL_SET([scripts],        [disable additional utilities (found in directory scripts).])
 ARG_ENABL_SET([tkm],            [enable Trusted Key Manager support.])
 ARG_DISBL_SET([tools],          [disable additional utilities (scepclient and pki).])
+ARG_ENABL_SET([aikgen],         [enable AIK generator.])
 # optional features
 ARG_ENABL_SET([bfd-backtraces], [use binutils libbfd to resolve backtraces for memory leaks and segfaults.])
 ARG_DISBL_SET([ikev1],          [disable IKEv1 protocol support in charon.])
@@ -1078,6 +1079,7 @@ manager_plugins=
 medsrv_plugins=
 nm_plugins=
 cmd_plugins=
+aikgen_plugins=
 
 # location specific lists for checksumming,
 # for src/libcharon, src/libhydra, src/libstrongswan and src/libtnccs
@@ -1098,19 +1100,19 @@ ADD_PLUGIN([aes],                  [s charon scepclient pki scripts nm cmd])
 ADD_PLUGIN([des],                  [s charon scepclient pki scripts nm cmd])
 ADD_PLUGIN([blowfish],             [s charon scepclient pki scripts nm cmd])
 ADD_PLUGIN([rc2],                  [s charon scepclient pki scripts nm cmd])
-ADD_PLUGIN([sha1],                 [s charon scepclient pki scripts medsrv attest nm cmd])
-ADD_PLUGIN([sha2],                 [s charon scepclient pki scripts medsrv attest nm cmd])
+ADD_PLUGIN([sha1],                 [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
+ADD_PLUGIN([sha2],                 [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
 ADD_PLUGIN([md4],                  [s charon manager scepclient pki nm cmd])
-ADD_PLUGIN([md5],                  [s charon scepclient pki scripts attest nm cmd])
-ADD_PLUGIN([rdrand],               [s charon scepclient pki scripts medsrv attest nm cmd])
-ADD_PLUGIN([random],               [s charon scepclient pki scripts medsrv attest nm cmd])
-ADD_PLUGIN([nonce],                [s charon nm cmd])
-ADD_PLUGIN([x509],                 [s charon scepclient pki scripts attest nm cmd])
+ADD_PLUGIN([md5],                  [s charon scepclient pki scripts attest nm cmd aikgen])
+ADD_PLUGIN([rdrand],               [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
+ADD_PLUGIN([random],               [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
+ADD_PLUGIN([nonce],                [s charon nm cmd aikgen])
+ADD_PLUGIN([x509],                 [s charon scepclient pki scripts attest nm cmd aikgen])
 ADD_PLUGIN([revocation],           [s charon nm cmd])
 ADD_PLUGIN([constraints],          [s charon nm cmd])
 ADD_PLUGIN([acert],                [s charon])
-ADD_PLUGIN([pubkey],               [s charon cmd])
-ADD_PLUGIN([pkcs1],                [s charon scepclient pki scripts manager medsrv attest nm cmd])
+ADD_PLUGIN([pubkey],               [s charon cmd aikgen])
+ADD_PLUGIN([pkcs1],                [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
 ADD_PLUGIN([pkcs7],                [s charon scepclient pki scripts nm cmd])
 ADD_PLUGIN([pkcs8],                [s charon scepclient pki scripts manager medsrv attest nm cmd])
 ADD_PLUGIN([pkcs12],               [s charon scepclient pki scripts cmd])
@@ -1119,13 +1121,13 @@ ADD_PLUGIN([dnskey],               [s charon pki])
 ADD_PLUGIN([sshkey],               [s charon pki nm cmd])
 ADD_PLUGIN([dnscert],              [c charon])
 ADD_PLUGIN([ipseckey],             [c charon])
-ADD_PLUGIN([pem],                  [s charon scepclient pki scripts manager medsrv attest nm cmd])
+ADD_PLUGIN([pem],                  [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
 ADD_PLUGIN([padlock],              [s charon])
-ADD_PLUGIN([openssl],              [s charon scepclient pki scripts manager medsrv attest nm cmd])
-ADD_PLUGIN([gcrypt],               [s charon scepclient pki scripts manager medsrv attest nm cmd])
-ADD_PLUGIN([af-alg],               [s charon scepclient pki scripts medsrv attest nm cmd])
+ADD_PLUGIN([openssl],              [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
+ADD_PLUGIN([gcrypt],               [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
+ADD_PLUGIN([af-alg],               [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
 ADD_PLUGIN([fips-prf],             [s charon nm cmd])
-ADD_PLUGIN([gmp],                  [s charon scepclient pki scripts manager medsrv attest nm cmd])
+ADD_PLUGIN([gmp],                  [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
 ADD_PLUGIN([agent],                [s charon nm cmd])
 ADD_PLUGIN([keychain],             [s charon cmd])
 ADD_PLUGIN([xcbc],                 [s charon nm cmd])
@@ -1214,6 +1216,7 @@ AC_SUBST(manager_plugins)
 AC_SUBST(medsrv_plugins)
 AC_SUBST(nm_plugins)
 AC_SUBST(cmd_plugins)
+AC_SUBST(aikgen_plugins)
 
 AC_SUBST(c_plugins)
 AC_SUBST(h_plugins)
@@ -1378,7 +1381,7 @@ AM_CONDITIONAL(USE_NM, test x$nm = xtrue)
 AM_CONDITIONAL(USE_TOOLS, test x$tools = xtrue)
 AM_CONDITIONAL(USE_SCRIPTS, test x$scripts = xtrue)
 AM_CONDITIONAL(USE_CONFTEST, test x$conftest = xtrue)
-AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$tools = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$tls = xtrue -o x$tnc_tnccs = xtrue)
+AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$tools = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$tls = xtrue -o x$tnc_tnccs = xtrue -o x$aikgen = xtrue)
 AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue)
 AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue)
 AM_CONDITIONAL(USE_LIBIPSEC, test x$libipsec = xtrue)
@@ -1395,12 +1398,13 @@ 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_PTS, test x$pts = xtrue)
-AM_CONDITIONAL(USE_TROUSERS, test x$tss = xtrousers)
+AM_CONDITIONAL(USE_TROUSERS, test x$tss = xtrousers -o x$aikgen = 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)
 AM_CONDITIONAL(USE_TKM, test x$tkm = xtrue)
 AM_CONDITIONAL(USE_CMD, test x$cmd = xtrue)
+AM_CONDITIONAL(USE_AIKGEN, test x$aikgen = xtrue)
 
 # ========================
 #  set global definitions
@@ -1604,6 +1608,7 @@ AC_CONFIG_FILES([
        src/_updown_espmark/Makefile
        src/_copyright/Makefile
        src/scepclient/Makefile
+       src/aikgen/Makefile
        src/pki/Makefile
        src/pki/man/Makefile
        src/pool/Makefile
index 93da489..e76eb43 100644 (file)
@@ -119,3 +119,7 @@ endif
 if USE_INTEGRITY_TEST
   SUBDIRS += checksum
 endif
+
+if USE_AIKGEN
+  SUBDIRS += aikgen
+endif
diff --git a/src/aikgen/.gitignore b/src/aikgen/.gitignore
new file mode 100644 (file)
index 0000000..2fe22e5
--- /dev/null
@@ -0,0 +1 @@
+aikgen
diff --git a/src/aikgen/Makefile.am b/src/aikgen/Makefile.am
new file mode 100644 (file)
index 0000000..dc59d20
--- /dev/null
@@ -0,0 +1,15 @@
+bin_PROGRAMS = aikgen
+
+aikgen_SOURCES = aikgen.c
+
+aikgen_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
+aikgen.o :     $(top_builddir)/config.status
+
+if USE_TROUSERS
+  aikgen_LDADD += -ltspi
+endif
+
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src/libstrongswan \
+       -DIPSEC_CONFDIR=\"${sysconfdir}\" \
+       -DPLUGINS=\""${aikgen_plugins}\""
diff --git a/src/aikgen/aikgen.c b/src/aikgen/aikgen.c
new file mode 100644 (file)
index 0000000..192636a
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+ * Copyright (C) 2014 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 <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>
+#include <errno.h>
+
+/* default directory where AIK keys are stored */
+#define AIK_DIR                                                        IPSEC_CONFDIR "/pts/"
+
+/* default name of AIK private key blob */
+#define DEFAULT_FILENAME_AIKBLOB               AIK_DIR "aikBlob.bin"
+
+/* default name of AIK private key blob */
+#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;
+static level_t default_loglevel = 1;
+
+/* options read by optionsfrom */
+options_t *options;
+
+/* global variables */
+certificate_t *cacert;
+public_key_t *ca_pubkey;
+chunk_t ca_modulus;
+chunk_t aik_pubkey;
+chunk_t aik_keyid;
+
+/* TPM context */
+TSS_HCONTEXT  hContext;
+
+/**
+ * logging function for aikgen
+ */
+static void aikgen_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 = aikgen_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_aikgen(err_t message, ...)
+{
+       int status = 0;
+
+       DESTROY_IF(cacert);
+       DESTROY_IF(ca_pubkey);
+       free(ca_modulus.ptr);
+       free(aik_pubkey.ptr);
+       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')
+       {
+               va_list args;
+               char m[8192];
+
+               va_start(args, message);
+               vsnprintf(m, sizeof(m), message, args);
+               va_end(args);
+
+               fprintf(stderr, "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: aikgen  --cacert|capubkey <filename>"
+               " [--aikblob <filename>] [--aikpubkey <filename>] \n"
+               "              [--idreq <filename>] [--force]"
+               " [--quiet] [--debug <level>]\n"
+               "       aikgen --help\n"
+               "\n"
+               "Options:\n"
+               " --cacert (-c)     certificate of [privacy] CA\n"
+               " --capubkey (-k)   public key of [privacy] CA\n"
+               " --aikblob (-b)    encrypted blob with AIK private key\n"
+               " --aikpubkey (-p)  AIK public key\n"
+               " --idreq (-i)      encrypted identity request\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_aikgen(message);
+}
+
+/**
+ * @brief main of aikgen which generates 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 *cacert_filename    = NULL;
+       char *capubkey_filename  = NULL;
+       char *aikblob_filename   = DEFAULT_FILENAME_AIKBLOB;
+       char *aikpubkey_filename = DEFAULT_FILENAME_AIKPUBKEY;
+       char *idreq_filename     = NULL;
+       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"))
+       {
+               exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
+       }
+       if (lib->integrity &&
+               !lib->integrity->check_file(lib->integrity, "aikgen", argv[0]))
+       {
+               fprintf(stderr, "integrity check of aikgen 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, '+' },
+                       { "cacert", required_argument, NULL, 'c' },
+                       { "capubkey", required_argument, NULL, 'k' },
+                       { "aikblob", required_argument, NULL, 'b' },
+                       { "aikpubkey", required_argument, NULL, 'p' },
+                       { "idreq", required_argument, NULL, 'i' },
+                       { "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, "ho:c:b:p:fqd:", 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_aikgen("optionsfrom failed");
+                               }
+                               continue;
+
+                       case 'c':       /* --cacert <filename> */
+                               cacert_filename = optarg;
+                               continue;
+
+                       case 'k':       /* --capubkey <filename> */
+                               capubkey_filename = optarg;
+                               continue;
+
+                       case 'b':       /* --aikblob <filename> */
+                               aikblob_filename = optarg;
+                               continue;
+
+                       case 'p':       /* --aikpubkey <filename> */
+                               aikpubkey_filename = optarg;
+                               continue;
+
+                       case 'i':       /* --idreq <filename> */
+                               idreq_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("aikgen");
+
+       if (!lib->plugins->load(lib->plugins,
+                       lib->settings->get_str(lib->settings, "aikgen.load", PLUGINS)))
+       {
+               exit_aikgen("plugin loading failed");
+       }
+
+       /* read certificate of [privacy] CA if it exists */
+       if (cacert_filename)
+       {
+               cacert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+                                                               BUILD_FROM_FILE, cacert_filename, BUILD_END);
+               if (!cacert)
+               {
+                       exit_aikgen("could not read ca certificate file '%s'",
+                                                cacert_filename);
+               }
+       }
+
+       /* optionally read public key of [privacy CA] if it exists */
+       if (!cacert)
+       {
+               if (!capubkey_filename)
+               {
+                       usage("either --cacert or --capubkey option is required");
+               }
+               cacert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+                                                               CERT_TRUSTED_PUBKEY, BUILD_FROM_FILE,
+                                                               capubkey_filename, BUILD_END);
+               if (!cacert)
+               {
+                       exit_aikgen("could not read ca public key file '%s'",
+                                                capubkey_filename);
+               }
+       }
+
+       /* extract public key from CA certificate or trusted CA public key */
+       ca_pubkey = cacert->get_public_key(cacert);
+       if (!ca_pubkey)
+       {
+               exit_aikgen("could not extract ca public key");
+       }
+       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",
+                                        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);
+       }
+
+       /* 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);
+       }
+
+       /* 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 */
+       if (idreq_filename)
+       {
+               if (!chunk_write(identity_req, idreq_filename, 0022, force))
+               {
+                       exit_aikgen("could not write AIK identity request file '%s': %s",
+                                                idreq_filename, strerror(errno));
+               }
+               DBG1(DBG_LIB, "AIK identity request written to '%s' (%u bytes)",
+                                          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);
+
+       if (!chunk_write(aik_blob, aikblob_filename, 0022, force))
+       {
+               exit_aikgen("could not write AIK blob file '%s': %s",
+                                        aikblob_filename, strerror(errno));
+       }
+       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");
+       }
+       if (!chunk_write(aik_pubkey, aikpubkey_filename, 0022, force))
+       {
+               exit_aikgen("could not write AIK public key file '%s': %s",
+                                        aikpubkey_filename, strerror(errno));
+       }
+       DBG1(DBG_LIB, "AIK public key written to '%s' (%u bytes)",
+                                  aikpubkey_filename, aik_pubkey.len);
+
+       /* display AIK keyid derived from subjectPublicKeyInfo encoding */
+       if (!lib->encoding->encode(lib->encoding, KEYID_PUBKEY_INFO_SHA1, NULL,
+                                       &aik_keyid, CRED_PART_RSA_MODULUS, aik_modulus,
+                                       CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
+       {
+               exit_aikgen("computation of AIK keyid failed");
+       }
+       DBG1(DBG_LIB, "AIK keyid: %#B", &aik_keyid);
+
+       exit_aikgen(NULL);
+       return -1; /* should never be reached */
+}
index 6163218..e6725d0 100644 (file)
@@ -1,7 +1,7 @@
 #! @IPSEC_SHELL@
 # prefix command to run stuff from our programs directory
 # Copyright (C) 1998-2002  Henry Spencer.
-# Copyright (C) 2006 Andreas Steffen
+# Copyright (C) 2006-2014 Andreas Steffen
 # Copyright (C) 2006 Martin Willi
 #
 # This program is free software; you can redistribute it and/or modify it
@@ -317,6 +317,10 @@ pki)
        shift
        exec $IPSEC_BINDIR/pki "$@"
        ;;
+aikgen)
+       shift
+       exec $IPSEC_BINDIR/aikgen "$@"
+       ;;
 version|--version)
        printf "$OS_NAME $IPSEC_NAME $IPSEC_VERSION\n"
        printf "$IPSEC_DISTRO\n"