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>