/src/p11-kit/p11-kit/proxy.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2008 Stefan Walter |
3 | | * Copyright (C) 2011 Collabora Ltd. |
4 | | * Copyright (C) 2021-2023 Red Hat Inc. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * |
10 | | * * Redistributions of source code must retain the above |
11 | | * copyright notice, this list of conditions and the |
12 | | * following disclaimer. |
13 | | * * Redistributions in binary form must reproduce the |
14 | | * above copyright notice, this list of conditions and |
15 | | * the following disclaimer in the documentation and/or |
16 | | * other materials provided with the distribution. |
17 | | * * The names of contributors to this software may not be |
18 | | * used to endorse or promote products derived from this |
19 | | * software without specific prior written permission. |
20 | | * |
21 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
22 | | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
23 | | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
24 | | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
25 | | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
26 | | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
27 | | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
28 | | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
29 | | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
30 | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF |
31 | | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
32 | | * DAMAGE. |
33 | | * |
34 | | * Author: Stef Walter <stefw@collabora.co.uk> |
35 | | */ |
36 | | |
37 | | #include "config.h" |
38 | | |
39 | | #include "compat.h" |
40 | 0 | #define P11_DEBUG_FLAG P11_DEBUG_PROXY |
41 | | #define CRYPTOKI_EXPORTS |
42 | | |
43 | | #include "debug.h" |
44 | | #include "dict.h" |
45 | | #include "library.h" |
46 | | #include "message.h" |
47 | | #include "modules.h" |
48 | | #include "pkcs11.h" |
49 | | #include "pkcs11x.h" |
50 | | #include "p11-kit.h" |
51 | | #include "private.h" |
52 | | #include "proxy.h" |
53 | | #include "virtual.h" |
54 | | |
55 | | #include <sys/types.h> |
56 | | #include <assert.h> |
57 | | #include <errno.h> |
58 | | #include <stdarg.h> |
59 | | #include <stddef.h> |
60 | | #include <stdlib.h> |
61 | | #include <stdio.h> |
62 | | #include <string.h> |
63 | | |
64 | | /* Start wrap slots slightly higher for testing */ |
65 | 0 | #define MAPPING_OFFSET 0x10 |
66 | 0 | #define FIRST_HANDLE 0x10 |
67 | | |
68 | | typedef struct _Mapping { |
69 | | CK_SLOT_ID wrap_slot; |
70 | | CK_SLOT_ID real_slot; |
71 | | CK_FUNCTION_LIST_PTR funcs; |
72 | | } Mapping; |
73 | | |
74 | | typedef struct _Session { |
75 | | CK_SESSION_HANDLE wrap_session; |
76 | | CK_SESSION_HANDLE real_session; |
77 | | CK_SLOT_ID wrap_slot; |
78 | | } Session; |
79 | | |
80 | | typedef struct { |
81 | | int refs; |
82 | | Mapping *mappings; |
83 | | unsigned int n_mappings; |
84 | | p11_dict *sessions; |
85 | | CK_FUNCTION_LIST **inited; |
86 | | unsigned int forkid; |
87 | | CK_SLOT_ID last_id; |
88 | | } Proxy; |
89 | | |
90 | | typedef struct _State { |
91 | | p11_virtual virt; |
92 | | struct _State *next; |
93 | | CK_FUNCTION_LIST **loaded; |
94 | | CK_INTERFACE wrapped; |
95 | | CK_ULONG last_handle; |
96 | | Proxy *px; |
97 | | } State; |
98 | | |
99 | | static State *all_instances = NULL; |
100 | | |
101 | 0 | #define PROXY_VALID(px) ((px) && (px)->forkid == p11_forkid) |
102 | 0 | #define PROXY_FORKED(px) ((px) && (px)->forkid != p11_forkid) |
103 | | |
104 | 0 | #define MANUFACTURER_ID "PKCS#11 Kit " |
105 | 0 | #define LIBRARY_DESCRIPTION "PKCS#11 Kit Proxy Module " |
106 | 0 | #define LIBRARY_VERSION_MAJOR 1 |
107 | 0 | #define LIBRARY_VERSION_MINOR 1 |
108 | | |
109 | | /* ----------------------------------------------------------------------------- |
110 | | * PKCS#11 PROXY MODULE |
111 | | */ |
112 | | |
113 | | static CK_RV |
114 | | map_slot_unlocked (Proxy *px, |
115 | | CK_SLOT_ID slot, |
116 | | Mapping *mapping) |
117 | 0 | { |
118 | 0 | unsigned int i; |
119 | |
|
120 | 0 | assert (px != NULL); |
121 | 0 | assert (mapping != NULL); |
122 | |
|
123 | 0 | for (i = 0; i < px->n_mappings; i++) { |
124 | 0 | assert (px->mappings != NULL); |
125 | 0 | if (px->mappings[i].wrap_slot == slot) { |
126 | 0 | memcpy (mapping, &px->mappings[i], sizeof(Mapping)); |
127 | 0 | return CKR_OK; |
128 | 0 | } |
129 | 0 | } |
130 | | |
131 | 0 | return CKR_SLOT_ID_INVALID; |
132 | 0 | } |
133 | | |
134 | | static CK_RV |
135 | | map_slot_to_real (Proxy *px, |
136 | | CK_SLOT_ID_PTR slot, |
137 | | Mapping *mapping) |
138 | 0 | { |
139 | 0 | CK_RV rv; |
140 | |
|
141 | 0 | assert (mapping != NULL); |
142 | |
|
143 | 0 | p11_lock (); |
144 | |
|
145 | 0 | if (!PROXY_VALID (px)) |
146 | 0 | rv = CKR_CRYPTOKI_NOT_INITIALIZED; |
147 | 0 | else |
148 | 0 | rv = map_slot_unlocked (px, *slot, mapping); |
149 | 0 | if (rv == CKR_OK) |
150 | 0 | *slot = mapping->real_slot; |
151 | |
|
152 | 0 | p11_unlock (); |
153 | |
|
154 | 0 | return rv; |
155 | 0 | } |
156 | | |
157 | | static CK_RV |
158 | | map_session_to_real (Proxy *px, |
159 | | CK_SESSION_HANDLE_PTR handle, |
160 | | Mapping *mapping, |
161 | | Session *session) |
162 | 0 | { |
163 | 0 | CK_RV rv = CKR_OK; |
164 | 0 | Session *sess; |
165 | |
|
166 | 0 | assert (handle != NULL); |
167 | 0 | assert (mapping != NULL); |
168 | |
|
169 | 0 | p11_lock (); |
170 | |
|
171 | 0 | if (!PROXY_VALID (px)) { |
172 | 0 | rv = CKR_CRYPTOKI_NOT_INITIALIZED; |
173 | 0 | } else { |
174 | 0 | assert (px->sessions); |
175 | 0 | sess = p11_dict_get (px->sessions, handle); |
176 | 0 | if (sess != NULL) { |
177 | 0 | *handle = sess->real_session; |
178 | 0 | rv = map_slot_unlocked (px, sess->wrap_slot, mapping); |
179 | 0 | if (session != NULL) |
180 | 0 | memcpy (session, sess, sizeof (Session)); |
181 | 0 | } else { |
182 | 0 | rv = CKR_SESSION_HANDLE_INVALID; |
183 | 0 | } |
184 | 0 | } |
185 | |
|
186 | 0 | p11_unlock (); |
187 | |
|
188 | 0 | return rv; |
189 | 0 | } |
190 | | |
191 | | static void |
192 | | proxy_free (Proxy *py, unsigned finalize) |
193 | 0 | { |
194 | 0 | if (py) { |
195 | 0 | if (finalize) |
196 | 0 | p11_kit_modules_finalize ((CK_FUNCTION_LIST **)py->inited); |
197 | 0 | free (py->inited); |
198 | 0 | p11_dict_free (py->sessions); |
199 | 0 | free (py->mappings); |
200 | 0 | free (py); |
201 | 0 | } |
202 | 0 | } |
203 | | |
204 | | static CK_RV |
205 | | proxy_C_Finalize (CK_X_FUNCTION_LIST *self, |
206 | | CK_VOID_PTR reserved) |
207 | 0 | { |
208 | 0 | Proxy *py = NULL; |
209 | 0 | State *state = (State *)self; |
210 | 0 | CK_RV rv = CKR_OK; |
211 | |
|
212 | 0 | p11_debug ("in"); |
213 | | |
214 | | /* WARNING: This function must be reentrant */ |
215 | |
|
216 | 0 | if (reserved) { |
217 | 0 | rv = CKR_ARGUMENTS_BAD; |
218 | |
|
219 | 0 | } else { |
220 | 0 | p11_lock (); |
221 | |
|
222 | 0 | if (!PROXY_VALID (state->px)) { |
223 | 0 | rv = CKR_CRYPTOKI_NOT_INITIALIZED; |
224 | 0 | py = state->px; |
225 | 0 | state->px = NULL; |
226 | 0 | } else if (state->px->refs-- == 1) { |
227 | 0 | py = state->px; |
228 | 0 | state->px = NULL; |
229 | 0 | } |
230 | |
|
231 | 0 | p11_unlock (); |
232 | |
|
233 | 0 | proxy_free (py, 1); |
234 | 0 | } |
235 | |
|
236 | 0 | p11_debug ("out: %lu", rv); |
237 | 0 | return rv; |
238 | 0 | } |
239 | | |
240 | | static CK_FUNCTION_LIST ** |
241 | | modules_dup (CK_FUNCTION_LIST **modules) |
242 | 0 | { |
243 | 0 | int count = 0; |
244 | |
|
245 | 0 | while (modules[count] != NULL) |
246 | 0 | count++; |
247 | |
|
248 | 0 | return memdup (modules, sizeof (CK_FUNCTION_LIST *) * (count + 1)); |
249 | 0 | } |
250 | | |
251 | | static CK_RV |
252 | | proxy_list_slots (Proxy *py, Mapping *mappings, unsigned int n_mappings) |
253 | 0 | { |
254 | 0 | CK_FUNCTION_LIST_PTR *f; |
255 | 0 | CK_FUNCTION_LIST_PTR funcs; |
256 | 0 | CK_SLOT_ID_PTR slots; |
257 | 0 | CK_ULONG i, count; |
258 | 0 | unsigned int j; |
259 | 0 | CK_RV rv = CKR_OK; |
260 | |
|
261 | 0 | for (f = py->inited; *f; ++f) { |
262 | 0 | funcs = *f; |
263 | 0 | assert (funcs != NULL); |
264 | 0 | slots = NULL; |
265 | | |
266 | | /* Ask module for its slots */ |
267 | 0 | rv = (funcs->C_GetSlotList) (FALSE, NULL, &count); |
268 | 0 | if (rv == CKR_OK && count) { |
269 | 0 | slots = calloc (count, sizeof (CK_SLOT_ID)); |
270 | 0 | rv = (funcs->C_GetSlotList) (FALSE, slots, &count); |
271 | 0 | } |
272 | |
|
273 | 0 | if (rv != CKR_OK) { |
274 | 0 | free (slots); |
275 | 0 | break; |
276 | 0 | } |
277 | | |
278 | 0 | return_val_if_fail (count == 0 || slots != NULL, CKR_GENERAL_ERROR); |
279 | | |
280 | 0 | if (count > 0) { |
281 | 0 | Mapping *new_mappings; |
282 | 0 | CK_SLOT_ID_PTR new_slots; |
283 | 0 | int new_slots_count = 0; |
284 | |
|
285 | 0 | new_slots = calloc (count, sizeof(CK_SLOT_ID)); |
286 | 0 | return_val_if_fail (new_slots != NULL, CKR_HOST_MEMORY); |
287 | 0 | new_mappings = reallocarray (py->mappings, (py->n_mappings + count), sizeof (Mapping)); |
288 | 0 | return_val_if_fail (new_mappings != NULL, CKR_HOST_MEMORY); |
289 | 0 | py->mappings = new_mappings; |
290 | | |
291 | | /* Reuse the existing mapping if any */ |
292 | 0 | for (i = 0; i < count; ++i) { |
293 | 0 | for (j = 0; j < n_mappings; ++j) { |
294 | | /* cppcheck-suppress nullPointer symbolName=mappings */ |
295 | | /* false-positive: https://trac.cppcheck.net/ticket/9573 */ |
296 | 0 | if (mappings[j].funcs == funcs && |
297 | 0 | mappings[j].real_slot == slots[i]) { |
298 | 0 | py->mappings[py->n_mappings].funcs = funcs; |
299 | 0 | py->mappings[py->n_mappings].real_slot = slots[i]; |
300 | 0 | py->mappings[py->n_mappings].wrap_slot = |
301 | 0 | mappings[j].wrap_slot; |
302 | 0 | ++py->n_mappings; |
303 | 0 | break; |
304 | 0 | } |
305 | 0 | } |
306 | 0 | if (n_mappings == 0 || j == n_mappings) { |
307 | 0 | new_slots[new_slots_count] = slots[i]; |
308 | 0 | ++new_slots_count; |
309 | 0 | } |
310 | 0 | } |
311 | | |
312 | | /* And now add a mapping for each new slot */ |
313 | 0 | for (i = 0; i < new_slots_count; ++i) { |
314 | 0 | ++py->last_id; |
315 | 0 | py->mappings[py->n_mappings].funcs = funcs; |
316 | 0 | py->mappings[py->n_mappings].wrap_slot = |
317 | 0 | py->last_id + MAPPING_OFFSET; |
318 | 0 | py->mappings[py->n_mappings].real_slot = new_slots[i]; |
319 | 0 | ++py->n_mappings; |
320 | 0 | } |
321 | |
|
322 | 0 | free(new_slots); |
323 | 0 | } |
324 | | |
325 | 0 | free (slots); |
326 | 0 | } |
327 | 0 | return rv; |
328 | 0 | } |
329 | | |
330 | | static CK_RV |
331 | | proxy_create (Proxy **res, CK_FUNCTION_LIST **loaded, |
332 | | Mapping *mappings, unsigned int n_mappings) |
333 | 0 | { |
334 | 0 | CK_RV rv = CKR_OK; |
335 | 0 | Proxy *py; |
336 | |
|
337 | 0 | py = calloc (1, sizeof (Proxy)); |
338 | 0 | return_val_if_fail (py != NULL, CKR_HOST_MEMORY); |
339 | | |
340 | 0 | py->forkid = p11_forkid; |
341 | 0 | py->last_id = 0; |
342 | |
|
343 | 0 | py->inited = modules_dup (loaded); |
344 | 0 | if (py->inited == NULL) { |
345 | 0 | proxy_free (py, 0); |
346 | 0 | return_val_if_reached (CKR_HOST_MEMORY); |
347 | 0 | } |
348 | | |
349 | 0 | rv = p11_kit_modules_initialize (py->inited, NULL); |
350 | |
|
351 | 0 | if (rv == CKR_OK) { |
352 | 0 | rv = proxy_list_slots (py, mappings, n_mappings); |
353 | 0 | } |
354 | |
|
355 | 0 | if (rv != CKR_OK) { |
356 | 0 | proxy_free (py, 1); |
357 | 0 | return rv; |
358 | 0 | } |
359 | | |
360 | 0 | py->sessions = p11_dict_new (p11_dict_ulongptr_hash, p11_dict_ulongptr_equal, NULL, free); |
361 | 0 | if (py->sessions == NULL) { |
362 | 0 | proxy_free (py, 1); |
363 | 0 | return_val_if_reached (CKR_HOST_MEMORY); |
364 | 0 | } |
365 | 0 | py->refs = 1; |
366 | |
|
367 | 0 | *res = py; |
368 | 0 | return CKR_OK; |
369 | 0 | } |
370 | | |
371 | | static CK_RV |
372 | | proxy_C_Initialize (CK_X_FUNCTION_LIST *self, |
373 | | CK_VOID_PTR init_args) |
374 | 0 | { |
375 | 0 | State *state = (State *)self; |
376 | 0 | bool initialize = false; |
377 | 0 | Mapping *mappings = NULL; |
378 | 0 | unsigned int n_mappings = 0; |
379 | 0 | Proxy *py; |
380 | 0 | CK_RV rv; |
381 | |
|
382 | 0 | p11_library_init_once (); |
383 | | |
384 | | /* WARNING: This function must be reentrant */ |
385 | |
|
386 | 0 | p11_debug ("in"); |
387 | |
|
388 | 0 | p11_lock (); |
389 | |
|
390 | 0 | if (!PROXY_VALID (state->px)) { |
391 | 0 | unsigned call_finalize = 1; |
392 | |
|
393 | 0 | initialize = true; |
394 | 0 | if (PROXY_FORKED(state->px)) { |
395 | 0 | call_finalize = 0; |
396 | 0 | if (state->px->mappings) { |
397 | 0 | mappings = state->px->mappings; |
398 | 0 | n_mappings = state->px->n_mappings; |
399 | 0 | state->px->mappings = NULL; |
400 | 0 | state->px->n_mappings = 0; |
401 | 0 | } |
402 | 0 | } |
403 | 0 | proxy_free (state->px, call_finalize); |
404 | |
|
405 | 0 | state->px = NULL; |
406 | 0 | } else { |
407 | 0 | state->px->refs++; |
408 | 0 | } |
409 | |
|
410 | 0 | p11_unlock (); |
411 | |
|
412 | 0 | if (!initialize) { |
413 | 0 | p11_debug ("out: already: %lu", CKR_OK); |
414 | 0 | return CKR_OK; |
415 | 0 | } |
416 | | |
417 | 0 | rv = proxy_create (&py, state->loaded, mappings, n_mappings); |
418 | 0 | free (mappings); |
419 | 0 | if (rv != CKR_OK) { |
420 | 0 | p11_debug ("out: %lu", rv); |
421 | 0 | return rv; |
422 | 0 | } |
423 | | |
424 | 0 | p11_lock (); |
425 | |
|
426 | 0 | if (state->px == NULL) { |
427 | 0 | state->px = py; |
428 | 0 | py = NULL; |
429 | 0 | } |
430 | |
|
431 | 0 | p11_unlock (); |
432 | |
|
433 | 0 | proxy_free (py, 1); |
434 | 0 | p11_debug ("out: 0"); |
435 | 0 | return rv; |
436 | 0 | } |
437 | | |
438 | | static CK_RV |
439 | | proxy_C_GetInfo (CK_X_FUNCTION_LIST *self, |
440 | | CK_INFO_PTR info) |
441 | 0 | { |
442 | 0 | State *state = (State *)self; |
443 | 0 | CK_RV rv = CKR_OK; |
444 | |
|
445 | 0 | p11_library_init_once (); |
446 | |
|
447 | 0 | return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD); |
448 | | |
449 | 0 | p11_lock (); |
450 | |
|
451 | 0 | if (!PROXY_VALID (state->px)) |
452 | 0 | rv = CKR_CRYPTOKI_NOT_INITIALIZED; |
453 | |
|
454 | 0 | p11_unlock (); |
455 | |
|
456 | 0 | if (rv != CKR_OK) |
457 | 0 | return rv; |
458 | | |
459 | 0 | memset (info, 0, sizeof (CK_INFO)); |
460 | 0 | info->cryptokiVersion.major = self->version.major; |
461 | 0 | info->cryptokiVersion.minor = self->version.minor; |
462 | 0 | info->libraryVersion.major = LIBRARY_VERSION_MAJOR; |
463 | 0 | info->libraryVersion.minor = LIBRARY_VERSION_MINOR; |
464 | 0 | info->flags = 0; |
465 | 0 | memcpy ((char*)info->manufacturerID, MANUFACTURER_ID, 32); |
466 | 0 | memcpy ((char*)info->libraryDescription, LIBRARY_DESCRIPTION, 32); |
467 | 0 | return CKR_OK; |
468 | 0 | } |
469 | | |
470 | | static CK_RV |
471 | | proxy_C_GetSlotList (CK_X_FUNCTION_LIST *self, |
472 | | CK_BBOOL token_present, |
473 | | CK_SLOT_ID_PTR slot_list, |
474 | | CK_ULONG_PTR count) |
475 | 0 | { |
476 | 0 | State *state = (State *)self; |
477 | 0 | CK_SLOT_INFO info; |
478 | 0 | Mapping *mapping; |
479 | 0 | CK_ULONG index; |
480 | 0 | CK_RV rv = CKR_OK; |
481 | 0 | unsigned int i; |
482 | |
|
483 | 0 | return_val_if_fail (count != NULL, CKR_ARGUMENTS_BAD); |
484 | | |
485 | 0 | p11_lock (); |
486 | |
|
487 | 0 | if (!PROXY_VALID (state->px)) { |
488 | 0 | rv = CKR_CRYPTOKI_NOT_INITIALIZED; |
489 | 0 | } |
490 | |
|
491 | 0 | if (rv == CKR_OK) { |
492 | 0 | Mapping *mappings = NULL; |
493 | 0 | unsigned int n_mappings = 0; |
494 | |
|
495 | 0 | if (state->px->n_mappings > 0) { |
496 | 0 | mappings = state->px->mappings; |
497 | 0 | n_mappings = state->px->n_mappings; |
498 | 0 | state->px->mappings = NULL; |
499 | 0 | state->px->n_mappings = 0; |
500 | 0 | } |
501 | 0 | rv = proxy_list_slots (state->px, mappings, n_mappings); |
502 | 0 | if (rv == CKR_OK) { |
503 | 0 | free (mappings); |
504 | 0 | } else { |
505 | 0 | p11_debug ("failed to list slots: %lu", rv); |
506 | 0 | state->px->mappings = mappings; |
507 | 0 | state->px->n_mappings = n_mappings; |
508 | 0 | } |
509 | 0 | } |
510 | |
|
511 | 0 | if (rv == CKR_OK) { |
512 | 0 | index = 0; |
513 | | |
514 | | /* Go through and build up a map */ |
515 | 0 | for (i = 0; i < state->px->n_mappings; ++i) { |
516 | 0 | mapping = &state->px->mappings[i]; |
517 | | |
518 | | /* Skip ones without a token if requested */ |
519 | 0 | if (token_present) { |
520 | 0 | rv = (mapping->funcs->C_GetSlotInfo) (mapping->real_slot, &info); |
521 | 0 | if (rv != CKR_OK) |
522 | 0 | break; |
523 | 0 | if (!(info.flags & CKF_TOKEN_PRESENT)) |
524 | 0 | continue; |
525 | 0 | } |
526 | | |
527 | | /* Fill in the slot if we can */ |
528 | 0 | if (slot_list && *count > index) |
529 | 0 | slot_list[index] = mapping->wrap_slot; |
530 | |
|
531 | 0 | ++index; |
532 | 0 | } |
533 | |
|
534 | 0 | if (slot_list && *count < index) |
535 | 0 | rv = CKR_BUFFER_TOO_SMALL; |
536 | |
|
537 | 0 | *count = index; |
538 | 0 | } |
539 | |
|
540 | 0 | p11_unlock (); |
541 | |
|
542 | 0 | return rv; |
543 | 0 | } |
544 | | |
545 | | static CK_RV |
546 | | proxy_C_WaitForSlotEvent (CK_X_FUNCTION_LIST *self, |
547 | | CK_FLAGS flags, |
548 | | CK_SLOT_ID_PTR slot, |
549 | | CK_VOID_PTR reserved) |
550 | 0 | { |
551 | 0 | State *state = (State *)self; |
552 | 0 | Proxy *py = state->px; |
553 | 0 | CK_FUNCTION_LIST_PTR *f; |
554 | 0 | CK_FUNCTION_LIST_PTR funcs; |
555 | 0 | CK_SLOT_ID real_slot; |
556 | 0 | unsigned int i; |
557 | 0 | CK_RV rv = CKR_NO_EVENT; |
558 | | |
559 | | /* Only the non-blocking case is supported. */ |
560 | 0 | if ((flags & CKF_DONT_BLOCK) == 0) |
561 | 0 | return CKR_FUNCTION_NOT_SUPPORTED; |
562 | | |
563 | 0 | p11_lock (); |
564 | |
|
565 | 0 | for (f = py->inited; *f; ++f) { |
566 | 0 | funcs = *f; |
567 | 0 | assert (funcs != NULL); |
568 | |
|
569 | 0 | rv = (funcs->C_WaitForSlotEvent) (flags, &real_slot, reserved); |
570 | 0 | if (rv == CKR_NO_EVENT) |
571 | 0 | continue; |
572 | 0 | if (rv != CKR_OK) |
573 | 0 | break; |
574 | 0 | for (i = 0; i < py->n_mappings; i++) |
575 | 0 | if (py->mappings[i].funcs == funcs && |
576 | 0 | py->mappings[i].real_slot == real_slot) { |
577 | 0 | *slot = py->mappings[i].wrap_slot; |
578 | 0 | break; |
579 | 0 | } |
580 | 0 | } |
581 | | |
582 | 0 | p11_unlock (); |
583 | |
|
584 | 0 | return rv; |
585 | 0 | } |
586 | | |
587 | | static CK_RV |
588 | | proxy_C_OpenSession (CK_X_FUNCTION_LIST *self, |
589 | | CK_SLOT_ID id, |
590 | | CK_FLAGS flags, |
591 | | CK_VOID_PTR user_data, |
592 | | CK_NOTIFY callback, |
593 | | CK_SESSION_HANDLE_PTR handle) |
594 | 0 | { |
595 | 0 | State *state = (State *)self; |
596 | 0 | Session *sess; |
597 | 0 | Mapping map; |
598 | 0 | CK_RV rv; |
599 | |
|
600 | 0 | return_val_if_fail (handle != NULL, CKR_ARGUMENTS_BAD); |
601 | | |
602 | 0 | rv = map_slot_to_real (state->px, &id, &map); |
603 | 0 | if (rv != CKR_OK) |
604 | 0 | return rv; |
605 | | |
606 | 0 | rv = (map.funcs->C_OpenSession) (id, flags, user_data, callback, handle); |
607 | |
|
608 | 0 | if (rv == CKR_OK) { |
609 | 0 | p11_lock (); |
610 | |
|
611 | 0 | if (!PROXY_VALID (state->px)) { |
612 | | /* |
613 | | * The underlying module should have returned an error, so this |
614 | | * code should never be reached with properly behaving modules. |
615 | | * That's why we don't cleanup and close the newly opened session here |
616 | | * or anything like that. |
617 | | */ |
618 | 0 | rv = CKR_CRYPTOKI_NOT_INITIALIZED; |
619 | |
|
620 | 0 | } else { |
621 | 0 | sess = calloc (1, sizeof (Session)); |
622 | 0 | return_val_if_fail (sess != NULL, CKR_HOST_MEMORY); |
623 | 0 | sess->wrap_slot = map.wrap_slot; |
624 | 0 | sess->real_session = *handle; |
625 | 0 | sess->wrap_session = ++state->last_handle; /* TODO: Handle wrapping, and then collisions */ |
626 | 0 | if (!p11_dict_set (state->px->sessions, &sess->wrap_session, sess)) |
627 | 0 | warn_if_reached (); |
628 | 0 | *handle = sess->wrap_session; |
629 | 0 | } |
630 | | |
631 | 0 | p11_unlock (); |
632 | 0 | } |
633 | | |
634 | 0 | return rv; |
635 | 0 | } |
636 | | |
637 | | static CK_RV |
638 | | proxy_C_CloseSession (CK_X_FUNCTION_LIST *self, |
639 | | CK_SESSION_HANDLE handle) |
640 | 0 | { |
641 | 0 | State *state = (State *)self; |
642 | 0 | CK_SESSION_HANDLE key; |
643 | 0 | Mapping map; |
644 | 0 | CK_RV rv; |
645 | |
|
646 | 0 | key = handle; |
647 | 0 | rv = map_session_to_real (state->px, &handle, &map, NULL); |
648 | 0 | if (rv != CKR_OK) |
649 | 0 | return rv; |
650 | 0 | rv = (map.funcs->C_CloseSession) (handle); |
651 | |
|
652 | 0 | if (rv == CKR_OK) { |
653 | 0 | p11_lock (); |
654 | |
|
655 | 0 | if (state->px) |
656 | 0 | p11_dict_remove (state->px->sessions, &key); |
657 | |
|
658 | 0 | p11_unlock (); |
659 | 0 | } |
660 | |
|
661 | 0 | return rv; |
662 | 0 | } |
663 | | |
664 | | static CK_RV |
665 | | proxy_C_CloseAllSessions (CK_X_FUNCTION_LIST *self, |
666 | | CK_SLOT_ID id) |
667 | 0 | { |
668 | 0 | State *state = (State *)self; |
669 | 0 | CK_SESSION_HANDLE_PTR to_close = NULL; |
670 | 0 | CK_RV rv = CKR_OK; |
671 | 0 | Session *sess; |
672 | 0 | CK_ULONG i, count = 0; |
673 | 0 | p11_dictiter iter; |
674 | |
|
675 | 0 | p11_lock (); |
676 | |
|
677 | 0 | if (!PROXY_VALID (state->px)) { |
678 | 0 | rv = CKR_CRYPTOKI_NOT_INITIALIZED; |
679 | 0 | } else { |
680 | 0 | assert (state->px->sessions != NULL); |
681 | 0 | to_close = calloc (p11_dict_size (state->px->sessions) + 1, sizeof (CK_SESSION_HANDLE)); |
682 | 0 | if (!to_close) { |
683 | 0 | rv = CKR_HOST_MEMORY; |
684 | 0 | } else { |
685 | 0 | p11_dict_iterate (state->px->sessions, &iter); |
686 | 0 | count = 0; |
687 | 0 | while (p11_dict_next (&iter, NULL, (void**)&sess)) { |
688 | 0 | if (sess->wrap_slot == id) |
689 | 0 | to_close[count++] = sess->wrap_session; |
690 | 0 | } |
691 | 0 | } |
692 | 0 | } |
693 | |
|
694 | 0 | p11_unlock (); |
695 | |
|
696 | 0 | if (rv != CKR_OK) |
697 | 0 | return rv; |
698 | | |
699 | 0 | for (i = 0; i < count; ++i) |
700 | 0 | proxy_C_CloseSession (self, to_close[i]); |
701 | |
|
702 | 0 | free (to_close); |
703 | 0 | return CKR_OK; |
704 | 0 | } |
705 | | |
706 | | static CK_RV |
707 | | proxy_C_GetSessionInfo (CK_X_FUNCTION_LIST *self, |
708 | | CK_SESSION_HANDLE handle, |
709 | | CK_SESSION_INFO_PTR info) |
710 | 0 | { |
711 | 0 | State *state = (State *)self; |
712 | 0 | Mapping map; |
713 | 0 | CK_RV rv; |
714 | |
|
715 | 0 | if (info == NULL) |
716 | 0 | return CKR_ARGUMENTS_BAD; |
717 | | |
718 | 0 | rv = map_session_to_real (state->px, &handle, &map, NULL); |
719 | 0 | if (rv != CKR_OK) |
720 | 0 | return rv; |
721 | | |
722 | 0 | rv = (map.funcs->C_GetSessionInfo) (handle, info); |
723 | 0 | if (rv == CKR_OK) |
724 | 0 | info->slotID = map.wrap_slot; |
725 | |
|
726 | 0 | return rv; |
727 | 0 | } |
728 | | |
729 | | #include "p11-kit/proxy-generated.h" |
730 | | |
731 | | static const char p11_interface_name[] = "PKCS 11"; |
732 | | |
733 | | static const CK_VERSION version_two = { |
734 | | CRYPTOKI_LEGACY_VERSION_MAJOR, |
735 | | CRYPTOKI_LEGACY_VERSION_MINOR |
736 | | }; |
737 | | |
738 | | static const CK_VERSION version_three = { |
739 | | CRYPTOKI_VERSION_MAJOR, |
740 | | CRYPTOKI_VERSION_MINOR |
741 | | }; |
742 | | |
743 | | /* We are not going to support any special interfaces */ |
744 | 0 | #define NUM_INTERFACES 2 |
745 | | |
746 | | static CK_RV |
747 | | get_interface_inlock(CK_INTERFACE **interface, const CK_VERSION *version, CK_FLAGS flags) |
748 | 0 | { |
749 | 0 | CK_FUNCTION_LIST_PTR module = NULL; |
750 | 0 | CK_FUNCTION_LIST **loaded = NULL; |
751 | 0 | State *state = NULL; |
752 | 0 | CK_RV rv; |
753 | |
|
754 | 0 | return_val_if_fail (interface, CKR_ARGUMENTS_BAD); |
755 | 0 | return_val_if_fail (version, CKR_ARGUMENTS_BAD); |
756 | | |
757 | 0 | if (memcmp (version, &version_three, sizeof(*version)) != 0 && |
758 | 0 | memcmp (version, &version_two, sizeof(*version)) != 0) |
759 | 0 | return CKR_ARGUMENTS_BAD; |
760 | | |
761 | | /* WARNING: Reentrancy can occur here */ |
762 | 0 | rv = p11_modules_load_inlock_reentrant (P11_KIT_MODULE_LOADED_FROM_PROXY, &loaded); |
763 | 0 | if (rv != CKR_OK) |
764 | 0 | goto cleanup; |
765 | | |
766 | 0 | state = calloc (1, sizeof (State)); |
767 | 0 | if (!state) { |
768 | 0 | rv = CKR_HOST_MEMORY; |
769 | 0 | goto cleanup; |
770 | 0 | } |
771 | | |
772 | 0 | p11_virtual_init (&state->virt, &proxy_functions, state, NULL); |
773 | |
|
774 | 0 | state->last_handle = FIRST_HANDLE; |
775 | |
|
776 | 0 | state->loaded = loaded; |
777 | 0 | loaded = NULL; |
778 | | |
779 | | /* Version must be set before calling p11_virtual_wrap, as it |
780 | | * is used to determine which functions are wrapped with |
781 | | * libffi closure. |
782 | | */ |
783 | 0 | state->virt.funcs.version = *version; |
784 | |
|
785 | 0 | module = p11_virtual_wrap (&state->virt, free); |
786 | 0 | if (module == NULL) { |
787 | 0 | rv = CKR_GENERAL_ERROR; |
788 | 0 | goto cleanup; |
789 | 0 | } |
790 | | |
791 | 0 | module->version = *version; |
792 | |
|
793 | 0 | state->wrapped.pInterfaceName = (char *)p11_interface_name; |
794 | |
|
795 | 0 | state->wrapped.pFunctionList = module; |
796 | 0 | module = NULL; |
797 | |
|
798 | 0 | state->wrapped.flags = flags; |
799 | |
|
800 | 0 | *interface = &state->wrapped; |
801 | |
|
802 | 0 | state->next = all_instances; |
803 | 0 | all_instances = state; |
804 | 0 | state = NULL; |
805 | |
|
806 | 0 | cleanup: |
807 | 0 | if (module) |
808 | 0 | p11_virtual_unwrap (module); |
809 | 0 | if (loaded) |
810 | 0 | p11_kit_modules_release (loaded); |
811 | 0 | if (state) { |
812 | 0 | p11_virtual_unwrap (state->wrapped.pFunctionList); |
813 | 0 | p11_kit_modules_release (state->loaded); |
814 | 0 | free (state); |
815 | 0 | } |
816 | 0 | return rv; |
817 | 0 | } |
818 | | |
819 | | #ifdef OS_WIN32 |
820 | | __declspec(dllexport) |
821 | | #endif |
822 | | CK_RV |
823 | | C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list) |
824 | 0 | { |
825 | 0 | CK_RV rv = CKR_OK; |
826 | 0 | CK_INTERFACE *res = NULL; |
827 | |
|
828 | 0 | p11_library_init_once (); |
829 | 0 | p11_lock (); |
830 | |
|
831 | 0 | rv = get_interface_inlock (&res, &version_two, 0); |
832 | 0 | if (rv == CKR_OK) |
833 | 0 | *list = res->pFunctionList; |
834 | |
|
835 | 0 | p11_unlock (); |
836 | |
|
837 | 0 | return rv; |
838 | 0 | } |
839 | | |
840 | | #ifdef OS_WIN32 |
841 | | __declspec(dllexport) |
842 | | #endif |
843 | | CK_RV |
844 | | C_GetInterfaceList (CK_INTERFACE_PTR pInterfacesList, CK_ULONG_PTR pulCount) |
845 | 0 | { |
846 | 0 | CK_RV rv = CKR_OK; |
847 | 0 | CK_INTERFACE *interfaces[NUM_INTERFACES]; |
848 | 0 | CK_ULONG count = 0; |
849 | 0 | CK_ULONG i; |
850 | |
|
851 | 0 | if (pulCount == NULL_PTR) |
852 | 0 | return CKR_ARGUMENTS_BAD; |
853 | | |
854 | 0 | if (pInterfacesList == NULL_PTR) { |
855 | 0 | *pulCount = NUM_INTERFACES; |
856 | 0 | return CKR_OK; |
857 | 0 | } |
858 | | |
859 | 0 | if (*pulCount < NUM_INTERFACES) { |
860 | 0 | *pulCount = NUM_INTERFACES; |
861 | 0 | return CKR_BUFFER_TOO_SMALL; |
862 | 0 | } |
863 | | |
864 | 0 | p11_library_init_once (); |
865 | 0 | p11_lock (); |
866 | |
|
867 | 0 | rv = get_interface_inlock (&interfaces[count++], &version_three, 0); |
868 | 0 | if (rv != CKR_OK) |
869 | 0 | goto cleanup; |
870 | | |
871 | 0 | rv = get_interface_inlock (&interfaces[count++], &version_two, 0); |
872 | 0 | if (rv != CKR_OK) |
873 | 0 | goto cleanup; |
874 | | |
875 | 0 | for (i = 0; i < count; i++) |
876 | 0 | pInterfacesList[i] = *interfaces[i]; |
877 | 0 | *pulCount = count; |
878 | |
|
879 | 0 | cleanup: |
880 | 0 | p11_unlock (); |
881 | |
|
882 | 0 | return rv; |
883 | 0 | } |
884 | | |
885 | | #ifdef OS_WIN32 |
886 | | __declspec(dllexport) |
887 | | #endif |
888 | | CK_RV |
889 | | C_GetInterface (CK_UTF8CHAR_PTR pInterfaceName, CK_VERSION_PTR pVersion, |
890 | | CK_INTERFACE_PTR_PTR ppInterface, CK_FLAGS flags) |
891 | 0 | { |
892 | 0 | int rv; |
893 | |
|
894 | 0 | if (ppInterface == NULL) { |
895 | 0 | return CKR_ARGUMENTS_BAD; |
896 | 0 | } |
897 | | |
898 | 0 | if (pInterfaceName && |
899 | 0 | strcmp ((const char *)pInterfaceName, p11_interface_name) != 0) { |
900 | 0 | return CKR_ARGUMENTS_BAD; |
901 | 0 | } |
902 | | |
903 | 0 | p11_library_init_once (); |
904 | 0 | p11_lock (); |
905 | |
|
906 | 0 | rv = get_interface_inlock (ppInterface, |
907 | 0 | pVersion ? pVersion : &version_three, |
908 | 0 | flags); |
909 | |
|
910 | 0 | p11_unlock (); |
911 | |
|
912 | 0 | return rv; |
913 | 0 | } |
914 | | |
915 | | void |
916 | | p11_proxy_module_cleanup (void) |
917 | 0 | { |
918 | 0 | State *state, *next; |
919 | |
|
920 | 0 | state = all_instances; |
921 | 0 | all_instances = NULL; |
922 | |
|
923 | 0 | for (; state != NULL; state = next) { |
924 | 0 | next = state->next; |
925 | 0 | p11_kit_modules_release (state->loaded); |
926 | 0 | p11_virtual_unwrap (state->wrapped.pFunctionList); |
927 | 0 | } |
928 | 0 | } |
929 | | |
930 | | bool |
931 | | p11_proxy_module_check (CK_FUNCTION_LIST_PTR module) |
932 | | { |
933 | | State *state; |
934 | | bool ret = false; |
935 | | |
936 | | if (!p11_virtual_is_wrapper (module)) |
937 | | return false; |
938 | | |
939 | | p11_lock (); |
940 | | for (state = all_instances; state != NULL; state = state->next) |
941 | | if (state->wrapped.pFunctionList == module) { |
942 | | ret = true; |
943 | | break; |
944 | | } |
945 | | p11_unlock (); |
946 | | |
947 | | return ret; |
948 | | } |
949 | | |
950 | | CK_RV |
951 | | p11_proxy_module_create (CK_FUNCTION_LIST_PTR *module, |
952 | | CK_FUNCTION_LIST_PTR *modules) |
953 | 0 | { |
954 | 0 | State *state; |
955 | 0 | CK_RV rv = CKR_OK; |
956 | |
|
957 | 0 | assert (module != NULL); |
958 | 0 | assert (modules != NULL); |
959 | |
|
960 | 0 | state = calloc (1, sizeof (State)); |
961 | 0 | if (!state) |
962 | 0 | return CKR_HOST_MEMORY; |
963 | | |
964 | 0 | p11_virtual_init (&state->virt, &proxy_functions, state, NULL); |
965 | 0 | state->last_handle = FIRST_HANDLE; |
966 | 0 | state->loaded = modules_dup (modules); |
967 | 0 | state->wrapped.pFunctionList = p11_virtual_wrap (&state->virt, (p11_destroyer)p11_virtual_uninit); |
968 | 0 | if (state->wrapped.pFunctionList == NULL) { |
969 | 0 | p11_kit_modules_release (state->loaded); |
970 | 0 | free (state); |
971 | 0 | return CKR_GENERAL_ERROR; |
972 | 0 | } |
973 | | |
974 | 0 | *module = state->wrapped.pFunctionList; |
975 | |
|
976 | 0 | return rv; |
977 | 0 | } |