CERTCertList * CERT_MatchUserCert(CERTCertDBHandle *handle, SECCertUsage usage, int nCANames, char **caNames, void *proto_win) { CERTCertList *certList = NULL; SECStatus rv; certList = CERT_FindUserCertsByUsage(handle, usage, PR_TRUE, PR_TRUE, proto_win); if ( certList == NULL ) { goto loser; } rv = CERT_FilterCertListByCANames(certList, nCANames, caNames, usage); if ( rv != SECSuccess ) { goto loser; } goto done; loser: if ( certList != NULL ) { CERT_DestroyCertList(certList); certList = NULL; } done: return(certList); }
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; }
static void free_PK11_ctx(struct PK11_ctx *ctx) { if(!ctx) return; if(ctx->list) CERT_DestroyCertList(ctx->list); if(ctx->obj) PK11_DestroyGenericObject(ctx->obj); if(ctx->slot) PK11_FreeSlot(ctx->slot); }
void forgetCerts(void) { certMem * oldCertMem; while (theCerts) { oldCertMem = theCerts; theCerts = theCerts->next; CERT_DestroyCertificate(oldCertMem->cert); PORT_Free(oldCertMem); } if (trustedCertList) { CERT_DestroyCertList(trustedCertList); } }
nsresult nsCertTree::GetCertsByType(PRUint32 aType, nsCertCompareFunc aCertCmpFn, void *aCertCmpFnArg) { nsNSSShutDownPreventionLock locker; CERTCertList *certList = NULL; nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext(); certList = PK11_ListCerts(PK11CertListUnique, cxt); nsresult rv = GetCertsByTypeFromCertList(certList, aType, aCertCmpFn, aCertCmpFnArg); if (certList) CERT_DestroyCertList(certList); return rv; }
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; }
/* NEED LOCKS IN HERE. */ CERTCertList * SSL_PeerCertificateChain(PRFileDesc *fd) { sslSocket *ss; CERTCertList *chain = NULL; CERTCertificate *cert; ssl3CertNode *cur; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain", SSL_GETPID(), fd)); return NULL; } if (!ss->opt.useSecurity || !ss->sec.peerCert) { PORT_SetError(SSL_ERROR_NO_CERTIFICATE); return NULL; } chain = CERT_NewCertList(); if (!chain) { return NULL; } cert = CERT_DupCertificate(ss->sec.peerCert); if (CERT_AddCertToListTail(chain, cert) != SECSuccess) { goto loser; } for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) { cert = CERT_DupCertificate(cur->cert); if (CERT_AddCertToListTail(chain, cert) != SECSuccess) { goto loser; } } return chain; loser: CERT_DestroyCertList(chain); return NULL; }
CERTCertList * cmmf_MakeCertList(CERTCertificate **inCerts) { CERTCertList *certList; CERTCertificate *currCert; SECItem *derCert, *freeCert = NULL; SECStatus rv; int i; certList = CERT_NewCertList(); if (certList == NULL) { return NULL; } for (i = 0; inCerts[i] != NULL; i++) { derCert = &inCerts[i]->derCert; if (derCert->data == NULL) { derCert = freeCert = cmmf_encode_certificate(inCerts[i]); } currCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), derCert, NULL, PR_FALSE, PR_TRUE); if (freeCert != NULL) { SECITEM_FreeItem(freeCert, PR_TRUE); freeCert = NULL; } if (currCert == NULL) { goto loser; } rv = CERT_AddCertToListTail(certList, currCert); if (rv != SECSuccess) { goto loser; } } return certList; loser: CERT_DestroyCertList(certList); return NULL; }
/* * 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; }
/* * Create a DER-encoded OCSP request (for the certificate whose nickname * is "name") and dump it out. */ static SECStatus create_request (FILE *out_file, CERTCertDBHandle *handle, CERTCertificate *cert, PRBool add_service_locator, PRBool add_acceptable_responses) { CERTCertList *certs = NULL; CERTCertificate *myCert = NULL; CERTOCSPRequest *request = NULL; PRTime now = PR_Now(); SECItem *encoding = NULL; SECStatus rv = SECFailure; if (handle == NULL || cert == NULL) return rv; myCert = CERT_DupCertificate(cert); if (myCert == NULL) goto loser; /* * We need to create a list of one. */ certs = CERT_NewCertList(); if (certs == NULL) goto loser; if (CERT_AddCertToListTail (certs, myCert) != SECSuccess) goto loser; /* * Now that cert is included in the list, we need to be careful * that we do not try to destroy it twice. This will prevent that. */ myCert = NULL; request = CERT_CreateOCSPRequest (certs, now, add_service_locator, NULL); if (request == NULL) goto loser; if (add_acceptable_responses) { rv = CERT_AddOCSPAcceptableResponses(request, SEC_OID_PKIX_OCSP_BASIC_RESPONSE); if (rv != SECSuccess) goto loser; } encoding = CERT_EncodeOCSPRequest (NULL, request, NULL); if (encoding == NULL) goto loser; MAKE_FILE_BINARY(out_file); if (fwrite (encoding->data, encoding->len, 1, out_file) != 1) goto loser; rv = SECSuccess; loser: if (encoding != NULL) SECITEM_FreeItem(encoding, PR_TRUE); if (request != NULL) CERT_DestroyOCSPRequest(request); if (certs != NULL) CERT_DestroyCertList (certs); if (myCert != NULL) CERT_DestroyCertificate(myCert); return rv; }
/* * 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); }
SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd, PRBool checksig, PRBool isServer) { nsNSSShutDownPreventionLock locker; // first the default action SECStatus rv = SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer); // We want to remember the CA certs in the temp db, so that the application can find the // complete chain at any time it might need it. // But we keep only those CA certs in the temp db, that we didn't already know. CERTCertificate *serverCert = SSL_PeerCertificate(fd); CERTCertificateCleaner serverCertCleaner(serverCert); if (serverCert) { nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret; nsRefPtr<nsSSLStatus> status = infoObject->SSLStatus(); nsRefPtr<nsNSSCertificate> nsc; if (!status || !status->mServerCert) { nsc = new nsNSSCertificate(serverCert); } if (SECSuccess == rv) { if (nsc) { PRBool dummyIsEV; nsc->GetIsExtendedValidation(&dummyIsEV); // the nsc object will cache the status } CERTCertList *certList = CERT_GetCertChainFromCert(serverCert, PR_Now(), certUsageSSLCA); nsCOMPtr<nsINSSComponent> nssComponent; for (CERTCertListNode *node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList); node = CERT_LIST_NEXT(node)) { 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; } if (node->cert == serverCert) { // We don't want to remember the server cert, // the code that cares for displaying page info does this already. continue; } // We have found a signer cert that we want to remember. nsCAutoString nickname; nickname = nsNSSCertificate::defaultServerNickname(node->cert); if (!nickname.IsEmpty()) { PK11SlotInfo *slot = PK11_GetInternalKeySlot(); if (slot) { PK11_ImportCert(slot, node->cert, CK_INVALID_HANDLE, const_cast<char*>(nickname.get()), PR_FALSE); PK11_FreeSlot(slot); } } } CERT_DestroyCertList(certList); } // The connection may get terminated, for example, if the server requires // a client cert. Let's provide a minimal SSLStatus // to the caller that contains at least the cert and its status. if (!status) { status = new nsSSLStatus(); infoObject->SetSSLStatus(status); } if (status && !status->mServerCert) { status->mServerCert = nsc; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("AuthCertificateCallback setting NEW cert %p\n", status->mServerCert.get())); } } 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; }
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); }
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 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; }
/* * Create a DER-encoded OCSP request (for the certificate whose nickname is * "cert_name"), then get and dump a corresponding response. The responder * location is either specified explicitly (as "responder_url") or found * via the AuthorityInfoAccess URL in the cert. */ static SECStatus dump_response (FILE *out_file, CERTCertDBHandle *handle, CERTCertificate *cert, const char *responder_url) { CERTCertList *certs = NULL; CERTCertificate *myCert = NULL; char *loc = NULL; PRTime now = PR_Now(); SECItem *response = NULL; SECStatus rv = SECFailure; PRBool includeServiceLocator; if (handle == NULL || cert == NULL) return rv; myCert = CERT_DupCertificate(cert); if (myCert == NULL) goto loser; if (responder_url != NULL) { loc = (char *) responder_url; includeServiceLocator = PR_TRUE; } else { loc = CERT_GetOCSPAuthorityInfoAccessLocation (cert); if (loc == NULL) goto loser; includeServiceLocator = PR_FALSE; } /* * We need to create a list of one. */ certs = CERT_NewCertList(); if (certs == NULL) goto loser; if (CERT_AddCertToListTail (certs, myCert) != SECSuccess) goto loser; /* * Now that cert is included in the list, we need to be careful * that we do not try to destroy it twice. This will prevent that. */ myCert = NULL; response = CERT_GetEncodedOCSPResponse (NULL, certs, loc, now, includeServiceLocator, NULL, NULL, NULL); if (response == NULL) goto loser; MAKE_FILE_BINARY(out_file); if (fwrite (response->data, response->len, 1, out_file) != 1) goto loser; rv = SECSuccess; loser: if (response != NULL) SECITEM_FreeItem (response, PR_TRUE); if (certs != NULL) CERT_DestroyCertList (certs); if (myCert != NULL) CERT_DestroyCertificate(myCert); if (loc != NULL && loc != responder_url) PORT_Free (loc); return rv; }
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; }
nsNSSCertListEnumerator::~nsNSSCertListEnumerator() { if (mCertList) { CERT_DestroyCertList(mCertList); } }
nsNSSCertList::~nsNSSCertList() { if (mCertList) { CERT_DestroyCertList(mCertList); } }
/* * 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; }
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; }
CERTCertList * CERT_CreateSubjectCertList(CERTCertList *certList, CERTCertDBHandle *handle, const SECItem *name, PRTime sorttime, PRBool validOnly) { NSSCryptoContext *cc; NSSCertificate **tSubjectCerts, **pSubjectCerts; NSSCertificate **ci; CERTCertificate *cert; NSSDER subject; PRBool myList = PR_FALSE; cc = STAN_GetDefaultCryptoContext(); NSSITEM_FROM_SECITEM(&subject, name); /* Collect both temp and perm certs for the subject */ tSubjectCerts = NSSCryptoContext_FindCertificatesBySubject(cc, &subject, NULL, 0, NULL); pSubjectCerts = NSSTrustDomain_FindCertificatesBySubject(handle, &subject, NULL, 0, NULL); if (!tSubjectCerts && !pSubjectCerts) { return NULL; } if (certList == NULL) { certList = CERT_NewCertList(); myList = PR_TRUE; if (!certList) goto loser; } /* Iterate over the matching temp certs. Add them to the list */ ci = tSubjectCerts; while (ci && *ci) { cert = STAN_GetCERTCertificateOrRelease(*ci); /* *ci may be invalid at this point, don't reference it again */ if (cert) { /* NOTE: add_to_subject_list adopts the incoming cert. */ add_to_subject_list(certList, cert, validOnly, sorttime); } ci++; } /* Iterate over the matching perm certs. Add them to the list */ ci = pSubjectCerts; while (ci && *ci) { cert = STAN_GetCERTCertificateOrRelease(*ci); /* *ci may be invalid at this point, don't reference it again */ if (cert) { /* NOTE: add_to_subject_list adopts the incoming cert. */ add_to_subject_list(certList, cert, validOnly, sorttime); } ci++; } /* all the references have been adopted or freed at this point, just * free the arrays now */ nss_ZFreeIf(tSubjectCerts); nss_ZFreeIf(pSubjectCerts); return certList; loser: /* need to free the references in tSubjectCerts and pSubjectCerts! */ nssCertificateArray_Destroy(tSubjectCerts); nssCertificateArray_Destroy(pSubjectCerts); if (myList && certList != NULL) { CERT_DestroyCertList(certList); } return NULL; }
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; }
SECStatus CertVerifier::VerifyCert(CERTCertificate * cert, const SECCertificateUsage usage, const PRTime time, nsIInterfaceRequestor * pinArg, const Flags flags, /*optional out*/ CERTCertList **validationChain, /*optional out*/ SECOidTag *evOidPolicy, /*optional out*/ CERTVerifyLog *verifyLog) { if (!cert) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (validationChain) { *validationChain = nullptr; } if (evOidPolicy) { *evOidPolicy = SEC_OID_UNKNOWN; } switch(usage){ case certificateUsageSSLClient: case certificateUsageSSLServer: case certificateUsageSSLCA: case certificateUsageEmailSigner: case certificateUsageEmailRecipient: case certificateUsageObjectSigner: case certificateUsageStatusResponder: break; default: NS_WARNING("Calling VerifyCert with invalid usage"); PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } ScopedCERTCertList trustAnchors; SECStatus rv; SECOidTag evPolicy = SEC_OID_UNKNOWN; #ifdef NSS_NO_LIBPKIX return ClassicVerifyCert(cert, usage, time, pinArg, validationChain, verifyLog); #else // Do EV checking only for sslserver usage if (usage == certificateUsageSSLServer) { SECStatus srv = getFirstEVPolicy(cert, evPolicy); if (srv == SECSuccess) { if (evPolicy != SEC_OID_UNKNOWN) { trustAnchors = getRootsForOid(evPolicy); } if (!trustAnchors) { return SECFailure; } // pkix ignores an empty trustanchors list and // decides then to use the whole set of trust in the DB // so we set the evPolicy to unkown in this case if (CERT_LIST_EMPTY(trustAnchors)) { evPolicy = SEC_OID_UNKNOWN; } } else { // Do not setup EV verification params evPolicy = SEC_OID_UNKNOWN; } } MOZ_ASSERT_IF(evPolicy != SEC_OID_UNKNOWN, trustAnchors); size_t i = 0; size_t validationChainLocation = 0; size_t validationTrustAnchorLocation = 0; CERTValOutParam cvout[4]; if (verifyLog) { cvout[i].type = cert_po_errorLog; cvout[i].value.pointer.log = verifyLog; ++i; } if (validationChain) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: setting up validation chain outparam.\n")); validationChainLocation = i; cvout[i].type = cert_po_certList; cvout[i].value.pointer.cert = nullptr; ++i; validationTrustAnchorLocation = i; cvout[i].type = cert_po_trustAnchor; cvout[i].value.pointer.chain = nullptr; ++i; } cvout[i].type = cert_po_end; CERTRevocationFlags rev; CERTRevocationMethodIndex revPreferredMethods[2]; rev.leafTests.preferred_methods = rev.chainTests.preferred_methods = revPreferredMethods; uint64_t revFlagsPerMethod[2]; rev.leafTests.cert_rev_flags_per_method = rev.chainTests.cert_rev_flags_per_method = revFlagsPerMethod; rev.leafTests.number_of_preferred_methods = rev.chainTests.number_of_preferred_methods = 1; rev.leafTests.number_of_defined_methods = rev.chainTests.number_of_defined_methods = cert_revocation_method_ocsp + 1; const bool localOnly = flags & FLAG_LOCAL_ONLY; CERTValInParam cvin[6]; // Parameters for both EV and DV validation cvin[0].type = cert_pi_useAIACertFetch; cvin[0].value.scalar.b = mMissingCertDownloadEnabled && !localOnly; cvin[1].type = cert_pi_revocationFlags; cvin[1].value.pointer.revocation = &rev; cvin[2].type = cert_pi_date; cvin[2].value.scalar.time = time; i = 3; const size_t evParamLocation = i; if (evPolicy != SEC_OID_UNKNOWN) { // EV setup! // XXX 859872 The current flags are not quite correct. (use // of ocsp flags for crl preferences). uint64_t ocspRevMethodFlags = CERT_REV_M_TEST_USING_THIS_METHOD | ((mOCSPDownloadEnabled && !localOnly) ? CERT_REV_M_ALLOW_NETWORK_FETCHING : CERT_REV_M_FORBID_NETWORK_FETCHING) | CERT_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE | CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE | CERT_REV_M_IGNORE_MISSING_FRESH_INFO | CERT_REV_M_STOP_TESTING_ON_FRESH_INFO | (mOCSPGETEnabled ? 0 : CERT_REV_M_FORCE_POST_METHOD_FOR_OCSP); rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_crl] = rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_crl] = CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD; rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] = rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] = ocspRevMethodFlags; rev.leafTests.cert_rev_method_independent_flags = rev.chainTests.cert_rev_method_independent_flags = // avoiding the network is good, let's try local first CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST // is overall revocation requirement strict or relaxed? | CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE ; rev.leafTests.preferred_methods[0] = rev.chainTests.preferred_methods[0] = cert_revocation_method_ocsp; cvin[i].type = cert_pi_policyOID; cvin[i].value.arraySize = 1; cvin[i].value.array.oids = &evPolicy; ++i; MOZ_ASSERT(trustAnchors); cvin[i].type = cert_pi_trustAnchors; cvin[i].value.pointer.chain = trustAnchors; ++i; cvin[i].type = cert_pi_end; rv = CERT_PKIXVerifyCert(cert, usage, cvin, cvout, pinArg); if (rv == SECSuccess) { if (evOidPolicy) { *evOidPolicy = evPolicy; } PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: successful CERT_PKIXVerifyCert(ev) \n")); goto pkix_done; } PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: failed CERT_PKIXVerifyCert(ev)\n")); if (validationChain && *validationChain) { // There SHOULD not be a validation chain on failure, asserion here for // the debug builds AND a fallback for production builds MOZ_ASSERT(false, "certPKIXVerifyCert returned failure AND a validationChain"); CERT_DestroyCertList(*validationChain); *validationChain = nullptr; } if (verifyLog) { // Cleanup the log so that it is ready the the next validation CERTVerifyLogNode *i_node; for (i_node = verifyLog->head; i_node; i_node = i_node->next) { //destroy cert if any. if (i_node->cert) { CERT_DestroyCertificate(i_node->cert); } // No need to cleanup the actual nodes in the arena. } verifyLog->count = 0; verifyLog->head = nullptr; verifyLog->tail = nullptr; } } if (!nsNSSComponent::globalConstFlagUsePKIXVerification){ // XXX: we do not care about the localOnly flag (currently) as the // caller that wants localOnly should disable and reenable the fetching. return ClassicVerifyCert(cert, usage, time, pinArg, validationChain, verifyLog); } // The current flags check the chain the same way as the leafs rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_crl] = rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_crl] = // implicit default source - makes no sense for CRLs CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE // let's not stop on fresh CRL. If OCSP is enabled, too, let's check it | CERT_REV_M_CONTINUE_TESTING_ON_FRESH_INFO // no fresh CRL? well, let other flag decide whether to fail or not | CERT_REV_M_IGNORE_MISSING_FRESH_INFO // testing using local CRLs is always allowed | CERT_REV_M_TEST_USING_THIS_METHOD // no local crl and don't know where to get it from? ignore | CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE // crl download based on parameter | ((mCRLDownloadEnabled && !localOnly) ? CERT_REV_M_ALLOW_NETWORK_FETCHING : CERT_REV_M_FORBID_NETWORK_FETCHING) ; rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] = rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] = // use OCSP CERT_REV_M_TEST_USING_THIS_METHOD // if app has a default OCSP responder configured, let's use it | CERT_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE // of course OCSP doesn't work without a source. let's accept such certs | CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE // if ocsp is required stop on lack of freshness | (mOCSPStrict ? CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO : CERT_REV_M_IGNORE_MISSING_FRESH_INFO) // ocsp success is sufficient | CERT_REV_M_STOP_TESTING_ON_FRESH_INFO // ocsp enabled controls network fetching, too | ((mOCSPDownloadEnabled && !localOnly) ? CERT_REV_M_ALLOW_NETWORK_FETCHING : CERT_REV_M_FORBID_NETWORK_FETCHING) | (mOCSPGETEnabled ? 0 : CERT_REV_M_FORCE_POST_METHOD_FOR_OCSP); ; rev.leafTests.preferred_methods[0] = rev.chainTests.preferred_methods[0] = cert_revocation_method_ocsp; rev.leafTests.cert_rev_method_independent_flags = rev.chainTests.cert_rev_method_independent_flags = // avoiding the network is good, let's try local first CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST // is overall revocation requirement strict or relaxed? | (mRequireRevocationInfo ? CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE : CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT) ; // Skip EV parameters cvin[evParamLocation].type = cert_pi_end; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: calling CERT_PKIXVerifyCert(dv) \n")); rv = CERT_PKIXVerifyCert(cert, usage, cvin, cvout, pinArg); pkix_done: if (validationChain) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: validation chain requested\n")); ScopedCERTCertificate trustAnchor(cvout[validationTrustAnchorLocation].value.pointer.cert); if (rv == SECSuccess) { if (! cvout[validationChainLocation].value.pointer.chain) { PR_SetError(PR_UNKNOWN_ERROR, 0); return SECFailure; } PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: I have a chain\n")); *validationChain = cvout[validationChainLocation].value.pointer.chain; if (trustAnchor) { // we should only add the issuer to the chain if it is not already // present. On CA cert checking, the issuer is the same cert, so in // that case we do not add the cert to the chain. if (!CERT_CompareCerts(trustAnchor, cert)) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: adding issuer to tail for display\n")); // note: rv is reused to catch errors on cert creation! ScopedCERTCertificate tempCert(CERT_DupCertificate(trustAnchor)); rv = CERT_AddCertToListTail(*validationChain, tempCert); if (rv == SECSuccess) { tempCert.forget(); // ownership traferred to validationChain } else { CERT_DestroyCertList(*validationChain); *validationChain = nullptr; } } } } else { // Validation was a fail, clean up if needed if (cvout[validationChainLocation].value.pointer.chain) { CERT_DestroyCertList(cvout[validationChainLocation].value.pointer.chain); } } } return rv; #endif }