nsresult
nsNSSCertificate::hasValidEVOidTag(SECOidTag &resultOidTag, PRBool &validEV)
{
  nsNSSShutDownPreventionLock locker;
  if (isAlreadyShutDown())
    return NS_ERROR_NOT_AVAILABLE;

  nsresult nrv;
  nsCOMPtr<nsINSSComponent> nssComponent = 
    do_GetService(PSM_COMPONENT_CONTRACTID, &nrv);
  if (NS_FAILED(nrv))
    return nrv;
  nssComponent->EnsureIdentityInfoLoaded();

  validEV = PR_FALSE;
  resultOidTag = SEC_OID_UNKNOWN;

  PRBool isOCSPEnabled = PR_FALSE;
  nsCOMPtr<nsIX509CertDB> certdb;
  certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
  if (certdb)
    certdb->GetIsOcspOn(&isOCSPEnabled);
  // No OCSP, no EV
  if (!isOCSPEnabled)
    return NS_OK;

  SECOidTag oid_tag;
  SECStatus rv = getFirstEVPolicy(mCert, oid_tag);
  if (rv != SECSuccess)
    return NS_OK;

  if (oid_tag == SEC_OID_UNKNOWN) // not in our list of OIDs accepted for EV
    return NS_OK;

  CERTCertList *rootList = getRootsForOid(oid_tag);
  CERTCertListCleaner rootListCleaner();

  CERTRevocationMethodIndex preferedRevMethods[1] = { 
    cert_revocation_method_ocsp
  };

  PRUint64 revMethodFlags = 
    CERT_REV_M_TEST_USING_THIS_METHOD
    | CERT_REV_M_ALLOW_NETWORK_FETCHING
    | CERT_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE
    | CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE
    | CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;

  PRUint64 revMethodIndependentFlags = 
    CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST
    | CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;

  PRUint64 methodFlags[2];
  methodFlags[cert_revocation_method_crl] = revMethodFlags;
  methodFlags[cert_revocation_method_ocsp] = revMethodFlags;

  CERTRevocationFlags rev;

  rev.leafTests.number_of_defined_methods = cert_revocation_method_ocsp +1;
  rev.leafTests.cert_rev_flags_per_method = methodFlags;
  rev.leafTests.number_of_preferred_methods = 1;
  rev.leafTests.preferred_methods = preferedRevMethods;
  rev.leafTests.cert_rev_method_independent_flags =
    revMethodIndependentFlags;

  rev.chainTests.number_of_defined_methods = cert_revocation_method_ocsp +1;
  rev.chainTests.cert_rev_flags_per_method = methodFlags;
  rev.chainTests.number_of_preferred_methods = 1;
  rev.chainTests.preferred_methods = preferedRevMethods;
  rev.chainTests.cert_rev_method_independent_flags =
    revMethodIndependentFlags;

  CERTValInParam cvin[3];
  cvin[0].type = cert_pi_policyOID;
  cvin[0].value.arraySize = 1; 
  cvin[0].value.array.oids = &oid_tag;

  cvin[1].type = cert_pi_revocationFlags;
  cvin[1].value.pointer.revocation = &rev;

  cvin[2].type = cert_pi_trustAnchors;
  cvin[2].value.pointer.chain = rootList;

  cvin[3].type = cert_pi_end;

  CERTValOutParam cvout[2];
  cvout[0].type = cert_po_trustAnchor;
  cvout[0].value.pointer.cert = nsnull;
  cvout[1].type = cert_po_end;

  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("calling CERT_PKIXVerifyCert nss cert %p\n", mCert));
  rv = CERT_PKIXVerifyCert(mCert, certificateUsageSSLServer,
                           cvin, cvout, nsnull);
  if (rv != SECSuccess)
    return NS_OK;

  CERTCertificate *issuerCert = cvout[0].value.pointer.cert;
  CERTCertificateCleaner issuerCleaner(issuerCert);

#ifdef PR_LOGGING
  if (PR_LOG_TEST(gPIPNSSLog, PR_LOG_DEBUG)) {
    nsNSSCertificate ic(issuerCert);
    nsAutoString fingerprint;
    ic.GetSha1Fingerprint(fingerprint);
    NS_LossyConvertUTF16toASCII fpa(fingerprint);
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CERT_PKIXVerifyCert returned success, issuer: %s, SHA1: %s\n", 
      issuerCert->subjectName, fpa.get()));
  }
#endif

  validEV = isApprovedForEV(oid_tag, issuerCert);
  if (validEV)
    resultOidTag = oid_tag;
 
  return NS_OK;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
nsresult
nsUsageArrayHelper::GetUsagesArray(const char *suffix,
                      bool localOnly,
                      uint32_t outArraySize,
                      uint32_t *_verified,
                      uint32_t *_count,
                      PRUnichar **outUsages)
{
  nsNSSShutDownPreventionLock locker;
  if (NS_FAILED(m_rv))
    return m_rv;

  if (outArraySize < max_returned_out_array_size)
    return NS_ERROR_FAILURE;

  nsCOMPtr<nsINSSComponent> nssComponent;

  if (!nsNSSComponent::globalConstFlagUsePKIXVerification && localOnly) {
    nsresult rv;
    nssComponent = do_GetService(kNSSComponentCID, &rv);
    if (NS_FAILED(rv))
      return rv;
    
    if (nssComponent) {
      nssComponent->SkipOcsp();
    }
  }
  
  uint32_t &count = *_count;
  count = 0;
  SECCertificateUsage usages = 0;
  int err = 0;
  
if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
  // CERT_VerifyCertificateNow returns SECFailure unless the certificate is
  // valid for all the given usages. Hoewver, we are only looking for the list
  // of usages for which the cert *is* valid.
  (void)
  CERT_VerifyCertificateNow(defaultcertdb, mCert, true,
			    certificateUsageSSLClient |
			    certificateUsageSSLServer |
			    certificateUsageSSLServerWithStepUp |
			    certificateUsageEmailSigner |
			    certificateUsageEmailRecipient |
			    certificateUsageObjectSigner |
			    certificateUsageSSLCA |
			    certificateUsageStatusResponder,
			    NULL, &usages);
  err = PR_GetError();
}
else {
  nsresult nsrv;
  nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
  if (!inss)
    return nsrv;
  nsRefPtr<nsCERTValInParamWrapper> survivingParams;
  if (localOnly)
    nsrv = inss->GetDefaultCERTValInParamLocalOnly(survivingParams);
  else
    nsrv = inss->GetDefaultCERTValInParam(survivingParams);
  
  if (NS_FAILED(nsrv))
    return nsrv;

  CERTValOutParam cvout[2];
  cvout[0].type = cert_po_usages;
  cvout[0].value.scalar.usages = 0;
  cvout[1].type = cert_po_end;
  
  CERT_PKIXVerifyCert(mCert, certificateUsageCheckAllUsages,
                      survivingParams->GetRawPointerForNSS(),
                      cvout, NULL);
  err = PR_GetError();
  usages = cvout[0].value.scalar.usages;
}

  // The following list of checks must be < max_returned_out_array_size
  
  check(suffix, usages & certificateUsageSSLClient, count, outUsages);
  check(suffix, usages & certificateUsageSSLServer, count, outUsages);
  check(suffix, usages & certificateUsageSSLServerWithStepUp, count, outUsages);
  check(suffix, usages & certificateUsageEmailSigner, count, outUsages);
  check(suffix, usages & certificateUsageEmailRecipient, count, outUsages);
  check(suffix, usages & certificateUsageObjectSigner, count, outUsages);
#if 0
  check(suffix, usages & certificateUsageProtectedObjectSigner, count, outUsages);
  check(suffix, usages & certificateUsageUserCertImport, count, outUsages);
#endif
  check(suffix, usages & certificateUsageSSLCA, count, outUsages);
#if 0
  check(suffix, usages & certificateUsageVerifyCA, count, outUsages);
#endif
  check(suffix, usages & certificateUsageStatusResponder, count, outUsages);
#if 0
  check(suffix, usages & certificateUsageAnyCA, count, outUsages);
#endif

  if (!nsNSSComponent::globalConstFlagUsePKIXVerification && localOnly && nssComponent) {
    nssComponent->SkipOcspOff();
  }

  if (count == 0) {
    verifyFailed(_verified, err);
  } else {
    *_verified = nsNSSCertificate::VERIFIED_OK;
  }
  return NS_OK;
}
Ejemplo n.º 5
0
NS_IMETHODIMP
nsNSSCertificate::VerifyForUsage(uint32_t usage, uint32_t *verificationResult)
{
  nsNSSShutDownPreventionLock locker;
  if (isAlreadyShutDown())
    return NS_ERROR_NOT_AVAILABLE;

  NS_ENSURE_ARG(verificationResult);

  nsresult nsrv;
  nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
  if (!inss)
    return nsrv;
  nsRefPtr<nsCERTValInParamWrapper> survivingParams;
  nsrv = inss->GetDefaultCERTValInParam(survivingParams);
  if (NS_FAILED(nsrv))
    return nsrv;
  
  SECCertificateUsage nss_usage;
  
  switch (usage)
  {
    case CERT_USAGE_SSLClient:
      nss_usage = certificateUsageSSLClient;
      break;

    case CERT_USAGE_SSLServer:
      nss_usage = certificateUsageSSLServer;
      break;

    case CERT_USAGE_SSLServerWithStepUp:
      nss_usage = certificateUsageSSLServerWithStepUp;
      break;

    case CERT_USAGE_SSLCA:
      nss_usage = certificateUsageSSLCA;
      break;

    case CERT_USAGE_EmailSigner:
      nss_usage = certificateUsageEmailSigner;
      break;

    case CERT_USAGE_EmailRecipient:
      nss_usage = certificateUsageEmailRecipient;
      break;

    case CERT_USAGE_ObjectSigner:
      nss_usage = certificateUsageObjectSigner;
      break;

    case CERT_USAGE_UserCertImport:
      nss_usage = certificateUsageUserCertImport;
      break;

    case CERT_USAGE_VerifyCA:
      nss_usage = certificateUsageVerifyCA;
      break;

    case CERT_USAGE_ProtectedObjectSigner:
      nss_usage = certificateUsageProtectedObjectSigner;
      break;

    case CERT_USAGE_StatusResponder:
      nss_usage = certificateUsageStatusResponder;
      break;

    case CERT_USAGE_AnyCA:
      nss_usage = certificateUsageAnyCA;
      break;

    default:
      return NS_ERROR_FAILURE;
  }

  SECStatus verify_result;
  if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
    CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
    verify_result = CERT_VerifyCertificateNow(defaultcertdb, mCert, true, 
                                              nss_usage, NULL, NULL);
  }
  else {
    CERTValOutParam cvout[1];
    cvout[0].type = cert_po_end;
    verify_result = CERT_PKIXVerifyCert(mCert, nss_usage,
                                        survivingParams->GetRawPointerForNSS(),
                                        cvout, NULL);
  }
  
  if (verify_result == SECSuccess)
  {
    *verificationResult = VERIFIED_OK;
  }
  else
  {
    int err = PR_GetError();

    // this list was cloned from verifyFailed

    switch (err)
    {
      case SEC_ERROR_INADEQUATE_KEY_USAGE:
      case SEC_ERROR_INADEQUATE_CERT_TYPE:
        *verificationResult = USAGE_NOT_ALLOWED;
        break;

      case SEC_ERROR_REVOKED_CERTIFICATE:
        *verificationResult = CERT_REVOKED;
        break;

      case SEC_ERROR_EXPIRED_CERTIFICATE:
        *verificationResult = CERT_EXPIRED;
        break;
        
      case SEC_ERROR_UNTRUSTED_CERT:
        *verificationResult = CERT_NOT_TRUSTED;
        break;
        
      case SEC_ERROR_UNTRUSTED_ISSUER:
        *verificationResult = ISSUER_NOT_TRUSTED;
        break;
        
      case SEC_ERROR_UNKNOWN_ISSUER:
        *verificationResult = ISSUER_UNKNOWN;
        break;
        
      case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
        *verificationResult = SIGNATURE_ALGORITHM_DISABLED;
        break;

      case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
        *verificationResult = INVALID_CA;
        break;
        
      case SEC_ERROR_CERT_USAGES_INVALID:
      default:
        *verificationResult = NOT_VERIFIED_UNKNOWN; 
        break;
    }
  }
  
  return NS_OK;  
}
Ejemplo n.º 6
0
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
}
Ejemplo n.º 7
0
int main(int argc, char *argv[])
{
	int opt;
	long fin = 0;
	int use_pkix = 0;
	SECStatus rv;
	char pbuf[1024];
	PRBool crlcheck = PR_FALSE;
	PRBool ocspcheck = PR_FALSE;
	PRBool strict = PR_FALSE;
	CERTCertDBHandle *handle = NULL;
	CERTCertificate **certout = NULL;
	CERTVerifyLog vfy_log;
	CERTVerifyLog vfy_log2;
	CERTVerifyLog *cur_log;
	CERTValOutParam *pkixout = NULL;

	SECItem c1;
	SECItem c2;
	SECItem *certs[2];
	certs[0] = &c1;
	certs[1] = &c2;

	int numcerts = 0;
	while ((opt = getopt(argc, argv, "u:d:e:pn:s:coSr")) != -1) {
		switch(opt) {
			/* usage type */
		case 'u':
			set_usage(optarg);
			break;
		case 'd':
			db_dir = optarg;
			break;
		case 's':
			sub_file = optarg;
			break;
		case 'c':
			crlcheck = PR_TRUE;
			break;
		case 'o':
			ocspcheck = PR_TRUE;
			break;
		case 'S':
			strict = PR_TRUE;
			break;
		case 'e':
			end_file = optarg;
			break;
		case 'p':
			use_pkix = 1;
			break;
		case 'n':
			rightca_nick = optarg;
			break;
		case 'r':
			retry_verify = PR_TRUE;
			break;
		default:
			print_usage();
			break;
		}
	}

	if (db_dir == NULL)
		db_dir = "testfiles/";
	if (end_file == NULL)
		end_file = "testfiles/end.pem";

	get_file(certs[numcerts++], end_file);

	if (sub_file != NULL) {
		get_file(certs[numcerts++], sub_file);
	}

	snprintf(pbuf, sizeof(pbuf), "sql:%s", db_dir);
	if (NSS_Initialize(pbuf, "", "", "secmod.db", 0x1) != SECSuccess) {
		printf("NSS_Initialize failed %d\n", PORT_GetError());
		exit(-1);
	}

	if ((handle = CERT_GetDefaultCertDB()) == NULL) {
		printf("NULL handle\n");
		exit(-1);
	}
	if (ocspcheck) {
		CERT_EnableOCSPChecking(handle);
		CERT_DisableOCSPDefaultResponder(handle);
		if (strict)
			CERT_SetOCSPFailureMode(ocspMode_FailureIsNotAVerificationFailure);
	}

	rv = CERT_ImportCerts(handle, 0, numcerts, certs, &certout, PR_FALSE,
							 PR_FALSE, NULL);
	if (rv != SECSuccess) {
		printf("CERT_ImportCerts failed %d\n", PORT_GetError());
		exit(-1);
	}
	vfy_log.count = 0;
	vfy_log.head = NULL;
	vfy_log.tail = NULL;
	vfy_log.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);

	vfy_log2.count = 0;
	vfy_log2.head = NULL;
	vfy_log2.tail = NULL;
	vfy_log2.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);

	if (use_pkix) {
		int in_idx = 0;
		CERTValInParam cvin[7];
		CERTValOutParam cvout[3];
		CERTCertList *trustcl = NULL;
		CERTRevocationFlags rev;
		PRUint64 revFlagsLeaf[2] = { 0, 0 };
		PRUint64 revFlagsChain[2] = { 0, 0 };

		zero(&cvin);	/* ??? is this reasonable? */
		zero(&cvout);	/* ??? is this reasonable? */
		zero(&rev);	/* ??? is this reasonable? */

		if (rightca_nick == NULL)
			rightca_nick = "root";

		if ((trustcl = get_trust_certlist(handle, rightca_nick)) == NULL) {
			printf("Couldn't find trust anchor\n");
			exit(-1);
		}

		cvin[in_idx].type = cert_pi_useAIACertFetch;
		cvin[in_idx++].value.scalar.b = PR_TRUE;
		cvin[in_idx].type = cert_pi_revocationFlags;
		cvin[in_idx++].value.pointer.revocation = &rev;
		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;

		set_rev_per_meth(&rev, revFlagsLeaf, revFlagsChain);
		set_rev_params(&rev, crlcheck, ocspcheck, strict);
		cvin[in_idx].type = cert_pi_end;

		cvout[0].type = cert_po_errorLog;
		cvout[0].value.pointer.log = &vfy_log;
		cur_log = &vfy_log;
		cvout[1].type = cert_po_certList;
		cvout[1].value.pointer.chain = NULL;
		cvout[2].type = cert_po_end;
		pkixout = &cvout[0];

pkixredo:
		rv = CERT_PKIXVerifyCert(*certout, pkixusage, cvin, cvout,
				NULL);

		//CERT_DestroyCertList(trustcl);

	} else {
		cur_log = &vfy_log;
vfyredo:
		rv = CERT_VerifyCert(handle, *certout, PR_TRUE, usage, PR_Now(),
								       NULL,
								       cur_log);
	}

	if (rv != SECSuccess || cur_log->count > 0) {
		if (cur_log->count > 0 && cur_log->head != NULL) {
			fin = err_stat(cur_log->head);
		} else {
			fin = PORT_GetError();
		}
		if (fin == SEC_ERROR_INADEQUATE_KEY_USAGE) {
			printf("SEC_ERROR_INADEQUATE_KEY_USAGE : Certificate key usage inadequate for attempted operation.\n"
				);
		} else if (fin == SEC_ERROR_INADEQUATE_CERT_TYPE) {
			printf("SEC_ERROR_INADEQUATE_CERT_TYPE : Certificate type not approved for application.\n"
				);
		} else {
			printf("OTHER : %ld", fin);
		}
	}
	if ((fin == SEC_ERROR_INADEQUATE_CERT_TYPE ||
			fin == SEC_ERROR_INADEQUATE_KEY_USAGE) &&
					 retry_verify && !retried) {
		printf("Retrying verification\n");
		fin = 0;
		retried = PR_TRUE;
		if (use_pkix) {
			pkixout[0].value.pointer.log = &vfy_log2;
			cur_log = &vfy_log2;
			pkixout[1].value.pointer.chain = NULL;
			if (pkixusage == certificateUsageSSLClient) {
				pkixusage = certificateUsageSSLServer;
			} else {
				pkixusage = certificateUsageSSLClient;
			}
			goto pkixredo;
		} else {
			if (usage == certUsageSSLClient) {
				usage = certUsageSSLServer;
			} else {
				usage = certUsageSSLClient;
			}
			goto vfyredo;
		}
	}

	PORT_FreeArena(vfy_log.arena, PR_FALSE);
	PORT_FreeArena(vfy_log2.arena, PR_FALSE);
	NSS_Shutdown();
	exit(fin == 0 ? 0 : 1);
}