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 : 6 : vcard_emul_alloc_arrays(unsigned char ***certsp, int **cert_lenp,
109 : : VCardKey ***keysp, int cert_count)
110 : : {
111 [ - + - - ]: 6 : *certsp = g_new(unsigned char *, cert_count);
112 [ - + - - ]: 6 : *cert_lenp = g_new(int, cert_count);
113 [ - + - - ]: 6 : *keysp = g_new(VCardKey *, cert_count);
114 : 6 : }
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 : 6 : PK11_ReferenceSlot(slot);
125 : : /* currently we don't need anything other than the slot */
126 : : return (VCardEmul *)slot;
127 : : }
128 : :
129 : : static void
130 : 5 : vcard_emul_delete_card(VCardEmul *vcard_emul)
131 : : {
132 : : PK11SlotInfo *slot = (PK11SlotInfo *)vcard_emul;
133 [ + - ]: 5 : if (slot == NULL) {
134 : : return;
135 : : }
136 : 5 : 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 : 118 : return (PK11SlotInfo *)vcard_get_private(card);
144 : : }
145 : :
146 : :
147 : : /*
148 : : * key functions
149 : : */
150 : : /* private constructure */
151 : : static VCardKey *
152 : 16 : vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert)
153 : : {
154 : : VCardKey *key;
155 : :
156 : 16 : key = g_new(VCardKey, 1);
157 : 16 : key->slot = PK11_ReferenceSlot(slot);
158 : 16 : key->cert = CERT_DupCertificate(cert);
159 : 16 : key->failedX509 = VCardEmulUnknown;
160 : 16 : return key;
161 : : }
162 : :
163 : : /* destructor */
164 : : void
165 : 13 : vcard_emul_delete_key(VCardKey *key)
166 : : {
167 [ + - + - ]: 13 : if (!nss_emul_init || (key == NULL)) {
168 : : return;
169 : : }
170 [ + - ]: 13 : if (key->cert) {
171 : 13 : CERT_DestroyCertificate(key->cert);
172 : : }
173 [ + - ]: 13 : if (key->slot) {
174 : 13 : PK11_FreeSlot(key->slot);
175 : : }
176 : 13 : 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 : 36 : 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 : 0 : vcard_emul_map_error(int error)
194 : : {
195 [ # # # # ]: 0 : switch (error) {
196 : : case SEC_ERROR_TOKEN_NOT_LOGGED_IN:
197 : : return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
198 : 0 : 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 : 0 : 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 : 16 : vcard_emul_rsa_bits(VCardKey *key)
220 : : {
221 : : SECKEYPublicKey *pub_key;
222 : : int bits = -1;
223 : :
224 [ - + ]: 16 : if (key == NULL) {
225 : : /* couldn't get the key, indicate that we aren't logged in */
226 : : return -1;
227 : : }
228 : 16 : pub_key = CERT_ExtractPublicKey(key->cert);
229 [ - + ]: 16 : if (pub_key == NULL) {
230 : : /* couldn't get the key, indicate that we aren't logged in */
231 : : return -1;
232 : : }
233 : :
234 : 16 : bits = SECKEY_PublicKeyStrengthInBits(pub_key);
235 : 16 : SECKEY_DestroyPublicKey(pub_key);
236 : 16 : return bits;
237 : : }
238 : :
239 : : /* RSA sign/decrypt with the key, signature happens 'in place' */
240 : : vcard_7816_status_t
241 : 36 : 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 [ - + ]: 36 : assert(buffer_size >= 0);
254 [ + - - + ]: 36 : 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 [ - + ]: 36 : 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 : 36 : signature_len = PK11_SignatureLen(priv_key);
269 [ - + ]: 36 : 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 [ - + ]: 36 : 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 [ + + ]: 36 : if (key->failedX509 != VCardEmulTrue
286 [ + + ]: 23 : && PK11_DoesMechanism(slot, CKM_RSA_X_509)) {
287 : 21 : rv = PK11_PrivDecryptRaw(priv_key, bp, &signature_len, signature_len,
288 : : buffer, buffer_size);
289 [ + - ]: 21 : if (rv == SECSuccess) {
290 [ - + ]: 21 : assert((unsigned)buffer_size == signature_len);
291 : 21 : memcpy(buffer, bp, signature_len);
292 : 21 : key->failedX509 = VCardEmulFalse;
293 : 21 : 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 [ + + + + ]: 15 : if ((buffer[0] == 0) && (buffer[1] == 1)) {
311 : : int i;
312 : :
313 [ + - ]: 1926 : for (i = 2; i < buffer_size; i++) {
314 : : /* rsa signature pad */
315 [ + + ]: 1926 : if (buffer[i] != 0xff) {
316 : : break;
317 : : }
318 : : }
319 [ + - + - ]: 12 : 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 : 12 : i++;
331 : 12 : hash.data = &buffer[i];
332 : 12 : hash.len = buffer_size - i;
333 : 12 : signature.data = bp;
334 : 12 : signature.len = signature_len;
335 : 12 : rv = PK11_Sign(priv_key, &signature, &hash);
336 [ - + ]: 12 : if (rv != SECSuccess) {
337 : 0 : ret = vcard_emul_map_error(PORT_GetError());
338 : 0 : goto cleanup;
339 : : }
340 [ - + ]: 12 : assert((unsigned)buffer_size == signature.len);
341 : 12 : 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 : 12 : key->failedX509 = VCardEmulTrue;
348 : 12 : 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 : 3 : rv = PK11_PrivDecryptPKCS1(priv_key, bp, &signature_len, buffer_size, buffer, buffer_size);
355 [ - + ]: 3 : if (rv != SECSuccess) {
356 : : /* The assumption was wrong. Give up */
357 : 0 : ret = vcard_emul_map_error(PORT_GetError());
358 : 0 : goto cleanup;
359 : : }
360 : 3 : pad_len = buffer_size - signature_len;
361 [ - + ]: 3 : 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 : 3 : buffer[0] = 0;
370 : 3 : buffer[1] = 2; /* RSA_encrypt */
371 : 3 : 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 : 3 : memset(&buffer[2], 0x03, pad_len);
380 : 3 : pad_len += 2; /* index to the end of the pad */
381 : 3 : buffer[pad_len] = 0;
382 : : pad_len++; /* index to the start of the data */
383 : 3 : 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 : 3 : key->failedX509 = VCardEmulTrue;
390 : 36 : cleanup:
391 [ - + ]: 36 : if (bp != buf) {
392 : 0 : g_free(bp);
393 : : }
394 : 36 : SECKEY_DestroyPrivateKey(priv_key);
395 : 36 : 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 : 36 : vcard_emul_logout(VCard *card)
479 : : {
480 : : PK11SlotInfo *slot;
481 : :
482 [ + - ]: 36 : if (!nss_emul_init) {
483 : : return;
484 : : }
485 : :
486 : : slot = vcard_emul_card_get_slot(card);
487 [ + + ]: 36 : if (PK11_IsLoggedIn(slot, NULL)) {
488 : 14 : PK11_Logout(slot); /* NOTE: ignoring SECStatus return value */
489 : : }
490 : : }
491 : :
492 : : void
493 : 16 : 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 : 16 : vcard_emul_logout(card);
500 : :
501 : : /* TODO: we may also need to send insertion/removal events? */
502 : 16 : }
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 : 8 : vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params)
533 : : {
534 : : VReaderEmul *new_reader_emul;
535 : :
536 : 8 : new_reader_emul = g_new(VReaderEmul, 1);
537 : :
538 : 8 : new_reader_emul->slot = PK11_ReferenceSlot(slot);
539 [ - + ]: 8 : new_reader_emul->default_type = type;
540 : 8 : new_reader_emul->type_params = g_strdup(params);
541 : 8 : new_reader_emul->present = PR_FALSE;
542 : 8 : new_reader_emul->series = 0;
543 : 8 : new_reader_emul->saved_vcard = NULL;
544 : 8 : return new_reader_emul;
545 : : }
546 : :
547 : : static void
548 : 5 : vreader_emul_delete(VReaderEmul *vreader_emul)
549 : : {
550 [ + - ]: 5 : if (vreader_emul == NULL) {
551 : : return;
552 : : }
553 : 5 : vcard_free(vreader_emul->saved_vcard);
554 [ + - ]: 5 : if (vreader_emul->slot) {
555 : 5 : PK11_FreeSlot(vreader_emul->slot);
556 : : }
557 : 5 : g_free(vreader_emul->type_params);
558 : 5 : g_free(vreader_emul);
559 : : }
560 : :
561 : : /*
562 : : * TODO: move this to emulater non-specific file
563 : : */
564 : : static VCardEmulType
565 : 6 : vcard_emul_get_type(VReader *vreader)
566 : : {
567 : : VReaderEmul *vreader_emul;
568 : :
569 : 6 : vreader_emul = vreader_get_private(vreader);
570 [ + - - + ]: 6 : 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 : 6 : vreader_emul = vreader_get_private(vreader);
585 [ - + + + ]: 6 : 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 : 10 : VReaderEmul *vreader_emul = vreader_get_private(vreader);
597 [ + - - + ]: 10 : if (vreader_emul == NULL) {
598 : : return NULL;
599 : : }
600 : 10 : 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 : 1 : vcard_emul_get_atr(G_GNUC_UNUSED VCard *card, unsigned char *atr, int *atr_len)
613 : : {
614 : : int len;
615 [ - + ]: 1 : assert(atr != NULL);
616 : :
617 [ + - ]: 1 : if (nss_atr == NULL) {
618 : 1 : nss_atr = vcard_alloc_atr("NSS", &nss_atr_len);
619 : : }
620 : 1 : len = MIN(nss_atr_len, *atr_len);
621 : 1 : memcpy(atr, nss_atr, len);
622 : 1 : *atr_len = len;
623 : 1 : }
624 : :
625 : : static SECStatus
626 : 6 : 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 : 6 : unsigned int digestLen = 0;
632 : :
633 : 6 : hashType = HASH_GetHashTypeByOidTag(SEC_OID_SHA256);
634 : 6 : hashContext = HASH_Create(hashType);
635 [ + - ]: 6 : if (hashContext == NULL) {
636 : : return SECFailure;
637 : : }
638 : :
639 : 6 : HASH_Begin(hashContext);
640 : 6 : HASH_Update(hashContext, data, len);
641 : 6 : HASH_End(hashContext, digest, &digestLen, 32);
642 : 6 : HASH_Destroy(hashContext);
643 : :
644 : 6 : vcard_set_serial(card, digest, (size_t) digestLen);
645 : :
646 : 6 : return SECSuccess;
647 : : }
648 : :
649 : : /*
650 : : * create a new card from certs and keys
651 : : */
652 : : static VCard *
653 : 6 : 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 : 6 : g_debug("%s: called", __func__);
664 : :
665 : 6 : type = vcard_emul_get_type(reader);
666 : :
667 : : /* ignore the inserted card */
668 [ - + ]: 6 : if (type == VCARD_EMUL_NONE) {
669 : : return NULL;
670 : : }
671 : : slot = vcard_emul_reader_get_slot(reader);
672 [ - + ]: 6 : 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 : 6 : vcard = vcard_new(vcard_emul, vcard_emul_delete_card);
684 [ - + ]: 6 : if (vcard == NULL) {
685 : : vcard_emul_delete_card(vcard_emul);
686 : 0 : return NULL;
687 : : }
688 : :
689 [ + - ]: 6 : if (cert_count > 0) {
690 : 6 : vcard_emul_create_serial(vcard, certs[0], cert_len[0]);
691 : : }
692 : :
693 : 6 : vcard_init(reader, vcard, type, params, certs, cert_len, keys, cert_count);
694 : 6 : 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, i;
710 : : unsigned char **certs;
711 : : SECItem **ids;
712 : : int *cert_len;
713 : : VCardKey **keys;
714 : : PK11SlotInfo *slot;
715 : : VCard *card;
716 : :
717 : 4 : g_debug("%s: called", __func__);
718 : :
719 : : slot = vcard_emul_reader_get_slot(vreader);
720 [ - + ]: 4 : if (slot == NULL) {
721 : : return NULL;
722 : : }
723 : :
724 : 4 : firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE);
725 [ + + ]: 4 : if (firstObj == NULL) {
726 : : return NULL;
727 : : }
728 : :
729 : : /* count the certs */
730 : : cert_count = 0;
731 [ + + ]: 6 : for (thisObj = firstObj; thisObj;
732 : 4 : thisObj = PK11_GetNextGenericObject(thisObj)) {
733 : 4 : cert_count++;
734 : : }
735 : :
736 : : /* allocate the arrays */
737 : 2 : vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count);
738 [ - + ]: 2 : ids = g_new(SECItem *, cert_count);
739 : :
740 : : /* fill in the arrays */
741 : : cert_count = i = 0;
742 [ + + ]: 6 : for (thisObj = firstObj; thisObj;
743 : 4 : thisObj = PK11_GetNextGenericObject(thisObj)) {
744 : : SECItem derCert, *id;
745 : : CERTCertificate *cert;
746 : : SECStatus rv;
747 : :
748 : 4 : g_debug("%s: Found certificate", __func__);
749 : 4 : rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj,
750 : : CKA_VALUE, &derCert);
751 [ - + ]: 4 : if (rv != SECSuccess) {
752 : 0 : continue;
753 : : }
754 : : /* Read ID and try to sort by this to get reproducible results
755 : : * in case of underlying pkcs11 module does not provide it */
756 : 4 : id = SECITEM_AllocItem(NULL, NULL, 0);
757 : 4 : rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj, CKA_ID, id);
758 [ - + ]: 4 : if (rv != SECSuccess) {
759 : 0 : SECITEM_FreeItem(&derCert, PR_FALSE);
760 : 0 : SECITEM_FreeItem(id, PR_TRUE);
761 : 0 : continue;
762 : : }
763 : : /* create floating temp cert. This gives us a cert structure even if
764 : : * the token isn't logged in */
765 : 4 : cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert,
766 : : NULL, PR_FALSE, PR_TRUE);
767 : 4 : SECITEM_FreeItem(&derCert, PR_FALSE);
768 [ - + ]: 4 : if (cert == NULL) {
769 : 0 : SECITEM_FreeItem(id, PR_TRUE);
770 : 0 : continue;
771 : : }
772 : :
773 [ + + ]: 4 : for (i = 0; i < cert_count; i++) {
774 [ + - ]: 2 : if (SECITEM_CompareItem(id, ids[i]) < SECEqual) {
775 : : /* Make space for the item here, move the rest of the items */
776 : 2 : memmove(&certs[i + 1], &certs[i], (cert_count - i) * sizeof(certs[0]));
777 : 2 : memmove(&cert_len[i + 1], &cert_len[i], (cert_count - i) * sizeof(cert_len[0]));
778 : 2 : memmove(&keys[i + 1], &keys[i], (cert_count - i) * sizeof(keys[0]));
779 : 2 : memmove(&ids[i + 1], &ids[i], (cert_count - i) * sizeof(ids[0]));
780 : 2 : break;
781 : : }
782 : : }
783 : 4 : certs[i] = cert->derCert.data;
784 : 4 : cert_len[i] = cert->derCert.len;
785 : 4 : keys[i] = vcard_emul_make_key(slot, cert);
786 : 4 : ids[i] = id;
787 : 4 : cert_count++;
788 : 4 : CERT_DestroyCertificate(cert); /* key obj still has a reference */
789 : : }
790 : 2 : PK11_DestroyGenericObjects(firstObj);
791 : : /* No longer needed */
792 [ + + ]: 6 : for (i = 0; i < cert_count; i++) {
793 : 4 : SECITEM_FreeItem(ids[i], PR_TRUE);
794 : : }
795 : 2 : g_free(ids);
796 : :
797 : : /* now create the card */
798 : 2 : card = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count);
799 : 2 : g_free(certs);
800 : 2 : g_free(cert_len);
801 : 2 : g_free(keys);
802 : :
803 : 2 : return card;
804 : : }
805 : :
806 : : static VCardEmulType default_card_type = VCARD_EMUL_NONE;
807 : : static const char *default_type_params = "";
808 : :
809 : : /*
810 : : * This thread looks for card and reader insertions and puts events on the
811 : : * event queue
812 : : */
813 : : static void
814 : 2 : vcard_emul_event_thread(void *arg)
815 : : {
816 : : PK11SlotInfo *slot;
817 : : VReader *vreader;
818 : : VReaderEmul *vreader_emul;
819 : : VCard *vcard;
820 : : SECMODModule *module = (SECMODModule *)arg;
821 : :
822 : : do {
823 : : /*
824 : : * XXX - the latency value doesn't matter one bit. you only get no
825 : : * blocking (flags |= CKF_DONT_BLOCK) or PKCS11_WAIT_LATENCY (==500),
826 : : * hard coded in coolkey. And it isn't coolkey's fault - the timeout
827 : : * value we pass get's dropped on the floor before C_WaitForSlotEvent
828 : : * is called.
829 : : */
830 : 6 : slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500);
831 [ - + ]: 4 : if (slot == NULL) {
832 : : /* this could be just a no event indication */
833 [ # # ]: 0 : if (PORT_GetError() == SEC_ERROR_NO_EVENT) {
834 : 0 : continue;
835 : : }
836 : : break;
837 : : }
838 : 4 : vreader = vcard_emul_find_vreader_from_slot(slot);
839 [ - + ]: 4 : if (vreader == NULL) {
840 : : /* new vreader */
841 : 0 : vreader_emul = vreader_emul_new(slot, default_card_type,
842 : : default_type_params);
843 : 0 : vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
844 : : vreader_emul_delete);
845 : 0 : PK11_FreeSlot(slot);
846 : : slot = NULL;
847 : 0 : vreader_add_reader(vreader);
848 : 0 : vreader_free(vreader);
849 : 0 : continue;
850 : : }
851 : : /* card remove/insert */
852 : 4 : vreader_emul = vreader_get_private(vreader);
853 [ + - ]: 4 : if (PK11_IsPresent(slot)) {
854 : 4 : int series = PK11_GetSlotSeries(slot);
855 [ - + ]: 4 : if (series != vreader_emul->series) {
856 [ # # ]: 0 : if (vreader_emul->present) {
857 : 0 : vreader_insert_card(vreader, NULL);
858 : : }
859 : 0 : vcard = vcard_emul_mirror_card(vreader);
860 : 0 : vreader_insert_card(vreader, vcard);
861 : 0 : vcard_free(vcard);
862 : : }
863 : 4 : vreader_emul->series = series;
864 : 4 : vreader_emul->present = 1;
865 : 4 : vreader_free(vreader);
866 : 4 : PK11_FreeSlot(slot);
867 : 4 : continue;
868 : : }
869 [ # # ]: 0 : if (vreader_emul->present) {
870 : 0 : vreader_insert_card(vreader, NULL);
871 : : }
872 : 0 : vreader_emul->series = 0;
873 : 0 : vreader_emul->present = 0;
874 : 0 : PK11_FreeSlot(slot);
875 : 0 : vreader_free(vreader);
876 : : } while (1);
877 : 0 : }
878 : :
879 : : /* if the card is inserted when we start up, make sure our state is correct */
880 : : static void
881 : 8 : vcard_emul_init_series(VReader *vreader, G_GNUC_UNUSED VCard *vcard)
882 : : {
883 : 8 : VReaderEmul *vreader_emul = vreader_get_private(vreader);
884 : 8 : PK11SlotInfo *slot = vreader_emul->slot;
885 : :
886 : 8 : vreader_emul->present = PK11_IsPresent(slot);
887 : 8 : vreader_emul->series = PK11_GetSlotSeries(slot);
888 [ - + ]: 8 : if (vreader_emul->present == 0) {
889 : 0 : vreader_insert_card(vreader, NULL);
890 : : }
891 : 8 : }
892 : :
893 : : /*
894 : : * each module has a separate wait call, create a thread for each module that
895 : : * we are using.
896 : : */
897 : : static void
898 : : vcard_emul_new_event_thread(SECMODModule *module)
899 : : {
900 : 2 : PR_CreateThread(PR_SYSTEM_THREAD, vcard_emul_event_thread,
901 : : module, PR_PRIORITY_HIGH, PR_GLOBAL_THREAD,
902 : : PR_UNJOINABLE_THREAD, 0);
903 : 2 : }
904 : :
905 : : static const VCardEmulOptions default_options = {
906 : : .nss_db = NULL,
907 : : .vreader = NULL,
908 : : .vreader_count = 0,
909 : : .hw_card_type = VCARD_EMUL_CAC,
910 : : .hw_type_params = NULL,
911 : : .use_hw = USE_HW_YES,
912 : : };
913 : :
914 : :
915 : : /*
916 : : * NSS needs the app to supply a password prompt. In our case the only time
917 : : * the password is supplied is as part of the Login APDU. The actual password
918 : : * is passed in the pw_arg in that case. In all other cases pw_arg should be
919 : : * NULL.
920 : : */
921 : : static char *
922 : 16 : vcard_emul_get_password(G_GNUC_UNUSED PK11SlotInfo *slot, PRBool retries, void *pw_arg)
923 : : {
924 : : /* if it didn't work the first time, don't keep trying */
925 [ + - ]: 16 : if (retries) {
926 : : return NULL;
927 : : }
928 : : /* we are looking up a password when we don't have one in hand */
929 [ + - ]: 16 : if (pw_arg == NULL) {
930 : : return NULL;
931 : : }
932 : : /* TODO: we really should verify that were are using the right slot */
933 : 16 : return PORT_Strdup(pw_arg);
934 : : }
935 : :
936 : : /* Force a card removal even if the card is not physically removed */
937 : : VCardEmulError
938 : 2 : vcard_emul_force_card_remove(VReader *vreader)
939 : : {
940 [ + - + + ]: 2 : if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) {
941 : 1 : return VCARD_EMUL_FAIL; /* card is already removed */
942 : : }
943 : :
944 : : /* OK, remove it */
945 : 1 : vreader_insert_card(vreader, NULL);
946 : 1 : return VCARD_EMUL_OK;
947 : : }
948 : :
949 : : /* Re-insert of a card that has been removed by force removal */
950 : : VCardEmulError
951 : 2 : vcard_emul_force_card_insert(VReader *vreader)
952 : : {
953 : : VReaderEmul *vreader_emul;
954 : : VCard *vcard;
955 : :
956 [ + - + + ]: 2 : if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) {
957 : 1 : return VCARD_EMUL_FAIL; /* card is already removed */
958 : : }
959 : 1 : vreader_emul = vreader_get_private(vreader);
960 : :
961 : : /* if it's a softcard, get the saved vcard from the reader emul structure */
962 [ + - ]: 1 : if (vreader_emul->saved_vcard) {
963 : 1 : vcard = vcard_reference(vreader_emul->saved_vcard);
964 : : } else {
965 : : /* it must be a physical card, rebuild it */
966 [ # # ]: 0 : if (!PK11_IsPresent(vreader_emul->slot)) {
967 : : /* physical card has been removed, not way to reinsert it */
968 : : return VCARD_EMUL_FAIL;
969 : : }
970 : 0 : vcard = vcard_emul_mirror_card(vreader);
971 : : }
972 : 1 : vreader_insert_card(vreader, vcard);
973 : 1 : vcard_free(vcard);
974 : :
975 : 1 : return VCARD_EMUL_OK;
976 : : }
977 : :
978 : : /* Previously we returned FAIL if no readers found. This makes
979 : : * no sense when using hardware, since there may be no readers connected
980 : : * at the time vcard_emul_init is called, but they will be properly
981 : : * recognized later. So Instead return FAIL only if no_hw==1 and no
982 : : * vcards can be created (indicates error with certificates provided
983 : : * or db), or if any other higher level error (NSS error, missing coolkey). */
984 : : static int vcard_emul_init_called;
985 : : static NSSInitContext *nss_ctx = NULL;
986 : :
987 : : VCardEmulError
988 : 8 : vcard_emul_init(const VCardEmulOptions *options)
989 : : {
990 : : PRBool has_readers = PR_FALSE;
991 : : VReader *vreader;
992 : : VReaderEmul *vreader_emul;
993 : : SECMODListLock *module_lock;
994 : : SECMODModuleList *module_list;
995 : : SECMODModuleList *mlp;
996 : : int i;
997 : : gchar *path = NULL;
998 : : const gchar *nss_db;
999 : :
1000 : 8 : g_debug("%s: called", __func__);
1001 : :
1002 [ + + ]: 8 : if (vcard_emul_init_called) {
1003 : : return VCARD_EMUL_INIT_ALREADY_INITED;
1004 : : }
1005 : 7 : vcard_emul_init_called = 1;
1006 : 7 : vreader_init();
1007 : 7 : vevent_queue_init();
1008 : :
1009 [ - + ]: 7 : if (options == NULL) {
1010 : : options = &default_options;
1011 : : }
1012 : :
1013 : : #if defined(ENABLE_PCSC)
1014 : : if (options->use_hw && options->hw_card_type == VCARD_EMUL_PASSTHRU) {
1015 : : if (options->vreader_count > 0) {
1016 : : fprintf(stderr, "Error: you cannot use a soft card and "
1017 : : "a passthru card simultaneously.\n");
1018 : : return VCARD_EMUL_FAIL;
1019 : : }
1020 : :
1021 : : if (capcsc_init()) {
1022 : : fprintf(stderr, "Error initializing PCSC interface.\n");
1023 : : return VCARD_EMUL_FAIL;
1024 : : }
1025 : :
1026 : : g_debug("%s: returning with passthrough initialized", __func__);
1027 : : return VCARD_EMUL_OK;
1028 : : }
1029 : : #endif
1030 : :
1031 : : /* first initialize NSS */
1032 : 7 : nss_db = options->nss_db;
1033 [ - + ]: 7 : if (nss_db == NULL) {
1034 : : #ifndef _WIN32
1035 : : nss_db = "/etc/pki/nssdb";
1036 : : #else
1037 : : const gchar * const *config_dirs = g_get_system_config_dirs();
1038 : : if (config_dirs == NULL || config_dirs[0] == NULL) {
1039 : : return VCARD_EMUL_FAIL;
1040 : : }
1041 : :
1042 : : path = g_build_filename(config_dirs[0], "pki", "nssdb", NULL);
1043 : : nss_db = path;
1044 : : #endif
1045 : : }
1046 : :
1047 : 7 : nss_ctx = NSS_InitContext(nss_db, "", "", "", NULL, NSS_INIT_READONLY);
1048 [ + + ]: 7 : if (nss_ctx == NULL) {
1049 : 1 : g_debug("%s: NSS_InitContext failed. Does the DB directory '%s' exist?",
1050 : : __func__, nss_db);
1051 : 1 : g_free(path);
1052 : 1 : return VCARD_EMUL_FAIL;
1053 : : }
1054 : 6 : g_free(path);
1055 : : path = NULL;
1056 : :
1057 : : /* Set password callback function */
1058 : 6 : PK11_SetPasswordFunc(vcard_emul_get_password);
1059 : :
1060 : : /* set up soft cards emulated by software certs rather than physical cards
1061 : : * */
1062 [ + + ]: 10 : for (i = 0; i < options->vreader_count; i++) {
1063 : : int j;
1064 : : int cert_count;
1065 : : unsigned char **certs;
1066 : : int *cert_len;
1067 : : VCardKey **keys;
1068 : : PK11SlotInfo *slot;
1069 : :
1070 : 4 : slot = PK11_FindSlotByName(options->vreader[i].name);
1071 [ - + ]: 4 : if (slot == NULL) {
1072 : 0 : continue;
1073 : : }
1074 : 4 : vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type,
1075 : 4 : options->vreader[i].type_params);
1076 : 4 : vreader = vreader_new(options->vreader[i].vname, vreader_emul,
1077 : : vreader_emul_delete);
1078 : 4 : vreader_add_reader(vreader);
1079 : :
1080 : 4 : vcard_emul_alloc_arrays(&certs, &cert_len, &keys,
1081 : 4 : options->vreader[i].cert_count);
1082 : :
1083 : : cert_count = 0;
1084 [ + + ]: 16 : for (j = 0; j < options->vreader[i].cert_count; j++) {
1085 : : /* we should have a better way of identifying certs than by
1086 : : * nickname here */
1087 : 12 : CERTCertificate *cert = PK11_FindCertFromNickname(
1088 : 12 : options->vreader[i].cert_name[j],
1089 : : NULL);
1090 [ - + ]: 12 : if (cert == NULL) {
1091 : 0 : continue;
1092 : : }
1093 : 12 : certs[cert_count] = cert->derCert.data;
1094 : 12 : cert_len[cert_count] = cert->derCert.len;
1095 : 12 : keys[cert_count] = vcard_emul_make_key(slot, cert);
1096 : : /* this is safe because the key is still holding a cert reference */
1097 : 12 : CERT_DestroyCertificate(cert);
1098 : 12 : cert_count++;
1099 : : }
1100 [ + - ]: 4 : if (cert_count) {
1101 : 4 : VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len,
1102 : : keys, cert_count);
1103 : 4 : vreader_insert_card(vreader, vcard);
1104 : 4 : vcard_emul_init_series(vreader, vcard);
1105 : : /* allow insertion and removal of soft cards */
1106 : 4 : vreader_emul->saved_vcard = vcard_reference(vcard);
1107 : 4 : vcard_free(vcard);
1108 : 4 : vreader_free(vreader);
1109 : : has_readers = PR_TRUE;
1110 : : }
1111 : 4 : PK11_FreeSlot(slot);
1112 : 4 : g_free(certs);
1113 : 4 : g_free(cert_len);
1114 : 4 : g_free(keys);
1115 : : }
1116 : :
1117 : : /* if we aren't suppose to use hw, skip looking up hardware tokens */
1118 [ + + ]: 6 : if (!options->use_hw) {
1119 : 4 : nss_emul_init = has_readers;
1120 : 4 : g_debug("%s: returning: Not using HW", __func__);
1121 : 4 : return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL;
1122 : : }
1123 : :
1124 : : /* make sure we have some PKCS #11 module loaded */
1125 : 2 : module_lock = SECMOD_GetDefaultModuleListLock();
1126 : 2 : module_list = SECMOD_GetDefaultModuleList();
1127 : :
1128 : : /* now examine all the slots, finding which should be readers */
1129 : : /* We should control this with options. For now we mirror out any
1130 : : * removable hardware slot */
1131 : 2 : default_card_type = options->hw_card_type;
1132 [ - + ]: 2 : default_type_params = g_strdup(options->hw_type_params);
1133 : :
1134 : 2 : SECMOD_GetReadLock(module_lock);
1135 [ + + ]: 6 : for (mlp = module_list; mlp; mlp = mlp->next) {
1136 : 4 : SECMODModule *module = mlp->module;
1137 : :
1138 : : /* Ignore the internal module */
1139 [ + - + + ]: 4 : if (module == NULL || module == SECMOD_GetInternalModule()) {
1140 : 2 : continue;
1141 : : }
1142 : :
1143 : 2 : g_debug("%s: Listing modules, trying %s", __func__, module->commonName);
1144 [ + + ]: 6 : for (i = 0; i < module->slotCount; i++) {
1145 : 4 : PK11SlotInfo *slot = module->slots[i];
1146 : :
1147 : : /* only map removable HW slots */
1148 [ + - + - ]: 4 : if (slot == NULL || !PK11_IsRemovable(slot) ||
1149 [ - + - - ]: 4 : (options->use_hw == USE_HW_YES && !PK11_IsHW(slot))) {
1150 : 0 : continue;
1151 : : }
1152 [ - + ]: 4 : if (strcmp("E-Gate 0 0", PK11_GetSlotName(slot)) == 0) {
1153 : : /*
1154 : : * coolkey <= 1.1.0-20 emulates this reader if it can't find
1155 : : * any hardware readers. This causes problems, warn user of
1156 : : * problems.
1157 : : */
1158 : 0 : fprintf(stderr, "known bad coolkey version - see "
1159 : : "https://bugzilla.redhat.com/show_bug.cgi?id=802435\n");
1160 : 0 : continue;
1161 : : }
1162 : 4 : vreader_emul = vreader_emul_new(slot, options->hw_card_type,
1163 : 4 : options->hw_type_params);
1164 : 4 : vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
1165 : : vreader_emul_delete);
1166 : 4 : vreader_add_reader(vreader);
1167 : 4 : g_debug("%s: Added reader from slot %s", __func__,
1168 : : PK11_GetSlotName(slot));
1169 : :
1170 [ + - ]: 4 : if (PK11_IsPresent(slot)) {
1171 : : VCard *vcard;
1172 : 4 : vcard = vcard_emul_mirror_card(vreader);
1173 : 4 : vreader_insert_card(vreader, vcard);
1174 : 4 : vcard_emul_init_series(vreader, vcard);
1175 : 4 : g_debug("%s: Added card to the reader %s", __func__,
1176 : : vreader_get_name(vreader));
1177 : 4 : vcard_free(vcard);
1178 : : }
1179 : 4 : vreader_free(vreader);
1180 : : }
1181 : : vcard_emul_new_event_thread(module);
1182 : : }
1183 : 2 : SECMOD_ReleaseReadLock(module_lock);
1184 : 2 : nss_emul_init = PR_TRUE;
1185 : :
1186 : 2 : return VCARD_EMUL_OK;
1187 : : }
1188 : :
1189 : : /* Recreate card insert events for all readers (user should
1190 : : * deduce implied reader insert. perhaps do a reader insert as well?)
1191 : : */
1192 : : void
1193 : 0 : vcard_emul_replay_insertion_events(void)
1194 : : {
1195 : : VReaderListEntry *current_entry;
1196 : : VReaderListEntry *next_entry;
1197 : 0 : VReaderList *list = vreader_get_reader_list();
1198 : :
1199 [ # # ]: 0 : for (current_entry = vreader_list_get_first(list); current_entry;
1200 : : current_entry = next_entry) {
1201 : 0 : VReader *vreader = vreader_list_get_reader(current_entry);
1202 : 0 : next_entry = vreader_list_get_next(current_entry);
1203 : 0 : vreader_queue_card_event(vreader);
1204 : : }
1205 : :
1206 : 0 : vreader_list_delete(list);
1207 : 0 : }
1208 : :
1209 : : VCardEmulError
1210 : 5 : vcard_emul_finalize(void)
1211 : : {
1212 : : SECStatus rv;
1213 : :
1214 : 5 : rv = NSS_ShutdownContext(nss_ctx);
1215 [ + + ]: 5 : if (rv != SECSuccess) {
1216 : 2 : g_debug("%s: NSS_ShutdownContext failed.", __func__);
1217 : 2 : return VCARD_EMUL_FAIL;
1218 : : }
1219 : 3 : nss_ctx = NULL;
1220 : :
1221 : 3 : return VCARD_EMUL_OK;
1222 : : }
1223 : :
1224 : : /*
1225 : : * Silly little functions to help parsing our argument string
1226 : : */
1227 : : static int
1228 : : count_tokens(const char *str, char token, char token_end)
1229 : : {
1230 : : int count = 0;
1231 : :
1232 [ + - ]: 90 : for (; *str; str++) {
1233 [ + + ]: 90 : if (*str == token) {
1234 : 10 : count++;
1235 : : }
1236 [ + + ]: 90 : if (*str == token_end) {
1237 : : break;
1238 : : }
1239 : : }
1240 : : return count;
1241 : : }
1242 : :
1243 : : static const char *
1244 : 83 : strip(const char *str)
1245 : : {
1246 [ + + + + ]: 97 : for (; *str && isspace(*str); str++) {
1247 : : }
1248 : 83 : return str;
1249 : : }
1250 : :
1251 : : static const char *
1252 : 8 : find_blank(const char *str)
1253 : : {
1254 [ + + + + ]: 45 : for (; *str && !isspace(*str); str++) {
1255 : : }
1256 : 8 : return str;
1257 : : }
1258 : :
1259 : :
1260 : : /*
1261 : : * We really want to use some existing argument parsing library here. That
1262 : : * would give us a consistent look */
1263 : : static VCardEmulOptions options;
1264 : : #define READER_STEP 4
1265 : :
1266 : : /* Expects "args" to be at the beginning of a token (ie right after the ','
1267 : : * ending the previous token), and puts the next token start in "token",
1268 : : * and its length in "token_length". "token" will not be nul-terminated.
1269 : : * After calling the macro, "args" will be advanced to the beginning of
1270 : : * the next token.
1271 : : */
1272 : : #define NEXT_TOKEN(token) \
1273 : : (token) = args; \
1274 : : args = strpbrk(args, ",)"); \
1275 : : if (args == NULL || *args == 0 || *args == ')') { \
1276 : : fprintf(stderr, "Error: invalid soft specification.\n"); \
1277 : : goto fail; \
1278 : : } \
1279 : : (token##_length) = args - (token); \
1280 : : args = strip(args+1);
1281 : :
1282 : : VCardEmulOptions *
1283 : 8 : vcard_emul_options(const char *args)
1284 : : {
1285 : : int i, j, reader_count = 0;
1286 : : VCardEmulOptions *opts;
1287 : :
1288 : : /* Allow the future use of allocating the options structure on the fly */
1289 : 8 : memcpy(&options, &default_options, sizeof(options));
1290 : : opts = &options;
1291 : :
1292 : : do {
1293 : 22 : args = strip(args); /* strip off the leading spaces */
1294 [ - + ]: 22 : if (*args == ',') {
1295 : 0 : args++;
1296 : 0 : continue;
1297 : : }
1298 : : /* soft=(slot_name,virt_name,emul_type,emul_flags,cert_1, (no eol)
1299 : : * cert_2,cert_3...) */
1300 [ + + ]: 22 : if (strncmp(args, "soft=", 5) == 0) {
1301 : : const char *name;
1302 : : size_t name_length;
1303 : : const char *vname;
1304 : : size_t vname_length;
1305 : : const char *type_params;
1306 : : size_t type_params_length;
1307 : : char type_str[100];
1308 : : VCardEmulType type;
1309 : : int count;
1310 : : VirtualReaderOptions *vreaderOpt;
1311 : :
1312 : 5 : args = strip(args + 5);
1313 [ - + ]: 5 : if (*args != '(') {
1314 : 0 : fprintf(stderr, "Error: invalid soft specification.\n");
1315 : 0 : goto fail;
1316 : : }
1317 : 5 : args = strip(args+1);
1318 : :
1319 [ + - + - : 5 : NEXT_TOKEN(name)
- + ]
1320 [ + - + - : 5 : NEXT_TOKEN(vname)
- + ]
1321 [ + - + - : 5 : NEXT_TOKEN(type_params)
- + ]
1322 : 5 : type_params_length = MIN(type_params_length, sizeof(type_str)-1);
1323 : 5 : memcpy(type_str, type_params, type_params_length);
1324 : 5 : type_str[type_params_length] = '\0';
1325 : 5 : type = vcard_emul_type_from_string(type_str);
1326 [ - + ]: 5 : if (type == VCARD_EMUL_NONE) {
1327 : 0 : fprintf(stderr, "Error: invalid smartcard type '%s'.\n",
1328 : : type_str);
1329 : 0 : goto fail;
1330 : : }
1331 : :
1332 [ + - + - : 5 : NEXT_TOKEN(type_params)
- + ]
1333 : :
1334 [ - + ]: 5 : if (*args == 0) {
1335 : 0 : fprintf(stderr, "Error: missing cert specification.\n");
1336 : 0 : goto fail;
1337 : : }
1338 : :
1339 [ + - ]: 5 : if (opts->vreader_count >= reader_count) {
1340 : 5 : reader_count += READER_STEP;
1341 [ - + - - ]: 5 : opts->vreader = g_renew(VirtualReaderOptions, opts->vreader,
1342 : : reader_count);
1343 : : }
1344 : 5 : vreaderOpt = &opts->vreader[opts->vreader_count];
1345 : 5 : vreaderOpt->name = g_strndup(name, name_length);
1346 : 5 : vreaderOpt->vname = g_strndup(vname, vname_length);
1347 : 5 : vreaderOpt->card_type = type;
1348 : 5 : vreaderOpt->type_params =
1349 : 5 : g_strndup(type_params, type_params_length);
1350 : 5 : count = count_tokens(args, ',', ')') + 1;
1351 : 5 : vreaderOpt->cert_count = count;
1352 [ - + - - ]: 5 : vreaderOpt->cert_name = g_new(char *, count);
1353 [ + + ]: 20 : for (i = 0; i < count; i++) {
1354 : : const char *cert = args;
1355 : 15 : args = strpbrk(args, ",)");
1356 : 15 : vreaderOpt->cert_name[i] = g_strndup(cert, args - cert);
1357 : 15 : args = strip(args+1);
1358 : : }
1359 [ - + ]: 5 : if (*args == ')') {
1360 : 0 : args++;
1361 : : }
1362 : 5 : opts->vreader_count++;
1363 : : /* use_hw= */
1364 [ + + ]: 17 : } else if (strncmp(args, "use_hw=", 7) == 0) {
1365 : 8 : args = strip(args+7);
1366 [ + + ]: 8 : if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') {
1367 : 5 : opts->use_hw = USE_HW_NO;
1368 [ + - ]: 3 : } else if (strncmp(args, "removable", 9) == 0) {
1369 : 3 : opts->use_hw = USE_HW_REMOVABLE;
1370 : : } else {
1371 : 0 : opts->use_hw = USE_HW_YES;
1372 : : }
1373 : 8 : args = find_blank(args);
1374 : : /* hw_type= */
1375 [ - + ]: 9 : } else if (strncmp(args, "hw_type=", 8) == 0) {
1376 : 0 : args = strip(args+8);
1377 : 0 : opts->hw_card_type = vcard_emul_type_from_string(args);
1378 [ # # ]: 0 : if (opts->hw_card_type == VCARD_EMUL_NONE) {
1379 : 0 : fprintf(stderr, "Error: invalid smartcard type '%s'.\n",
1380 : : args);
1381 : 0 : goto fail;
1382 : : }
1383 : 0 : args = find_blank(args);
1384 : : /* hw_params= */
1385 [ - + ]: 9 : } else if (strncmp(args, "hw_params=", 10) == 0) {
1386 : : const char *params;
1387 : :
1388 [ # # ]: 0 : if (opts->hw_type_params != NULL) {
1389 : 0 : fprintf(stderr, "Error: redefinition of hw_params= is not allowed.\n");
1390 : 0 : goto fail;
1391 : : }
1392 : 0 : args = strip(args+10);
1393 : : params = args;
1394 : 0 : args = find_blank(args);
1395 : 0 : opts->hw_type_params = g_strndup(params, args-params);
1396 : : /* db="/data/base/path" */
1397 [ + + ]: 9 : } else if (strncmp(args, "db=", 3) == 0) {
1398 : : const char *db;
1399 : :
1400 [ - + ]: 8 : if (opts->nss_db != NULL) {
1401 : 0 : fprintf(stderr, "Error: redefinition of db= is not allowed.\n");
1402 : 0 : goto fail;
1403 : : }
1404 : 8 : args = strip(args+3);
1405 [ - + ]: 8 : if (*args != '"') {
1406 : 0 : fprintf(stderr, "Error: you must quote the file path.\n");
1407 : 0 : goto fail;
1408 : : }
1409 : 8 : args++;
1410 : : db = args;
1411 : 8 : args = strpbrk(args, "\"\n");
1412 [ - + ]: 8 : if (args == NULL) {
1413 : 0 : fprintf(stderr, "Error: invalid db argument.\n");
1414 : 0 : goto fail;
1415 : : }
1416 : 8 : opts->nss_db = g_strndup(db, args-db);
1417 [ + - ]: 8 : if (*args != 0) {
1418 : 8 : args++;
1419 : : }
1420 [ - + ]: 1 : } else if (strncmp(args, "nssemul", 7) == 0) {
1421 : 0 : opts->hw_card_type = VCARD_EMUL_CAC;
1422 : 0 : opts->use_hw = USE_HW_YES;
1423 : 0 : args = find_blank(args + 7);
1424 : : #if defined(ENABLE_PCSC)
1425 : : } else if (strncmp(args, "passthru", 8) == 0) {
1426 : : opts->hw_card_type = VCARD_EMUL_PASSTHRU;
1427 : : opts->use_hw = USE_HW_YES;
1428 : : args = find_blank(args + 8);
1429 : : #endif
1430 : : } else {
1431 : 1 : fprintf(stderr, "Error: Unknown smartcard specification.\n");
1432 : 1 : goto fail;
1433 : : }
1434 [ + + ]: 21 : } while (*args != 0);
1435 : :
1436 : : return opts;
1437 : :
1438 : : fail:
1439 : : /* Clean up what was allocated above on failure */
1440 [ - + ]: 1 : for (i = 0; i < opts->vreader_count; i++) {
1441 : 0 : g_free(opts->vreader[i].name);
1442 : 0 : g_free(opts->vreader[i].vname);
1443 : 0 : g_free(opts->vreader[i].type_params);
1444 [ # # ]: 0 : for (j = 0; j < opts->vreader[i].cert_count; j++) {
1445 : 0 : g_free(opts->vreader[i].cert_name[j]);
1446 : : }
1447 : 0 : g_free(opts->vreader[i].cert_name);
1448 : : }
1449 : 1 : g_free(opts->vreader);
1450 : 1 : g_free(opts->hw_type_params);
1451 : 1 : g_free(opts->nss_db);
1452 : 1 : return NULL;
1453 : : }
1454 : :
1455 : : unsigned char *
1456 : 6 : vcard_emul_read_object(VCard *card, const char *label,
1457 : : unsigned int *ret_len)
1458 : : {
1459 : : PK11SlotInfo *slot;
1460 : : PK11GenericObject *obj, *firstObj, *myObj = NULL;
1461 : : SECItem result;
1462 : : SECStatus r;
1463 : : unsigned char *ret;
1464 : :
1465 : : slot = vcard_emul_card_get_slot(card);
1466 : :
1467 : 6 : firstObj = PK11_FindGenericObjects(slot, CKO_DATA);
1468 : 6 : g_debug("%s: Search for generic objects: got %p", __func__, firstObj);
1469 [ - + ]: 6 : for (obj = firstObj; obj; obj = PK11_GetNextGenericObject(obj)) {
1470 : : int found = 0;
1471 : 0 : r = PK11_ReadRawAttribute(PK11_TypeGeneric, obj,
1472 : : CKA_LABEL, &result);
1473 [ # # ]: 0 : if (r != SECSuccess) {
1474 : 0 : PK11_DestroyGenericObjects(firstObj);
1475 : 0 : return NULL;
1476 : : }
1477 : :
1478 [ # # ]: 0 : if (strlen(label) == result.len
1479 [ # # ]: 0 : && memcmp(label, result.data, result.len) == 0)
1480 : : found = 1;
1481 : :
1482 : 0 : PORT_Free(result.data);
1483 : 0 : result.data = NULL;
1484 : :
1485 [ # # ]: 0 : if (found) {
1486 : 0 : PK11_UnlinkGenericObject(obj);
1487 : : myObj = obj;
1488 : 0 : break;
1489 : : }
1490 : : }
1491 : 6 : PK11_DestroyGenericObjects(firstObj);
1492 : :
1493 [ + - ]: 6 : if (!myObj)
1494 : : return NULL;
1495 : :
1496 : 0 : r = PK11_ReadRawAttribute(PK11_TypeGeneric, myObj,
1497 : : CKA_VALUE, &result);
1498 : 0 : PK11_DestroyGenericObject(myObj);
1499 [ # # ]: 0 : if (r != SECSuccess)
1500 : : return NULL;
1501 : :
1502 : 0 : *ret_len = result.len;
1503 : 0 : ret = g_memdup2(result.data, result.len);
1504 : 0 : PORT_Free(result.data);
1505 : 0 : return ret;
1506 : : }
1507 : :
1508 : : void
1509 : 0 : vcard_emul_usage(void)
1510 : : {
1511 : 0 : fprintf(stderr,
1512 : : "emul args: comma separated list of the following arguments\n"
1513 : : " db={nss_database} (default sql:/etc/pki/nssdb)\n"
1514 : : " use_hw=[yes|no|removable] (default yes)\n"
1515 : : " hw_type={card_type_to_emulate} (default CAC)\n"
1516 : : " hw_params={param_for_card} (default \"\")\n"
1517 : : " nssemul (alias for use_hw=yes, hw_type=CAC)\n"
1518 : : #if defined(ENABLE_PCSC)
1519 : : " passthru (alias for use_hw=yes, hw_type=PASSTHRU)\n"
1520 : : #endif
1521 : : " soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n"
1522 : : " {cert1},{cert2},{cert3} (default none)\n"
1523 : : "\n"
1524 : : " {nss_database} The location of the NSS cert & key database\n"
1525 : : " {card_type_to_emulate} What card interface to present to the guest\n"
1526 : : " {param_for_card} Card interface specific parameters\n"
1527 : : " {slot_name} NSS slot that contains the certs\n"
1528 : : " {vreader_name} Virtual reader name to present to the guest\n"
1529 : : " {certN} Nickname of the certificate n on the virtual card\n"
1530 : : "\n"
1531 : : "These parameters come as a single string separated by blanks or newlines."
1532 : : "\n"
1533 : : "Unless use_hw is set to no, all tokens that look like removable hardware\n"
1534 : : "tokens will be presented to the guest using the emulator specified by\n"
1535 : : "hw_type, and parameters of hw_params. If use_hw is set to 'removable', "
1536 : : "present any removable token.\n"
1537 : : "\n"
1538 : : "If more one or more soft= parameters are specified, these readers will be\n"
1539 : : "presented to the guest\n"
1540 : : #if defined(ENABLE_PCSC)
1541 : : "\n"
1542 : : "If a hw_type of PASSTHRU is given, a connection will be made to the hardware\n"
1543 : : "using libpcscslite. Note that in that case, no soft cards are permitted.\n"
1544 : : #endif
1545 : : );
1546 : 0 : }
1547 : : /* vim: set ts=4 sw=4 tw=0 noet expandtab: */
|