2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
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>.
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
16 #include "pkcs11_manager.h"
19 #include <utils/linked_list.h>
20 #include <threading/thread.h>
22 #include "pkcs11_library.h"
24 #include <processing/jobs/callback_job.h>
26 typedef struct private_pkcs11_manager_t private_pkcs11_manager_t
;
29 * Private data of an pkcs11_manager_t object.
31 struct private_pkcs11_manager_t
{
34 * Public pkcs11_manager_t interface.
36 pkcs11_manager_t
public;
39 * List of loaded libraries, as lib_entry_t
44 * Slot event callback function
46 pkcs11_manager_token_event_t cb
;
49 * Slot event user data
55 * Entry for a loaded library
58 /* back reference to this */
59 private_pkcs11_manager_t
*this;
60 /* associated library path */
63 pkcs11_library_t
*lib
;
64 /* event dispatcher job */
69 * Destroy a lib_entry_t
71 static void lib_entry_destroy(lib_entry_t
*entry
)
75 entry
->job
->cancel(entry
->job
);
77 entry
->lib
->destroy(entry
->lib
);
82 * Print supported mechanisms of a token in a slot
84 static void print_mechs(lib_entry_t
*entry
, CK_SLOT_ID slot
)
86 enumerator_t
*enumerator
;
87 CK_MECHANISM_TYPE type
;
88 CK_MECHANISM_INFO info
;
90 enumerator
= entry
->lib
->create_mechanism_enumerator(entry
->lib
, slot
);
91 while (enumerator
->enumerate(enumerator
, &type
, &info
))
93 DBG2(DBG_CFG
, " %N %lu-%lu [ %s%s%s%s%s%s%s%s%s%s%s%s%s]",
95 info
.ulMinKeySize
, info
.ulMaxKeySize
,
96 info
.flags
& CKF_HW ?
"HW " : "",
97 info
.flags
& CKF_ENCRYPT ?
"ENCR " : "",
98 info
.flags
& CKF_DECRYPT ?
"DECR " : "",
99 info
.flags
& CKF_DIGEST ?
"DGST " : "",
100 info
.flags
& CKF_SIGN ?
"SIGN " : "",
101 info
.flags
& CKF_SIGN_RECOVER ?
"SIGN_RCVR " : "",
102 info
.flags
& CKF_VERIFY ?
"VRFY " : "",
103 info
.flags
& CKF_VERIFY_RECOVER ?
"VRFY_RCVR " : "",
104 info
.flags
& CKF_GENERATE ?
"GEN " : "",
105 info
.flags
& CKF_GENERATE_KEY_PAIR ?
"GEN_KEY_PAIR " : "",
106 info
.flags
& CKF_WRAP ?
"WRAP " : "",
107 info
.flags
& CKF_UNWRAP ?
"UNWRAP " : "",
108 info
.flags
& CKF_DERIVE ?
"DERIVE " : "");
110 enumerator
->destroy(enumerator
);
116 static void handle_token(lib_entry_t
*entry
, CK_SLOT_ID slot
)
121 rv
= entry
->lib
->f
->C_GetTokenInfo(slot
, &info
);
124 DBG1(DBG_CFG
, "C_GetTokenInfo failed: %N", ck_rv_names
, rv
);
127 pkcs11_library_trim(info
.label
, sizeof(info
.label
));
128 pkcs11_library_trim(info
.manufacturerID
, sizeof(info
.manufacturerID
));
129 pkcs11_library_trim(info
.model
, sizeof(info
.model
));
130 DBG1(DBG_CFG
, " %s (%s: %s)",
131 info
.label
, info
.manufacturerID
, info
.model
);
133 print_mechs(entry
, slot
);
137 * Handle slot changes
139 static void handle_slot(lib_entry_t
*entry
, CK_SLOT_ID slot
, bool hot
)
144 rv
= entry
->lib
->f
->C_GetSlotInfo(slot
, &info
);
147 DBG1(DBG_CFG
, "C_GetSlotInfo failed: %N", ck_rv_names
, rv
);
151 pkcs11_library_trim(info
.slotDescription
, sizeof(info
.slotDescription
));
152 if (info
.flags
& CKF_TOKEN_PRESENT
)
154 DBG1(DBG_CFG
, " found token in slot '%s':%lu (%s)",
155 entry
->lib
->get_name(entry
->lib
), slot
, info
.slotDescription
);
156 handle_token(entry
, slot
);
159 entry
->this->cb(entry
->this->data
, entry
->lib
, slot
, TRUE
);
164 DBG1(DBG_CFG
, "token removed from slot '%s':%lu (%s)",
165 entry
->lib
->get_name(entry
->lib
), slot
, info
.slotDescription
);
168 entry
->this->cb(entry
->this->data
, entry
->lib
, slot
, FALSE
);
174 * Dispatch slot events
176 static job_requeue_t
dispatch_slot_events(lib_entry_t
*entry
)
182 old
= thread_cancelability(TRUE
);
183 rv
= entry
->lib
->f
->C_WaitForSlotEvent(0, &slot
, NULL
);
184 thread_cancelability(old
);
185 if (rv
== CKR_FUNCTION_NOT_SUPPORTED
|| rv
== CKR_NO_EVENT
)
187 DBG1(DBG_CFG
, "module '%s' does not support hot-plugging, cancelled",
188 entry
->lib
->get_name(entry
->lib
));
189 return JOB_REQUEUE_NONE
;
191 if (rv
== CKR_CRYPTOKI_NOT_INITIALIZED
)
192 { /* C_Finalize called, abort */
193 return JOB_REQUEUE_NONE
;
197 DBG1(DBG_CFG
, "error in C_WaitForSlotEvent: %N", ck_rv_names
, rv
);
199 handle_slot(entry
, slot
, TRUE
);
201 return JOB_REQUEUE_DIRECT
;
205 * End dispatching, unset job
207 static void end_dispatch(lib_entry_t
*entry
)
213 * Get the slot list of a library
215 static CK_SLOT_ID_PTR
get_slot_list(pkcs11_library_t
*p11
, CK_ULONG
*out
)
217 CK_SLOT_ID_PTR slots
;
221 rv
= p11
->f
->C_GetSlotList(TRUE
, NULL
, &count
);
224 DBG1(DBG_CFG
, "C_GetSlotList() failed: %N", ck_rv_names
, rv
);
231 slots
= malloc(sizeof(CK_SLOT_ID
) * count
);
232 rv
= p11
->f
->C_GetSlotList(TRUE
, slots
, &count
);
235 DBG1(DBG_CFG
, "C_GetSlotList() failed: %N", ck_rv_names
, rv
);
244 * Query the slots for tokens
246 static void query_slots(lib_entry_t
*entry
)
249 CK_SLOT_ID_PTR slots
;
252 slots
= get_slot_list(entry
->lib
, &count
);
255 for (i
= 0; i
< count
; i
++)
257 handle_slot(entry
, slots
[i
], FALSE
);
267 /* implements enumerator */
269 /* inner enumerator over PKCS#11 libraries */
271 /* active library entry */
273 /* slot list with tokens */
274 CK_SLOT_ID_PTR slots
;
275 /* number of slots */
279 } token_enumerator_t
;
281 METHOD(enumerator_t
, enumerate_token
, bool,
282 token_enumerator_t
*this, pkcs11_library_t
**out
, CK_SLOT_ID
*slot
)
284 if (this->current
>= this->count
)
292 if (!this->inner
->enumerate(this->inner
, &this->entry
))
296 this->slots
= get_slot_list(this->entry
->lib
, &this->count
);
298 *out
= this->entry
->lib
;
299 *slot
= this->slots
[this->current
++];
303 METHOD(enumerator_t
, destroy_token
, void,
304 token_enumerator_t
*this)
306 this->inner
->destroy(this->inner
);
311 METHOD(pkcs11_manager_t
, create_token_enumerator
, enumerator_t
*,
312 private_pkcs11_manager_t
*this)
314 token_enumerator_t
*enumerator
;
318 .enumerate
= (void*)_enumerate_token
,
319 .destroy
= _destroy_token
,
321 .inner
= this->libs
->create_enumerator(this->libs
),
323 return &enumerator
->public;
329 static private_pkcs11_manager_t
*singleton
= NULL
;
331 METHOD(pkcs11_manager_t
, destroy
, void,
332 private_pkcs11_manager_t
*this)
334 this->libs
->destroy_function(this->libs
, (void*)lib_entry_destroy
);
342 pkcs11_manager_t
*pkcs11_manager_create(pkcs11_manager_token_event_t cb
,
345 private_pkcs11_manager_t
*this;
346 enumerator_t
*enumerator
;
352 .create_token_enumerator
= _create_token_enumerator
,
355 .libs
= linked_list_create(),
360 enumerator
= lib
->settings
->create_section_enumerator(lib
->settings
,
361 "libstrongswan.plugins.pkcs11.modules");
362 while (enumerator
->enumerate(enumerator
, &module
))
368 entry
->path
= lib
->settings
->get_str(lib
->settings
,
369 "libstrongswan.plugins.pkcs11.modules.%s.path", NULL
, module
);
372 DBG1(DBG_CFG
, "PKCS11 module '%s' lacks library path", module
);
376 entry
->lib
= pkcs11_library_create(module
, entry
->path
,
377 lib
->settings
->get_bool(lib
->settings
,
378 "libstrongswan.plugins.pkcs11.modules.%s.os_locking",
385 this->libs
->insert_last(this->libs
, entry
);
387 enumerator
->destroy(enumerator
);
391 enumerator
= this->libs
->create_enumerator(this->libs
);
392 while (enumerator
->enumerate(enumerator
, &entry
))
395 entry
->job
= callback_job_create_with_prio((void*)dispatch_slot_events
,
396 entry
, (void*)end_dispatch
, NULL
, JOB_PRIO_CRITICAL
);
397 lib
->processor
->queue_job(lib
->processor
, (job_t
*)entry
->job
);
399 enumerator
->destroy(enumerator
);
401 return &this->public;
407 pkcs11_manager_t
*pkcs11_manager_get()
409 return (pkcs11_manager_t
*)singleton
;