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>