/* * 'clone' a physical card as a virtual card */ static VCard * vcard_emul_mirror_card(VReader *vreader) { /* * lookup certs using the C_FindObjects. The Stan Cert handle won't give * us the real certs until we log in. */ PK11GenericObject *firstObj, *thisObj; int cert_count; unsigned char **certs; int *cert_len; VCardKey **keys; PK11SlotInfo *slot; PRBool ret; VCard *card; slot = vcard_emul_reader_get_slot(vreader); if (slot == NULL) { return NULL; } firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE); if (firstObj == NULL) { return NULL; } /* count the certs */ cert_count = 0; for (thisObj = firstObj; thisObj; thisObj = PK11_GetNextGenericObject(thisObj)) { cert_count++; } if (cert_count == 0) { PK11_DestroyGenericObjects(firstObj); return NULL; } /* allocate the arrays */ ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count); if (ret == PR_FALSE) { return NULL; } /* fill in the arrays */ cert_count = 0; for (thisObj = firstObj; thisObj; thisObj = PK11_GetNextGenericObject(thisObj)) { SECItem derCert; CERTCertificate *cert; SECStatus rv; rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj, CKA_VALUE, &derCert); if (rv != SECSuccess) { continue; } /* create floating temp cert. This gives us a cert structure even if * the token isn't logged in */ cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert, NULL, PR_FALSE, PR_TRUE); SECITEM_FreeItem(&derCert, PR_FALSE); if (cert == NULL) { continue; } certs[cert_count] = cert->derCert.data; cert_len[cert_count] = cert->derCert.len; keys[cert_count] = vcard_emul_make_key(slot, cert); cert_count++; CERT_DestroyCertificate(cert); /* key obj still has a reference */ } /* now create the card */ card = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); g_free(certs); g_free(cert_len); g_free(keys); return card; }
VCardEmulError vcard_emul_init(const VCardEmulOptions *options) { SECStatus rv; PRBool ret, has_readers = PR_FALSE; VReader *vreader; VReaderEmul *vreader_emul; SECMODListLock *module_lock; SECMODModuleList *module_list; SECMODModuleList *mlp; int i; if (vcard_emul_init_called) { return VCARD_EMUL_INIT_ALREADY_INITED; } vcard_emul_init_called = 1; vreader_init(); vevent_queue_init(); if (options == NULL) { options = &default_options; } /* first initialize NSS */ if (options->nss_db) { rv = NSS_Init(options->nss_db); } else { gchar *path; #ifndef _WIN32 path = g_strdup("/etc/pki/nssdb"); #else if (g_get_system_config_dirs() == NULL || g_get_system_config_dirs()[0] == NULL) { return VCARD_EMUL_FAIL; } path = g_build_filename( g_get_system_config_dirs()[0], "pki", "nssdb", NULL); #endif rv = NSS_Init(path); g_free(path); } if (rv != SECSuccess) { return VCARD_EMUL_FAIL; } /* Set password callback function */ PK11_SetPasswordFunc(vcard_emul_get_password); /* set up soft cards emulated by software certs rather than physical cards * */ for (i = 0; i < options->vreader_count; i++) { int j; int cert_count; unsigned char **certs; int *cert_len; VCardKey **keys; PK11SlotInfo *slot; slot = PK11_FindSlotByName(options->vreader[i].name); if (slot == NULL) { continue; } vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type, options->vreader[i].type_params); vreader = vreader_new(options->vreader[i].vname, vreader_emul, vreader_emul_delete); vreader_add_reader(vreader); cert_count = options->vreader[i].cert_count; ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, options->vreader[i].cert_count); if (ret == PR_FALSE) { continue; } cert_count = 0; for (j = 0; j < options->vreader[i].cert_count; j++) { /* we should have a better way of identifying certs than by * nickname here */ CERTCertificate *cert = PK11_FindCertFromNickname( options->vreader[i].cert_name[j], NULL); if (cert == NULL) { continue; } certs[cert_count] = cert->derCert.data; cert_len[cert_count] = cert->derCert.len; keys[cert_count] = vcard_emul_make_key(slot, cert); /* this is safe because the key is still holding a cert reference */ CERT_DestroyCertificate(cert); cert_count++; } if (cert_count) { VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); vreader_insert_card(vreader, vcard); vcard_emul_init_series(vreader, vcard); /* allow insertion and removal of soft cards */ vreader_emul->saved_vcard = vcard_reference(vcard); vcard_free(vcard); vreader_free(vreader); has_readers = PR_TRUE; } g_free(certs); g_free(cert_len); g_free(keys); } /* if we aren't suppose to use hw, skip looking up hardware tokens */ if (!options->use_hw) { nss_emul_init = has_readers; return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL; } /* make sure we have some PKCS #11 module loaded */ module_lock = SECMOD_GetDefaultModuleListLock(); module_list = SECMOD_GetDefaultModuleList(); SECMOD_GetReadLock(module_lock); for (mlp = module_list; mlp; mlp = mlp->next) { SECMODModule *module = mlp->module; if (module_has_removable_hw_slots(module)) { break; } } SECMOD_ReleaseReadLock(module_lock); /* now examine all the slots, finding which should be readers */ /* We should control this with options. For now we mirror out any * removable hardware slot */ default_card_type = options->hw_card_type; default_type_params = g_strdup(options->hw_type_params); SECMOD_GetReadLock(module_lock); for (mlp = module_list; mlp; mlp = mlp->next) { SECMODModule *module = mlp->module; /* Ignore the internal module */ if (module == NULL || module == SECMOD_GetInternalModule()) { continue; } for (i = 0; i < module->slotCount; i++) { PK11SlotInfo *slot = module->slots[i]; /* only map removable HW slots */ if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) { continue; } if (strcmp("E-Gate 0 0", PK11_GetSlotName(slot)) == 0) { /* * coolkey <= 1.1.0-20 emulates this reader if it can't find * any hardware readers. This causes problems, warn user of * problems. */ fprintf(stderr, "known bad coolkey version - see " "https://bugzilla.redhat.com/show_bug.cgi?id=802435\n"); continue; } vreader_emul = vreader_emul_new(slot, options->hw_card_type, options->hw_type_params); vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, vreader_emul_delete); vreader_add_reader(vreader); if (PK11_IsPresent(slot)) { VCard *vcard; vcard = vcard_emul_mirror_card(vreader); vreader_insert_card(vreader, vcard); vcard_emul_init_series(vreader, vcard); vcard_free(vcard); } } vcard_emul_new_event_thread(module); } SECMOD_ReleaseReadLock(module_lock); nss_emul_init = PR_TRUE; return VCARD_EMUL_OK; }
VCardEmulError vcard_emul_init(const VCardEmulOptions *options) { SECStatus rv; PRBool ret, has_readers = PR_FALSE, need_coolkey_module; VReader *vreader; VReaderEmul *vreader_emul; SECMODListLock *module_lock; SECMODModuleList *module_list; SECMODModuleList *mlp; int i; if (vcard_emul_init_called) { return VCARD_EMUL_INIT_ALREADY_INITED; } vcard_emul_init_called = 1; vreader_init(); vevent_queue_init(); if (options == NULL) { options = &default_options; } /* first initialize NSS */ if (options->nss_db) { rv = NSS_Init(options->nss_db); } else { rv = NSS_Init("sql:/etc/pki/nssdb"); } if (rv != SECSuccess) { return VCARD_EMUL_FAIL; } /* Set password callback function */ PK11_SetPasswordFunc(vcard_emul_get_password); /* set up soft cards emulated by software certs rather than physical cards * */ for (i = 0; i < options->vreader_count; i++) { int j; int cert_count; unsigned char **certs; int *cert_len; VCardKey **keys; PK11SlotInfo *slot; slot = PK11_FindSlotByName(options->vreader[i].name); if (slot == NULL) { continue; } vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type, options->vreader[i].type_params); vreader = vreader_new(options->vreader[i].vname, vreader_emul, vreader_emul_delete); vreader_add_reader(vreader); cert_count = options->vreader[i].cert_count; ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, options->vreader[i].cert_count); if (ret == PR_FALSE) { continue; } cert_count = 0; for (j = 0; j < options->vreader[i].cert_count; j++) { /* we should have a better way of identifying certs than by * nickname here */ CERTCertificate *cert = PK11_FindCertFromNickname( options->vreader[i].cert_name[j], NULL); if (cert == NULL) { continue; } certs[cert_count] = cert->derCert.data; cert_len[cert_count] = cert->derCert.len; keys[cert_count] = vcard_emul_make_key(slot, cert); /* this is safe because the key is still holding a cert reference */ CERT_DestroyCertificate(cert); cert_count++; } if (cert_count) { VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); vreader_insert_card(vreader, vcard); vcard_emul_init_series(vreader, vcard); /* allow insertion and removal of soft cards */ vreader_emul->saved_vcard = vcard_reference(vcard); vcard_free(vcard); vreader_free(vreader); has_readers = PR_TRUE; } g_free(certs); g_free(cert_len); g_free(keys); } /* if we aren't suppose to use hw, skip looking up hardware tokens */ if (!options->use_hw) { nss_emul_init = has_readers; return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL; } /* make sure we have some PKCS #11 module loaded */ module_lock = SECMOD_GetDefaultModuleListLock(); module_list = SECMOD_GetDefaultModuleList(); need_coolkey_module = !has_readers; SECMOD_GetReadLock(module_lock); for (mlp = module_list; mlp; mlp = mlp->next) { SECMODModule *module = mlp->module; if (module_has_removable_hw_slots(module)) { need_coolkey_module = PR_FALSE; break; } } SECMOD_ReleaseReadLock(module_lock); if (need_coolkey_module) { SECMODModule *module; module = SECMOD_LoadUserModule( (char *)"library=libcoolkeypk11.so name=Coolkey", NULL, PR_FALSE); if (module == NULL) { return VCARD_EMUL_FAIL; } SECMOD_DestroyModule(module); /* free our reference, Module will still * be on the list. * until we destroy it */ } /* now examine all the slots, finding which should be readers */ /* We should control this with options. For now we mirror out any * removable hardware slot */ default_card_type = options->hw_card_type; default_type_params = strdup(options->hw_type_params); SECMOD_GetReadLock(module_lock); for (mlp = module_list; mlp; mlp = mlp->next) { SECMODModule *module = mlp->module; PRBool has_emul_slots = PR_FALSE; if (module == NULL) { continue; } for (i = 0; i < module->slotCount; i++) { PK11SlotInfo *slot = module->slots[i]; /* only map removable HW slots */ if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) { continue; } vreader_emul = vreader_emul_new(slot, options->hw_card_type, options->hw_type_params); vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, vreader_emul_delete); vreader_add_reader(vreader); has_readers = PR_TRUE; has_emul_slots = PR_TRUE; if (PK11_IsPresent(slot)) { VCard *vcard; vcard = vcard_emul_mirror_card(vreader); vreader_insert_card(vreader, vcard); vcard_emul_init_series(vreader, vcard); vcard_free(vcard); } } if (has_emul_slots) { vcard_emul_new_event_thread(module); } } SECMOD_ReleaseReadLock(module_lock); nss_emul_init = has_readers; return VCARD_EMUL_OK; }