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>