Annotation of embedaddon/strongswan/src/aikgen/aikgen.c, revision 1.1.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>