Branch data Line data Source code
1 : : /*
2 : : * This is the actual card emulator.
3 : : *
4 : : * These functions can be implemented in different ways on different platforms
5 : : * using the underlying system primitives. For Linux it uses NSS, though direct
6 : : * to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be
7 : : * used. On Windows CAPI could be used.
8 : : *
9 : : * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10 : : * See the COPYING file in the top-level directory.
11 : : */
12 : : #include "config.h"
13 : :
14 : : #include <glib.h>
15 : :
16 : : #include "common.h"
17 : :
18 : : /*
19 : : * NSS headers
20 : : */
21 : :
22 : : /* avoid including prototypes.h that redefines uint32 */
23 : : #define NO_NSPR_10_SUPPORT
24 : :
25 : : #include <nss.h>
26 : : #include <pk11pub.h>
27 : : #include <cert.h>
28 : : #include <keyhi.h>
29 : : #include <secmod.h>
30 : : #include <prthread.h>
31 : : #include <secerr.h>
32 : : #include <secoid.h>
33 : : #include <secmodt.h>
34 : : #include <sechash.h>
35 : :
36 : : #include "vcard.h"
37 : : #include "card_7816t.h"
38 : : #include "vcard_emul.h"
39 : : #include "vreader.h"
40 : : #include "vevent.h"
41 : :
42 : : #include "vcardt_internal.h"
43 : : #if defined(ENABLE_PCSC)
44 : : #include "capcsc.h"
45 : : #endif
46 : :
47 : :
48 : : typedef enum {
49 : : VCardEmulUnknown = -1,
50 : : VCardEmulFalse = 0,
51 : : VCardEmulTrue = 1
52 : : } VCardEmulTriState;
53 : :
54 : : struct VCardKeyStruct {
55 : : CERTCertificate *cert;
56 : : PK11SlotInfo *slot;
57 : : VCardEmulTriState failedX509;
58 : : };
59 : :
60 : :
61 : : typedef struct VirtualReaderOptionsStruct VirtualReaderOptions;
62 : :
63 : : struct VReaderEmulStruct {
64 : : PK11SlotInfo *slot;
65 : : VCardEmulType default_type;
66 : : char *type_params;
67 : : PRBool present;
68 : : int series;
69 : : VCard *saved_vcard;
70 : : };
71 : :
72 : : /*
73 : : * NSS Specific options
74 : : */
75 : : struct VirtualReaderOptionsStruct {
76 : : char *name;
77 : : char *vname;
78 : : VCardEmulType card_type;
79 : : char *type_params;
80 : : char **cert_name;
81 : : int cert_count;
82 : : };
83 : :
84 : : enum {
85 : : USE_HW_NO,
86 : : USE_HW_YES,
87 : : USE_HW_REMOVABLE,
88 : : };
89 : :
90 : : struct VCardEmulOptionsStruct {
91 : : char *nss_db;
92 : : VirtualReaderOptions *vreader;
93 : : int vreader_count;
94 : : VCardEmulType hw_card_type;
95 : : char *hw_type_params;
96 : : int use_hw;
97 : : };
98 : :
99 : : static int nss_emul_init;
100 : :
101 : : /* if we have more that just the slot, define
102 : : * VCardEmulStruct here */
103 : :
104 : : /*
105 : : * allocate the set of arrays for certs, cert_len, key
106 : : */
107 : : static void
108 : 5 : vcard_emul_alloc_arrays(unsigned char ***certsp, int **cert_lenp,
109 : : VCardKey ***keysp, int cert_count)
110 : : {
111 [ - + - - ]: 5 : *certsp = g_new(unsigned char *, cert_count);
112 [ - + - - ]: 5 : *cert_lenp = g_new(int, cert_count);
113 [ - + - - ]: 5 : *keysp = g_new(VCardKey *, cert_count);
114 : 5 : }
115 : :
116 : : /*
117 : : * Emulator specific card information
118 : : */
119 : : typedef struct CardEmulCardStruct CardEmulPrivate;
120 : :
121 : : static VCardEmul *
122 : : vcard_emul_new_card(PK11SlotInfo *slot)
123 : : {
124 : 5 : PK11_ReferenceSlot(slot);
125 : : /* currently we don't need anything other than the slot */
126 : : return (VCardEmul *)slot;
127 : : }
128 : :
129 : : static void
130 : 4 : vcard_emul_delete_card(VCardEmul *vcard_emul)
131 : : {
132 : : PK11SlotInfo *slot = (PK11SlotInfo *)vcard_emul;
133 [ + - ]: 4 : if (slot == NULL) {
134 : : return;
135 : : }
136 : 4 : PK11_FreeSlot(slot);
137 : : }
138 : :
139 : : static PK11SlotInfo *
140 : : vcard_emul_card_get_slot(VCard *card)
141 : : {
142 : : /* note, the card is holding the reference, no need to get another one */
143 : 99 : return (PK11SlotInfo *)vcard_get_private(card);
144 : : }
145 : :
146 : :
147 : : /*
148 : : * key functions
149 : : */
150 : : /* private constructure */
151 : : static VCardKey *
152 : 11 : vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert)
153 : : {
154 : : VCardKey *key;
155 : :
156 : 11 : key = g_new(VCardKey, 1);
157 : 11 : key->slot = PK11_ReferenceSlot(slot);
158 : 11 : key->cert = CERT_DupCertificate(cert);
159 : 11 : key->failedX509 = VCardEmulUnknown;
160 : 11 : return key;
161 : : }
162 : :
163 : : /* destructor */
164 : : void
165 : 8 : vcard_emul_delete_key(VCardKey *key)
166 : : {
167 [ + - + - ]: 8 : if (!nss_emul_init || (key == NULL)) {
168 : : return;
169 : : }
170 [ + - ]: 8 : if (key->cert) {
171 : 8 : CERT_DestroyCertificate(key->cert);
172 : : }
173 [ + - ]: 8 : if (key->slot) {
174 : 8 : PK11_FreeSlot(key->slot);
175 : : }
176 : 8 : g_free(key);
177 : : }
178 : :
179 : : /*
180 : : * grab the nss key from a VCardKey. If it doesn't exist, try to look it up
181 : : */
182 : : static SECKEYPrivateKey *
183 : : vcard_emul_get_nss_key(VCardKey *key)
184 : : {
185 : : /* NOTE: if we aren't logged into the token, this could return NULL */
186 : 19 : return PK11_FindPrivateKeyFromCert(key->slot, key->cert, NULL);
187 : : }
188 : :
189 : : /*
190 : : * Map NSS errors to 7816 errors
191 : : */
192 : : static vcard_7816_status_t
193 : 1 : vcard_emul_map_error(int error)
194 : : {
195 [ + - - - ]: 1 : switch (error) {
196 : : case SEC_ERROR_TOKEN_NOT_LOGGED_IN:
197 : : return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
198 : 1 : case SEC_ERROR_BAD_DATA:
199 : : case SEC_ERROR_OUTPUT_LEN:
200 : : case SEC_ERROR_INPUT_LEN:
201 : : case SEC_ERROR_INVALID_ARGS:
202 : : case SEC_ERROR_INVALID_ALGORITHM:
203 : : case SEC_ERROR_NO_KEY:
204 : : case SEC_ERROR_INVALID_KEY:
205 : : case SEC_ERROR_DECRYPTION_DISALLOWED:
206 : : case SEC_ERROR_PKCS11_GENERAL_ERROR:
207 : 1 : return VCARD7816_STATUS_ERROR_DATA_INVALID;
208 : 0 : case SEC_ERROR_NO_MEMORY:
209 : 0 : return VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE;
210 : 0 : default:
211 : 0 : g_debug("error %x", 0x2000 + error);
212 : 0 : g_warn_if_reached();
213 : : }
214 : 0 : return VCARD7816_STATUS_EXC_ERROR_CHANGE;
215 : : }
216 : :
217 : : /* get RSA bits */
218 : : int
219 : 11 : vcard_emul_rsa_bits(VCardKey *key)
220 : : {
221 : : SECKEYPublicKey *pub_key;
222 : : int bits = -1;
223 : :
224 [ - + ]: 11 : if (key == NULL) {
225 : : /* couldn't get the key, indicate that we aren't logged in */
226 : : return -1;
227 : : }
228 : 11 : pub_key = CERT_ExtractPublicKey(key->cert);
229 [ - + ]: 11 : if (pub_key == NULL) {
230 : : /* couldn't get the key, indicate that we aren't logged in */
231 : : return -1;
232 : : }
233 : :
234 : 11 : bits = SECKEY_PublicKeyStrengthInBits(pub_key);
235 : 11 : SECKEY_DestroyPublicKey(pub_key);
236 : 11 : return bits;
237 : : }
238 : :
239 : : /* RSA sign/decrypt with the key, signature happens 'in place' */
240 : : vcard_7816_status_t
241 : 19 : vcard_emul_rsa_op(VCard *card, VCardKey *key,
242 : : unsigned char *buffer, int buffer_size)
243 : : {
244 : : SECKEYPrivateKey *priv_key;
245 : : unsigned signature_len;
246 : : PK11SlotInfo *slot;
247 : : SECStatus rv;
248 : : unsigned char buf[2048];
249 : : unsigned char *bp = NULL;
250 : : int pad_len;
251 : : vcard_7816_status_t ret = VCARD7816_STATUS_SUCCESS;
252 : :
253 [ - + ]: 19 : assert(buffer_size >= 0);
254 [ + - - + ]: 19 : if ((!nss_emul_init) || (key == NULL)) {
255 : : /* couldn't get the key, indicate that we aren't logged in */
256 : : return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
257 : : }
258 : : priv_key = vcard_emul_get_nss_key(key);
259 [ - + ]: 19 : if (priv_key == NULL) {
260 : : /* couldn't get the key, indicate that we aren't logged in */
261 : : return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
262 : : }
263 : : slot = vcard_emul_card_get_slot(card);
264 : :
265 : : /*
266 : : * this is only true of the rsa signature
267 : : */
268 : 19 : signature_len = PK11_SignatureLen(priv_key);
269 [ - + ]: 19 : if ((unsigned)buffer_size != signature_len) {
270 : : ret = VCARD7816_STATUS_ERROR_DATA_INVALID;
271 : 0 : goto cleanup;
272 : : }
273 : : /* be able to handle larger keys if necessary */
274 : : bp = &buf[0];
275 [ - + ]: 19 : if (sizeof(buf) < signature_len) {
276 : 0 : bp = g_malloc(signature_len);
277 : : }
278 : :
279 : : /*
280 : : * do the raw operations. Some tokens claim to do CKM_RSA_X_509, but then
281 : : * choke when they try to do the actual operations. Try to detect
282 : : * those cases and treat them as if the token didn't claim support for
283 : : * X_509.
284 : : */
285 [ + + ]: 19 : if (key->failedX509 != VCardEmulTrue
286 [ + + ]: 12 : && PK11_DoesMechanism(slot, CKM_RSA_X_509)) {
287 : 11 : rv = PK11_PrivDecryptRaw(priv_key, bp, &signature_len, signature_len,
288 : : buffer, buffer_size);
289 [ + - ]: 11 : if (rv == SECSuccess) {
290 [ - + ]: 11 : assert((unsigned)buffer_size == signature_len);
291 : 11 : memcpy(buffer, bp, signature_len);
292 : 11 : key->failedX509 = VCardEmulFalse;
293 : 11 : goto cleanup;
294 : : }
295 : : /*
296 : : * we've had a successful X509 operation, this failure must be
297 : : * something else
298 : : */
299 [ # # ]: 0 : if (key->failedX509 == VCardEmulFalse) {
300 : 0 : ret = vcard_emul_map_error(PORT_GetError());
301 : 0 : goto cleanup;
302 : : }
303 : : /*
304 : : * key->failedX509 must be Unknown at this point, try the
305 : : * non-x_509 case
306 : : */
307 : : }
308 : : /* token does not support CKM_RSA_X509, emulate that with CKM_RSA_PKCS */
309 : : /* is this a PKCS #1 formatted signature? */
310 [ + + + + ]: 8 : if ((buffer[0] == 0) && (buffer[1] == 1)) {
311 : : int i;
312 : :
313 [ + - ]: 576 : for (i = 2; i < buffer_size; i++) {
314 : : /* rsa signature pad */
315 [ + + ]: 576 : if (buffer[i] != 0xff) {
316 : : break;
317 : : }
318 : : }
319 [ + - + - ]: 6 : if ((i < buffer_size) && (buffer[i] == 0)) {
320 : : /* yes, we have a properly formatted PKCS #1 signature */
321 : : /*
322 : : * NOTE: even if we accidentally got an encrypt buffer, which
323 : : * through sheer luck started with 00, 01, ff, 00, it won't matter
324 : : * because the resulting Sign operation will effectively decrypt
325 : : * the real buffer.
326 : : */
327 : : SECItem signature;
328 : : SECItem hash;
329 : :
330 : 6 : i++;
331 : 6 : hash.data = &buffer[i];
332 : 6 : hash.len = buffer_size - i;
333 : 6 : signature.data = bp;
334 : 6 : signature.len = signature_len;
335 : 6 : rv = PK11_Sign(priv_key, &signature, &hash);
336 [ - + ]: 6 : if (rv != SECSuccess) {
337 : 0 : ret = vcard_emul_map_error(PORT_GetError());
338 : 0 : goto cleanup;
339 : : }
340 [ - + ]: 6 : assert((unsigned)buffer_size == signature.len);
341 : 6 : memcpy(buffer, bp, signature.len);
342 : : /*
343 : : * we got here because either the X509 attempt failed, or the
344 : : * token couldn't do the X509 operation, in either case stay
345 : : * with the PKCS version for future operations on this key
346 : : */
347 : 6 : key->failedX509 = VCardEmulTrue;
348 : 6 : goto cleanup;
349 : : }
350 : : }
351 : : /* We can not do raw RSA operation and the bytes do not look like PKCS#1.5
352 : : * Assuming it is deciphering operation.
353 : : */
354 : 2 : rv = PK11_PrivDecryptPKCS1(priv_key, bp, &signature_len, buffer_size, buffer, buffer_size);
355 [ + + ]: 2 : if (rv != SECSuccess) {
356 : : /* The assumption was wrong. Give up */
357 : 1 : ret = vcard_emul_map_error(PORT_GetError());
358 : 1 : goto cleanup;
359 : : }
360 : 1 : pad_len = buffer_size - signature_len;
361 [ - + ]: 1 : if (pad_len < 4) {
362 : : ret = VCARD7816_STATUS_ERROR_GENERAL;
363 : 0 : goto cleanup;
364 : : }
365 : : /*
366 : : * OK now we've decrypted the payload, package it up in PKCS #1 for the
367 : : * upper layer.
368 : : */
369 : 1 : buffer[0] = 0;
370 : 1 : buffer[1] = 2; /* RSA_encrypt */
371 : 1 : pad_len -= 3; /* format is 0 || 2 || pad || 0 || data */
372 : : /*
373 : : * padding for PKCS #1 encrypted data is a string of random bytes. The
374 : : * random bytes protect against potential decryption attacks against RSA.
375 : : * Since PrivDecrypt has already stripped those bytes, we can't reconstruct
376 : : * them. This shouldn't matter to the upper level code which should just
377 : : * strip this code out anyway, so We'll pad with a constant 3.
378 : : */
379 : 1 : memset(&buffer[2], 0x03, pad_len);
380 : 1 : pad_len += 2; /* index to the end of the pad */
381 : 1 : buffer[pad_len] = 0;
382 : : pad_len++; /* index to the start of the data */
383 : 1 : memcpy(&buffer[pad_len], bp, signature_len);
384 : : /*
385 : : * we got here because either the X509 attempt failed, or the
386 : : * token couldn't do the X509 operation, in either case stay
387 : : * with the PKCS version for future operations on this key
388 : : */
389 : 1 : key->failedX509 = VCardEmulTrue;
390 : 19 : cleanup:
391 [ - + ]: 19 : if (bp != buf) {
392 : 0 : g_free(bp);
393 : : }
394 : 19 : SECKEY_DestroyPrivateKey(priv_key);
395 : 19 : return ret;
396 : : }
397 : :
398 : : /*
399 : : * Login functions
400 : : */
401 : : /* return the number of login attempts still possible on the card. if unknown,
402 : : * return -1 */
403 : : int
404 : 4 : vcard_emul_get_login_count(G_GNUC_UNUSED VCard *card)
405 : : {
406 : 4 : return -1;
407 : : }
408 : :
409 : : /* login into the card, return the 7816 status word (sw2 || sw1) */
410 : : vcard_7816_status_t
411 : 20 : vcard_emul_login(VCard *card, unsigned char *pin, int pin_len)
412 : : {
413 : : PK11SlotInfo *slot;
414 : : unsigned char *pin_string;
415 : : int i;
416 : : SECStatus rv;
417 : :
418 [ - + ]: 20 : if (!nss_emul_init) {
419 : : return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
420 : : }
421 : : slot = vcard_emul_card_get_slot(card);
422 : : /* We depend on the PKCS #11 module internal login state here because we
423 : : * create a separate process to handle each guest instance. If we needed
424 : : * to handle multiple guests from one process, then we would need to keep
425 : : * a lot of extra state in our card structure
426 : : * */
427 : 20 : pin_string = g_malloc(pin_len+1);
428 : 20 : memcpy(pin_string, pin, pin_len);
429 : 20 : pin_string[pin_len] = 0;
430 : :
431 : : /* handle CAC expanded pins correctly */
432 [ + + + + ]: 44 : for (i = pin_len-1; i >= 0 && (pin_string[i] == 0xff); i--) {
433 : 24 : pin_string[i] = 0;
434 : : }
435 : :
436 : : /* If using an emulated card, make sure to log out of any already logged in
437 : : * session. */
438 : 20 : vcard_emul_logout(card);
439 : :
440 : 20 : rv = PK11_Authenticate(slot, PR_FALSE, pin_string);
441 : 20 : memset(pin_string, 0, pin_len); /* don't let the pin hang around in memory
442 : : to be snooped */
443 : 20 : g_free(pin_string);
444 [ - + ]: 20 : if (rv == SECSuccess) {
445 : : return VCARD7816_STATUS_SUCCESS;
446 : : }
447 : : /* map the error from port get error */
448 : : return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
449 : : }
450 : :
451 : : int
452 : 26 : vcard_emul_is_logged_in(VCard *card)
453 : : {
454 : : PK11SlotInfo *slot;
455 : :
456 [ + - ]: 26 : if (!nss_emul_init) {
457 : : return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
458 : : }
459 : :
460 : : slot = vcard_emul_card_get_slot(card);
461 : : /* We depend on the PKCS #11 module internal login state here because we
462 : : * create a separate process to handle each guest instance. If we needed
463 : : * to handle multiple guests from one process, then we would need to keep
464 : : * a lot of extra state in our card structure
465 : : */
466 : :
467 : : /* If we do not need log in, we present the token as "logged in" */
468 [ + + ]: 26 : if (PK11_NeedLogin(slot) == PR_FALSE) {
469 : : return 1;
470 : : }
471 : :
472 : : /* For the tokens that require login, delegate to NSS to figure out the
473 : : * login status */
474 : 20 : return !!PK11_IsLoggedIn(slot, NULL);
475 : : }
476 : :
477 : : void
478 : 34 : vcard_emul_logout(VCard *card)
479 : : {
480 : : PK11SlotInfo *slot;
481 : :
482 [ + - ]: 34 : if (!nss_emul_init) {
483 : : return;
484 : : }
485 : :
486 : : slot = vcard_emul_card_get_slot(card);
487 [ + + ]: 34 : if (PK11_IsLoggedIn(slot, NULL)) {
488 : 14 : PK11_Logout(slot); /* NOTE: ignoring SECStatus return value */
489 : : }
490 : : }
491 : :
492 : : void
493 : 14 : vcard_emul_reset(VCard *card, G_GNUC_UNUSED VCardPower power)
494 : : {
495 : : /*
496 : : * if we reset the card (either power on or power off), we lose our login
497 : : * state
498 : : */
499 : 14 : vcard_emul_logout(card);
500 : :
501 : : /* TODO: we may also need to send insertion/removal events? */
502 : 14 : }
503 : :
504 : : static VReader *
505 : 4 : vcard_emul_find_vreader_from_slot(PK11SlotInfo *slot)
506 : : {
507 : 4 : VReaderList *reader_list = vreader_get_reader_list();
508 : : VReaderListEntry *current_entry;
509 : :
510 [ - + ]: 4 : if (reader_list == NULL) {
511 : : return NULL;
512 : : }
513 [ + - ]: 6 : for (current_entry = vreader_list_get_first(reader_list); current_entry;
514 : 2 : current_entry = vreader_list_get_next(current_entry)) {
515 : 6 : VReader *reader = vreader_list_get_reader(current_entry);
516 : 6 : VReaderEmul *reader_emul = vreader_get_private(reader);
517 [ + + ]: 6 : if (reader_emul->slot == slot) {
518 : 4 : vreader_list_delete(reader_list);
519 : 4 : return reader;
520 : : }
521 : 2 : vreader_free(reader);
522 : : }
523 : :
524 : 0 : vreader_list_delete(reader_list);
525 : 0 : return NULL;
526 : : }
527 : :
528 : : /*
529 : : * create a new reader emul
530 : : */
531 : : static VReaderEmul *
532 : 7 : vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params)
533 : : {
534 : : VReaderEmul *new_reader_emul;
535 : :
536 : 7 : new_reader_emul = g_new(VReaderEmul, 1);
537 : :
538 : 7 : new_reader_emul->slot = PK11_ReferenceSlot(slot);
539 : 7 : new_reader_emul->default_type = type;
540 : 7 : new_reader_emul->type_params = g_strdup(params);
541 : 7 : new_reader_emul->present = PR_FALSE;
542 : 7 : new_reader_emul->series = 0;
543 : 7 : new_reader_emul->saved_vcard = NULL;
544 : 7 : return new_reader_emul;
545 : : }
546 : :
547 : : static void
548 : 4 : vreader_emul_delete(VReaderEmul *vreader_emul)
549 : : {
550 [ + - ]: 4 : if (vreader_emul == NULL) {
551 : : return;
552 : : }
553 : 4 : vcard_free(vreader_emul->saved_vcard);
554 [ + - ]: 4 : if (vreader_emul->slot) {
555 : 4 : PK11_FreeSlot(vreader_emul->slot);
556 : : }
557 : 4 : g_free(vreader_emul->type_params);
558 : 4 : g_free(vreader_emul);
559 : : }
560 : :
561 : : /*
562 : : * TODO: move this to emulater non-specific file
563 : : */
564 : : static VCardEmulType
565 : 5 : vcard_emul_get_type(VReader *vreader)
566 : : {
567 : : VReaderEmul *vreader_emul;
568 : :
569 : 5 : vreader_emul = vreader_get_private(vreader);
570 [ + - - + ]: 5 : if (vreader_emul && vreader_emul->default_type != VCARD_EMUL_NONE) {
571 : : return vreader_emul->default_type;
572 : : }
573 : :
574 : 0 : return vcard_emul_type_select(vreader);
575 : : }
576 : : /*
577 : : * TODO: move this to emulater non-specific file
578 : : */
579 : : static const char *
580 : : vcard_emul_get_type_params(VReader *vreader)
581 : : {
582 : : VReaderEmul *vreader_emul;
583 : :
584 : 5 : vreader_emul = vreader_get_private(vreader);
585 [ - + + + ]: 5 : if (vreader_emul && vreader_emul->type_params) {
586 : : return vreader_emul->type_params;
587 : : }
588 : :
589 : : return "";
590 : : }
591 : :
592 : : /* pull the slot out of the reader private data */
593 : : static PK11SlotInfo *
594 : : vcard_emul_reader_get_slot(VReader *vreader)
595 : : {
596 : 9 : VReaderEmul *vreader_emul = vreader_get_private(vreader);
597 [ + - - + ]: 9 : if (vreader_emul == NULL) {
598 : : return NULL;
599 : : }
600 : 9 : return vreader_emul->slot;
601 : : }
602 : :
603 : : /*
604 : : * Card ATR's map to physical cards. vcard_alloc_atr will set appropriate
605 : : * historical bytes for any software emulated card. The remaining bytes can be
606 : : * used to indicate the actual emulator
607 : : */
608 : : static unsigned char *nss_atr;
609 : : static int nss_atr_len;
610 : :
611 : : void
612 : 0 : vcard_emul_get_atr(G_GNUC_UNUSED VCard *card, unsigned char *atr, int *atr_len)
613 : : {
614 : : int len;
615 [ # # ]: 0 : assert(atr != NULL);
616 : :
617 [ # # ]: 0 : if (nss_atr == NULL) {
618 : 0 : nss_atr = vcard_alloc_atr("NSS", &nss_atr_len);
619 : : }
620 : 0 : len = MIN(nss_atr_len, *atr_len);
621 : 0 : memcpy(atr, nss_atr, len);
622 : 0 : *atr_len = len;
623 : 0 : }
624 : :
625 : : static SECStatus
626 : 5 : vcard_emul_create_serial(VCard *card, unsigned char *data, int len)
627 : : {
628 : : HASH_HashType hashType;
629 : : HASHContext *hashContext = NULL;
630 : : unsigned char digest[32];
631 : 5 : unsigned int digestLen = 0;
632 : :
633 : 5 : hashType = HASH_GetHashTypeByOidTag(SEC_OID_SHA256);
634 : 5 : hashContext = HASH_Create(hashType);
635 [ + - ]: 5 : if (hashContext == NULL) {
636 : : return SECFailure;
637 : : }
638 : :
639 : 5 : HASH_Begin(hashContext);
640 : 5 : HASH_Update(hashContext, data, len);
641 : 5 : HASH_End(hashContext, digest, &digestLen, 32);
642 : 5 : HASH_Destroy(hashContext);
643 : :
644 : 5 : vcard_set_serial(card, digest, (size_t) digestLen);
645 : :
646 : 5 : return SECSuccess;
647 : : }
648 : :
649 : : /*
650 : : * create a new card from certs and keys
651 : : */
652 : : static VCard *
653 : 5 : vcard_emul_make_card(VReader *reader,
654 : : unsigned char * const *certs, int *cert_len,
655 : : VCardKey *keys[], int cert_count)
656 : : {
657 : : VCardEmul *vcard_emul;
658 : : VCard *vcard;
659 : : PK11SlotInfo *slot;
660 : : VCardEmulType type;
661 : : const char *params;
662 : :
663 : 5 : g_debug("%s: called", __func__);
664 : :
665 : 5 : type = vcard_emul_get_type(reader);
666 : :
667 : : /* ignore the inserted card */
668 [ - + ]: 5 : if (type == VCARD_EMUL_NONE) {
669 : : return NULL;
670 : : }
671 : : slot = vcard_emul_reader_get_slot(reader);
672 [ - + ]: 5 : if (slot == NULL) {
673 : : return NULL;
674 : : }
675 : :
676 : : params = vcard_emul_get_type_params(reader);
677 : : /* params these can be NULL */
678 : :
679 : : vcard_emul = vcard_emul_new_card(slot);
680 : : if (vcard_emul == NULL) {
681 : : return NULL;
682 : : }
683 : 5 : vcard = vcard_new(vcard_emul, vcard_emul_delete_card);
684 [ - + ]: 5 : if (vcard == NULL) {
685 : : vcard_emul_delete_card(vcard_emul);
686 : 0 : return NULL;
687 : : }
688 : :
689 [ + - ]: 5 : if (cert_count > 0) {
690 : 5 : vcard_emul_create_serial(vcard, certs[0], cert_len[0]);
691 : : }
692 : :
693 : 5 : vcard_init(reader, vcard, type, params, certs, cert_len, keys, cert_count);
694 : 5 : return vcard;
695 : : }
696 : :
697 : :
698 : : /*
699 : : * 'clone' a physical card as a virtual card
700 : : */
701 : : static VCard *
702 : 4 : vcard_emul_mirror_card(VReader *vreader)
703 : : {
704 : : /*
705 : : * lookup certs using the C_FindObjects. The Stan Cert handle won't give
706 : : * us the real certs until we log in.
707 : : */
708 : : PK11GenericObject *firstObj, *thisObj;
709 : : int cert_count;
710 : : unsigned char **certs;
711 : : int *cert_len;
712 : : VCardKey **keys;
713 : : PK11SlotInfo *slot;
714 : : VCard *card;
715 : :
716 : 4 : g_debug("%s: called", __func__);
717 : :
718 : : slot = vcard_emul_reader_get_slot(vreader);
719 [ - + ]: 4 : if (slot == NULL) {
720 : : return NULL;
721 : : }
722 : :
723 : 4 : firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE);
724 [ + + ]: 4 : if (firstObj == NULL) {
725 : : return NULL;
726 : : }
727 : :
728 : : /* count the certs */
729 : : cert_count = 0;
730 [ + + ]: 4 : for (thisObj = firstObj; thisObj;
731 : 2 : thisObj = PK11_GetNextGenericObject(thisObj)) {
732 : 2 : cert_count++;
733 : : }
734 : :
735 : : /* allocate the arrays */
736 : 2 : vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count);
737 : :
738 : : /* fill in the arrays */
739 : : cert_count = 0;
740 [ + + ]: 4 : for (thisObj = firstObj; thisObj;
741 : 2 : thisObj = PK11_GetNextGenericObject(thisObj)) {
742 : : SECItem derCert;
743 : : CERTCertificate *cert;
744 : : SECStatus rv;
745 : :
746 : 2 : g_debug("%s: Found certificate", __func__);
747 : 2 : rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj,
748 : : CKA_VALUE, &derCert);
749 [ - + ]: 2 : if (rv != SECSuccess) {
750 : 0 : continue;
751 : : }
752 : : /* create floating temp cert. This gives us a cert structure even if
753 : : * the token isn't logged in */
754 : 2 : cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert,
755 : : NULL, PR_FALSE, PR_TRUE);
756 : 2 : SECITEM_FreeItem(&derCert, PR_FALSE);
757 [ - + ]: 2 : if (cert == NULL) {
758 : 0 : continue;
759 : : }
760 : :
761 : 2 : certs[cert_count] = cert->derCert.data;
762 : 2 : cert_len[cert_count] = cert->derCert.len;
763 : 2 : keys[cert_count] = vcard_emul_make_key(slot, cert);
764 : 2 : cert_count++;
765 : 2 : CERT_DestroyCertificate(cert); /* key obj still has a reference */
766 : : }
767 : 2 : PK11_DestroyGenericObjects(firstObj);
768 : :
769 : : /* now create the card */
770 : 2 : card = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count);
771 : 2 : g_free(certs);
772 : 2 : g_free(cert_len);
773 : 2 : g_free(keys);
774 : :
775 : 2 : return card;
776 : : }
777 : :
778 : : static VCardEmulType default_card_type = VCARD_EMUL_NONE;
779 : : static const char *default_type_params = "";
780 : :
781 : : /*
782 : : * This thread looks for card and reader insertions and puts events on the
783 : : * event queue
784 : : */
785 : : static void
786 : 2 : vcard_emul_event_thread(void *arg)
787 : : {
788 : : PK11SlotInfo *slot;
789 : : VReader *vreader;
790 : : VReaderEmul *vreader_emul;
791 : : VCard *vcard;
792 : : SECMODModule *module = (SECMODModule *)arg;
793 : :
794 : : do {
795 : : /*
796 : : * XXX - the latency value doesn't matter one bit. you only get no
797 : : * blocking (flags |= CKF_DONT_BLOCK) or PKCS11_WAIT_LATENCY (==500),
798 : : * hard coded in coolkey. And it isn't coolkey's fault - the timeout
799 : : * value we pass get's dropped on the floor before C_WaitForSlotEvent
800 : : * is called.
801 : : */
802 : 6 : slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500);
803 [ - + ]: 4 : if (slot == NULL) {
804 : : /* this could be just a no event indication */
805 [ # # ]: 0 : if (PORT_GetError() == SEC_ERROR_NO_EVENT) {
806 : 0 : continue;
807 : : }
808 : : break;
809 : : }
810 : 4 : vreader = vcard_emul_find_vreader_from_slot(slot);
811 [ - + ]: 4 : if (vreader == NULL) {
812 : : /* new vreader */
813 : 0 : vreader_emul = vreader_emul_new(slot, default_card_type,
814 : : default_type_params);
815 : 0 : vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
816 : : vreader_emul_delete);
817 : 0 : PK11_FreeSlot(slot);
818 : : slot = NULL;
819 : 0 : vreader_add_reader(vreader);
820 : 0 : vreader_free(vreader);
821 : 0 : continue;
822 : : }
823 : : /* card remove/insert */
824 : 4 : vreader_emul = vreader_get_private(vreader);
825 [ + - ]: 4 : if (PK11_IsPresent(slot)) {
826 : 4 : int series = PK11_GetSlotSeries(slot);
827 [ - + ]: 4 : if (series != vreader_emul->series) {
828 [ # # ]: 0 : if (vreader_emul->present) {
829 : 0 : vreader_insert_card(vreader, NULL);
830 : : }
831 : 0 : vcard = vcard_emul_mirror_card(vreader);
832 : 0 : vreader_insert_card(vreader, vcard);
833 : 0 : vcard_free(vcard);
834 : : }
835 : 4 : vreader_emul->series = series;
836 : 4 : vreader_emul->present = 1;
837 : 4 : vreader_free(vreader);
838 : 4 : PK11_FreeSlot(slot);
839 : 4 : continue;
840 : : }
841 [ # # ]: 0 : if (vreader_emul->present) {
842 : 0 : vreader_insert_card(vreader, NULL);
843 : : }
844 : 0 : vreader_emul->series = 0;
845 : 0 : vreader_emul->present = 0;
846 : 0 : PK11_FreeSlot(slot);
847 : 0 : vreader_free(vreader);
848 : : } while (1);
849 : 0 : }
850 : :
851 : : /* if the card is inserted when we start up, make sure our state is correct */
852 : : static void
853 : 7 : vcard_emul_init_series(VReader *vreader, G_GNUC_UNUSED VCard *vcard)
854 : : {
855 : 7 : VReaderEmul *vreader_emul = vreader_get_private(vreader);
856 : 7 : PK11SlotInfo *slot = vreader_emul->slot;
857 : :
858 : 7 : vreader_emul->present = PK11_IsPresent(slot);
859 : 7 : vreader_emul->series = PK11_GetSlotSeries(slot);
860 [ - + ]: 7 : if (vreader_emul->present == 0) {
861 : 0 : vreader_insert_card(vreader, NULL);
862 : : }
863 : 7 : }
864 : :
865 : : /*
866 : : * each module has a separate wait call, create a thread for each module that
867 : : * we are using.
868 : : */
869 : : static void
870 : : vcard_emul_new_event_thread(SECMODModule *module)
871 : : {
872 : 2 : PR_CreateThread(PR_SYSTEM_THREAD, vcard_emul_event_thread,
873 : : module, PR_PRIORITY_HIGH, PR_GLOBAL_THREAD,
874 : : PR_UNJOINABLE_THREAD, 0);
875 : 2 : }
876 : :
877 : : static const VCardEmulOptions default_options = {
878 : : .nss_db = NULL,
879 : : .vreader = NULL,
880 : : .vreader_count = 0,
881 : : .hw_card_type = VCARD_EMUL_CAC,
882 : : .hw_type_params = NULL,
883 : : .use_hw = USE_HW_YES,
884 : : };
885 : :
886 : :
887 : : /*
888 : : * NSS needs the app to supply a password prompt. In our case the only time
889 : : * the password is supplied is as part of the Login APDU. The actual password
890 : : * is passed in the pw_arg in that case. In all other cases pw_arg should be
891 : : * NULL.
892 : : */
893 : : static char *
894 : 16 : vcard_emul_get_password(G_GNUC_UNUSED PK11SlotInfo *slot, PRBool retries, void *pw_arg)
895 : : {
896 : : /* if it didn't work the first time, don't keep trying */
897 [ + - ]: 16 : if (retries) {
898 : : return NULL;
899 : : }
900 : : /* we are looking up a password when we don't have one in hand */
901 [ + - ]: 16 : if (pw_arg == NULL) {
902 : : return NULL;
903 : : }
904 : : /* TODO: we really should verify that were are using the right slot */
905 : 16 : return PORT_Strdup(pw_arg);
906 : : }
907 : :
908 : : /* Force a card removal even if the card is not physically removed */
909 : : VCardEmulError
910 : 2 : vcard_emul_force_card_remove(VReader *vreader)
911 : : {
912 [ + - + + ]: 2 : if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) {
913 : 1 : return VCARD_EMUL_FAIL; /* card is already removed */
914 : : }
915 : :
916 : : /* OK, remove it */
917 : 1 : vreader_insert_card(vreader, NULL);
918 : 1 : return VCARD_EMUL_OK;
919 : : }
920 : :
921 : : /* Re-insert of a card that has been removed by force removal */
922 : : VCardEmulError
923 : 2 : vcard_emul_force_card_insert(VReader *vreader)
924 : : {
925 : : VReaderEmul *vreader_emul;
926 : : VCard *vcard;
927 : :
928 [ + - + + ]: 2 : if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) {
929 : 1 : return VCARD_EMUL_FAIL; /* card is already removed */
930 : : }
931 : 1 : vreader_emul = vreader_get_private(vreader);
932 : :
933 : : /* if it's a softcard, get the saved vcard from the reader emul structure */
934 [ + - ]: 1 : if (vreader_emul->saved_vcard) {
935 : 1 : vcard = vcard_reference(vreader_emul->saved_vcard);
936 : : } else {
937 : : /* it must be a physical card, rebuild it */
938 [ # # ]: 0 : if (!PK11_IsPresent(vreader_emul->slot)) {
939 : : /* physical card has been removed, not way to reinsert it */
940 : : return VCARD_EMUL_FAIL;
941 : : }
942 : 0 : vcard = vcard_emul_mirror_card(vreader);
943 : : }
944 : 1 : vreader_insert_card(vreader, vcard);
945 : 1 : vcard_free(vcard);
946 : :
947 : 1 : return VCARD_EMUL_OK;
948 : : }
949 : :
950 : : /* Previously we returned FAIL if no readers found. This makes
951 : : * no sense when using hardware, since there may be no readers connected
952 : : * at the time vcard_emul_init is called, but they will be properly
953 : : * recognized later. So Instead return FAIL only if no_hw==1 and no
954 : : * vcards can be created (indicates error with certificates provided
955 : : * or db), or if any other higher level error (NSS error, missing coolkey). */
956 : : static int vcard_emul_init_called;
957 : : static NSSInitContext *nss_ctx = NULL;
958 : :
959 : : VCardEmulError
960 : 7 : vcard_emul_init(const VCardEmulOptions *options)
961 : : {
962 : : PRBool has_readers = PR_FALSE;
963 : : VReader *vreader;
964 : : VReaderEmul *vreader_emul;
965 : : SECMODListLock *module_lock;
966 : : SECMODModuleList *module_list;
967 : : SECMODModuleList *mlp;
968 : : int i;
969 : : gchar *path = NULL;
970 : : const gchar *nss_db;
971 : :
972 : 7 : g_debug("%s: called", __func__);
973 : :
974 [ + + ]: 7 : if (vcard_emul_init_called) {
975 : : return VCARD_EMUL_INIT_ALREADY_INITED;
976 : : }
977 : 6 : vcard_emul_init_called = 1;
978 : 6 : vreader_init();
979 : 6 : vevent_queue_init();
980 : :
981 [ - + ]: 6 : if (options == NULL) {
982 : : options = &default_options;
983 : : }
984 : :
985 : : #if defined(ENABLE_PCSC)
986 : : if (options->use_hw && options->hw_card_type == VCARD_EMUL_PASSTHRU) {
987 : : if (options->vreader_count > 0) {
988 : : fprintf(stderr, "Error: you cannot use a soft card and "
989 : : "a passthru card simultaneously.\n");
990 : : return VCARD_EMUL_FAIL;
991 : : }
992 : :
993 : : if (capcsc_init()) {
994 : : fprintf(stderr, "Error initializing PCSC interface.\n");
995 : : return VCARD_EMUL_FAIL;
996 : : }
997 : :
998 : : g_debug("%s: returning with passthrough initialized", __func__);
999 : : return VCARD_EMUL_OK;
1000 : : }
1001 : : #endif
1002 : :
1003 : : /* first initialize NSS */
1004 : 6 : nss_db = options->nss_db;
1005 [ - + ]: 6 : if (nss_db == NULL) {
1006 : : #ifndef _WIN32
1007 : : nss_db = "/etc/pki/nssdb";
1008 : : #else
1009 : : const gchar * const *config_dirs = g_get_system_config_dirs();
1010 : : if (config_dirs == NULL || config_dirs[0] == NULL) {
1011 : : return VCARD_EMUL_FAIL;
1012 : : }
1013 : :
1014 : : path = g_build_filename(config_dirs[0], "pki", "nssdb", NULL);
1015 : : nss_db = path;
1016 : : #endif
1017 : : }
1018 : :
1019 : 6 : nss_ctx = NSS_InitContext(nss_db, "", "", "", NULL, NSS_INIT_READONLY);
1020 [ + + ]: 6 : if (nss_ctx == NULL) {
1021 : 1 : g_debug("%s: NSS_InitContext failed. Does the DB directory '%s' exist?",
1022 : : __func__, nss_db);
1023 : 1 : g_free(path);
1024 : 1 : return VCARD_EMUL_FAIL;
1025 : : }
1026 : 5 : g_free(path);
1027 : : path = NULL;
1028 : :
1029 : : /* Set password callback function */
1030 : 5 : PK11_SetPasswordFunc(vcard_emul_get_password);
1031 : :
1032 : : /* set up soft cards emulated by software certs rather than physical cards
1033 : : * */
1034 [ + + ]: 8 : for (i = 0; i < options->vreader_count; i++) {
1035 : : int j;
1036 : : int cert_count;
1037 : : unsigned char **certs;
1038 : : int *cert_len;
1039 : : VCardKey **keys;
1040 : : PK11SlotInfo *slot;
1041 : :
1042 : 3 : slot = PK11_FindSlotByName(options->vreader[i].name);
1043 [ - + ]: 3 : if (slot == NULL) {
1044 : 0 : continue;
1045 : : }
1046 : 3 : vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type,
1047 : 3 : options->vreader[i].type_params);
1048 : 3 : vreader = vreader_new(options->vreader[i].vname, vreader_emul,
1049 : : vreader_emul_delete);
1050 : 3 : vreader_add_reader(vreader);
1051 : :
1052 : 3 : vcard_emul_alloc_arrays(&certs, &cert_len, &keys,
1053 : 3 : options->vreader[i].cert_count);
1054 : :
1055 : : cert_count = 0;
1056 [ + + ]: 12 : for (j = 0; j < options->vreader[i].cert_count; j++) {
1057 : : /* we should have a better way of identifying certs than by
1058 : : * nickname here */
1059 : 9 : CERTCertificate *cert = PK11_FindCertFromNickname(
1060 : 9 : options->vreader[i].cert_name[j],
1061 : : NULL);
1062 [ - + ]: 9 : if (cert == NULL) {
1063 : 0 : continue;
1064 : : }
1065 : 9 : certs[cert_count] = cert->derCert.data;
1066 : 9 : cert_len[cert_count] = cert->derCert.len;
1067 : 9 : keys[cert_count] = vcard_emul_make_key(slot, cert);
1068 : : /* this is safe because the key is still holding a cert reference */
1069 : 9 : CERT_DestroyCertificate(cert);
1070 : 9 : cert_count++;
1071 : : }
1072 [ + - ]: 3 : if (cert_count) {
1073 : 3 : VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len,
1074 : : keys, cert_count);
1075 : 3 : vreader_insert_card(vreader, vcard);
1076 : 3 : vcard_emul_init_series(vreader, vcard);
1077 : : /* allow insertion and removal of soft cards */
1078 : 3 : vreader_emul->saved_vcard = vcard_reference(vcard);
1079 : 3 : vcard_free(vcard);
1080 : 3 : vreader_free(vreader);
1081 : : has_readers = PR_TRUE;
1082 : : }
1083 : 3 : PK11_FreeSlot(slot);
1084 : 3 : g_free(certs);
1085 : 3 : g_free(cert_len);
1086 : 3 : g_free(keys);
1087 : : }
1088 : :
1089 : : /* if we aren't suppose to use hw, skip looking up hardware tokens */
1090 [ + + ]: 5 : if (!options->use_hw) {
1091 : 3 : nss_emul_init = has_readers;
1092 : 3 : g_debug("%s: returning: Not using HW", __func__);
1093 : 3 : return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL;
1094 : : }
1095 : :
1096 : : /* make sure we have some PKCS #11 module loaded */
1097 : 2 : module_lock = SECMOD_GetDefaultModuleListLock();
1098 : 2 : module_list = SECMOD_GetDefaultModuleList();
1099 : :
1100 : : /* now examine all the slots, finding which should be readers */
1101 : : /* We should control this with options. For now we mirror out any
1102 : : * removable hardware slot */
1103 : 2 : default_card_type = options->hw_card_type;
1104 : 2 : default_type_params = g_strdup(options->hw_type_params);
1105 : :
1106 : 2 : SECMOD_GetReadLock(module_lock);
1107 [ + + ]: 6 : for (mlp = module_list; mlp; mlp = mlp->next) {
1108 : 4 : SECMODModule *module = mlp->module;
1109 : :
1110 : : /* Ignore the internal module */
1111 [ + - + + ]: 4 : if (module == NULL || module == SECMOD_GetInternalModule()) {
1112 : 2 : continue;
1113 : : }
1114 : :
1115 : 2 : g_debug("%s: Listing modules, trying %s", __func__, module->commonName);
1116 [ + + ]: 6 : for (i = 0; i < module->slotCount; i++) {
1117 : 4 : PK11SlotInfo *slot = module->slots[i];
1118 : :
1119 : : /* only map removable HW slots */
1120 [ + - + - ]: 4 : if (slot == NULL || !PK11_IsRemovable(slot) ||
1121 [ - + - - ]: 4 : (options->use_hw == USE_HW_YES && !PK11_IsHW(slot))) {
1122 : 0 : continue;
1123 : : }
1124 [ - + ]: 4 : if (strcmp("E-Gate 0 0", PK11_GetSlotName(slot)) == 0) {
1125 : : /*
1126 : : * coolkey <= 1.1.0-20 emulates this reader if it can't find
1127 : : * any hardware readers. This causes problems, warn user of
1128 : : * problems.
1129 : : */
1130 : 0 : fprintf(stderr, "known bad coolkey version - see "
1131 : : "https://bugzilla.redhat.com/show_bug.cgi?id=802435\n");
1132 : 0 : continue;
1133 : : }
1134 : 4 : vreader_emul = vreader_emul_new(slot, options->hw_card_type,
1135 : 4 : options->hw_type_params);
1136 : 4 : vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
1137 : : vreader_emul_delete);
1138 : 4 : vreader_add_reader(vreader);
1139 : 4 : g_debug("%s: Added reader from slot %s", __func__,
1140 : : PK11_GetSlotName(slot));
1141 : :
1142 [ + - ]: 4 : if (PK11_IsPresent(slot)) {
1143 : : VCard *vcard;
1144 : 4 : vcard = vcard_emul_mirror_card(vreader);
1145 : 4 : vreader_insert_card(vreader, vcard);
1146 : 4 : vcard_emul_init_series(vreader, vcard);
1147 : 4 : g_debug("%s: Added card to the reader %s", __func__,
1148 : : vreader_get_name(vreader));
1149 : 4 : vcard_free(vcard);
1150 : : }
1151 : 4 : vreader_free(vreader);
1152 : : }
1153 : : vcard_emul_new_event_thread(module);
1154 : : }
1155 : 2 : SECMOD_ReleaseReadLock(module_lock);
1156 : 2 : nss_emul_init = PR_TRUE;
1157 : :
1158 : 2 : return VCARD_EMUL_OK;
1159 : : }
1160 : :
1161 : : /* Recreate card insert events for all readers (user should
1162 : : * deduce implied reader insert. perhaps do a reader insert as well?)
1163 : : */
1164 : : void
1165 : 0 : vcard_emul_replay_insertion_events(void)
1166 : : {
1167 : : VReaderListEntry *current_entry;
1168 : : VReaderListEntry *next_entry;
1169 : 0 : VReaderList *list = vreader_get_reader_list();
1170 : :
1171 [ # # ]: 0 : for (current_entry = vreader_list_get_first(list); current_entry;
1172 : : current_entry = next_entry) {
1173 : 0 : VReader *vreader = vreader_list_get_reader(current_entry);
1174 : 0 : next_entry = vreader_list_get_next(current_entry);
1175 : 0 : vreader_queue_card_event(vreader);
1176 : : }
1177 : :
1178 : 0 : vreader_list_delete(list);
1179 : 0 : }
1180 : :
1181 : : VCardEmulError
1182 : 4 : vcard_emul_finalize(void)
1183 : : {
1184 : : SECStatus rv;
1185 : :
1186 : 4 : rv = NSS_ShutdownContext(nss_ctx);
1187 [ + + ]: 4 : if (rv != SECSuccess) {
1188 : 2 : g_debug("%s: NSS_ShutdownContext failed.", __func__);
1189 : 2 : return VCARD_EMUL_FAIL;
1190 : : }
1191 : 2 : nss_ctx = NULL;
1192 : :
1193 : 2 : return VCARD_EMUL_OK;
1194 : : }
1195 : :
1196 : : /*
1197 : : * Silly little functions to help parsing our argument string
1198 : : */
1199 : : static int
1200 : : count_tokens(const char *str, char token, char token_end)
1201 : : {
1202 : : int count = 0;
1203 : :
1204 [ + - ]: 72 : for (; *str; str++) {
1205 [ + + ]: 72 : if (*str == token) {
1206 : 8 : count++;
1207 : : }
1208 [ + + ]: 72 : if (*str == token_end) {
1209 : : break;
1210 : : }
1211 : : }
1212 : : return count;
1213 : : }
1214 : :
1215 : : static const char *
1216 : 69 : strip(const char *str)
1217 : : {
1218 [ + + + + ]: 81 : for (; *str && isspace(*str); str++) {
1219 : : }
1220 : 69 : return str;
1221 : : }
1222 : :
1223 : : static const char *
1224 : 7 : find_blank(const char *str)
1225 : : {
1226 [ + + + + ]: 42 : for (; *str && !isspace(*str); str++) {
1227 : : }
1228 : 7 : return str;
1229 : : }
1230 : :
1231 : :
1232 : : /*
1233 : : * We really want to use some existing argument parsing library here. That
1234 : : * would give us a consistent look */
1235 : : static VCardEmulOptions options;
1236 : : #define READER_STEP 4
1237 : :
1238 : : /* Expects "args" to be at the beginning of a token (ie right after the ','
1239 : : * ending the previous token), and puts the next token start in "token",
1240 : : * and its length in "token_length". "token" will not be nul-terminated.
1241 : : * After calling the macro, "args" will be advanced to the beginning of
1242 : : * the next token.
1243 : : */
1244 : : #define NEXT_TOKEN(token) \
1245 : : (token) = args; \
1246 : : args = strpbrk(args, ",)"); \
1247 : : if (args == NULL || *args == 0 || *args == ')') { \
1248 : : fprintf(stderr, "Error: invalid soft specification.\n"); \
1249 : : goto fail; \
1250 : : } \
1251 : : (token##_length) = args - (token); \
1252 : : args = strip(args+1);
1253 : :
1254 : : VCardEmulOptions *
1255 : 7 : vcard_emul_options(const char *args)
1256 : : {
1257 : : int i, j, reader_count = 0;
1258 : : VCardEmulOptions *opts;
1259 : :
1260 : : /* Allow the future use of allocating the options structure on the fly */
1261 : 7 : memcpy(&options, &default_options, sizeof(options));
1262 : : opts = &options;
1263 : :
1264 : : do {
1265 : 19 : args = strip(args); /* strip off the leading spaces */
1266 [ - + ]: 19 : if (*args == ',') {
1267 : 0 : args++;
1268 : 0 : continue;
1269 : : }
1270 : : /* soft=(slot_name,virt_name,emul_type,emul_flags,cert_1, (no eol)
1271 : : * cert_2,cert_3...) */
1272 [ + + ]: 19 : if (strncmp(args, "soft=", 5) == 0) {
1273 : : const char *name;
1274 : : size_t name_length;
1275 : : const char *vname;
1276 : : size_t vname_length;
1277 : : const char *type_params;
1278 : : size_t type_params_length;
1279 : : char type_str[100];
1280 : : VCardEmulType type;
1281 : : int count;
1282 : : VirtualReaderOptions *vreaderOpt;
1283 : :
1284 : 4 : args = strip(args + 5);
1285 [ - + ]: 4 : if (*args != '(') {
1286 : 0 : fprintf(stderr, "Error: invalid soft specification.\n");
1287 : 0 : goto fail;
1288 : : }
1289 : 4 : args = strip(args+1);
1290 : :
1291 [ + - + - : 4 : NEXT_TOKEN(name)
- + ]
1292 [ + - + - : 4 : NEXT_TOKEN(vname)
- + ]
1293 [ + - + - : 4 : NEXT_TOKEN(type_params)
- + ]
1294 : 4 : type_params_length = MIN(type_params_length, sizeof(type_str)-1);
1295 : 4 : memcpy(type_str, type_params, type_params_length);
1296 : 4 : type_str[type_params_length] = '\0';
1297 : 4 : type = vcard_emul_type_from_string(type_str);
1298 [ - + ]: 4 : if (type == VCARD_EMUL_NONE) {
1299 : 0 : fprintf(stderr, "Error: invalid smartcard type '%s'.\n",
1300 : : type_str);
1301 : 0 : goto fail;
1302 : : }
1303 : :
1304 [ + - + - : 4 : NEXT_TOKEN(type_params)
- + ]
1305 : :
1306 [ - + ]: 4 : if (*args == 0) {
1307 : 0 : fprintf(stderr, "Error: missing cert specification.\n");
1308 : 0 : goto fail;
1309 : : }
1310 : :
1311 [ + - ]: 4 : if (opts->vreader_count >= reader_count) {
1312 : 4 : reader_count += READER_STEP;
1313 [ - + - - ]: 4 : opts->vreader = g_renew(VirtualReaderOptions, opts->vreader,
1314 : : reader_count);
1315 : : }
1316 : 4 : vreaderOpt = &opts->vreader[opts->vreader_count];
1317 : 4 : vreaderOpt->name = g_strndup(name, name_length);
1318 : 4 : vreaderOpt->vname = g_strndup(vname, vname_length);
1319 : 4 : vreaderOpt->card_type = type;
1320 : 4 : vreaderOpt->type_params =
1321 : 4 : g_strndup(type_params, type_params_length);
1322 : 4 : count = count_tokens(args, ',', ')') + 1;
1323 : 4 : vreaderOpt->cert_count = count;
1324 [ - + - - ]: 4 : vreaderOpt->cert_name = g_new(char *, count);
1325 [ + + ]: 16 : for (i = 0; i < count; i++) {
1326 : : const char *cert = args;
1327 : 12 : args = strpbrk(args, ",)");
1328 : 12 : vreaderOpt->cert_name[i] = g_strndup(cert, args - cert);
1329 : 12 : args = strip(args+1);
1330 : : }
1331 [ - + ]: 4 : if (*args == ')') {
1332 : 0 : args++;
1333 : : }
1334 : 4 : opts->vreader_count++;
1335 : : /* use_hw= */
1336 [ + + ]: 15 : } else if (strncmp(args, "use_hw=", 7) == 0) {
1337 : 7 : args = strip(args+7);
1338 [ + - + + : 7 : if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') {
- + ]
1339 : 4 : opts->use_hw = USE_HW_NO;
1340 [ + - ]: 3 : } else if (strncmp(args, "removable", 9) == 0) {
1341 : 3 : opts->use_hw = USE_HW_REMOVABLE;
1342 : : } else {
1343 : 0 : opts->use_hw = USE_HW_YES;
1344 : : }
1345 : 7 : args = find_blank(args);
1346 : : /* hw_type= */
1347 [ - + ]: 8 : } else if (strncmp(args, "hw_type=", 8) == 0) {
1348 : 0 : args = strip(args+8);
1349 : 0 : opts->hw_card_type = vcard_emul_type_from_string(args);
1350 [ # # ]: 0 : if (opts->hw_card_type == VCARD_EMUL_NONE) {
1351 : 0 : fprintf(stderr, "Error: invalid smartcard type '%s'.\n",
1352 : : args);
1353 : 0 : goto fail;
1354 : : }
1355 : 0 : args = find_blank(args);
1356 : : /* hw_params= */
1357 [ - + ]: 8 : } else if (strncmp(args, "hw_params=", 10) == 0) {
1358 : : const char *params;
1359 : :
1360 [ # # ]: 0 : if (opts->hw_type_params != NULL) {
1361 : 0 : fprintf(stderr, "Error: redefinition of hw_params= is not allowed.\n");
1362 : 0 : goto fail;
1363 : : }
1364 : 0 : args = strip(args+10);
1365 : : params = args;
1366 : 0 : args = find_blank(args);
1367 : 0 : opts->hw_type_params = g_strndup(params, args-params);
1368 : : /* db="/data/base/path" */
1369 [ + + ]: 8 : } else if (strncmp(args, "db=", 3) == 0) {
1370 : : const char *db;
1371 : :
1372 [ - + ]: 7 : if (opts->nss_db != NULL) {
1373 : 0 : fprintf(stderr, "Error: redefinition of db= is not allowed.\n");
1374 : 0 : goto fail;
1375 : : }
1376 : 7 : args = strip(args+3);
1377 [ - + ]: 7 : if (*args != '"') {
1378 : 0 : fprintf(stderr, "Error: you must quote the file path.\n");
1379 : 0 : goto fail;
1380 : : }
1381 : 7 : args++;
1382 : : db = args;
1383 : 7 : args = strpbrk(args, "\"\n");
1384 [ - + ]: 7 : if (args == NULL) {
1385 : 0 : fprintf(stderr, "Error: invalid db argument.\n");
1386 : 0 : goto fail;
1387 : : }
1388 : 7 : opts->nss_db = g_strndup(db, args-db);
1389 [ + - ]: 7 : if (*args != 0) {
1390 : 7 : args++;
1391 : : }
1392 [ - + ]: 1 : } else if (strncmp(args, "nssemul", 7) == 0) {
1393 : 0 : opts->hw_card_type = VCARD_EMUL_CAC;
1394 : 0 : opts->use_hw = USE_HW_YES;
1395 : 0 : args = find_blank(args + 7);
1396 : : #if defined(ENABLE_PCSC)
1397 : : } else if (strncmp(args, "passthru", 8) == 0) {
1398 : : opts->hw_card_type = VCARD_EMUL_PASSTHRU;
1399 : : opts->use_hw = USE_HW_YES;
1400 : : args = find_blank(args + 8);
1401 : : #endif
1402 : : } else {
1403 : 1 : fprintf(stderr, "Error: Unknown smartcard specification.\n");
1404 : 1 : goto fail;
1405 : : }
1406 [ + + ]: 18 : } while (*args != 0);
1407 : :
1408 : : return opts;
1409 : :
1410 : : fail:
1411 : : /* Clean up what was allocated above on failure */
1412 [ - + ]: 1 : for (i = 0; i < opts->vreader_count; i++) {
1413 : 0 : g_free(opts->vreader[i].name);
1414 : 0 : g_free(opts->vreader[i].vname);
1415 : 0 : g_free(opts->vreader[i].type_params);
1416 [ # # ]: 0 : for (j = 0; j < opts->vreader[i].cert_count; j++) {
1417 : 0 : g_free(opts->vreader[i].cert_name[j]);
1418 : : }
1419 : 0 : g_free(opts->vreader[i].cert_name);
1420 : : }
1421 : 1 : g_free(opts->vreader);
1422 : 1 : g_free(opts->hw_type_params);
1423 : 1 : g_free(opts->nss_db);
1424 : 1 : return NULL;
1425 : : }
1426 : :
1427 : : unsigned char *
1428 : 6 : vcard_emul_read_object(VCard *card, const char *label,
1429 : : unsigned int *ret_len)
1430 : : {
1431 : : PK11SlotInfo *slot;
1432 : : PK11GenericObject *obj, *firstObj, *myObj = NULL;
1433 : : SECItem result;
1434 : : SECStatus r;
1435 : : unsigned char *ret;
1436 : :
1437 : : slot = vcard_emul_card_get_slot(card);
1438 : :
1439 : 6 : firstObj = PK11_FindGenericObjects(slot, CKO_DATA);
1440 : 6 : g_debug("%s: Search for generic objects: got %p", __func__, firstObj);
1441 [ - + ]: 6 : for (obj = firstObj; obj; obj = PK11_GetNextGenericObject(obj)) {
1442 : : int found = 0;
1443 : 0 : r = PK11_ReadRawAttribute(PK11_TypeGeneric, obj,
1444 : : CKA_LABEL, &result);
1445 [ # # ]: 0 : if (r != SECSuccess) {
1446 : 0 : PK11_DestroyGenericObjects(firstObj);
1447 : 0 : return NULL;
1448 : : }
1449 : :
1450 [ # # ]: 0 : if (strlen(label) == result.len
1451 [ # # ]: 0 : && memcmp(label, result.data, result.len) == 0)
1452 : : found = 1;
1453 : :
1454 : 0 : PORT_Free(result.data);
1455 : 0 : result.data = NULL;
1456 : :
1457 [ # # ]: 0 : if (found) {
1458 : 0 : PK11_UnlinkGenericObject(obj);
1459 : : myObj = obj;
1460 : 0 : break;
1461 : : }
1462 : : }
1463 : 6 : PK11_DestroyGenericObjects(firstObj);
1464 : :
1465 [ + - ]: 6 : if (!myObj)
1466 : : return NULL;
1467 : :
1468 : 0 : r = PK11_ReadRawAttribute(PK11_TypeGeneric, myObj,
1469 : : CKA_VALUE, &result);
1470 : 0 : PK11_DestroyGenericObject(myObj);
1471 [ # # ]: 0 : if (r != SECSuccess)
1472 : : return NULL;
1473 : :
1474 : 0 : *ret_len = result.len;
1475 : 0 : ret = g_memdup2(result.data, result.len);
1476 : 0 : PORT_Free(result.data);
1477 : 0 : return ret;
1478 : : }
1479 : :
1480 : : void
1481 : 0 : vcard_emul_usage(void)
1482 : : {
1483 : 0 : fprintf(stderr,
1484 : : "emul args: comma separated list of the following arguments\n"
1485 : : " db={nss_database} (default sql:/etc/pki/nssdb)\n"
1486 : : " use_hw=[yes|no|removable] (default yes)\n"
1487 : : " hw_type={card_type_to_emulate} (default CAC)\n"
1488 : : " hw_params={param_for_card} (default \"\")\n"
1489 : : " nssemul (alias for use_hw=yes, hw_type=CAC)\n"
1490 : : #if defined(ENABLE_PCSC)
1491 : : " passthru (alias for use_hw=yes, hw_type=PASSTHRU)\n"
1492 : : #endif
1493 : : " soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n"
1494 : : " {cert1},{cert2},{cert3} (default none)\n"
1495 : : "\n"
1496 : : " {nss_database} The location of the NSS cert & key database\n"
1497 : : " {card_type_to_emulate} What card interface to present to the guest\n"
1498 : : " {param_for_card} Card interface specific parameters\n"
1499 : : " {slot_name} NSS slot that contains the certs\n"
1500 : : " {vreader_name} Virtual reader name to present to the guest\n"
1501 : : " {certN} Nickname of the certificate n on the virtual card\n"
1502 : : "\n"
1503 : : "These parameters come as a single string separated by blanks or newlines."
1504 : : "\n"
1505 : : "Unless use_hw is set to no, all tokens that look like removable hardware\n"
1506 : : "tokens will be presented to the guest using the emulator specified by\n"
1507 : : "hw_type, and parameters of hw_params. If use_hw is set to 'removable', "
1508 : : "present any removable token.\n"
1509 : : "\n"
1510 : : "If more one or more soft= parameters are specified, these readers will be\n"
1511 : : "presented to the guest\n"
1512 : : #if defined(ENABLE_PCSC)
1513 : : "\n"
1514 : : "If a hw_type of PASSTHRU is given, a connection will be made to the hardware\n"
1515 : : "using libpcscslite. Note that in that case, no soft cards are permitted.\n"
1516 : : #endif
1517 : : );
1518 : 0 : }
1519 : : /* vim: set ts=4 sw=4 tw=0 noet expandtab: */
|