Annotation of embedaddon/strongswan/src/libcharon/plugins/stroke/stroke_cred.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2008-2017 Tobias Brunner
        !             3:  * Copyright (C) 2008 Martin Willi
        !             4:  * HSR Hochschule fuer Technik Rapperswil
        !             5:  *
        !             6:  * This program is free software; you can redistribute it and/or modify it
        !             7:  * under the terms of the GNU General Public License as published by the
        !             8:  * Free Software Foundation; either version 2 of the License, or (at your
        !             9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            10:  *
        !            11:  * This program is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            14:  * for more details.
        !            15:  */
        !            16: 
        !            17: #include <sys/types.h>
        !            18: #include <sys/stat.h>
        !            19: #include <limits.h>
        !            20: #include <fcntl.h>
        !            21: #include <errno.h>
        !            22: #include <unistd.h>
        !            23: 
        !            24: #ifdef HAVE_GLOB_H
        !            25: #include <glob.h>
        !            26: #endif
        !            27: 
        !            28: #include "stroke_cred.h"
        !            29: 
        !            30: #include <credentials/certificates/x509.h>
        !            31: #include <credentials/certificates/crl.h>
        !            32: #include <credentials/certificates/ac.h>
        !            33: #include <credentials/containers/pkcs12.h>
        !            34: #include <credentials/sets/mem_cred.h>
        !            35: #include <credentials/sets/callback_cred.h>
        !            36: #include <collections/linked_list.h>
        !            37: #include <utils/lexparser.h>
        !            38: #include <threading/rwlock.h>
        !            39: #include <daemon.h>
        !            40: 
        !            41: /* configuration directories and files */
        !            42: #define CONFIG_DIR IPSEC_CONFDIR
        !            43: #define IPSEC_D_DIR CONFIG_DIR "/ipsec.d"
        !            44: #define PRIVATE_KEY_DIR IPSEC_D_DIR "/private"
        !            45: #define CERTIFICATE_DIR IPSEC_D_DIR "/certs"
        !            46: #define CA_CERTIFICATE_DIR IPSEC_D_DIR "/cacerts"
        !            47: #define AA_CERTIFICATE_DIR IPSEC_D_DIR "/aacerts"
        !            48: #define ATTR_CERTIFICATE_DIR IPSEC_D_DIR "/acerts"
        !            49: #define OCSP_CERTIFICATE_DIR IPSEC_D_DIR "/ocspcerts"
        !            50: #define CRL_DIR IPSEC_D_DIR "/crls"
        !            51: #define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
        !            52: 
        !            53: #define MAX_SECRETS_RECURSION 10
        !            54: 
        !            55: typedef struct private_stroke_cred_t private_stroke_cred_t;
        !            56: 
        !            57: /**
        !            58:  * private data of stroke_cred
        !            59:  */
        !            60: struct private_stroke_cred_t {
        !            61: 
        !            62:        /**
        !            63:         * public functions
        !            64:         */
        !            65:        stroke_cred_t public;
        !            66: 
        !            67:        /**
        !            68:         * secrets file with credential information
        !            69:         */
        !            70:        char *secrets_file;
        !            71: 
        !            72:        /**
        !            73:         * credentials: end entity certs, attribute certs, CRLs, etc.
        !            74:         */
        !            75:        mem_cred_t *creds;
        !            76: 
        !            77:        /**
        !            78:         * Attribute Authority certificates
        !            79:         */
        !            80:        mem_cred_t *aacerts;
        !            81: 
        !            82:        /**
        !            83:         * ignore missing CA basic constraint (i.e. treat all certificates in
        !            84:         * ipsec.conf ca sections and ipsec.d/cacerts as CA certificates)
        !            85:         */
        !            86:        bool force_ca_cert;
        !            87: 
        !            88:        /**
        !            89:         * cache CRLs to disk?
        !            90:         */
        !            91:        bool cachecrl;
        !            92: 
        !            93:        /**
        !            94:         * CA certificate store
        !            95:         */
        !            96:        stroke_ca_t *ca;
        !            97: };
        !            98: 
        !            99: /** Length of smartcard specifier parts (module, keyid) */
        !           100: #define SC_PART_LEN 128
        !           101: 
        !           102: /**
        !           103:  * Kind of smartcard specifier token
        !           104:  */
        !           105: typedef enum {
        !           106:        SC_FORMAT_SLOT_MODULE_KEYID,
        !           107:        SC_FORMAT_SLOT_KEYID,
        !           108:        SC_FORMAT_KEYID,
        !           109:        SC_FORMAT_INVALID,
        !           110: } smartcard_format_t;
        !           111: 
        !           112: /**
        !           113:  * Parse a smartcard specifier token
        !           114:  */
        !           115: static smartcard_format_t parse_smartcard(char *smartcard, u_int *slot,
        !           116:                                                                                  char *module, char *keyid)
        !           117: {
        !           118:        /* The token has one of the following three formats:
        !           119:         * - %smartcard<slot>@<module>:<keyid>
        !           120:         * - %smartcard<slot>:<keyid>
        !           121:         * - %smartcard:<keyid>
        !           122:         */
        !           123:        char buf[2 * SC_PART_LEN], *pos;
        !           124: 
        !           125:        if (sscanf(smartcard, "%%smartcard%u@%255s", slot, buf) == 2)
        !           126:        {
        !           127:                pos = strchr(buf, ':');
        !           128:                if (!pos)
        !           129:                {
        !           130:                        return SC_FORMAT_INVALID;
        !           131:                }
        !           132:                *pos++ = '\0';
        !           133:                snprintf(module, SC_PART_LEN, "%s", buf);
        !           134:                snprintf(keyid, SC_PART_LEN, "%s", pos);
        !           135:                return SC_FORMAT_SLOT_MODULE_KEYID;
        !           136:        }
        !           137:        if (sscanf(smartcard, "%%smartcard%u:%127s", slot, keyid) == 2)
        !           138:        {
        !           139:                return SC_FORMAT_SLOT_KEYID;
        !           140:        }
        !           141:        if (sscanf(smartcard, "%%smartcard:%127s", keyid) == 1)
        !           142:        {
        !           143:                return SC_FORMAT_KEYID;
        !           144:        }
        !           145:        return SC_FORMAT_INVALID;
        !           146: }
        !           147: 
        !           148: /**
        !           149:  * Load a credential from a smartcard
        !           150:  */
        !           151: static certificate_t *load_from_smartcard(smartcard_format_t format,
        !           152:                                                                                  u_int slot, char *module, char *keyid,
        !           153:                                                                                  credential_type_t type, int subtype)
        !           154: {
        !           155:        chunk_t chunk;
        !           156:        void *cred;
        !           157: 
        !           158:        chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
        !           159:        switch (format)
        !           160:        {
        !           161:                case SC_FORMAT_SLOT_MODULE_KEYID:
        !           162:                        cred = lib->creds->create(lib->creds, type, subtype,
        !           163:                                                        BUILD_PKCS11_SLOT, slot,
        !           164:                                                        BUILD_PKCS11_MODULE, module,
        !           165:                                                        BUILD_PKCS11_KEYID, chunk, BUILD_END);
        !           166:                        break;
        !           167:                case SC_FORMAT_SLOT_KEYID:
        !           168:                        cred = lib->creds->create(lib->creds, type, subtype,
        !           169:                                                        BUILD_PKCS11_SLOT, slot,
        !           170:                                                        BUILD_PKCS11_KEYID, chunk, BUILD_END);
        !           171:                        break;
        !           172:                case SC_FORMAT_KEYID:
        !           173:                        cred = lib->creds->create(lib->creds, type, subtype,
        !           174:                                                        BUILD_PKCS11_KEYID, chunk, BUILD_END);
        !           175:                        break;
        !           176:                default:
        !           177:                        cred = NULL;
        !           178:                        break;
        !           179:        }
        !           180:        free(chunk.ptr);
        !           181: 
        !           182:        return cred;
        !           183: }
        !           184: 
        !           185: METHOD(stroke_cred_t, load_peer, certificate_t*,
        !           186:        private_stroke_cred_t *this, char *filename)
        !           187: {
        !           188:        certificate_t *cert = NULL;
        !           189:        char path[PATH_MAX];
        !           190: 
        !           191:        if (strpfx(filename, "%smartcard"))
        !           192:        {
        !           193:                smartcard_format_t format;
        !           194:                char module[SC_PART_LEN], keyid[SC_PART_LEN];
        !           195:                u_int slot;
        !           196: 
        !           197:                format = parse_smartcard(filename, &slot, module, keyid);
        !           198:                if (format != SC_FORMAT_INVALID)
        !           199:                {
        !           200:                        cert = (certificate_t*)load_from_smartcard(format,
        !           201:                                                        slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
        !           202:                }
        !           203:        }
        !           204:        else
        !           205:        {
        !           206:                if (*filename == '/')
        !           207:                {
        !           208:                        snprintf(path, sizeof(path), "%s", filename);
        !           209:                }
        !           210:                else
        !           211:                {
        !           212:                        snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
        !           213:                }
        !           214: 
        !           215:                cert = lib->creds->create(lib->creds,
        !           216:                                                                  CRED_CERTIFICATE, CERT_ANY,
        !           217:                                                                  BUILD_FROM_FILE, path,
        !           218:                                                                  BUILD_END);
        !           219:        }
        !           220:        if (cert)
        !           221:        {
        !           222:                cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
        !           223:                DBG1(DBG_CFG, "  loaded certificate \"%Y\" from '%s'",
        !           224:                                          cert->get_subject(cert), filename);
        !           225:                return cert;
        !           226:        }
        !           227:        DBG1(DBG_CFG, "  loading certificate from '%s' failed", filename);
        !           228:        return NULL;
        !           229: }
        !           230: 
        !           231: METHOD(stroke_cred_t, load_pubkey, certificate_t*,
        !           232:        private_stroke_cred_t *this, char *filename, identification_t *identity)
        !           233: {
        !           234:        certificate_t *cert;
        !           235:        public_key_t *key;
        !           236:        char path[PATH_MAX];
        !           237:        builder_part_t build_part;
        !           238:        key_type_t type = KEY_ANY;
        !           239: 
        !           240:        if (streq(filename, "%dns"))
        !           241:        {
        !           242:                return NULL;
        !           243:        }
        !           244:        if (strncaseeq(filename, "dns:", 4))
        !           245:        {       /* RFC 3110 format */
        !           246:                build_part = BUILD_BLOB_DNSKEY;
        !           247:                /* not a complete RR, only RSA supported */
        !           248:                type = KEY_RSA;
        !           249:                filename += 4;
        !           250:        }
        !           251:        else if (strncaseeq(filename, "ssh:", 4))
        !           252:        {       /* SSH key */
        !           253:                build_part = BUILD_BLOB_SSHKEY;
        !           254:                filename += 4;
        !           255:        }
        !           256:        else
        !           257:        {       /* try PKCS#1 by default */
        !           258:                build_part = BUILD_BLOB_ASN1_DER;
        !           259:        }
        !           260:        if (strncaseeq(filename, "0x", 2) || strncaseeq(filename, "0s", 2))
        !           261:        {
        !           262:                chunk_t printable_key, raw_key;
        !           263: 
        !           264:                printable_key = chunk_create(filename + 2, strlen(filename) - 2);
        !           265:                raw_key = strncaseeq(filename, "0x", 2) ?
        !           266:                                                                 chunk_from_hex(printable_key, NULL) :
        !           267:                                                                 chunk_from_base64(printable_key, NULL);
        !           268:                key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type,
        !           269:                                                                 build_part, raw_key, BUILD_END);
        !           270:                chunk_free(&raw_key);
        !           271:                if (key)
        !           272:                {
        !           273:                        cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
        !           274:                                                                          CERT_TRUSTED_PUBKEY,
        !           275:                                                                          BUILD_PUBLIC_KEY, key,
        !           276:                                                                          BUILD_SUBJECT, identity,
        !           277:                                                                          BUILD_END);
        !           278:                        type = key->get_type(key);
        !           279:                        key->destroy(key);
        !           280:                        if (cert)
        !           281:                        {
        !           282:                                cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
        !           283:                                DBG1(DBG_CFG, "  loaded %N public key for \"%Y\"",
        !           284:                                         key_type_names, type, identity);
        !           285:                                return cert;
        !           286:                        }
        !           287:                }
        !           288:                DBG1(DBG_CFG, "  loading public key for \"%Y\" failed", identity);
        !           289:        }
        !           290:        else
        !           291:        {
        !           292:                if (*filename == '/')
        !           293:                {
        !           294:                        snprintf(path, sizeof(path), "%s", filename);
        !           295:                }
        !           296:                else
        !           297:                {
        !           298:                        snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
        !           299:                }
        !           300: 
        !           301:                cert = lib->creds->create(lib->creds,
        !           302:                                                                  CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY,
        !           303:                                                                  BUILD_FROM_FILE, path,
        !           304:                                                                  BUILD_SUBJECT, identity,
        !           305:                                                                  BUILD_END);
        !           306:                if (cert)
        !           307:                {
        !           308:                        cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
        !           309:                        key = cert->get_public_key(cert);
        !           310:                        type = key->get_type(key);
        !           311:                        key->destroy(key);
        !           312:                        DBG1(DBG_CFG, "  loaded %N public key for \"%Y\" from '%s'",
        !           313:                                 key_type_names, type, identity, filename);
        !           314:                        return cert;
        !           315:                }
        !           316:                DBG1(DBG_CFG, "  loading public key for \"%Y\" from '%s' failed",
        !           317:                         identity, filename);
        !           318:        }
        !           319:        return NULL;
        !           320: }
        !           321: 
        !           322: /**
        !           323:  * Load a CA certificate, optionally force it to be one
        !           324:  */
        !           325: static certificate_t *load_ca_cert(char *filename, bool force_ca_cert)
        !           326: {
        !           327:        certificate_t *cert = NULL;
        !           328:        char path[PATH_MAX];
        !           329: 
        !           330:        if (strpfx(filename, "%smartcard"))
        !           331:        {
        !           332:                smartcard_format_t format;
        !           333:                char module[SC_PART_LEN], keyid[SC_PART_LEN];
        !           334:                u_int slot;
        !           335: 
        !           336:                format = parse_smartcard(filename, &slot, module, keyid);
        !           337:                if (format != SC_FORMAT_INVALID)
        !           338:                {
        !           339:                        cert = (certificate_t*)load_from_smartcard(format,
        !           340:                                                        slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
        !           341:                }
        !           342:        }
        !           343:        else
        !           344:        {
        !           345:                if (*filename == '/')
        !           346:                {
        !           347:                        snprintf(path, sizeof(path), "%s", filename);
        !           348:                }
        !           349:                else
        !           350:                {
        !           351:                        snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
        !           352:                }
        !           353: 
        !           354:                if (force_ca_cert)
        !           355:                {       /* we treat this certificate as a CA certificate even if it has no
        !           356:                         * CA basic constraint */
        !           357:                        cert = lib->creds->create(lib->creds,
        !           358:                                                                  CRED_CERTIFICATE, CERT_X509,
        !           359:                                                                  BUILD_FROM_FILE, path, BUILD_X509_FLAG, X509_CA,
        !           360:                                                                  BUILD_END);
        !           361:                }
        !           362:                else
        !           363:                {
        !           364:                        cert = lib->creds->create(lib->creds,
        !           365:                                                                  CRED_CERTIFICATE, CERT_X509,
        !           366:                                                                  BUILD_FROM_FILE, path,
        !           367:                                                                  BUILD_END);
        !           368:                }
        !           369:        }
        !           370:        if (cert)
        !           371:        {
        !           372:                x509_t *x509 = (x509_t*)cert;
        !           373: 
        !           374:                if (!(x509->get_flags(x509) & X509_CA))
        !           375:                {
        !           376:                        DBG1(DBG_CFG, "  ca certificate \"%Y\" lacks ca basic constraint, "
        !           377:                                 "discarded", cert->get_subject(cert));
        !           378:                        cert->destroy(cert);
        !           379:                        return NULL;
        !           380:                }
        !           381:                DBG1(DBG_CFG, "  loaded ca certificate \"%Y\" from '%s'",
        !           382:                         cert->get_subject(cert), filename);
        !           383:                return cert;
        !           384:        }
        !           385:        return NULL;
        !           386: }
        !           387: 
        !           388: /**
        !           389:  * Used by stroke_ca.c
        !           390:  */
        !           391: certificate_t *stroke_load_ca_cert(char *filename)
        !           392: {
        !           393:        bool force_ca_cert;
        !           394: 
        !           395:        force_ca_cert = lib->settings->get_bool(lib->settings,
        !           396:                                                "%s.plugins.stroke.ignore_missing_ca_basic_constraint",
        !           397:                                                FALSE, lib->ns);
        !           398:        return load_ca_cert(filename, force_ca_cert);
        !           399: }
        !           400: 
        !           401: /**
        !           402:  * Load a CA certificate from disk
        !           403:  */
        !           404: static void load_x509_ca(private_stroke_cred_t *this, char *file,
        !           405:                                                 mem_cred_t *creds)
        !           406: {
        !           407:        certificate_t *cert;
        !           408: 
        !           409:        cert = load_ca_cert(file, this->force_ca_cert);
        !           410:        if (cert)
        !           411:        {
        !           412:                cert = this->ca->get_cert_ref(this->ca, cert);
        !           413:                creds->add_cert(creds, TRUE, cert);
        !           414:        }
        !           415:        else
        !           416:        {
        !           417:                DBG1(DBG_CFG, "  loading ca certificate from '%s' failed", file);
        !           418:        }
        !           419: }
        !           420: 
        !           421: /**
        !           422:  * Load AA certificate with flags from disk
        !           423:  */
        !           424: static void load_x509_aa(private_stroke_cred_t *this,char *file,
        !           425:                                                 mem_cred_t *creds)
        !           426: {
        !           427:        certificate_t *cert;
        !           428: 
        !           429:        cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
        !           430:                                                          BUILD_FROM_FILE, file,
        !           431:                                                          BUILD_X509_FLAG, X509_AA, BUILD_END);
        !           432:        if (cert)
        !           433:        {
        !           434:                DBG1(DBG_CFG, "  loaded AA certificate \"%Y\" from '%s'",
        !           435:                         cert->get_subject(cert), file);
        !           436:                creds->add_cert(creds, TRUE, cert);
        !           437:        }
        !           438:        else
        !           439:        {
        !           440:                DBG1(DBG_CFG, "  loading AA certificate from '%s' failed", file);
        !           441:        }
        !           442: }
        !           443: 
        !           444: /**
        !           445:  * Load a certificate with flags from disk
        !           446:  */
        !           447: static void load_x509(private_stroke_cred_t *this, char *file, x509_flag_t flag,
        !           448:                                          mem_cred_t *creds)
        !           449: {
        !           450:        certificate_t *cert;
        !           451: 
        !           452:        /* for all other flags, we add them to the certificate. */
        !           453:        cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
        !           454:                                                          BUILD_FROM_FILE, file,
        !           455:                                                          BUILD_X509_FLAG, flag, BUILD_END);
        !           456:        if (cert)
        !           457:        {
        !           458:                DBG1(DBG_CFG, "  loaded certificate \"%Y\" from '%s'",
        !           459:                         cert->get_subject(cert), file);
        !           460:                creds->add_cert(creds, TRUE, cert);
        !           461:        }
        !           462:        else
        !           463:        {
        !           464:                DBG1(DBG_CFG, "  loading certificate from '%s' failed", file);
        !           465:        }
        !           466: }
        !           467: 
        !           468: /**
        !           469:  * Load a CRL from a file
        !           470:  */
        !           471: static void load_x509_crl(private_stroke_cred_t *this, char *file,
        !           472:                                                  mem_cred_t *creds)
        !           473: {
        !           474:        certificate_t *cert;
        !           475: 
        !           476:        cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
        !           477:                                                          BUILD_FROM_FILE, file, BUILD_END);
        !           478:        if (cert)
        !           479:        {
        !           480:                DBG1(DBG_CFG, "  loaded crl from '%s'",  file);
        !           481:                creds->add_crl(creds, (crl_t*)cert);
        !           482:        }
        !           483:        else
        !           484:        {
        !           485:                DBG1(DBG_CFG, "  loading crl from '%s' failed", file);
        !           486:        }
        !           487: }
        !           488: 
        !           489: /**
        !           490:  * Load an attribute certificate from a file
        !           491:  */
        !           492: static void load_x509_ac(private_stroke_cred_t *this, char *file,
        !           493:                                                 mem_cred_t *creds)
        !           494: {
        !           495:        certificate_t *cert;
        !           496: 
        !           497:        cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC,
        !           498:                                                          BUILD_FROM_FILE, file, BUILD_END);
        !           499:        if (cert)
        !           500:        {
        !           501:                DBG1(DBG_CFG, "  loaded attribute certificate from '%s'", file);
        !           502:                creds->add_cert(creds, FALSE, cert);
        !           503:        }
        !           504:        else
        !           505:        {
        !           506:                DBG1(DBG_CFG, "  loading attribute certificate from '%s' failed", file);
        !           507:        }
        !           508: }
        !           509: 
        !           510: /**
        !           511:  * load trusted certificates from a directory
        !           512:  */
        !           513: static void load_certdir(private_stroke_cred_t *this, char *path,
        !           514:                                                 certificate_type_t type, x509_flag_t flag,
        !           515:                                                 mem_cred_t *creds)
        !           516: {
        !           517:        enumerator_t *enumerator;
        !           518:        struct stat st;
        !           519:        char *file;
        !           520: 
        !           521:        enumerator = enumerator_create_directory(path);
        !           522:        if (enumerator)
        !           523:        {
        !           524:                while (enumerator->enumerate(enumerator, NULL, &file, &st))
        !           525:                {
        !           526:                        if (!S_ISREG(st.st_mode))
        !           527:                        {
        !           528:                                /* skip special file */
        !           529:                                continue;
        !           530:                        }
        !           531:                        switch (type)
        !           532:                        {
        !           533:                                case CERT_X509:
        !           534:                                        if (flag & X509_CA)
        !           535:                                        {
        !           536:                                                load_x509_ca(this, file, creds);
        !           537:                                        }
        !           538:                                        else if (flag & X509_AA)
        !           539:                                        {
        !           540:                                                load_x509_aa(this, file, creds);
        !           541:                                        }
        !           542:                                        else
        !           543:                                        {
        !           544:                                                load_x509(this, file, flag, creds);
        !           545:                                        }
        !           546:                                        break;
        !           547:                                case CERT_X509_CRL:
        !           548:                                        load_x509_crl(this, file, creds);
        !           549:                                        break;
        !           550:                                case CERT_X509_AC:
        !           551:                                        load_x509_ac(this, file, creds);
        !           552:                                        break;
        !           553:                                default:
        !           554:                                        break;
        !           555:                        }
        !           556:                }
        !           557:                enumerator->destroy(enumerator);
        !           558:        }
        !           559:        else
        !           560:        {
        !           561:                DBG1(DBG_CFG, "  reading directory failed");
        !           562:        }
        !           563: }
        !           564: 
        !           565: METHOD(credential_set_t, cache_cert, void,
        !           566:        private_stroke_cred_t *this, certificate_t *cert)
        !           567: {
        !           568:        if (cert->get_type(cert) == CERT_X509_CRL && this->cachecrl)
        !           569:        {
        !           570:                /* CRLs get written to /etc/ipsec.d/crls/<authkeyId>.crl */
        !           571:                crl_t *crl = (crl_t*)cert;
        !           572: 
        !           573:                cert->get_ref(cert);
        !           574:                if (this->creds->add_crl(this->creds, crl))
        !           575:                {
        !           576:                        char buf[BUF_LEN];
        !           577:                        chunk_t chunk, hex;
        !           578:                        bool is_delta_crl;
        !           579: 
        !           580:                        is_delta_crl = crl->is_delta_crl(crl, NULL);
        !           581: 
        !           582:                        chunk = crl->get_authKeyIdentifier(crl);
        !           583:                        hex = chunk_to_hex(chunk, NULL, FALSE);
        !           584:                        snprintf(buf, sizeof(buf), "%s/%s%s.crl", CRL_DIR, hex.ptr,
        !           585:                                                                                is_delta_crl ? "_delta" : "");
        !           586:                        free(hex.ptr);
        !           587: 
        !           588:                        if (cert->get_encoding(cert, CERT_ASN1_DER, &chunk))
        !           589:                        {
        !           590:                                if (chunk_write(chunk, buf, 022, TRUE))
        !           591:                                {
        !           592:                                        DBG1(DBG_CFG, "  written crl file '%s' (%d bytes)",
        !           593:                                                 buf, chunk.len);
        !           594:                                }
        !           595:                                else
        !           596:                                {
        !           597:                                        DBG1(DBG_CFG, "  writing crl file '%s' failed: %s",
        !           598:                                                 buf, strerror(errno));
        !           599:                                }
        !           600:                                free(chunk.ptr);
        !           601:                        }
        !           602:                }
        !           603:        }
        !           604: }
        !           605: 
        !           606: METHOD(stroke_cred_t, cachecrl, void,
        !           607:        private_stroke_cred_t *this, bool enabled)
        !           608: {
        !           609:        DBG1(DBG_CFG, "crl caching to %s %s",
        !           610:                 CRL_DIR, enabled ? "enabled" : "disabled");
        !           611:        this->cachecrl = enabled;
        !           612: }
        !           613: 
        !           614: 
        !           615: /**
        !           616:  * Convert a string of characters into a binary secret
        !           617:  * A string between single or double quotes is treated as ASCII characters
        !           618:  * A string prepended by 0x is treated as HEX and prepended by 0s as Base64
        !           619:  */
        !           620: static err_t extract_secret(chunk_t *secret, chunk_t *line)
        !           621: {
        !           622:        chunk_t raw_secret;
        !           623:        char delimiter = ' ';
        !           624:        bool quotes = FALSE;
        !           625: 
        !           626:        if (!eat_whitespace(line))
        !           627:        {
        !           628:                return "missing secret";
        !           629:        }
        !           630: 
        !           631:        if (*line->ptr == '\'' || *line->ptr == '"')
        !           632:        {
        !           633:                quotes = TRUE;
        !           634:                delimiter = *line->ptr;
        !           635:                line->ptr++;  line->len--;
        !           636:        }
        !           637: 
        !           638:        if (!extract_token(&raw_secret, delimiter, line))
        !           639:        {
        !           640:                if (delimiter == ' ')
        !           641:                {
        !           642:                        raw_secret = *line;
        !           643:                }
        !           644:                else
        !           645:                {
        !           646:                        return "missing second delimiter";
        !           647:                }
        !           648:        }
        !           649: 
        !           650:        if (quotes)
        !           651:        {
        !           652:                /* treat as an ASCII string */
        !           653:                *secret = chunk_clone(raw_secret);
        !           654:                return NULL;
        !           655:        }
        !           656:        /* treat 0x as hex, 0s as base64 */
        !           657:        if (raw_secret.len > 2)
        !           658:        {
        !           659:                if (strncasecmp("0x", raw_secret.ptr, 2) == 0)
        !           660:                {
        !           661:                        *secret = chunk_from_hex(chunk_skip(raw_secret, 2), NULL);
        !           662:                        return NULL;
        !           663:                }
        !           664:                if (strncasecmp("0s", raw_secret.ptr, 2) == 0)
        !           665:                {
        !           666:                        *secret = chunk_from_base64(chunk_skip(raw_secret, 2), NULL);
        !           667:                        return NULL;
        !           668:                }
        !           669:        }
        !           670:        *secret = chunk_clone(raw_secret);
        !           671:        return NULL;
        !           672: }
        !           673: 
        !           674: /**
        !           675:  * Data for passphrase callback
        !           676:  */
        !           677: typedef struct {
        !           678:        /** cached passphrases */
        !           679:        mem_cred_t *cache;
        !           680:        /** socket we use for prompting */
        !           681:        FILE *prompt;
        !           682:        /** type of secret to unlock */
        !           683:        int type;
        !           684:        /** private key file */
        !           685:        char *path;
        !           686:        /** number of tries */
        !           687:        int try;
        !           688: } passphrase_cb_data_t;
        !           689: 
        !           690: /**
        !           691:  * Callback function to receive passphrases
        !           692:  */
        !           693: static shared_key_t* passphrase_cb(passphrase_cb_data_t *data,
        !           694:                                                                   shared_key_type_t type, identification_t *me,
        !           695:                                                                   identification_t *other, id_match_t *match_me,
        !           696:                                                                   id_match_t *match_other)
        !           697: {
        !           698:        static const int max_tries = 3;
        !           699:        shared_key_t *shared;
        !           700:        chunk_t secret;
        !           701:        char buf[256];
        !           702: 
        !           703:        if (type != SHARED_ANY && type != SHARED_PRIVATE_KEY_PASS)
        !           704:        {
        !           705:                return NULL;
        !           706:        }
        !           707: 
        !           708:        data->try++;
        !           709:        if (data->try > max_tries + 1)
        !           710:        {       /* another builder might call this after we gave up, fail silently */
        !           711:                return NULL;
        !           712:        }
        !           713:        if (data->try > max_tries)
        !           714:        {
        !           715:                fprintf(data->prompt, "Passphrase invalid, giving up.\n");
        !           716:                return NULL;
        !           717:        }
        !           718:        if (data->try > 1)
        !           719:        {
        !           720:                fprintf(data->prompt, "Passphrase invalid!\n");
        !           721:        }
        !           722:        fprintf(data->prompt, "%s '%s' is encrypted.\n",
        !           723:                        data->type == CRED_PRIVATE_KEY ? "Private key" : "PKCS#12 file",
        !           724:                        data->path);
        !           725:        fprintf(data->prompt, "Passphrase:\n");
        !           726:        if (fgets(buf, sizeof(buf), data->prompt))
        !           727:        {
        !           728:                secret = chunk_create(buf, strlen(buf));
        !           729:                if (secret.len > 1)
        !           730:                {       /* trim appended \n */
        !           731:                        secret.len--;
        !           732:                        if (match_me)
        !           733:                        {
        !           734:                                *match_me = ID_MATCH_PERFECT;
        !           735:                        }
        !           736:                        if (match_other)
        !           737:                        {
        !           738:                                *match_other = ID_MATCH_NONE;
        !           739:                        }
        !           740:                        shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
        !           741:                                                                           chunk_clone(secret));
        !           742:                        data->cache->add_shared(data->cache, shared->get_ref(shared), NULL);
        !           743:                        return shared;
        !           744:                }
        !           745:        }
        !           746:        return NULL;
        !           747: }
        !           748: 
        !           749: /**
        !           750:  * Data for PIN callback
        !           751:  */
        !           752: typedef struct {
        !           753:        /** socket we use for prompting */
        !           754:        FILE *prompt;
        !           755:        /** card label */
        !           756:        char *card;
        !           757:        /** card keyid */
        !           758:        chunk_t keyid;
        !           759:        /** number of tries */
        !           760:        int try;
        !           761:        /** provided PIN */
        !           762:        shared_key_t *shared;
        !           763: } pin_cb_data_t;
        !           764: 
        !           765: /**
        !           766:  * Callback function to receive PINs
        !           767:  */
        !           768: static shared_key_t* pin_cb(pin_cb_data_t *data, shared_key_type_t type,
        !           769:                                                        identification_t *me, identification_t *other,
        !           770:                                                        id_match_t *match_me, id_match_t *match_other)
        !           771: {
        !           772:        chunk_t secret;
        !           773:        char buf[256];
        !           774: 
        !           775:        if (type != SHARED_ANY && type != SHARED_PIN)
        !           776:        {
        !           777:                return NULL;
        !           778:        }
        !           779: 
        !           780:        if (!me || !chunk_equals(me->get_encoding(me), data->keyid))
        !           781:        {
        !           782:                return NULL;
        !           783:        }
        !           784: 
        !           785:        data->try++;
        !           786:        if (data->try > 1)
        !           787:        {
        !           788:                fprintf(data->prompt, "PIN invalid, aborting.\n");
        !           789:                return NULL;
        !           790:        }
        !           791:        fprintf(data->prompt, "Login to '%s' required\n", data->card);
        !           792:        fprintf(data->prompt, "PIN:\n");
        !           793:        if (fgets(buf, sizeof(buf), data->prompt))
        !           794:        {
        !           795:                secret = chunk_create(buf, strlen(buf));
        !           796:                if (secret.len > 1)
        !           797:                {       /* trim appended \n */
        !           798:                        secret.len--;
        !           799:                        if (match_me)
        !           800:                        {
        !           801:                                *match_me = ID_MATCH_PERFECT;
        !           802:                        }
        !           803:                        if (match_other)
        !           804:                        {
        !           805:                                *match_other = ID_MATCH_NONE;
        !           806:                        }
        !           807:                        DESTROY_IF(data->shared);
        !           808:                        data->shared = shared_key_create(SHARED_PIN, chunk_clone(secret));
        !           809:                        return data->shared->get_ref(data->shared);
        !           810:                }
        !           811:        }
        !           812:        return NULL;
        !           813: }
        !           814: 
        !           815: /**
        !           816:  * Load a smartcard with a PIN
        !           817:  */
        !           818: static bool load_pin(mem_cred_t *secrets, chunk_t line, int line_nr,
        !           819:                                         FILE *prompt)
        !           820: {
        !           821:        chunk_t sc = chunk_empty, secret = chunk_empty;
        !           822:        char smartcard[BUF_LEN], keyid[SC_PART_LEN], module[SC_PART_LEN];
        !           823:        private_key_t *key = NULL;
        !           824:        u_int slot;
        !           825:        chunk_t chunk;
        !           826:        shared_key_t *shared = NULL;
        !           827:        identification_t *id;
        !           828:        mem_cred_t *mem = NULL;
        !           829:        callback_cred_t *cb = NULL;
        !           830:        pin_cb_data_t pin_data;
        !           831:        smartcard_format_t format;
        !           832: 
        !           833:        err_t ugh = extract_value(&sc, &line);
        !           834: 
        !           835:        if (ugh != NULL)
        !           836:        {
        !           837:                DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
        !           838:                return FALSE;
        !           839:        }
        !           840:        if (sc.len == 0)
        !           841:        {
        !           842:                DBG1(DBG_CFG, "line %d: expected %%smartcard specifier", line_nr);
        !           843:                return FALSE;
        !           844:        }
        !           845:        snprintf(smartcard, sizeof(smartcard), "%.*s", (int)sc.len, sc.ptr);
        !           846:        smartcard[sizeof(smartcard) - 1] = '\0';
        !           847: 
        !           848:        format = parse_smartcard(smartcard, &slot, module, keyid);
        !           849:        if (format == SC_FORMAT_INVALID)
        !           850:        {
        !           851:                DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is not"
        !           852:                                " supported or invalid", line_nr);
        !           853:                return FALSE;
        !           854:        }
        !           855: 
        !           856:        if (!eat_whitespace(&line))
        !           857:        {
        !           858:                DBG1(DBG_CFG, "line %d: expected PIN", line_nr);
        !           859:                return FALSE;
        !           860:        }
        !           861:        ugh = extract_secret(&secret, &line);
        !           862:        if (ugh != NULL)
        !           863:        {
        !           864:                DBG1(DBG_CFG, "line %d: malformed PIN: %s", line_nr, ugh);
        !           865:                return FALSE;
        !           866:        }
        !           867: 
        !           868:        chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
        !           869:        if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
        !           870:        {
        !           871:                free(secret.ptr);
        !           872:                if (!prompt)
        !           873:                {       /* no IO channel to prompt, skip */
        !           874:                        chunk_clear(&chunk);
        !           875:                        return TRUE;
        !           876:                }
        !           877:                /* use callback credential set to prompt for the pin */
        !           878:                pin_data = (pin_cb_data_t){
        !           879:                        .prompt = prompt,
        !           880:                        .card = smartcard,
        !           881:                        .keyid = chunk,
        !           882:                };
        !           883:                cb = callback_cred_create_shared((void*)pin_cb, &pin_data);
        !           884:                lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
        !           885:        }
        !           886:        else
        !           887:        {
        !           888:                /* provide our pin in a temporary credential set */
        !           889:                shared = shared_key_create(SHARED_PIN, secret);
        !           890:                id = identification_create_from_encoding(ID_KEY_ID, chunk);
        !           891:                mem = mem_cred_create();
        !           892:                mem->add_shared(mem, shared->get_ref(shared), id, NULL);
        !           893:                lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
        !           894:        }
        !           895: 
        !           896:        /* unlock: smartcard needs the pin and potentially calls public set */
        !           897:        key = (private_key_t*)load_from_smartcard(format, slot, module, keyid,
        !           898:                                                                                          CRED_PRIVATE_KEY, KEY_ANY);
        !           899: 
        !           900:        if (key)
        !           901:        {
        !           902:                DBG1(DBG_CFG, "  loaded private key from %.*s", (int)sc.len, sc.ptr);
        !           903:                secrets->add_key(secrets, key);
        !           904:        }
        !           905:        if (mem)
        !           906:        {
        !           907:                if (!key)
        !           908:                {
        !           909:                        shared->destroy(shared);
        !           910:                        shared = NULL;
        !           911:                }
        !           912:                lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
        !           913:                mem->destroy(mem);
        !           914:        }
        !           915:        if (cb)
        !           916:        {
        !           917:                if (key)
        !           918:                {
        !           919:                        shared = pin_data.shared;
        !           920:                }
        !           921:                else
        !           922:                {
        !           923:                        DESTROY_IF(pin_data.shared);
        !           924:                }
        !           925:                lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
        !           926:                cb->destroy(cb);
        !           927:        }
        !           928:        if (shared)
        !           929:        {
        !           930:                id = identification_create_from_encoding(ID_KEY_ID, chunk);
        !           931:                secrets->add_shared(secrets, shared, id, NULL);
        !           932:        }
        !           933:        chunk_clear(&chunk);
        !           934:        return TRUE;
        !           935: }
        !           936: 
        !           937: /**
        !           938:  * Load a private key or PKCS#12 container from a file
        !           939:  */
        !           940: static bool load_from_file(chunk_t line, int line_nr, FILE *prompt,
        !           941:                                                   char *path, int type, int subtype,
        !           942:                                                   void **result)
        !           943: {
        !           944:        chunk_t filename;
        !           945:        chunk_t secret = chunk_empty;
        !           946: 
        !           947:        err_t ugh = extract_value(&filename, &line);
        !           948: 
        !           949:        if (ugh != NULL)
        !           950:        {
        !           951:                DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
        !           952:                return FALSE;
        !           953:        }
        !           954:        if (filename.len == 0)
        !           955:        {
        !           956:                DBG1(DBG_CFG, "line %d: empty filename", line_nr);
        !           957:                return FALSE;
        !           958:        }
        !           959:        if (*filename.ptr == '/')
        !           960:        {
        !           961:                /* absolute path name */
        !           962:                snprintf(path, PATH_MAX, "%.*s", (int)filename.len, filename.ptr);
        !           963:        }
        !           964:        else
        !           965:        {
        !           966:                /* relative path name */
        !           967:                snprintf(path, PATH_MAX, "%s/%.*s", PRIVATE_KEY_DIR,
        !           968:                                 (int)filename.len, filename.ptr);
        !           969:        }
        !           970: 
        !           971:        /* check for optional passphrase */
        !           972:        if (eat_whitespace(&line))
        !           973:        {
        !           974:                ugh = extract_secret(&secret, &line);
        !           975:                if (ugh != NULL)
        !           976:                {
        !           977:                        DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
        !           978:                        return FALSE;
        !           979:                }
        !           980:        }
        !           981:        if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
        !           982:        {
        !           983:                callback_cred_t *cb;
        !           984:                passphrase_cb_data_t pp_data = {
        !           985:                        .prompt = prompt,
        !           986:                        .type = type,
        !           987:                        .path = path,
        !           988:                        .try = 0,
        !           989:                };
        !           990: 
        !           991:                free(secret.ptr);
        !           992:                if (!prompt)
        !           993:                {
        !           994:                        *result = NULL;
        !           995:                        return TRUE;
        !           996:                }
        !           997:                /* add cache first so if valid passphrases are needed multiple times
        !           998:                 * the callback is not called anymore */
        !           999:                pp_data.cache = mem_cred_create();
        !          1000:                lib->credmgr->add_local_set(lib->credmgr, &pp_data.cache->set, FALSE);
        !          1001:                /* use callback credential set to prompt for the passphrase */
        !          1002:                cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data);
        !          1003:                lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
        !          1004: 
        !          1005:                *result = lib->creds->create(lib->creds, type, subtype,
        !          1006:                                                                         BUILD_FROM_FILE, path, BUILD_END);
        !          1007: 
        !          1008:                lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
        !          1009:                cb->destroy(cb);
        !          1010:                lib->credmgr->remove_local_set(lib->credmgr, &pp_data.cache->set);
        !          1011:                pp_data.cache->destroy(pp_data.cache);
        !          1012:        }
        !          1013:        else
        !          1014:        {
        !          1015:                mem_cred_t *mem = NULL;
        !          1016:                shared_key_t *shared;
        !          1017: 
        !          1018:                /* provide our pin in a temporary credential set */
        !          1019:                shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
        !          1020:                mem = mem_cred_create();
        !          1021:                mem->add_shared(mem, shared, NULL);
        !          1022:                if (eat_whitespace(&line))
        !          1023:                {       /* if there is a second passphrase add that too, could be needed for
        !          1024:                         * PKCS#12 files using different passwords for MAC and encryption */
        !          1025:                        ugh = extract_secret(&secret, &line);
        !          1026:                        if (ugh != NULL)
        !          1027:                        {
        !          1028:                                DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
        !          1029:                                mem->destroy(mem);
        !          1030:                                return FALSE;
        !          1031:                        }
        !          1032:                        shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
        !          1033:                        mem->add_shared(mem, shared, NULL);
        !          1034:                }
        !          1035:                lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
        !          1036: 
        !          1037:                *result = lib->creds->create(lib->creds, type, subtype,
        !          1038:                                                                         BUILD_FROM_FILE, path, BUILD_END);
        !          1039: 
        !          1040:                lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
        !          1041:                mem->destroy(mem);
        !          1042:        }
        !          1043:        return TRUE;
        !          1044: }
        !          1045: 
        !          1046: /**
        !          1047:  * Load a private key
        !          1048:  */
        !          1049: static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
        !          1050:                                                 FILE *prompt, key_type_t key_type)
        !          1051: {
        !          1052:        char path[PATH_MAX];
        !          1053:        private_key_t *key;
        !          1054: 
        !          1055:        if (!load_from_file(line, line_nr, prompt, path, CRED_PRIVATE_KEY,
        !          1056:                                                key_type, (void**)&key))
        !          1057:        {
        !          1058:                return FALSE;
        !          1059:        }
        !          1060:        if (key)
        !          1061:        {
        !          1062:                DBG1(DBG_CFG, "  loaded %N private key from '%s'",
        !          1063:                         key_type_names, key->get_type(key), path);
        !          1064:                secrets->add_key(secrets, key);
        !          1065:        }
        !          1066:        else
        !          1067:        {
        !          1068:                DBG1(DBG_CFG, "  loading private key from '%s' failed", path);
        !          1069:        }
        !          1070:        return TRUE;
        !          1071: }
        !          1072: 
        !          1073: /**
        !          1074:  * Load a PKCS#12 container
        !          1075:  */
        !          1076: static bool load_pkcs12(private_stroke_cred_t *this, mem_cred_t *secrets,
        !          1077:                                                chunk_t line, int line_nr, FILE *prompt)
        !          1078: {
        !          1079:        enumerator_t *enumerator;
        !          1080:        char path[PATH_MAX];
        !          1081:        certificate_t *cert;
        !          1082:        private_key_t *key;
        !          1083:        pkcs12_t *pkcs12;
        !          1084: 
        !          1085:        if (!load_from_file(line, line_nr, prompt, path, CRED_CONTAINER,
        !          1086:                                                CONTAINER_PKCS12, (void**)&pkcs12))
        !          1087:        {
        !          1088:                return FALSE;
        !          1089:        }
        !          1090:        if (!pkcs12)
        !          1091:        {
        !          1092:                DBG1(DBG_CFG, "  loading credentials from '%s' failed", path);
        !          1093:                return TRUE;
        !          1094:        }
        !          1095:        enumerator = pkcs12->create_cert_enumerator(pkcs12);
        !          1096:        while (enumerator->enumerate(enumerator, &cert))
        !          1097:        {
        !          1098:                x509_t *x509 = (x509_t*)cert;
        !          1099: 
        !          1100:                if (x509->get_flags(x509) & X509_CA)
        !          1101:                {
        !          1102:                        DBG1(DBG_CFG, "  loaded ca certificate \"%Y\" from '%s'",
        !          1103:                                 cert->get_subject(cert), path);
        !          1104:                }
        !          1105:                else
        !          1106:                {
        !          1107:                        DBG1(DBG_CFG, "  loaded certificate \"%Y\" from '%s'",
        !          1108:                                 cert->get_subject(cert), path);
        !          1109:                }
        !          1110:                this->creds->add_cert(this->creds, TRUE, cert->get_ref(cert));
        !          1111:        }
        !          1112:        enumerator->destroy(enumerator);
        !          1113:        enumerator = pkcs12->create_key_enumerator(pkcs12);
        !          1114:        while (enumerator->enumerate(enumerator, &key))
        !          1115:        {
        !          1116:                DBG1(DBG_CFG, "  loaded %N private key from '%s'",
        !          1117:                         key_type_names, key->get_type(key), path);
        !          1118:                secrets->add_key(secrets, key->get_ref(key));
        !          1119:        }
        !          1120:        enumerator->destroy(enumerator);
        !          1121:        pkcs12->container.destroy(&pkcs12->container);
        !          1122:        return TRUE;
        !          1123: }
        !          1124: 
        !          1125: /**
        !          1126:  * Load a shared key
        !          1127:  */
        !          1128: static bool load_shared(mem_cred_t *secrets, chunk_t line, int line_nr,
        !          1129:                                                shared_key_type_t type, chunk_t ids)
        !          1130: {
        !          1131:        shared_key_t *shared_key;
        !          1132:        linked_list_t *owners;
        !          1133:        chunk_t secret = chunk_empty;
        !          1134: 
        !          1135:        err_t ugh = extract_secret(&secret, &line);
        !          1136:        if (ugh != NULL)
        !          1137:        {
        !          1138:                DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh);
        !          1139:                return FALSE;
        !          1140:        }
        !          1141:        shared_key = shared_key_create(type, secret);
        !          1142:        DBG1(DBG_CFG, "  loaded %N secret for %s", shared_key_type_names, type,
        !          1143:                 ids.len > 0 ? (char*)ids.ptr : "%any");
        !          1144:        DBG4(DBG_CFG, "  secret: %#B", &secret);
        !          1145: 
        !          1146:        owners = linked_list_create();
        !          1147:        while (ids.len > 0)
        !          1148:        {
        !          1149:                chunk_t id;
        !          1150: 
        !          1151:                ugh = extract_value(&id, &ids);
        !          1152:                if (ugh != NULL)
        !          1153:                {
        !          1154:                        DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
        !          1155:                        shared_key->destroy(shared_key);
        !          1156:                        owners->destroy_offset(owners, offsetof(identification_t, destroy));
        !          1157:                        return FALSE;
        !          1158:                }
        !          1159:                if (id.len == 0)
        !          1160:                {
        !          1161:                        continue;
        !          1162:                }
        !          1163: 
        !          1164:                /* NULL terminate the ID string */
        !          1165:                *(id.ptr + id.len) = '\0';
        !          1166:                owners->insert_last(owners, identification_create_from_string(id.ptr));
        !          1167:        }
        !          1168:        if (!owners->get_count(owners))
        !          1169:        {
        !          1170:                owners->insert_last(owners,
        !          1171:                                        identification_create_from_encoding(ID_ANY, chunk_empty));
        !          1172:        }
        !          1173:        secrets->add_shared_list(secrets, shared_key, owners);
        !          1174:        return TRUE;
        !          1175: }
        !          1176: 
        !          1177: /**
        !          1178:  * reload ipsec.secrets
        !          1179:  */
        !          1180: static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
        !          1181:                                                 char *file, int level, FILE *prompt)
        !          1182: {
        !          1183:        int line_nr = 0;
        !          1184:        chunk_t *src, line;
        !          1185: 
        !          1186:        DBG1(DBG_CFG, "loading secrets from '%s'", file);
        !          1187:        src = chunk_map(file, FALSE);
        !          1188:        if (!src)
        !          1189:        {
        !          1190:                DBG1(DBG_CFG, "opening secrets file '%s' failed: %s", file,
        !          1191:                         strerror(errno));
        !          1192:                return;
        !          1193:        }
        !          1194: 
        !          1195:        if (!secrets)
        !          1196:        {
        !          1197:                secrets = mem_cred_create();
        !          1198:        }
        !          1199: 
        !          1200:        while (fetchline(src, &line))
        !          1201:        {
        !          1202:                chunk_t ids, token;
        !          1203:                key_type_t key_type;
        !          1204:                shared_key_type_t type;
        !          1205: 
        !          1206:                line_nr++;
        !          1207: 
        !          1208:                if (!eat_whitespace(&line))
        !          1209:                {
        !          1210:                        continue;
        !          1211:                }
        !          1212:                if (line.len > strlen("include ") && strpfx(line.ptr, "include "))
        !          1213:                {
        !          1214:                        char **expanded, *dir, pattern[PATH_MAX];
        !          1215:                        u_char *pos;
        !          1216: 
        !          1217:                        if (level > MAX_SECRETS_RECURSION)
        !          1218:                        {
        !          1219:                                DBG1(DBG_CFG, "maximum level of %d includes reached, ignored",
        !          1220:                                         MAX_SECRETS_RECURSION);
        !          1221:                                continue;
        !          1222:                        }
        !          1223:                        /* terminate filename by space */
        !          1224:                        line = chunk_skip(line, strlen("include "));
        !          1225:                        pos = memchr(line.ptr, ' ', line.len);
        !          1226:                        if (pos)
        !          1227:                        {
        !          1228:                                line.len = pos - line.ptr;
        !          1229:                        }
        !          1230:                        if (line.len && line.ptr[0] == '/')
        !          1231:                        {
        !          1232:                                if (line.len + 1 > sizeof(pattern))
        !          1233:                                {
        !          1234:                                        DBG1(DBG_CFG, "include pattern too long, ignored");
        !          1235:                                        continue;
        !          1236:                                }
        !          1237:                                snprintf(pattern, sizeof(pattern), "%.*s",
        !          1238:                                                 (int)line.len, line.ptr);
        !          1239:                        }
        !          1240:                        else
        !          1241:                        {       /* use directory of current file if relative */
        !          1242:                                dir = path_dirname(file);
        !          1243: 
        !          1244:                                if (line.len + 1 + strlen(dir) + 1 > sizeof(pattern))
        !          1245:                                {
        !          1246:                                        DBG1(DBG_CFG, "include pattern too long, ignored");
        !          1247:                                        free(dir);
        !          1248:                                        continue;
        !          1249:                                }
        !          1250:                                snprintf(pattern, sizeof(pattern), "%s/%.*s",
        !          1251:                                                 dir, (int)line.len, line.ptr);
        !          1252:                                free(dir);
        !          1253:                        }
        !          1254: #ifdef HAVE_GLOB_H
        !          1255:                        {
        !          1256:                                glob_t buf;
        !          1257:                                if (glob(pattern, GLOB_ERR, NULL, &buf) != 0)
        !          1258:                                {
        !          1259:                                        DBG1(DBG_CFG, "expanding file expression '%s' failed",
        !          1260:                                                 pattern);
        !          1261:                                }
        !          1262:                                else
        !          1263:                                {
        !          1264:                                        for (expanded = buf.gl_pathv; *expanded != NULL; expanded++)
        !          1265:                                        {
        !          1266:                                                load_secrets(this, secrets, *expanded, level + 1,
        !          1267:                                                                         prompt);
        !          1268:                                        }
        !          1269:                                }
        !          1270:                                globfree(&buf);
        !          1271:                        }
        !          1272: #else /* HAVE_GLOB_H */
        !          1273:                        /* if glob(3) is not available, try to load pattern directly */
        !          1274:                        load_secrets(this, secrets, pattern, level + 1, prompt);
        !          1275: #endif /* HAVE_GLOB_H */
        !          1276:                        continue;
        !          1277:                }
        !          1278: 
        !          1279:                if (line.len > 2 && strpfx(line.ptr, ": "))
        !          1280:                {
        !          1281:                        /* no ids, skip the ':' */
        !          1282:                        ids = chunk_empty;
        !          1283:                        line.ptr++;
        !          1284:                        line.len--;
        !          1285:                }
        !          1286:                else if (extract_token_str(&ids, " : ", &line))
        !          1287:                {
        !          1288:                        /* NULL terminate the extracted id string */
        !          1289:                        *(ids.ptr + ids.len) = '\0';
        !          1290:                }
        !          1291:                else
        !          1292:                {
        !          1293:                        DBG1(DBG_CFG, "line %d: missing ' : ' separator", line_nr);
        !          1294:                        break;
        !          1295:                }
        !          1296: 
        !          1297:                if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
        !          1298:                {
        !          1299:                        DBG1(DBG_CFG, "line %d: missing token", line_nr);
        !          1300:                        break;
        !          1301:                }
        !          1302:                if (match("RSA", &token) || match("ECDSA", &token) ||
        !          1303:                        match("BLISS", &token) || match("PKCS8", &token))
        !          1304:                {
        !          1305:                        if (match("RSA", &token))
        !          1306:                        {
        !          1307:                                key_type = KEY_RSA;
        !          1308:                        }
        !          1309:                        else if (match("ECDSA", &token))
        !          1310:                        {
        !          1311:                                key_type = KEY_ECDSA;
        !          1312:                        }
        !          1313:                        else if (match("BLISS", &token))
        !          1314:                        {
        !          1315:                                key_type = KEY_BLISS;
        !          1316:                        }
        !          1317:                        else
        !          1318:                        {
        !          1319:                                key_type = KEY_ANY;
        !          1320:                        }
        !          1321:                        if (!load_private(secrets, line, line_nr, prompt, key_type))
        !          1322:                        {
        !          1323:                                break;
        !          1324:                        }
        !          1325:                }
        !          1326:                else if (match("P12", &token))
        !          1327:                {
        !          1328:                        if (!load_pkcs12(this, secrets, line, line_nr, prompt))
        !          1329:                        {
        !          1330:                                break;
        !          1331:                        }
        !          1332:                }
        !          1333:                else if (match("PIN", &token))
        !          1334:                {
        !          1335:                        if (!load_pin(secrets, line, line_nr, prompt))
        !          1336:                        {
        !          1337:                                break;
        !          1338:                        }
        !          1339:                }
        !          1340:                else if ((match("PSK", &token) && (type = SHARED_IKE)) ||
        !          1341:                                 (match("EAP", &token) && (type = SHARED_EAP)) ||
        !          1342:                                 (match("NTLM", &token) && (type = SHARED_NT_HASH)) ||
        !          1343:                                 (match("XAUTH", &token) && (type = SHARED_EAP)))
        !          1344:                {
        !          1345:                        if (!load_shared(secrets, line, line_nr, type, ids))
        !          1346:                        {
        !          1347:                                break;
        !          1348:                        }
        !          1349:                }
        !          1350:                else
        !          1351:                {
        !          1352:                        DBG1(DBG_CFG, "line %d: token must be either RSA, ECDSA, BLISS, "
        !          1353:                                                  "PKCS8 P12, PIN, PSK, EAP, XAUTH or NTLM", line_nr);
        !          1354:                        break;
        !          1355:                }
        !          1356:        }
        !          1357:        chunk_unmap(src);
        !          1358: 
        !          1359:        if (level == 0)
        !          1360:        {       /* replace secrets in active credential set */
        !          1361:                this->creds->replace_secrets(this->creds, secrets, FALSE);
        !          1362:                secrets->destroy(secrets);
        !          1363:        }
        !          1364: }
        !          1365: 
        !          1366: /**
        !          1367:  * load all certificates from ipsec.d
        !          1368:  */
        !          1369: static void load_certs(private_stroke_cred_t *this)
        !          1370: {
        !          1371:        mem_cred_t *creds;
        !          1372: 
        !          1373:        DBG1(DBG_CFG, "loading ca certificates from '%s'",
        !          1374:                 CA_CERTIFICATE_DIR);
        !          1375:        creds = mem_cred_create();
        !          1376:        load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA, creds);
        !          1377:        this->ca->replace_certs(this->ca, creds);
        !          1378:        creds->destroy(creds);
        !          1379: 
        !          1380:        DBG1(DBG_CFG, "loading aa certificates from '%s'",
        !          1381:                 AA_CERTIFICATE_DIR);
        !          1382:        load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA, this->aacerts);
        !          1383: 
        !          1384:        DBG1(DBG_CFG, "loading ocsp signer certificates from '%s'",
        !          1385:                 OCSP_CERTIFICATE_DIR);
        !          1386:        load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509, X509_OCSP_SIGNER,
        !          1387:                                 this->creds);
        !          1388: 
        !          1389:        DBG1(DBG_CFG, "loading attribute certificates from '%s'",
        !          1390:                 ATTR_CERTIFICATE_DIR);
        !          1391:        load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0, this->creds);
        !          1392: 
        !          1393:        DBG1(DBG_CFG, "loading crls from '%s'",
        !          1394:                 CRL_DIR);
        !          1395:        load_certdir(this, CRL_DIR, CERT_X509_CRL, 0, this->creds);
        !          1396: }
        !          1397: 
        !          1398: METHOD(stroke_cred_t, reread, void,
        !          1399:        private_stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt)
        !          1400: {
        !          1401:        mem_cred_t *creds;
        !          1402: 
        !          1403:        if (msg->reread.flags & REREAD_SECRETS)
        !          1404:        {
        !          1405:                DBG1(DBG_CFG, "rereading secrets");
        !          1406:                load_secrets(this, NULL, this->secrets_file, 0, prompt);
        !          1407:        }
        !          1408:        if (msg->reread.flags & REREAD_CACERTS)
        !          1409:        {
        !          1410:                /* first reload certificates in ca sections, so we can refer to them */
        !          1411:                this->ca->reload_certs(this->ca);
        !          1412: 
        !          1413:                DBG1(DBG_CFG, "rereading ca certificates from '%s'",
        !          1414:                         CA_CERTIFICATE_DIR);
        !          1415:                creds = mem_cred_create();
        !          1416:                load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA, creds);
        !          1417:                this->ca->replace_certs(this->ca, creds);
        !          1418:                creds->destroy(creds);
        !          1419:        }
        !          1420:        if (msg->reread.flags & REREAD_AACERTS)
        !          1421:        {
        !          1422:                DBG1(DBG_CFG, "rereading aa certificates from '%s'",
        !          1423:                         AA_CERTIFICATE_DIR);
        !          1424:                creds = mem_cred_create();
        !          1425:                load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA, creds);
        !          1426:                this->aacerts->replace_certs(this->aacerts, creds, FALSE);
        !          1427:                creds->destroy(creds);
        !          1428:                lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
        !          1429:        }
        !          1430:        if (msg->reread.flags & REREAD_OCSPCERTS)
        !          1431:        {
        !          1432:                DBG1(DBG_CFG, "rereading ocsp signer certificates from '%s'",
        !          1433:                         OCSP_CERTIFICATE_DIR);
        !          1434:                load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509,
        !          1435:                         X509_OCSP_SIGNER, this->creds);
        !          1436:        }
        !          1437:        if (msg->reread.flags & REREAD_ACERTS)
        !          1438:        {
        !          1439:                DBG1(DBG_CFG, "rereading attribute certificates from '%s'",
        !          1440:                         ATTR_CERTIFICATE_DIR);
        !          1441:                load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0, this->creds);
        !          1442:        }
        !          1443:        if (msg->reread.flags & REREAD_CRLS)
        !          1444:        {
        !          1445:                DBG1(DBG_CFG, "rereading crls from '%s'",
        !          1446:                         CRL_DIR);
        !          1447:                load_certdir(this, CRL_DIR, CERT_X509_CRL, 0, this->creds);
        !          1448:        }
        !          1449: }
        !          1450: 
        !          1451: METHOD(stroke_cred_t, add_shared, void,
        !          1452:        private_stroke_cred_t *this, shared_key_t *shared, linked_list_t *owners)
        !          1453: {
        !          1454:        this->creds->add_shared_list(this->creds, shared, owners);
        !          1455: }
        !          1456: 
        !          1457: METHOD(stroke_cred_t, destroy, void,
        !          1458:        private_stroke_cred_t *this)
        !          1459: {
        !          1460:        lib->credmgr->remove_set(lib->credmgr, &this->aacerts->set);
        !          1461:        lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
        !          1462:        this->aacerts->destroy(this->aacerts);
        !          1463:        this->creds->destroy(this->creds);
        !          1464:        free(this);
        !          1465: }
        !          1466: 
        !          1467: /*
        !          1468:  * see header file
        !          1469:  */
        !          1470: stroke_cred_t *stroke_cred_create(stroke_ca_t *ca)
        !          1471: {
        !          1472:        private_stroke_cred_t *this;
        !          1473: 
        !          1474:        INIT(this,
        !          1475:                .public = {
        !          1476:                        .set = {
        !          1477:                                .create_private_enumerator = (void*)return_null,
        !          1478:                                .create_cert_enumerator = (void*)return_null,
        !          1479:                                .create_shared_enumerator = (void*)return_null,
        !          1480:                                .create_cdp_enumerator = (void*)return_null,
        !          1481:                                .cache_cert = (void*)_cache_cert,
        !          1482:                        },
        !          1483:                        .reread = _reread,
        !          1484:                        .load_peer = _load_peer,
        !          1485:                        .load_pubkey = _load_pubkey,
        !          1486:                        .add_shared = _add_shared,
        !          1487:                        .cachecrl = _cachecrl,
        !          1488:                        .destroy = _destroy,
        !          1489:                },
        !          1490:                .secrets_file = lib->settings->get_str(lib->settings,
        !          1491:                                                                "%s.plugins.stroke.secrets_file", SECRETS_FILE,
        !          1492:                                                                lib->ns),
        !          1493:                .creds = mem_cred_create(),
        !          1494:                .aacerts = mem_cred_create(),
        !          1495:                .ca = ca,
        !          1496:        );
        !          1497: 
        !          1498:        if (lib->settings->get_bool(lib->settings, "%s.cache_crls", FALSE, lib->ns))
        !          1499:        {
        !          1500:                cachecrl(this, TRUE);
        !          1501:        }
        !          1502:        lib->credmgr->add_set(lib->credmgr, &this->creds->set);
        !          1503:        lib->credmgr->add_set(lib->credmgr, &this->aacerts->set);
        !          1504: 
        !          1505:        this->force_ca_cert = lib->settings->get_bool(lib->settings,
        !          1506:                                                "%s.plugins.stroke.ignore_missing_ca_basic_constraint",
        !          1507:                                                FALSE, lib->ns);
        !          1508: 
        !          1509:        load_certs(this);
        !          1510:        load_secrets(this, NULL, this->secrets_file, 0, NULL);
        !          1511: 
        !          1512:        return &this->public;
        !          1513: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>