android: New release after improving connectivity/scheduling
[strongswan.git] / src / libstrongswan / plugins / pkcs11 / pkcs11_plugin.c
1 /*
2 * Copyright (C) 2011 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * Copyright (C) 2010 Martin Willi
6 * Copyright (C) 2010 revosec AG
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #include "pkcs11_plugin.h"
20
21 #include <library.h>
22 #include <utils/debug.h>
23 #include <collections/linked_list.h>
24 #include <threading/mutex.h>
25 #include <threading/rwlock.h>
26
27 #include "pkcs11_manager.h"
28 #include "pkcs11_creds.h"
29 #include "pkcs11_private_key.h"
30 #include "pkcs11_public_key.h"
31 #include "pkcs11_hasher.h"
32 #include "pkcs11_rng.h"
33 #include "pkcs11_dh.h"
34
35 typedef struct private_pkcs11_plugin_t private_pkcs11_plugin_t;
36
37 /**
38 * private data of pkcs11_plugin
39 */
40 struct private_pkcs11_plugin_t {
41
42 /**
43 * public functions
44 */
45 pkcs11_plugin_t public;
46
47 /**
48 * PKCS#11 library/slot manager
49 */
50 pkcs11_manager_t *manager;
51
52 /**
53 * List of credential sets, pkcs11_creds_t
54 */
55 linked_list_t *creds;
56
57 /**
58 * mutex to lock list
59 */
60 mutex_t *mutex;
61
62 /**
63 * TRUE if events from tokens are to be handled
64 */
65 bool handle_events;
66
67 /**
68 * Lock for the above flag
69 */
70 rwlock_t *handle_events_lock;
71 };
72
73 /**
74 * Token event callback function
75 */
76 static void token_event_cb(private_pkcs11_plugin_t *this, pkcs11_library_t *p11,
77 CK_SLOT_ID slot, bool add)
78 {
79 enumerator_t *enumerator;
80 pkcs11_creds_t *creds, *found = NULL;
81
82 this->handle_events_lock->read_lock(this->handle_events_lock);
83 if (add && this->handle_events)
84 {
85 if (lib->settings->get_bool(lib->settings,
86 "%s.plugins.pkcs11.modules.%s.load_certs",
87 TRUE, lib->ns, p11->get_name(p11)))
88 {
89 creds = pkcs11_creds_create(p11, slot);
90 if (creds)
91 {
92 this->mutex->lock(this->mutex);
93 this->creds->insert_last(this->creds, creds);
94 this->mutex->unlock(this->mutex);
95 lib->credmgr->add_set(lib->credmgr, &creds->set);
96 }
97 }
98 }
99 else if (this->handle_events)
100 {
101 this->mutex->lock(this->mutex);
102 enumerator = this->creds->create_enumerator(this->creds);
103 while (enumerator->enumerate(enumerator, &creds))
104 {
105 if (creds->get_library(creds) == p11 &&
106 creds->get_slot(creds) == slot)
107 {
108 found = creds;
109 this->creds->remove_at(this->creds, enumerator);
110 break;
111 }
112 }
113 enumerator->destroy(enumerator);
114 this->mutex->unlock(this->mutex);
115
116 if (found)
117 {
118 lib->credmgr->remove_set(lib->credmgr, &found->set);
119 found->destroy(found);
120 /* flush the cache after a token is gone */
121 lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
122 }
123 }
124 this->handle_events_lock->unlock(this->handle_events_lock);
125 }
126
127 METHOD(plugin_t, get_name, char*,
128 private_pkcs11_plugin_t *this)
129 {
130 return "pkcs11";
131 }
132
133 /**
134 * Load/unload certificates from tokens.
135 */
136 static bool handle_certs(private_pkcs11_plugin_t *this,
137 plugin_feature_t *feature, bool reg, void *data)
138 {
139 this->handle_events_lock->write_lock(this->handle_events_lock);
140 this->handle_events = reg;
141 this->handle_events_lock->unlock(this->handle_events_lock);
142
143 if (reg)
144 {
145 enumerator_t *enumerator;
146 pkcs11_library_t *p11;
147 CK_SLOT_ID slot;
148
149 enumerator = this->manager->create_token_enumerator(this->manager);
150 while (enumerator->enumerate(enumerator, &p11, &slot))
151 {
152 token_event_cb(this, p11, slot, TRUE);
153 }
154 enumerator->destroy(enumerator);
155
156 lib->creds->add_builder(lib->creds, CRED_CERTIFICATE,
157 CERT_X509, FALSE, (void*)pkcs11_creds_load);
158 }
159 else
160 {
161 pkcs11_creds_t *creds;
162
163 while (this->creds->remove_last(this->creds, (void**)&creds) == SUCCESS)
164 {
165 lib->credmgr->remove_set(lib->credmgr, &creds->set);
166 creds->destroy(creds);
167 }
168
169 lib->creds->remove_builder(lib->creds, (void*)pkcs11_creds_load);
170 }
171 return TRUE;
172 }
173
174 METHOD(plugin_t, reload, bool,
175 private_pkcs11_plugin_t *this)
176 {
177 if (lib->settings->get_bool(lib->settings, "%s.plugins.pkcs11.reload_certs",
178 FALSE, lib->ns))
179 {
180 DBG1(DBG_CFG, "reloading certificates from PKCS#11 tokens");
181 handle_certs(this, NULL, FALSE, NULL);
182 handle_certs(this, NULL, TRUE, NULL);
183 return TRUE;
184 }
185 return FALSE;
186 }
187
188 METHOD(plugin_t, get_features, int,
189 private_pkcs11_plugin_t *this, plugin_feature_t *features[])
190 {
191 static plugin_feature_t f_hash[] = {
192 PLUGIN_REGISTER(HASHER, pkcs11_hasher_create),
193 PLUGIN_PROVIDE(HASHER, HASH_MD2),
194 PLUGIN_PROVIDE(HASHER, HASH_MD5),
195 PLUGIN_PROVIDE(HASHER, HASH_SHA1),
196 PLUGIN_PROVIDE(HASHER, HASH_SHA256),
197 PLUGIN_PROVIDE(HASHER, HASH_SHA384),
198 PLUGIN_PROVIDE(HASHER, HASH_SHA512),
199 };
200 static plugin_feature_t f_dh[] = {
201 PLUGIN_REGISTER(DH, pkcs11_dh_create),
202 PLUGIN_PROVIDE(DH, MODP_2048_BIT),
203 PLUGIN_PROVIDE(DH, MODP_2048_224),
204 PLUGIN_PROVIDE(DH, MODP_2048_256),
205 PLUGIN_PROVIDE(DH, MODP_1536_BIT),
206 PLUGIN_PROVIDE(DH, MODP_3072_BIT),
207 PLUGIN_PROVIDE(DH, MODP_4096_BIT),
208 PLUGIN_PROVIDE(DH, MODP_6144_BIT),
209 PLUGIN_PROVIDE(DH, MODP_8192_BIT),
210 PLUGIN_PROVIDE(DH, MODP_1024_BIT),
211 PLUGIN_PROVIDE(DH, MODP_1024_160),
212 PLUGIN_PROVIDE(DH, MODP_768_BIT),
213 PLUGIN_PROVIDE(DH, MODP_CUSTOM),
214 };
215 static plugin_feature_t f_ecdh[] = {
216 PLUGIN_REGISTER(DH, pkcs11_dh_create),
217 PLUGIN_PROVIDE(DH, ECP_192_BIT),
218 PLUGIN_PROVIDE(DH, ECP_224_BIT),
219 PLUGIN_PROVIDE(DH, ECP_256_BIT),
220 PLUGIN_PROVIDE(DH, ECP_384_BIT),
221 PLUGIN_PROVIDE(DH, ECP_521_BIT),
222 };
223 static plugin_feature_t f_rng[] = {
224 PLUGIN_REGISTER(RNG, pkcs11_rng_create),
225 PLUGIN_PROVIDE(RNG, RNG_STRONG),
226 PLUGIN_PROVIDE(RNG, RNG_TRUE),
227 };
228 static plugin_feature_t f_privkey[] = {
229 PLUGIN_REGISTER(PRIVKEY, pkcs11_private_key_connect, FALSE),
230 PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
231 };
232 static plugin_feature_t f_pubkey[] = {
233 PLUGIN_REGISTER(PUBKEY, pkcs11_public_key_load, TRUE),
234 PLUGIN_PROVIDE(PUBKEY, KEY_RSA),
235 PLUGIN_PROVIDE(PUBKEY, KEY_ECDSA),
236 };
237 static plugin_feature_t f_manager[] = {
238 PLUGIN_CALLBACK((plugin_feature_callback_t)handle_certs, NULL),
239 PLUGIN_PROVIDE(CUSTOM, "pkcs11-certs"),
240 PLUGIN_DEPENDS(CERT_DECODE, CERT_X509),
241 };
242 static plugin_feature_t f[countof(f_hash) + countof(f_dh) + countof(f_rng) +
243 countof(f_ecdh) + countof(f_privkey) +
244 countof(f_pubkey) + countof(f_manager)] = {};
245 static int count = 0;
246
247 if (!count)
248 { /* initialize only once */
249 bool use_ecc = lib->settings->get_bool(lib->settings,
250 "%s.plugins.pkcs11.use_ecc", FALSE, lib->ns);
251 plugin_features_add(f, f_manager, countof(f_manager), &count);
252 /* private key handling for EC keys is not disabled by use_ecc */
253 plugin_features_add(f, f_privkey, countof(f_privkey), &count);
254 if (lib->settings->get_bool(lib->settings,
255 "%s.plugins.pkcs11.use_pubkey", FALSE, lib->ns))
256 {
257 plugin_features_add(f, f_pubkey, countof(f_pubkey) - (use_ecc ? 0 : 1),
258 &count);
259 }
260 if (lib->settings->get_bool(lib->settings,
261 "%s.plugins.pkcs11.use_hasher", FALSE, lib->ns))
262 {
263 plugin_features_add(f, f_hash, countof(f_hash), &count);
264 }
265 if (lib->settings->get_bool(lib->settings,
266 "%s.plugins.pkcs11.use_rng", FALSE, lib->ns))
267 {
268 plugin_features_add(f, f_rng, countof(f_rng), &count);
269 }
270 if (lib->settings->get_bool(lib->settings,
271 "%s.plugins.pkcs11.use_dh", FALSE, lib->ns))
272 {
273 plugin_features_add(f, f_dh, countof(f_dh), &count);
274 if (use_ecc)
275 {
276 plugin_features_add(f, f_ecdh, countof(f_ecdh), &count);
277 }
278 }
279 }
280 *features = f;
281 return count;
282 }
283
284 METHOD(plugin_t, destroy, void,
285 private_pkcs11_plugin_t *this)
286 {
287 lib->set(lib, "pkcs11-manager", NULL);
288 this->manager->destroy(this->manager);
289 this->creds->destroy(this->creds);
290 this->mutex->destroy(this->mutex);
291 this->handle_events_lock->destroy(this->handle_events_lock);
292 free(this);
293 }
294
295 /*
296 * see header file
297 */
298 plugin_t *pkcs11_plugin_create()
299 {
300 private_pkcs11_plugin_t *this;
301
302 INIT(this,
303 .public = {
304 .plugin = {
305 .get_name = _get_name,
306 .get_features = _get_features,
307 .reload = _reload,
308 .destroy = _destroy,
309 },
310 },
311 .creds = linked_list_create(),
312 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
313 .handle_events_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
314 );
315
316 this->manager = pkcs11_manager_create((void*)token_event_cb, this);
317 lib->set(lib, "pkcs11-manager", this->manager);
318
319 return &this->public.plugin;
320 }