Annotation of embedaddon/strongswan/src/libstrongswan/plugins/keychain/keychain_creds.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2013 Martin Willi
        !             3:  * Copyright (C) 2013 revosec AG
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify it
        !             6:  * under the terms of the GNU General Public License as published by the
        !             7:  * Free Software Foundation; either version 2 of the License, or (at your
        !             8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !             9:  *
        !            10:  * This program is distributed in the hope that it will be useful, but
        !            11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            13:  * for more details.
        !            14:  */
        !            15: 
        !            16: #include "keychain_creds.h"
        !            17: 
        !            18: #include <utils/debug.h>
        !            19: #include <credentials/sets/mem_cred.h>
        !            20: #include <processing/jobs/callback_job.h>
        !            21: 
        !            22: #include <Security/Security.h>
        !            23: 
        !            24: /**
        !            25:  * System Roots keychain
        !            26:  */
        !            27: #define SYSTEM_ROOTS "/System/Library/Keychains/SystemRootCertificates.keychain"
        !            28: 
        !            29: /**
        !            30:  * System keychain
        !            31:  */
        !            32: #define SYSTEM "/Library/Keychains/System.keychain"
        !            33: 
        !            34: typedef struct private_keychain_creds_t private_keychain_creds_t;
        !            35: 
        !            36: /**
        !            37:  * Private data of an keychain_creds_t object.
        !            38:  */
        !            39: struct private_keychain_creds_t {
        !            40: 
        !            41:        /**
        !            42:         * Public keychain_creds_t interface.
        !            43:         */
        !            44:        keychain_creds_t public;
        !            45: 
        !            46:        /**
        !            47:         * Active in-memory credential set
        !            48:         */
        !            49:        mem_cred_t *set;
        !            50: 
        !            51:        /**
        !            52:         * System roots credential set
        !            53:         */
        !            54:        mem_cred_t *roots;
        !            55: 
        !            56:        /**
        !            57:         * Run loop of event monitoring thread
        !            58:         */
        !            59:        CFRunLoopRef loop;
        !            60: };
        !            61: 
        !            62: /**
        !            63:  * Load a credential sets with certificates from a keychain path
        !            64:  */
        !            65: static mem_cred_t* load_certs(private_keychain_creds_t *this, char *path)
        !            66: {
        !            67:        SecKeychainRef keychain;
        !            68:        SecKeychainSearchRef search;
        !            69:        SecKeychainItemRef item;
        !            70:        mem_cred_t *set;
        !            71:        OSStatus status;
        !            72:        int loaded = 0;
        !            73: 
        !            74:        set = mem_cred_create();
        !            75: 
        !            76:        DBG2(DBG_CFG, "loading certificates from %s:", path);
        !            77:        status = SecKeychainOpen(path, &keychain);
        !            78:        if (status == errSecSuccess)
        !            79:        {
        !            80:                status = SecKeychainSearchCreateFromAttributes(keychain,
        !            81:                                                                        kSecCertificateItemClass, NULL, &search);
        !            82:                if (status == errSecSuccess)
        !            83:                {
        !            84:                        while (SecKeychainSearchCopyNext(search, &item) == errSecSuccess)
        !            85:                        {
        !            86:                                certificate_t *cert;
        !            87:                                UInt32 len;
        !            88:                                void *data;
        !            89: 
        !            90:                                if (SecKeychainItemCopyAttributesAndData(item, NULL, NULL, NULL,
        !            91:                                                                                                &len, &data) == errSecSuccess)
        !            92:                                {
        !            93:                                        cert = lib->creds->create(lib->creds,
        !            94:                                                                CRED_CERTIFICATE, CERT_X509,
        !            95:                                                                BUILD_BLOB_ASN1_DER, chunk_create(data, len),
        !            96:                                                                BUILD_END);
        !            97:                                        if (cert)
        !            98:                                        {
        !            99:                                                DBG2(DBG_CFG, "  loaded '%Y'", cert->get_subject(cert));
        !           100:                                                set->add_cert(set, TRUE, cert);
        !           101:                                                loaded++;
        !           102:                                        }
        !           103:                                        SecKeychainItemFreeAttributesAndData(NULL, data);
        !           104:                                }
        !           105:                                CFRelease(item);
        !           106:                        }
        !           107:                        CFRelease(search);
        !           108:                }
        !           109:                CFRelease(keychain);
        !           110:        }
        !           111:        DBG1(DBG_CFG, "loaded %d certificates from %s", loaded, path);
        !           112:        return set;
        !           113: }
        !           114: 
        !           115: /**
        !           116:  * Callback function reloading keychain on changes
        !           117:  */
        !           118: static OSStatus keychain_cb(SecKeychainEvent keychainEvent,
        !           119:                                                        SecKeychainCallbackInfo *info,
        !           120:                                                        private_keychain_creds_t *this)
        !           121: {
        !           122:        mem_cred_t *new;
        !           123: 
        !           124:        DBG1(DBG_CFG, "received keychain event, reloading credentials");
        !           125: 
        !           126:        /* register new before removing old */
        !           127:        new = load_certs(this, SYSTEM);
        !           128:        lib->credmgr->add_set(lib->credmgr, &new->set);
        !           129:        lib->credmgr->remove_set(lib->credmgr, &this->set->set);
        !           130: 
        !           131:        lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
        !           132: 
        !           133:        this->set->destroy(this->set);
        !           134:        this->set = new;
        !           135: 
        !           136:        return errSecSuccess;
        !           137: }
        !           138: 
        !           139: /**
        !           140:  * Wait for changes in the keychain and handle them
        !           141:  */
        !           142: static job_requeue_t monitor_changes(private_keychain_creds_t *this)
        !           143: {
        !           144:        if (SecKeychainAddCallback((SecKeychainCallback)keychain_cb,
        !           145:                                                kSecAddEventMask | kSecDeleteEventMask |
        !           146:                                                kSecUpdateEventMask | kSecTrustSettingsChangedEventMask,
        !           147:                                                this) == errSecSuccess)
        !           148:        {
        !           149:                this->loop = CFRunLoopGetCurrent();
        !           150: 
        !           151:                /* does not return until cancelled */
        !           152:                CFRunLoopRun();
        !           153: 
        !           154:                this->loop = NULL;
        !           155:                SecKeychainRemoveCallback((SecKeychainCallback)keychain_cb);
        !           156:        }
        !           157:        return JOB_REQUEUE_NONE;
        !           158: }
        !           159: 
        !           160: /**
        !           161:  * Cancel the monitoring thread in its RunLoop
        !           162:  */
        !           163: static bool cancel_monitor(private_keychain_creds_t *this)
        !           164: {
        !           165:        if (this->loop)
        !           166:        {
        !           167:                CFRunLoopStop(this->loop);
        !           168:        }
        !           169:        return TRUE;
        !           170: }
        !           171: 
        !           172: METHOD(keychain_creds_t, destroy, void,
        !           173:        private_keychain_creds_t *this)
        !           174: {
        !           175:        lib->credmgr->remove_set(lib->credmgr, &this->set->set);
        !           176:        lib->credmgr->remove_set(lib->credmgr, &this->roots->set);
        !           177:        this->set->destroy(this->set);
        !           178:        this->roots->destroy(this->roots);
        !           179:        free(this);
        !           180: }
        !           181: 
        !           182: /**
        !           183:  * See header
        !           184:  */
        !           185: keychain_creds_t *keychain_creds_create()
        !           186: {
        !           187:        private_keychain_creds_t *this;
        !           188: 
        !           189:        INIT(this,
        !           190:                .public = {
        !           191:                        .destroy = _destroy,
        !           192:                },
        !           193:        );
        !           194: 
        !           195:        this->roots = load_certs(this, SYSTEM_ROOTS);
        !           196:        this->set = load_certs(this, SYSTEM);
        !           197: 
        !           198:        lib->credmgr->add_set(lib->credmgr, &this->roots->set);
        !           199:        lib->credmgr->add_set(lib->credmgr, &this->set->set);
        !           200: 
        !           201:        lib->processor->queue_job(lib->processor,
        !           202:                        (job_t*)callback_job_create_with_prio((void*)monitor_changes,
        !           203:                                        this, NULL, (void*)cancel_monitor, JOB_PRIO_CRITICAL));
        !           204: 
        !           205:        return &this->public;
        !           206: }

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