Return to keychain_creds.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / keychain |
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: }