Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs11/pkcs11_manager.c, revision 1.1.1.1
1.1 misho 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:
18: #include <utils/debug.h>
19: #include <collections/linked_list.h>
20: #include <threading/thread.h>
21:
22: #include "pkcs11_library.h"
23:
24: #include <processing/jobs/callback_job.h>
25:
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: /**
39: * List of loaded libraries, as lib_entry_t
40: */
41: linked_list_t *libs;
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;
52: };
53:
54: /**
55: * Entry for a loaded library
56: */
57: typedef struct {
58: /* back reference to this */
59: private_pkcs11_manager_t *this;
60: /* associated library path */
61: char *path;
62: /* loaded library */
63: pkcs11_library_t *lib;
64: } lib_entry_t;
65:
66: /**
67: * Destroy a lib_entry_t
68: */
69: static void lib_entry_destroy(lib_entry_t *entry)
70: {
71: entry->lib->destroy(entry->lib);
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: {
80: enumerator_t *enumerator;
81: CK_MECHANISM_TYPE type;
82: CK_MECHANISM_INFO info;
83:
84: enumerator = entry->lib->create_mechanism_enumerator(entry->lib, slot);
85: while (enumerator->enumerate(enumerator, &type, &info))
86: {
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 " : "");
103: }
104: enumerator->destroy(enumerator);
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: */
133: static void handle_slot(lib_entry_t *entry, CK_SLOT_ID slot, bool hot)
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)",
149: entry->lib->get_name(entry->lib), slot, info.slotDescription);
150: handle_token(entry, slot);
151: if (hot)
152: {
153: entry->this->cb(entry->this->data, entry->lib, slot, TRUE);
154: }
155: }
156: else
157: {
158: DBG1(DBG_CFG, "token removed from slot '%s':%lu (%s)",
159: entry->lib->get_name(entry->lib), slot, info.slotDescription);
160: if (hot)
161: {
162: entry->this->cb(entry->this->data, entry->lib, slot, FALSE);
163: }
164: }
165: }
166:
167: CALLBACK(dispatch_slot_events, job_requeue_t,
168: lib_entry_t *entry)
169: {
170: CK_SLOT_ID slot;
171: CK_RV rv;
172:
173: rv = entry->lib->f->C_WaitForSlotEvent(0, &slot, NULL);
174: if (rv == CKR_FUNCTION_NOT_SUPPORTED || rv == CKR_NO_EVENT)
175: {
176: DBG1(DBG_CFG, "module '%s' does not support hot-plugging, cancelled",
177: entry->lib->get_name(entry->lib));
178: return JOB_REQUEUE_NONE;
179: }
180: if (rv == CKR_CRYPTOKI_NOT_INITIALIZED)
181: { /* C_Finalize called, abort */
182: return JOB_REQUEUE_NONE;
183: }
184: if (rv != CKR_OK)
185: {
186: DBG1(DBG_CFG, "error in C_WaitForSlotEvent: %N", ck_rv_names, rv);
187: }
188: handle_slot(entry, slot, TRUE);
189:
190: return JOB_REQUEUE_DIRECT;
191: }
192:
193: CALLBACK(cancel_events, bool,
194: lib_entry_t *entry)
195: {
196: /* it's possible other threads still use the API after this call, but we
197: * have no other way to return from C_WaitForSlotEvent() if we can't cancel
198: * the thread because libraries hold locks they don't release */
199: entry->lib->f->C_Finalize(NULL);
200: return TRUE;
201: }
202:
203: /**
204: * Get the slot list of a library
205: */
206: static CK_SLOT_ID_PTR get_slot_list(pkcs11_library_t *p11, CK_ULONG *out)
207: {
208: CK_SLOT_ID_PTR slots;
209: CK_ULONG count;
210: CK_RV rv;
211:
212: rv = p11->f->C_GetSlotList(TRUE, NULL, &count);
213: if (rv != CKR_OK)
214: {
215: DBG1(DBG_CFG, "C_GetSlotList() failed: %N", ck_rv_names, rv);
216: return NULL;
217: }
218: if (count == 0)
219: {
220: return NULL;
221: }
222: slots = malloc(sizeof(CK_SLOT_ID) * count);
223: rv = p11->f->C_GetSlotList(TRUE, slots, &count);
224: if (rv != CKR_OK)
225: {
226: DBG1(DBG_CFG, "C_GetSlotList() failed: %N", ck_rv_names, rv);
227: free(slots);
228: return NULL;
229: }
230: *out = count;
231: return slots;
232: }
233:
234: /**
235: * Query the slots for tokens
236: */
237: static void query_slots(lib_entry_t *entry)
238: {
239: CK_ULONG count;
240: CK_SLOT_ID_PTR slots;
241: int i;
242:
243: slots = get_slot_list(entry->lib, &count);
244: if (slots)
245: {
246: for (i = 0; i < count; i++)
247: {
248: handle_slot(entry, slots[i], FALSE);
249: }
250: free(slots);
251: }
252: }
253:
254: /**
255: * Token enumerator
256: */
257: typedef struct {
258: /* implements enumerator */
259: enumerator_t public;
260: /* inner enumerator over PKCS#11 libraries */
261: enumerator_t *inner;
262: /* active library entry */
263: lib_entry_t *entry;
264: /* slot list with tokens */
265: CK_SLOT_ID_PTR slots;
266: /* number of slots */
267: CK_ULONG count;
268: /* current slot */
269: int current;
270: } token_enumerator_t;
271:
272: METHOD(enumerator_t, enumerate_token, bool,
273: token_enumerator_t *this, va_list args)
274: {
275: pkcs11_library_t **out;
276: CK_SLOT_ID *slot;
277:
278: VA_ARGS_VGET(args, out, slot);
279:
280: if (this->current >= this->count)
281: {
282: free(this->slots);
283: this->slots = NULL;
284: this->current = 0;
285: }
286: while (!this->slots)
287: {
288: if (!this->inner->enumerate(this->inner, &this->entry))
289: {
290: return FALSE;
291: }
292: this->slots = get_slot_list(this->entry->lib, &this->count);
293: }
294: *out = this->entry->lib;
295: *slot = this->slots[this->current++];
296: return TRUE;
297: }
298:
299: METHOD(enumerator_t, destroy_token, void,
300: token_enumerator_t *this)
301: {
302: this->inner->destroy(this->inner);
303: free(this->slots);
304: free(this);
305: }
306:
307: METHOD(pkcs11_manager_t, create_token_enumerator, enumerator_t*,
308: private_pkcs11_manager_t *this)
309: {
310: token_enumerator_t *enumerator;
311:
312: INIT(enumerator,
313: .public = {
314: .enumerate = enumerator_enumerate_default,
315: .venumerate = _enumerate_token,
316: .destroy = _destroy_token,
317: },
318: .inner = this->libs->create_enumerator(this->libs),
319: );
320: return &enumerator->public;
321: }
322:
323: METHOD(pkcs11_manager_t, destroy, void,
324: private_pkcs11_manager_t *this)
325: {
326: this->libs->destroy_function(this->libs, (void*)lib_entry_destroy);
327: free(this);
328: }
329:
330: /**
331: * See header
332: */
333: pkcs11_manager_t *pkcs11_manager_create(pkcs11_manager_token_event_t cb,
334: void *data)
335: {
336: private_pkcs11_manager_t *this;
337: enumerator_t *enumerator;
338: lib_entry_t *entry;
339: char *module;
340:
341: INIT(this,
342: .public = {
343: .create_token_enumerator = _create_token_enumerator,
344: .destroy = _destroy,
345: },
346: .libs = linked_list_create(),
347: .cb = cb,
348: .data = data,
349: );
350:
351: enumerator = lib->settings->create_section_enumerator(lib->settings,
352: "%s.plugins.pkcs11.modules", lib->ns);
353: while (enumerator->enumerate(enumerator, &module))
354: {
355: INIT(entry,
356: .this = this,
357: );
358:
359: entry->path = lib->settings->get_str(lib->settings,
360: "%s.plugins.pkcs11.modules.%s.path", NULL, lib->ns, module);
361: if (!entry->path)
362: {
363: DBG1(DBG_CFG, "PKCS11 module '%s' lacks library path", module);
364: free(entry);
365: continue;
366: }
367: entry->lib = pkcs11_library_create(module, entry->path,
368: lib->settings->get_bool(lib->settings,
369: "%s.plugins.pkcs11.modules.%s.os_locking",
370: FALSE, lib->ns, module));
371: if (!entry->lib)
372: {
373: free(entry);
374: continue;
375: }
376: this->libs->insert_last(this->libs, entry);
377: }
378: enumerator->destroy(enumerator);
379:
380: enumerator = this->libs->create_enumerator(this->libs);
381: while (enumerator->enumerate(enumerator, &entry))
382: {
383: query_slots(entry);
384: lib->processor->queue_job(lib->processor,
385: (job_t*)callback_job_create_with_prio(dispatch_slot_events,
386: entry, NULL, cancel_events, JOB_PRIO_CRITICAL));
387: }
388: enumerator->destroy(enumerator);
389:
390: return &this->public;
391: }
392:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>