c667983b99e0c0d889545afd6a3df58b65c4238d
[strongswan.git] / src / libstrongswan / plugins / keychain / keychain_creds.c
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
21 #include <Security/Security.h>
22
23 /**
24 * System Root certificates keychain
25 */
26 #define SYSTEM_ROOTS "/System/Library/Keychains/SystemRootCertificates.keychain"
27
28 typedef struct private_keychain_creds_t private_keychain_creds_t;
29
30 /**
31 * Private data of an keychain_creds_t object.
32 */
33 struct private_keychain_creds_t {
34
35 /**
36 * Public keychain_creds_t interface.
37 */
38 keychain_creds_t public;
39
40 /**
41 * Active in-memory credential set
42 */
43 mem_cred_t *set;
44
45 /**
46 * System roots credential set
47 */
48 mem_cred_t *roots;
49 };
50
51 /**
52 * Load a credential set with System Root certificates
53 */
54 static mem_cred_t* load_roots(private_keychain_creds_t *this)
55 {
56 SecKeychainRef keychain;
57 SecKeychainSearchRef search;
58 SecKeychainItemRef item;
59 mem_cred_t *set;
60 OSStatus status;
61
62 set = mem_cred_create();
63
64 DBG1(DBG_CFG, "loading System Roots certificates:");
65 status = SecKeychainOpen(SYSTEM_ROOTS, &keychain);
66 if (status == errSecSuccess)
67 {
68 status = SecKeychainSearchCreateFromAttributes(keychain,
69 kSecCertificateItemClass, NULL, &search);
70 if (status == errSecSuccess)
71 {
72 while (SecKeychainSearchCopyNext(search, &item) == errSecSuccess)
73 {
74 certificate_t *cert;
75 UInt32 len;
76 void *data;
77
78 if (SecKeychainItemCopyAttributesAndData(item, NULL, NULL, NULL,
79 &len, &data) == errSecSuccess)
80 {
81 cert = lib->creds->create(lib->creds,
82 CRED_CERTIFICATE, CERT_X509,
83 BUILD_BLOB_ASN1_DER, chunk_create(data, len),
84 BUILD_END);
85 if (cert)
86 {
87 DBG1(DBG_CFG, " loaded '%Y'", cert->get_subject(cert));
88 set->add_cert(set, TRUE, cert);
89 }
90 SecKeychainItemFreeAttributesAndData(NULL, data);
91 }
92 CFRelease(item);
93 }
94 CFRelease(search);
95 }
96 CFRelease(keychain);
97 }
98 return set;
99 }
100
101 /**
102 * Create a credential set loaded with certificates
103 */
104 static mem_cred_t* load_creds(private_keychain_creds_t *this)
105 {
106 mem_cred_t *set;
107 OSStatus status;
108 CFDictionaryRef query;
109 CFArrayRef certs;
110 const void* keys[] = {
111 kSecReturnData,
112 kSecMatchLimit,
113 kSecClass,
114 kSecAttrCanVerify,
115 kSecMatchTrustedOnly,
116 };
117 const void* values[] = {
118 kCFBooleanTrue,
119 kSecMatchLimitAll,
120 kSecClassCertificate,
121 kCFBooleanTrue,
122 kCFBooleanTrue,
123 };
124 int i;
125
126 set = mem_cred_create();
127
128 DBG1(DBG_CFG, "loading System certificates:");
129 query = CFDictionaryCreate(NULL, keys, values, countof(keys),
130 &kCFTypeDictionaryKeyCallBacks,
131 &kCFTypeDictionaryValueCallBacks);
132 if (query)
133 {
134 status = SecItemCopyMatching(query, (CFTypeRef*)&certs);
135 CFRelease(query);
136 if (status == errSecSuccess)
137 {
138 for (i = 0; i < CFArrayGetCount(certs); i++)
139 {
140 certificate_t *cert;
141 CFDataRef data;
142 chunk_t chunk;
143
144 data = CFArrayGetValueAtIndex(certs, i);
145 if (data)
146 {
147 chunk = chunk_create((char*)CFDataGetBytePtr(data),
148 CFDataGetLength(data));
149 cert = lib->creds->create(lib->creds,
150 CRED_CERTIFICATE, CERT_X509,
151 BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
152 if (cert)
153 {
154 DBG1(DBG_CFG, " loaded '%Y'", cert->get_subject(cert));
155 set->add_cert(set, TRUE, cert);
156 }
157 }
158 }
159 CFRelease(certs);
160 }
161 }
162 return set;
163 }
164
165 METHOD(keychain_creds_t, destroy, void,
166 private_keychain_creds_t *this)
167 {
168 lib->credmgr->remove_set(lib->credmgr, &this->set->set);
169 lib->credmgr->remove_set(lib->credmgr, &this->roots->set);
170 this->set->destroy(this->set);
171 this->roots->destroy(this->roots);
172 free(this);
173 }
174
175 /**
176 * See header
177 */
178 keychain_creds_t *keychain_creds_create()
179 {
180 private_keychain_creds_t *this;
181
182 INIT(this,
183 .public = {
184 .destroy = _destroy,
185 },
186 );
187
188 this->roots = load_roots(this);
189 this->set = load_creds(this);
190
191 lib->credmgr->add_set(lib->credmgr, &this->roots->set);
192 lib->credmgr->add_set(lib->credmgr, &this->set->set);
193
194 return &this->public;
195 }