1 /* Support of smartcards and cryptotokens
2 * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
3 * Copyright (C) 2004 David Buechi, Michael Meier
4 * Zuercher Hochschule Winterthur, Switzerland
6 * Copyright (C) 2005 Michael Joosten
8 * Copyright (C) 2005 Andreas Steffen
9 * Hochschule für Technik Rapperswil, Switzerland
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * RCSID $Id: smartcard.c,v 1.41 2006/01/04 21:03:52 as Exp $
33 #include <ipsec_policy.h>
35 #include "constants.h"
38 #include "rsaref/unix.h"
39 #include "rsaref/pkcs11.h"
49 #include "smartcard.h"
53 #define DEFAULT_BASE 16
55 /* chained list of smartcard records */
56 static smartcard_t
*smartcards
= NULL
;
58 /* number of generated sc objects */
59 static int sc_number
= 0;
61 const smartcard_t empty_sc
= {
64 { CERT_NONE
, {NULL
} }, /* last_cert */
70 { NULL
, 0 } , /* pin */
73 FALSE
, /* session_opened */
74 FALSE
, /* logged_in */
79 #ifdef SMARTCARD /* compile with smartcard support */
81 #define SCX_MAGIC 0xd00bed00
83 struct scx_pkcs11_module
{
88 typedef struct scx_pkcs11_module scx_pkcs11_module_t
;
90 /* PKCS #11 cryptoki context */
91 static bool scx_initialized
= FALSE
;
92 static scx_pkcs11_module_t
*pkcs11_module
= NULL_PTR
;
93 static CK_FUNCTION_LIST_PTR pkcs11_functions
= NULL_PTR
;
95 /* crytoki v2.11 - return values of PKCS #11 functions*/
97 static const char *const pkcs11_return_name
[] = {
101 "CKR_SLOT_ID_INVALID",
104 "CKR_FUNCTION_FAILED",
107 "CKR_NEED_TO_CREATE_THREADS",
111 static const char *const pkcs11_return_name_10
[] = {
112 "CKR_ATTRIBUTE_READ_ONLY",
113 "CKR_ATTRIBUTE_SENSITIVE",
114 "CKR_ATTRIBUTE_TYPE_INVALID",
115 "CKR_ATTRIBUTE_VALUE_INVALID"
118 static const char *const pkcs11_return_name_20
[] = {
123 static const char *const pkcs11_return_name_30
[] = {
129 static const char *const pkcs11_return_name_40
[] = {
130 "CKR_ENCRYPTED_DATA_INVALID",
131 "CKR_ENCRYPTED_DATA_LEN_RANGE"
134 static const char *const pkcs11_return_name_50
[] = {
135 "CKR_FUNCTION_CANCELED",
136 "CKR_FUNCTION_NOT_PARALLEL",
137 "CKR_0x52_UNDEFINED",
138 "CKR_0x53_UNDEFINED",
139 "CKR_FUNCTION_NOT_SUPPORTED"
142 static const char *const pkcs11_return_name_60
[] = {
143 "CKR_KEY_HANDLE_INVALID",
145 "CKR_KEY_SIZE_RANGE",
146 "CKR_KEY_TYPE_INCONSISTENT",
147 "CKR_KEY_NOT_NEEDED",
150 "CKR_KEY_INDIGESTIBLE",
151 "CKR_KEY_FUNCTION_NOT_PERMITTED",
152 "CKR_KEY_NOT_WRAPPABLE",
153 "CKR_KEY_UNEXTRACTABLE"
156 static const char *const pkcs11_return_name_70
[] = {
157 "CKR_MECHANISM_INVALID",
158 "CKR_MECHANISM_PARAM_INVALID"
161 static const char *const pkcs11_return_name_80
[] = {
162 "CKR_OBJECT_HANDLE_INVALID"
165 static const char *const pkcs11_return_name_90
[] = {
166 "CKR_OPERATION_ACTIVE",
167 "CKR_OPERATION_NOT_INITIALIZED"
170 static const char *const pkcs11_return_name_A0
[] = {
178 static const char *const pkcs11_return_name_B0
[] = {
179 "CKR_SESSION_CLOSED",
181 "CKR_0xB2_UNDEFINED",
182 "CKR_SESSION_HANDLE_INVALID",
183 "CKR_SESSION_PARALLEL_NOT_SUPPORTED",
184 "CKR_SESSION_READ_ONLY",
185 "CKR_SESSION_EXISTS",
186 "CKR_SESSION_READ_ONLY_EXISTS",
187 "CKR_SESSION_READ_WRITE_SO_EXISTS"
190 static const char *const pkcs11_return_name_C0
[] = {
191 "CKR_SIGNATURE_INVALID",
192 "CKR_SIGNATURE_LEN_RANGE"
195 static const char *const pkcs11_return_name_D0
[] = {
196 "CKR_TEMPLATE_INCOMPLETE",
197 "CKR_TEMPLATE_INCONSISTENT"
200 static const char *const pkcs11_return_name_E0
[] = {
201 "CKR_TOKEN_NOT_PRESENT",
202 "CKR_TOKEN_NOT_RECOGNIZED",
203 "CKR_TOKEN_WRITE_PROTECTED"
206 static const char *const pkcs11_return_name_F0
[] = {
207 "CKR_UNWRAPPING_KEY_HANDLE_INVALID",
208 "CKR_UNWRAPPING_KEY_SIZE_RANGE",
209 "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT"
212 static const char *const pkcs11_return_name_100
[] = {
213 "CKR_USER_ALREADY_LOGGED_IN",
214 "CKR_USER_NOT_LOGGED_IN",
215 "CKR_USER_PIN_NOT_INITIALIZED",
216 "CKR_USER_TYPE_INVALID",
217 "CKR_USER_ANOTHER_ALREADY_LOGGED_IN",
218 "CKR_USER_TOO_MANY_TYPES"
221 static const char *const pkcs11_return_name_110
[] = {
222 "CKR_WRAPPED_KEY_INVALID",
223 "CKR_0x111_UNDEFINED",
224 "CKR_WRAPPED_KEY_LEN_RANGE",
225 "CKR_WRAPPING_KEY_HANDLE_INVALID",
226 "CKR_WRAPPING_KEY_SIZE_RANGE",
227 "CKR_WRAPPING_KEY_TYPE_INCONSISTENT"
230 static const char *const pkcs11_return_name_120
[] = {
231 "CKR_RANDOM_SEED_NOT_SUPPORTED",
235 static const char *const pkcs11_return_name_130
[] = {
236 "CKR_DOMAIN_PARAMS_INVALID"
239 static const char *const pkcs11_return_name_150
[] = {
240 "CKR_BUFFER_TOO_SMALL"
243 static const char *const pkcs11_return_name_160
[] = {
244 "CKR_SAVED_STATE_INVALID"
247 static const char *const pkcs11_return_name_170
[] = {
248 "CKR_INFORMATION_SENSITIVE"
251 static const char *const pkcs11_return_name_180
[] = {
252 "CKR_STATE_UNSAVEABLE"
255 static const char *const pkcs11_return_name_190
[] = {
256 "CKR_CRYPTOKI_NOT_INITIALIZED",
257 "CKR_CRYPTOKI_ALREADY_INITIALIZED"
260 static const char *const pkcs11_return_name_1A0
[] = {
262 "CKR_MUTEX_NOT_LOCKED"
265 static const char *const pkcs11_return_name_200
[] = {
266 "CKR_FUNCTION_REJECTED"
269 static const char *const pkcs11_return_name_vendor
[] = {
273 static enum_names pkcs11_return_names_vendor
=
274 { CKR_VENDOR_DEFINED
, CKR_VENDOR_DEFINED
275 , pkcs11_return_name_vendor
, NULL
};
277 static enum_names pkcs11_return_names_200
=
278 { CKR_FUNCTION_REJECTED
, CKR_FUNCTION_REJECTED
279 , pkcs11_return_name_200
, &pkcs11_return_names_vendor
};
281 static enum_names pkcs11_return_names_1A0
=
282 { CKR_MUTEX_BAD
, CKR_MUTEX_NOT_LOCKED
283 , pkcs11_return_name_1A0
, &pkcs11_return_names_200
};
285 static enum_names pkcs11_return_names_190
=
286 { CKR_CRYPTOKI_NOT_INITIALIZED
, CKR_CRYPTOKI_ALREADY_INITIALIZED
287 , pkcs11_return_name_190
, &pkcs11_return_names_1A0
};
289 static enum_names pkcs11_return_names_180
=
290 { CKR_STATE_UNSAVEABLE
, CKR_STATE_UNSAVEABLE
291 , pkcs11_return_name_180
, &pkcs11_return_names_190
};
293 static enum_names pkcs11_return_names_170
=
294 { CKR_INFORMATION_SENSITIVE
, CKR_INFORMATION_SENSITIVE
295 , pkcs11_return_name_170
, &pkcs11_return_names_180
};
297 static enum_names pkcs11_return_names_160
=
298 { CKR_SAVED_STATE_INVALID
, CKR_SAVED_STATE_INVALID
299 , pkcs11_return_name_160
, &pkcs11_return_names_170
};
301 static enum_names pkcs11_return_names_150
=
302 { CKR_BUFFER_TOO_SMALL
, CKR_BUFFER_TOO_SMALL
303 , pkcs11_return_name_150
, &pkcs11_return_names_160
};
305 static enum_names pkcs11_return_names_130
=
306 { CKR_DOMAIN_PARAMS_INVALID
, CKR_DOMAIN_PARAMS_INVALID
307 , pkcs11_return_name_130
, &pkcs11_return_names_150
};
309 static enum_names pkcs11_return_names_120
=
310 { CKR_RANDOM_SEED_NOT_SUPPORTED
, CKR_RANDOM_NO_RNG
311 , pkcs11_return_name_120
, &pkcs11_return_names_130
};
313 static enum_names pkcs11_return_names_110
=
314 { CKR_WRAPPED_KEY_INVALID
, CKR_WRAPPING_KEY_TYPE_INCONSISTENT
315 , pkcs11_return_name_110
, &pkcs11_return_names_120
};
317 static enum_names pkcs11_return_names_100
=
318 { CKR_USER_ALREADY_LOGGED_IN
, CKR_USER_TOO_MANY_TYPES
319 , pkcs11_return_name_100
, &pkcs11_return_names_110
};
321 static enum_names pkcs11_return_names_F0
=
322 { CKR_UNWRAPPING_KEY_HANDLE_INVALID
, CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT
323 , pkcs11_return_name_F0
, &pkcs11_return_names_100
};
325 static enum_names pkcs11_return_names_E0
=
326 { CKR_TOKEN_NOT_PRESENT
, CKR_TOKEN_WRITE_PROTECTED
327 , pkcs11_return_name_E0
, &pkcs11_return_names_F0
};
329 static enum_names pkcs11_return_names_D0
=
330 { CKR_TEMPLATE_INCOMPLETE
, CKR_TEMPLATE_INCONSISTENT
331 , pkcs11_return_name_D0
,&pkcs11_return_names_E0
};
333 static enum_names pkcs11_return_names_C0
=
334 { CKR_SIGNATURE_INVALID
, CKR_SIGNATURE_LEN_RANGE
335 , pkcs11_return_name_C0
, &pkcs11_return_names_D0
};
337 static enum_names pkcs11_return_names_B0
=
338 { CKR_SESSION_CLOSED
, CKR_SESSION_READ_WRITE_SO_EXISTS
339 , pkcs11_return_name_B0
, &pkcs11_return_names_C0
};
341 static enum_names pkcs11_return_names_A0
=
342 { CKR_PIN_INCORRECT
, CKR_PIN_LOCKED
343 , pkcs11_return_name_A0
, &pkcs11_return_names_B0
};
345 static enum_names pkcs11_return_names_90
=
346 { CKR_OPERATION_ACTIVE
, CKR_OPERATION_NOT_INITIALIZED
347 , pkcs11_return_name_90
, &pkcs11_return_names_A0
};
349 static enum_names pkcs11_return_names_80
=
350 { CKR_OBJECT_HANDLE_INVALID
, CKR_OBJECT_HANDLE_INVALID
351 , pkcs11_return_name_80
, &pkcs11_return_names_90
};
353 static enum_names pkcs11_return_names_70
=
354 { CKR_MECHANISM_INVALID
, CKR_MECHANISM_PARAM_INVALID
355 , pkcs11_return_name_70
, &pkcs11_return_names_80
};
357 static enum_names pkcs11_return_names_60
=
358 { CKR_KEY_HANDLE_INVALID
, CKR_KEY_UNEXTRACTABLE
359 , pkcs11_return_name_60
, &pkcs11_return_names_70
};
361 static enum_names pkcs11_return_names_50
=
362 { CKR_FUNCTION_CANCELED
, CKR_FUNCTION_NOT_SUPPORTED
363 , pkcs11_return_name_50
, &pkcs11_return_names_60
};
365 static enum_names pkcs11_return_names_40
=
366 { CKR_ENCRYPTED_DATA_INVALID
, CKR_ENCRYPTED_DATA_LEN_RANGE
367 , pkcs11_return_name_40
, &pkcs11_return_names_50
};
369 static enum_names pkcs11_return_names_30
=
370 { CKR_DEVICE_ERROR
, CKR_DEVICE_REMOVED
371 , pkcs11_return_name_30
, &pkcs11_return_names_40
};
373 static enum_names pkcs11_return_names_20
=
374 { CKR_DATA_INVALID
, CKR_DATA_LEN_RANGE
375 , pkcs11_return_name_20
, &pkcs11_return_names_30
};
377 static enum_names pkcs11_return_names_10
=
378 { CKR_ATTRIBUTE_READ_ONLY
, CKR_ATTRIBUTE_VALUE_INVALID
379 , pkcs11_return_name_10
, &pkcs11_return_names_20
};
381 static enum_names pkcs11_return_names
=
382 { CKR_OK
, CKR_CANT_LOCK
383 , pkcs11_return_name
, &pkcs11_return_names_10
};
386 * Unload a PKCS#11 module.
387 * The calling application is responsible for cleaning up
388 * and calling C_Finalize()
391 scx_unload_pkcs11_module(scx_pkcs11_module_t
*mod
)
393 if (!mod
|| mod
->_magic
!= SCX_MAGIC
)
394 return CKR_ARGUMENTS_BAD
;
396 if (dlclose(mod
->handle
) < 0)
397 return CKR_FUNCTION_FAILED
;
399 memset(mod
, 0, sizeof(*mod
));
404 static scx_pkcs11_module_t
*
405 scx_load_pkcs11_module(const char *name
, CK_FUNCTION_LIST_PTR_PTR funcs
)
407 CK_RV (*c_get_function_list
)(CK_FUNCTION_LIST_PTR_PTR
);
408 scx_pkcs11_module_t
*mod
;
412 if (name
== NULL
|| *name
== '\0')
415 /* Try to load PKCS#11 library module*/
416 handle
= dlopen(name
, RTLD_NOW
);
420 mod
= alloc_thing(scx_pkcs11_module_t
, "scx_pkcs11_module");
421 mod
->_magic
= SCX_MAGIC
;
422 mod
->handle
= handle
;
424 /* Get the list of function pointers */
425 c_get_function_list
= (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR
))
426 dlsym(mod
->handle
, "C_GetFunctionList");
427 if (!c_get_function_list
)
430 rv
= c_get_function_list(funcs
);
434 failed
: scx_unload_pkcs11_module(mod
);
439 * retrieve a certificate object
442 scx_find_cert_object(CK_SESSION_HANDLE session
, CK_OBJECT_HANDLE object
443 , smartcard_t
*sc
, cert_t
*cert
)
445 size_t hex_len
, label_len
;
446 u_char
*hex_id
= NULL
;
448 x509cert_t
*x509cert
;
450 CK_ATTRIBUTE attr
[] = {
451 { CKA_ID
, NULL_PTR
, 0L },
452 { CKA_LABEL
, NULL_PTR
, 0L },
453 { CKA_VALUE
, NULL_PTR
, 0L }
456 /* initialize the return argument */
459 /* get the length of the attributes first */
460 CK_RV rv
= pkcs11_functions
->C_GetAttributeValue(session
, object
, attr
, 3);
463 plog("couldn't read the attribute sizes: %s"
464 , enum_show(&pkcs11_return_names
, rv
));
470 hex_id
= alloc_bytes(attr
[0].ulValueLen
, "hex id");
471 hex_len
= attr
[0].ulValueLen
;
472 sc
->label
= alloc_bytes(attr
[1].ulValueLen
+ 1, "sc label");
473 label_len
= attr
[1].ulValueLen
;
474 blob
.ptr
= alloc_bytes(attr
[2].ulValueLen
, "x509cert blob");
475 blob
.len
= attr
[2].ulValueLen
;
477 attr
[0].pValue
= hex_id
;
478 attr
[1].pValue
= sc
->label
;
479 attr
[2].pValue
= blob
.ptr
;
481 /* now get the attributes */
482 rv
= pkcs11_functions
->C_GetAttributeValue(session
, object
, attr
, 3);
485 plog("couldn't read the attributes: %s"
486 , enum_show(&pkcs11_return_names
, rv
));
495 /* convert id from hex to ASCII */
496 sc
->id
= alloc_bytes(2*hex_len
+ 1, " sc id");
497 datatot(hex_id
, hex_len
, 16, sc
->id
, 2*hex_len
+ 1);
500 /* safeguard in case the label is not null terminated */
501 sc
->label
[label_len
] = '\0';
503 /* parse the retrieved cert */
504 x509cert
= alloc_thing(x509cert_t
, "x509cert");
505 *x509cert
= empty_x509cert
;
506 x509cert
->smartcard
= TRUE
;
508 if (!parse_x509cert(blob
, 0, x509cert
))
510 plog("failed to load cert from smartcard, error in X.509 certificate");
511 free_x509cert(x509cert
);
514 cert
->type
= CERT_X509_SIGNATURE
;
515 cert
->u
.x509
= x509cert
;
520 * search a given slot for PKCS#11 certificate objects
523 scx_find_cert_objects(CK_SLOT_ID slot
, CK_SESSION_HANDLE session
)
526 CK_OBJECT_CLASS
class = CKO_CERTIFICATE
;
527 CK_ATTRIBUTE attr
[] = {{ CKA_CLASS
, &class, sizeof(class) }};
529 rv
= pkcs11_functions
->C_FindObjectsInit(session
, attr
, 1);
532 plog("error in C_FindObjectsInit: %s"
533 , enum_show(&pkcs11_return_names
, rv
));
539 CK_OBJECT_HANDLE object
;
540 CK_ULONG obj_count
= 0;
546 rv
= pkcs11_functions
->C_FindObjects(session
, &object
, 1, &obj_count
);
549 plog("error in C_FindObjects: %s"
550 , enum_show(&pkcs11_return_names
, rv
));
554 /* no objects left */
558 /* create and initialize a new smartcard object */
559 sc
= alloc_thing(smartcard_t
, "smartcard");
561 sc
->any_slot
= FALSE
;
564 if (!scx_find_cert_object(session
, object
, sc
, &sc
->last_cert
))
570 DBG_log("found cert in %s with id: %s, label: '%s'"
571 , scx_print_slot(sc
, ""), sc
->id
, sc
->label
)
574 /* check validity of certificate */
575 cert
= sc
->last_cert
.u
.x509
;
576 valid_until
= cert
->notAfter
;
577 ugh
= check_validity(cert
, &valid_until
);
588 DBG_log(" certificate is valid")
594 /* put end entity and ca certificates into different chains */
596 add_authcert(cert
, AUTH_CA
);
599 add_x509_public_key(cert
, valid_until
, DAL_LOCAL
);
600 sc
->last_cert
.u
.x509
= add_x509cert(cert
);
603 share_cert(sc
->last_cert
);
604 time(&sc
->last_load
);
607 rv
= pkcs11_functions
->C_FindObjectsFinal(session
);
610 plog("error in C_FindObjectsFinal: %s"
611 , enum_show(&pkcs11_return_names
, rv
));
616 * search all slots for PKCS#11 certificate objects
619 scx_find_all_cert_objects(void)
622 CK_SLOT_ID_PTR slots
= NULL_PTR
;
623 CK_ULONG slot_count
= 0;
626 if (!scx_initialized
)
628 plog("pkcs11 module not initialized");
632 /* read size, always returns CKR_OK ! */
633 rv
= pkcs11_functions
->C_GetSlotList(FALSE
, NULL_PTR
, &slot_count
);
635 /* allocate memory for the slots */
636 slots
= (CK_SLOT_ID
*)alloc_bytes(slot_count
* sizeof(CK_SLOT_ID
), "slots");
638 rv
= pkcs11_functions
->C_GetSlotList(FALSE
, slots
, &slot_count
);
641 plog("error in C_GetSlotList: %s", enum_show(&pkcs11_return_names
, rv
));
646 /* look in every slot for certificate objects */
647 for (i
= 0; i
< slot_count
; i
++)
649 CK_SLOT_ID slot
= slots
[i
];
651 CK_SESSION_HANDLE session
;
653 rv
= pkcs11_functions
->C_GetSlotInfo(slot
, &info
);
657 plog("error in C_GetSlotInfo: %s"
658 , enum_show(&pkcs11_return_names
, rv
));
662 if (!(info
.flags
& CKF_TOKEN_PRESENT
))
664 plog("no token present in slot %lu", slot
);
668 rv
= pkcs11_functions
->C_OpenSession(slot
669 , CKF_SERIAL_SESSION
, NULL_PTR
, NULL_PTR
, &session
);
672 plog("failed to open a session on slot %lu: %s"
673 , slot
, enum_show(&pkcs11_return_names
, rv
));
677 DBG_log("pkcs11 session #%ld for searching slot %lu", session
, slot
)
679 scx_find_cert_objects(slot
, session
);
681 rv
= pkcs11_functions
->C_CloseSession(session
);
684 plog("error in C_CloseSession: %s"
685 , enum_show(&pkcs11_return_names
, rv
));
693 * load and initialize PKCS#11 cryptoki module
696 scx_init(const char* module
)
703 plog("weird - pkcs11 module seems already to be initialized");
708 #ifdef PKCS11_DEFAULT_LIB
709 module
= PKCS11_DEFAULT_LIB
;
712 plog("no pkcs11 module defined");
717 DBG(DBG_CONTROL
| DBG_CRYPT
,
718 DBG_log("pkcs11 module '%s' loading...", module
)
720 pkcs11_module
= scx_load_pkcs11_module(module
, &pkcs11_functions
);
721 if (pkcs11_module
== NULL
)
723 plog("failed to load pkcs11 module '%s'", module
);
727 DBG(DBG_CONTROL
| DBG_CRYPT
,
728 DBG_log("pkcs11 module initializing...")
730 rv
= pkcs11_functions
->C_Initialize(NULL
);
733 plog("failed to initialize pkcs11 module: %s"
734 , enum_show(&pkcs11_return_names
, rv
));
738 scx_initialized
= TRUE
;
739 DBG(DBG_CONTROL
| DBG_CRYPT
,
740 DBG_log("pkcs11 module loaded and initialized")
743 scx_find_all_cert_objects();
748 * finalize and unload PKCS#11 cryptoki module
754 while (smartcards
!= NULL
)
756 scx_release(smartcards
);
759 if (pkcs11_functions
!= NULL_PTR
)
761 pkcs11_functions
->C_Finalize(NULL_PTR
);
762 pkcs11_functions
= NULL_PTR
;
765 if (pkcs11_module
!= NULL
)
767 scx_unload_pkcs11_module(pkcs11_module
);
768 pkcs11_module
= NULL
;
771 scx_initialized
= FALSE
;
772 DBG(DBG_CONTROL
| DBG_CRYPT
,
773 DBG_log("pkcs11 module finalized and unloaded")
779 * does a filename contain the token %smartcard?
782 scx_on_smartcard(const char *filename
)
784 return strncmp(filename
, SCX_TOKEN
, strlen(SCX_TOKEN
)) == 0;
789 * find a specific object on the smartcard
792 scx_pkcs11_find_object( CK_SESSION_HANDLE session
,
793 CK_OBJECT_HANDLE_PTR object
,
794 CK_OBJECT_CLASS
class,
800 CK_ULONG obj_count
= 0;
801 CK_ULONG attr_count
= 1;
803 CK_ATTRIBUTE attr
[] = {
804 { CKA_CLASS
, &class, sizeof(class) },
810 ttodata(id
, strlen(id
), 16, buf
, BUF_LEN
, &len
);
811 attr
[1].ulValueLen
= len
;
815 /* get info for certificate with id */
816 rv
= pkcs11_functions
->C_FindObjectsInit(session
, attr
, attr_count
);
819 plog("error in C_FindObjectsInit: %s"
820 , enum_show(&pkcs11_return_names
, rv
));
824 rv
= pkcs11_functions
->C_FindObjects(session
, object
, 1, &obj_count
);
827 plog("error in C_FindObjects: %s"
828 , enum_show(&pkcs11_return_names
, rv
));
832 rv
= pkcs11_functions
->C_FindObjectsFinal(session
);
835 plog("error in C_FindObjectsFinal: %s"
836 , enum_show(&pkcs11_return_names
, rv
));
840 return (obj_count
!= 0);
844 * check if a given certificate object id is found in a slot
847 scx_find_cert_id_in_slot(smartcard_t
*sc
, CK_SLOT_ID slot
)
849 CK_SESSION_HANDLE session
;
850 CK_OBJECT_HANDLE object
;
853 CK_RV rv
= pkcs11_functions
->C_GetSlotInfo(slot
, &info
);
857 plog("error in C_GetSlotInfo: %s"
858 , enum_show(&pkcs11_return_names
, rv
));
862 if (!(info
.flags
& CKF_TOKEN_PRESENT
))
864 plog("no token present in slot %lu", slot
);
868 rv
= pkcs11_functions
->C_OpenSession(slot
869 , CKF_SERIAL_SESSION
, NULL_PTR
, NULL_PTR
, &session
);
872 plog("failed to open a session on slot %lu: %s"
873 , slot
, enum_show(&pkcs11_return_names
, rv
));
877 DBG_log("pkcs11 session #%ld for searching slot %lu", session
, slot
)
880 /* check if there is a certificate on the card in the specified slot */
881 if (scx_pkcs11_find_object(session
, &object
, CKO_CERTIFICATE
, sc
->id
))
884 sc
->any_slot
= FALSE
;
885 sc
->session
= session
;
886 sc
->session_opened
= TRUE
;
890 rv
= pkcs11_functions
->C_CloseSession(session
);
893 plog("error in C_CloseSession: %s"
894 , enum_show(&pkcs11_return_names
, rv
));
901 * Connect to the smart card in the reader and select the correct slot
904 scx_establish_context(smartcard_t
*sc
)
907 bool id_found
= FALSE
;
909 if (!scx_initialized
)
911 plog("pkcs11 module not initialized");
915 if (sc
->session_opened
)
917 DBG(DBG_CONTROL
| DBG_CRYPT
,
918 DBG_log("pkcs11 session #%ld already open", sc
->session
)
924 id_found
= scx_find_cert_id_in_slot(sc
, sc
->slot
);
930 CK_SLOT_ID_PTR slots
= NULL_PTR
;
931 CK_ULONG slot_count
= 0;
934 /* read size, always returns CKR_OK ! */
935 rv
= pkcs11_functions
->C_GetSlotList(FALSE
, NULL_PTR
, &slot_count
);
937 /* allocate memory for the slots */
938 slots
= (CK_SLOT_ID
*)alloc_bytes(slot_count
* sizeof(CK_SLOT_ID
), "slots");
940 rv
= pkcs11_functions
->C_GetSlotList(FALSE
, slots
, &slot_count
);
943 plog("error in C_GetSlotList: %s"
944 , enum_show(&pkcs11_return_names
, rv
));
949 /* look in every slot for a certificate with a given object ID */
950 for (i
= 0; i
< slot_count
; i
++)
953 id_found
= scx_find_cert_id_in_slot(sc
, slot
);
962 DBG(DBG_CONTROL
| DBG_CRYPT
,
963 DBG_log("found token with id %s in slot %lu", sc
->id
, sc
->slot
);
964 DBG_log("pkcs11 session #%ld opened", sc
->session
)
969 plog(" no certificate with id %s found on smartcard", sc
->id
);
973 plog("warning: SMARTCARD support is deactivated in pluto/Makefile!");
979 * log in to a session
982 scx_login(smartcard_t
*sc
)
989 DBG(DBG_CONTROL
| DBG_CRYPT
,
990 DBG_log("pkcs11 session #%ld login already done", sc
->session
)
995 if (sc
->pin
.ptr
== NULL
)
997 plog("unable to log in without PIN!");
1001 if (!sc
->session_opened
)
1003 plog("session not opened");
1007 rv
= pkcs11_functions
->C_Login(sc
->session
, CKU_USER
1008 , (CK_UTF8CHAR
*) sc
->pin
.ptr
, sc
->pin
.len
);
1009 if (rv
!= CKR_OK
&& rv
!= CKR_USER_ALREADY_LOGGED_IN
)
1011 plog("unable to login: %s"
1012 , enum_show(&pkcs11_return_names
, rv
));
1015 DBG(DBG_CONTROL
| DBG_CRYPT
,
1016 DBG_log("pkcs11 session #%ld login successful", sc
->session
)
1018 sc
->logged_in
= TRUE
;
1027 * logout from a session
1030 scx_logout(smartcard_t
*sc
)
1034 rv
= pkcs11_functions
->C_Logout(sc
->session
);
1036 plog("error in C_Logout: %s"
1037 , enum_show(&pkcs11_return_names
, rv
));
1039 DBG(DBG_CONTROL
| DBG_CRYPT
,
1040 DBG_log("pkcs11 session #%ld logout", sc
->session
)
1042 sc
->logged_in
= FALSE
;
1048 * Release context and disconnect from card
1051 scx_release_context(smartcard_t
*sc
)
1056 if (!scx_initialized
)
1059 if (sc
->session_opened
)
1064 sc
->session_opened
= FALSE
;
1066 rv
= pkcs11_functions
->C_CloseSession(sc
->session
);
1068 plog("error in C_CloseSession: %s"
1069 , enum_show(&pkcs11_return_names
, rv
));
1071 DBG(DBG_CONTROL
| DBG_CRYPT
,
1072 DBG_log("pkcs11 session #%ld closed", sc
->session
)
1079 * Load host certificate from smartcard
1082 scx_load_cert(const char *filename
, smartcard_t
**scp
, cert_t
*cert
1085 #ifdef SMARTCARD /* compile with smartcard support */
1086 CK_OBJECT_HANDLE object
;
1088 const char *number_slot_id
= filename
+ strlen(SCX_TOKEN
);
1090 smartcard_t
*sc
= scx_add(scx_parse_number_slot_id(number_slot_id
));
1092 /* return the smartcard object */
1095 /* is there a cached smartcard certificate? */
1096 *cached
= sc
->last_cert
.type
!= CERT_NONE
1097 && (time(NULL
) - sc
->last_load
) < SCX_CERT_CACHE_INTERVAL
;
1101 *cert
= sc
->last_cert
;
1102 plog(" using cached cert from smartcard #%d (%s, id: %s, label: '%s')"
1104 , scx_print_slot(sc
, "")
1110 if (!scx_establish_context(sc
))
1112 scx_release_context(sc
);
1116 /* find the certificate object */
1117 if (!scx_pkcs11_find_object(sc
->session
, &object
, CKO_CERTIFICATE
, sc
->id
))
1119 scx_release_context(sc
);
1123 /* retrieve the certificate object */
1124 if (!scx_find_cert_object(sc
->session
, object
, sc
, cert
))
1126 scx_release_context(sc
);
1130 if (!pkcs11_keep_state
)
1131 scx_release_context(sc
);
1133 plog(" loaded cert from smartcard #%d (%s, id: %s, label: '%s')"
1135 , scx_print_slot(sc
, "")
1141 plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!");
1147 * parse slot number and key id
1148 * the following syntax is allowed
1151 * %smartcard#2 2 - -
1153 * %smartcard:45 - - 45
1154 * %smartcard0:45 - 0 45
1157 scx_parse_number_slot_id(const char *number_slot_id
)
1159 int len
= strlen(number_slot_id
);
1160 smartcard_t
*sc
= alloc_thing(smartcard_t
, "smartcard");
1162 /* assign default values */
1165 if (len
== 0) /* default: use certificate #1 */
1169 else if (*number_slot_id
== '#') /* #number scheme */
1174 ugh
= atoul(number_slot_id
+1, len
-1 , 10, &ul
);
1176 sc
->number
= (int)ul
;
1178 plog("error parsing smartcard number: %s", ugh
);
1180 else /* slot:id scheme */
1183 char *p
= strchr(number_slot_id
, ':');
1187 int id_len
= len
- (p
+ 1 - number_slot_id
);
1188 slot_len
-= (1 + id_len
);
1190 if (id_len
> 0) /* we have an id */
1193 if (slot_len
> 0) /* we have a slot */
1198 ugh
= atoul(number_slot_id
, slot_len
, 10, &ul
);
1202 sc
->any_slot
= FALSE
;
1205 plog("error parsing smartcard slot number: %s", ugh
);
1208 /* unshare the id string */
1209 sc
->id
= clone_str(sc
->id
, "key id");
1214 * Verify pin on card
1217 scx_verify_pin(smartcard_t
*sc
)
1225 if (sc
->pin
.ptr
== NULL
)
1227 plog("unable to verify without PIN");
1231 /* establish context */
1232 if (!scx_establish_context(sc
))
1234 scx_release_context(sc
);
1238 rv
= pkcs11_functions
->C_Login(sc
->session
, CKU_USER
,
1239 (CK_UTF8CHAR
*) sc
->pin
.ptr
, sc
->pin
.len
);
1240 if (rv
== CKR_OK
|| rv
== CKR_USER_ALREADY_LOGGED_IN
)
1243 sc
->logged_in
= TRUE
;
1244 DBG(DBG_CONTROL
| DBG_CRYPT
,
1245 DBG_log((rv
== CKR_OK
)
1246 ?
"PIN code correct"
1247 : "already logged in, no PIN entry required");
1248 DBG_log("pkcs11 session #%ld login successful", sc
->session
)
1253 DBG(DBG_CONTROL
| DBG_CRYPT
,
1254 DBG_log("PIN code incorrect")
1257 if (!pkcs11_keep_state
)
1258 scx_release_context(sc
);
1266 * Sign hash on smartcard
1269 scx_sign_hash(smartcard_t
*sc
, const u_char
*in
, size_t inlen
1270 , u_char
*out
, size_t outlen
)
1274 CK_OBJECT_HANDLE object
;
1275 CK_ULONG siglen
= (CK_ULONG
)outlen
;
1276 CK_BBOOL sign_flag
, decrypt_flag
;
1277 CK_ATTRIBUTE attr
[] = {
1278 { CKA_SIGN
, &sign_flag
, sizeof(sign_flag
) },
1279 { CKA_DECRYPT
, &decrypt_flag
, sizeof(decrypt_flag
) }
1285 if (!scx_pkcs11_find_object(sc
->session
, &object
, CKO_PRIVATE_KEY
, sc
->id
))
1287 plog("unable to find private key with id '%s'", sc
->id
);
1291 rv
= pkcs11_functions
->C_GetAttributeValue(sc
->session
, object
, attr
, 2);
1294 plog("couldn't read the private key attributes: %s"
1295 , enum_show(&pkcs11_return_names
, rv
));
1299 DBG_log("RSA key flags: sign = %s, decrypt = %s"
1300 , (sign_flag
)?
"true":"false"
1301 , (decrypt_flag
)?
"true":"false")
1306 CK_MECHANISM mech
= { CKM_RSA_PKCS
, NULL_PTR
, 0 };
1308 rv
= pkcs11_functions
->C_SignInit(sc
->session
, &mech
, object
);
1311 plog("error in C_SignInit: %s"
1312 , enum_show(&pkcs11_return_names
, rv
));
1316 rv
= pkcs11_functions
->C_Sign(sc
->session
, (CK_BYTE_PTR
)in
, inlen
1320 plog("error in C_Sign: %s"
1321 , enum_show(&pkcs11_return_names
, rv
));
1325 else if (decrypt_flag
)
1327 CK_MECHANISM mech
= { CKM_RSA_X_509
, NULL_PTR
, 0 };
1331 /* PKCS#1 v1.5 8.1 encryption-block formatting */
1333 *p
++ = 0x01; /* BT (block type) 01 */
1334 padlen
= outlen
- 3 - inlen
;
1335 memset(p
, 0xFF, padlen
);
1338 memcpy(p
, in
, inlen
);
1340 rv
= pkcs11_functions
->C_DecryptInit(sc
->session
, &mech
, object
);
1343 plog("error in C_DecryptInit: %s"
1344 , enum_show(&pkcs11_return_names
, rv
));
1348 rv
= pkcs11_functions
->C_Decrypt(sc
->session
, out
, outlen
1352 plog("error in C_Decrypt: %s"
1353 , enum_show(&pkcs11_return_names
, rv
));
1359 plog("private key has neither sign nor decrypt flag set");
1363 if (siglen
> (CK_ULONG
)outlen
)
1365 plog("signature length (%lu) larger than allocated buffer (%d)"
1366 , siglen
, (int)outlen
);
1376 * encrypt data block with an RSA public key
1379 scx_encrypt(smartcard_t
*sc
, const u_char
*in
, size_t inlen
1380 , u_char
*out
, size_t *outlen
)
1384 CK_OBJECT_HANDLE object
;
1385 CK_ULONG len
= (CK_ULONG
)(*outlen
);
1386 CK_BBOOL encrypt_flag
;
1387 CK_ATTRIBUTE attr
[] = {
1388 { CKA_MODULUS
, NULL_PTR
, 0L },
1389 { CKA_PUBLIC_EXPONENT
, NULL_PTR
, 0L },
1390 { CKA_ENCRYPT
, &encrypt_flag
, sizeof(encrypt_flag
) }
1392 CK_MECHANISM mech
= { CKM_RSA_PKCS
, NULL_PTR
, 0 };
1394 if (!scx_establish_context(sc
))
1396 scx_release_context(sc
);
1400 if (!scx_pkcs11_find_object(sc
->session
, &object
, CKO_PUBLIC_KEY
, sc
->id
))
1402 plog("unable to find public key with id '%s'", sc
->id
);
1406 rv
= pkcs11_functions
->C_GetAttributeValue(sc
->session
, object
, attr
, 3);
1409 plog("couldn't read the public key attributes: %s"
1410 , enum_show(&pkcs11_return_names
, rv
));
1411 scx_release_context(sc
);
1417 plog("public key cannot be used for encryption");
1418 scx_release_context(sc
);
1422 /* there must be enough space left for the PKCS#1 v1.5 padding */
1423 if (inlen
> attr
[0].ulValueLen
- 11)
1425 plog("smartcard input data length (%d) exceeds maximum of %lu bytes"
1426 , (int)inlen
, attr
[0].ulValueLen
- 11);
1427 if (!pkcs11_keep_state
)
1428 scx_release_context(sc
);
1432 rv
= pkcs11_functions
->C_EncryptInit(sc
->session
, &mech
, object
);
1436 if (rv
== CKR_FUNCTION_NOT_SUPPORTED
)
1438 RSA_public_key_t rsa
;
1439 chunk_t plain_text
= {in
, inlen
};
1440 chunk_t cipher_text
;
1443 DBG_log("doing RSA encryption in software")
1445 attr
[0].pValue
= alloc_bytes(attr
[0].ulValueLen
, "modulus");
1446 attr
[1].pValue
= alloc_bytes(attr
[1].ulValueLen
, "exponent");
1448 rv
= pkcs11_functions
->C_GetAttributeValue(sc
->session
, object
, attr
, 2);
1451 plog("couldn't read modulus and public exponent: %s"
1452 , enum_show(&pkcs11_return_names
, rv
));
1453 pfree(attr
[0].pValue
);
1454 pfree(attr
[1].pValue
);
1455 scx_release_context(sc
);
1458 rsa
.k
= attr
[0].ulValueLen
;
1459 n_to_mpz(&rsa
.n
, attr
[0].pValue
, attr
[0].ulValueLen
);
1460 n_to_mpz(&rsa
.e
, attr
[1].pValue
, attr
[1].ulValueLen
);
1461 pfree(attr
[0].pValue
);
1462 pfree(attr
[1].pValue
);
1464 cipher_text
= RSA_encrypt(&rsa
, plain_text
);
1465 free_RSA_public_content(&rsa
);
1466 if (cipher_text
.ptr
== NULL
)
1468 plog("smartcard input data length is too large");
1469 if (!pkcs11_keep_state
)
1470 scx_release_context(sc
);
1474 memcpy(out
, cipher_text
.ptr
, cipher_text
.len
);
1475 *outlen
= cipher_text
.len
;
1476 freeanychunk(cipher_text
);
1477 if (!pkcs11_keep_state
)
1478 scx_release_context(sc
);
1483 plog("error in C_EncryptInit: %s"
1484 , enum_show(&pkcs11_return_names
, rv
));
1485 scx_release_context(sc
);
1491 DBG_log("doing RSA encryption on smartcard")
1493 rv
= pkcs11_functions
->C_Encrypt(sc
->session
, in
, inlen
1497 plog("error in C_Encrypt: %s"
1498 , enum_show(&pkcs11_return_names
, rv
));
1499 scx_release_context(sc
);
1502 if (!pkcs11_keep_state
)
1503 scx_release_context(sc
);
1505 *outlen
= (size_t)len
;
1512 * decrypt a data block with an RSA private key
1515 scx_decrypt(smartcard_t
*sc
, const u_char
*in
, size_t inlen
1516 , u_char
*out
, size_t *outlen
)
1520 CK_OBJECT_HANDLE object
;
1521 CK_ULONG len
= (CK_ULONG
)(*outlen
);
1522 CK_BBOOL decrypt_flag
;
1523 CK_ATTRIBUTE attr
[] = {
1524 { CKA_DECRYPT
, &decrypt_flag
, sizeof(decrypt_flag
) }
1526 CK_MECHANISM mech
= { CKM_RSA_PKCS
, NULL_PTR
, 0 };
1528 if (!scx_establish_context(sc
) || !scx_login(sc
))
1530 scx_release_context(sc
);
1534 if (!scx_pkcs11_find_object(sc
->session
, &object
, CKO_PRIVATE_KEY
, sc
->id
))
1536 plog("unable to find private key with id '%s'", sc
->id
);
1540 rv
= pkcs11_functions
->C_GetAttributeValue(sc
->session
, object
, attr
, 1);
1543 plog("couldn't read the private key attributes: %s"
1544 , enum_show(&pkcs11_return_names
, rv
));
1550 plog("private key cannot be used for decryption");
1551 scx_release_context(sc
);
1556 DBG_log("doing RSA decryption on smartcard")
1558 rv
= pkcs11_functions
->C_DecryptInit(sc
->session
, &mech
, object
);
1561 plog("error in C_DecryptInit: %s"
1562 , enum_show(&pkcs11_return_names
, rv
));
1563 scx_release_context(sc
);
1567 rv
= pkcs11_functions
->C_Decrypt(sc
->session
, in
, inlen
1571 plog("error in C_Decrypt: %s"
1572 , enum_show(&pkcs11_return_names
, rv
));
1573 scx_release_context(sc
);
1576 if (!pkcs11_keep_state
)
1577 scx_release_context(sc
);
1579 *outlen
= (size_t)len
;
1586 /* receive an encrypted data block via whack,
1587 * decrypt it using a private RSA key and
1588 * return the decrypted data block via whack
1591 scx_op_via_whack(const char* msg
, int inbase
, int outbase
, sc_op_t op
1592 , const char* keyid
, int whackfd
)
1594 char inbuf
[RSA_MAX_OCTETS
];
1595 char outbuf
[2*RSA_MAX_OCTETS
+ 1];
1596 size_t outlen
= sizeof(inbuf
);
1598 smartcard_t
*sc
,*sc_new
;
1600 const char *number_slot_id
= "";
1602 err_t ugh
= ttodata(msg
, 0, inbase
, inbuf
, sizeof(inbuf
), &inlen
);
1604 /* no prefix - use default base */
1605 if (ugh
!= NULL
&& inbase
== 0)
1606 ugh
= ttodata(msg
, 0, DEFAULT_BASE
, inbuf
, sizeof(inbuf
), &inlen
);
1610 plog("format error in smartcard input data: %s", ugh
);
1616 number_slot_id
= (strncmp(keyid
, SCX_TOKEN
, strlen(SCX_TOKEN
)) == 0)
1617 ? keyid
+ strlen(SCX_TOKEN
) : keyid
;
1620 sc_new
= scx_parse_number_slot_id(number_slot_id
);
1621 sc
= scx_add(sc_new
);
1625 DBG((op
== SC_OP_ENCRYPT
)? DBG_PRIVATE
:DBG_RAW
,
1626 DBG_dump("smartcard input data:\n", inbuf
, inlen
)
1629 if (op
== SC_OP_DECRYPT
)
1631 if (!sc
->valid
&& whackfd
!= NULL_FD
)
1632 scx_get_pin(sc
, whackfd
);
1636 loglog(RC_NOVALIDPIN
, "cannot decrypt without valid PIN");
1641 DBG(DBG_CONTROL
| DBG_CRYPT
,
1642 DBG_log("using RSA key from smartcard (slot: %d, id: %s)"
1643 , (int)sc
->slot
, sc
->id
)
1649 if (!scx_encrypt(sc
, inbuf
, inlen
, inbuf
, &outlen
))
1653 if (!scx_decrypt(sc
, inbuf
, inlen
, inbuf
, &outlen
))
1660 DBG((op
== SC_OP_DECRYPT
)? DBG_PRIVATE
:DBG_RAW
,
1661 DBG_dump("smartcard output data:\n", inbuf
, outlen
)
1664 if (outbase
== 0) /* use default base */
1665 outbase
= DEFAULT_BASE
;
1667 if (outbase
== 256) /* ascii plain text */
1668 whack_log(RC_COMMENT
, "%.*s", (int)outlen
, inbuf
);
1671 outlen
= datatot(inbuf
, outlen
, outbase
, outbuf
, sizeof(outbuf
));
1674 plog("error in output format conversion");
1677 whack_log(RC_COMMENT
, "%s", outbuf
);
1683 * get length of RSA key in bytes
1686 scx_get_keylength(smartcard_t
*sc
)
1690 CK_OBJECT_HANDLE object
;
1691 CK_ATTRIBUTE attr
[] = {{ CKA_MODULUS
, NULL_PTR
, 0}};
1696 if (!scx_pkcs11_find_object(sc
->session
, &object
, CKO_PRIVATE_KEY
, sc
->id
))
1698 plog("unable to find private key with id '%s'", sc
->id
);
1702 /* get the length of the private key */
1703 rv
= pkcs11_functions
->C_GetAttributeValue(sc
->session
, object
1704 , (CK_ATTRIBUTE_PTR
)&attr
, 1);
1707 plog("failed to get key length: %s"
1708 , enum_show(&pkcs11_return_names
, rv
));
1712 return attr
[0].ulValueLen
; /*Return key length in bytes */
1719 * prompt for pin and verify it
1722 scx_get_pin(smartcard_t
*sc
, int whackfd
)
1728 whack_log(RC_ENTERSECRET
, "need PIN for #%d (%s, id: %s, label: '%s')"
1729 , sc
->number
, scx_print_slot(sc
, ""), sc
->id
, sc
->label
);
1731 for (i
= 0; i
< SCX_MAX_PIN_TRIALS
; i
++)
1734 whack_log(RC_ENTERSECRET
, "invalid PIN, please try again");
1736 n
= read(whackfd
, pin
, BUF_LEN
);
1740 whack_log(RC_LOG_SERIOUS
, "read(whackfd) failed");
1744 if (strlen(pin
) == 0)
1746 whack_log(RC_LOG_SERIOUS
, "no PIN entered, aborted");
1751 sc
->pin
.len
= strlen(pin
);
1753 /* verify the pin */
1754 if (scx_verify_pin(sc
))
1756 clonetochunk(sc
->pin
, pin
, strlen(pin
), "pin");
1760 /* wrong pin - we try another round */
1761 sc
->pin
= empty_chunk
;
1765 whack_log(RC_SUCCESS
, "valid PIN");
1767 whack_log(RC_LOG_SERIOUS
, "invalid PIN, too many trials");
1770 whack_log(RC_LOG_SERIOUS
, "SMARTCARD support is deactivated in pluto/Makefile!");
1780 scx_free_pin(chunk_t
*pin
)
1782 if (pin
->ptr
!= NULL
)
1784 /* clear pin field in memory */
1785 memset(pin
->ptr
, '\0', pin
->len
);
1792 * frees a smartcard record
1795 scx_free(smartcard_t
*sc
)
1799 scx_release_context(sc
);
1801 pfreeany(sc
->label
);
1802 scx_free_pin(&sc
->pin
);
1807 /* release of a smartcard record decreases the count by one
1808 " the record is freed when the counter reaches zero
1811 scx_release(smartcard_t
*sc
)
1813 if (sc
!= NULL
&& --sc
->count
== 0)
1815 smartcard_t
**pp
= &smartcards
;
1819 release_cert(sc
->last_cert
);
1825 * compare two smartcard records by comparing their slots and ids
1828 scx_same(smartcard_t
*a
, smartcard_t
*b
)
1830 if (a
->number
&& b
->number
)
1833 return a
->number
== b
->number
;
1837 /* same id and/or same slot */
1838 return (!a
->id
|| (b
->id
&& streq(a
->id
, b
->id
)))
1839 && (a
->any_slot
|| b
->any_slot
|| a
->slot
== b
->slot
);
1843 /* for each link pointing to the smartcard record
1844 " increase the count by one
1847 scx_share(smartcard_t
*sc
)
1854 * adds a smartcard record to the chained list
1857 scx_add(smartcard_t
*smartcard
)
1859 smartcard_t
*sc
= smartcards
;
1860 smartcard_t
**psc
= &smartcards
;
1864 if (scx_same(smartcard
, sc
)) /* already in chain, free smartcard record */
1866 scx_free(smartcard
);
1873 /* insert new smartcard record at the end of the chain */
1875 smartcard
->number
= ++sc_number
;
1876 smartcard
->count
= 1;
1877 DBG(DBG_CONTROL
| DBG_PARSING
,
1878 DBG_log(" smartcard #%d added", sc_number
)
1884 * get the smartcard that belongs to an X.509 certificate
1887 scx_get(x509cert_t
*cert
)
1889 smartcard_t
*sc
= smartcards
;
1893 if (sc
->last_cert
.u
.x509
== cert
)
1901 * prints either the slot number or 'any slot'
1904 scx_print_slot(smartcard_t
*sc
, const char *whitespace
)
1906 char *buf
= temporary_cyclic_buffer();
1909 snprintf(buf
, BUF_LEN
, "any slot");
1911 snprintf(buf
, BUF_LEN
, "slot: %s%lu", whitespace
, sc
->slot
);
1916 * list all smartcard info records in a chained list
1921 smartcard_t
*sc
= smartcards
;
1925 whack_log(RC_COMMENT
, " ");
1926 whack_log(RC_COMMENT
, "List of Smartcard Objects:");
1927 whack_log(RC_COMMENT
, " ");
1932 whack_log(RC_COMMENT
, "%s, #%d, count: %d"
1933 , timetoa(&sc
->last_load
, utc
)
1936 whack_log(RC_COMMENT
, " %s, session %s, logged %s, has %s"
1937 , scx_print_slot(sc
, " ")
1938 , sc
->session_opened?
"opened" : "closed"
1939 , sc
->logged_in?
"in" : "out"
1940 , sc
->pinpad?
"pin pad"
1941 : ((sc
->pin
.ptr
== NULL
)?
"no pin"
1942 : sc
->valid?
"valid pin" : "invalid pin"));
1944 whack_log(RC_COMMENT
, " id: %s", sc
->id
);
1945 if (sc
->label
!= NULL
)
1946 whack_log(RC_COMMENT
, " label: '%s'", sc
->label
);
1947 if (sc
->last_cert
.type
== CERT_X509_SIGNATURE
)
1951 dntoa(buf
, BUF_LEN
, sc
->last_cert
.u
.x509
->subject
);
1952 whack_log(RC_COMMENT
, " subject: '%s'", buf
);