Return to aikgen.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / aikgen |
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: }