NS_IMETHODIMP nsNSSCertificateDB::FindCertByNickname(nsISupports *aToken, const nsAString &nickname, nsIX509Cert **_rvCert) { nsNSSShutDownPreventionLock locker; CERTCertificate *cert = NULL; char *asciiname = NULL; NS_ConvertUTF16toUTF8 aUtf8Nickname(nickname); asciiname = const_cast<char*>(aUtf8Nickname.get()); PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname)); #if 0 // what it should be, but for now... if (aToken) { cert = PK11_FindCertFromNickname(asciiname, NULL); } else { cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname); } #endif cert = PK11_FindCertFromNickname(asciiname, NULL); if (!cert) { cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname); } if (cert) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("got it\n")); nsCOMPtr<nsIX509Cert> pCert = new nsNSSCertificate(cert); CERT_DestroyCertificate(cert); *_rvCert = pCert; NS_ADDREF(*_rvCert); return NS_OK; } *_rvCert = nsnull; return NS_ERROR_FAILURE; }
static X509* nss_get_cert(NSS_CTX *ctx, const char *s) { X509 *x509 = NULL; CERTCertificate *cert = NULL; CALL_TRACE("nss_get_cert...\n"); if (ctx == NULL) { NSSerr(NSS_F_GET_CERT, NSS_R_INVALID_ARGUMENT); goto done; } if (!NSS_IsInitialized()) { NSSerr(NSS_F_GET_CERT, NSS_R_DB_IS_NOT_INITIALIZED); goto done; } nss_debug(ctx, "search certificate '%s'", s); cert = PK11_FindCertFromNickname(s, NULL); nss_trace(ctx, "found certificate mem='%p'", cert); if (cert == NULL) goto done; x509 = X509_from_CERTCertificate(cert); done: if (cert) CERT_DestroyCertificate(cert); nss_debug(ctx, "certificate %s", (x509 ? "found": "not found")); return(x509); }
// nsPKCS12Blob::LoadCerts // // Given an array of certificate nicknames, load the corresponding // certificates into a local array. nsresult nsPKCS12Blob::LoadCerts(const PRUnichar **certNames, int numCerts) { nsresult rv; char namecpy[256]; /* Create the local array if needed */ if (!mCertArray) { rv = NS_NewISupportsArray(getter_AddRefs(mCertArray)); if (NS_FAILED(rv)) { if (!handleError()) return NS_ERROR_OUT_OF_MEMORY; } } /* Add the certs */ for (int i=0; i<numCerts; i++) { strcpy(namecpy, NS_ConvertUTF16toUTF8(certNames[i])); CERTCertificate *nssCert = PK11_FindCertFromNickname(namecpy, NULL); if (!nssCert) { if (!handleError()) return NS_ERROR_FAILURE; else continue; /* user may request to keep going */ } nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(nssCert); CERT_DestroyCertificate(nssCert); if (!cert) { if (!handleError()) return NS_ERROR_OUT_OF_MEMORY; } else { mCertArray->AppendElement(cert); } } return NS_OK; }
/** * * Check that the Peer certificate's issuer certificate matches the one found * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the * issuer check, so we provide comments that mimic the OpenSSL * X509_check_issued function (in x509v3/v3_purp.c) */ static SECStatus check_issuer_cert(PRFileDesc *sock, char *issuer_nickname) { CERTCertificate *cert,*cert_issuer,*issuer; SECStatus res=SECSuccess; void *proto_win = NULL; /* PRArenaPool *tmpArena = NULL; CERTAuthKeyID *authorityKeyID = NULL; SECITEM *caname = NULL; */ cert = SSL_PeerCertificate(sock); cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner); proto_win = SSL_RevealPinArg(sock); issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win); if((!cert_issuer) || (!issuer)) res = SECFailure; else if(SECITEM_CompareItem(&cert_issuer->derCert, &issuer->derCert)!=SECEqual) res = SECFailure; CERT_DestroyCertificate(cert); CERT_DestroyCertificate(issuer); CERT_DestroyCertificate(cert_issuer); return res; }
/** * Obtains a signing context. * * @param ctx A pointer to the signing context to fill * @return 0 on success * -1 on error */ int NSSSignBegin(const char *certName, SGNContext **ctx, SECKEYPrivateKey **privKey, CERTCertificate **cert, uint32_t *signatureLength) { secuPWData pwdata = { PW_NONE, 0 }; if (!certName || !ctx || !privKey || !cert || !signatureLength) { fprintf(stderr, "ERROR: Invalid parameter passed to NSSSignBegin\n"); return -1; } /* Get the cert and embedded public key out of the database */ *cert = PK11_FindCertFromNickname(certName, &pwdata); if (!*cert) { fprintf(stderr, "ERROR: Could not find cert from nickname\n"); return -1; } /* Get the private key out of the database */ *privKey = PK11_FindKeyByAnyCert(*cert, &pwdata); if (!*privKey) { fprintf(stderr, "ERROR: Could not find private key\n"); return -1; } *signatureLength = PK11_SignatureLen(*privKey); if (*signatureLength > BLOCKSIZE) { fprintf(stderr, "ERROR: Program must be compiled with a larger block size" " to support signing with signatures this large: %u.\n", *signatureLength); return -1; } /* Check that the key length is large enough for our requirements */ if (*signatureLength < XP_MIN_SIGNATURE_LEN_IN_BYTES) { fprintf(stderr, "ERROR: Key length must be >= %d bytes\n", XP_MIN_SIGNATURE_LEN_IN_BYTES); return -1; } *ctx = SGN_NewContext (SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, *privKey); if (!*ctx) { fprintf(stderr, "ERROR: Could not create signature context\n"); return -1; } if (SGN_Begin(*ctx) != SECSuccess) { fprintf(stderr, "ERROR: Could not begin signature\n"); return -1; } return 0; }
/*********************************************************************** * * G e n e r a t e C e r t * * Runs the whole process of creating a new cert, getting info from the * user, etc. */ int GenerateCert(char *nickname, int keysize, char *token) { CERTCertDBHandle * db; CERTCertificate * cert; char *subject; unsigned long serial; char stdinbuf[160]; /* Print warning about having the browser open */ PR_fprintf(PR_STDOUT /*always go to console*/, "\nWARNING: Performing this operation while the browser is running could cause" "\ncorruption of your security databases. If the browser is currently running," "\nyou should exit the browser before continuing this operation. Enter " "\n\"y\" to continue, or anything else to abort: "); pr_fgets(stdinbuf, 160, PR_STDIN); PR_fprintf(PR_STDOUT, "\n"); if (tolower(stdinbuf[0]) != 'y') { PR_fprintf(errorFD, "Operation aborted at user's request.\n"); errorCount++; return - 1; } db = CERT_GetDefaultCertDB(); if (!db) { FatalError("Unable to open certificate database"); } if (PK11_FindCertFromNickname(nickname, &pwdata)) { PR_fprintf(errorFD, "ERROR: Certificate with nickname \"%s\" already exists in database. You\n" "must choose a different nickname.\n", nickname); errorCount++; exit(ERRX); } LL_L2UI(serial, PR_Now()); subject = GetSubjectFromUser(serial); cert = GenerateSelfSignedObjectSigningCert(nickname, db, subject, serial, keysize, token); if (cert) { output_ca_cert(cert, db); CERT_DestroyCertificate(cert); } PORT_Free(subject); return 0; }
/** * * Callback to pick the SSL client certificate. */ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct CERTDistNamesStr *caNames, struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey) { SECKEYPrivateKey *privKey; struct ssl_connect_data *connssl = (struct ssl_connect_data *) arg; char *nickname = connssl->client_nickname; void *proto_win = NULL; SECStatus secStatus = SECFailure; PK11SlotInfo *slot; (void)caNames; proto_win = SSL_RevealPinArg(sock); if(!nickname) return secStatus; connssl->client_cert = PK11_FindCertFromNickname(nickname, proto_win); if(connssl->client_cert) { if(!strncmp(nickname, "PEM Token", 9)) { CK_SLOT_ID slotID = 1; /* hardcoded for now */ char slotname[SLOTSIZE]; snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID); slot = PK11_FindSlotByName(slotname); privKey = PK11_FindPrivateKeyFromCert(slot, connssl->client_cert, NULL); PK11_FreeSlot(slot); if(privKey) { secStatus = SECSuccess; } } else { privKey = PK11_FindKeyByAnyCert(connssl->client_cert, proto_win); if(privKey) secStatus = SECSuccess; } } if(secStatus == SECSuccess) { *pRetCert = connssl->client_cert; *pRetKey = privKey; } else { if(connssl->client_cert) CERT_DestroyCertificate(connssl->client_cert); connssl->client_cert = NULL; } return secStatus; }
int SslSocket::listen(const SocketAddress& sa, int backlog) const { //get certificate and key (is this the correct way?) std::string cName( (certname == "") ? "localhost.localdomain" : certname); CERTCertificate *cert = PK11_FindCertFromNickname(const_cast<char*>(cName.c_str()), 0); if (!cert) throw Exception(QPID_MSG("Failed to load certificate '" << cName << "'")); SECKEYPrivateKey *key = PK11_FindKeyByAnyCert(cert, 0); if (!key) throw Exception(QPID_MSG("Failed to retrieve private key from certificate")); NSS_CHECK(SSL_ConfigSecureServer(prototype, cert, key, NSS_FindCertKEAType(cert))); SECKEY_DestroyPrivateKey(key); CERT_DestroyCertificate(cert); return BSDSocket::listen(sa, backlog); }
int qnetd_instance_init_certs(struct qnetd_instance *instance) { instance->server.cert = PK11_FindCertFromNickname( instance->advanced_settings->cert_nickname, NULL); if (instance->server.cert == NULL) { return (-1); } instance->server.private_key = PK11_FindKeyByAnyCert(instance->server.cert, NULL); if (instance->server.private_key == NULL) { return (-1); } return (0); }
static CURLcode nss_load_cert(struct ssl_connect_data *ssl, const char *filename, PRBool cacert) { CURLcode err = (cacert) ? CURLE_SSL_CACERT_BADFILE : CURLE_SSL_CERTPROBLEM; #ifdef HAVE_PK11_CREATEGENERICOBJECT /* libnsspem.so leaks memory if the requested file does not exist. For more * details, go to <https://bugzilla.redhat.com/734760>. */ if(is_file(filename)) err = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert); if(CURLE_OK == err && !cacert) { /* we have successfully loaded a client certificate */ CERTCertificate *cert; char *nickname = NULL; char *n = strrchr(filename, '/'); if(n) n++; /* The following undocumented magic helps to avoid a SIGSEGV on call * of PK11_ReadRawAttribute() from SelectClientCert() when using an * immature version of libnsspem.so. For more details, go to * <https://bugzilla.redhat.com/733685>. */ nickname = aprintf("PEM Token #1:%s", n); if(nickname) { cert = PK11_FindCertFromNickname(nickname, NULL); if(cert) CERT_DestroyCertificate(cert); free(nickname); } } #endif return err; }
int SslSocket::listen(uint16_t port, int backlog, const std::string& certName, bool clientAuth) const { //configure prototype socket: prototype = SSL_ImportFD(0, PR_NewTCPSocket()); if (clientAuth) { NSS_CHECK(SSL_OptionSet(prototype, SSL_REQUEST_CERTIFICATE, PR_TRUE)); NSS_CHECK(SSL_OptionSet(prototype, SSL_REQUIRE_CERTIFICATE, PR_TRUE)); } //get certificate and key (is this the correct way?) CERTCertificate *cert = PK11_FindCertFromNickname(const_cast<char*>(certName.c_str()), 0); if (!cert) throw Exception(QPID_MSG("Failed to load certificate '" << certName << "'")); SECKEYPrivateKey *key = PK11_FindKeyByAnyCert(cert, 0); if (!key) throw Exception(QPID_MSG("Failed to retrieve private key from certificate")); NSS_CHECK(SSL_ConfigSecureServer(prototype, cert, key, NSS_FindCertKEAType(cert))); SECKEY_DestroyPrivateKey(key); CERT_DestroyCertificate(cert); //bind and listen const int& socket = impl->fd; int yes=1; QPID_POSIX_CHECK(setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes))); struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = htons(port); name.sin_addr.s_addr = 0; if (::bind(socket, (struct sockaddr*)&name, sizeof(name)) < 0) throw Exception(QPID_MSG("Can't bind to port " << port << ": " << strError(errno))); if (::listen(socket, backlog) < 0) throw Exception(QPID_MSG("Can't listen on port " << port << ": " << strError(errno))); socklen_t namelen = sizeof(name); if (::getsockname(socket, (struct sockaddr*)&name, &namelen) < 0) throw QPID_POSIX_ERROR(errno); return ntohs(name.sin_port); }
CERTCertificate * CERT_FindCertByNickname(CERTCertDBHandle *handle, const char *nickname) { NSSCryptoContext *cc; NSSCertificate *c, *ct; CERTCertificate *cert; NSSUsage usage; usage.anyUsage = PR_TRUE; cc = STAN_GetDefaultCryptoContext(); ct = NSSCryptoContext_FindBestCertificateByNickname(cc, nickname, NULL, &usage, NULL); cert = PK11_FindCertFromNickname(nickname, NULL); c = NULL; if (cert) { c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert)); CERT_DestroyCertificate(cert); if (ct) { CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); } } else { c = ct; } return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; }
CERTCertificate * CERT_FindCertByNicknameOrEmailAddr(CERTCertDBHandle *handle, const char *name) { NSSCryptoContext *cc; NSSCertificate *c, *ct; CERTCertificate *cert; NSSUsage usage; if (NULL == name) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } usage.anyUsage = PR_TRUE; cc = STAN_GetDefaultCryptoContext(); ct = NSSCryptoContext_FindBestCertificateByNickname(cc, name, NULL, &usage, NULL); if (!ct && PORT_Strchr(name, '@') != NULL) { char* lowercaseName = CERT_FixupEmailAddr(name); if (lowercaseName) { ct = NSSCryptoContext_FindBestCertificateByEmail(cc, lowercaseName, NULL, &usage, NULL); PORT_Free(lowercaseName); } } cert = PK11_FindCertFromNickname(name, NULL); if (cert) { c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert)); CERT_DestroyCertificate(cert); if (ct) { CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); } } else { c = ct; } return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; }
int main(int argc, char **argv) { char *NSSConfigDir = NULL; const char *certNames[MAX_SIGNATURES]; char *MARChannelID = MAR_CHANNEL_ID; char *productVersion = MOZ_APP_VERSION; uint32_t k; int rv = -1; uint32_t certCount = 0; int32_t sigIndex = -1; #if !defined(NO_SIGN_VERIFY) uint32_t fileSizes[MAX_SIGNATURES]; const uint8_t* certBuffers[MAX_SIGNATURES]; char* DERFilePaths[MAX_SIGNATURES]; #if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS) CERTCertificate* certs[MAX_SIGNATURES]; #endif #endif memset((void*)certNames, 0, sizeof(certNames)); #if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY) memset((void*)certBuffers, 0, sizeof(certBuffers)); #endif #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \ defined(XP_MACOSX)) memset(DERFilePaths, 0, sizeof(DERFilePaths)); memset(fileSizes, 0, sizeof(fileSizes)); #endif if (argc > 1 && 0 == strcmp(argv[1], "--version")) { print_version(); return 0; } if (argc < 3) { print_usage(); return -1; } while (argc > 0) { if (argv[1][0] == '-' && (argv[1][1] == 'c' || argv[1][1] == 't' || argv[1][1] == 'x' || argv[1][1] == 'v' || argv[1][1] == 's' || argv[1][1] == 'i' || argv[1][1] == 'T' || argv[1][1] == 'r' || argv[1][1] == 'X' || argv[1][1] == 'I')) { break; /* -C workingdirectory */ } else if (argv[1][0] == '-' && argv[1][1] == 'C') { if (chdir(argv[2]) != 0) { return -1; } argv += 2; argc -= 2; } #if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \ defined(XP_MACOSX)) /* -D DERFilePath, also matches -D[index] DERFilePath We allow an index for verifying to be symmetric with the import and export command line arguments. */ else if (argv[1][0] == '-' && argv[1][1] == 'D' && (argv[1][2] == (char)('0' + certCount) || argv[1][2] == '\0')) { if (certCount >= MAX_SIGNATURES) { print_usage(); return -1; } DERFilePaths[certCount++] = argv[2]; argv += 2; argc -= 2; } #endif /* -d NSSConfigdir */ else if (argv[1][0] == '-' && argv[1][1] == 'd') { NSSConfigDir = argv[2]; argv += 2; argc -= 2; /* -n certName, also matches -n[index] certName We allow an index for verifying to be symmetric with the import and export command line arguments. */ } else if (argv[1][0] == '-' && argv[1][1] == 'n' && (argv[1][2] == (char)('0' + certCount) || argv[1][2] == '\0' || !strcmp(argv[2], "-X") || !strcmp(argv[2], "-I"))) { if (certCount >= MAX_SIGNATURES) { print_usage(); return -1; } certNames[certCount++] = argv[2]; if (strlen(argv[1]) > 2 && (!strcmp(argv[2], "-X") || !strcmp(argv[2], "-I")) && argv[1][2] >= '0' && argv[1][2] <= '9') { sigIndex = argv[1][2] - '0'; argv++; argc--; } else { argv += 2; argc -= 2; } /* MAR channel ID */ } else if (argv[1][0] == '-' && argv[1][1] == 'H') { MARChannelID = argv[2]; argv += 2; argc -= 2; /* Product Version */ } else if (argv[1][0] == '-' && argv[1][1] == 'V') { productVersion = argv[2]; argv += 2; argc -= 2; } else { print_usage(); return -1; } } if (argv[1][0] != '-') { print_usage(); return -1; } switch (argv[1][1]) { case 'c': { struct ProductInformationBlock infoBlock; infoBlock.MARChannelID = MARChannelID; infoBlock.productVersion = productVersion; return mar_create(argv[2], argc - 3, argv + 3, &infoBlock); } case 'i': { struct ProductInformationBlock infoBlock; infoBlock.MARChannelID = MARChannelID; infoBlock.productVersion = productVersion; return refresh_product_info_block(argv[2], &infoBlock); } case 'T': { struct ProductInformationBlock infoBlock; uint32_t numSignatures, numAdditionalBlocks; int hasSignatureBlock, hasAdditionalBlock; if (!get_mar_file_info(argv[2], &hasSignatureBlock, &numSignatures, &hasAdditionalBlock, NULL, &numAdditionalBlocks)) { if (hasSignatureBlock) { printf("Signature block found with %d signature%s\n", numSignatures, numSignatures != 1 ? "s" : ""); } if (hasAdditionalBlock) { printf("%d additional block%s found:\n", numAdditionalBlocks, numAdditionalBlocks != 1 ? "s" : ""); } rv = read_product_info_block(argv[2], &infoBlock); if (!rv) { printf(" - Product Information Block:\n"); printf(" - MAR channel name: %s\n" " - Product version: %s\n", infoBlock.MARChannelID, infoBlock.productVersion); free((void *)infoBlock.MARChannelID); free((void *)infoBlock.productVersion); } } printf("\n"); /* The fall through from 'T' to 't' is intentional */ } case 't': return mar_test(argv[2]); /* Extract a MAR file */ case 'x': return mar_extract(argv[2]); #ifndef NO_SIGN_VERIFY /* Extract a MAR signature */ case 'X': if (sigIndex == -1) { fprintf(stderr, "ERROR: Signature index was not passed.\n"); return -1; } if (sigIndex >= MAX_SIGNATURES || sigIndex < -1) { fprintf(stderr, "ERROR: Signature index is out of range: %d.\n", sigIndex); return -1; } return extract_signature(argv[2], sigIndex, argv[3]); /* Import a MAR signature */ case 'I': if (sigIndex == -1) { fprintf(stderr, "ERROR: signature index was not passed.\n"); return -1; } if (sigIndex >= MAX_SIGNATURES || sigIndex < -1) { fprintf(stderr, "ERROR: Signature index is out of range: %d.\n", sigIndex); return -1; } if (argc < 5) { print_usage(); return -1; } return import_signature(argv[2], sigIndex, argv[3], argv[4]); case 'v': if (certCount == 0) { print_usage(); return -1; } #if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS) if (!NSSConfigDir || certCount == 0) { print_usage(); return -1; } if (NSSInitCryptoContext(NSSConfigDir)) { fprintf(stderr, "ERROR: Could not initialize crypto library.\n"); return -1; } #endif rv = 0; for (k = 0; k < certCount; ++k) { #if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS) rv = mar_read_entire_file(DERFilePaths[k], MAR_MAX_CERT_SIZE, &certBuffers[k], &fileSizes[k]); #else /* It is somewhat circuitous to look up a CERTCertificate and then pass * in its DER encoding just so we can later re-create that * CERTCertificate to extract the public key out of it. However, by doing * things this way, we maximize the reuse of the mar_verify_signatures * function and also we keep the control flow as similar as possible * between programs and operating systems, at least for the functions * that are critically important to security. */ certs[k] = PK11_FindCertFromNickname(certNames[k], NULL); if (certs[k]) { certBuffers[k] = certs[k]->derCert.data; fileSizes[k] = certs[k]->derCert.len; } else { rv = -1; } #endif if (rv) { fprintf(stderr, "ERROR: could not read file %s", DERFilePaths[k]); break; } } if (!rv) { MarFile *mar = mar_open(argv[2]); if (mar) { rv = mar_verify_signatures(mar, certBuffers, fileSizes, certCount); mar_close(mar); } else { fprintf(stderr, "ERROR: Could not open MAR file.\n"); rv = -1; } } for (k = 0; k < certCount; ++k) { #if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS) free((void*)certBuffers[k]); #else /* certBuffers[k] is owned by certs[k] so don't free it */ CERT_DestroyCertificate(certs[k]); #endif } if (rv) { /* Determine if the source MAR file has the new fields for signing */ int hasSignatureBlock; if (get_mar_file_info(argv[2], &hasSignatureBlock, NULL, NULL, NULL, NULL)) { fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n"); } else if (!hasSignatureBlock) { fprintf(stderr, "ERROR: The MAR file is in the old format so has" " no signature to verify.\n"); } return -1; } return 0; case 's': if (!NSSConfigDir || certCount == 0 || argc < 4) { print_usage(); return -1; } return mar_repackage_and_sign(NSSConfigDir, certNames, certCount, argv[2], argv[3]); case 'r': return strip_signature_block(argv[2], argv[3]); #endif /* endif NO_SIGN_VERIFY disabled */ default: print_usage(); return -1; } }
void nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert, nsIInterfaceRequestor* ctx, nsCString &nickname) { nickname.Truncate(); nsNSSShutDownPreventionLock locker; nsresult rv; CK_OBJECT_HANDLE keyHandle; CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB(); nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); if (NS_FAILED(rv)) return; nsCAutoString username; char *temp_un = CERT_GetCommonName(&cert->subject); if (temp_un) { username = temp_un; PORT_Free(temp_un); temp_un = nsnull; } nsCAutoString caname; char *temp_ca = CERT_GetOrgName(&cert->issuer); if (temp_ca) { caname = temp_ca; PORT_Free(temp_ca); temp_ca = nsnull; } nsAutoString tmpNickFmt; nssComponent->GetPIPNSSBundleString("nick_template", tmpNickFmt); NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt); nsCAutoString baseName; char *temp_nn = PR_smprintf(nickFmt.get(), username.get(), caname.get()); if (!temp_nn) { return; } else { baseName = temp_nn; PR_smprintf_free(temp_nn); temp_nn = nsnull; } nickname = baseName; /* * We need to see if the private key exists on a token, if it does * then we need to check for nicknames that already exist on the smart * card. */ PK11SlotInfo *slot = PK11_KeyForCertExists(cert, &keyHandle, ctx); PK11SlotInfoCleaner slotCleaner(slot); if (!slot) return; if (!PK11_IsInternal(slot)) { char *tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), baseName.get()); if (!tmp) { nickname.Truncate(); return; } baseName = tmp; PR_smprintf_free(tmp); nickname = baseName; } int count = 1; while (true) { if ( count > 1 ) { char *tmp = PR_smprintf("%s #%d", baseName.get(), count); if (!tmp) { nickname.Truncate(); return; } nickname = tmp; PR_smprintf_free(tmp); } CERTCertificate *dummycert = nsnull; CERTCertificateCleaner dummycertCleaner(dummycert); if (PK11_IsInternal(slot)) { /* look up the nickname to make sure it isn't in use already */ dummycert = CERT_FindCertByNickname(defaultcertdb, nickname.get()); } else { /* * Check the cert against others that already live on the smart * card. */ dummycert = PK11_FindCertFromNickname(nickname.get(), ctx); if (dummycert != NULL) { /* * Make sure the subject names are different. */ if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual) { /* * There is another certificate with the same nickname and * the same subject name on the smart card, so let's use this * nickname. */ CERT_DestroyCertificate(dummycert); dummycert = NULL; } } } if (!dummycert) break; count++; } }
/********************************************************************* * * c r e a t e _ p k 7 */ static int create_pk7 (char *dir, char *keyName, int *keyType) { int status = 0; char *file_ext; CERTCertificate * cert; CERTCertDBHandle * db; FILE * in, *out; char sf_file [FNSIZE]; char pk7_file [FNSIZE]; /* open cert database */ db = CERT_GetDefaultCertDB(); if (db == NULL) return - 1; /* find cert */ /*cert = CERT_FindCertByNicknameOrEmailAddr(db, keyName);*/ cert = PK11_FindCertFromNickname(keyName, &pwdata); if (cert == NULL) { SECU_PrintError ( PROGRAM_NAME, "Cannot find the cert \"%s\"", keyName); return -1; } /* determine the key type, which sets the extension for pkcs7 object */ *keyType = jar_find_key_type (cert); file_ext = (*keyType == dsaKey) ? "dsa" : "rsa"; sprintf (sf_file, "%s/META-INF/%s.sf", dir, base); sprintf (pk7_file, "%s/META-INF/%s.%s", dir, base, file_ext); if ((in = fopen (sf_file, "rb")) == NULL) { PR_fprintf(errorFD, "%s: Can't open %s for reading\n", PROGRAM_NAME, sf_file); errorCount++; exit (ERRX); } if ((out = fopen (pk7_file, "wb")) == NULL) { PR_fprintf(errorFD, "%s: Can't open %s for writing\n", PROGRAM_NAME, sf_file); errorCount++; exit (ERRX); } status = SignFile (out, in, cert); CERT_DestroyCertificate (cert); fclose (in); fclose (out); if (status) { PR_fprintf(errorFD, "%s: PROBLEM signing data (%s)\n", PROGRAM_NAME, SECU_ErrorString ((int16) PORT_GetError())); errorCount++; return - 1; } return 0; }
/********************************************************************* * * L i s t C e r t s */ int ListCerts(char *key, int list_certs) { int failed = 0; SECStatus rv; char *ugly_list; CERTCertDBHandle *db; CERTCertificate *cert; CERTVerifyLog errlog; errlog.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (errlog.arena == NULL) { out_of_memory(); } errlog.head = NULL; errlog.tail = NULL; errlog.count = 0; ugly_list = PORT_ZAlloc(16); if (ugly_list == NULL) { out_of_memory(); } *ugly_list = 0; db = CERT_GetDefaultCertDB(); if (list_certs == 2) { PR_fprintf(outputFD, "\nS Certificates\n"); PR_fprintf(outputFD, "- ------------\n"); } else { PR_fprintf(outputFD, "\nObject signing certificates\n"); PR_fprintf(outputFD, "---------------------------------------\n"); } num_trav_certs = 0; /* Traverse ALL tokens in all slots, authenticating to them all */ rv = PK11_TraverseSlotCerts(cert_trav_callback, (void *)&list_certs, &pwdata); if (rv) { PR_fprintf(outputFD, "**Traverse of ALL slots & tokens failed**\n"); return -1; } if (num_trav_certs == 0) { PR_fprintf(outputFD, "You don't appear to have any object signing certificates.\n"); } if (list_certs == 2) { PR_fprintf(outputFD, "- ------------\n"); } else { PR_fprintf(outputFD, "---------------------------------------\n"); } if (list_certs == 1) { PR_fprintf(outputFD, "For a list including CA's, use \"%s -L\"\n", PROGRAM_NAME); } if (list_certs == 2) { PR_fprintf(outputFD, "Certificates that can be used to sign objects have *'s to " "their left.\n"); } if (key) { /* Do an analysis of the given cert */ cert = PK11_FindCertFromNickname(key, &pwdata); if (cert) { PR_fprintf(outputFD, "\nThe certificate with nickname \"%s\" was found:\n", cert->nickname); PR_fprintf(outputFD, "\tsubject name: %s\n", cert->subjectName); PR_fprintf(outputFD, "\tissuer name: %s\n", cert->issuerName); PR_fprintf(outputFD, "\n"); rv = CERT_CertTimesValid(cert); if (rv != SECSuccess) { PR_fprintf(outputFD, "**This certificate is expired**\n"); } else { PR_fprintf(outputFD, "This certificate is not expired.\n"); } rv = CERT_VerifyCert(db, cert, PR_TRUE, certUsageObjectSigner, PR_Now(), &pwdata, &errlog); if (rv != SECSuccess) { failed = 1; if (errlog.count > 0) { PR_fprintf(outputFD, "**Certificate validation failed for the " "following reason(s):**\n"); } else { PR_fprintf(outputFD, "**Certificate validation failed**"); } } else { PR_fprintf(outputFD, "This certificate is valid.\n"); } displayVerifyLog(&errlog); } else { failed = 1; PR_fprintf(outputFD, "The certificate with nickname \"%s\" was NOT FOUND\n", key); } } if (errlog.arena != NULL) { PORT_FreeArena(errlog.arena, PR_FALSE); } if (failed) { return -1; } return 0; }
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; }
static CERTCertificate * common_FindCertByNicknameOrEmailAddrForUsage(CERTCertDBHandle *handle, const char *name, PRBool anyUsage, SECCertUsage lookingForUsage) { NSSCryptoContext *cc; NSSCertificate *c, *ct; CERTCertificate *cert = NULL; NSSUsage usage; CERTCertList *certlist; if (NULL == name) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } usage.anyUsage = anyUsage; if (!anyUsage) { usage.nss3lookingForCA = PR_FALSE; usage.nss3usage = lookingForUsage; } cc = STAN_GetDefaultCryptoContext(); ct = NSSCryptoContext_FindBestCertificateByNickname(cc, name, NULL, &usage, NULL); if (!ct && PORT_Strchr(name, '@') != NULL) { char *lowercaseName = CERT_FixupEmailAddr(name); if (lowercaseName) { ct = NSSCryptoContext_FindBestCertificateByEmail( cc, lowercaseName, NULL, &usage, NULL); PORT_Free(lowercaseName); } } if (anyUsage) { cert = PK11_FindCertFromNickname(name, NULL); } else { if (ct) { /* Does ct really have the required usage? */ nssDecodedCert *dc; dc = nssCertificate_GetDecoding(ct); if (!dc->matchUsage(dc, &usage)) { CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); ct = NULL; } } certlist = PK11_FindCertsFromNickname(name, NULL); if (certlist) { SECStatus rv = CERT_FilterCertListByUsage(certlist, lookingForUsage, PR_FALSE); if (SECSuccess == rv && !CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist)) { cert = CERT_DupCertificate(CERT_LIST_HEAD(certlist)->cert); } CERT_DestroyCertList(certlist); } } if (cert) { c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert)); CERT_DestroyCertificate(cert); if (ct) { CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct)); } } else { c = ct; } return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; }
int SetServerSecParms(struct ThreadData *td) { int rv; SECKEYPrivateKey *privKey; PRFileDesc *s; s = td->r; rv = SSL_Enable(s, SSL_SECURITY, 1); /* Enable security on this socket */ if (rv < 0) return Error(10); if (SSLT_CLIENTAUTH_INITIAL == REP_ServerDoClientAuth) { rv = SSL_Enable(s, SSL_REQUEST_CERTIFICATE, 1); if (rv < 0) return Error(11); } ClearCiphers(td); EnableCiphers(td); PK11_SetPasswordFunc(MyPWFunc); SSL_SetPKCS11PinArg(s,(void*) MyPWFunc); /* Find the certificates we are going to use from the database */ /* Test for dummy certificate, which shouldn't exist */ td->cert = PK11_FindCertFromNickname("XXXXXX_CERT_HARDCOREII_1024",NULL); if (td->cert != NULL) return Error(16); td->cert = NULL; if (NO_CERT != REP_ServerCert) { td->cert = PK11_FindCertFromNickname(nicknames[REP_ServerCert],NULL); } /* Note: if we're set to use NO_CERT as the server cert, then we'll * just essentially skip the rest of this (except for session ID cache setup) */ if ( (NULL == td->cert) && ( NO_CERT != REP_ServerCert )) { PR_fprintf(PR_STDERR, "Can't find certificate %s\n", nicknames[REP_ServerCert]); PR_fprintf(PR_STDERR, "Server: Seclib error: %s\n", SECU_ErrorString ((int16) PR_GetError())); return Error(12); } if ((NO_CERT != REP_ServerCert)) { privKey = PK11_FindKeyByAnyCert(td->cert, NULL); if (privKey == NULL) { dbmsg((PR_STDERR, "Can't find key for this certificate\n")); return Error(13); } rv = SSL_ConfigSecureServer(s,td->cert,privKey, kt_rsa); if (rv != PR_SUCCESS) { dbmsg((PR_STDERR, "Can't config server error(%d) \n",rv)); return Error(14); } } rv = SSL_ConfigServerSessionIDCache(10, 0, 0, "."); if (rv != 0) { dbmsg((PR_STDERR, "Can't config server session ID cache (%d) \n",rv)); return Error(15); } return 0; }
void OsTLSServerConnectionSocket::NSSInitSocket(PRFileDesc* pDescriptor, long timeoutInSecs, const char* szPassword) { PRFileDesc *tcpSocket = NULL; PRSocketOptionData socketOption; PRStatus prStatus; SECStatus secStatus; // PRIntn hostenum; // PRNetAddr addr; SSLKEAType certKEA; tcpSocket = pDescriptor; if (socketDescriptor > OS_INVALID_SOCKET_DESCRIPTOR) { mpCert = PK11_FindCertFromNickname((char*)mCertNickname.data(), (char*)mCertPassword.data()); if (mpCert == NULL) { mbInitializeFailed = true; goto TlsError; } unsigned char* szPwd = (unsigned char*) PR_Malloc(mCertPassword.length()+ 1); strncpy((char*)szPwd, mCertPassword.data(), mCertPassword.length()+1); mpPrivKey = PK11_FindKeyByAnyCert(mpCert, (char*)szPwd); if (mpPrivKey == NULL) { mbInitializeFailed = true; goto TlsError; } if (tcpSocket) { /* Make the socket blocking. */ socketOption.option = PR_SockOpt_Nonblocking; socketOption.value.non_blocking = PR_FALSE; prStatus = PR_SetSocketOption(tcpSocket, &socketOption); if (prStatus != PR_SUCCESS) { mbInitializeFailed = true; goto TlsError; } /* Import the socket into the SSL layer. */ mpPRfd = SSL_ImportFD(NULL, tcpSocket); if (!mpPRfd) { mbInitializeFailed = true; goto TlsError; } /* Set configuration options. */ secStatus = SSL_OptionSet(mpPRfd, SSL_SECURITY, PR_TRUE); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } secStatus = SSL_OptionSet(mpPRfd, SSL_HANDSHAKE_AS_SERVER, PR_TRUE); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } secStatus = SSL_AuthCertificateHook(mpPRfd, (SSLAuthCertificate)OsTLS::AuthCertificate, (void *)CERT_GetDefaultCertDB()); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } secStatus = SSL_BadCertHook(mpPRfd, (SSLBadCertHandler)OsTLS::BadCertHandler, NULL); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } secStatus = SSL_HandshakeCallback(mpPRfd, (SSLHandshakeCallback)OsTLS::HandshakeCallback, (void*)this); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } secStatus = SSL_SetPKCS11PinArg(mpPRfd, (void*)szPassword); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } certKEA = NSS_FindCertKEAType(mpCert); secStatus = SSL_ConfigSecureServer(mpPRfd, mpCert, mpPrivKey, certKEA); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } secStatus = SSL_ResetHandshake(mpPRfd, /* asServer */ PR_TRUE); if (secStatus != SECSuccess) { mbInitializeFailed = true; goto TlsError; } PR_Free(szPwd); } else { mIsConnected = FALSE; OsConnectionSocket::close(); mbInitializeFailed = true; } } TlsError: return; }
// Constructor OsTLSServerSocket::OsTLSServerSocket(int connectionQueueSize, int serverPort, UtlString certNickname, UtlString certPassword, UtlString dbLocation, const UtlString bindAddress) : OsServerSocket(connectionQueueSize,serverPort, bindAddress.data(), false), mCertNickname(certNickname), mCertPassword(certPassword), mDbLocation(dbLocation), mpMozillaSSLSocket(NULL), mpCert(NULL), mpPrivKey(NULL), mTlsInitCode(TLS_INIT_SUCCESS) { PRSocketOptionData socketOption; PRStatus prStatus; SECStatus secStatus; // import the newly created socket into NSS, and set the PRFileDesc. if (socketDescriptor > OS_INVALID_SOCKET_DESCRIPTOR) { /* Call the NSPR initialization routines. */ PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); /* Set the cert database password callback. */ PK11_SetPasswordFunc(OsTLS::PasswordCallback); secStatus = NSS_Init(dbLocation.data()); if (secStatus != SECSuccess) { mTlsInitCode = TLS_INIT_DATABASE_FAILURE; return ; } /* Set the policy for this server (REQUIRED - no default). */ secStatus = NSS_SetExportPolicy(); if (secStatus != SECSuccess) { mTlsInitCode = TLS_INIT_DATABASE_FAILURE; return ; } /* Get own certificate and private key. */ mpCert = PK11_FindCertFromNickname((char*) certNickname.data(), (void*)certPassword.data()); if (mpCert == NULL) { return ; } unsigned char* szPwd = (unsigned char*) PR_Malloc(certPassword.length()+ 1); strncpy((char*)szPwd, certPassword.data(), certPassword.length()+1); mpPrivKey = PK11_FindKeyByAnyCert(mpCert, (void*)szPwd); if (mpPrivKey == NULL) { mTlsInitCode = TLS_INIT_BAD_PASSWORD; // probably a wrong password return ; } /* Configure the server's cache for a multi-process application * using default timeout values (24 hrs) and directory location (/tmp). */ SSL_ConfigMPServerSIDCache(256, 0, 0, NULL); mpMozillaSSLSocket = PR_ImportTCPSocket(socketDescriptor); if (!mpMozillaSSLSocket) { mTlsInitCode = TLS_INIT_TCP_IMPORT_FAILURE; } else { /* Make the socket blocking. */ socketOption.option = PR_SockOpt_Nonblocking; socketOption.value.non_blocking = PR_FALSE; prStatus = PR_SetSocketOption(mpMozillaSSLSocket, &socketOption); if (prStatus != PR_SUCCESS) { mTlsInitCode = TLS_INIT_NSS_FAILURE; return; } secStatus = SSL_CipherPrefSetDefault(SSL_RSA_WITH_NULL_MD5, PR_TRUE); if (secStatus != SECSuccess) { mTlsInitCode = TLS_INIT_NSS_FAILURE; return; } PRNetAddr addr; /* Configure the network connection. */ addr.inet.family = PR_AF_INET; addr.inet.ip = inet_addr(bindAddress.data()); addr.inet.port = PR_htons(serverPort); /* Bind the address to the listener socket. */ prStatus = PR_Bind(mpMozillaSSLSocket, &addr); if (prStatus != PR_SUCCESS) { mTlsInitCode = TLS_INIT_NSS_FAILURE; return; } /* Listen for connection on the socket. The second argument is * the maximum size of the queue for pending connections. */ prStatus = PR_Listen(mpMozillaSSLSocket, connectionQueueSize); if (prStatus != PR_SUCCESS) { mTlsInitCode = TLS_INIT_NSS_FAILURE; return; } } } }
static int nss_load_cert(struct ssl_connect_data *ssl, const char *filename, PRBool cacert) { #ifdef HAVE_PK11_CREATEGENERICOBJECT /* All CA and trust objects go into slot 0. Other slots are used * for storing certificates. */ const int slot_id = (cacert) ? 0 : 1; #endif CERTCertificate *cert; char *nickname = NULL; char *n = NULL; /* If there is no slash in the filename it is assumed to be a regular * NSS nickname. */ if(is_file(filename)) { n = strrchr(filename, '/'); if(n) n++; if(!mod) return 1; } else { /* A nickname from the NSS internal database */ if(cacert) return 0; /* You can't specify an NSS CA nickname this way */ nickname = strdup(filename); if(!nickname) return 0; goto done; } #ifdef HAVE_PK11_CREATEGENERICOBJECT nickname = aprintf("PEM Token #%d:%s", slot_id, n); if(!nickname) return 0; if(CURLE_OK != nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert)) { free(nickname); return 0; } #else /* We don't have PK11_CreateGenericObject but a file-based cert was passed * in. We need to fail. */ return 0; #endif done: /* Double-check that the certificate or nickname requested exists in * either the token or the NSS certificate database. */ if(!cacert) { cert = PK11_FindCertFromNickname((char *)nickname, NULL); /* An invalid nickname was passed in */ if(cert == NULL) { free(nickname); PR_SetError(SEC_ERROR_UNKNOWN_CERT, 0); return 0; } CERT_DestroyCertificate(cert); } free(nickname); return 1; }
static int nss_load_cert(struct ssl_connect_data *ssl, const char *filename, PRBool cacert) { #ifdef HAVE_PK11_CREATEGENERICOBJECT CK_SLOT_ID slotID; PK11SlotInfo * slot = NULL; CK_ATTRIBUTE *attrs; CK_ATTRIBUTE theTemplate[20]; CK_BBOOL cktrue = CK_TRUE; CK_BBOOL ckfalse = CK_FALSE; CK_OBJECT_CLASS objClass = CKO_CERTIFICATE; char slotname[SLOTSIZE]; #endif CERTCertificate *cert; char *nickname = NULL; char *n = NULL; /* If there is no slash in the filename it is assumed to be a regular * NSS nickname. */ if(is_file(filename)) { n = strrchr(filename, '/'); if(n) n++; if(!mod) return 1; } else { /* A nickname from the NSS internal database */ if(cacert) return 0; /* You can't specify an NSS CA nickname this way */ nickname = strdup(filename); if(!nickname) return 0; goto done; } #ifdef HAVE_PK11_CREATEGENERICOBJECT attrs = theTemplate; /* All CA and trust objects go into slot 0. Other slots are used * for storing certificates. With each new user certificate we increment * the slot count. We only support 1 user certificate right now. */ if(cacert) slotID = 0; else slotID = 1; snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID); nickname = aprintf("PEM Token #%ld:%s", slotID, n); if(!nickname) return 0; slot = PK11_FindSlotByName(slotname); if(!slot) { free(nickname); return 0; } PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++; PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++; PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1); attrs++; if(cacert) { PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); } else { PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); } attrs++; /* This load the certificate in our PEM module into the appropriate * slot. */ ssl->cacert[slotID] = PK11_CreateGenericObject(slot, theTemplate, 4, PR_FALSE /* isPerm */); PK11_FreeSlot(slot); if(ssl->cacert[slotID] == NULL) { free(nickname); return 0; } #else /* We don't have PK11_CreateGenericObject but a file-based cert was passed * in. We need to fail. */ return 0; #endif done: /* Double-check that the certificate or nickname requested exists in * either the token or the NSS certificate database. */ if(!cacert) { cert = PK11_FindCertFromNickname((char *)nickname, NULL); /* An invalid nickname was passed in */ if(cert == NULL) { free(nickname); PR_SetError(SEC_ERROR_UNKNOWN_CERT, 0); return 0; } CERT_DestroyCertificate(cert); } free(nickname); return 1; }
SECStatus ConfigSecureServerWithNamedCert(PRFileDesc *fd, const char *certName, /*optional*/ ScopedCERTCertificate *certOut, /*optional*/ SSLKEAType *keaOut) { ScopedCERTCertificate cert(PK11_FindCertFromNickname(certName, nullptr)); if (!cert) { PrintPRError("PK11_FindCertFromNickname failed"); return SECFailure; } // If an intermediate certificate issued the server certificate (rather than // directly by a trust anchor), we want to send it along in the handshake so // we don't encounter unknown issuer errors when that's not what we're // testing. UniqueCERTCertificateList certList; ScopedCERTCertificate issuerCert( CERT_FindCertByName(CERT_GetDefaultCertDB(), &cert->derIssuer)); // If we can't find the issuer cert, continue without it. if (issuerCert) { // Sadly, CERTCertificateList does not have a CERT_NewCertificateList // utility function, so we must create it ourselves. This consists // of creating an arena, allocating space for the CERTCertificateList, // and then transferring ownership of the arena to that list. ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!arena) { PrintPRError("PORT_NewArena failed"); return SECFailure; } certList.reset(static_cast<CERTCertificateList*>( PORT_ArenaAlloc(arena.get(), sizeof(CERTCertificateList)))); if (!certList) { PrintPRError("PORT_ArenaAlloc failed"); return SECFailure; } certList->arena = arena.forget(); // We also have to manually copy the certificates we care about to the // list, because there aren't any utility functions for that either. certList->certs = reinterpret_cast<SECItem*>( PORT_ArenaAlloc(certList->arena, 2 * sizeof(SECItem))); if (SECITEM_CopyItem(certList->arena, certList->certs, &cert->derCert) != SECSuccess) { PrintPRError("SECITEM_CopyItem failed"); return SECFailure; } if (SECITEM_CopyItem(certList->arena, certList->certs + 1, &issuerCert->derCert) != SECSuccess) { PrintPRError("SECITEM_CopyItem failed"); return SECFailure; } certList->len = 2; } ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); UniqueSECKEYPrivateKey key( PK11_FindKeyByDERCert(slot.get(), cert.get(), nullptr)); if (!key) { PrintPRError("PK11_FindKeyByDERCert failed"); return SECFailure; } SSLKEAType certKEA = NSS_FindCertKEAType(cert); if (SSL_ConfigSecureServerWithCertChain(fd, cert.get(), certList.get(), key.get(), certKEA) != SECSuccess) { PrintPRError("SSL_ConfigSecureServer failed"); return SECFailure; } if (certOut) { *certOut = cert.forget(); } if (keaOut) { *keaOut = certKEA; } return SECSuccess; }
/* * Find a user certificate that matchs the given criteria. * * "handle" - database to search * "nickname" - nickname to match * "usage" - certificate usage to match * "validOnly" - only return certs that are curently valid * "proto_win" - window handle passed to pkcs11 */ CERTCertificate * CERT_FindUserCertByUsage(CERTCertDBHandle *handle, const char *nickname, SECCertUsage usage, PRBool validOnly, void *proto_win) { CERTCertificate *cert = NULL; CERTCertList *certList = NULL; SECStatus rv; int64 time; time = PR_Now(); /* use the pk11 call so that we pick up any certs on tokens, * which may require login */ /* XXX - why is this restricted? */ if ( proto_win != NULL ) { cert = PK11_FindCertFromNickname(nickname,proto_win); } /* sigh, There are still problems find smart cards from the temp * db. This will get smart cards working again. The real fix * is to make sure we can search the temp db by their token nickname. */ if (cert == NULL) { cert = CERT_FindCertByNickname(handle,nickname); } if ( cert != NULL ) { unsigned int requiredKeyUsage; unsigned int requiredCertType; rv = CERT_KeyUsageAndTypeForCertUsage(usage, PR_FALSE, &requiredKeyUsage, &requiredCertType); if ( rv != SECSuccess ) { /* drop the extra reference */ CERT_DestroyCertificate(cert); cert = NULL; goto loser; } /* If we already found the right cert, just return it */ if ( (!validOnly || CERT_CheckCertValidTimes(cert, time, PR_FALSE) == secCertTimeValid) && (CERT_CheckKeyUsage(cert, requiredKeyUsage) == SECSuccess) && (cert->nsCertType & requiredCertType) && CERT_IsUserCert(cert) ) { return(cert); } /* collect certs for this nickname, sorting them into the list */ certList = CERT_CreateSubjectCertList(certList, handle, &cert->derSubject, time, validOnly); CERT_FilterCertListForUserCerts(certList); /* drop the extra reference */ CERT_DestroyCertificate(cert); cert = NULL; } if ( certList == NULL ) { goto loser; } /* remove certs with incorrect usage */ rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE); if ( rv != SECSuccess ) { goto loser; } if ( ! CERT_LIST_END(CERT_LIST_HEAD(certList), certList) ) { cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert); } loser: if ( certList != NULL ) { CERT_DestroyCertList(certList); } return(cert); }
/* * Find all user certificates that match the given criteria. * * "handle" - database to search * "usage" - certificate usage to match * "oneCertPerName" - if set then only return the "best" cert per * name * "validOnly" - only return certs that are curently valid * "proto_win" - window handle passed to pkcs11 */ CERTCertList * CERT_FindUserCertsByUsage(CERTCertDBHandle *handle, SECCertUsage usage, PRBool oneCertPerName, PRBool validOnly, void *proto_win) { CERTCertNicknames *nicknames = NULL; char **nnptr; int nn; CERTCertificate *cert = NULL; CERTCertList *certList = NULL; SECStatus rv; int64 time; CERTCertListNode *node = NULL; CERTCertListNode *freenode = NULL; int n; time = PR_Now(); nicknames = CERT_GetCertNicknames(handle, SEC_CERT_NICKNAMES_USER, proto_win); if ( ( nicknames == NULL ) || ( nicknames->numnicknames == 0 ) ) { goto loser; } nnptr = nicknames->nicknames; nn = nicknames->numnicknames; while ( nn > 0 ) { cert = NULL; /* use the pk11 call so that we pick up any certs on tokens, * which may require login */ if ( proto_win != NULL ) { cert = PK11_FindCertFromNickname(*nnptr,proto_win); } /* Sigh, It turns out if the cert is already in the temp db, because * it's in the perm db, then the nickname lookup doesn't work. * since we already have the cert here, though, than we can just call * CERT_CreateSubjectCertList directly. For those cases where we didn't * find the cert in pkcs #11 (because we didn't have a password arg, * or because the nickname is for a peer, server, or CA cert, then we * go look the cert up. */ if (cert == NULL) { cert = CERT_FindCertByNickname(handle,*nnptr); } if ( cert != NULL ) { /* collect certs for this nickname, sorting them into the list */ certList = CERT_CreateSubjectCertList(certList, handle, &cert->derSubject, time, validOnly); CERT_FilterCertListForUserCerts(certList); /* drop the extra reference */ CERT_DestroyCertificate(cert); } nnptr++; nn--; } /* remove certs with incorrect usage */ rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE); if ( rv != SECSuccess ) { goto loser; } /* remove any extra certs for each name */ if ( oneCertPerName ) { PRBool *flags; nn = nicknames->numnicknames; nnptr = nicknames->nicknames; flags = (PRBool *)PORT_ZAlloc(sizeof(PRBool) * nn); if ( flags == NULL ) { goto loser; } node = CERT_LIST_HEAD(certList); /* treverse all certs in the list */ while ( !CERT_LIST_END(node, certList) ) { /* find matching nickname index */ for ( n = 0; n < nn; n++ ) { if ( CERT_MatchNickname(nnptr[n], node->cert->nickname) ) { /* We found a match. If this is the first one, then * set the flag and move on to the next cert. If this * is not the first one then delete it from the list. */ if ( flags[n] ) { /* We have already seen a cert with this nickname, * so delete this one. */ freenode = node; node = CERT_LIST_NEXT(node); CERT_RemoveCertListNode(freenode); } else { /* keep the first cert for each nickname, but set the * flag so we know to delete any others with the same * nickname. */ flags[n] = PR_TRUE; node = CERT_LIST_NEXT(node); } break; } } if ( n == nn ) { /* if we get here it means that we didn't find a matching * nickname, which should not happen. */ PORT_Assert(0); node = CERT_LIST_NEXT(node); } } PORT_Free(flags); } goto done; loser: if ( certList != NULL ) { CERT_DestroyCertList(certList); certList = NULL; } done: if ( nicknames != NULL ) { CERT_FreeNicknames(nicknames); } return(certList); }
/** * * Callback to pick the SSL client certificate. */ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct CERTDistNamesStr *caNames, struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey) { static const char pem_nickname[] = "PEM Token #1"; const char *pem_slotname = pem_nickname; struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; struct SessionHandle *data = connssl->data; const char *nickname = connssl->client_nickname; if (mod && nickname && 0 == strncmp(nickname, pem_nickname, /* length of "PEM Token" */ 9)) { /* use the cert/key provided by PEM reader */ PK11SlotInfo *slot; void *proto_win = SSL_RevealPinArg(sock); *pRetKey = NULL; *pRetCert = PK11_FindCertFromNickname(nickname, proto_win); if (NULL == *pRetCert) { failf(data, "NSS: client certificate not found: %s", nickname); return SECFailure; } slot = PK11_FindSlotByName(pem_slotname); if (NULL == slot) { failf(data, "NSS: PK11 slot not found: %s", pem_slotname); return SECFailure; } *pRetKey = PK11_FindPrivateKeyFromCert(slot, *pRetCert, NULL); PK11_FreeSlot(slot); if (NULL == *pRetKey) { failf(data, "NSS: private key not found for certificate: %s", nickname); return SECFailure; } infof(data, "NSS: client certificate: %s\n", nickname); display_cert_info(data, *pRetCert); return SECSuccess; } /* use the default NSS hook */ if (SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames, pRetCert, pRetKey) || NULL == *pRetCert) { if (NULL == nickname) failf(data, "NSS: client certificate not found (nickname not specified)"); else failf(data, "NSS: client certificate not found: %s", nickname); return SECFailure; } /* get certificate nickname if any */ nickname = (*pRetCert)->nickname; if (NULL == nickname) nickname = "[unknown]"; if (NULL == *pRetKey) { failf(data, "NSS: private key not found for certificate: %s", nickname); return SECFailure; } infof(data, "NSS: using client certificate: %s\n", nickname); display_cert_info(data, *pRetCert); return SECSuccess; }
int __pmSecureServerInit(void) { const PRUint16 *cipher; SECStatus secsts; int pathSpecified; int sts = 0; PM_INIT_LOCKS(); PM_LOCK(secureserver_lock); /* Only attempt this once. */ if (secure_server.initialized) goto done; secure_server.initialized = 1; if (PR_Initialized() != PR_TRUE) PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); /* Configure optional (cmdline) password file in case DB locked */ PK11_SetPasswordFunc(certificate_database_password); /* * Configure location of the NSS database with a sane default. * For servers, we default to the shared (sql) system-wide database. * If command line db specified, pass it directly through - allowing * any old database format, at the users discretion. */ if (!secure_server.database_path[0]) { const char *path; pathSpecified = 0; path = serverdb(secure_server.database_path, MAXPATHLEN, "sql:"); /* this is the default case on some platforms, so no log spam */ if (access(path, R_OK|X_OK) < 0) { if (pmDebugOptions.context) pmNotifyErr(LOG_INFO, "Cannot access system security database: %s", secure_server.database_path); sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } } else pathSpecified = 1; /* * pmproxy acts as both a client and server. Since the * server init path happens first, the db previously * got opened readonly. Instead try to open RW. * Fallback if there is an error. */ secsts = NSS_InitReadWrite(secure_server.database_path); if( secsts != SECSuccess ) secsts = NSS_Init(secure_server.database_path); if (secsts != SECSuccess && !pathSpecified) { /* fallback, older versions of NSS do not support sql: */ serverdb(secure_server.database_path, MAXPATHLEN, ""); secsts = NSS_Init(secure_server.database_path); } if (secsts != SECSuccess) { pmNotifyErr(LOG_ERR, "Cannot setup certificate DB (%s): %s", secure_server.database_path, pmErrStr(__pmSecureSocketsError(PR_GetError()))); sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } /* Some NSS versions don't do this correctly in NSS_SetDomesticPolicy. */ for (cipher = SSL_GetImplementedCiphers(); *cipher != 0; ++cipher) SSL_CipherPolicySet(*cipher, SSL_ALLOWED); /* Configure SSL session cache for multi-process server, using defaults */ secsts = SSL_ConfigMPServerSIDCache(1, 0, 0, NULL); if (secsts != SECSuccess) { pmNotifyErr(LOG_ERR, "Unable to configure SSL session ID cache: %s", pmErrStr(__pmSecureSocketsError(PR_GetError()))); sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } else { secure_server.ssl_session_cache_setup = 1; } /* * Iterate over any/all PCP Collector nickname certificates, * seeking one valid certificate. No-such-nickname is not an * error (not configured by admin at all) but anything else is. */ CERTCertList *certlist; CERTCertDBHandle *nssdb = CERT_GetDefaultCertDB(); CERTCertificate *dbcert = PK11_FindCertFromNickname(secure_server.cert_nickname, NULL); if (dbcert) { PRTime now = PR_Now(); SECItem *name = &dbcert->derSubject; CERTCertListNode *node; certlist = CERT_CreateSubjectCertList(NULL, nssdb, name, now, PR_FALSE); if (certlist) { for (node = CERT_LIST_HEAD(certlist); !CERT_LIST_END(node, certlist); node = CERT_LIST_NEXT (node)) { if (pmDebugOptions.context) __pmDumpCertificate(stderr, secure_server.cert_nickname, node->cert); if (!__pmValidCertificate(nssdb, node->cert, now)) continue; secure_server.certificate_verified = 1; break; } CERT_DestroyCertList(certlist); } if (secure_server.certificate_verified) { secure_server.certificate_KEA = NSS_FindCertKEAType(dbcert); secure_server.private_key = PK11_FindKeyByAnyCert(dbcert, NULL); if (!secure_server.private_key) { pmNotifyErr(LOG_ERR, "Unable to extract %s private key", secure_server.cert_nickname); CERT_DestroyCertificate(dbcert); secure_server.certificate_verified = 0; sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } } else { pmNotifyErr(LOG_ERR, "Unable to find a valid %s", secure_server.cert_nickname); CERT_DestroyCertificate(dbcert); sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } } if (! secure_server.certificate_verified) { if (pmDebugOptions.context) { pmNotifyErr(LOG_INFO, "No valid %s in security database: %s", secure_server.cert_nickname, secure_server.database_path); } sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } secure_server.certificate = dbcert; secure_server.init_failed = 0; sts = 0; done: PM_UNLOCK(secureserver_lock); return sts; }
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; }