Added an option to reload certificates from PKCS#11 tokens on SIGHUP
[strongswan.git] / src / libstrongswan / plugins / pkcs11 / pkcs11_plugin.c
1 /*
2 * Copyright (C) 2011 Tobias Brunner
3 * 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 <debug.h>
23 #include <utils/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 creds = pkcs11_creds_create(p11, slot);
86 if (creds)
87 {
88 this->mutex->lock(this->mutex);
89 this->creds->insert_last(this->creds, creds);
90 this->mutex->unlock(this->mutex);
91 lib->credmgr->add_set(lib->credmgr, &creds->set);
92 }
93 }
94 else if (this->handle_events)
95 {
96 this->mutex->lock(this->mutex);
97 enumerator = this->creds->create_enumerator(this->creds);
98 while (enumerator->enumerate(enumerator, &creds))
99 {
100 if (creds->get_library(creds) == p11 &&
101 creds->get_slot(creds) == slot)
102 {
103 found = creds;
104 this->creds->remove_at(this->creds, enumerator);
105 break;
106 }
107 }
108 enumerator->destroy(enumerator);
109 this->mutex->unlock(this->mutex);
110
111 if (found)
112 {
113 lib->credmgr->remove_set(lib->credmgr, &found->set);
114 found->destroy(found);
115 /* flush the cache after a token is gone */
116 lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
117 }
118 }
119 this->handle_events_lock->unlock(this->handle_events_lock);
120 }
121
122 METHOD(plugin_t, get_name, char*,
123 private_pkcs11_plugin_t *this)
124 {
125 return "pkcs11";
126 }
127
128 /**
129 * Load/unload certificates from tokens.
130 */
131 static bool handle_certs(private_pkcs11_plugin_t *this,
132 plugin_feature_t *feature, bool reg, void *data)
133 {
134 this->handle_events_lock->write_lock(this->handle_events_lock);
135 this->handle_events = reg;
136 this->handle_events_lock->unlock(this->handle_events_lock);
137
138 if (reg)
139 {
140 enumerator_t *enumerator;
141 pkcs11_library_t *p11;
142 CK_SLOT_ID slot;
143
144 enumerator = this->manager->create_token_enumerator(this->manager);
145 while (enumerator->enumerate(enumerator, &p11, &slot))
146 {
147 token_event_cb(this, p11, slot, TRUE);
148 }
149 enumerator->destroy(enumerator);
150 }
151 else
152 {
153 pkcs11_creds_t *creds;
154
155 while (this->creds->remove_last(this->creds, (void**)&creds) == SUCCESS)
156 {
157 lib->credmgr->remove_set(lib->credmgr, &creds->set);
158 creds->destroy(creds);
159 }
160 }
161 return TRUE;
162 }
163
164 METHOD(plugin_t, reload, bool,
165 private_pkcs11_plugin_t *this)
166 {
167 if (lib->settings->get_bool(lib->settings,
168 "libstrongswan.plugins.pkcs11.reload_certs", FALSE))
169 {
170 DBG1(DBG_CFG, "reloading certificates from PKCS#11 tokens");
171 handle_certs(this, NULL, FALSE, NULL);
172 handle_certs(this, NULL, TRUE, NULL);
173 return TRUE;
174 }
175 return FALSE;
176 }
177
178 /**
179 * Add a set of features
180 */
181 static inline void add_features(plugin_feature_t *f, plugin_feature_t *n,
182 int count, int *pos)
183 {
184 int i;
185 for (i = 0; i < count; i++)
186 {
187 f[(*pos)++] = n[i];
188 }
189 }
190
191 METHOD(plugin_t, get_features, int,
192 private_pkcs11_plugin_t *this, plugin_feature_t *features[])
193 {
194 static plugin_feature_t f_hash[] = {
195 PLUGIN_REGISTER(HASHER, pkcs11_hasher_create),
196 PLUGIN_PROVIDE(HASHER, HASH_MD2),
197 PLUGIN_PROVIDE(HASHER, HASH_MD5),
198 PLUGIN_PROVIDE(HASHER, HASH_SHA1),
199 PLUGIN_PROVIDE(HASHER, HASH_SHA256),
200 PLUGIN_PROVIDE(HASHER, HASH_SHA384),
201 PLUGIN_PROVIDE(HASHER, HASH_SHA512),
202 };
203 static plugin_feature_t f_dh[] = {
204 PLUGIN_REGISTER(DH, pkcs11_dh_create),
205 PLUGIN_PROVIDE(DH, MODP_2048_BIT),
206 PLUGIN_PROVIDE(DH, MODP_2048_224),
207 PLUGIN_PROVIDE(DH, MODP_2048_256),
208 PLUGIN_PROVIDE(DH, MODP_1536_BIT),
209 PLUGIN_PROVIDE(DH, MODP_3072_BIT),
210 PLUGIN_PROVIDE(DH, MODP_4096_BIT),
211 PLUGIN_PROVIDE(DH, MODP_6144_BIT),
212 PLUGIN_PROVIDE(DH, MODP_8192_BIT),
213 PLUGIN_PROVIDE(DH, MODP_1024_BIT),
214 PLUGIN_PROVIDE(DH, MODP_1024_160),
215 PLUGIN_PROVIDE(DH, MODP_768_BIT),
216 PLUGIN_PROVIDE(DH, MODP_CUSTOM),
217 };
218 static plugin_feature_t f_ecdh[] = {
219 PLUGIN_REGISTER(DH, pkcs11_dh_create),
220 PLUGIN_PROVIDE(DH, ECP_192_BIT),
221 PLUGIN_PROVIDE(DH, ECP_224_BIT),
222 PLUGIN_PROVIDE(DH, ECP_256_BIT),
223 PLUGIN_PROVIDE(DH, ECP_384_BIT),
224 PLUGIN_PROVIDE(DH, ECP_521_BIT),
225 };
226 static plugin_feature_t f_rng[] = {
227 PLUGIN_REGISTER(RNG, pkcs11_rng_create),
228 PLUGIN_PROVIDE(RNG, RNG_STRONG),
229 PLUGIN_PROVIDE(RNG, RNG_TRUE),
230 };
231 static plugin_feature_t f_privkey[] = {
232 PLUGIN_REGISTER(PRIVKEY, pkcs11_private_key_connect, FALSE),
233 PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
234 };
235 static plugin_feature_t f_pubkey[] = {
236 PLUGIN_REGISTER(PUBKEY, pkcs11_public_key_load, TRUE),
237 PLUGIN_PROVIDE(PUBKEY, KEY_RSA),
238 PLUGIN_PROVIDE(PUBKEY, KEY_ECDSA),
239 };
240 static plugin_feature_t f_manager[] = {
241 PLUGIN_CALLBACK((plugin_feature_callback_t)handle_certs, NULL),
242 PLUGIN_PROVIDE(CUSTOM, "pkcs11-certs"),
243 PLUGIN_DEPENDS(CERT_DECODE, CERT_X509),
244 };
245 static plugin_feature_t f[countof(f_hash) + countof(f_dh) + countof(f_rng) +
246 countof(f_ecdh) + countof(f_privkey) +
247 countof(f_pubkey) + countof(f_manager)] = {};
248 static int count = 0;
249
250 if (!count)
251 { /* initialize only once */
252 bool use_ecc = lib->settings->get_bool(lib->settings,
253 "libstrongswan.plugins.pkcs11.use_ecc", FALSE);
254 add_features(f, f_manager, countof(f_manager), &count);
255 /* private key handling for EC keys is not disabled by use_ecc */
256 add_features(f, f_privkey, countof(f_privkey), &count);
257 if (lib->settings->get_bool(lib->settings,
258 "libstrongswan.plugins.pkcs11.use_pubkey", FALSE))
259 {
260 add_features(f, f_pubkey, countof(f_pubkey) - (use_ecc ? 0 : 1),
261 &count);
262 }
263 if (lib->settings->get_bool(lib->settings,
264 "libstrongswan.plugins.pkcs11.use_hasher", FALSE))
265 {
266 add_features(f, f_hash, countof(f_hash), &count);
267 }
268 if (lib->settings->get_bool(lib->settings,
269 "libstrongswan.plugins.pkcs11.use_rng", FALSE))
270 {
271 add_features(f, f_rng, countof(f_rng), &count);
272 }
273 if (lib->settings->get_bool(lib->settings,
274 "libstrongswan.plugins.pkcs11.use_dh", FALSE))
275 {
276 add_features(f, f_dh, countof(f_dh), &count);
277 if (use_ecc)
278 {
279 add_features(f, f_ecdh, countof(f_ecdh), &count);
280 }
281 }
282 }
283 *features = f;
284 return count;
285 }
286
287 METHOD(plugin_t, destroy, void,
288 private_pkcs11_plugin_t *this)
289 {
290 lib->set(lib, "pkcs11-manager", NULL);
291 this->manager->destroy(this->manager);
292 this->creds->destroy(this->creds);
293 this->mutex->destroy(this->mutex);
294 this->handle_events_lock->destroy(this->handle_events_lock);
295 free(this);
296 }
297
298 /*
299 * see header file
300 */
301 plugin_t *pkcs11_plugin_create()
302 {
303 private_pkcs11_plugin_t *this;
304
305 INIT(this,
306 .public = {
307 .plugin = {
308 .get_name = _get_name,
309 .get_features = _get_features,
310 .reload = _reload,
311 .destroy = _destroy,
312 },
313 },
314 .creds = linked_list_create(),
315 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
316 .handle_events_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
317 );
318
319 this->manager = pkcs11_manager_create((void*)token_event_cb, this);
320 lib->set(lib, "pkcs11-manager", this->manager);
321
322 return &this->public.plugin;
323 }