File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / aikgen / aikgen.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 09:46:44 2020 UTC (4 years, 4 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, v5_8_4p7, HEAD
Strongswan

    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>