static PRBool nss3certificate_isValidIssuer(nssDecodedCert *dc) { CERTCertificate *c = (CERTCertificate *)dc->data; unsigned int ignore; return CERT_IsCACert(c, &ignore); }
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; }
/* CERT_FilterCertListByUsage */ static PRBool nss3certificate_matchUsage(nssDecodedCert *dc, const NSSUsage *usage) { CERTCertificate *cc; unsigned int requiredKeyUsage = 0; unsigned int requiredCertType = 0; SECStatus secrv; PRBool match; PRBool ca; /* This is for NSS 3.3 functions that do not specify a usage */ if (usage->anyUsage) { return PR_TRUE; } ca = usage->nss3lookingForCA; secrv = CERT_KeyUsageAndTypeForCertUsage(usage->nss3usage, ca, &requiredKeyUsage, &requiredCertType); if (secrv != SECSuccess) { return PR_FALSE; } cc = (CERTCertificate *)dc->data; secrv = CERT_CheckKeyUsage(cc, requiredKeyUsage); match = (PRBool)(secrv == SECSuccess); if (match) { unsigned int certType = 0; if (ca) { (void)CERT_IsCACert(cc, &certType); } else { certType = cc->nsCertType; } if (!(certType & requiredCertType)) { match = PR_FALSE; } } return match; }
static int vfy_chain_pkix(CERTCertificate **chain, int chain_len, CERTCertificate **end_out, bool *rev_opts) { CERTCertificate *end_cert = NULL; CERTCertList *trustcl = get_all_root_certs(); if (trustcl == NULL) { DBG(DBG_X509, DBG_log("X509: no trust anchor available for verification")); return VERIFY_RET_SKIP; } int i; for (i = 0; i < chain_len; i++) { if (!CERT_IsCACert(chain[i], NULL)) { end_cert = chain[i]; break; } } if (end_cert == NULL) { libreswan_log("X509: no EE-cert in chain!"); return VERIFY_RET_FAIL; } CERTVerifyLog *cur_log = NULL; CERTVerifyLog vfy_log; CERTVerifyLog vfy_log2; new_vfy_log(&vfy_log); new_vfy_log(&vfy_log2); CERTRevocationFlags rev; zero(&rev); /* ??? are there pointer fields? */ PRUint64 revFlagsLeaf[2] = { 0, 0 }; PRUint64 revFlagsChain[2] = { 0, 0 }; set_rev_per_meth(&rev, revFlagsLeaf, revFlagsChain); set_rev_params(&rev, rev_opts[RO_CRL_S], rev_opts[RO_OCSP], rev_opts[RO_OCSP_S]); int in_idx = 0; CERTValInParam cvin[7]; CERTValOutParam cvout[3]; zero(&cvin); /* ??? are there pointer fields? */ zero(&cvout); /* ??? are there pointer fields? */ cvin[in_idx].type = cert_pi_revocationFlags; cvin[in_idx++].value.pointer.revocation = &rev; cvin[in_idx].type = cert_pi_useAIACertFetch; cvin[in_idx++].value.scalar.b = rev_opts[RO_OCSP]; cvin[in_idx].type = cert_pi_trustAnchors; cvin[in_idx++].value.pointer.chain = trustcl; cvin[in_idx].type = cert_pi_useOnlyTrustAnchors; cvin[in_idx++].value.scalar.b = PR_TRUE; cvin[in_idx].type = cert_pi_end; cvout[0].type = cert_po_errorLog; cvout[0].value.pointer.log = cur_log = &vfy_log; cvout[1].type = cert_po_certList; cvout[1].value.pointer.chain = NULL; cvout[2].type = cert_po_end; /* kludge alert!! * verification may be performed twice: once with the * 'client' usage and once with 'server', which is an NSS * detail and not related to IKE. In the absence of a real * IKE profile being available for NSS, this covers more * KU/EKU combinations */ int fin; SECCertificateUsage usage; for (usage = certificateUsageSSLClient; ; usage = certificateUsageSSLServer) { SECStatus rv = CERT_PKIXVerifyCert(end_cert, usage, cvin, cvout, NULL); if (rv != SECSuccess || cur_log->count > 0) { if (cur_log->count > 0 && cur_log->head != NULL) { if (usage == certificateUsageSSLClient && RETRYABLE_TYPE(cur_log->head->error)) { /* try again, after some adjustments */ DBG(DBG_X509, DBG_log("retrying verification with the NSS serverAuth profile")); /* ??? since we are about to overwrite cvout[1], * should we be doing: * if (cvout[1].value.pointer.chain != NULL) * CERT_DestroyCertList(cvout[1].value.pointer.chain); */ cvout[0].value.pointer.log = cur_log = &vfy_log2; cvout[1].value.pointer.chain = NULL; continue; } else { fin = nss_err_to_revfail(cur_log->head); } } else { /* * An rv != SECSuccess without CERTVerifyLog results should not * happen, but catch it anyway */ libreswan_log("X509: unspecified NSS verification failure"); fin = VERIFY_RET_FAIL; } } else { DBG(DBG_X509, DBG_log("certificate is valid")); *end_out = end_cert; fin = VERIFY_RET_OK; } break; } CERT_DestroyCertList(trustcl); PORT_FreeArena(vfy_log.arena, PR_FALSE); PORT_FreeArena(vfy_log2.arena, PR_FALSE); if (cvout[1].value.pointer.chain != NULL) { CERT_DestroyCertList(cvout[1].value.pointer.chain); } return fin; }
/* From certdb.c */ static SECStatus cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted) { SECStatus rv; SECItem *derCert; CERTCertificate *cert = NULL; CERTCertificate *newcert = NULL; CERTCertDBHandle *handle; CERTCertTrust trust; PRBool isca; char *nickname; unsigned int certtype; handle = CERT_GetDefaultCertDB(); while (numcerts--) { derCert = certs; certs++; /* decode my certificate */ /* This use is ok -- only looks at decoded parts, calls NewTemp later */ newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL); if ( newcert == NULL ) { goto loser; } if (!trusted) { /* make sure that cert is valid */ rv = CERT_CertTimesValid(newcert); if ( rv == SECFailure ) { goto endloop; } } /* does it have the CA extension */ /* * Make sure that if this is an intermediate CA in the chain that * it was given permission by its signer to be a CA. */ isca = CERT_IsCACert(newcert, &certtype); if ( !isca ) { if (!trusted) { goto endloop; } trust.sslFlags = CERTDB_VALID_CA; trust.emailFlags = CERTDB_VALID_CA; trust.objectSigningFlags = CERTDB_VALID_CA; } else { /* SSL ca's must have the ssl bit set */ if ( ( certUsage == certUsageSSLCA ) && (( certtype & NS_CERT_TYPE_SSL_CA ) != NS_CERT_TYPE_SSL_CA )) { goto endloop; } /* it passed all of the tests, so lets add it to the database */ /* mark it as a CA */ PORT_Memset((void *)&trust, 0, sizeof(trust)); switch ( certUsage ) { case certUsageSSLCA: trust.sslFlags = CERTDB_VALID_CA; break; case certUsageUserCertImport: if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) { trust.sslFlags = CERTDB_VALID_CA; } if ((certtype & NS_CERT_TYPE_EMAIL_CA) == NS_CERT_TYPE_EMAIL_CA ) { trust.emailFlags = CERTDB_VALID_CA; } if ( ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) == NS_CERT_TYPE_OBJECT_SIGNING_CA ) { trust.objectSigningFlags = CERTDB_VALID_CA; } break; default: PORT_Assert(0); break; } } cert = CERT_NewTempCertificate(handle, derCert, NULL, PR_FALSE, PR_FALSE); if ( cert == NULL ) { goto loser; } /* if the cert is temp, make it perm; otherwise we're done */ if (cert->istemp) { /* get a default nickname for it */ nickname = CERT_MakeCANickname(cert); rv = CERT_AddTempCertToPerm(cert, nickname, &trust); /* free the nickname */ if ( nickname ) { PORT_Free(nickname); } } else { rv = SECSuccess; } CERT_DestroyCertificate(cert); cert = NULL; if ( rv != SECSuccess ) { goto loser; } endloop: if ( newcert ) { CERT_DestroyCertificate(newcert); newcert = NULL; } } rv = SECSuccess; goto done; loser: rv = SECFailure; done: if ( newcert ) { CERT_DestroyCertificate(newcert); newcert = NULL; } if ( cert ) { CERT_DestroyCertificate(cert); cert = NULL; } return(rv); }
// Based on nsNSSCertificateDB::handleCACertDownload, minus the UI bits. bool ImportCACerts(const net::CertificateList& certificates, net::X509Certificate* root, net::NSSCertDatabase::TrustBits trustBits, net::NSSCertDatabase::ImportCertFailureList* not_imported) { if (certificates.empty() || !root) return false; crypto::ScopedPK11Slot slot(crypto::GetPublicNSSKeySlot()); if (!slot.get()) { LOG(ERROR) << "Couldn't get internal key slot!"; return false; } // Mozilla had some code here to check if a perm version of the cert exists // already and use that, but CERT_NewTempCertificate actually does that // itself, so we skip it here. if (!CERT_IsCACert(root->os_cert_handle(), NULL)) { not_imported->push_back(net::NSSCertDatabase::ImportCertFailure( root, net::ERR_IMPORT_CA_CERT_NOT_CA)); } else if (root->os_cert_handle()->isperm) { // Mozilla just returns here, but we continue in case there are other certs // in the list which aren't already imported. // TODO(mattm): should we set/add trust if it differs from the present // settings? not_imported->push_back(net::NSSCertDatabase::ImportCertFailure( root, net::ERR_IMPORT_CERT_ALREADY_EXISTS)); } else { // Mozilla uses CERT_AddTempCertToPerm, however it is privately exported, // and it doesn't take the slot as an argument either. Instead, we use // PK11_ImportCert and CERT_ChangeCertTrust. SECStatus srv = PK11_ImportCert( slot.get(), root->os_cert_handle(), CK_INVALID_HANDLE, root->GetDefaultNickname(net::CA_CERT).c_str(), PR_FALSE /* includeTrust (unused) */); if (srv != SECSuccess) { LOG(ERROR) << "PK11_ImportCert failed with error " << PORT_GetError(); return false; } if (!SetCertTrust(root, net::CA_CERT, trustBits)) return false; } PRTime now = PR_Now(); // Import additional delivered certificates that can be verified. // This is sort of merged in from Mozilla's ImportValidCACertsInList. Mozilla // uses CERT_FilterCertListByUsage to filter out non-ca certs, but we want to // keep using X509Certificates, so that we can use them to build the // |not_imported| result. So, we keep using our net::CertificateList and // filter it ourself. for (size_t i = 0; i < certificates.size(); i++) { const scoped_refptr<net::X509Certificate>& cert = certificates[i]; if (cert == root) { // we already processed that one continue; } // Mozilla uses CERT_FilterCertListByUsage(certList, certUsageAnyCA, // PR_TRUE). Afaict, checking !CERT_IsCACert on each cert is equivalent. if (!CERT_IsCACert(cert->os_cert_handle(), NULL)) { not_imported->push_back(net::NSSCertDatabase::ImportCertFailure( cert, net::ERR_IMPORT_CA_CERT_NOT_CA)); VLOG(1) << "skipping cert (non-ca)"; continue; } if (cert->os_cert_handle()->isperm) { not_imported->push_back(net::NSSCertDatabase::ImportCertFailure( cert, net::ERR_IMPORT_CERT_ALREADY_EXISTS)); VLOG(1) << "skipping cert (perm)"; continue; } if (CERT_VerifyCert(CERT_GetDefaultCertDB(), cert->os_cert_handle(), PR_TRUE, certUsageVerifyCA, now, NULL, NULL) != SECSuccess) { // TODO(mattm): use better error code (map PORT_GetError to an appropriate // error value). (maybe make MapSecurityError or MapCertErrorToCertStatus // public.) not_imported->push_back(net::NSSCertDatabase::ImportCertFailure( cert, net::ERR_FAILED)); VLOG(1) << "skipping cert (verify) " << PORT_GetError(); continue; } // Mozilla uses CERT_ImportCerts, which doesn't take a slot arg. We use // PK11_ImportCert instead. SECStatus srv = PK11_ImportCert( slot.get(), cert->os_cert_handle(), CK_INVALID_HANDLE, cert->GetDefaultNickname(net::CA_CERT).c_str(), PR_FALSE /* includeTrust (unused) */); if (srv != SECSuccess) { LOG(ERROR) << "PK11_ImportCert failed with error " << PORT_GetError(); // TODO(mattm): Should we bail or continue on error here? Mozilla doesn't // check error code at all. not_imported->push_back(net::NSSCertDatabase::ImportCertFailure( cert, net::ERR_IMPORT_CA_CERT_FAILED)); } } // Any errors importing individual certs will be in listed in |not_imported|. return true; }
/* * FUNCTION: pkix_pl_OcspResponse_VerifySignature * DESCRIPTION: * * This function verifies the ocspResponse signature field in the OcspResponse * pointed to by "response", storing PKIX_TRUE at "pPassed" if verification * is successful and PKIX_FALSE otherwise. If verification is unsuccessful an * error code (an enumeration of type SECErrorCodes) is stored at *pReturnCode. * * PARAMETERS * "response" * The address of the OcspResponse whose signature field is to be * retrieved. Must be non-NULL. * "cert" * The address of the Cert for which the OCSP query was made. Must be * non-NULL. * "procParams" * Address of ProcessingParams used to initialize the ExpirationChecker * and TargetCertChecker. Must be non-NULL. * "pPassed" * Address at which the Boolean result is stored. Must be non-NULL. * "pNBIOContext" * Address at which the NBIOContext is stored indicating whether the * checking is complete. Must be non-NULL. * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if the function succeeds. * Returns an OcspResponse Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ PKIX_Error * pkix_pl_OcspResponse_VerifySignature( PKIX_PL_OcspResponse *response, PKIX_PL_Cert *cert, PKIX_ProcessingParams *procParams, PKIX_Boolean *pPassed, void **pNBIOContext, void *plContext) { SECStatus rv = SECFailure; CERTOCSPResponse *nssOCSPResponse = NULL; CERTCertificate *issuerCert = NULL; PKIX_BuildResult *buildResult = NULL; void *nbio = NULL; void *state = NULL; ocspSignature *signature = NULL; ocspResponseData *tbsData = NULL; SECItem *tbsResponseDataDER = NULL; PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifySignature"); PKIX_NULLCHECK_FOUR(response, cert, pPassed, pNBIOContext); nbio = *pNBIOContext; *pNBIOContext = NULL; nssOCSPResponse = response->nssOCSPResponse; if (nssOCSPResponse == NULL) { PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); goto cleanup; } tbsData = ocsp_GetResponseData(nssOCSPResponse, &tbsResponseDataDER); signature = ocsp_GetResponseSignature(nssOCSPResponse); /* Are we resuming after a WOULDBLOCK response? */ if (nbio == NULL) { /* No, this is a new query */ issuerCert = CERT_FindCertIssuer(cert->nssCert, PR_Now(), certUsageAnyCA); /* * If this signature has already gone through verification, * just return the cached result. */ if (signature->wasChecked) { if (signature->status == SECSuccess) { response->signerCert = CERT_DupCertificate(signature->cert); } else { PORT_SetError(signature->failureReason); goto cleanup; } } response->signerCert = ocsp_GetSignerCertificate(response->handle, tbsData, signature, issuerCert); if (response->signerCert == NULL) { PORT_SetError(SEC_ERROR_UNKNOWN_SIGNER); goto cleanup; } PKIX_CHECK( PKIX_PL_Cert_CreateFromCERTCertificate(response->signerCert, &(response->pkixSignerCert), plContext), PKIX_CERTCREATEWITHNSSCERTFAILED); /* * We could mark this true at the top of this function, or * always below at "finish", but if the problem was just that * we could not find the signer's cert, leave that as if the * signature hasn't been checked. Maybe a subsequent call will * have better luck. */ signature->wasChecked = PR_TRUE; /* * We are about to verify the signer certificate; we need to * specify *when* that certificate must be valid -- for our * purposes we expect it to be valid when the response was * signed. The value of "producedAt" is the signing time. */ rv = DER_GeneralizedTimeToTime(&response->producedAt, &tbsData->producedAt); if (rv != SECSuccess) { PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); goto cleanup; } /* * We need producedAtDate and pkixSignerCert if we are calling a * user-supplied verification function. Let's put their * creation before the code that gets repeated when * non-blocking I/O is used. */ PKIX_CHECK( pkix_pl_Date_CreateFromPRTime((PRTime)response->producedAt, &(response->producedAtDate), plContext), PKIX_DATECREATEFROMPRTIMEFAILED); } /* * Just because we have a cert does not mean it is any good; check * it for validity, trust and usage. Use the caller-supplied * verification function, if one was supplied. */ if (ocsp_CertIsOCSPDefaultResponder(response->handle, response->signerCert)) { rv = SECSuccess; } else { SECCertUsage certUsage; if (CERT_IsCACert(response->signerCert, NULL)) { certUsage = certUsageAnyCA; } else { certUsage = certUsageStatusResponder; } PKIX_CHECK_ONLY_FATAL( pkix_pl_OcspResponse_VerifyResponse(response, procParams, certUsage, &state, &buildResult, &nbio, plContext), PKIX_CERTVERIFYKEYUSAGEFAILED); if (pkixTempErrorReceived) { rv = SECFailure; goto cleanup; } if (nbio != NULL) { *pNBIOContext = nbio; goto cleanup; } } rv = ocsp_VerifyResponseSignature(response->signerCert, signature, tbsResponseDataDER, NULL); cleanup: if (rv == SECSuccess) { *pPassed = PKIX_TRUE; } else { *pPassed = PKIX_FALSE; } if (signature) { if (signature->wasChecked) { signature->status = rv; } if (rv != SECSuccess) { signature->failureReason = PORT_GetError(); if (response->signerCert != NULL) { CERT_DestroyCertificate(response->signerCert); response->signerCert = NULL; } } else { /* Save signer's certificate in signature. */ signature->cert = CERT_DupCertificate(response->signerCert); } } if (issuerCert) CERT_DestroyCertificate(issuerCert); PKIX_RETURN(OCSPRESPONSE); }
nsresult nsNSSCertificateDB::handleCACertDownload(nsIArray *x509Certs, nsIInterfaceRequestor *ctx) { // First thing we have to do is figure out which certificate we're // gonna present to the user. The CA may have sent down a list of // certs which may or may not be a chained list of certs. Until // the day we can design some solid UI for the general case, we'll // code to the > 90% case. That case is where a CA sends down a // list that is a hierarchy whose root is either the first or // the last cert. What we're gonna do is compare the first // 2 entries, if the second was signed by the first, we assume // the root cert is the first cert and display it. Otherwise, // we compare the last 2 entries, if the second to last cert was // signed by the last cert, then we assume the last cert is the // root and display it. nsNSSShutDownPreventionLock locker; PRUint32 numCerts; x509Certs->GetLength(&numCerts); NS_ASSERTION(numCerts > 0, "Didn't get any certs to import."); if (numCerts == 0) return NS_OK; // Nothing to import, so nothing to do. nsCOMPtr<nsIX509Cert> certToShow; nsCOMPtr<nsISupports> isupports; PRUint32 selCertIndex; if (numCerts == 1) { // There's only one cert, so let's show it. selCertIndex = 0; certToShow = do_QueryElementAt(x509Certs, selCertIndex); } else { nsCOMPtr<nsIX509Cert> cert0; // first cert nsCOMPtr<nsIX509Cert> cert1; // second cert nsCOMPtr<nsIX509Cert> certn_2; // second to last cert nsCOMPtr<nsIX509Cert> certn_1; // last cert cert0 = do_QueryElementAt(x509Certs, 0); cert1 = do_QueryElementAt(x509Certs, 1); certn_2 = do_QueryElementAt(x509Certs, numCerts-2); certn_1 = do_QueryElementAt(x509Certs, numCerts-1); nsXPIDLString cert0SubjectName; nsXPIDLString cert1IssuerName; nsXPIDLString certn_2IssuerName; nsXPIDLString certn_1SubjectName; cert0->GetSubjectName(cert0SubjectName); cert1->GetIssuerName(cert1IssuerName); certn_2->GetIssuerName(certn_2IssuerName); certn_1->GetSubjectName(certn_1SubjectName); if (cert1IssuerName.Equals(cert0SubjectName)) { // In this case, the first cert in the list signed the second, // so the first cert is the root. Let's display it. selCertIndex = 0; certToShow = cert0; } else if (certn_2IssuerName.Equals(certn_1SubjectName)) { // In this case the last cert has signed the second to last cert. // The last cert is the root, so let's display it. selCertIndex = numCerts-1; certToShow = certn_1; } else { // It's not a chain, so let's just show the first one in the // downloaded list. selCertIndex = 0; certToShow = cert0; } } if (!certToShow) return NS_ERROR_FAILURE; nsCOMPtr<nsICertificateDialogs> dialogs; nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs), NS_GET_IID(nsICertificateDialogs), NS_CERTIFICATEDIALOGS_CONTRACTID); if (NS_FAILED(rv)) return rv; SECItem der; rv=certToShow->GetRawDER(&der.len, (PRUint8 **)&der.data); if (NS_FAILED(rv)) return rv; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n")); CERTCertificate *tmpCert; CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); tmpCert = CERT_FindCertByDERCert(certdb, &der); if (!tmpCert) { tmpCert = CERT_NewTempCertificate(certdb, &der, nsnull, PR_FALSE, PR_TRUE); } nsMemory::Free(der.data); der.data = nsnull; der.len = 0; if (!tmpCert) { NS_ERROR("Couldn't create cert from DER blob\n"); return NS_ERROR_FAILURE; } CERTCertificateCleaner tmpCertCleaner(tmpCert); if (!CERT_IsCACert(tmpCert, NULL)) { DisplayCertificateAlert(ctx, "NotACACert", certToShow); return NS_ERROR_FAILURE; } if (tmpCert->isperm) { DisplayCertificateAlert(ctx, "CaCertExists", certToShow); return NS_ERROR_FAILURE; } PRUint32 trustBits; PRBool allows; rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows); if (NS_FAILED(rv)) return rv; if (!allows) return NS_ERROR_NOT_AVAILABLE; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits)); nsXPIDLCString nickname; nickname.Adopt(CERT_MakeCANickname(tmpCert)); PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get())); nsNSSCertTrust trust; trust.SetValidCA(); trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL), !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL), !!(trustBits & nsIX509CertDB::TRUSTED_OBJSIGN)); SECStatus srv = CERT_AddTempCertToPerm(tmpCert, const_cast<char*>(nickname.get()), trust.GetTrust()); if (srv != SECSuccess) return NS_ERROR_FAILURE; // Import additional delivered certificates that can be verified. // build a CertList for filtering CERTCertList *certList = CERT_NewCertList(); if (certList == NULL) { return NS_ERROR_FAILURE; } CERTCertListCleaner listCleaner(certList); // get all remaining certs into temp store for (PRUint32 i=0; i<numCerts; i++) { if (i == selCertIndex) { // we already processed that one continue; } certToShow = do_QueryElementAt(x509Certs, i); certToShow->GetRawDER(&der.len, (PRUint8 **)&der.data); CERTCertificate *tmpCert2 = CERT_NewTempCertificate(certdb, &der, nsnull, PR_FALSE, PR_TRUE); nsMemory::Free(der.data); der.data = nsnull; der.len = 0; if (!tmpCert2) { NS_ASSERTION(0, "Couldn't create temp cert from DER blob\n"); continue; // Let's try to import the rest of 'em } CERT_AddCertToListTail(certList, tmpCert2); } return ImportValidCACertsInList(certList, ctx); }