Annotation of embedaddon/strongswan/src/libstrongswan/plugins/keychain/keychain_creds.c, revision 1.1.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>