NS_IMETHODIMP nsNSSCertificateDB::FindCertByEmailAddress(nsISupports *aToken, const char *aEmailAddress, nsIX509Cert **_retval) { nsNSSShutDownPreventionLock locker; CERTCertificate *any_cert = CERT_FindCertByNicknameOrEmailAddr(CERT_GetDefaultCertDB(), (char*)aEmailAddress); if (!any_cert) return NS_ERROR_FAILURE; CERTCertificateCleaner certCleaner(any_cert); // any_cert now contains a cert with the right subject, but it might not have the correct usage CERTCertList *certlist = CERT_CreateSubjectCertList( nsnull, CERT_GetDefaultCertDB(), &any_cert->derSubject, PR_Now(), PR_TRUE); if (!certlist) return NS_ERROR_FAILURE; CERTCertListCleaner listCleaner(certlist); if (SECSuccess != CERT_FilterCertListByUsage(certlist, certUsageEmailRecipient, PR_FALSE)) return NS_ERROR_FAILURE; if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist)) return NS_ERROR_FAILURE; nsNSSCertificate *nssCert = new nsNSSCertificate(CERT_LIST_HEAD(certlist)->cert); if (!nssCert) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(nssCert); *_retval = static_cast<nsIX509Cert*>(nssCert); return NS_OK; }
/* * GetSortedNameList * * Converts a CERTCertList to a list of certificate names */ void nsNSSCertificateDB::getCertNames(CERTCertList *certList, PRUint32 type, PRUint32 *_count, PRUnichar ***_certNames) { nsNSSShutDownPreventionLock locker; nsresult rv; CERTCertListNode *node; PRUint32 numcerts = 0, i=0; PRUnichar **tmpArray = NULL; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("List of certs %d:\n", type)); for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList); node = CERT_LIST_NEXT(node)) { if (getCertType(node->cert) == type) { numcerts++; } } PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("num certs: %d\n", numcerts)); int nc = (numcerts == 0) ? 1 : numcerts; tmpArray = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nc); if (numcerts == 0) goto finish; for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList); node = CERT_LIST_NEXT(node)) { if (getCertType(node->cert) == type) { nsNSSCertificate pipCert(node->cert); char *dbkey = NULL; char *namestr = NULL; nsAutoString certstr; rv = pipCert.GetDbKey(&dbkey); nsAutoString keystr = NS_ConvertASCIItoUTF16(dbkey); PR_FREEIF(dbkey); if (type == nsIX509Cert::EMAIL_CERT) { namestr = node->cert->emailAddr; } else { namestr = node->cert->nickname; if (namestr) { char *sc = strchr(namestr, ':'); if (sc) *sc = DELIM; } } if (!namestr) namestr = ""; nsAutoString certname = NS_ConvertASCIItoUTF16(namestr); certstr.Append(PRUnichar(DELIM)); certstr += certname; certstr.Append(PRUnichar(DELIM)); certstr += keystr; tmpArray[i++] = ToNewUnicode(certstr); } } finish: *_count = numcerts; *_certNames = tmpArray; }
CERTCertificateList* hack_NewCertificateListFromCertList(CERTCertList* list) { CERTCertificateList * chain = NULL; PLArenaPool * arena = NULL; CERTCertListNode * node; int len; if (CERT_LIST_EMPTY(list)) goto loser; arena = PORT_NewArena(4096); if (arena == NULL) goto loser; for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list); len++, node = CERT_LIST_NEXT(node)) { } chain = PORT_ArenaNew(arena, CERTCertificateList); if (chain == NULL) goto loser; chain->certs = PORT_ArenaNewArray(arena, SECItem, len); if (!chain->certs) goto loser; chain->len = len; for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list); len++, node = CERT_LIST_NEXT(node)) { // Check to see if the last cert to be sent is a self-signed cert, // and if so, omit it from the list of certificates. However, if // there is only one cert (len == 0), include the cert, as it means // the EE cert is self-signed. if (len > 0 && (len == chain->len - 1) && node->cert->isRoot) { chain->len = len; break; } SECITEM_CopyItem(arena, &chain->certs[len], &node->cert->derCert); } chain->arena = arena; return chain; loser: if (arena) { PORT_FreeArena(arena, PR_FALSE); } return NULL; }
CERTDistNames * CERT_DistNamesFromCertList(CERTCertList *certList) { CERTDistNames *dnames = NULL; PLArenaPool *arena; CERTCertListNode *node = NULL; SECItem *names = NULL; int listLen = 0, i = 0; if (certList == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } node = CERT_LIST_HEAD(certList); while (!CERT_LIST_END(node, certList)) { listLen += 1; node = CERT_LIST_NEXT(node); } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) goto loser; dnames = PORT_ArenaZNew(arena, CERTDistNames); if (dnames == NULL) goto loser; dnames->arena = arena; dnames->nnames = listLen; dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, listLen); if (names == NULL) goto loser; node = CERT_LIST_HEAD(certList); while (!CERT_LIST_END(node, certList)) { CERTCertificate *cert = node->cert; SECStatus rv = SECITEM_CopyItem(arena, &names[i++], &cert->derSubject); if (rv == SECFailure) { goto loser; } node = CERT_LIST_NEXT(node); } return dnames; loser: if (arena) { PORT_FreeArena(arena, PR_FALSE); } return NULL; }
CERTCertificate * CERT_FindCertByKeyID(CERTCertDBHandle *handle, SECItem *name, SECItem *keyID) { CERTCertList *list; CERTCertificate *cert = NULL; CERTCertListNode *node, *head; list = CERT_CreateSubjectCertList(NULL, handle, name, 0, PR_FALSE); if (list == NULL) return NULL; node = head = CERT_LIST_HEAD(list); if (head) { do { if (node->cert && SECITEM_ItemsAreEqual(&node->cert->subjectKeyID, keyID)) { cert = CERT_DupCertificate(node->cert); goto done; } node = CERT_LIST_NEXT(node); } while (node && head != node); } PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); done: if (list) { CERT_DestroyCertList(list); } return cert; }
/* void deleteCert (in nsIX509Cert cert); */ NS_IMETHODIMP nsNSSCertList::DeleteCert(nsIX509Cert *aCert) { /* This should be a query interface, but currently this his how the * rest of PSM is working */ nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert); CERTCertificate *cert = nssCert->GetCert(); CERTCertListNode *node; if (cert == nullptr) { NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate."); return NS_ERROR_FAILURE; } if (mCertList == nullptr) { NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList."); return NS_ERROR_FAILURE; } for (node = CERT_LIST_HEAD(mCertList); !CERT_LIST_END(node,mCertList); node = CERT_LIST_NEXT(node)) { if (node->cert == cert) { CERT_RemoveCertListNode(node); return NS_OK; } } return NS_OK; /* should we fail if we couldn't find it? */ }
static CERTCertificate *load_cert_file(sxc_client_t *sx, const char *file, struct PK11_ctx *ctx) { const char *slot_name = "PEM Token #0"; CK_OBJECT_CLASS obj_class; CK_ATTRIBUTE attrs[/* max count of attributes */ 4]; unsigned attr_cnt = 0; CK_BBOOL cktrue = CK_TRUE; SECMODModule *mod; CERTCertificate *cert = NULL; if(!file || !ctx) { sxi_seterr(sx, SXE_EARG, "NULL argument"); return NULL; } memset(ctx, 0, sizeof(*ctx)); mod = SECMOD_LoadUserModule("library=libnsspem.so name=PEM", NULL, PR_FALSE); if (!mod || !mod->loaded) { if (mod) SECMOD_DestroyModule(mod); sxi_setsyserr(sx, SXE_ECFG, "Failed to load NSS PEM library"); return NULL; } sxi_crypto_check_ver(NULL); ctx->slot = PK11_FindSlotByName(slot_name); if (ctx->slot) { obj_class = CKO_CERTIFICATE; PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class)); PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)file, strlen(file) + 1); if(CKO_CERTIFICATE == obj_class) { CK_BBOOL *pval = &cktrue; PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval)); } ctx->obj = PK11_CreateGenericObject(ctx->slot, attrs, attr_cnt, PR_FALSE); if (!ctx->obj) { sxi_seterr(sx, SXE_ECFG, "Cannot load certificate from '%s': %s, %s", file, PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT), PR_ErrorToName(PR_GetError())); return NULL; } ctx->list = PK11_ListCertsInSlot(ctx->slot); if (ctx->list) { CERTCertListNode *node = CERT_LIST_HEAD(ctx->list); cert = node ? node->cert : NULL; } } else { sxi_seterr(sx, SXE_ECFG, "Failed to initialize NSS PEM token"); return NULL; } return cert; }
SECStatus cmmf_ExtractCertsFromList(CERTCertList *inCertList, PLArenaPool *poolp, CERTCertificate ***certArray) { CERTCertificate **arrayLocalCopy; CERTCertListNode *node; int numNodes = 0, i; for (node = CERT_LIST_HEAD(inCertList); !CERT_LIST_END(node, inCertList); node = CERT_LIST_NEXT(node)) { numNodes++; } arrayLocalCopy = *certArray = (poolp == NULL) ? PORT_NewArray(CERTCertificate *, (numNodes + 1)) : PORT_ArenaNewArray(poolp, CERTCertificate *, (numNodes + 1)); if (arrayLocalCopy == NULL) { return SECFailure; } for (node = CERT_LIST_HEAD(inCertList), i = 0; !CERT_LIST_END(node, inCertList); node = CERT_LIST_NEXT(node), i++) { arrayLocalCopy[i] = CERT_DupCertificate(node->cert); if (arrayLocalCopy[i] == NULL) { int j; for (j = 0; j < i; j++) { CERT_DestroyCertificate(arrayLocalCopy[j]); } if (poolp == NULL) { PORT_Free(arrayLocalCopy); } *certArray = NULL; return SECFailure; } } arrayLocalCopy[numNodes] = NULL; return SECSuccess; }
Result AppTrustDomain::FindIssuer(Input encodedIssuerName, IssuerChecker& checker, Time) { MOZ_ASSERT(mTrustedRoot); if (!mTrustedRoot) { return Result::FATAL_ERROR_INVALID_STATE; } // TODO(bug 1035418): If/when mozilla::pkix relaxes the restriction that // FindIssuer must only pass certificates with a matching subject name to // checker.Check, we can stop using CERT_CreateSubjectCertList and instead // use logic like this: // // 1. First, try the trusted trust anchor. // 2. Secondly, iterate through the certificates that were stored in the CMS // message, passing each one to checker.Check. SECItem encodedIssuerNameSECItem = UnsafeMapInputToSECItem(encodedIssuerName); UniqueCERTCertList candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(), &encodedIssuerNameSECItem, 0, false)); if (candidates) { for (CERTCertListNode* n = CERT_LIST_HEAD(candidates); !CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) { Input certDER; Result rv = certDER.Init(n->cert->derCert.data, n->cert->derCert.len); if (rv != Success) { continue; // probably too big } bool keepGoing; rv = checker.Check(certDER, nullptr/*additionalNameConstraints*/, keepGoing); if (rv != Success) { return rv; } if (!keepGoing) { break; } } } return Success; }
/* would not do name in pluto, but dn */ static CERTCertList *get_trust_certlist(CERTCertDBHandle *handle, const char *name) { CERTCertList *trustcl = NULL; CERTCertList *tmpcl = NULL; CERTCertificate *ca = NULL; CERTCertListNode *node = NULL; if ((ca = CERT_FindCertByNickname(handle, name)) == NULL) { printf("CERT_FindCertByNickname failed %d\n", PORT_GetError()); return NULL; } if (ca->isRoot) { printf("trust anchor: %s\n",ca->subjectName); trustcl = CERT_NewCertList(); CERT_AddCertToListTail(trustcl, ca); } else { tmpcl = CERT_GetCertChainFromCert(ca, PR_Now(), certUsageAnyCA); if (tmpcl == NULL) { printf("CERT_GetCertChainFromCert failed %d\n", PORT_GetError()); return NULL; } for (node = CERT_LIST_HEAD(tmpcl); !CERT_LIST_END(node, tmpcl); node = CERT_LIST_NEXT(node)) { printf("CERT list: %s\n", node->cert->subjectName); if (node->cert->isRoot) { trustcl = CERT_NewCertList(); CERT_AddCertToListTail(trustcl, node->cert); break; } } } if (trustcl == NULL || CERT_LIST_EMPTY(trustcl)) { printf("Trust chain empty!\n"); return NULL; } return trustcl; }
CERTCertList * nsNSSCertList::DupCertList(CERTCertList *aCertList) { if (!aCertList) return nullptr; CERTCertList *newList = CERT_NewCertList(); if (newList == nullptr) { return nullptr; } CERTCertListNode *node; for (node = CERT_LIST_HEAD(aCertList); !CERT_LIST_END(node, aCertList); node = CERT_LIST_NEXT(node)) { CERTCertificate *cert = CERT_DupCertificate(node->cert); CERT_AddCertToListTail(newList, cert); } return newList; }
/* nsISupports getNext(); */ NS_IMETHODIMP nsNSSCertListEnumerator::GetNext(nsISupports **_retval) { NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE); CERTCertListNode *node = CERT_LIST_HEAD(mCertList); if (CERT_LIST_END(node, mCertList)) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(node->cert); if (!nssCert) { return NS_ERROR_OUT_OF_MEMORY; } *_retval = nssCert; NS_ADDREF(*_retval); CERT_RemoveCertListNode(node); return NS_OK; }
void SaveIntermediateCerts(const ScopedCERTCertList& certList) { if (!certList) { return; } bool isEndEntity = true; for (CERTCertListNode* node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList); node = CERT_LIST_NEXT(node)) { if (isEndEntity) { // Skip the end-entity; we only want to store intermediates isEndEntity = false; continue; } if (node->cert->slot) { // This cert was found on a token, no need to remember it in the temp db. continue; } if (node->cert->isperm) { // We don't need to remember certs already stored in perm db. continue; } // We have found a signer cert that we want to remember. char* nickname = DefaultServerNicknameForCert(node->cert); if (nickname && *nickname) { ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalKeySlot()); if (slot) { PK11_ImportCert(slot.get(), node->cert, CK_INVALID_HANDLE, nickname, false); } } PR_FREEIF(nickname); } }
static CERTCertList *get_all_root_certs(void) { PK11SlotInfo *slot = PK11_GetInternalKeySlot(); if (slot == NULL) return NULL; if (PK11_NeedLogin(slot)) { SECStatus rv = PK11_Authenticate(slot, PR_TRUE, lsw_return_nss_password_file_info()); if (rv != SECSuccess) return NULL; } CERTCertList *allcerts = PK11_ListCertsInSlot(slot); if (allcerts == NULL) return NULL; CERTCertList *roots = CERT_NewCertList(); CERTCertListNode *node; for (node = CERT_LIST_HEAD(allcerts); !CERT_LIST_END(node, allcerts); node = CERT_LIST_NEXT(node)) { if (CERT_IsCACert(node->cert, NULL) && node->cert->isRoot) { CERT_DupCertificate(node->cert); CERT_AddCertToListTail(roots, node->cert); } } CERT_DestroyCertList(allcerts); if (roots == NULL || CERT_LIST_EMPTY(roots)) return NULL; return roots; }
/* * nsIEnumerator getChain(); */ NS_IMETHODIMP nsNSSCertificate::GetChain(nsIArray **_rvChain) { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; NS_ENSURE_ARG(_rvChain); nsresult rv; /* Get the cert chain from NSS */ CERTCertList *nssChain = NULL; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting chain for \"%s\"\n", mCert->nickname)); nssChain = CERT_GetCertChainFromCert(mCert, PR_Now(), certUsageSSLClient); if (!nssChain) return NS_ERROR_FAILURE; /* enumerate the chain for scripting purposes */ nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); if (NS_FAILED(rv)) { goto done; } CERTCertListNode *node; for (node = CERT_LIST_HEAD(nssChain); !CERT_LIST_END(node, nssChain); node = CERT_LIST_NEXT(node)) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("adding %s to chain\n", node->cert->nickname)); nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert); array->AppendElement(cert, false); } *_rvChain = array; NS_IF_ADDREF(*_rvChain); rv = NS_OK; done: if (nssChain) CERT_DestroyCertList(nssChain); return rv; }
/* * 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); }
int main(int argc, char *argv[], char *envp[]) { char * certDir = NULL; char * progName = NULL; char * oidStr = NULL; CERTCertificate * cert; CERTCertificate * firstCert = NULL; CERTCertificate * issuerCert = NULL; CERTCertDBHandle * defaultDB = NULL; PRBool isAscii = PR_FALSE; PRBool trusted = PR_FALSE; SECStatus secStatus; SECCertificateUsage certUsage = certificateUsageSSLServer; PLOptState * optstate; PRTime time = 0; PLOptStatus status; int usePkix = 0; int rv = 1; int usage; CERTVerifyLog log; CERTCertList *builtChain = NULL; PRBool certFetching = PR_FALSE; int revDataIndex = 0; PRBool ocsp_fetchingFailureIsAFailure = PR_TRUE; PRBool useDefaultRevFlags = PR_TRUE; int vfyCounts = 1; PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); progName = PL_strdup(argv[0]); optstate = PL_CreateOptState(argc, argv, "ab:c:d:efg:h:i:m:o:prs:tu:vw:W:"); while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { switch(optstate->option) { case 0 : /* positional parameter */ goto breakout; case 'a' : isAscii = PR_TRUE; break; case 'b' : secStatus = DER_AsciiToTime(&time, optstate->value); if (secStatus != SECSuccess) Usage(progName); break; case 'd' : certDir = PL_strdup(optstate->value); break; case 'e' : ocsp_fetchingFailureIsAFailure = PR_FALSE; break; case 'f' : certFetching = PR_TRUE; break; case 'g' : if (revMethodsData[revDataIndex].testTypeStr || revMethodsData[revDataIndex].methodTypeStr) { revDataIndex += 1; if (revDataIndex == REV_METHOD_INDEX_MAX) { fprintf(stderr, "Invalid revocation configuration" "specified.\n"); secStatus = SECFailure; break; } } useDefaultRevFlags = PR_FALSE; revMethodsData[revDataIndex]. testTypeStr = PL_strdup(optstate->value); break; case 'h' : revMethodsData[revDataIndex]. testFlagsStr = PL_strdup(optstate->value);break; case 'i' : vfyCounts = PORT_Atoi(optstate->value); break; break; case 'm' : if (revMethodsData[revDataIndex].methodTypeStr) { revDataIndex += 1; if (revDataIndex == REV_METHOD_INDEX_MAX) { fprintf(stderr, "Invalid revocation configuration" "specified.\n"); secStatus = SECFailure; break; } } useDefaultRevFlags = PR_FALSE; revMethodsData[revDataIndex]. methodTypeStr = PL_strdup(optstate->value); break; case 'o' : oidStr = PL_strdup(optstate->value); break; case 'p' : usePkix += 1; break; case 'r' : isAscii = PR_FALSE; break; case 's' : revMethodsData[revDataIndex]. methodFlagsStr = PL_strdup(optstate->value); break; case 't' : trusted = PR_TRUE; break; case 'u' : usage = PORT_Atoi(optstate->value); if (usage < 0 || usage > 62) Usage(progName); certUsage = ((SECCertificateUsage)1) << usage; if (certUsage > certificateUsageHighest) Usage(progName); break; case 'w': pwdata.source = PW_PLAINTEXT; pwdata.data = PORT_Strdup(optstate->value); break; case 'W': pwdata.source = PW_FROMFILE; pwdata.data = PORT_Strdup(optstate->value); break; case 'v' : verbose++; break; default : Usage(progName); break; } } breakout: if (status != PL_OPT_OK) Usage(progName); if (usePkix < 2) { if (oidStr) { fprintf(stderr, "Policy oid(-o) can be used only with" " CERT_PKIXVerifyChain(-pp) function.\n"); Usage(progName); } if (trusted) { fprintf(stderr, "Cert trust flag can be used only with" " CERT_PKIXVerifyChain(-pp) function.\n"); Usage(progName); } } if (!useDefaultRevFlags && parseRevMethodsAndFlags()) { fprintf(stderr, "Invalid revocation configuration specified.\n"); goto punt; } /* Set our password function callback. */ PK11_SetPasswordFunc(SECU_GetModulePassword); /* Initialize the NSS libraries. */ if (certDir) { secStatus = NSS_Init(certDir); } else { secStatus = NSS_NoDB_Init(NULL); /* load the builtins */ SECMOD_AddNewModule("Builtins", DLL_PREFIX"nssckbi."DLL_SUFFIX, 0, 0); } if (secStatus != SECSuccess) { exitErr("NSS_Init"); } SECU_RegisterDynamicOids(); if (isOCSPEnabled()) { CERT_EnableOCSPChecking(CERT_GetDefaultCertDB()); CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB()); if (!ocsp_fetchingFailureIsAFailure) { CERT_SetOCSPFailureMode(ocspMode_FailureIsNotAVerificationFailure); } } while (status == PL_OPT_OK) { switch(optstate->option) { default : Usage(progName); break; case 'a' : isAscii = PR_TRUE; break; case 'r' : isAscii = PR_FALSE; break; case 't' : trusted = PR_TRUE; break; case 0 : /* positional parameter */ if (usePkix < 2 && trusted) { fprintf(stderr, "Cert trust flag can be used only with" " CERT_PKIXVerifyChain(-pp) function.\n"); Usage(progName); } cert = getCert(optstate->value, isAscii, progName); if (!cert) goto punt; rememberCert(cert, trusted); if (!firstCert) firstCert = cert; trusted = PR_FALSE; } status = PL_GetNextOpt(optstate); } PL_DestroyOptState(optstate); if (status == PL_OPT_BAD || !firstCert) Usage(progName); /* Initialize log structure */ log.arena = PORT_NewArena(512); log.head = log.tail = NULL; log.count = 0; do { if (usePkix < 2) { /* NOW, verify the cert chain. */ if (usePkix) { /* Use old API with libpkix validation lib */ CERT_SetUsePKIXForValidation(PR_TRUE); } if (!time) time = PR_Now(); defaultDB = CERT_GetDefaultCertDB(); secStatus = CERT_VerifyCertificate(defaultDB, firstCert, PR_TRUE /* check sig */, certUsage, time, &pwdata, /* wincx */ &log, /* error log */ NULL);/* returned usages */ } else do { static CERTValOutParam cvout[4]; static CERTValInParam cvin[6]; SECOidTag oidTag; int inParamIndex = 0; static PRUint64 revFlagsLeaf[2]; static PRUint64 revFlagsChain[2]; static CERTRevocationFlags rev; if (oidStr) { PRArenaPool *arena; SECOidData od; memset(&od, 0, sizeof od); od.offset = SEC_OID_UNKNOWN; od.desc = "User Defined Policy OID"; od.mechanism = CKM_INVALID_MECHANISM; od.supportedExtension = INVALID_CERT_EXTENSION; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( !arena ) { fprintf(stderr, "out of memory"); goto punt; } secStatus = SEC_StringToOID(arena, &od.oid, oidStr, 0); if (secStatus != SECSuccess) { PORT_FreeArena(arena, PR_FALSE); fprintf(stderr, "Can not encode oid: %s(%s)\n", oidStr, SECU_Strerror(PORT_GetError())); break; } oidTag = SECOID_AddEntry(&od); PORT_FreeArena(arena, PR_FALSE); if (oidTag == SEC_OID_UNKNOWN) { fprintf(stderr, "Can not add new oid to the dynamic " "table: %s\n", oidStr); secStatus = SECFailure; break; } cvin[inParamIndex].type = cert_pi_policyOID; cvin[inParamIndex].value.arraySize = 1; cvin[inParamIndex].value.array.oids = &oidTag; inParamIndex++; } if (trustedCertList) { cvin[inParamIndex].type = cert_pi_trustAnchors; cvin[inParamIndex].value.pointer.chain = trustedCertList; inParamIndex++; } cvin[inParamIndex].type = cert_pi_useAIACertFetch; cvin[inParamIndex].value.scalar.b = certFetching; inParamIndex++; rev.leafTests.cert_rev_flags_per_method = revFlagsLeaf; rev.chainTests.cert_rev_flags_per_method = revFlagsChain; secStatus = configureRevocationParams(&rev); if (secStatus) { fprintf(stderr, "Can not config revocation parameters "); break; } cvin[inParamIndex].type = cert_pi_revocationFlags; cvin[inParamIndex].value.pointer.revocation = &rev; inParamIndex++; if (time) { cvin[inParamIndex].type = cert_pi_date; cvin[inParamIndex].value.scalar.time = time; inParamIndex++; } cvin[inParamIndex].type = cert_pi_end; cvout[0].type = cert_po_trustAnchor; cvout[0].value.pointer.cert = NULL; cvout[1].type = cert_po_certList; cvout[1].value.pointer.chain = NULL; /* setting pointer to CERTVerifyLog. Initialized structure * will be used CERT_PKIXVerifyCert */ cvout[2].type = cert_po_errorLog; cvout[2].value.pointer.log = &log; cvout[3].type = cert_po_end; secStatus = CERT_PKIXVerifyCert(firstCert, certUsage, cvin, cvout, &pwdata); if (secStatus != SECSuccess) { break; } issuerCert = cvout[0].value.pointer.cert; builtChain = cvout[1].value.pointer.chain; } while (0); /* Display validation results */ if (secStatus != SECSuccess || log.count > 0) { CERTVerifyLogNode *node = NULL; PRIntn err = PR_GetError(); fprintf(stderr, "Chain is bad, %d = %s\n", err, SECU_Strerror(err)); SECU_displayVerifyLog(stderr, &log, verbose); /* Have cert refs in the log only in case of failure. * Destroy them. */ for (node = log.head; node; node = node->next) { if (node->cert) CERT_DestroyCertificate(node->cert); } rv = 1; } else { fprintf(stderr, "Chain is good!\n"); if (issuerCert) { if (verbose > 1) { rv = SEC_PrintCertificateAndTrust(issuerCert, "Root Certificate", NULL); if (rv != SECSuccess) { SECU_PrintError(progName, "problem printing certificate"); } } else if (verbose > 0) { SECU_PrintName(stdout, &issuerCert->subject, "Root " "Certificate Subject:", 0); } CERT_DestroyCertificate(issuerCert); } if (builtChain) { CERTCertListNode *node; int count = 0; char buff[256]; if (verbose) { for(node = CERT_LIST_HEAD(builtChain); !CERT_LIST_END(node, builtChain); node = CERT_LIST_NEXT(node), count++ ) { sprintf(buff, "Certificate %d Subject", count + 1); SECU_PrintName(stdout, &node->cert->subject, buff, 0); } } CERT_DestroyCertList(builtChain); } rv = 0; } } while (--vfyCounts > 0); /* Need to destroy CERTVerifyLog arena at the end */ PORT_FreeArena(log.arena, PR_FALSE); punt: forgetCerts(); if (NSS_Shutdown() != SECSuccess) { SECU_PrintError(progName, "NSS_Shutdown"); rv = 1; } PORT_Free(progName); PORT_Free(certDir); PORT_Free(oidStr); freeRevocationMethodData(); if (pwdata.data) { PORT_Free(pwdata.data); } PR_Cleanup(); return rv; }
nsresult nsNSSCertificateDB::ImportValidCACertsInList(CERTCertList *certList, nsIInterfaceRequestor *ctx) { SECItem **rawArray; /* filter out the certs we don't want */ SECStatus srv = CERT_FilterCertListByUsage(certList, certUsageAnyCA, PR_TRUE); if (srv != SECSuccess) { return NS_ERROR_FAILURE; } /* go down the remaining list of certs and verify that they have * valid chains, if yes, then import. */ PRTime now = PR_Now(); CERTCertListNode *node; for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node,certList); node = CERT_LIST_NEXT(node)) { bool alert_and_skip = false; if (CERT_VerifyCert(CERT_GetDefaultCertDB(), node->cert, PR_TRUE, certUsageVerifyCA, now, ctx, NULL) != SECSuccess) { alert_and_skip = true; } CERTCertificateList *certChain = nsnull; CERTCertificateListCleaner chainCleaner(certChain); if (!alert_and_skip) { certChain = CERT_CertChainFromCert(node->cert, certUsageAnyCA, PR_FALSE); if (!certChain) { alert_and_skip = true; } } if (alert_and_skip) { nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(node->cert); DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow); continue; } /* * CertChain returns an array of SECItems, import expects an array of * SECItem pointers. Create the SECItem Pointers from the array of * SECItems. */ rawArray = (SECItem **) PORT_Alloc(certChain->len * sizeof(SECItem *)); if (!rawArray) { continue; } for (int i=0; i < certChain->len; i++) { rawArray[i] = &certChain->certs[i]; } CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageAnyCA, certChain->len, rawArray, NULL, PR_TRUE, PR_TRUE, NULL); PORT_Free(rawArray); } return NS_OK; }
NS_IMETHODIMP nsCertPicker::PickByUsage(nsIInterfaceRequestor *ctx, const PRUnichar *selectedNickname, PRInt32 certUsage, bool allowInvalid, bool allowDuplicateNicknames, bool *canceled, nsIX509Cert **_retval) { nsNSSShutDownPreventionLock locker; PRInt32 selectedIndex = -1; bool selectionFound = false; PRUnichar **certNicknameList = nsnull; PRUnichar **certDetailsList = nsnull; CERTCertListNode* node = nsnull; nsresult rv = NS_OK; { // Iterate over all certs. This assures that user is logged in to all hardware tokens. CERTCertList *allcerts = nsnull; nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); allcerts = PK11_ListCerts(PK11CertListUnique, ctx); CERT_DestroyCertList(allcerts); } /* find all user certs that are valid and for SSL */ /* note that we are allowing expired certs in this list */ CERTCertList *certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), (SECCertUsage)certUsage, !allowDuplicateNicknames, !allowInvalid, ctx); CERTCertListCleaner clc(certList); if (!certList) { return NS_ERROR_NOT_AVAILABLE; } CERTCertNicknames *nicknames = getNSSCertNicknamesFromCertList(certList); CERTCertNicknamesCleaner cnc(nicknames); if (!nicknames) { return NS_ERROR_NOT_AVAILABLE; } certNicknameList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames); certDetailsList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames); if (!certNicknameList || !certDetailsList) { nsMemory::Free(certNicknameList); nsMemory::Free(certDetailsList); return NS_ERROR_OUT_OF_MEMORY; } PRInt32 CertsToUse; for (CertsToUse = 0, node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList) && CertsToUse < nicknames->numnicknames; node = CERT_LIST_NEXT(node) ) { nsNSSCertificate *tempCert = nsNSSCertificate::Create(node->cert); if (tempCert) { // XXX we really should be using an nsCOMPtr instead of manually add-refing, // but nsNSSCertificate does not have a default constructor. NS_ADDREF(tempCert); nsAutoString i_nickname(NS_ConvertUTF8toUTF16(nicknames->nicknames[CertsToUse])); nsAutoString nickWithSerial; nsAutoString details; if (!selectionFound) { if (i_nickname == nsDependentString(selectedNickname)) { selectedIndex = CertsToUse; selectionFound = PR_TRUE; } } if (NS_SUCCEEDED(tempCert->FormatUIStrings(i_nickname, nickWithSerial, details))) { certNicknameList[CertsToUse] = ToNewUnicode(nickWithSerial); certDetailsList[CertsToUse] = ToNewUnicode(details); } else { certNicknameList[CertsToUse] = nsnull; certDetailsList[CertsToUse] = nsnull; } NS_RELEASE(tempCert); ++CertsToUse; } } if (CertsToUse) { nsICertPickDialogs *dialogs = nsnull; rv = getNSSDialogs((void**)&dialogs, NS_GET_IID(nsICertPickDialogs), NS_CERTPICKDIALOGS_CONTRACTID); if (NS_SUCCEEDED(rv)) { nsPSMUITracker tracker; if (tracker.isUIForbidden()) { rv = NS_ERROR_NOT_AVAILABLE; } else { /* Throw up the cert picker dialog and get back the index of the selected cert */ rv = dialogs->PickCertificate(ctx, (const PRUnichar**)certNicknameList, (const PRUnichar**)certDetailsList, CertsToUse, &selectedIndex, canceled); } NS_RELEASE(dialogs); } } PRInt32 i; for (i = 0; i < CertsToUse; ++i) { nsMemory::Free(certNicknameList[i]); nsMemory::Free(certDetailsList[i]); } nsMemory::Free(certNicknameList); nsMemory::Free(certDetailsList); if (!CertsToUse) { return NS_ERROR_NOT_AVAILABLE; } if (NS_SUCCEEDED(rv) && !*canceled) { for (i = 0, node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList); ++i, node = CERT_LIST_NEXT(node)) { if (i == selectedIndex) { nsNSSCertificate *cert = nsNSSCertificate::Create(node->cert); if (!cert) { rv = NS_ERROR_OUT_OF_MEMORY; break; } nsIX509Cert *x509 = 0; nsresult rv = cert->QueryInterface(NS_GET_IID(nsIX509Cert), (void**)&x509); if (NS_FAILED(rv)) { break; } NS_ADDREF(x509); *_retval = x509; NS_RELEASE(cert); break; } } } return rv; }
// Recursively build the path from the given subject certificate to the root. // // Be very careful about changing the order of checks. The order is significant // because it affects which error we return when a certificate or certificate // chain has multiple problems. See the error ranking documentation in // pkix/pkix.h. static Result BuildForward(TrustDomain& trustDomain, BackCert& subject, PRTime time, EndEntityOrCA endEntityOrCA, KeyUsages requiredKeyUsagesIfPresent, KeyPurposeId requiredEKUIfPresent, const CertPolicyId& requiredPolicy, /*optional*/ const SECItem* stapledOCSPResponse, unsigned int subCACount, /*out*/ ScopedCERTCertList& results) { Result rv; TrustLevel trustLevel; // If this is an end-entity and not a trust anchor, we defer reporting // any error found here until after attempting to find a valid chain. // See the explanation of error prioritization in pkix.h. rv = CheckIssuerIndependentProperties(trustDomain, subject, time, endEntityOrCA, requiredKeyUsagesIfPresent, requiredEKUIfPresent, requiredPolicy, subCACount, &trustLevel); PRErrorCode deferredEndEntityError = 0; if (rv != Success) { if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity && trustLevel != TrustLevel::TrustAnchor) { deferredEndEntityError = PR_GetError(); } else { return rv; } } if (trustLevel == TrustLevel::TrustAnchor) { // End of the recursion. // Construct the results cert chain. results = CERT_NewCertList(); if (!results) { return MapSECStatus(SECFailure); } for (BackCert* cert = &subject; cert; cert = cert->childCert) { CERTCertificate* dup = CERT_DupCertificate(cert->GetNSSCert()); if (CERT_AddCertToListHead(results.get(), dup) != SECSuccess) { CERT_DestroyCertificate(dup); return MapSECStatus(SECFailure); } // dup is now owned by results. } // This must be done here, after the chain is built but before any // revocation checks have been done. SECStatus srv = trustDomain.IsChainValid(results.get()); if (srv != SECSuccess) { return MapSECStatus(srv); } return Success; } if (endEntityOrCA == EndEntityOrCA::MustBeCA) { // Avoid stack overflows and poor performance by limiting cert chain // length. static const unsigned int MAX_SUBCA_COUNT = 6; if (subCACount >= MAX_SUBCA_COUNT) { return Fail(RecoverableError, SEC_ERROR_UNKNOWN_ISSUER); } ++subCACount; } else { PR_ASSERT(subCACount == 0); } // Find a trusted issuer. // TODO(bug 965136): Add SKI/AKI matching optimizations ScopedCERTCertList candidates; if (trustDomain.FindPotentialIssuers(&subject.GetNSSCert()->derIssuer, time, candidates) != SECSuccess) { return MapSECStatus(SECFailure); } if (!candidates) { return Fail(RecoverableError, SEC_ERROR_UNKNOWN_ISSUER); } PRErrorCode errorToReturn = 0; for (CERTCertListNode* n = CERT_LIST_HEAD(candidates); !CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) { rv = BuildForwardInner(trustDomain, subject, time, requiredEKUIfPresent, requiredPolicy, n->cert->derCert, subCACount, results); if (rv == Success) { // If we found a valid chain but deferred reporting an error with the // end-entity certificate, report it now. if (deferredEndEntityError != 0) { return Fail(FatalError, deferredEndEntityError); } SECStatus srv = trustDomain.CheckRevocation(endEntityOrCA, subject.GetNSSCert(), n->cert, time, stapledOCSPResponse); if (srv != SECSuccess) { return MapSECStatus(SECFailure); } // We found a trusted issuer. At this point, we know the cert is valid // and results contains the complete cert chain. return Success; } if (rv != RecoverableError) { return rv; } PRErrorCode currentError = PR_GetError(); switch (currentError) { case 0: PR_NOT_REACHED("Error code not set!"); return Fail(FatalError, PR_INVALID_STATE_ERROR); case SEC_ERROR_UNTRUSTED_CERT: currentError = SEC_ERROR_UNTRUSTED_ISSUER; break; default: break; } if (errorToReturn == 0) { errorToReturn = currentError; } else if (errorToReturn != currentError) { errorToReturn = SEC_ERROR_UNKNOWN_ISSUER; } } if (errorToReturn == 0) { errorToReturn = SEC_ERROR_UNKNOWN_ISSUER; } return Fail(RecoverableError, errorToReturn); }
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; }
static int nss_cmd_list_cert(NSS_CTX *ctx, long i) { int ret = 0; BIO *out = NULL; void *wincx = NULL; CERTCertList *list; CERTCertListNode *node; PK11CertListType type; CALL_TRACE("nss_cmd_list_cert: %ld\n", i); if (ctx == NULL) { NSSerr(NSS_F_CMD_LIST_CERT, NSS_R_INVALID_ARGUMENT); goto done; } if (!NSS_IsInitialized()) { NSSerr(NSS_F_CMD_LIST_CERT, NSS_R_DB_IS_NOT_INITIALIZED); goto done; } #if 0 softoken/secmodt.h: PK11CertListUnique = 0, /* get one instance of all certs */ softoken/secmodt.h: PK11CertListUser = 1, /* get all instances of user certs */ softoken/secmodt.h: PK11CertListRootUnique = 2, /* get one instance of CA certs without a private key. */ softoken/secmodt.h: PK11CertListCA = 3, /* get all instances of CA certs */ softoken/secmodt.h: PK11CertListCAUnique = 4, /* get one instance of CA certs */ softoken/secmodt.h: PK11CertListUserUnique = 5, /* get one instance of user certs */ softoken/secmodt.h: PK11CertListAll = 6 /* get all instances of all certs */ #endif switch (i) { case 1: type = PK11CertListUser; break; case 2: type = PK11CertListCA ; break; case 3: type = PK11CertListAll ; break; default: goto done; break; } out = BIO_new_fp(stdout, BIO_NOCLOSE); list = PK11_ListCerts(type, wincx); for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list); node = CERT_LIST_NEXT(node) ) { CERTCertificate *cert = node->cert; BIO_printf(out, "nickname='%s'\n" , cert->nickname); BIO_printf(out, " subject_name='%s'\n", cert->subjectName); /* NOTE: * - NSS cut long strings in cert->subjectName (?) * - RFC 3280 : For UTF8String or UniversalString at least four * times the upper bound should be allowed. * => lets perform own output */ BIO_printf_CERTName(out, &cert->subject, " "); BIO_printf(out, " email_addr ='%s'\n", cert->emailAddr); } CERT_DestroyCertList(list); ret = 1; done: if (out) BIO_free(out); return(ret); }
SECStatus NSS_CMSSignedData_ImportCerts(NSSCMSSignedData *sigd, CERTCertDBHandle *certdb, SECCertUsage certusage, PRBool keepcerts) { int certcount; CERTCertificate **certArray = NULL; CERTCertList *certList = NULL; CERTCertListNode *node; SECStatus rv; SECItem **rawArray; int i; PRTime now; if (!sigd) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } certcount = NSS_CMSArray_Count((void **)sigd->rawCerts); /* get the certs in the temp DB */ rv = CERT_ImportCerts(certdb, certusage, certcount, sigd->rawCerts, &certArray, PR_FALSE, PR_FALSE, NULL); if (rv != SECSuccess) { goto loser; } /* save the certs so they don't get destroyed */ for (i = 0; i < certcount; i++) { CERTCertificate *cert = certArray[i]; if (cert) NSS_CMSSignedData_AddTempCertificate(sigd, cert); } if (!keepcerts) { goto done; } /* build a CertList for filtering */ certList = CERT_NewCertList(); if (certList == NULL) { rv = SECFailure; goto loser; } for (i = 0; i < certcount; i++) { CERTCertificate *cert = certArray[i]; if (cert) cert = CERT_DupCertificate(cert); if (cert) CERT_AddCertToListTail(certList, cert); } /* filter out the certs we don't want */ rv = CERT_FilterCertListByUsage(certList, certusage, PR_FALSE); if (rv != SECSuccess) { goto loser; } /* go down the remaining list of certs and verify that they have * valid chains, then import them. */ now = PR_Now(); for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList); node = CERT_LIST_NEXT(node)) { CERTCertificateList *certChain; if (CERT_VerifyCert(certdb, node->cert, PR_TRUE, certusage, now, NULL, NULL) != SECSuccess) { continue; } certChain = CERT_CertChainFromCert(node->cert, certusage, PR_FALSE); if (!certChain) { continue; } /* * CertChain returns an array of SECItems, import expects an array of * SECItem pointers. Create the SECItem Pointers from the array of * SECItems. */ rawArray = (SECItem **)PORT_Alloc(certChain->len * sizeof(SECItem *)); if (!rawArray) { CERT_DestroyCertificateList(certChain); continue; } for (i = 0; i < certChain->len; i++) { rawArray[i] = &certChain->certs[i]; } (void)CERT_ImportCerts(certdb, certusage, certChain->len, rawArray, NULL, keepcerts, PR_FALSE, NULL); PORT_Free(rawArray); CERT_DestroyCertificateList(certChain); } rv = SECSuccess; /* XXX CRL handling */ done: if (sigd->signerInfos != NULL) { /* fill in all signerinfo's certs */ for (i = 0; sigd->signerInfos[i] != NULL; i++) (void)NSS_CMSSignerInfo_GetSigningCertificate( sigd->signerInfos[i], certdb); } loser: /* now free everything */ if (certArray) { CERT_DestroyCertArray(certArray, certcount); } if (certList) { CERT_DestroyCertList(certList); } return rv; }
int FileCertExport_main(int argc, char * argv[]) { CERTCertListNode *node; SECStatus rv = 0; /*初始化数据库*/ rv = NSS_InitReadWrite(GetSystemDBDir()); if (SECSuccess != rv) { printf("初始化数据库失败\n"); return -1; } CERTCertList * certs = NULL; CERTCertDBHandle *certHandle; certHandle = CERT_GetDefaultCertDB(); CERTCertificate *the_cert; /*用nickname查找数据库证书*/ char * nickname = "BCDEF";/*nickname*/ the_cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, nickname); if (NULL == the_cert) { printf("nickname为%s证书未找到",nickname); } certs = CERT_CreateSubjectCertList(NULL, certHandle, &the_cert->derSubject, PR_Now(), PR_FALSE); /*导出cert的文件名称*/ char * tempCertPath = malloc(255); memset(tempCertPath, 0, 255); strcpy(tempCertPath, GetSystemDBDir()); strcat(tempCertPath, "11111out_2.cer"); FILE * fileOUT = fopen(tempCertPath, "w+b"); if (NULL == fileOUT) { printf("%s文件打开失败\n",tempCertPath); return -1; } CERT_DestroyCertificate(the_cert); if (!certs) { return SECFailure; } for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs); node = CERT_LIST_NEXT(node)) { the_cert = node->cert; /* now get the subjectList that matches this cert */ SECItem data; data.data = the_cert->derCert.data; data.len = the_cert->derCert.len; { PRInt32 numBytes = fwrite(data.data,data.len,1,fileOUT); if (numBytes != (PRInt32) data.len) { rv = SECFailure; } rv = SECSuccess; } if (rv != SECSuccess) { break; } } fclose(fileOUT); printf("Export Cert SUCCESS!\n"); if (certs) { CERT_DestroyCertList(certs); } rv = NSS_Shutdown(); return rv; }
static CERTCertificate * get_signer_cert(char *addr) { CERTCertDBHandle *handle; CERTCertList *list; CERTCertListNode *node; CERTCertificate *cert = NULL; const char *cp; char *nick; char *vn; int vs, found = 0; addr = skin(addr); vn = ac_alloc(vs = strlen(addr) + 30); snprintf(vn, vs, "smime-sign-nickname-%s", addr); if ((nick = value(vn)) == NULL) nick = value("smime-sign-nickname"); ac_free(vn); handle = CERT_GetDefaultCertDB(); if (nick) { cert = CERT_FindCertByNickname(handle, nick); if (cert == NULL) fprintf(stderr, "No certificate \"%s\" found.\n", nick); return cert; } if ((list = CERT_FindUserCertsByUsage(handle, certUsageEmailSigner, PR_TRUE, PR_TRUE, NULL)) == NULL) { fprintf(stderr, "Cannot find any certificates for signing.\n"); return NULL; } for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list); node = CERT_LIST_NEXT(node)) { if ((cp = CERT_GetCertEmailAddress(&node->cert->subject)) != NULL && asccasecmp(cp, addr) == 0) { cert = node->cert; found++; } } if (cert == NULL) { for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list) && cert == NULL; node = CERT_LIST_NEXT(node)) { cp = CERT_GetFirstEmailAddress(node->cert); while (cp) { if (asccasecmp(cp, addr) == 0) { cert = node->cert; found++; } cp = CERT_GetNextEmailAddress(node->cert, cp); } } } if (found > 1) { fprintf(stderr, "More than one signing certificate found for <%s>.\n" "Use the smime-sign-nickname variable.\n", addr); return NULL; } if (cert == NULL) fprintf(stderr, "Cannot find a signing certificate for <%s>.\n", addr); 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); }
nsresult nsCertTree::GetCertsByTypeFromCertList(CERTCertList *aCertList, PRUint32 aWantedType, nsCertCompareFunc aCertCmpFn, void *aCertCmpFnArg) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("GetCertsByTypeFromCertList")); if (!aCertList) return NS_ERROR_FAILURE; if (!mOriginalOverrideService) return NS_ERROR_FAILURE; nsTHashtable<nsCStringHashKey> allHostPortOverrideKeys; if (!allHostPortOverrideKeys.Init()) return NS_ERROR_OUT_OF_MEMORY; if (aWantedType == nsIX509Cert::SERVER_CERT) { mOriginalOverrideService-> EnumerateCertOverrides(nsnull, CollectAllHostPortOverridesCallback, &allHostPortOverrideKeys); } CERTCertListNode *node; int count = 0; for (node = CERT_LIST_HEAD(aCertList); !CERT_LIST_END(node, aCertList); node = CERT_LIST_NEXT(node)) { bool wantThisCert = (aWantedType == nsIX509Cert2::ANY_CERT); bool wantThisCertIfNoOverrides = false; bool wantThisCertIfHaveOverrides = false; bool addOverrides = false; if (!wantThisCert) { PRUint32 thisCertType = getCertType(node->cert); // The output from getCertType is a "guess", which can be wrong. // The guess is based on stored trust flags, but for the host:port // overrides, we are storing certs without any trust flags associated. // So we must check whether the cert really belongs to the // server, email or unknown tab. We will lookup the cert in the override // list to come to the decision. Unfortunately, the lookup in the // override list is quite expensive. Therefore we are using this // lengthy if/else statement to minimize // the number of override-list-lookups. if (aWantedType == nsIX509Cert::SERVER_CERT && thisCertType == nsIX509Cert::UNKNOWN_CERT) { // This unknown cert was stored without trust // Are there host:port based overrides stored? // If yes, display them. addOverrides = true; } else if (aWantedType == nsIX509Cert::UNKNOWN_CERT && thisCertType == nsIX509Cert::UNKNOWN_CERT) { // This unknown cert was stored without trust. // If there are associated overrides, do not show as unknown. // If there are no associated overrides, display as unknown. wantThisCertIfNoOverrides = true; } else if (aWantedType == nsIX509Cert::SERVER_CERT && thisCertType == nsIX509Cert::SERVER_CERT) { // This server cert is explicitly marked as a web site peer, // with or without trust, but editable, so show it wantThisCert = true; // Are there host:port based overrides stored? // If yes, display them. addOverrides = true; } else if (aWantedType == nsIX509Cert::SERVER_CERT && thisCertType == nsIX509Cert::EMAIL_CERT) { // This cert might have been categorized as an email cert // because it carries an email address. But is it really one? // Our cert categorization is uncertain when it comes to // distinguish between email certs and web site certs. // So, let's see if we have an override for that cert // and if there is, conclude it's really a web site cert. addOverrides = true; } else if (aWantedType == nsIX509Cert::EMAIL_CERT && thisCertType == nsIX509Cert::EMAIL_CERT) { // This cert might have been categorized as an email cert // because it carries an email address. But is it really one? // Our cert categorization is uncertain when it comes to // distinguish between email certs and web site certs. // So, let's see if we have an override for that cert // and if there is, conclude it's really a web site cert. wantThisCertIfNoOverrides = true; } else if (thisCertType == aWantedType) { wantThisCert = true; } } nsCOMPtr<nsIX509Cert> pipCert = nsNSSCertificate::Create(node->cert); if (!pipCert) return NS_ERROR_OUT_OF_MEMORY; if (wantThisCertIfNoOverrides || wantThisCertIfHaveOverrides) { PRUint32 ocount = 0; nsresult rv = mOverrideService->IsCertUsedForOverrides(pipCert, true, // we want temporaries true, // we want permanents &ocount); if (wantThisCertIfNoOverrides) { if (NS_FAILED(rv) || ocount == 0) { // no overrides for this cert wantThisCert = true; } } if (wantThisCertIfHaveOverrides) { if (NS_SUCCEEDED(rv) && ocount > 0) { // there are overrides for this cert wantThisCert = true; } } } nsRefPtr<nsCertAddonInfo> certai = new nsCertAddonInfo; if (!certai) return NS_ERROR_OUT_OF_MEMORY; certai->mCert = pipCert; certai->mUsageCount = 0; if (wantThisCert || addOverrides) { int InsertPosition = 0; for (; InsertPosition < count; ++InsertPosition) { nsCOMPtr<nsIX509Cert> cert = nsnull; nsRefPtr<nsCertTreeDispInfo> elem = mDispInfo.SafeElementAt(InsertPosition, NULL); if (elem && elem->mAddonInfo) { cert = elem->mAddonInfo->mCert; } if ((*aCertCmpFn)(aCertCmpFnArg, pipCert, cert) < 0) { break; } } if (wantThisCert) { nsCertTreeDispInfo *certdi = new nsCertTreeDispInfo; if (!certdi) return NS_ERROR_OUT_OF_MEMORY; certdi->mAddonInfo = certai; certai->mUsageCount++; certdi->mTypeOfEntry = nsCertTreeDispInfo::direct_db; // not necessary: certdi->mAsciiHost.Clear(); certdi->mPort = -1; certdi->mOverrideBits = nsCertOverride::ob_None; certdi->mIsTemporary = false; mDispInfo.InsertElementAt(InsertPosition, certdi); ++count; ++InsertPosition; } if (addOverrides) { nsCertAndArrayAndPositionAndCounterAndTracker cap; cap.certai = certai; cap.array = &mDispInfo; cap.position = InsertPosition; cap.counter = 0; cap.tracker = &allHostPortOverrideKeys; mOriginalOverrideService-> EnumerateCertOverrides(pipCert, MatchingCertOverridesCallback, &cap); count += cap.counter; } } } if (aWantedType == nsIX509Cert::SERVER_CERT) { nsArrayAndPositionAndCounterAndTracker cap; cap.array = &mDispInfo; cap.position = 0; cap.counter = 0; cap.tracker = &allHostPortOverrideKeys; mOriginalOverrideService-> EnumerateCertOverrides(nsnull, AddRemaningHostPortOverridesCallback, &cap); } return NS_OK; }
/* * objectType is bitwise-OR of all the object types you want to traverse. */ static PRStatus traverseTokenObjects (JNIEnv *env, PK11SlotInfo *slot, TokenObjectTraversalCallback cb, int objectTypes, void *data) { PRStatus status = PR_FAILURE; JSSTraversalStatus travstat = INIT_TRAVSTAT; SECKEYPrivateKeyList* privkList = NULL; SECKEYPublicKeyList* pubkList = NULL; PK11SymKey *symKey = NULL; CERTCertList *certList = NULL; SECStatus secstat; /* * Get all private keys */ if( objectTypes & PRIVKEY ) { SECKEYPrivateKeyListNode *node = NULL; privkList = PK11_ListPrivKeysInSlot(slot, NULL /*nickname*/, NULL /*wincx*/); if( privkList != NULL ) { for( node = PRIVKEY_LIST_HEAD(privkList); ! PRIVKEY_LIST_END(node, privkList); node = PRIVKEY_LIST_NEXT(node) ) { travstat = cb(env, slot, PRIVKEY, (void*) node->key, data); if( travstat.status == PR_FAILURE ) { goto finish; } if( travstat.deleteIt ) { /* Setting "force" to PR_FALSE means that if there is a * matching cert, the key won't be deleted. * If the KeyStore API is being followed, the cert * should have the same nickname as the key. So * both will get deleted when we scan for matching * certs later. */ PK11_DeleteTokenPrivateKey(node->key, PR_FALSE /*force*/); node->key = NULL; PR_REMOVE_LINK(&node->links); /* we don't free node because it is allocated from * the list's arena and will get freed when the list * is freed. */ } if( travstat.stopIterating ) { goto stop_early; } } } } /* * Get all symmetric keys */ if(objectTypes & SYMKEY) { /* this function returns a chained list of symmetric keys */ symKey = PK11_ListFixedKeysInSlot(slot, NULL /*nickname*/, NULL/*wincx*/); while( symKey != NULL ) { PK11SymKey *deadKey; travstat = cb(env, slot, SYMKEY, (void*) symKey, data); if( travstat.status != PR_SUCCESS ) { goto finish; } if( travstat.deleteIt ) { /* this just deletes the PKCS #11 object. The data structure * is NOT deleted. */ PK11_DeleteTokenSymKey(symKey); } if( travstat.stopIterating ) { goto stop_early; } deadKey = symKey; symKey = PK11_GetNextSymKey(symKey); PK11_FreeSymKey(deadKey); } } /* * get all public keys */ if( objectTypes & PUBKEY ) { SECKEYPublicKeyListNode *node = NULL; pubkList = PK11_ListPublicKeysInSlot(slot, NULL /*nickname*/); if( pubkList != NULL ) { for( node = PUBKEY_LIST_HEAD(pubkList); ! PUBKEY_LIST_END(node, pubkList); node = PUBKEY_LIST_NEXT(node) ) { if( node->key == NULL ) { /* workaround NSS bug 130699: PK11_ListPublicKeysInSlot * returns NULL if slot contains token symmetric key */ continue; } travstat = cb(env, slot, PUBKEY, (void*) node->key, data); if( travstat.status != PR_SUCCESS ) { goto finish; } if( travstat.deleteIt ) { /* XXX!!! * Workaround for 125408: PK11_DeleteTokenPublic key asserts * Don't delete the public key. * PK11_DeleteTokenPublicKey(node->key); * node->key = NULL; * PR_REMOVE_LINK(&node->links); */ /* node is allocated from the list's arena, it will get * freed with the list */ } if( travstat.stopIterating ) { goto stop_early; } } /* * XXX!!! * Destroy the list before we move on. Why bother, since we'll * do it anyway in the finish block? Because of bug 125408. * If we delete the cert and private key while traversing certs, * we'll delete the public key too, and then we'll crash when * we free the same public key while destroying the list. */ SECKEY_DestroyPublicKeyList(pubkList); pubkList = NULL; } } /* * Get all certs */ if( objectTypes & CERT ) { CERTCertListNode *node = NULL; certList = PK11_ListCertsInSlot(slot); if( certList == NULL ) { JSS_throwMsgPrErr(env, TOKEN_EXCEPTION, "Failed to list certificates on token"); goto finish; } for( node = CERT_LIST_HEAD(certList); ! CERT_LIST_END(node, certList); node = CERT_LIST_NEXT(node) ) { travstat = cb(env, slot, CERT, (void*) node->cert, data); if( travstat.status != PR_SUCCESS ) { goto finish; } if( travstat.deleteIt ) { /* * Since, in a KeyStore, certs and private keys go together, * remove the private key too, if there is one. * * The hack here is that PK11_DeleteTokenCertAndKey will * not delete the cert if there is no matching private key. * We want to the cert to be deleted even if the key isn't * there. So we only call that function if we're sure the * key is there. Otherwise we delete the cert directly. */ SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(node->cert, NULL /*wincx*/); PRBool keyPresent = (privKey != NULL); SECKEY_DestroyPrivateKey(privKey); if( keyPresent ) { PK11_DeleteTokenCertAndKey(node->cert, NULL /*wincx*/); } else { SEC_DeletePermCertificate(node->cert); } PR_REMOVE_LINK(&node->links); /* node is allocated from the list's arena, it will get freed * with the list */ } if( travstat.stopIterating ) { goto stop_early; } } } stop_early: status = PR_SUCCESS; finish: if( privkList != NULL ) { SECKEY_DestroyPrivateKeyList(privkList); } if( pubkList != NULL ) { SECKEY_DestroyPublicKeyList(pubkList); } while( symKey != NULL ) { PK11SymKey *deadKey; deadKey = symKey; symKey = PK11_GetNextSymKey(symKey); PK11_FreeSymKey(deadKey); } if( certList != NULL ) { CERT_DestroyCertList(certList); } return status; }
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; }
// Recursively build the path from the given subject certificate to the root. // // Be very careful about changing the order of checks. The order is significant // because it affects which error we return when a certificate or certificate // chain has multiple problems. See the error ranking documentation in // insanity/pkix.h. static Result BuildForward(TrustDomain& trustDomain, BackCert& subject, PRTime time, EndEntityOrCA endEntityOrCA, KeyUsages requiredKeyUsagesIfPresent, SECOidTag requiredEKUIfPresent, SECOidTag requiredPolicy, /*optional*/ const SECItem* stapledOCSPResponse, unsigned int subCACount, /*out*/ ScopedCERTCertList& results) { // Avoid stack overflows and poor performance by limiting cert length. // XXX: 6 is not enough for chains.sh anypolicywithlevel.cfg tests static const size_t MAX_DEPTH = 8; if (subCACount >= MAX_DEPTH - 1) { return RecoverableError; } Result rv; TrustDomain::TrustLevel trustLevel; bool expiredEndEntity = false; rv = CheckIssuerIndependentProperties(trustDomain, subject, time, endEntityOrCA, requiredKeyUsagesIfPresent, requiredEKUIfPresent, requiredPolicy, subCACount, &trustLevel); if (rv != Success) { // CheckIssuerIndependentProperties checks for expiration last, so if // it returned SEC_ERROR_EXPIRED_CERTIFICATE we know that is the only // problem with the cert found so far. Keep going to see if we can build // a path; if not, it's better to return the path building failure. expiredEndEntity = endEntityOrCA == MustBeEndEntity && trustLevel != TrustDomain::TrustAnchor && PR_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE; if (!expiredEndEntity) { return rv; } } if (trustLevel == TrustDomain::TrustAnchor) { // End of the recursion. Create the result list and add the trust anchor to // it. results = CERT_NewCertList(); if (!results) { return FatalError; } rv = subject.PrependNSSCertToList(results.get()); return rv; } // Find a trusted issuer. // TODO(bug 965136): Add SKI/AKI matching optimizations ScopedCERTCertList candidates; if (trustDomain.FindPotentialIssuers(&subject.GetNSSCert()->derIssuer, time, candidates) != SECSuccess) { return MapSECStatus(SECFailure); } PORT_Assert(candidates.get()); if (!candidates) { return Fail(RecoverableError, SEC_ERROR_UNKNOWN_ISSUER); } PRErrorCode errorToReturn = 0; for (CERTCertListNode* n = CERT_LIST_HEAD(candidates); !CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) { rv = BuildForwardInner(trustDomain, subject, time, endEntityOrCA, requiredEKUIfPresent, requiredPolicy, n->cert, stapledOCSPResponse, subCACount, results); if (rv == Success) { if (expiredEndEntity) { // We deferred returning this error to see if we should return // "unknown issuer" instead. Since we found a valid issuer, it's // time to return "expired." PR_SetError(SEC_ERROR_EXPIRED_CERTIFICATE, 0); return RecoverableError; } SECStatus srv = trustDomain.CheckRevocation(endEntityOrCA, subject.GetNSSCert(), n->cert, time, stapledOCSPResponse); if (srv != SECSuccess) { return MapSECStatus(SECFailure); } // We found a trusted issuer. At this point, we know the cert is valid return subject.PrependNSSCertToList(results.get()); } if (rv != RecoverableError) { return rv; } PRErrorCode currentError = PR_GetError(); switch (currentError) { case 0: PR_NOT_REACHED("Error code not set!"); PR_SetError(PR_INVALID_STATE_ERROR, 0); return FatalError; case SEC_ERROR_UNTRUSTED_CERT: currentError = SEC_ERROR_UNTRUSTED_ISSUER; break; default: break; } if (errorToReturn == 0) { errorToReturn = currentError; } else if (errorToReturn != currentError) { errorToReturn = SEC_ERROR_UNKNOWN_ISSUER; } } if (errorToReturn == 0) { errorToReturn = SEC_ERROR_UNKNOWN_ISSUER; } return Fail(RecoverableError, errorToReturn); }