Annotation of embedaddon/strongswan/src/aikgen/aikgen.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2014-2016 Andreas Steffen
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #include "tpm_tss.h"
! 17:
! 18: #include <library.h>
! 19: #include <utils/debug.h>
! 20: #include <utils/optionsfrom.h>
! 21: #include <credentials/certificates/x509.h>
! 22: #include <credentials/keys/public_key.h>
! 23:
! 24: #include <syslog.h>
! 25: #include <getopt.h>
! 26: #include <errno.h>
! 27:
! 28: /* default directory where AIK keys are stored */
! 29: #define AIK_DIR IPSEC_CONFDIR "/pts/"
! 30:
! 31: /* default name of AIK private key blob */
! 32: #define DEFAULT_FILENAME_AIKBLOB AIK_DIR "aikBlob.bin"
! 33:
! 34: /* default name of AIK public key */
! 35: #define DEFAULT_FILENAME_AIKPUBKEY AIK_DIR "aikPub.der"
! 36:
! 37: /* logging */
! 38: static bool log_to_stderr = TRUE;
! 39: static bool log_to_syslog = TRUE;
! 40: static level_t default_loglevel = 1;
! 41:
! 42: /* options read by optionsfrom */
! 43: options_t *options;
! 44:
! 45: /* global variables */
! 46: certificate_t *cacert;
! 47: public_key_t *ca_pubkey;
! 48: chunk_t ca_modulus;
! 49: chunk_t aik_pubkey;
! 50: chunk_t aik_keyid;
! 51: tpm_tss_t *tpm;
! 52:
! 53: /**
! 54: * logging function for aikgen
! 55: */
! 56: static void aikgen_dbg(debug_t group, level_t level, char *fmt, ...)
! 57: {
! 58: char buffer[8192];
! 59: char *current = buffer, *next;
! 60: va_list args;
! 61:
! 62: if (level <= default_loglevel)
! 63: {
! 64: if (log_to_stderr)
! 65: {
! 66: va_start(args, fmt);
! 67: vfprintf(stderr, fmt, args);
! 68: va_end(args);
! 69: fprintf(stderr, "\n");
! 70: }
! 71: if (log_to_syslog)
! 72: {
! 73: /* write in memory buffer first */
! 74: va_start(args, fmt);
! 75: vsnprintf(buffer, sizeof(buffer), fmt, args);
! 76: va_end(args);
! 77:
! 78: /* do a syslog with every line */
! 79: while (current)
! 80: {
! 81: next = strchr(current, '\n');
! 82: if (next)
! 83: {
! 84: *(next++) = '\0';
! 85: }
! 86: syslog(LOG_INFO, "%s\n", current);
! 87: current = next;
! 88: }
! 89: }
! 90: }
! 91: }
! 92:
! 93: /**
! 94: * Initialize logging to stderr/syslog
! 95: */
! 96: static void init_log(const char *program)
! 97: {
! 98: dbg = aikgen_dbg;
! 99:
! 100: if (log_to_stderr)
! 101: {
! 102: setbuf(stderr, NULL);
! 103: }
! 104: if (log_to_syslog)
! 105: {
! 106: openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
! 107: }
! 108: }
! 109:
! 110: /**
! 111: * @brief exit aikgen
! 112: *
! 113: * @param status 0 = OK, -1 = general discomfort
! 114: */
! 115: static void exit_aikgen(err_t message, ...)
! 116: {
! 117: int status = 0;
! 118:
! 119: DESTROY_IF(tpm);
! 120: DESTROY_IF(cacert);
! 121: DESTROY_IF(ca_pubkey);
! 122: free(ca_modulus.ptr);
! 123: free(aik_pubkey.ptr);
! 124: free(aik_keyid.ptr);
! 125: options->destroy(options);
! 126:
! 127: /* print any error message to stderr */
! 128: if (message != NULL && *message != '\0')
! 129: {
! 130: va_list args;
! 131: char m[8192];
! 132:
! 133: va_start(args, message);
! 134: vsnprintf(m, sizeof(m), message, args);
! 135: va_end(args);
! 136:
! 137: fprintf(stderr, "aikgen error: %s\n", m);
! 138: status = -1;
! 139: }
! 140: library_deinit();
! 141: exit(status);
! 142: }
! 143:
! 144: /**
! 145: * @brief prints the usage of the program to the stderr output
! 146: *
! 147: * If message is set, program is exited with 1 (error)
! 148: * @param message message in case of an error
! 149: */
! 150: static void usage(const char *message)
! 151: {
! 152: fprintf(stderr,
! 153: "Usage: aikgen --cacert|capubkey <filename>"
! 154: " [--aikblob <filename>] [--aikpubkey <filename>] \n"
! 155: " [--idreq <filename>] [--force]"
! 156: " [--quiet] [--debug <level>]\n"
! 157: " aikgen --help\n"
! 158: "\n"
! 159: "Options:\n"
! 160: " --cacert (-c) certificate of [privacy] CA\n"
! 161: " --capubkey (-k) public key of [privacy] CA\n"
! 162: " --aikblob (-b) encrypted blob with AIK private key\n"
! 163: " --aikpubkey (-p) AIK public key\n"
! 164: " --idreq (-i) encrypted identity request\n"
! 165: " --force (-f) force to overwrite existing files\n"
! 166: " --help (-h) show usage and exit\n"
! 167: "\n"
! 168: "Debugging output:\n"
! 169: " --debug (-l) changes the log level (-1..4, default: 1)\n"
! 170: " --quiet (-q) do not write log output to stderr\n"
! 171: );
! 172: exit_aikgen(message);
! 173: }
! 174:
! 175: /**
! 176: * @brief main of aikgen which generates an Attestation Identity Key (AIK)
! 177: *
! 178: * @param argc number of arguments
! 179: * @param argv pointer to the argument values
! 180: */
! 181: int main(int argc, char *argv[])
! 182: {
! 183: /* external values */
! 184: extern char * optarg;
! 185: extern int optind;
! 186:
! 187: char *cacert_filename = NULL;
! 188: char *capubkey_filename = NULL;
! 189: char *aikblob_filename = DEFAULT_FILENAME_AIKBLOB;
! 190: char *aikpubkey_filename = DEFAULT_FILENAME_AIKPUBKEY;
! 191: char *idreq_filename = NULL;
! 192: bool force = FALSE;
! 193: chunk_t identity_req;
! 194: chunk_t aik_blob;
! 195: hasher_t *hasher;
! 196:
! 197: atexit(library_deinit);
! 198: if (!library_init(NULL, "aikgen"))
! 199: {
! 200: exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
! 201: }
! 202: if (lib->integrity &&
! 203: !lib->integrity->check_file(lib->integrity, "aikgen", argv[0]))
! 204: {
! 205: fprintf(stderr, "integrity check of aikgen failed\n");
! 206: exit(SS_RC_DAEMON_INTEGRITY);
! 207: }
! 208:
! 209: /* initialize global variables */
! 210: options = options_create();
! 211:
! 212: for (;;)
! 213: {
! 214: static const struct option long_opts[] = {
! 215: /* name, has_arg, flag, val */
! 216: { "help", no_argument, NULL, 'h' },
! 217: { "optionsfrom", required_argument, NULL, '+' },
! 218: { "cacert", required_argument, NULL, 'c' },
! 219: { "capubkey", required_argument, NULL, 'k' },
! 220: { "aikblob", required_argument, NULL, 'b' },
! 221: { "aikpubkey", required_argument, NULL, 'p' },
! 222: { "idreq", required_argument, NULL, 'i' },
! 223: { "force", no_argument, NULL, 'f' },
! 224: { "quiet", no_argument, NULL, 'q' },
! 225: { "debug", required_argument, NULL, 'l' },
! 226: { 0,0,0,0 }
! 227: };
! 228:
! 229: /* parse next option */
! 230: int c = getopt_long(argc, argv, "ho:c:b:p:fqd:", long_opts, NULL);
! 231:
! 232: switch (c)
! 233: {
! 234: case EOF: /* end of flags */
! 235: break;
! 236:
! 237: case 'h': /* --help */
! 238: usage(NULL);
! 239:
! 240: case '+': /* --optionsfrom <filename> */
! 241: if (!options->from(options, optarg, &argc, &argv, optind))
! 242: {
! 243: exit_aikgen("optionsfrom failed");
! 244: }
! 245: continue;
! 246:
! 247: case 'c': /* --cacert <filename> */
! 248: cacert_filename = optarg;
! 249: continue;
! 250:
! 251: case 'k': /* --capubkey <filename> */
! 252: capubkey_filename = optarg;
! 253: continue;
! 254:
! 255: case 'b': /* --aikblob <filename> */
! 256: aikblob_filename = optarg;
! 257: continue;
! 258:
! 259: case 'p': /* --aikpubkey <filename> */
! 260: aikpubkey_filename = optarg;
! 261: continue;
! 262:
! 263: case 'i': /* --idreq <filename> */
! 264: idreq_filename = optarg;
! 265: continue;
! 266:
! 267: case 'f': /* --force */
! 268: force = TRUE;
! 269: continue;
! 270:
! 271: case 'q': /* --quiet */
! 272: log_to_stderr = FALSE;
! 273: continue;
! 274:
! 275: case 'l': /* --debug <level> */
! 276: default_loglevel = atoi(optarg);
! 277: continue;
! 278:
! 279: default:
! 280: usage("unknown option");
! 281: }
! 282: /* break from loop */
! 283: break;
! 284: }
! 285:
! 286: init_log("aikgen");
! 287:
! 288: if (!lib->plugins->load(lib->plugins,
! 289: lib->settings->get_str(lib->settings, "aikgen.load", PLUGINS)))
! 290: {
! 291: exit_aikgen("plugin loading failed");
! 292: }
! 293:
! 294: /* read certificate of [privacy] CA if it exists */
! 295: if (cacert_filename)
! 296: {
! 297: cacert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
! 298: BUILD_FROM_FILE, cacert_filename, BUILD_END);
! 299: if (!cacert)
! 300: {
! 301: exit_aikgen("could not read ca certificate file '%s'",
! 302: cacert_filename);
! 303: }
! 304: }
! 305:
! 306: /* optionally read public key of [privacy CA] if it exists */
! 307: if (!cacert)
! 308: {
! 309: if (!capubkey_filename)
! 310: {
! 311: usage("either --cacert or --capubkey option is required");
! 312: }
! 313: cacert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
! 314: CERT_TRUSTED_PUBKEY, BUILD_FROM_FILE,
! 315: capubkey_filename, BUILD_END);
! 316: if (!cacert)
! 317: {
! 318: exit_aikgen("could not read ca public key file '%s'",
! 319: capubkey_filename);
! 320: }
! 321: }
! 322:
! 323: /* extract public key from CA certificate or trusted CA public key */
! 324: ca_pubkey = cacert->get_public_key(cacert);
! 325: if (!ca_pubkey)
! 326: {
! 327: exit_aikgen("could not extract ca public key");
! 328: }
! 329: if (ca_pubkey->get_type(ca_pubkey) != KEY_RSA ||
! 330: ca_pubkey->get_keysize(ca_pubkey) != 2048)
! 331: {
! 332: exit_aikgen("CA public key must be RSA 2048 but is %N %d",
! 333: key_type_names, ca_pubkey->get_type(ca_pubkey),
! 334: ca_pubkey->get_keysize(ca_pubkey));
! 335: }
! 336: if (!ca_pubkey->get_encoding(ca_pubkey, PUBKEY_RSA_MODULUS, &ca_modulus))
! 337: {
! 338: exit_aikgen("could not extract RSA modulus from CA public key");
! 339: }
! 340:
! 341: /* try to find a TPM 1.2 */
! 342: tpm = tpm_tss_probe(TPM_VERSION_1_2);
! 343: if (!tpm)
! 344: {
! 345: exit_aikgen("no TPM 1.2 found");
! 346: }
! 347:
! 348: if (!tpm->generate_aik(tpm, ca_modulus, &aik_blob, &aik_pubkey,
! 349: &identity_req))
! 350: {
! 351: exit_aikgen("could not generate AIK");
! 352: }
! 353:
! 354: /* optionally output identity request encrypted with CA public key */
! 355: if (idreq_filename)
! 356: {
! 357: if (!chunk_write(identity_req, idreq_filename, 0022, force))
! 358: {
! 359: exit_aikgen("could not write AIK identity request file '%s': %s",
! 360: idreq_filename, strerror(errno));
! 361: }
! 362: DBG1(DBG_LIB, "AIK identity request written to '%s' (%u bytes)",
! 363: idreq_filename, identity_req.len);
! 364: }
! 365:
! 366: /* output AIK private key blob */
! 367: if (!chunk_write(aik_blob, aikblob_filename, 0022, force))
! 368: {
! 369: exit_aikgen("could not write AIK blob file '%s': %s",
! 370: aikblob_filename, strerror(errno));
! 371: }
! 372: DBG1(DBG_LIB, "AIK private key blob written to '%s' (%u bytes)",
! 373: aikblob_filename, aik_blob.len);
! 374:
! 375: /* output AIK public key */
! 376: if (!chunk_write(aik_pubkey, aikpubkey_filename, 0022, force))
! 377: {
! 378: exit_aikgen("could not write AIK public key file '%s': %s",
! 379: aikpubkey_filename, strerror(errno));
! 380: }
! 381: DBG1(DBG_LIB, "AIK public key written to '%s' (%u bytes)",
! 382: aikpubkey_filename, aik_pubkey.len);
! 383:
! 384: /* display AIK keyid derived from subjectPublicKeyInfo encoding */
! 385: hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
! 386: if (!hasher || !hasher->allocate_hash(hasher, aik_pubkey, &aik_keyid))
! 387: {
! 388: DESTROY_IF(hasher);
! 389: exit_aikgen("SHA1 hash algorithm not supported, computation of AIK "
! 390: "keyid failed");
! 391: }
! 392: hasher->destroy(hasher);
! 393: DBG1(DBG_LIB, "AIK keyid: %#B", &aik_keyid);
! 394:
! 395: exit_aikgen(NULL);
! 396: return -1; /* should never be reached */
! 397: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>