Annotation of embedaddon/strongswan/src/libcharon/plugins/vici/vici_authority.c, revision 1.1.1.2

1.1       misho       1: /*
1.1.1.2 ! misho       2:  * Copyright (C) 2016-2020 Tobias Brunner
1.1       misho       3:  * Copyright (C) 2015 Andreas Steffen
                      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: #define _GNU_SOURCE
                     18: 
                     19: #include "vici_authority.h"
                     20: #include "vici_builder.h"
                     21: 
                     22: #include <threading/rwlock.h>
                     23: #include <collections/linked_list.h>
                     24: #include <credentials/certificates/x509.h>
                     25: #include <utils/debug.h>
                     26: 
                     27: #include <stdio.h>
                     28: 
                     29: typedef struct private_vici_authority_t private_vici_authority_t;
                     30: 
                     31: /**
                     32:  * Private data of an vici_authority_t object.
                     33:  */
                     34: struct private_vici_authority_t {
                     35: 
                     36:        /**
                     37:         * Public vici_authority_t interface.
                     38:         */
                     39:        vici_authority_t public;
                     40: 
                     41:        /**
                     42:         * Dispatcher
                     43:         */
                     44:        vici_dispatcher_t *dispatcher;
                     45: 
                     46:        /**
1.1.1.2 ! misho      47:         * List of certification authorities (authority_t*)
1.1       misho      48:         */
1.1.1.2 ! misho      49:        linked_list_t *authorities;
1.1       misho      50: 
                     51:        /**
1.1.1.2 ! misho      52:         * List of CA certificates (ca_cert_t*)
1.1       misho      53:         */
1.1.1.2 ! misho      54:        linked_list_t *certs;
1.1       misho      55: 
                     56:        /**
                     57:         * rwlock to lock access to certification authorities
                     58:         */
                     59:        rwlock_t *lock;
                     60: 
                     61: };
                     62: 
                     63: typedef struct authority_t authority_t;
                     64: 
                     65: /**
                     66:  * loaded certification authorities
                     67:  */
                     68: struct authority_t {
                     69: 
                     70:        /**
                     71:         * Name of the certification authority
                     72:         */
                     73:        char *name;
                     74: 
                     75:        /**
                     76:         * Reference to CA certificate
                     77:         */
                     78:        certificate_t *cert;
                     79: 
                     80:        /**
                     81:         * CRL URIs
                     82:         */
                     83:        linked_list_t *crl_uris;
                     84: 
                     85:        /**
                     86:         * OCSP URIs
                     87:         */
                     88:        linked_list_t *ocsp_uris;
                     89: 
                     90:        /**
                     91:         * Base URI used for certificates from this CA
                     92:         */
                     93:        char *cert_uri_base;
                     94: };
                     95: 
                     96: /**
                     97:  * create a new certification authority
                     98:  */
                     99: static authority_t *authority_create(char *name)
                    100: {
                    101:        authority_t *authority;
                    102: 
                    103:        INIT(authority,
                    104:                .name = strdup(name),
                    105:                .crl_uris = linked_list_create(),
                    106:                .ocsp_uris = linked_list_create(),
                    107:        );
                    108: 
                    109:        return authority;
                    110: }
                    111: 
1.1.1.2 ! misho     112: CALLBACK(authority_destroy, void,
        !           113:        authority_t *this)
1.1       misho     114: {
                    115:        this->crl_uris->destroy_function(this->crl_uris, free);
                    116:        this->ocsp_uris->destroy_function(this->ocsp_uris, free);
                    117:        DESTROY_IF(this->cert);
                    118:        free(this->cert_uri_base);
                    119:        free(this->name);
                    120:        free(this);
                    121: }
                    122: 
1.1.1.2 ! misho     123: typedef struct ca_cert_t ca_cert_t;
        !           124: 
        !           125: /**
        !           126:  * Loaded CA certificate.
        !           127:  */
        !           128: struct ca_cert_t {
        !           129: 
        !           130:        /**
        !           131:         * Reference to certificate.
        !           132:         */
        !           133:        certificate_t *cert;
        !           134: 
        !           135:        /**
        !           136:         * The number of authority sections referring to this certificate.
        !           137:         */
        !           138:        u_int count;
        !           139: 
        !           140:        /**
        !           141:         * TRUE if this certificate was (also) added externally.
        !           142:         */
        !           143:        bool external;
        !           144: };
        !           145: 
        !           146: /**
        !           147:  * Destroy a CA certificate entry
        !           148:  */
        !           149: CALLBACK(ca_cert_destroy, void,
        !           150:        ca_cert_t *this)
        !           151: {
        !           152:        this->cert->destroy(this->cert);
        !           153:        free(this);
        !           154: }
        !           155: 
        !           156: CALLBACK(match_cert, bool,
        !           157:        ca_cert_t *item, va_list args)
        !           158: {
        !           159:        certificate_t *cert;
        !           160: 
        !           161:        VA_ARGS_VGET(args, cert);
        !           162:        return cert->equals(cert, item->cert);
        !           163: }
        !           164: 
        !           165: /**
        !           166:  * Add a CA certificate to the local store
        !           167:  */
        !           168: static certificate_t *add_cert_internal(private_vici_authority_t *this,
        !           169:                                                                                certificate_t *cert, bool external)
        !           170: {
        !           171:        ca_cert_t *found;
        !           172: 
        !           173:        if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert))
        !           174:        {
        !           175:                cert->destroy(cert);
        !           176:                cert = found->cert->get_ref(found->cert);
        !           177:        }
        !           178:        else
        !           179:        {
        !           180:                INIT(found,
        !           181:                        .cert = cert->get_ref(cert)
        !           182:                );
        !           183:                this->certs->insert_first(this->certs, found);
        !           184:        }
        !           185:        if (external)
        !           186:        {
        !           187:                found->external = TRUE;
        !           188:        }
        !           189:        else
        !           190:        {
        !           191:                found->count++;
        !           192:        }
        !           193:        return cert;
        !           194: }
        !           195: 
        !           196: CALLBACK(remove_external_certs, bool,
        !           197:        ca_cert_t *item, void *unused)
        !           198: {
        !           199:        if (item->external)
        !           200:        {
        !           201:                item->external = FALSE;
        !           202: 
        !           203:                if (!item->count)
        !           204:                {
        !           205:                        ca_cert_destroy(item);
        !           206:                        return TRUE;
        !           207:                }
        !           208:        }
        !           209:        return FALSE;
        !           210: }
        !           211: 
        !           212: CALLBACK2(remove_cert, bool,
        !           213:        ca_cert_t *item, certificate_t *cert)
        !           214: {
        !           215:        if (cert == item->cert)
        !           216:        {
        !           217:                if (--item->count == 0 && !item->external)
        !           218:                {
        !           219:                        ca_cert_destroy(item);
        !           220:                        return TRUE;
        !           221:                }
        !           222:        }
        !           223:        return FALSE;
        !           224: }
1.1       misho     225: 
                    226: /**
                    227:  * Create a (error) reply message
                    228:  */
                    229: static vici_message_t* create_reply(char *fmt, ...)
                    230: {
                    231:        vici_builder_t *builder;
                    232:        va_list args;
                    233: 
                    234:        builder = vici_builder_create();
                    235:        builder->add_kv(builder, "success", fmt ? "no" : "yes");
                    236:        if (fmt)
                    237:        {
                    238:                va_start(args, fmt);
                    239:                builder->vadd_kv(builder, "errmsg", fmt, args);
                    240:                va_end(args);
                    241:        }
                    242:        return builder->finalize(builder);
                    243: }
                    244: 
                    245: /**
                    246:  * A rule to parse a key/value or list item
                    247:  */
                    248: typedef struct {
                    249:        /** name of the key/value or list */
                    250:        char *name;
                    251:        /** function to parse value */
                    252:        bool (*parse)(void *out, chunk_t value);
                    253:        /** result, passed to parse() */
                    254:        void *out;
                    255: } parse_rule_t;
                    256: 
                    257: /**
                    258:  * Parse key/values using a rule-set
                    259:  */
                    260: static bool parse_rules(parse_rule_t *rules, int count, char *name,
                    261:                                                chunk_t value, vici_message_t **reply)
                    262: {
                    263:        int i;
                    264: 
                    265:        for (i = 0; i < count; i++)
                    266:        {
                    267:                if (streq(name, rules[i].name))
                    268:                {
                    269:                        if (rules[i].parse(rules[i].out, value))
                    270:                        {
                    271:                                return TRUE;
                    272:                        }
                    273:                        *reply = create_reply("invalid value for: %s, authority discarded",
                    274:                                                                  name);
                    275:                        return FALSE;
                    276:                }
                    277:        }
                    278:        *reply = create_reply("unknown option: %s, authority discarded", name);
                    279:        return FALSE;
                    280: }
                    281: 
                    282: /**
                    283:  * Parse callback data, passed to each callback
                    284:  */
                    285: typedef struct {
                    286:        private_vici_authority_t *this;
                    287:        vici_message_t *reply;
                    288: } request_data_t;
                    289: 
                    290: /**
                    291:  * Data associated with an authority load
                    292:  */
                    293: typedef struct {
                    294:        request_data_t *request;
                    295:        authority_t *authority;
                    296:        char *handle;
                    297:        uint32_t slot;
                    298:        char *module;
                    299:        char *file;
                    300: } load_data_t;
                    301: 
                    302: /**
                    303:  * Clean up data associated with an authority load
                    304:  */
                    305: static void free_load_data(load_data_t *data)
                    306: {
                    307:        if (data->authority)
                    308:        {
                    309:                authority_destroy(data->authority);
                    310:        }
                    311:        free(data->handle);
                    312:        free(data->module);
                    313:        free(data->file);
                    314:        free(data);
                    315: }
                    316: 
                    317: /**
                    318:  * Parse a string
                    319:  */
                    320: CALLBACK(parse_string, bool,
                    321:        char **str, chunk_t v)
                    322: {
                    323:        if (!chunk_printable(v, NULL, ' '))
                    324:        {
                    325:                return FALSE;
                    326:        }
                    327:        *str = strndup(v.ptr, v.len);
                    328: 
                    329:        return TRUE;
                    330: }
                    331: 
                    332: /**
                    333:  * Parse a uint32_t
                    334:  */
                    335: CALLBACK(parse_uint32, bool,
                    336:        uint32_t *out, chunk_t v)
                    337: {
                    338:        char buf[16], *end;
                    339:        u_long l;
                    340: 
                    341:        if (!vici_stringify(v, buf, sizeof(buf)))
                    342:        {
                    343:                return FALSE;
                    344:        }
                    345:        l = strtoul(buf, &end, 0);
                    346:        if (*end == 0)
                    347:        {
                    348:                *out = l;
                    349:                return TRUE;
                    350:        }
                    351:        return FALSE;
                    352: }
                    353: 
                    354: /**
                    355:  * Parse list of URIs
                    356:  */
                    357: CALLBACK(parse_uris, bool,
                    358:        linked_list_t *out, chunk_t v)
                    359: {
                    360:        char *uri;
                    361: 
                    362:        if (!chunk_printable(v, NULL, ' '))
                    363:        {
                    364:                return FALSE;
                    365:        }
                    366:        uri = strndup(v.ptr, v.len);
                    367:        out->insert_last(out, uri);
                    368: 
                    369:        return TRUE;
                    370: }
                    371: 
                    372: /**
                    373:  * Parse a CA certificate
                    374:  */
                    375: CALLBACK(parse_cacert, bool,
                    376:        certificate_t **cacert, chunk_t v)
                    377: {
                    378:        certificate_t *cert;
                    379:        x509_t *x509;
                    380: 
                    381:        cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
                    382:                                                                                  BUILD_BLOB_PEM, v, BUILD_END);
                    383:        if (!cert)
                    384:        {
                    385:                return create_reply("parsing %N certificate failed",
                    386:                                                        certificate_type_names, CERT_X509);
                    387:        }
                    388:        x509 = (x509_t*)cert;
                    389: 
                    390:        if ((x509->get_flags(x509) & X509_CA) != X509_CA)
                    391:        {
                    392:                cert->destroy(cert);
                    393:                return create_reply("certificate without CA flag, rejected");
                    394:        }
                    395:        *cacert = cert;
                    396: 
                    397:        return TRUE;
                    398: }
                    399: 
                    400: CALLBACK(authority_kv, bool,
                    401:        load_data_t *data, vici_message_t *message, char *name, chunk_t value)
                    402: {
                    403:        parse_rule_t rules[] = {
                    404:                { "cacert",                     parse_cacert, &data->authority->cert                    },
                    405:                { "file",                       parse_string, &data->file                                               },
                    406:                { "handle",                     parse_string, &data->handle                                             },
                    407:                { "slot",                       parse_uint32, &data->slot                                               },
                    408:                { "module",                     parse_string, &data->module                                             },
                    409:                { "cert_uri_base",      parse_string, &data->authority->cert_uri_base   },
                    410:        };
                    411: 
                    412:        return parse_rules(rules, countof(rules), name, value,
                    413:                                           &data->request->reply);
                    414: }
                    415: 
                    416: CALLBACK(authority_li, bool,
                    417:        load_data_t *data, vici_message_t *message, char *name, chunk_t value)
                    418: {
                    419:        parse_rule_t rules[] = {
                    420:                { "crl_uris",   parse_uris, data->authority->crl_uris  },
                    421:                { "ocsp_uris",  parse_uris, data->authority->ocsp_uris },
                    422:        };
                    423: 
                    424:        return parse_rules(rules, countof(rules), name, value,
                    425:                                           &data->request->reply);
                    426: }
                    427: 
                    428: static void log_authority_data(authority_t *authority)
                    429: {
                    430:        enumerator_t *enumerator;
                    431:        identification_t *subject;
                    432:        bool first = TRUE;
                    433:        char *uri;
                    434: 
                    435:        subject = authority->cert->get_subject(authority->cert);
                    436:        DBG2(DBG_CFG, "  cacert = %Y", subject);
                    437: 
                    438:        enumerator = authority->crl_uris->create_enumerator(authority->crl_uris);
                    439:        while (enumerator->enumerate(enumerator, &uri))
                    440:        {
                    441:                if (first)
                    442:                {
                    443:                        DBG2(DBG_CFG, "  crl_uris = %s", uri);
                    444:                        first = FALSE;
                    445:                }
                    446:                else
                    447:                {
                    448:                        DBG2(DBG_CFG, "             %s", uri);
                    449:                }
                    450:        }
                    451:        enumerator->destroy(enumerator);
                    452: 
                    453:        first = TRUE;
                    454:        enumerator = authority->ocsp_uris->create_enumerator(authority->ocsp_uris);
                    455:        while (enumerator->enumerate(enumerator, &uri))
                    456:        {
                    457:                if (first)
                    458:                {
                    459:                        DBG2(DBG_CFG, "  ocsp_uris = %s", uri);
                    460:                        first = FALSE;
                    461:                }
                    462:                else
                    463:                {
                    464:                        DBG2(DBG_CFG, "              %s", uri);
                    465:                }
                    466:        }
                    467:        enumerator->destroy(enumerator);
                    468: 
                    469:        if (authority->cert_uri_base)
                    470:        {
                    471:                DBG2(DBG_CFG, "  cert_uri_base = %s", authority->cert_uri_base);
                    472:        }
                    473: }
                    474: 
                    475: CALLBACK(authority_sn, bool,
                    476:        request_data_t *request, vici_message_t *message,
                    477:        vici_parse_context_t *ctx, char *name)
                    478: {
                    479:        enumerator_t *enumerator;
                    480:        linked_list_t *authorities;
                    481:        authority_t *authority;
                    482:        load_data_t *data;
                    483:        chunk_t handle;
                    484: 
                    485:        INIT(data,
                    486:                .request = request,
                    487:                .authority = authority_create(name),
                    488:                .slot = -1,
                    489:        );
                    490: 
                    491:        DBG2(DBG_CFG, " authority %s:", name);
                    492: 
                    493:        if (!message->parse(message, ctx, NULL, authority_kv, authority_li, data))
                    494:        {
                    495:                free_load_data(data);
                    496:                return FALSE;
                    497:        }
                    498:        if (!data->authority->cert)
                    499:        {
                    500:                if (data->file)
                    501:                {
                    502:                        data->authority->cert = lib->creds->create(lib->creds,
                    503:                                                                                CRED_CERTIFICATE, CERT_X509,
                    504:                                                                                BUILD_FROM_FILE, data->file, BUILD_END);
                    505:                }
                    506:                else if (data->handle)
                    507:                {
                    508:                        handle = chunk_from_hex(chunk_from_str(data->handle), NULL);
                    509:                        if (data->slot != -1)
                    510:                        {
                    511:                                data->authority->cert = lib->creds->create(lib->creds,
                    512:                                                                CRED_CERTIFICATE, CERT_X509,
                    513:                                                                BUILD_PKCS11_KEYID, handle,
                    514:                                                                BUILD_PKCS11_SLOT, data->slot,
                    515:                                                                data->module ? BUILD_PKCS11_MODULE : BUILD_END,
                    516:                                                                data->module, BUILD_END);
                    517:                        }
                    518:                        else
                    519:                        {
                    520:                                data->authority->cert = lib->creds->create(lib->creds,
                    521:                                                                CRED_CERTIFICATE, CERT_X509,
                    522:                                                                BUILD_PKCS11_KEYID, handle,
                    523:                                                                data->module ? BUILD_PKCS11_MODULE : BUILD_END,
                    524:                                                                data->module, BUILD_END);
                    525:                        }
                    526:                        chunk_free(&handle);
                    527:                }
                    528:        }
                    529:        if (!data->authority->cert)
                    530:        {
                    531:                request->reply = create_reply("CA certificate missing: %s", name);
                    532:                free_load_data(data);
                    533:                return FALSE;
                    534:        }
                    535:        log_authority_data(data->authority);
                    536: 
                    537:        request->this->lock->write_lock(request->this->lock);
                    538: 
1.1.1.2 ! misho     539:        data->authority->cert = add_cert_internal(request->this,
        !           540:                                                                                          data->authority->cert, FALSE);
        !           541: 
1.1       misho     542:        authorities = request->this->authorities;
                    543:        enumerator = authorities->create_enumerator(authorities);
                    544:        while (enumerator->enumerate(enumerator, &authority))
                    545:        {
                    546:                if (streq(authority->name, name))
                    547:                {
                    548:                        /* remove the old authority definition */
                    549:                        authorities->remove_at(authorities, enumerator);
1.1.1.2 ! misho     550:                        request->this->certs->remove(request->this->certs, authority->cert,
        !           551:                                                                                 remove_cert);
1.1       misho     552:                        authority_destroy(authority);
                    553:                        break;
                    554:                }
                    555:        }
                    556:        enumerator->destroy(enumerator);
                    557:        authorities->insert_last(authorities, data->authority);
                    558: 
                    559:        request->this->lock->unlock(request->this->lock);
1.1.1.2 ! misho     560:        data->authority = NULL;
1.1       misho     561:        free_load_data(data);
                    562: 
                    563:        return TRUE;
                    564: }
                    565: 
                    566: CALLBACK(load_authority, vici_message_t*,
                    567:        private_vici_authority_t *this, char *name, u_int id, vici_message_t *message)
                    568: {
                    569:        request_data_t request = {
                    570:                .this = this,
                    571:        };
                    572: 
                    573:        if (!message->parse(message, NULL, authority_sn, NULL, NULL, &request))
                    574:        {
                    575:                if (request.reply)
                    576:                {
                    577:                        return request.reply;
                    578:                }
                    579:                return create_reply("parsing request failed");
                    580:        }
                    581:        return create_reply(NULL);
                    582: }
                    583: 
                    584: CALLBACK(unload_authority, vici_message_t*,
                    585:        private_vici_authority_t *this, char *name, u_int id, vici_message_t *message)
                    586: {
                    587:        enumerator_t *enumerator;
                    588:        authority_t *authority;
                    589:        char *authority_name;
                    590:        bool found = FALSE;
                    591: 
                    592:        authority_name = message->get_str(message, NULL, "name");
                    593:        if (!authority_name)
                    594:        {
                    595:                return create_reply("unload: missing authority name");
                    596:        }
                    597: 
                    598:        this->lock->write_lock(this->lock);
                    599:        enumerator = this->authorities->create_enumerator(this->authorities);
                    600:        while (enumerator->enumerate(enumerator, &authority))
                    601:        {
                    602:                if (streq(authority->name, authority_name))
                    603:                {
                    604:                        this->authorities->remove_at(this->authorities, enumerator);
1.1.1.2 ! misho     605:                        this->certs->remove(this->certs, authority->cert, remove_cert);
1.1       misho     606:                        authority_destroy(authority);
                    607:                        found = TRUE;
                    608:                        break;
                    609:                }
                    610:        }
                    611:        enumerator->destroy(enumerator);
                    612:        this->lock->unlock(this->lock);
                    613: 
                    614:        if (!found)
                    615:        {
                    616:                return create_reply("unload: authority '%s' not found", authority_name);
                    617:        }
1.1.1.2 ! misho     618:        lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
1.1       misho     619:        return create_reply(NULL);
                    620: }
                    621: 
                    622: CALLBACK(get_authorities, vici_message_t*,
                    623:        private_vici_authority_t *this, char *name, u_int id,
                    624:        vici_message_t *message)
                    625: {
                    626:        vici_builder_t *builder;
                    627:        enumerator_t *enumerator;
                    628:        authority_t *authority;
                    629: 
                    630:        builder = vici_builder_create();
                    631:        builder->begin_list(builder, "authorities");
                    632: 
                    633:        this->lock->read_lock(this->lock);
                    634:        enumerator = this->authorities->create_enumerator(this->authorities);
                    635:        while (enumerator->enumerate(enumerator, &authority))
                    636:        {
                    637:                builder->add_li(builder, "%s", authority->name);
                    638:        }
                    639:        enumerator->destroy(enumerator);
                    640:        this->lock->unlock(this->lock);
                    641: 
                    642:        builder->end_list(builder);
                    643: 
                    644:        return builder->finalize(builder);
                    645: }
                    646: 
                    647: CALLBACK(list_authorities, vici_message_t*,
                    648:        private_vici_authority_t *this, char *name, u_int id, vici_message_t *request)
                    649: {
                    650:        enumerator_t *enumerator, *e;
                    651:        authority_t *authority;
                    652:        vici_builder_t *b;
                    653:        char *str, *uri;
                    654: 
                    655:        str = request->get_str(request, NULL, "name");
                    656: 
                    657:        this->lock->read_lock(this->lock);
                    658:        enumerator = this->authorities->create_enumerator(this->authorities);
                    659:        while (enumerator->enumerate(enumerator, &authority))
                    660:        {
                    661:                if (str && !streq(str, authority->name))
                    662:                {
                    663:                        continue;
                    664:                }
                    665:                b = vici_builder_create();
                    666: 
                    667:                /* open authority section */
                    668:                b->begin_section(b, authority->name);
                    669: 
                    670:                /* subject DN of cacert */
                    671:                b->add_kv(b, "cacert", "%Y",
                    672:                                          authority->cert->get_subject(authority->cert));
                    673: 
                    674:                /* list of crl_uris */
                    675:                b->begin_list(b, "crl_uris");
                    676:                e = authority->crl_uris->create_enumerator(authority->crl_uris);
                    677:                while (e->enumerate(e, &uri))
                    678:                {
                    679:                        b->add_li(b, "%s", uri);
                    680:                }
                    681:                e->destroy(e);
                    682:                b->end_list(b);
                    683: 
                    684:                /* list of ocsp_uris */
                    685:                b->begin_list(b, "ocsp_uris");
                    686:                e = authority->ocsp_uris->create_enumerator(authority->ocsp_uris);
                    687:                while (e->enumerate(e, &uri))
                    688:                {
                    689:                        b->add_li(b, "%s", uri);
                    690:                }
                    691:                e->destroy(e);
                    692:                b->end_list(b);
                    693: 
                    694:                /* cert_uri_base */
                    695:                if (authority->cert_uri_base)
                    696:                {
                    697:                        b->add_kv(b, "cert_uri_base", "%s", authority->cert_uri_base);
                    698:                }
                    699: 
                    700:                /* close authority and raise event */
                    701:                b->end_section(b);
                    702:                this->dispatcher->raise_event(this->dispatcher, "list-authority", id,
                    703:                                                                          b->finalize(b));
                    704:        }
                    705:        enumerator->destroy(enumerator);
                    706:        this->lock->unlock(this->lock);
                    707: 
                    708:        b = vici_builder_create();
                    709:        return b->finalize(b);
                    710: }
                    711: 
                    712: static void manage_command(private_vici_authority_t *this,
                    713:                                                   char *name, vici_command_cb_t cb, bool reg)
                    714: {
                    715:        this->dispatcher->manage_command(this->dispatcher, name,
                    716:                                                                         reg ? cb : NULL, this);
                    717: }
                    718: 
                    719: /**
                    720:  * (Un-)register dispatcher functions
                    721:  */
                    722: static void manage_commands(private_vici_authority_t *this, bool reg)
                    723: {
                    724:        this->dispatcher->manage_event(this->dispatcher, "list-authority", reg);
                    725: 
                    726:        manage_command(this, "load-authority", load_authority, reg);
                    727:        manage_command(this, "unload-authority", unload_authority, reg);
                    728:        manage_command(this, "get-authorities", get_authorities, reg);
                    729:        manage_command(this, "list-authorities", list_authorities, reg);
                    730: }
                    731: 
                    732: /**
1.1.1.2 ! misho     733:  * Data for the certificate and CDP enumerator
1.1       misho     734:  */
                    735: typedef struct {
                    736:        private_vici_authority_t *this;
                    737:        certificate_type_t type;
1.1.1.2 ! misho     738:        key_type_t key;
1.1       misho     739:        identification_t *id;
1.1.1.2 ! misho     740: } cert_data_t;
1.1       misho     741: 
1.1.1.2 ! misho     742: CALLBACK(cert_data_destroy, void,
        !           743:        cert_data_t *data)
1.1       misho     744: {
                    745:        data->this->lock->unlock(data->this->lock);
                    746:        free(data);
                    747: }
                    748: 
1.1.1.2 ! misho     749: CALLBACK(certs_filter, bool,
        !           750:        cert_data_t *data, enumerator_t *orig, va_list args)
        !           751: {
        !           752:        ca_cert_t *ca;
        !           753:        certificate_t **out;
        !           754: 
        !           755:        VA_ARGS_VGET(args, out);
        !           756: 
        !           757:        while (orig->enumerate(orig, &ca))
        !           758:        {
        !           759:                if (certificate_matches(ca->cert, data->type, data->key, data->id))
        !           760:                {
        !           761:                        *out = ca->cert;
        !           762:                        return TRUE;
        !           763:                }
        !           764:        }
        !           765:        return FALSE;
        !           766: }
        !           767: 
        !           768: METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
        !           769:        private_vici_authority_t *this, certificate_type_t cert, key_type_t key,
        !           770:        identification_t *id, bool trusted)
        !           771: {
        !           772:        enumerator_t *enumerator;
        !           773:        cert_data_t *data;
        !           774: 
        !           775:        INIT(data,
        !           776:                .this = this,
        !           777:                .type = cert,
        !           778:                .key = key,
        !           779:                .id = id,
        !           780:        );
        !           781: 
        !           782:        this->lock->read_lock(this->lock);
        !           783:        enumerator = this->certs->create_enumerator(this->certs);
        !           784:        return enumerator_create_filter(enumerator, certs_filter, data,
        !           785:                                                                        cert_data_destroy);
        !           786: }
        !           787: 
        !           788: CALLBACK(create_inner_cdp, enumerator_t*,
        !           789:        authority_t *authority, cert_data_t *data)
1.1       misho     790: {
                    791:        public_key_t *public;
                    792:        enumerator_t *enumerator = NULL;
                    793:        linked_list_t *list;
                    794: 
                    795:        if (data->type == CERT_X509_OCSP_RESPONSE)
                    796:        {
                    797:                list = authority->ocsp_uris;
                    798:        }
                    799:        else
                    800:        {
                    801:                list = authority->crl_uris;
                    802:        }
                    803: 
                    804:        public = authority->cert->get_public_key(authority->cert);
                    805:        if (public)
                    806:        {
                    807:                if (!data->id)
                    808:                {
                    809:                        enumerator = list->create_enumerator(list);
                    810:                }
                    811:                else
                    812:                {
1.1.1.2 ! misho     813:                        if (public->has_fingerprint(public,
        !           814:                                                                                data->id->get_encoding(data->id)))
1.1       misho     815:                        {
                    816:                                enumerator = list->create_enumerator(list);
                    817:                        }
                    818:                }
                    819:                public->destroy(public);
                    820:        }
                    821:        return enumerator;
                    822: }
                    823: 
1.1.1.2 ! misho     824: CALLBACK(create_inner_cdp_hashandurl, enumerator_t*,
        !           825:        authority_t *authority, cert_data_t *data)
1.1       misho     826: {
                    827:        enumerator_t *enumerator = NULL;
                    828: 
                    829:        if (!data->id || !authority->cert_uri_base)
                    830:        {
                    831:                return NULL;
                    832:        }
                    833: 
1.1.1.2 ! misho     834:        if (authority->cert->has_subject(authority->cert,
        !           835:                                                                         data->id) != ID_MATCH_NONE)
1.1       misho     836:        {
                    837:                enumerator = enumerator_create_single(strdup(authority->cert_uri_base),
                    838:                                                                                          free);
                    839:        }
                    840:        return enumerator;
                    841: }
                    842: 
                    843: METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
                    844:        private_vici_authority_t *this, certificate_type_t type,
                    845:        identification_t *id)
                    846: {
1.1.1.2 ! misho     847:        cert_data_t *data;
1.1       misho     848: 
                    849:        switch (type)
                    850:        {       /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */
                    851:                case CERT_X509:
                    852:                case CERT_X509_CRL:
                    853:                case CERT_X509_OCSP_RESPONSE:
                    854:                case CERT_ANY:
                    855:                        break;
                    856:                default:
                    857:                        return NULL;
                    858:        }
                    859: 
1.1.1.2 ! misho     860:        INIT(data,
        !           861:                .this = this,
        !           862:                .type = type,
        !           863:                .id = id,
        !           864:        );
1.1       misho     865: 
1.1.1.2 ! misho     866:        this->lock->read_lock(this->lock);
1.1       misho     867:        return enumerator_create_nested(
                    868:                        this->authorities->create_enumerator(this->authorities),
                    869:                        (type == CERT_X509) ? (void*)create_inner_cdp_hashandurl :
1.1.1.2 ! misho     870:                        (void*)create_inner_cdp, data, cert_data_destroy);
        !           871: }
        !           872: 
        !           873: METHOD(vici_authority_t, add_ca_cert, certificate_t*,
        !           874:        private_vici_authority_t *this, certificate_t *cert)
        !           875: {
        !           876:        this->lock->write_lock(this->lock);
        !           877:        cert = add_cert_internal(this, cert, TRUE);
        !           878:        this->lock->unlock(this->lock);
        !           879:        return cert;
        !           880: }
        !           881: 
        !           882: METHOD(vici_authority_t, clear_ca_certs, void,
        !           883:        private_vici_authority_t *this)
        !           884: {
        !           885:        this->lock->write_lock(this->lock);
        !           886:        this->certs->remove(this->certs, NULL, remove_external_certs);
        !           887:        this->lock->unlock(this->lock);
1.1       misho     888: }
                    889: 
                    890: METHOD(vici_authority_t, destroy, void,
                    891:        private_vici_authority_t *this)
                    892: {
                    893:        manage_commands(this, FALSE);
                    894: 
                    895:        this->authorities->destroy_function(this->authorities,
                    896:                                                                           (void*)authority_destroy);
1.1.1.2 ! misho     897:        this->certs->destroy_function(this->certs, ca_cert_destroy);
1.1       misho     898:        this->lock->destroy(this->lock);
                    899:        free(this);
                    900: }
                    901: 
                    902: /**
                    903:  * See header
                    904:  */
1.1.1.2 ! misho     905: vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher)
1.1       misho     906: {
                    907:        private_vici_authority_t *this;
                    908: 
                    909:        INIT(this,
                    910:                .public = {
                    911:                        .set = {
                    912:                                .create_private_enumerator = (void*)return_null,
1.1.1.2 ! misho     913:                                .create_cert_enumerator = _create_cert_enumerator,
1.1       misho     914:                                .create_shared_enumerator = (void*)return_null,
                    915:                                .create_cdp_enumerator = _create_cdp_enumerator,
                    916:                                .cache_cert = (void*)nop,
                    917:                        },
1.1.1.2 ! misho     918:                        .add_ca_cert = _add_ca_cert,
        !           919:                        .clear_ca_certs = _clear_ca_certs,
1.1       misho     920:                        .destroy = _destroy,
                    921:                },
                    922:                .dispatcher = dispatcher,
                    923:                .authorities = linked_list_create(),
1.1.1.2 ! misho     924:                .certs = linked_list_create(),
1.1       misho     925:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
                    926:        );
                    927: 
                    928:        manage_commands(this, TRUE);
                    929: 
                    930:        return &this->public;
                    931: }

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