Store VNC auth scheme per-client as well as per-server
[qemu/ar7.git] / libcacard / vcard_emul_nss.c
blobf3db657d749900058978749c0a56b78c3fc219a1
1 /*
2 * This is the actual card emulator.
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.
9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10 * See the COPYING.LIB file in the top-level directory.
14 * NSS headers
17 /* avoid including prototypes.h that redefines uint32 */
18 #define NO_NSPR_10_SUPPORT
20 #include <nss.h>
21 #include <pk11pub.h>
22 #include <cert.h>
23 #include <key.h>
24 #include <secmod.h>
25 #include <prthread.h>
26 #include <secerr.h>
28 #include "qemu-common.h"
30 #include "vcard.h"
31 #include "card_7816t.h"
32 #include "vcard_emul.h"
33 #include "vreader.h"
34 #include "vevent.h"
36 struct VCardKeyStruct {
37 CERTCertificate *cert;
38 PK11SlotInfo *slot;
39 SECKEYPrivateKey *key;
43 typedef struct VirtualReaderOptionsStruct VirtualReaderOptions;
45 struct VReaderEmulStruct {
46 PK11SlotInfo *slot;
47 VCardEmulType default_type;
48 char *type_params;
49 PRBool present;
50 int series;
51 VCard *saved_vcard;
55 * NSS Specific options
57 struct VirtualReaderOptionsStruct {
58 char *name;
59 char *vname;
60 VCardEmulType card_type;
61 char *type_params;
62 char **cert_name;
63 int cert_count;
66 struct VCardEmulOptionsStruct {
67 void *nss_db;
68 VirtualReaderOptions *vreader;
69 int vreader_count;
70 VCardEmulType hw_card_type;
71 const char *hw_type_params;
72 PRBool use_hw;
75 static int nss_emul_init;
77 /* if we have more that just the slot, define
78 * VCardEmulStruct here */
81 * allocate the set of arrays for certs, cert_len, key
83 static PRBool
84 vcard_emul_alloc_arrays(unsigned char ***certsp, int **cert_lenp,
85 VCardKey ***keysp, int cert_count)
87 *certsp = NULL;
88 *cert_lenp = NULL;
89 *keysp = NULL;
90 *certsp = (unsigned char **)qemu_malloc(sizeof(unsigned char *)*cert_count);
91 *cert_lenp = (int *)qemu_malloc(sizeof(int)*cert_count);
92 *keysp = (VCardKey **)qemu_malloc(sizeof(VCardKey *)*cert_count);
93 return PR_TRUE;
97 * Emulator specific card information
99 typedef struct CardEmulCardStruct CardEmulPrivate;
101 static VCardEmul *
102 vcard_emul_new_card(PK11SlotInfo *slot)
104 PK11_ReferenceSlot(slot);
105 /* currently we don't need anything other than the slot */
106 return (VCardEmul *)slot;
109 static void
110 vcard_emul_delete_card(VCardEmul *vcard_emul)
112 PK11SlotInfo *slot = (PK11SlotInfo *)vcard_emul;
113 if (slot == NULL) {
114 return;
116 PK11_FreeSlot(slot);
119 static PK11SlotInfo *
120 vcard_emul_card_get_slot(VCard *card)
122 /* note, the card is holding the reference, no need to get another one */
123 return (PK11SlotInfo *)vcard_get_private(card);
128 * key functions
130 /* private constructure */
131 static VCardKey *
132 vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert)
134 VCardKey *key;
136 key = (VCardKey *)qemu_malloc(sizeof(VCardKey));
137 key->slot = PK11_ReferenceSlot(slot);
138 key->cert = CERT_DupCertificate(cert);
139 /* NOTE: if we aren't logged into the token, this could return NULL */
140 /* NOTE: the cert is a temp cert, not necessarily the cert in the token,
141 * use the DER version of this function */
142 key->key = PK11_FindKeyByDERCert(slot, cert, NULL);
143 return key;
146 /* destructor */
147 void
148 vcard_emul_delete_key(VCardKey *key)
150 if (!nss_emul_init || (key == NULL)) {
151 return;
153 if (key->key) {
154 SECKEY_DestroyPrivateKey(key->key);
155 key->key = NULL;
157 if (key->cert) {
158 CERT_DestroyCertificate(key->cert);
160 if (key->slot) {
161 PK11_FreeSlot(key->slot);
163 return;
167 * grab the nss key from a VCardKey. If it doesn't exist, try to look it up
169 static SECKEYPrivateKey *
170 vcard_emul_get_nss_key(VCardKey *key)
172 if (key->key) {
173 return key->key;
175 /* NOTE: if we aren't logged into the token, this could return NULL */
176 key->key = PK11_FindPrivateKeyFromCert(key->slot, key->cert, NULL);
177 return key->key;
181 * Map NSS errors to 7816 errors
183 static vcard_7816_status_t
184 vcard_emul_map_error(int error)
186 switch (error) {
187 case SEC_ERROR_TOKEN_NOT_LOGGED_IN:
188 return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
189 case SEC_ERROR_BAD_DATA:
190 case SEC_ERROR_OUTPUT_LEN:
191 case SEC_ERROR_INPUT_LEN:
192 case SEC_ERROR_INVALID_ARGS:
193 case SEC_ERROR_INVALID_ALGORITHM:
194 case SEC_ERROR_NO_KEY:
195 case SEC_ERROR_INVALID_KEY:
196 case SEC_ERROR_DECRYPTION_DISALLOWED:
197 return VCARD7816_STATUS_ERROR_DATA_INVALID;
198 case SEC_ERROR_NO_MEMORY:
199 return VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE;
201 return VCARD7816_STATUS_EXC_ERROR_CHANGE;
204 /* RSA sign/decrypt with the key, signature happens 'in place' */
205 vcard_7816_status_t
206 vcard_emul_rsa_op(VCard *card, VCardKey *key,
207 unsigned char *buffer, int buffer_size)
209 SECKEYPrivateKey *priv_key;
210 unsigned signature_len;
211 SECStatus rv;
213 if ((!nss_emul_init) || (key == NULL)) {
214 /* couldn't get the key, indicate that we aren't logged in */
215 return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
217 priv_key = vcard_emul_get_nss_key(key);
220 * this is only true of the rsa signature
222 signature_len = PK11_SignatureLen(priv_key);
223 if (buffer_size != signature_len) {
224 return VCARD7816_STATUS_ERROR_DATA_INVALID;
226 rv = PK11_PrivDecryptRaw(priv_key, buffer, &signature_len, signature_len,
227 buffer, buffer_size);
228 if (rv != SECSuccess) {
229 return vcard_emul_map_error(PORT_GetError());
231 assert(buffer_size == signature_len);
232 return VCARD7816_STATUS_SUCCESS;
236 * Login functions
238 /* return the number of login attempts still possible on the card. if unknown,
239 * return -1 */
241 vcard_emul_get_login_count(VCard *card)
243 return -1;
246 /* login into the card, return the 7816 status word (sw2 || sw1) */
247 vcard_7816_status_t
248 vcard_emul_login(VCard *card, unsigned char *pin, int pin_len)
250 PK11SlotInfo *slot;
251 unsigned char *pin_string = NULL;
252 int i;
253 SECStatus rv;
255 if (!nss_emul_init) {
256 return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
258 slot = vcard_emul_card_get_slot(card);
259 /* We depend on the PKCS #11 module internal login state here because we
260 * create a separate process to handle each guest instance. If we needed
261 * to handle multiple guests from one process, then we would need to keep
262 * a lot of extra state in our card structure
263 * */
264 pin_string = qemu_malloc(pin_len+1);
265 memcpy(pin_string, pin, pin_len);
266 pin_string[pin_len] = 0;
268 /* handle CAC expanded pins correctly */
269 for (i = pin_len-1; i >= 0 && (pin_string[i] == 0xff); i--) {
270 pin_string[i] = 0;
273 rv = PK11_Authenticate(slot, PR_FALSE, pin_string);
274 memset(pin_string, 0, pin_len); /* don't let the pin hang around in memory
275 to be snooped */
276 qemu_free(pin_string);
277 if (rv == SECSuccess) {
278 return VCARD7816_STATUS_SUCCESS;
280 /* map the error from port get error */
281 return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
284 void
285 vcard_emul_reset(VCard *card, VCardPower power)
287 PK11SlotInfo *slot;
289 if (!nss_emul_init) {
290 return;
294 * if we reset the card (either power on or power off), we lose our login
295 * state
297 /* TODO: we may also need to send insertion/removal events? */
298 slot = vcard_emul_card_get_slot(card);
299 PK11_Logout(slot); /* NOTE: ignoring SECStatus return value */
300 return;
304 static VReader *
305 vcard_emul_find_vreader_from_slot(PK11SlotInfo *slot)
307 VReaderList *reader_list = vreader_get_reader_list();
308 VReaderListEntry *current_entry = NULL;
310 if (reader_list == NULL) {
311 return NULL;
313 for (current_entry = vreader_list_get_first(reader_list); current_entry;
314 current_entry = vreader_list_get_next(current_entry)) {
315 VReader *reader = vreader_list_get_reader(current_entry);
316 VReaderEmul *reader_emul = vreader_get_private(reader);
317 if (reader_emul->slot == slot) {
318 return reader;
320 vreader_free(reader);
323 return NULL;
327 * create a new reader emul
329 static VReaderEmul *
330 vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params)
332 VReaderEmul *new_reader_emul;
334 new_reader_emul = (VReaderEmul *)qemu_malloc(sizeof(VReaderEmul));
336 new_reader_emul->slot = PK11_ReferenceSlot(slot);
337 new_reader_emul->default_type = type;
338 new_reader_emul->type_params = strdup(params);
339 new_reader_emul->present = PR_FALSE;
340 new_reader_emul->series = 0;
341 new_reader_emul->saved_vcard = NULL;
342 return new_reader_emul;
345 static void
346 vreader_emul_delete(VReaderEmul *vreader_emul)
348 if (vreader_emul == NULL) {
349 return;
351 if (vreader_emul->slot) {
352 PK11_FreeSlot(vreader_emul->slot);
354 if (vreader_emul->type_params) {
355 qemu_free(vreader_emul->type_params);
357 qemu_free(vreader_emul);
361 * TODO: move this to emulater non-specific file
363 static VCardEmulType
364 vcard_emul_get_type(VReader *vreader)
366 VReaderEmul *vreader_emul;
368 vreader_emul = vreader_get_private(vreader);
369 if (vreader_emul && vreader_emul->default_type != VCARD_EMUL_NONE) {
370 return vreader_emul->default_type;
373 return vcard_emul_type_select(vreader);
376 * TODO: move this to emulater non-specific file
378 static const char *
379 vcard_emul_get_type_params(VReader *vreader)
381 VReaderEmul *vreader_emul;
383 vreader_emul = vreader_get_private(vreader);
384 if (vreader_emul && vreader_emul->type_params) {
385 return vreader_emul->type_params;
388 return "";
391 /* pull the slot out of the reader private data */
392 static PK11SlotInfo *
393 vcard_emul_reader_get_slot(VReader *vreader)
395 VReaderEmul *vreader_emul = vreader_get_private(vreader);
396 if (vreader_emul == NULL) {
397 return NULL;
399 return vreader_emul->slot;
403 * Card ATR's map to physical cards. VCARD_ATR_PREFIX will set appropriate
404 * historical bytes for any software emulated card. The remaining bytes can be
405 * used to indicate the actual emulator
407 static const unsigned char nss_atr[] = { VCARD_ATR_PREFIX(3), 'N', 'S', 'S' };
409 void
410 vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len)
412 int len = MIN(sizeof(nss_atr), *atr_len);
413 assert(atr != NULL);
415 memcpy(atr, nss_atr, len);
416 *atr_len = len;
417 return;
421 * create a new card from certs and keys
423 static VCard *
424 vcard_emul_make_card(VReader *reader,
425 unsigned char * const *certs, int *cert_len,
426 VCardKey *keys[], int cert_count)
428 VCardEmul *vcard_emul;
429 VCard *vcard;
430 PK11SlotInfo *slot;
431 VCardEmulType type;
432 const char *params;
434 type = vcard_emul_get_type(reader);
436 /* ignore the inserted card */
437 if (type == VCARD_EMUL_NONE) {
438 return NULL;
440 slot = vcard_emul_reader_get_slot(reader);
441 if (slot == NULL) {
442 return NULL;
445 params = vcard_emul_get_type_params(reader);
446 /* params these can be NULL */
448 vcard_emul = vcard_emul_new_card(slot);
449 if (vcard_emul == NULL) {
450 return NULL;
452 vcard = vcard_new(vcard_emul, vcard_emul_delete_card);
453 if (vcard == NULL) {
454 vcard_emul_delete_card(vcard_emul);
455 return NULL;
457 vcard_init(reader, vcard, type, params, certs, cert_len, keys, cert_count);
458 return vcard;
463 * 'clone' a physical card as a virtual card
465 static VCard *
466 vcard_emul_mirror_card(VReader *vreader)
469 * lookup certs using the C_FindObjects. The Stan Cert handle won't give
470 * us the real certs until we log in.
472 PK11GenericObject *firstObj, *thisObj;
473 int cert_count;
474 unsigned char **certs;
475 int *cert_len;
476 VCardKey **keys;
477 PK11SlotInfo *slot;
478 PRBool ret;
480 slot = vcard_emul_reader_get_slot(vreader);
481 if (slot == NULL) {
482 return NULL;
485 firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE);
486 if (firstObj == NULL) {
487 return NULL;
490 /* count the certs */
491 cert_count = 0;
492 for (thisObj = firstObj; thisObj;
493 thisObj = PK11_GetNextGenericObject(thisObj)) {
494 cert_count++;
497 if (cert_count == 0) {
498 PK11_DestroyGenericObjects(firstObj);
499 return NULL;
502 /* allocate the arrays */
503 ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count);
504 if (ret == PR_FALSE) {
505 return NULL;
508 /* fill in the arrays */
509 cert_count = 0;
510 for (thisObj = firstObj; thisObj;
511 thisObj = PK11_GetNextGenericObject(thisObj)) {
512 SECItem derCert;
513 CERTCertificate *cert;
514 SECStatus rv;
516 rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj,
517 CKA_VALUE, &derCert);
518 if (rv != SECSuccess) {
519 continue;
521 /* create floating temp cert. This gives us a cert structure even if
522 * the token isn't logged in */
523 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert,
524 NULL, PR_FALSE, PR_TRUE);
525 SECITEM_FreeItem(&derCert, PR_FALSE);
526 if (cert == NULL) {
527 continue;
530 certs[cert_count] = cert->derCert.data;
531 cert_len[cert_count] = cert->derCert.len;
532 keys[cert_count] = vcard_emul_make_key(slot, cert);
533 cert_count++;
534 CERT_DestroyCertificate(cert); /* key obj still has a reference */
537 /* now create the card */
538 return vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count);
541 static VCardEmulType default_card_type = VCARD_EMUL_NONE;
542 static const char *default_type_params = "";
545 * This thread looks for card and reader insertions and puts events on the
546 * event queue
548 static void
549 vcard_emul_event_thread(void *arg)
551 PK11SlotInfo *slot;
552 VReader *vreader;
553 VReaderEmul *vreader_emul;
554 VCard *vcard;
555 SECMODModule *module = (SECMODModule *)arg;
557 do {
558 slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500);
559 if (slot == NULL) {
560 break;
562 vreader = vcard_emul_find_vreader_from_slot(slot);
563 if (vreader == NULL) {
564 /* new vreader */
565 vreader_emul = vreader_emul_new(slot, default_card_type,
566 default_type_params);
567 vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
568 vreader_emul_delete);
569 PK11_FreeSlot(slot);
570 slot = NULL;
571 vreader_add_reader(vreader);
572 vreader_free(vreader);
573 continue;
575 /* card remove/insert */
576 vreader_emul = vreader_get_private(vreader);
577 if (PK11_IsPresent(slot)) {
578 int series = PK11_GetSlotSeries(slot);
579 if (series != vreader_emul->series) {
580 if (vreader_emul->present) {
581 vreader_insert_card(vreader, NULL);
583 vcard = vcard_emul_mirror_card(vreader);
584 vreader_insert_card(vreader, vcard);
585 vcard_free(vcard);
587 vreader_emul->series = series;
588 vreader_emul->present = 1;
589 vreader_free(vreader);
590 PK11_FreeSlot(slot);
591 continue;
593 if (vreader_emul->present) {
594 vreader_insert_card(vreader, NULL);
596 vreader_emul->series = 0;
597 vreader_emul->present = 0;
598 PK11_FreeSlot(slot);
599 vreader_free(vreader);
600 } while (1);
603 /* if the card is inserted when we start up, make sure our state is correct */
604 static void
605 vcard_emul_init_series(VReader *vreader, VCard *vcard)
607 VReaderEmul *vreader_emul = vreader_get_private(vreader);
608 PK11SlotInfo *slot = vreader_emul->slot;
610 vreader_emul->present = PK11_IsPresent(slot);
611 vreader_emul->series = PK11_GetSlotSeries(slot);
612 if (vreader_emul->present == 0) {
613 vreader_insert_card(vreader, NULL);
618 * each module has a separate wait call, create a thread for each module that
619 * we are using.
621 static void
622 vcard_emul_new_event_thread(SECMODModule *module)
624 PR_CreateThread(PR_SYSTEM_THREAD, vcard_emul_event_thread,
625 module, PR_PRIORITY_HIGH, PR_GLOBAL_THREAD,
626 PR_UNJOINABLE_THREAD, 0);
629 static const VCardEmulOptions default_options = {
630 .nss_db = NULL,
631 .vreader = NULL,
632 .vreader_count = 0,
633 .hw_card_type = VCARD_EMUL_CAC,
634 .hw_type_params = "",
635 .use_hw = PR_TRUE
640 * NSS needs the app to supply a password prompt. In our case the only time
641 * the password is supplied is as part of the Login APDU. The actual password
642 * is passed in the pw_arg in that case. In all other cases pw_arg should be
643 * NULL.
645 static char *
646 vcard_emul_get_password(PK11SlotInfo *slot, PRBool retries, void *pw_arg)
648 /* if it didn't work the first time, don't keep trying */
649 if (retries) {
650 return NULL;
652 /* we are looking up a password when we don't have one in hand */
653 if (pw_arg == NULL) {
654 return NULL;
656 /* TODO: we really should verify that were are using the right slot */
657 return PORT_Strdup(pw_arg);
660 /* Force a card removal even if the card is not physically removed */
661 VCardEmulError
662 vcard_emul_force_card_remove(VReader *vreader)
664 if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) {
665 return VCARD_EMUL_FAIL; /* card is already removed */
668 /* OK, remove it */
669 vreader_insert_card(vreader, NULL);
670 return VCARD_EMUL_OK;
673 /* Re-insert of a card that has been removed by force removal */
674 VCardEmulError
675 vcard_emul_force_card_insert(VReader *vreader)
677 VReaderEmul *vreader_emul;
678 VCard *vcard;
680 if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) {
681 return VCARD_EMUL_FAIL; /* card is already removed */
683 vreader_emul = vreader_get_private(vreader);
685 /* if it's a softcard, get the saved vcard from the reader emul structure */
686 if (vreader_emul->saved_vcard) {
687 vcard = vcard_reference(vreader_emul->saved_vcard);
688 } else {
689 /* it must be a physical card, rebuild it */
690 if (!PK11_IsPresent(vreader_emul->slot)) {
691 /* physical card has been removed, not way to reinsert it */
692 return VCARD_EMUL_FAIL;
694 vcard = vcard_emul_mirror_card(vreader);
696 vreader_insert_card(vreader, vcard);
697 vcard_free(vcard);
699 return VCARD_EMUL_OK;
703 static PRBool
704 module_has_removable_hw_slots(SECMODModule *mod)
706 int i;
707 PRBool ret = PR_FALSE;
708 SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
710 if (!moduleLock) {
711 PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
712 return ret;
714 SECMOD_GetReadLock(moduleLock);
715 for (i = 0; i < mod->slotCount; i++) {
716 PK11SlotInfo *slot = mod->slots[i];
717 if (PK11_IsRemovable(slot) && PK11_IsHW(slot)) {
718 ret = PR_TRUE;
719 break;
722 SECMOD_ReleaseReadLock(moduleLock);
723 return ret;
726 /* Previously we returned FAIL if no readers found. This makes
727 * no sense when using hardware, since there may be no readers connected
728 * at the time vcard_emul_init is called, but they will be properly
729 * recognized later. So Instead return FAIL only if no_hw==1 and no
730 * vcards can be created (indicates error with certificates provided
731 * or db), or if any other higher level error (NSS error, missing coolkey). */
732 static int vcard_emul_init_called;
734 VCardEmulError
735 vcard_emul_init(const VCardEmulOptions *options)
737 SECStatus rv;
738 PRBool ret, has_readers = PR_FALSE, need_coolkey_module;
739 VReader *vreader;
740 VReaderEmul *vreader_emul;
741 SECMODListLock *module_lock;
742 SECMODModuleList *module_list;
743 SECMODModuleList *mlp;
744 int i;
746 if (vcard_emul_init_called) {
747 return VCARD_EMUL_INIT_ALREADY_INITED;
749 vcard_emul_init_called = 1;
750 vreader_init();
751 vevent_queue_init();
753 if (options == NULL) {
754 options = &default_options;
757 /* first initialize NSS */
758 if (options->nss_db) {
759 rv = NSS_Init(options->nss_db);
760 } else {
761 rv = NSS_Init("sql:/etc/pki/nssdb");
763 if (rv != SECSuccess) {
764 return VCARD_EMUL_FAIL;
766 /* Set password callback function */
767 PK11_SetPasswordFunc(vcard_emul_get_password);
769 /* set up soft cards emulated by software certs rather than physical cards
770 * */
771 for (i = 0; i < options->vreader_count; i++) {
772 int j;
773 int cert_count;
774 unsigned char **certs;
775 int *cert_len;
776 VCardKey **keys;
777 PK11SlotInfo *slot;
779 slot = PK11_FindSlotByName(options->vreader[i].name);
780 if (slot == NULL) {
781 continue;
783 vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type,
784 options->vreader[i].type_params);
785 vreader = vreader_new(options->vreader[i].vname, vreader_emul,
786 vreader_emul_delete);
787 vreader_add_reader(vreader);
788 cert_count = options->vreader[i].cert_count;
790 ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys,
791 options->vreader[i].cert_count);
792 if (ret == PR_FALSE) {
793 continue;
795 cert_count = 0;
796 for (j = 0; j < options->vreader[i].cert_count; j++) {
797 /* we should have a better way of identifying certs than by
798 * nickname here */
799 CERTCertificate *cert = PK11_FindCertFromNickname(
800 options->vreader[i].cert_name[j],
801 NULL);
802 if (cert == NULL) {
803 continue;
805 certs[cert_count] = cert->derCert.data;
806 cert_len[cert_count] = cert->derCert.len;
807 keys[cert_count] = vcard_emul_make_key(slot, cert);
808 /* this is safe because the key is still holding a cert reference */
809 CERT_DestroyCertificate(cert);
810 cert_count++;
812 if (cert_count) {
813 VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len,
814 keys, cert_count);
815 vreader_insert_card(vreader, vcard);
816 vcard_emul_init_series(vreader, vcard);
817 /* allow insertion and removal of soft cards */
818 vreader_emul->saved_vcard = vcard_reference(vcard);
819 vcard_free(vcard);
820 vreader_free(vreader);
821 has_readers = PR_TRUE;
825 /* if we aren't suppose to use hw, skip looking up hardware tokens */
826 if (!options->use_hw) {
827 nss_emul_init = has_readers;
828 return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL;
831 /* make sure we have some PKCS #11 module loaded */
832 module_lock = SECMOD_GetDefaultModuleListLock();
833 module_list = SECMOD_GetDefaultModuleList();
834 need_coolkey_module = !has_readers;
835 SECMOD_GetReadLock(module_lock);
836 for (mlp = module_list; mlp; mlp = mlp->next) {
837 SECMODModule *module = mlp->module;
838 if (module_has_removable_hw_slots(module)) {
839 need_coolkey_module = PR_FALSE;
840 break;
843 SECMOD_ReleaseReadLock(module_lock);
845 if (need_coolkey_module) {
846 SECMODModule *module;
847 module = SECMOD_LoadUserModule(
848 (char *)"library=libcoolkeypk11.so name=Coolkey",
849 NULL, PR_FALSE);
850 if (module == NULL) {
851 return VCARD_EMUL_FAIL;
853 SECMOD_DestroyModule(module); /* free our reference, Module will still
854 * be on the list.
855 * until we destroy it */
858 /* now examine all the slots, finding which should be readers */
859 /* We should control this with options. For now we mirror out any
860 * removable hardware slot */
861 default_card_type = options->hw_card_type;
862 default_type_params = strdup(options->hw_type_params);
864 SECMOD_GetReadLock(module_lock);
865 for (mlp = module_list; mlp; mlp = mlp->next) {
866 SECMODModule *module = mlp->module;
867 PRBool has_emul_slots = PR_FALSE;
869 if (module == NULL) {
870 continue;
873 for (i = 0; i < module->slotCount; i++) {
874 PK11SlotInfo *slot = module->slots[i];
876 /* only map removable HW slots */
877 if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) {
878 continue;
880 vreader_emul = vreader_emul_new(slot, options->hw_card_type,
881 options->hw_type_params);
882 vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
883 vreader_emul_delete);
884 vreader_add_reader(vreader);
886 has_readers = PR_TRUE;
887 has_emul_slots = PR_TRUE;
889 if (PK11_IsPresent(slot)) {
890 VCard *vcard;
891 vcard = vcard_emul_mirror_card(vreader);
892 vreader_insert_card(vreader, vcard);
893 vcard_emul_init_series(vreader, vcard);
894 vcard_free(vcard);
897 if (has_emul_slots) {
898 vcard_emul_new_event_thread(module);
901 SECMOD_ReleaseReadLock(module_lock);
902 nss_emul_init = has_readers;
904 return VCARD_EMUL_OK;
907 /* Recreate card insert events for all readers (user should
908 * deduce implied reader insert. perhaps do a reader insert as well?)
910 void
911 vcard_emul_replay_insertion_events(void)
913 VReaderListEntry *current_entry;
914 VReaderListEntry *next_entry = NULL;
915 VReaderList *list = vreader_get_reader_list();
917 for (current_entry = vreader_list_get_first(list); current_entry;
918 current_entry = next_entry) {
919 VReader *vreader = vreader_list_get_reader(current_entry);
920 next_entry = vreader_list_get_next(current_entry);
921 vreader_queue_card_event(vreader);
926 * Silly little functions to help parsing our argument string
928 static char *
929 copy_string(const char *str, int str_len)
931 char *new_str;
933 new_str = qemu_malloc(str_len+1);
934 memcpy(new_str, str, str_len);
935 new_str[str_len] = 0;
936 return new_str;
939 static int
940 count_tokens(const char *str, char token, char token_end)
942 int count = 0;
944 for (; *str; str++) {
945 if (*str == token) {
946 count++;
948 if (*str == token_end) {
949 break;
952 return count;
955 static const char *
956 strip(const char *str)
958 for (; *str && isspace(*str); str++) {
960 return str;
963 static const char *
964 find_blank(const char *str)
966 for (; *str && !isspace(*str); str++) {
968 return str;
973 * We really want to use some existing argument parsing library here. That
974 * would give us a consistent look */
975 static VCardEmulOptions options;
976 #define READER_STEP 4
978 VCardEmulOptions *
979 vcard_emul_options(const char *args)
981 int reader_count = 0;
982 VCardEmulOptions *opts;
983 char type_str[100];
984 int type_len;
986 /* Allow the future use of allocating the options structure on the fly */
987 memcpy(&options, &default_options, sizeof(options));
988 opts = &options;
990 do {
991 args = strip(args); /* strip off the leading spaces */
992 if (*args == ',') {
993 continue;
995 /* soft=(slot_name,virt_name,emul_type,emul_flags,cert_1, (no eol)
996 * cert_2,cert_3...) */
997 if (strncmp(args, "soft=", 5) == 0) {
998 const char *name;
999 const char *vname;
1000 const char *type_params;
1001 VCardEmulType type;
1002 int name_length, vname_length, type_params_length, count, i;
1003 VirtualReaderOptions *vreaderOpt = NULL;
1005 args = strip(args + 5);
1006 if (*args != '(') {
1007 continue;
1009 name = args;
1010 args = strpbrk(args + 1, ",)");
1011 if (*args == 0) {
1012 break;
1014 if (*args == ')') {
1015 args++;
1016 continue;
1018 args = strip(args+1);
1019 name_length = args - name - 2;
1020 vname = args;
1021 args = strpbrk(args + 1, ",)");
1022 if (*args == 0) {
1023 break;
1025 if (*args == ')') {
1026 args++;
1027 continue;
1029 vname_length = args - name - 2;
1030 args = strip(args+1);
1031 type_len = strpbrk(args, ",)") - args;
1032 assert(sizeof(type_str) > type_len);
1033 strncpy(type_str, args, type_len);
1034 type_str[type_len] = 0;
1035 type = vcard_emul_type_from_string(type_str);
1036 args = strpbrk(args, ",)");
1037 if (*args == 0) {
1038 break;
1040 if (*args == ')') {
1041 args++;
1042 continue;
1044 args = strip(args++);
1045 type_params = args;
1046 args = strpbrk(args + 1, ",)");
1047 if (*args == 0) {
1048 break;
1050 if (*args == ')') {
1051 args++;
1052 continue;
1054 type_params_length = args - name;
1055 args = strip(args++);
1056 if (*args == 0) {
1057 break;
1060 if (opts->vreader_count >= reader_count) {
1061 reader_count += READER_STEP;
1062 vreaderOpt = realloc(opts->vreader,
1063 reader_count * sizeof(*vreaderOpt));
1064 if (vreaderOpt == NULL) {
1065 return opts; /* we're done */
1068 opts->vreader = vreaderOpt;
1069 vreaderOpt = &vreaderOpt[opts->vreader_count];
1070 vreaderOpt->name = copy_string(name, name_length);
1071 vreaderOpt->vname = copy_string(vname, vname_length);
1072 vreaderOpt->card_type = type;
1073 vreaderOpt->type_params =
1074 copy_string(type_params, type_params_length);
1075 count = count_tokens(args, ',', ')');
1076 vreaderOpt->cert_count = count;
1077 vreaderOpt->cert_name = (char **)qemu_malloc(count*sizeof(char *));
1078 for (i = 0; i < count; i++) {
1079 const char *cert = args + 1;
1080 args = strpbrk(args + 1, ",)");
1081 vreaderOpt->cert_name[i] = copy_string(cert, args - cert);
1083 if (*args == ')') {
1084 args++;
1086 opts->vreader_count++;
1087 /* use_hw= */
1088 } else if (strncmp(args, "use_hw=", 7) == 0) {
1089 args = strip(args+7);
1090 if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') {
1091 opts->use_hw = PR_FALSE;
1092 } else {
1093 opts->use_hw = PR_TRUE;
1095 args = find_blank(args);
1096 /* hw_type= */
1097 } else if (strncmp(args, "hw_type=", 8) == 0) {
1098 args = strip(args+8);
1099 opts->hw_card_type = vcard_emul_type_from_string(args);
1100 args = find_blank(args);
1101 /* hw_params= */
1102 } else if (strncmp(args, "hw_params=", 10) == 0) {
1103 const char *params;
1104 args = strip(args+10);
1105 params = args;
1106 args = find_blank(args);
1107 opts->hw_type_params = copy_string(params, args-params);
1108 /* db="/data/base/path" */
1109 } else if (strncmp(args, "db=", 3) == 0) {
1110 const char *db;
1111 args = strip(args+3);
1112 if (*args != '"') {
1113 continue;
1115 args++;
1116 db = args;
1117 args = strpbrk(args, "\"\n");
1118 opts->nss_db = copy_string(db, args-db);
1119 if (*args != 0) {
1120 args++;
1122 } else {
1123 args = find_blank(args);
1125 } while (*args != 0);
1127 return opts;
1130 void
1131 vcard_emul_usage(void)
1133 fprintf(stderr,
1134 "emul args: comma separated list of the following arguments\n"
1135 " db={nss_database} (default sql:/etc/pki/nssdb)\n"
1136 " use_hw=[yes|no] (default yes)\n"
1137 " hw_type={card_type_to_emulate} (default CAC)\n"
1138 " hw_param={param_for_card} (default \"\")\n"
1139 " soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n"
1140 " {cert1},{cert2},{cert3} (default none)\n"
1141 "\n"
1142 " {nss_database} The location of the NSS cert & key database\n"
1143 " {card_type_to_emulate} What card interface to present to the guest\n"
1144 " {param_for_card} Card interface specific parameters\n"
1145 " {slot_name} NSS slot that contains the certs\n"
1146 " {vreader_name} Virutal reader name to present to the guest\n"
1147 " {certN} Nickname of the certificate n on the virtual card\n"
1148 "\n"
1149 "These parameters come as a single string separated by blanks or newlines."
1150 "\n"
1151 "Unless use_hw is set to no, all tokens that look like removable hardware\n"
1152 "tokens will be presented to the guest using the emulator specified by\n"
1153 "hw_type, and parameters of hw_param.\n"
1154 "\n"
1155 "If more one or more soft= parameters are specified, these readers will be\n"
1156 "presented to the guest\n");