]>
Commit | Line | Data |
---|---|---|
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 |
26 | typedef struct private_pkcs11_manager_t private_pkcs11_manager_t; |
27 | ||
28 | /** | |
29 | * Private data of an pkcs11_manager_t object. | |
30 | */ | |
31 | struct 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 | */ | |
57 | typedef 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 | */ | |
69 | static 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 | */ | |
78 | static 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 | */ | |
110 | static 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 | 133 | static 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 | */ | |
170 | static 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 | */ | |
201 | static 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 | */ | |
232 | static 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 | */ | |
252 | typedef 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 | ||
267 | METHOD(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 | ||
289 | METHOD(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 | ||
297 | METHOD(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 |
312 | METHOD(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 |
322 | pkcs11_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 |