}  subjectCert = NULL;
issuerCert = NULL; }
cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,		     PRBool checkSig, PRBool* sigerror,                     SECCertUsage certUsage, int64 t, void *wincx,                     CERTVerifyLog *log, PRBool* revoked){    SECTrustType trustType;    CERTBasicConstraints basicConstraint;    CERTCertificate *issuerCert = NULL;    CERTCertificate *subjectCert = NULL;    CERTCertificate *badCert = NULL;    PRBool isca;    PRBool isFortezzaV1 = PR_FALSE;    SECStatus rv;    SECStatus rvFinal = SECSuccess;    int count;    int currentPathLen = 0;    int pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT;    int flags;    unsigned int caCertType;    unsigned int requiredCAKeyUsage;    unsigned int requiredFlags;    PRArenaPool *arena = NULL;    CERTGeneralName *namesList = NULL;    CERTCertificate **certsList      = NULL;    int certsListLen = 16;    int namesCount = 0;    PRBool subjectCertIsSelfIssued;    cbd_FortezzaType last_type = cbd_None;    if (revoked) {        *revoked = PR_FALSE;    }    if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE,					 &requiredCAKeyUsage,					 &caCertType)	!= SECSuccess ) {	PORT_Assert(0);	EXIT_IF_NOT_LOGGING(log);	requiredCAKeyUsage = 0;	caCertType = 0;    }    switch ( certUsage ) {      case certUsageSSLClient:      case certUsageSSLServer:      case certUsageSSLCA:      case certUsageSSLServerWithStepUp:      case certUsageEmailSigner:      case certUsageEmailRecipient:      case certUsageObjectSigner:      case certUsageVerifyCA:      case certUsageStatusResponder:	if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,					   &trustType) != SECSuccess ) {	    PORT_Assert(0);	    EXIT_IF_NOT_LOGGING(log);	    requiredFlags = 0;	    trustType = trustSSL;	}	break;      default:	PORT_Assert(0);	EXIT_IF_NOT_LOGGING(log);	requiredFlags = 0;	trustType = trustSSL;/* This used to be 0, but we need something			      * that matches the enumeration type.			      */	caCertType = 0;    }        subjectCert = CERT_DupCertificate(cert);    if ( subjectCert == NULL ) {	goto loser;    }    /* determine if the cert is fortezza.     */    isFortezzaV1 = (PRBool)	(CERT_GetCertKeyType(&subjectCert->subjectPublicKeyInfo) 							== fortezzaKey);    if (isFortezzaV1) {	rv = cert_VerifyFortezzaV1Cert(handle, subjectCert, &last_type, 						cbd_None, t, wincx);	if (rv == SECFailure) {	    /**** PORT_SetError is already set by cert_VerifyFortezzaV1Cert **/	    LOG_ERROR_OR_EXIT(log,subjectCert,0,0);	}    }    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);    if (arena == NULL) {	goto loser;    }    certsList = PORT_ZNewArray(CERTCertificate *, certsListLen);    if (certsList == NULL)	goto loser;    /* RFC 3280 says that the name constraints will apply to the names    ** in the leaf (EE) cert, whether it is self issued or not, so    ** we pretend that it is not.    */    subjectCertIsSelfIssued = PR_FALSE;    for ( count = 0; count < CERT_MAX_CERT_CHAIN; count++ ) {	PRBool validCAOverride = PR_FALSE;	/* Construct a list of names for the current and all previous 	 * certifcates (except leaf (EE) certs, root CAs, and self-issued	 * intermediate CAs) to be verified against the name constraints 	 * extension of the issuer certificate. 	 */	if (subjectCertIsSelfIssued == PR_FALSE) {	    CERTGeneralName *subjectNameList;	    int subjectNameListLen;	    int i;	    subjectNameList    = CERT_GetCertificateNames(subjectCert, arena);	    subjectNameListLen = CERT_GetNamesLength(subjectNameList);	    if (certsListLen <= namesCount + subjectNameListLen) {		CERTCertificate **tmpCertsList;		certsListLen = (namesCount + subjectNameListLen) * 2;		tmpCertsList = 		    (CERTCertificate **)PORT_Realloc(certsList, 	                            certsListLen * sizeof(CERTCertificate *));		if (tmpCertsList == NULL) {		    goto loser;		}		certsList = tmpCertsList;	    }	    for (i = 0; i < subjectNameListLen; i++) {		certsList[namesCount + i] = subjectCert;	    }	    namesCount += subjectNameListLen;	    namesList = cert_CombineNamesLists(namesList, subjectNameList);	}	/* find the certificate of the issuer */	issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage);	if ( ! issuerCert ) {	    PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);	    LOG_ERROR(log,subjectCert,count,0);	    goto loser;	}	/* verify the signature on the cert */	if ( checkSig ) {	    rv = CERT_VerifySignedData(&subjectCert->signatureWrap,				       issuerCert, t, wincx);    	    if ( rv != SECSuccess ) {                if (sigerror) {                    *sigerror = PR_TRUE;                }		if ( PORT_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE ) {		    PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);		    LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);		} else {		    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);		    LOG_ERROR_OR_EXIT(log,subjectCert,count,0);		}	    }	}	/*	 * XXX - fortezza may need error logging stuff added	 */	if (isFortezzaV1) {	    rv = cert_VerifyFortezzaV1Cert(handle, issuerCert, &last_type, 					last_type, t, wincx);	    if (rv == SECFailure) {		/**** PORT_SetError is already set by *		 * cert_VerifyFortezzaV1Cert **/		LOG_ERROR_OR_EXIT(log,subjectCert,0,0);	    }	}	/* If the basicConstraint extension is included in an immediate CA	 * certificate, make sure that the isCA flag is on.  If the	 * pathLenConstraint component exists, it must be greater than the	 * number of CA certificates we have seen so far.  If the extension	 * is omitted, we will assume that this is a CA certificate with	 * an unlimited pathLenConstraint (since it already passes the	 * netscape-cert-type extension checking).	 *	 * In the fortezza (V1) case, we've already checked the CA bits	 * in the key, so we're presumed to be a CA; however we really don't	 * want to bypass Basic constraint or netscape extension parsing.         *          * In Fortezza V2, basicConstraint will be set for every CA,PCA,PAA	 */	rv = CERT_FindBasicConstraintExten(issuerCert, &basicConstraint);	if ( rv != SECSuccess ) {	    if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {		LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);	    } 	    pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT;	    /* no basic constraints found, if we're fortezza, CA bit is already	     * verified (isca = PR_TRUE). otherwise, we aren't (yet) a ca	     * isca = PR_FALSE */	    isca = isFortezzaV1;	} else  {	    if ( basicConstraint.isCA == PR_FALSE ) {		PORT_SetError (SEC_ERROR_CA_CERT_INVALID);		LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);	    }	    pathLengthLimit = basicConstraint.pathLenConstraint;	    isca = PR_TRUE;	}    	/* make sure that the path len constraint is properly set.*/	if (pathLengthLimit >= 0 && currentPathLen > pathLengthLimit) {	    PORT_SetError (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID);	    LOG_ERROR_OR_EXIT(log, issuerCert, count+1, pathLengthLimit);	}		/* XXX - the error logging may need to go down into CRL stuff at some	 * point	 */	/* check revoked list (issuer) */        rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx);        if (rv == SECFailure) {            if (revoked) {                *revoked = PR_TRUE;            }            LOG_ERROR_OR_EXIT(log,subjectCert,count,0);        } else if (rv == SECWouldBlock) {            /* We found something fishy, so we intend to issue an             * error to the user, but the user may wish to continue             * processing, in which case we better make sure nothing             * worse has happened... so keep cranking the loop */            rvFinal = SECFailure;            if (revoked) {                *revoked = PR_TRUE;            }            LOG_ERROR(log,subjectCert,count,0);        }	if ( issuerCert->trust ) {	    /* we have some trust info, but this does NOT imply that this	     * cert is actually trusted for any purpose.  The cert may be	     * explicitly UNtrusted.  We won't know until we examine the	     * trust bits.	     */	    if (certUsage == certUsageStatusResponder) {		/* XXX NSS has done this for years, but it seems incorrect. */		rv = rvFinal;		goto done;	    }	    /*	     * check the trust parms of the issuer	     */	    if ( certUsage == certUsageVerifyCA ) {		if ( subjectCert->nsCertType & NS_CERT_TYPE_EMAIL_CA ) {		    trustType = trustEmail;		} else if ( subjectCert->nsCertType & NS_CERT_TYPE_SSL_CA ) {		    trustType = trustSSL;		} else {		    trustType = trustObjectSigning;		}	    }	    	    flags = SEC_GET_TRUST_FLAGS(issuerCert->trust, trustType);	    	    if (flags & CERTDB_VALID_CA) {		if ( ( flags & requiredFlags ) == requiredFlags) {		    /* we found a trusted one, so return */		    rv = rvFinal; 		    goto done;		}		validCAOverride = PR_TRUE;	    }	}	if (!validCAOverride) {	    /*	     * Make sure that if this is an intermediate CA in the chain that	     * it was given permission by its signer to be a CA.	     */	    /*	     * if basicConstraints says it is a ca, then we check the	     * nsCertType.  If the nsCertType has any CA bits set, then	     * it must have the right one.	     */	    if (!isca || (issuerCert->nsCertType & NS_CERT_TYPE_CA)) {		isca = (issuerCert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE;	    }		    if (  !isca  ) {		PORT_SetError(SEC_ERROR_CA_CERT_INVALID);		LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0);	    }	    /* make sure key usage allows cert signing */	    if (CERT_CheckKeyUsage(issuerCert, requiredCAKeyUsage) != SECSuccess) {		PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);		LOG_ERROR_OR_EXIT(log,issuerCert,count+1,requiredCAKeyUsage);	    }	}	/* make sure that the entire chain is within the name space of the 	** current issuer certificate.	*/	rv = CERT_CompareNameSpace(issuerCert, namesList, certsList, 	                           arena, &badCert);	if (rv != SECSuccess || badCert != NULL) {	    PORT_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE);            LOG_ERROR_OR_EXIT(log, badCert, count + 1, 0);	    goto loser;	}	/* make sure that the issuer is not self signed.  If it is, then	 * stop here to prevent looping.	 */	if (issuerCert->isRoot) {	    PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER);	    LOG_ERROR(log, issuerCert, count+1, 0);	    goto loser;	} 	/* The issuer cert will be the subject cert in the next loop.	 * A cert is self-issued if its subject and issuer are equal and	 * both are of non-zero length. 	 */	subjectCertIsSelfIssued = (PRBool)	    SECITEM_ItemsAreEqual(&issuerCert->derIssuer, 				  &issuerCert->derSubject) &&	    issuerCert->derSubject.len > 0;	if (subjectCertIsSelfIssued == PR_FALSE) {	    /* RFC 3280 says only non-self-issued intermediate CA certs 	     * count in path length.	     */	    ++currentPathLen;	}	CERT_DestroyCertificate(subjectCert);	subjectCert = issuerCert;    }    subjectCert = NULL;    PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);    LOG_ERROR(log,issuerCert,count,0);loser:    rv = SECFailure;done:    if (certsList != NULL) {	PORT_Free(certsList);    }    if ( issuerCert ) {	CERT_DestroyCertificate(issuerCert);    }        if ( subjectCert ) {	CERT_DestroyCertificate(subjectCert);    }    if ( arena != NULL ) {	PORT_FreeArena(arena, PR_FALSE);    }    return rv;}