]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/pkcs11/pkcs11_manager.c
Moved debug.[ch] to utils folder
[thirdparty/strongswan.git] / src / libstrongswan / plugins / pkcs11 / pkcs11_manager.c
CommitLineData
2e209bec
MW
1/*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 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 "pkcs11_manager.h"
17
f05b4272 18#include <utils/debug.h>
12642a68 19#include <collections/linked_list.h>
6522d6c5 20#include <threading/thread.h>
2e209bec
MW
21
22#include "pkcs11_library.h"
23
6522d6c5
MW
24#include <processing/jobs/callback_job.h>
25
2e209bec
MW
26typedef struct private_pkcs11_manager_t private_pkcs11_manager_t;
27
28/**
29 * Private data of an pkcs11_manager_t object.
30 */
31struct private_pkcs11_manager_t {
32
33 /**
34 * Public pkcs11_manager_t interface.
35 */
36 pkcs11_manager_t public;
37
38 /**
6522d6c5 39 * List of loaded libraries, as lib_entry_t
2e209bec
MW
40 */
41 linked_list_t *libs;
fdd7e212
MW
42
43 /**
44 * Slot event callback function
45 */
46 pkcs11_manager_token_event_t cb;
47
48 /**
49 * Slot event user data
50 */
51 void *data;
2e209bec
MW
52};
53
6522d6c5
MW
54/**
55 * Entry for a loaded library
56 */
57typedef struct {
58 /* back reference to this */
59 private_pkcs11_manager_t *this;
6522d6c5
MW
60 /* associated library path */
61 char *path;
62 /* loaded library */
63 pkcs11_library_t *lib;
6522d6c5
MW
64} lib_entry_t;
65
66/**
67 * Destroy a lib_entry_t
68 */
69static void lib_entry_destroy(lib_entry_t *entry)
70{
5b0bcfb1 71 entry->lib->destroy(entry->lib);
6522d6c5
MW
72 free(entry);
73}
74
75/**
76 * Print supported mechanisms of a token in a slot
77 */
78static void print_mechs(lib_entry_t *entry, CK_SLOT_ID slot)
79{
5a27bf8a
MW
80 enumerator_t *enumerator;
81 CK_MECHANISM_TYPE type;
6522d6c5 82 CK_MECHANISM_INFO info;
6522d6c5 83
5a27bf8a
MW
84 enumerator = entry->lib->create_mechanism_enumerator(entry->lib, slot);
85 while (enumerator->enumerate(enumerator, &type, &info))
6522d6c5 86 {
5a27bf8a
MW
87 DBG2(DBG_CFG, " %N %lu-%lu [ %s%s%s%s%s%s%s%s%s%s%s%s%s]",
88 ck_mech_names, type,
89 info.ulMinKeySize, info.ulMaxKeySize,
90 info.flags & CKF_HW ? "HW " : "",
91 info.flags & CKF_ENCRYPT ? "ENCR " : "",
92 info.flags & CKF_DECRYPT ? "DECR " : "",
93 info.flags & CKF_DIGEST ? "DGST " : "",
94 info.flags & CKF_SIGN ? "SIGN " : "",
95 info.flags & CKF_SIGN_RECOVER ? "SIGN_RCVR " : "",
96 info.flags & CKF_VERIFY ? "VRFY " : "",
97 info.flags & CKF_VERIFY_RECOVER ? "VRFY_RCVR " : "",
98 info.flags & CKF_GENERATE ? "GEN " : "",
99 info.flags & CKF_GENERATE_KEY_PAIR ? "GEN_KEY_PAIR " : "",
100 info.flags & CKF_WRAP ? "WRAP " : "",
101 info.flags & CKF_UNWRAP ? "UNWRAP " : "",
102 info.flags & CKF_DERIVE ? "DERIVE " : "");
6522d6c5 103 }
5a27bf8a 104 enumerator->destroy(enumerator);
6522d6c5
MW
105}
106
107/**
108 * Handle a token
109 */
110static void handle_token(lib_entry_t *entry, CK_SLOT_ID slot)
111{
112 CK_TOKEN_INFO info;
113 CK_RV rv;
114
115 rv = entry->lib->f->C_GetTokenInfo(slot, &info);
116 if (rv != CKR_OK)
117 {
118 DBG1(DBG_CFG, "C_GetTokenInfo failed: %N", ck_rv_names, rv);
119 return;
120 }
121 pkcs11_library_trim(info.label, sizeof(info.label));
122 pkcs11_library_trim(info.manufacturerID, sizeof(info.manufacturerID));
123 pkcs11_library_trim(info.model, sizeof(info.model));
124 DBG1(DBG_CFG, " %s (%s: %s)",
125 info.label, info.manufacturerID, info.model);
126
127 print_mechs(entry, slot);
128}
129
130/**
131 * Handle slot changes
132 */
a3aeb892 133static void handle_slot(lib_entry_t *entry, CK_SLOT_ID slot, bool hot)
6522d6c5
MW
134{
135 CK_SLOT_INFO info;
136 CK_RV rv;
137
138 rv = entry->lib->f->C_GetSlotInfo(slot, &info);
139 if (rv != CKR_OK)
140 {
141 DBG1(DBG_CFG, "C_GetSlotInfo failed: %N", ck_rv_names, rv);
142 return;
143 }
144
145 pkcs11_library_trim(info.slotDescription, sizeof(info.slotDescription));
146 if (info.flags & CKF_TOKEN_PRESENT)
147 {
148 DBG1(DBG_CFG, " found token in slot '%s':%lu (%s)",
36c852a0 149 entry->lib->get_name(entry->lib), slot, info.slotDescription);
6522d6c5 150 handle_token(entry, slot);
a3aeb892
MW
151 if (hot)
152 {
153 entry->this->cb(entry->this->data, entry->lib, slot, TRUE);
154 }
6522d6c5
MW
155 }
156 else
157 {
158 DBG1(DBG_CFG, "token removed from slot '%s':%lu (%s)",
36c852a0 159 entry->lib->get_name(entry->lib), slot, info.slotDescription);
a3aeb892
MW
160 if (hot)
161 {
162 entry->this->cb(entry->this->data, entry->lib, slot, FALSE);
163 }
6522d6c5
MW
164 }
165}
166
167/**
168 * Dispatch slot events
169 */
170static job_requeue_t dispatch_slot_events(lib_entry_t *entry)
171{
172 CK_SLOT_ID slot;
173 CK_RV rv;
174 bool old;
175
176 old = thread_cancelability(TRUE);
177 rv = entry->lib->f->C_WaitForSlotEvent(0, &slot, NULL);
178 thread_cancelability(old);
fe876b24 179 if (rv == CKR_FUNCTION_NOT_SUPPORTED || rv == CKR_NO_EVENT)
6522d6c5
MW
180 {
181 DBG1(DBG_CFG, "module '%s' does not support hot-plugging, cancelled",
36c852a0 182 entry->lib->get_name(entry->lib));
6522d6c5
MW
183 return JOB_REQUEUE_NONE;
184 }
185 if (rv == CKR_CRYPTOKI_NOT_INITIALIZED)
186 { /* C_Finalize called, abort */
187 return JOB_REQUEUE_NONE;
188 }
189 if (rv != CKR_OK)
190 {
191 DBG1(DBG_CFG, "error in C_WaitForSlotEvent: %N", ck_rv_names, rv);
192 }
a3aeb892 193 handle_slot(entry, slot, TRUE);
6522d6c5
MW
194
195 return JOB_REQUEUE_DIRECT;
196}
197
36c852a0
MW
198/**
199 * Get the slot list of a library
200 */
201static CK_SLOT_ID_PTR get_slot_list(pkcs11_library_t *p11, CK_ULONG *out)
202{
203 CK_SLOT_ID_PTR slots;
204 CK_ULONG count;
205 CK_RV rv;
206
207 rv = p11->f->C_GetSlotList(TRUE, NULL, &count);
208 if (rv != CKR_OK)
209 {
210 DBG1(DBG_CFG, "C_GetSlotList() failed: %N", ck_rv_names, rv);
211 return NULL;
212 }
213 if (count == 0)
214 {
215 return NULL;
216 }
217 slots = malloc(sizeof(CK_SLOT_ID) * count);
218 rv = p11->f->C_GetSlotList(TRUE, slots, &count);
219 if (rv != CKR_OK)
220 {
221 DBG1(DBG_CFG, "C_GetSlotList() failed: %N", ck_rv_names, rv);
222 free(slots);
223 return NULL;
224 }
225 *out = count;
226 return slots;
227}
228
6522d6c5
MW
229/**
230 * Query the slots for tokens
231 */
232static void query_slots(lib_entry_t *entry)
233{
36c852a0 234 CK_ULONG count;
6522d6c5
MW
235 CK_SLOT_ID_PTR slots;
236 int i;
237
36c852a0
MW
238 slots = get_slot_list(entry->lib, &count);
239 if (slots)
6522d6c5 240 {
36c852a0 241 for (i = 0; i < count; i++)
6522d6c5 242 {
a3aeb892 243 handle_slot(entry, slots[i], FALSE);
6522d6c5
MW
244 }
245 free(slots);
246 }
247}
2e209bec 248
36c852a0
MW
249/**
250 * Token enumerator
251 */
252typedef struct {
253 /* implements enumerator */
254 enumerator_t public;
255 /* inner enumerator over PKCS#11 libraries */
256 enumerator_t *inner;
257 /* active library entry */
258 lib_entry_t *entry;
259 /* slot list with tokens */
260 CK_SLOT_ID_PTR slots;
261 /* number of slots */
262 CK_ULONG count;
263 /* current slot */
264 int current;
265} token_enumerator_t;
266
267METHOD(enumerator_t, enumerate_token, bool,
268 token_enumerator_t *this, pkcs11_library_t **out, CK_SLOT_ID *slot)
269{
270 if (this->current >= this->count)
271 {
272 free(this->slots);
273 this->slots = NULL;
274 this->current = 0;
275 }
276 while (!this->slots)
277 {
278 if (!this->inner->enumerate(this->inner, &this->entry))
279 {
280 return FALSE;
281 }
282 this->slots = get_slot_list(this->entry->lib, &this->count);
283 }
284 *out = this->entry->lib;
285 *slot = this->slots[this->current++];
286 return TRUE;
287}
288
289METHOD(enumerator_t, destroy_token, void,
290 token_enumerator_t *this)
291{
292 this->inner->destroy(this->inner);
293 free(this->slots);
294 free(this);
295}
296
297METHOD(pkcs11_manager_t, create_token_enumerator, enumerator_t*,
298 private_pkcs11_manager_t *this)
299{
300 token_enumerator_t *enumerator;
301
302 INIT(enumerator,
303 .public = {
304 .enumerate = (void*)_enumerate_token,
305 .destroy = _destroy_token,
306 },
307 .inner = this->libs->create_enumerator(this->libs),
308 );
309 return &enumerator->public;
310}
311
2e209bec
MW
312METHOD(pkcs11_manager_t, destroy, void,
313 private_pkcs11_manager_t *this)
314{
6522d6c5 315 this->libs->destroy_function(this->libs, (void*)lib_entry_destroy);
2e209bec
MW
316 free(this);
317}
318
319/**
320 * See header
321 */
fdd7e212
MW
322pkcs11_manager_t *pkcs11_manager_create(pkcs11_manager_token_event_t cb,
323 void *data)
2e209bec
MW
324{
325 private_pkcs11_manager_t *this;
326 enumerator_t *enumerator;
6522d6c5
MW
327 lib_entry_t *entry;
328 char *module;
2e209bec
MW
329
330 INIT(this,
331 .public = {
36c852a0 332 .create_token_enumerator = _create_token_enumerator,
2e209bec
MW
333 .destroy = _destroy,
334 },
335 .libs = linked_list_create(),
fdd7e212
MW
336 .cb = cb,
337 .data = data,
2e209bec
MW
338 );
339
340 enumerator = lib->settings->create_section_enumerator(lib->settings,
341 "libstrongswan.plugins.pkcs11.modules");
342 while (enumerator->enumerate(enumerator, &module))
343 {
6522d6c5
MW
344 INIT(entry,
345 .this = this,
6522d6c5 346 );
2e209bec 347
5b0bcfb1 348 entry->path = lib->settings->get_str(lib->settings,
2e209bec 349 "libstrongswan.plugins.pkcs11.modules.%s.path", NULL, module);
6522d6c5 350 if (!entry->path)
2e209bec 351 {
a79eba2e 352 DBG1(DBG_CFG, "PKCS11 module '%s' lacks library path", module);
5b0bcfb1 353 free(entry);
2e209bec
MW
354 continue;
355 }
9cda3992
MW
356 entry->lib = pkcs11_library_create(module, entry->path,
357 lib->settings->get_bool(lib->settings,
358 "libstrongswan.plugins.pkcs11.modules.%s.os_locking",
359 FALSE, module));
6522d6c5 360 if (!entry->lib)
2e209bec 361 {
5b0bcfb1 362 free(entry);
6522d6c5 363 continue;
2e209bec 364 }
66267ea5
MW
365 this->libs->insert_last(this->libs, entry);
366 }
367 enumerator->destroy(enumerator);
368
66267ea5
MW
369 enumerator = this->libs->create_enumerator(this->libs);
370 while (enumerator->enumerate(enumerator, &entry))
371 {
6522d6c5 372 query_slots(entry);
26d77eb3
TB
373 lib->processor->queue_job(lib->processor,
374 (job_t*)callback_job_create_with_prio((void*)dispatch_slot_events,
375 entry, NULL, (void*)return_false, JOB_PRIO_CRITICAL));
2e209bec
MW
376 }
377 enumerator->destroy(enumerator);
36c852a0 378
2e209bec
MW
379 return &this->public;
380}
36c852a0 381