andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public
andre@0:  * License, v. 2.0. If a copy of the MPL was not distributed with this
andre@0:  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
andre@0: /*
andre@0:  * nss_pkix_proxy.h
andre@0:  *
andre@0:  * PKIX - NSS proxy functions
andre@0:  *
andre@0:  * NOTE: All structures, functions, data types are parts of library private
andre@0:  * api and are subjects to change in any following releases.
andre@0:  *
andre@0:  */
andre@0: #include "prerror.h"
andre@0: #include "prprf.h"
andre@0:  
andre@0: #include "nspr.h"
andre@0: #include "pk11func.h"
andre@0: #include "certdb.h"
andre@0: #include "cert.h"
andre@0: #include "secerr.h"
andre@0: #include "nssb64.h"
andre@0: #include "secasn1.h"
andre@0: #include "secder.h"
andre@0: #include "pkit.h"
andre@0: 
andre@0: #include "pkix_pl_common.h"
andre@0: 
andre@0: extern PRLogModuleInfo *pkixLog;
andre@0: 
andre@0: #ifdef DEBUG_volkov
andre@0: /* Temporary declarations of functioins. Will be removed with fix for
andre@0:  * 391183 */
andre@0: extern char *
andre@0: pkix_Error2ASCII(PKIX_Error *error, void *plContext);
andre@0: 
andre@0: extern void
andre@0: cert_PrintCert(PKIX_PL_Cert *pkixCert, void *plContext);
andre@0: 
andre@0: extern PKIX_Error *
andre@0: cert_PrintCertChain(PKIX_List *pkixCertChain, void *plContext);
andre@0: 
andre@0: #endif /* DEBUG */
andre@0: 
andre@0: #ifdef PKIX_OBJECT_LEAK_TEST
andre@0: 
andre@0: extern PKIX_UInt32
andre@0: pkix_pl_lifecycle_ObjectLeakCheck(int *);
andre@0: 
andre@0: extern SECStatus
andre@0: pkix_pl_lifecycle_ObjectTableUpdate(int *objCountTable);
andre@0: 
andre@0: PRInt32 parallelFnInvocationCount;
andre@0: #endif /* PKIX_OBJECT_LEAK_TEST */
andre@0: 
andre@0: 
andre@0: static PRBool usePKIXValidationEngine = PR_FALSE;
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: CERT_SetUsePKIXForValidation
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  * Enables or disables use of libpkix for certificate validation
andre@0:  *
andre@0:  * PARAMETERS:
andre@0:  *  "enable"
andre@0:  *      PR_TRUE: enables use of libpkix for cert validation.
andre@0:  *      PR_FALSE: disables.
andre@0:  * THREAD SAFETY:
andre@0:  *  NOT Thread Safe.
andre@0:  * RETURNS:
andre@0:  *  Returns SECSuccess if successfully enabled
andre@0:  */
andre@0: SECStatus
andre@0: CERT_SetUsePKIXForValidation(PRBool enable)
andre@0: {
andre@0:     usePKIXValidationEngine = (enable > 0) ? PR_TRUE : PR_FALSE;
andre@0:     return SECSuccess;
andre@0: }
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: CERT_GetUsePKIXForValidation
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  * Checks if libpkix building function should be use for certificate
andre@0:  * chain building.
andre@0:  *
andre@0:  * PARAMETERS:
andre@0:  *  NONE
andre@0:  * THREAD SAFETY:
andre@0:  *  NOT Thread Safe
andre@0:  * RETURNS:
andre@0:  *  Returns PR_TRUE if libpkix should be used. PR_FALSE otherwise.
andre@0:  */
andre@0: PRBool
andre@0: CERT_GetUsePKIXForValidation()
andre@0: {
andre@0:     return usePKIXValidationEngine;
andre@0: }
andre@0: 
andre@0: #ifdef NOTDEF
andre@0: /*
andre@0:  * FUNCTION: cert_NssKeyUsagesToPkix
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  * Converts nss key usage bit field(PRUint32) to pkix key usage
andre@0:  * bit field.
andre@0:  *
andre@0:  * PARAMETERS:
andre@0:  *  "nssKeyUsage"
andre@0:  *      Nss key usage bit field.
andre@0:  *  "pkixKeyUsage"
andre@0:  *      Pkix key usage big field.
andre@0:  *  "plContext"
andre@0:  *      Platform-specific context pointer.
andre@0:  * THREAD SAFETY:
andre@0:  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
andre@0:  * RETURNS:
andre@0:  *  Returns NULL if the function succeeds.
andre@0:  *  Returns a Fatal Error if the function fails in an unrecoverable way.
andre@0:  */
andre@0: static PKIX_Error*
andre@0: cert_NssKeyUsagesToPkix(
andre@0:     PRUint32 nssKeyUsage,
andre@0:     PKIX_UInt32 *pPkixKeyUsage,
andre@0:     void *plContext)
andre@0: {
andre@0:     PKIX_UInt32 pkixKeyUsage = 0;
andre@0: 
andre@0:     PKIX_ENTER(CERTVFYPKIX, "cert_NssKeyUsagesToPkix");
andre@0:     PKIX_NULLCHECK_ONE(pPkixKeyUsage);
andre@0: 
andre@0:     *pPkixKeyUsage = 0;
andre@0: 
andre@0:     if (nssKeyUsage & KU_DIGITAL_SIGNATURE) {
andre@0:         pkixKeyUsage |= PKIX_DIGITAL_SIGNATURE;
andre@0:     }
andre@0:     
andre@0:     if (nssKeyUsage & KU_NON_REPUDIATION) {
andre@0:         pkixKeyUsage |= PKIX_NON_REPUDIATION;
andre@0:     }
andre@0: 
andre@0:     if (nssKeyUsage & KU_KEY_ENCIPHERMENT) {
andre@0:         pkixKeyUsage |= PKIX_KEY_ENCIPHERMENT;
andre@0:     }
andre@0:     
andre@0:     if (nssKeyUsage & KU_DATA_ENCIPHERMENT) {
andre@0:         pkixKeyUsage |= PKIX_DATA_ENCIPHERMENT;
andre@0:     }
andre@0:     
andre@0:     if (nssKeyUsage & KU_KEY_AGREEMENT) {
andre@0:         pkixKeyUsage |= PKIX_KEY_AGREEMENT;
andre@0:     }
andre@0:     
andre@0:     if (nssKeyUsage & KU_KEY_CERT_SIGN) {
andre@0:         pkixKeyUsage |= PKIX_KEY_CERT_SIGN;
andre@0:     }
andre@0:     
andre@0:     if (nssKeyUsage & KU_CRL_SIGN) {
andre@0:         pkixKeyUsage |= PKIX_CRL_SIGN;
andre@0:     }
andre@0: 
andre@0:     if (nssKeyUsage & KU_ENCIPHER_ONLY) {
andre@0:         pkixKeyUsage |= PKIX_ENCIPHER_ONLY;
andre@0:     }
andre@0:     
andre@0:     /* Not supported. XXX we should support this once it is
andre@0:      * fixed in NSS */
andre@0:     /* pkixKeyUsage |= PKIX_DECIPHER_ONLY; */
andre@0: 
andre@0:     *pPkixKeyUsage = pkixKeyUsage;
andre@0: 
andre@0:     PKIX_RETURN(CERTVFYPKIX);
andre@0: }
andre@0: 
andre@0: extern SECOidTag ekuOidStrings[];
andre@0: 
andre@0: enum {
andre@0:     ekuIndexSSLServer = 0,
andre@0:     ekuIndexSSLClient,
andre@0:     ekuIndexCodeSigner,
andre@0:     ekuIndexEmail,
andre@0:     ekuIndexTimeStamp,
andre@0:     ekuIndexStatusResponder,
andre@0:     ekuIndexUnknown
andre@0: } ekuIndex;
andre@0: 
andre@0: typedef struct {
andre@0:     SECCertUsage certUsage;
andre@0:     PRUint32 ekuStringIndex;
andre@0: } SECCertUsageToEku;
andre@0: 
andre@0: const SECCertUsageToEku certUsageEkuStringMap[] = {
andre@0:     {certUsageSSLClient,             ekuIndexSSLClient},
andre@0:     {certUsageSSLServer,             ekuIndexSSLServer},
andre@0:     {certUsageSSLCA,                 ekuIndexSSLServer},
andre@0:     {certUsageEmailSigner,           ekuIndexEmail},
andre@0:     {certUsageEmailRecipient,        ekuIndexEmail},
andre@0:     {certUsageObjectSigner,          ekuIndexCodeSigner},
andre@0:     {certUsageUserCertImport,        ekuIndexUnknown},
andre@0:     {certUsageVerifyCA,              ekuIndexUnknown},
andre@0:     {certUsageProtectedObjectSigner, ekuIndexUnknown},
andre@0:     {certUsageStatusResponder,       ekuIndexStatusResponder},
andre@0:     {certUsageAnyCA,                 ekuIndexUnknown},
andre@0: };
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: cert_NssCertificateUsageToPkixKUAndEKU
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  * Converts nss CERTCertificateUsage bit field to pkix key and
andre@0:  * extended key usages.
andre@0:  *
andre@0:  * PARAMETERS:
andre@0:  *  "cert"
andre@0:  *      Pointer to CERTCertificate structure of validating cert.
andre@0:  *  "requiredCertUsages"
andre@0:  *      Required usage that will be converted to pkix eku and ku. 
andre@0:  *  "requiredKeyUsage",
andre@0:  *      Additional key usages impose to cert.
andre@0:  *  "isCA",
andre@0:  *      it true, convert usages for cert that is a CA cert.  
andre@0:  *  "ppkixEKUList"
andre@0:  *      Returned address of a list of pkix extended key usages.
andre@0:  *  "ppkixKU"
andre@0:  *      Returned address of pkix required key usages bit field. 
andre@0:  *  "plContext"
andre@0:  *      Platform-specific context pointer.
andre@0:  * THREAD SAFETY:
andre@0:  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
andre@0:  * RETURNS:
andre@0:  *  Returns NULL if the function succeeds.
andre@0:  *  Returns a Cert Verify Error if the function fails in an unrecoverable way.
andre@0:  *  Returns a Fatal Error if the function fails in an unrecoverable way.
andre@0:  */
andre@0: static PKIX_Error*
andre@0: cert_NssCertificateUsageToPkixKUAndEKU(
andre@0:     CERTCertificate *cert,
andre@0:     SECCertUsage     requiredCertUsage,
andre@0:     PRUint32         requiredKeyUsages,
andre@0:     PRBool           isCA,
andre@0:     PKIX_List      **ppkixEKUList,
andre@0:     PKIX_UInt32     *ppkixKU,
andre@0:     void            *plContext)
andre@0: {
andre@0:     PKIX_List           *ekuOidsList = NULL;
andre@0:     PKIX_PL_OID         *ekuOid = NULL;
andre@0:     int                  i = 0;
andre@0:     int                  ekuIndex = ekuIndexUnknown;
andre@0: 
andre@0:     PKIX_ENTER(CERTVFYPKIX, "cert_NssCertificateUsageToPkixEku");
andre@0:     PKIX_NULLCHECK_TWO(ppkixEKUList, ppkixKU);
andre@0:     
andre@0:     PKIX_CHECK(
andre@0:         PKIX_List_Create(&ekuOidsList, plContext),
andre@0:         PKIX_LISTCREATEFAILED);
andre@0: 
andre@0:     for (;i < PR_ARRAY_SIZE(certUsageEkuStringMap);i++) {
andre@0:         const SECCertUsageToEku *usageToEkuElem =
andre@0:             &certUsageEkuStringMap[i];
andre@0:         if (usageToEkuElem->certUsage == requiredCertUsage) {
andre@0:             ekuIndex = usageToEkuElem->ekuStringIndex;
andre@0:             break;
andre@0:         }
andre@0:     }
andre@0:     if (ekuIndex != ekuIndexUnknown) {
andre@0:         PRUint32             reqKeyUsage = 0;
andre@0:         PRUint32             reqCertType = 0;
andre@0: 
andre@0:         CERT_KeyUsageAndTypeForCertUsage(requiredCertUsage, isCA,
andre@0:                                          &reqKeyUsage,
andre@0:                                          &reqCertType);
andre@0:         
andre@0:         requiredKeyUsages |= reqKeyUsage;
andre@0:         
andre@0:         PKIX_CHECK(
andre@0:             PKIX_PL_OID_Create(ekuOidStrings[ekuIndex], &ekuOid,
andre@0:                                plContext),
andre@0:             PKIX_OIDCREATEFAILED);
andre@0:         
andre@0:         PKIX_CHECK(
andre@0:             PKIX_List_AppendItem(ekuOidsList, (PKIX_PL_Object *)ekuOid,
andre@0:                                  plContext),
andre@0:             PKIX_LISTAPPENDITEMFAILED);
andre@0:         
andre@0:         PKIX_DECREF(ekuOid);
andre@0:     }
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         cert_NssKeyUsagesToPkix(requiredKeyUsages, ppkixKU, plContext),
andre@0:         PKIX_NSSCERTIFICATEUSAGETOPKIXKUANDEKUFAILED);
andre@0: 
andre@0:     *ppkixEKUList = ekuOidsList;
andre@0:     ekuOidsList = NULL;
andre@0: 
andre@0: cleanup:
andre@0:     
andre@0:     PKIX_DECREF(ekuOid);
andre@0:     PKIX_DECREF(ekuOidsList);
andre@0: 
andre@0:     PKIX_RETURN(CERTVFYPKIX);
andre@0: }
andre@0: 
andre@0: #endif
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: cert_ProcessingParamsSetKeyAndCertUsage
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  * Converts cert usage to pkix KU type and sets
andre@0:  * converted data into PKIX_ProcessingParams object. It also sets
andre@0:  * proper cert usage into nsscontext object.
andre@0:  *
andre@0:  * PARAMETERS:
andre@0:  *  "procParams"
andre@0:  *      Pointer to PKIX_ProcessingParams used during validation.
andre@0:  *  "requiredCertUsage"
andre@0:  *      Required certificate usages the certificate and chain is built and
andre@0:  *      validated for.
andre@0:  *  "requiredKeyUsage"
andre@0:  *      Request additional key usages the certificate should be validated for.
andre@0:  *  "plContext"
andre@0:  *      Platform-specific context pointer.
andre@0:  * THREAD SAFETY:
andre@0:  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
andre@0:  * RETURNS:
andre@0:  *  Returns NULL if the function succeeds.
andre@0:  *  Returns a Cert Verify Error if the function fails in an unrecoverable way.
andre@0:  *  Returns a Fatal Error if the function fails in an unrecoverable way.
andre@0:  */
andre@0: static PKIX_Error*
andre@0: cert_ProcessingParamsSetKeyAndCertUsage(
andre@0:     PKIX_ProcessingParams *procParams,
andre@0:     SECCertUsage           requiredCertUsage,
andre@0:     PRUint32               requiredKeyUsages,
andre@0:     void                  *plContext)
andre@0: {
andre@0:     PKIX_CertSelector     *certSelector = NULL;
andre@0:     PKIX_ComCertSelParams *certSelParams = NULL;
andre@0:     PKIX_PL_NssContext    *nssContext = (PKIX_PL_NssContext*)plContext;
andre@0:  
andre@0:     PKIX_ENTER(CERTVFYPKIX, "cert_ProcessingParamsSetKeyAndCertUsage");
andre@0:     PKIX_NULLCHECK_TWO(procParams, nssContext);
andre@0:     
andre@0:     PKIX_CHECK(
andre@0:         pkix_pl_NssContext_SetCertUsage(
andre@0: 	    ((SECCertificateUsage)1) << requiredCertUsage, nssContext),
andre@0: 	    PKIX_NSSCONTEXTSETCERTUSAGEFAILED);
andre@0: 
andre@0:     if (requiredKeyUsages) {
andre@0:         PKIX_CHECK(
andre@0:             PKIX_ProcessingParams_GetTargetCertConstraints(procParams,
andre@0:                                                            &certSelector, plContext),
andre@0:             PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED);
andre@0:         
andre@0:         PKIX_CHECK(
andre@0:             PKIX_CertSelector_GetCommonCertSelectorParams(certSelector,
andre@0:                                                           &certSelParams, plContext),
andre@0:             PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED);
andre@0:         
andre@0:         
andre@0:         PKIX_CHECK(
andre@0:             PKIX_ComCertSelParams_SetKeyUsage(certSelParams, requiredKeyUsages,
andre@0:                                               plContext),
andre@0:             PKIX_COMCERTSELPARAMSSETKEYUSAGEFAILED);
andre@0:     }
andre@0: cleanup:
andre@0:     PKIX_DECREF(certSelector);
andre@0:     PKIX_DECREF(certSelParams);
andre@0: 
andre@0:     PKIX_RETURN(CERTVFYPKIX);
andre@0: }
andre@0: 
andre@0: /*
andre@0:  * Unused parameters: 
andre@0:  *
andre@0:  *  CERTCertList *initialChain,
andre@0:  *  CERTCertStores certStores,
andre@0:  *  CERTCertRevCheckers certRevCheckers,
andre@0:  *  CERTCertChainCheckers certChainCheckers,
andre@0:  *  SECItem *initPolicies,
andre@0:  *  PRBool policyQualifierRejected,
andre@0:  *  PRBool anyPolicyInhibited,
andre@0:  *  PRBool reqExplicitPolicy,
andre@0:  *  PRBool policyMappingInhibited,
andre@0:  *  PKIX_CertSelector certConstraints,
andre@0:  */
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: cert_CreatePkixProcessingParams
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  * Creates and fills in PKIX_ProcessingParams structure to be used
andre@0:  * for certificate chain building.
andre@0:  *
andre@0:  * PARAMETERS:
andre@0:  *  "cert"
andre@0:  *      Pointer to the CERTCertificate: the leaf certificate of a chain.
andre@0:  *  "time"
andre@0:  *      Validity time.
andre@0:  *  "wincx"
andre@0:  *      Nss db password token.
andre@0:  *  "useArena"
andre@0:  *      Flags to use arena for data allocation during chain building process.
andre@0:  *  "pprocParams"
andre@0:  *      Address to return created processing parameters.
andre@0:  *  "plContext"
andre@0:  *      Platform-specific context pointer.
andre@0:  * THREAD SAFETY:
andre@0:  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
andre@0:  * RETURNS:
andre@0:  *  Returns NULL if the function succeeds.
andre@0:  *  Returns a Cert Verify Error if the function fails in an unrecoverable way.
andre@0:  *  Returns a Fatal Error if the function fails in an unrecoverable way.
andre@0:  */
andre@0: static PKIX_Error*
andre@0: cert_CreatePkixProcessingParams(
andre@0:     CERTCertificate        *cert,
andre@0:     PRBool                  checkSig, /* not used yet. See bug 391476 */
andre@0:     PRTime                  time,
andre@0:     void                   *wincx,
andre@0:     PRBool                  useArena,
andre@0:     PRBool                  disableOCSPRemoteFetching,
andre@0:     PKIX_ProcessingParams **pprocParams,
andre@0:     void                  **pplContext)
andre@0: {
andre@0:     PKIX_List             *anchors = NULL;
andre@0:     PKIX_PL_Cert          *targetCert = NULL;
andre@0:     PKIX_PL_Date          *date = NULL;
andre@0:     PKIX_ProcessingParams *procParams = NULL;
andre@0:     PKIX_CertSelector     *certSelector = NULL;
andre@0:     PKIX_ComCertSelParams *certSelParams = NULL;
andre@0:     PKIX_CertStore        *certStore = NULL;
andre@0:     PKIX_List             *certStores = NULL;
andre@0:     PKIX_RevocationChecker *revChecker = NULL;
andre@0:     PKIX_UInt32           methodFlags = 0;
andre@0:     void                  *plContext = NULL;
andre@0:     CERTStatusConfig      *statusConfig = NULL;
andre@0:     
andre@0:     PKIX_ENTER(CERTVFYPKIX, "cert_CreatePkixProcessingParams");
andre@0:     PKIX_NULLCHECK_TWO(cert, pprocParams);
andre@0:  
andre@0:     PKIX_CHECK(
andre@0:         PKIX_PL_NssContext_Create(0, useArena, wincx, &plContext),
andre@0:         PKIX_NSSCONTEXTCREATEFAILED);
andre@0: 
andre@0:     *pplContext = plContext;
andre@0: 
andre@0: #ifdef PKIX_NOTDEF 
andre@0:     /* Functions should be implemented in patch for 390532 */
andre@0:     PKIX_CHECK(
andre@0:         pkix_pl_NssContext_SetCertSignatureCheck(checkSig,
andre@0:                                                  (PKIX_PL_NssContext*)plContext),
andre@0:         PKIX_NSSCONTEXTSETCERTSIGNCHECKFAILED);
andre@0: 
andre@0: #endif /* PKIX_NOTDEF */
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         PKIX_ProcessingParams_Create(&procParams, plContext),
andre@0:         PKIX_PROCESSINGPARAMSCREATEFAILED);
andre@0:     
andre@0:     PKIX_CHECK(
andre@0:         PKIX_ComCertSelParams_Create(&certSelParams, plContext),
andre@0:         PKIX_COMCERTSELPARAMSCREATEFAILED);
andre@0:     
andre@0:     PKIX_CHECK(
andre@0:         PKIX_PL_Cert_CreateFromCERTCertificate(cert, &targetCert, plContext),
andre@0:         PKIX_CERTCREATEWITHNSSCERTFAILED);
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         PKIX_ComCertSelParams_SetCertificate(certSelParams,
andre@0:                                              targetCert, plContext),
andre@0:         PKIX_COMCERTSELPARAMSSETCERTIFICATEFAILED);
andre@0:     
andre@0:     PKIX_CHECK(
andre@0:         PKIX_CertSelector_Create(NULL, NULL, &certSelector, plContext),
andre@0:         PKIX_COULDNOTCREATECERTSELECTOROBJECT);
andre@0:     
andre@0:     PKIX_CHECK(
andre@0:         PKIX_CertSelector_SetCommonCertSelectorParams(certSelector,
andre@0:                                                       certSelParams, plContext),
andre@0:         PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED);
andre@0:     
andre@0:     PKIX_CHECK(
andre@0:         PKIX_ProcessingParams_SetTargetCertConstraints(procParams,
andre@0:                                                        certSelector, plContext),
andre@0:         PKIX_PROCESSINGPARAMSSETTARGETCERTCONSTRAINTSFAILED);
andre@0: 
andre@0:     /* Turn off quialification of target cert since leaf cert is
andre@0:      * already check for date validity, key usages and extended
andre@0:      * key usages. */
andre@0:     PKIX_CHECK(
andre@0:         PKIX_ProcessingParams_SetQualifyTargetCert(procParams, PKIX_FALSE,
andre@0:                                                    plContext),
andre@0:         PKIX_PROCESSINGPARAMSSETQUALIFYTARGETCERTFLAGFAILED);
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         PKIX_PL_Pk11CertStore_Create(&certStore, plContext),
andre@0:         PKIX_PK11CERTSTORECREATEFAILED);
andre@0:     
andre@0:     PKIX_CHECK(
andre@0:         PKIX_List_Create(&certStores, plContext),
andre@0:         PKIX_UNABLETOCREATELIST);
andre@0:     
andre@0:     PKIX_CHECK(
andre@0:         PKIX_List_AppendItem(certStores, (PKIX_PL_Object *)certStore,
andre@0:                              plContext),
andre@0:         PKIX_LISTAPPENDITEMFAILED);
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         PKIX_ProcessingParams_SetCertStores(procParams, certStores,
andre@0:                                             plContext),
andre@0:         PKIX_PROCESSINGPARAMSADDCERTSTOREFAILED);
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         PKIX_PL_Date_CreateFromPRTime(time, &date, plContext),
andre@0:         PKIX_DATECREATEFROMPRTIMEFAILED);
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         PKIX_ProcessingParams_SetDate(procParams, date, plContext),
andre@0:         PKIX_PROCESSINGPARAMSSETDATEFAILED);
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         PKIX_RevocationChecker_Create(
andre@0:                                   PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST |
andre@0:                                   PKIX_REV_MI_NO_OVERALL_INFO_REQUIREMENT,
andre@0:                                   PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST |
andre@0:                                   PKIX_REV_MI_NO_OVERALL_INFO_REQUIREMENT,
andre@0:                                   &revChecker, plContext),
andre@0:         PKIX_REVOCATIONCHECKERCREATEFAILED);
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         PKIX_ProcessingParams_SetRevocationChecker(procParams, revChecker,
andre@0:                                                    plContext),
andre@0:         PKIX_PROCESSINGPARAMSSETREVOCATIONCHECKERFAILED);
andre@0: 
andre@0:     /* CRL method flags */
andre@0:     methodFlags = 
andre@0:         PKIX_REV_M_TEST_USING_THIS_METHOD |
andre@0:         PKIX_REV_M_FORBID_NETWORK_FETCHING |
andre@0:         PKIX_REV_M_SKIP_TEST_ON_MISSING_SOURCE |   /* 0 */
andre@0:         PKIX_REV_M_IGNORE_MISSING_FRESH_INFO |     /* 0 */
andre@0:         PKIX_REV_M_CONTINUE_TESTING_ON_FRESH_INFO;
andre@0: 
andre@0:     /* add CRL revocation method to check the leaf certificate */
andre@0:     PKIX_CHECK(
andre@0:         PKIX_RevocationChecker_CreateAndAddMethod(revChecker, procParams,
andre@0:                                          PKIX_RevocationMethod_CRL, methodFlags,
andre@0:                                          0, NULL, PKIX_TRUE, plContext),
andre@0:         PKIX_REVOCATIONCHECKERADDMETHODFAILED);
andre@0: 
andre@0:     /* add CRL revocation method for other certs in the chain. */
andre@0:     PKIX_CHECK(
andre@0:         PKIX_RevocationChecker_CreateAndAddMethod(revChecker, procParams,
andre@0:                                          PKIX_RevocationMethod_CRL, methodFlags,
andre@0:                                          0, NULL, PKIX_FALSE, plContext),
andre@0:         PKIX_REVOCATIONCHECKERADDMETHODFAILED);
andre@0:     
andre@0:     /* For compatibility with the old code, need to check that
andre@0:      * statusConfig is set in the db handle and status checker
andre@0:      * is defined befor allow ocsp status check on the leaf cert.*/
andre@0:     statusConfig = CERT_GetStatusConfig(CERT_GetDefaultCertDB());
andre@0:     if (statusConfig != NULL && statusConfig->statusChecker != NULL) {
andre@0: 
andre@0:         /* Enable OCSP revocation checking for the leaf cert. */
andre@0:         /* OCSP method flags */
andre@0:         methodFlags =
andre@0:             PKIX_REV_M_TEST_USING_THIS_METHOD |
andre@0:             PKIX_REV_M_ALLOW_NETWORK_FETCHING |         /* 0 */
andre@0:             PKIX_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE |  /* 0 */
andre@0:             PKIX_REV_M_SKIP_TEST_ON_MISSING_SOURCE |    /* 0 */
andre@0:             PKIX_REV_M_IGNORE_MISSING_FRESH_INFO |      /* 0 */
andre@0:             PKIX_REV_M_CONTINUE_TESTING_ON_FRESH_INFO;
andre@0:         
andre@0:         /* Disabling ocsp fetching when checking the status
andre@0:          * of ocsp response signer. Here and in the next if,
andre@0:          * adjust flags for ocsp signer cert validation case. */
andre@0:         if (disableOCSPRemoteFetching) {
andre@0:             methodFlags |= PKIX_REV_M_FORBID_NETWORK_FETCHING;
andre@0:         }
andre@0:         
andre@0:         if (ocsp_FetchingFailureIsVerificationFailure()
andre@0:             && !disableOCSPRemoteFetching) {
andre@0:             methodFlags |=
andre@0:                 PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO;
andre@0:         }
andre@0:         
andre@0:         /* add OCSP revocation method to check only the leaf certificate.*/
andre@0:         PKIX_CHECK(
andre@0:             PKIX_RevocationChecker_CreateAndAddMethod(revChecker, procParams,
andre@0:                                      PKIX_RevocationMethod_OCSP, methodFlags,
andre@0:                                      1, NULL, PKIX_TRUE, plContext),
andre@0:             PKIX_REVOCATIONCHECKERADDMETHODFAILED);
andre@0:     }
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         PKIX_ProcessingParams_SetAnyPolicyInhibited(procParams, PR_FALSE,
andre@0:                                                     plContext),
andre@0:         PKIX_PROCESSINGPARAMSSETANYPOLICYINHIBITED);
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         PKIX_ProcessingParams_SetExplicitPolicyRequired(procParams, PR_FALSE,
andre@0:                                                        plContext),
andre@0:         PKIX_PROCESSINGPARAMSSETEXPLICITPOLICYREQUIRED);
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         PKIX_ProcessingParams_SetPolicyMappingInhibited(procParams, PR_FALSE,
andre@0:                                                         plContext),
andre@0:         PKIX_PROCESSINGPARAMSSETPOLICYMAPPINGINHIBITED);
andre@0:  
andre@0:     *pprocParams = procParams;
andre@0:     procParams = NULL;
andre@0: 
andre@0: cleanup:
andre@0:     PKIX_DECREF(anchors);
andre@0:     PKIX_DECREF(targetCert);
andre@0:     PKIX_DECREF(date);
andre@0:     PKIX_DECREF(certSelector);
andre@0:     PKIX_DECREF(certSelParams);
andre@0:     PKIX_DECREF(certStore);
andre@0:     PKIX_DECREF(certStores);
andre@0:     PKIX_DECREF(procParams);
andre@0:     PKIX_DECREF(revChecker);
andre@0: 
andre@0:     PKIX_RETURN(CERTVFYPKIX);
andre@0: }
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: cert_PkixToNssCertsChain
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  * Converts pkix cert list into nss cert list.
andre@0:  * 
andre@0:  * PARAMETERS:
andre@0:  *  "pkixCertChain"
andre@0:  *      Pkix certificate list.     
andre@0:  *  "pvalidChain"
andre@0:  *      An address of returned nss certificate list.
andre@0:  *  "plContext"
andre@0:  *      Platform-specific context pointer.
andre@0:  * THREAD SAFETY:
andre@0:  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
andre@0:  * RETURNS:
andre@0:  *  Returns NULL if the function succeeds.
andre@0:  *  Returns a Cert Verify Error if the function fails in an unrecoverable way.
andre@0:  *  Returns a Fatal Error if the function fails in an unrecoverable way.
andre@0:  */
andre@0: static PKIX_Error*
andre@0: cert_PkixToNssCertsChain(
andre@0:     PKIX_List *pkixCertChain, 
andre@0:     CERTCertList **pvalidChain, 
andre@0:     void *plContext)
andre@0: {
andre@0:     PLArenaPool     *arena = NULL;
andre@0:     CERTCertificate *nssCert = NULL;
andre@0:     CERTCertList    *validChain = NULL;
andre@0:     PKIX_PL_Object  *certItem = NULL;
andre@0:     PKIX_UInt32      length = 0;
andre@0:     PKIX_UInt32      i = 0;
andre@0: 
andre@0:     PKIX_ENTER(CERTVFYPKIX, "cert_PkixToNssCertsChain");
andre@0:     PKIX_NULLCHECK_ONE(pvalidChain);
andre@0: 
andre@0:     if (pkixCertChain == NULL) {
andre@0:         goto cleanup;
andre@0:     }
andre@0:     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
andre@0:     if (arena == NULL) {
andre@0:         PKIX_ERROR(PKIX_OUTOFMEMORY);
andre@0:     }
andre@0:     validChain = (CERTCertList*)PORT_ArenaZAlloc(arena, sizeof(CERTCertList));
andre@0:     if (validChain == NULL) {
andre@0:         PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
andre@0:     }
andre@0:     PR_INIT_CLIST(&validChain->list);
andre@0:     validChain->arena = arena;
andre@0:     arena = NULL;
andre@0: 
andre@0:     PKIX_CHECK(
andre@0:         PKIX_List_GetLength(pkixCertChain, &length, plContext),
andre@0:         PKIX_LISTGETLENGTHFAILED);
andre@0: 
andre@0:     for (i = 0; i < length; i++){
andre@0:         CERTCertListNode *node = NULL;
andre@0: 
andre@0:         PKIX_CHECK(
andre@0:             PKIX_List_GetItem(pkixCertChain, i, &certItem, plContext),
andre@0:             PKIX_LISTGETITEMFAILED);
andre@0:         
andre@0:         PKIX_CHECK(
andre@0:             PKIX_PL_Cert_GetCERTCertificate((PKIX_PL_Cert*)certItem, &nssCert,
andre@0:                                     plContext),
andre@0:             PKIX_CERTGETCERTCERTIFICATEFAILED);
andre@0:         
andre@0:         node =
andre@0:             (CERTCertListNode *)PORT_ArenaZAlloc(validChain->arena,
andre@0:                                                  sizeof(CERTCertListNode));
andre@0:         if ( node == NULL ) {
andre@0:             PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
andre@0:         }
andre@0: 
andre@0:         PR_INSERT_BEFORE(&node->links, &validChain->list);
andre@0: 
andre@0:         node->cert = nssCert;
andre@0:         nssCert = NULL;
andre@0: 
andre@0:         PKIX_DECREF(certItem);
andre@0:     }
andre@0: 
andre@0:     *pvalidChain = validChain;
andre@0: 
andre@0: cleanup:
andre@0:     if (PKIX_ERROR_RECEIVED){
andre@0:         if (validChain) {
andre@0:             CERT_DestroyCertList(validChain);
andre@0:         } else if (arena) {
andre@0:             PORT_FreeArena(arena, PR_FALSE);
andre@0:         }
andre@0:         if (nssCert) {
andre@0:             CERT_DestroyCertificate(nssCert);
andre@0:         }
andre@0:     }
andre@0:     PKIX_DECREF(certItem);
andre@0: 
andre@0:     PKIX_RETURN(CERTVFYPKIX);
andre@0: }
andre@0: 
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: cert_BuildAndValidateChain
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  * The function builds and validates a cert chain based on certificate
andre@0:  * selection criterias from procParams. This function call PKIX_BuildChain
andre@0:  * to accomplish chain building. If PKIX_BuildChain returns with incomplete
andre@0:  * IO, the function waits with PR_Poll until the blocking IO is finished and
andre@0:  * return control back to PKIX_BuildChain.
andre@0:  *
andre@0:  * PARAMETERS:
andre@0:  *  "procParams"
andre@0:  *      Processing parameters to be used during chain building.
andre@0:  *  "pResult"
andre@0:  *      Returned build result.
andre@0:  *  "pVerifyNode"
andre@0:  *      Returned pointed to verify node structure: the tree-like structure
andre@0:  *      that reports points of chain building failures.
andre@0:  *  "plContext"
andre@0:  *      Platform-specific context pointer.
andre@0:  * THREAD SAFETY:
andre@0:  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
andre@0:  * RETURNS:
andre@0:  *  Returns NULL if the function succeeds.
andre@0:  *  Returns a Cert Verify Error if the function fails in an unrecoverable way.
andre@0:  *  Returns a Fatal Error if the function fails in an unrecoverable way.
andre@0:  */
andre@0: static PKIX_Error*
andre@0: cert_BuildAndValidateChain(
andre@0:     PKIX_ProcessingParams *procParams,
andre@0:     PKIX_BuildResult **pResult,
andre@0:     PKIX_VerifyNode **pVerifyNode,
andre@0:     void *plContext)
andre@0: {
andre@0:     PKIX_BuildResult *result = NULL;
andre@0:     PKIX_VerifyNode  *verifyNode = NULL;
andre@0:     void             *nbioContext = NULL;
andre@0:     void             *state = NULL;
andre@0:     
andre@0:     PKIX_ENTER(CERTVFYPKIX, "cert_BuildAndVerifyChain");
andre@0:     PKIX_NULLCHECK_TWO(procParams, pResult);
andre@0:  
andre@0:     do {
andre@0:         if (nbioContext && state) {
andre@0:             /* PKIX-XXX: need to test functionality of NBIO handling in libPkix.
andre@0:              * See bug 391180 */
andre@0:             PRInt32 filesReady = 0;
andre@0:             PRPollDesc *pollDesc = (PRPollDesc*)nbioContext;
andre@0:             filesReady = PR_Poll(pollDesc, 1, PR_INTERVAL_NO_TIMEOUT);
andre@0:             if (filesReady <= 0) {
andre@0:                 PKIX_ERROR(PKIX_PRPOLLRETBADFILENUM);
andre@0:             }
andre@0:         }
andre@0: 
andre@0:         PKIX_CHECK(
andre@0:             PKIX_BuildChain(procParams, &nbioContext, &state,
andre@0:                             &result, &verifyNode, plContext),
andre@0:             PKIX_UNABLETOBUILDCHAIN);
andre@0:         
andre@0:     } while (nbioContext && state);
andre@0: 
andre@0:     *pResult = result;
andre@0: 
andre@0: cleanup:
andre@0:     if (pVerifyNode) {
andre@0:         *pVerifyNode = verifyNode;
andre@0:     }
andre@0: 
andre@0:     PKIX_RETURN(CERTVFYPKIX);
andre@0: }
andre@0: 
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: cert_PkixErrorToNssCode
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  * Converts pkix error(PKIX_Error) structure to PR error codes.
andre@0:  *
andre@0:  * PKIX-XXX to be implemented. See 391183.
andre@0:  *
andre@0:  * PARAMETERS:
andre@0:  *  "error"
andre@0:  *      Pkix error that will be converted.
andre@0:  *  "nssCode"
andre@0:  *      Corresponding nss error code.
andre@0:  *  "plContext"
andre@0:  *      Platform-specific context pointer.
andre@0:  * THREAD SAFETY:
andre@0:  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
andre@0:  * RETURNS:
andre@0:  *  Returns NULL if the function succeeds.
andre@0:  *  Returns a Cert Verify Error if the function fails in an unrecoverable way.
andre@0:  *  Returns a Fatal Error if the function fails in an unrecoverable way.
andre@0:  */
andre@0: static PKIX_Error *
andre@0: cert_PkixErrorToNssCode(
andre@0:     PKIX_Error *error,
andre@0:     SECErrorCodes *pNssErr,
andre@0:     void *plContext)
andre@0: {
andre@0:     int errLevel = 0;
andre@0:     PKIX_Int32 nssErr = 0;
andre@0:     PKIX_Error *errPtr = error;
andre@0: 
andre@0:     PKIX_ENTER(CERTVFYPKIX, "cert_PkixErrorToNssCode");
andre@0:     PKIX_NULLCHECK_TWO(error, pNssErr);
andre@0:     
andre@0:     /* Loop until we find at least one error with non-null
andre@0:      * plErr code, that is going to be nss error code. */
andre@0:     while (errPtr) {
andre@0:         if (errPtr->plErr && !nssErr) {
andre@0:             nssErr = errPtr->plErr;
andre@0:             if (!pkixLog) break;
andre@0:         }
andre@0:         if (pkixLog) {
andre@0: #ifdef PKIX_ERROR_DESCRIPTION            
andre@0:             PR_LOG(pkixLog, 2, ("Error at level %d: %s\n", errLevel,
andre@0:                                 PKIX_ErrorText[errPtr->errCode]));
andre@0: #else
andre@0:             PR_LOG(pkixLog, 2, ("Error at level %d: Error code %d\n", errLevel,
andre@0:                                 errPtr->errCode));
andre@0: #endif /* PKIX_ERROR_DESCRIPTION */
andre@0:         }
andre@0:         errPtr = errPtr->cause;
andre@0:         errLevel += 1; 
andre@0:     }
andre@0:     PORT_Assert(nssErr);
andre@0:     if (!nssErr) {
andre@0:         *pNssErr = SEC_ERROR_LIBPKIX_INTERNAL;
andre@0:     } else {
andre@0:         *pNssErr = nssErr;
andre@0:     }
andre@0: 
andre@0:     PKIX_RETURN(CERTVFYPKIX);
andre@0: }
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: cert_GetLogFromVerifyNode
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  * Recursive function that converts verify node tree-like set of structures
andre@0:  * to CERTVerifyLog.
andre@0:  *
andre@0:  * PARAMETERS:
andre@0:  *  "log"
andre@0:  *      Pointed to already allocated CERTVerifyLog structure. 
andre@0:  *  "node"
andre@0:  *      A node of PKIX_VerifyNode tree.
andre@0:  *  "plContext"
andre@0:  *      Platform-specific context pointer.
andre@0:  * THREAD SAFETY:
andre@0:  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
andre@0:  * RETURNS:
andre@0:  *  Returns NULL if the function succeeds.
andre@0:  *  Returns a Cert Verify Error if the function fails in an unrecoverable way.
andre@0:  *  Returns a Fatal Error if the function fails in an unrecoverable way.
andre@0:  */
andre@0: static PKIX_Error *
andre@0: cert_GetLogFromVerifyNode(
andre@0:     CERTVerifyLog *log,
andre@0:     PKIX_VerifyNode *node,
andre@0:     void *plContext)
andre@0: {
andre@0:     PKIX_List       *children = NULL;
andre@0:     PKIX_VerifyNode *childNode = NULL;
andre@0: 
andre@0:     PKIX_ENTER(CERTVFYPKIX, "cert_GetLogFromVerifyNode");
andre@0: 
andre@0:     children = node->children;
andre@0: 
andre@0:     if (children == NULL) {
andre@0:         PKIX_ERRORCODE errCode = PKIX_ANCHORDIDNOTCHAINTOCERT;
andre@0:         if (node->error && node->error->errCode != errCode) {
andre@0: #ifdef DEBUG_volkov
andre@0:             char *string = pkix_Error2ASCII(node->error, plContext);
andre@0:             fprintf(stderr, "Branch search finished with error: \t%s\n", string);
andre@0:             PKIX_PL_Free(string, NULL);
andre@0: #endif
andre@0:             if (log != NULL) {
andre@0:                 SECErrorCodes nssErrorCode = 0;
andre@0:                 CERTCertificate *cert = NULL;
andre@0: 
andre@0:                 cert = node->verifyCert->nssCert;
andre@0: 
andre@0:                 PKIX_CHECK(
andre@0:                     cert_PkixErrorToNssCode(node->error, &nssErrorCode,
andre@0:                                             plContext),
andre@0:                     PKIX_GETPKIXERRORCODEFAILED);
andre@0:                 
andre@0:                 cert_AddToVerifyLog(log, cert, nssErrorCode, node->depth, NULL);
andre@0:             }
andre@0:         }
andre@0:         PKIX_RETURN(CERTVFYPKIX);
andre@0:     } else {
andre@0:         PRUint32      i = 0;
andre@0:         PKIX_UInt32   length = 0;
andre@0: 
andre@0:         PKIX_CHECK(
andre@0:             PKIX_List_GetLength(children, &length, plContext),
andre@0:             PKIX_LISTGETLENGTHFAILED);
andre@0:         
andre@0:         for (i = 0; i < length; i++){
andre@0: 
andre@0:             PKIX_CHECK(
andre@0:                 PKIX_List_GetItem(children, i, (PKIX_PL_Object**)&childNode,
andre@0:                                   plContext),
andre@0:                 PKIX_LISTGETITEMFAILED);
andre@0:             
andre@0:             PKIX_CHECK(
andre@0:                 cert_GetLogFromVerifyNode(log, childNode, plContext),
andre@0:                 PKIX_ERRORINRECURSIVEEQUALSCALL);
andre@0: 
andre@0:             PKIX_DECREF(childNode);
andre@0:         }
andre@0:     }
andre@0: 
andre@0: cleanup:
andre@0:     PKIX_DECREF(childNode);
andre@0: 
andre@0:     PKIX_RETURN(CERTVFYPKIX);
andre@0: }
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: cert_GetBuildResults
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  * Converts pkix build results to nss results. This function is called
andre@0:  * regardless of build result.
andre@0:  *
andre@0:  * If it called after chain was successfully constructed, then it will
andre@0:  * convert:
andre@0:  *   * pkix cert list that represent the chain to nss cert list
andre@0:  *   * trusted root the chain was anchored to nss certificate.
andre@0:  *
andre@0:  * In case of failure it will convert:
andre@0:  *   * pkix error to PR error code(will set it with PORT_SetError)
andre@0:  *   * pkix validation log to nss CERTVerifyLog
andre@0:  *   
andre@0:  * PARAMETERS:
andre@0:  *  "buildResult"
andre@0:  *      Build results returned by PKIX_BuildChain.
andre@0:  *  "verifyNode"
andre@0:  *      Tree-like structure of chain building/validation failures
andre@0:  *      returned by PKIX_BuildChain. Ignored in case of success.
andre@0:  *  "error"
andre@0:  *      Final error returned by PKIX_BuildChain. Should be NULL in
andre@0:  *      case of success.
andre@0:  *  "log"
andre@0:  *      Address of pre-allocated(if not NULL) CERTVerifyLog structure.
andre@0:  *  "ptrustedRoot"
andre@0:  *      Address of returned trusted root the chain was anchored to.
andre@0:  *  "pvalidChain"
andre@0:  *      Address of returned valid chain.
andre@0:  *  "plContext"
andre@0:  *      Platform-specific context pointer.
andre@0:  * THREAD SAFETY:
andre@0:  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
andre@0:  * RETURNS:
andre@0:  *  Returns NULL if the function succeeds.
andre@0:  *  Returns a Cert Verify Error if the function fails in an unrecoverable way.
andre@0:  *  Returns a Fatal Error if the function fails in an unrecoverable way.
andre@0:  */
andre@0: static PKIX_Error*
andre@0: cert_GetBuildResults(
andre@0:     PKIX_BuildResult *buildResult,
andre@0:     PKIX_VerifyNode  *verifyNode,
andre@0:     PKIX_Error       *error,
andre@0:     CERTVerifyLog    *log,
andre@0:     CERTCertificate **ptrustedRoot,
andre@0:     CERTCertList    **pvalidChain,
andre@0:     void             *plContext)
andre@0: {
andre@0:     PKIX_ValidateResult *validResult = NULL;
andre@0:     CERTCertList        *validChain = NULL;
andre@0:     CERTCertificate     *trustedRoot = NULL;
andre@0:     PKIX_TrustAnchor    *trustAnchor = NULL;
andre@0:     PKIX_PL_Cert        *trustedCert = NULL;
andre@0:     PKIX_List           *pkixCertChain = NULL;
andre@0: #ifdef DEBUG_volkov
andre@0:     PKIX_Error          *tmpPkixError = NULL;
andre@0: #endif /* DEBUG */
andre@0:             
andre@0:     PKIX_ENTER(CERTVFYPKIX, "cert_GetBuildResults");
andre@0:     if (buildResult == NULL && error == NULL) {
andre@0:         PKIX_ERROR(PKIX_NULLARGUMENT);
andre@0:     }
andre@0: 
andre@0:     if (error) {
andre@0:         SECErrorCodes nssErrorCode = 0;
andre@0: #ifdef DEBUG_volkov        
andre@0:         char *temp = pkix_Error2ASCII(error, plContext);
andre@0:         fprintf(stderr, "BUILD ERROR:\n%s\n", temp);
andre@0:         PKIX_PL_Free(temp, NULL);
andre@0: #endif /* DEBUG */
andre@0:         if (verifyNode) {
andre@0:             PKIX_Error *tmpError =
andre@0:                 cert_GetLogFromVerifyNode(log, verifyNode, plContext);
andre@0:             if (tmpError) {
andre@0:                 PKIX_PL_Object_DecRef((PKIX_PL_Object *)tmpError, plContext);
andre@0:             }
andre@0:         }
andre@0:         cert_PkixErrorToNssCode(error, &nssErrorCode, plContext);
andre@0:         PORT_SetError(nssErrorCode);
andre@0:         goto cleanup;
andre@0:     }
andre@0: 
andre@0:     if (pvalidChain) {
andre@0:         PKIX_CHECK(
andre@0:             PKIX_BuildResult_GetCertChain(buildResult, &pkixCertChain,
andre@0:                                           plContext),
andre@0:             PKIX_BUILDRESULTGETCERTCHAINFAILED);
andre@0: 
andre@0: #ifdef DEBUG_volkov
andre@0:         tmpPkixError = cert_PrintCertChain(pkixCertChain, plContext);
andre@0:         if (tmpPkixError) {
andre@0:             PKIX_PL_Object_DecRef((PKIX_PL_Object*)tmpPkixError, plContext);
andre@0:         }
andre@0: #endif        
andre@0: 
andre@0:         PKIX_CHECK(
andre@0:             cert_PkixToNssCertsChain(pkixCertChain, &validChain, plContext),
andre@0:             PKIX_CERTCHAINTONSSCHAINFAILED);
andre@0:     }
andre@0: 
andre@0:     if (ptrustedRoot) {
andre@0:         PKIX_CHECK(
andre@0:             PKIX_BuildResult_GetValidateResult(buildResult, &validResult,
andre@0:                                                plContext),
andre@0:             PKIX_BUILDRESULTGETVALIDATERESULTFAILED);
andre@0: 
andre@0:         PKIX_CHECK(
andre@0:             PKIX_ValidateResult_GetTrustAnchor(validResult, &trustAnchor,
andre@0:                                                plContext),
andre@0:             PKIX_VALIDATERESULTGETTRUSTANCHORFAILED);
andre@0: 
andre@0:         PKIX_CHECK(
andre@0:             PKIX_TrustAnchor_GetTrustedCert(trustAnchor, &trustedCert,
andre@0:                                             plContext),
andre@0:             PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED);
andre@0: 
andre@0: #ifdef DEBUG_volkov
andre@0:         if (pvalidChain == NULL) {
andre@0:             cert_PrintCert(trustedCert, plContext);
andre@0:         }
andre@0: #endif        
andre@0: 
andre@0:        PKIX_CHECK(
andre@0:             PKIX_PL_Cert_GetCERTCertificate(trustedCert, &trustedRoot,
andre@0:                                             plContext),
andre@0:             PKIX_CERTGETCERTCERTIFICATEFAILED);
andre@0:     }
andre@0:  
andre@0:     PORT_Assert(!PKIX_ERROR_RECEIVED);
andre@0: 
andre@0:     if (trustedRoot) {
andre@0:         *ptrustedRoot = trustedRoot;
andre@0:     }
andre@0:     if (validChain) {
andre@0:         *pvalidChain = validChain;
andre@0:     }
andre@0: 
andre@0: cleanup:
andre@0:     if (PKIX_ERROR_RECEIVED) {
andre@0:         if (trustedRoot) {
andre@0:             CERT_DestroyCertificate(trustedRoot);
andre@0:         }
andre@0:         if (validChain) {
andre@0:             CERT_DestroyCertList(validChain);
andre@0:         }
andre@0:     }
andre@0:     PKIX_DECREF(trustAnchor);
andre@0:     PKIX_DECREF(trustedCert);
andre@0:     PKIX_DECREF(pkixCertChain);
andre@0:     PKIX_DECREF(validResult);
andre@0:     PKIX_DECREF(error);
andre@0:     PKIX_DECREF(verifyNode);
andre@0:     PKIX_DECREF(buildResult);
andre@0:     
andre@0:     PKIX_RETURN(CERTVFYPKIX);
andre@0: }
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: cert_VerifyCertChainPkix
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  * The main wrapper function that is called from CERT_VerifyCert and
andre@0:  * CERT_VerifyCACertForUsage functions to validate cert with libpkix.
andre@0:  *
andre@0:  * PARAMETERS:
andre@0:  *  "cert"
andre@0:  *      Leaf certificate of a chain we want to build.
andre@0:  *  "checkSig"
andre@0:  *      Certificate signatures will not be verified if this
andre@0:  *      flag is set to PR_FALSE.
andre@0:  *  "requiredUsage"
andre@0:  *      Required usage for certificate and chain.
andre@0:  *  "time"
andre@0:  *      Validity time.
andre@0:  *  "wincx"
andre@0:  *      Nss database password token.
andre@0:  *  "log"
andre@0:  *      Address of already allocated CERTVerifyLog structure. Not
andre@0:  *      used if NULL;
andre@0:  *  "pSigerror"
andre@0:  *      Address of PRBool. If not NULL, returns true is cert chain
andre@0:  *      was invalidated because of bad certificate signature.
andre@0:  *  "pRevoked"
andre@0:  *      Address of PRBool. If not NULL, returns true is cert chain
andre@0:  *      was invalidated because a revoked certificate was found in
andre@0:  *      the chain.
andre@0:  * THREAD SAFETY:
andre@0:  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
andre@0:  * RETURNS:
andre@0:  *  SECFailure is chain building process has failed. SECSuccess otherwise.
andre@0:  */
andre@0: SECStatus
andre@0: cert_VerifyCertChainPkix(
andre@0:     CERTCertificate *cert,
andre@0:     PRBool           checkSig,
andre@0:     SECCertUsage     requiredUsage,
andre@0:     PRTime           time,
andre@0:     void            *wincx,
andre@0:     CERTVerifyLog   *log,
andre@0:     PRBool          *pSigerror,
andre@0:     PRBool          *pRevoked)
andre@0: {
andre@0:     PKIX_ProcessingParams *procParams = NULL;
andre@0:     PKIX_BuildResult      *result = NULL;
andre@0:     PKIX_VerifyNode       *verifyNode = NULL;
andre@0:     PKIX_Error            *error = NULL;
andre@0: 
andre@0:     SECStatus              rv = SECFailure;
andre@0:     void                  *plContext = NULL;
andre@0: #ifdef DEBUG_volkov
andre@0:     CERTCertificate       *trustedRoot = NULL;
andre@0:     CERTCertList          *validChain = NULL;
andre@0: #endif /* DEBUG */
andre@0: 
andre@0: #ifdef PKIX_OBJECT_LEAK_TEST
andre@0:     int  leakedObjNum = 0;
andre@0:     int  memLeakLoopCount = 0;
andre@0:     int  objCountTable[PKIX_NUMTYPES]; 
andre@0:     int  fnInvLocalCount = 0;
andre@0:     PKIX_Boolean savedUsePkixEngFlag = usePKIXValidationEngine;
andre@0: 
andre@0:     if (usePKIXValidationEngine) {
andre@0:         /* current memory leak testing implementation does not allow
andre@0:          * to run simultaneous tests one the same or a different threads.
andre@0:          * Setting the variable to false, to make additional chain
andre@0:          * validations be handled by old nss. */
andre@0:         usePKIXValidationEngine = PR_FALSE;
andre@0:     }
andre@0:     testStartFnStackPosition = 2;
andre@0:     fnStackNameArr[0] = "cert_VerifyCertChainPkix";
andre@0:     fnStackInvCountArr[0] = 0;
andre@0:     PKIX_Boolean abortOnLeak = 
andre@0:         (PR_GetEnv("PKIX_OBJECT_LEAK_TEST_ABORT_ON_LEAK") == NULL) ?
andre@0:                                                    PKIX_FALSE : PKIX_TRUE;
andre@0:     runningLeakTest = PKIX_TRUE;
andre@0: 
andre@0:     /* Prevent multi-threaded run of object leak test */
andre@0:     fnInvLocalCount = PR_ATOMIC_INCREMENT(&parallelFnInvocationCount);
andre@0:     PORT_Assert(fnInvLocalCount == 1);
andre@0: 
andre@0: do {
andre@0:     rv = SECFailure;
andre@0:     plContext = NULL;
andre@0:     procParams = NULL;
andre@0:     result = NULL;
andre@0:     verifyNode = NULL;
andre@0:     error = NULL;
andre@0: #ifdef DEBUG_volkov
andre@0:     trustedRoot = NULL;
andre@0:     validChain = NULL;
andre@0: #endif /* DEBUG */
andre@0:     errorGenerated = PKIX_FALSE;
andre@0:     stackPosition = 0;
andre@0: 
andre@0:     if (leakedObjNum) {
andre@0:         pkix_pl_lifecycle_ObjectTableUpdate(objCountTable); 
andre@0:     }
andre@0:     memLeakLoopCount += 1;
andre@0: #endif /* PKIX_OBJECT_LEAK_TEST */
andre@0: 
andre@0:     error =
andre@0:         cert_CreatePkixProcessingParams(cert, checkSig, time, wincx,
andre@0:                                     PR_FALSE/*use arena*/,
andre@0:                                     requiredUsage == certUsageStatusResponder,
andre@0:                                     &procParams, &plContext);
andre@0:     if (error) {
andre@0:         goto cleanup;
andre@0:     }
andre@0: 
andre@0:     error =
andre@0:         cert_ProcessingParamsSetKeyAndCertUsage(procParams, requiredUsage, 0,
andre@0:                                                 plContext);
andre@0:     if (error) {
andre@0:         goto cleanup;
andre@0:     }
andre@0: 
andre@0:     error = 
andre@0:         cert_BuildAndValidateChain(procParams, &result, &verifyNode, plContext);
andre@0:     if (error) {
andre@0:         goto cleanup;
andre@0:     }
andre@0:     
andre@0:     if (pRevoked) {
andre@0:         /* Currently always PR_FALSE. Will be fixed as a part of 394077 */
andre@0:         *pRevoked = PR_FALSE;
andre@0:     }
andre@0:     if (pSigerror) {
andre@0:         /* Currently always PR_FALSE. Will be fixed as a part of 394077 */
andre@0:         *pSigerror = PR_FALSE;
andre@0:     }
andre@0:     rv = SECSuccess;
andre@0: 
andre@0: cleanup:
andre@0:     error = cert_GetBuildResults(result, verifyNode, error, log,
andre@0: #ifdef DEBUG_volkov                                 
andre@0:                                  &trustedRoot, &validChain,
andre@0: #else
andre@0:                                  NULL, NULL,
andre@0: #endif /* DEBUG */
andre@0:                                  plContext);
andre@0:     if (error) {
andre@0: #ifdef DEBUG_volkov        
andre@0:         char *temp = pkix_Error2ASCII(error, plContext);
andre@0:         fprintf(stderr, "GET BUILD RES ERRORS:\n%s\n", temp);
andre@0:         PKIX_PL_Free(temp, NULL);
andre@0: #endif /* DEBUG */
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)error, plContext);
andre@0:     }
andre@0: #ifdef DEBUG_volkov
andre@0:     if (trustedRoot) {
andre@0:         CERT_DestroyCertificate(trustedRoot);
andre@0:     }
andre@0:     if (validChain) {
andre@0:         CERT_DestroyCertList(validChain);
andre@0:     }
andre@0: #endif /* DEBUG */
andre@0:     if (procParams) {
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)procParams, plContext);
andre@0:     }
andre@0:     if (plContext) {
andre@0:         PKIX_PL_NssContext_Destroy(plContext);
andre@0:     }
andre@0: 
andre@0: #ifdef PKIX_OBJECT_LEAK_TEST
andre@0:     leakedObjNum =
andre@0:         pkix_pl_lifecycle_ObjectLeakCheck(leakedObjNum ? objCountTable : NULL);
andre@0:     
andre@0:     if (pkixLog && leakedObjNum) {
andre@0:         PR_LOG(pkixLog, 1, ("The generated error caused an object leaks. Loop %d."
andre@0:                             "Stack %s\n", memLeakLoopCount, errorFnStackString));
andre@0:     }
andre@0:     PR_Free(errorFnStackString);
andre@0:     errorFnStackString = NULL;
andre@0:     if (abortOnLeak) {
andre@0:         PORT_Assert(leakedObjNum == 0);
andre@0:     }
andre@0: 
andre@0: } while (errorGenerated);
andre@0: 
andre@0:     runningLeakTest = PKIX_FALSE; 
andre@0:     PR_ATOMIC_DECREMENT(&parallelFnInvocationCount);
andre@0:     usePKIXValidationEngine = savedUsePkixEngFlag;
andre@0: #endif /* PKIX_OBJECT_LEAK_TEST */
andre@0: 
andre@0:     return rv;
andre@0: }
andre@0: 
andre@0: PKIX_CertSelector *
andre@0: cert_GetTargetCertConstraints(CERTCertificate *target, void *plContext) 
andre@0: {
andre@0:     PKIX_ComCertSelParams *certSelParams = NULL;
andre@0:     PKIX_CertSelector *certSelector = NULL;
andre@0:     PKIX_CertSelector *r= NULL;
andre@0:     PKIX_PL_Cert *eeCert = NULL;
andre@0:     PKIX_Error *error = NULL;
andre@0: 
andre@0:     error = PKIX_PL_Cert_CreateFromCERTCertificate(target, &eeCert, plContext);
andre@0:     if (error != NULL) goto cleanup;
andre@0: 
andre@0:     error = PKIX_CertSelector_Create(NULL, NULL, &certSelector, plContext);
andre@0:     if (error != NULL) goto cleanup;
andre@0: 
andre@0:     error = PKIX_ComCertSelParams_Create(&certSelParams, plContext);
andre@0:     if (error != NULL) goto cleanup;
andre@0: 
andre@0:     error = PKIX_ComCertSelParams_SetCertificate(
andre@0:                                 certSelParams, eeCert, plContext);
andre@0:     if (error != NULL) goto cleanup;
andre@0: 
andre@0:     error = PKIX_CertSelector_SetCommonCertSelectorParams
andre@0:         (certSelector, certSelParams, plContext);
andre@0:     if (error != NULL) goto cleanup;
andre@0: 
andre@0:     error = PKIX_PL_Object_IncRef((PKIX_PL_Object *)certSelector, plContext);
andre@0:     if (error == NULL) r = certSelector;
andre@0: 
andre@0: cleanup:
andre@0:     if (certSelParams != NULL) 
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)certSelParams, plContext);
andre@0: 
andre@0:     if (eeCert != NULL) 
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)eeCert, plContext);
andre@0: 
andre@0:     if (certSelector != NULL) 
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)certSelector, plContext);
andre@0: 
andre@0:     if (error != NULL) {
andre@0: 	SECErrorCodes nssErr;
andre@0: 
andre@0: 	cert_PkixErrorToNssCode(error, &nssErr, plContext);
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)error, plContext);
andre@0: 	PORT_SetError(nssErr);
andre@0:     }
andre@0: 
andre@0:     return r;
andre@0: }
andre@0: 
andre@0: static PKIX_List *
andre@0: cert_GetCertStores(void *plContext)
andre@0: {
andre@0:     PKIX_CertStore *certStore = NULL;
andre@0:     PKIX_List *certStores = NULL;
andre@0:     PKIX_List *r = NULL;
andre@0:     PKIX_Error *error = NULL;
andre@0: 
andre@0:     error = PKIX_PL_Pk11CertStore_Create(&certStore, plContext);
andre@0:     if (error != NULL) goto cleanup;
andre@0: 
andre@0:     error = PKIX_List_Create(&certStores, plContext);
andre@0:     if (error != NULL)  goto cleanup;
andre@0: 
andre@0:     error = PKIX_List_AppendItem( certStores, 
andre@0:                           (PKIX_PL_Object *)certStore, plContext);
andre@0:     if (error != NULL)  goto cleanup;
andre@0: 
andre@0:     error = PKIX_PL_Object_IncRef((PKIX_PL_Object *)certStores, plContext);
andre@0:     if (error == NULL) r = certStores;
andre@0: 
andre@0: cleanup:
andre@0:     if (certStores != NULL) 
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)certStores, plContext);
andre@0: 
andre@0:     if (certStore != NULL) 
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)certStore, plContext);
andre@0: 
andre@0:     if (error != NULL) {
andre@0: 	SECErrorCodes nssErr;
andre@0: 
andre@0: 	cert_PkixErrorToNssCode(error, &nssErr, plContext);
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)error, plContext);
andre@0: 	PORT_SetError(nssErr);
andre@0:     }
andre@0: 
andre@0:     return r;
andre@0: }
andre@0: 
andre@0: 
andre@0: struct fake_PKIX_PL_CertStruct {
andre@0:         CERTCertificate *nssCert;
andre@0: };
andre@0: 
andre@0: /* This needs to be part of the PKIX_PL_* */
andre@0: /* This definitely needs to go away, and be replaced with
andre@0:    a real accessor function in PKIX */
andre@0: static CERTCertificate *
andre@0: cert_NSSCertFromPKIXCert(const PKIX_PL_Cert *pkix_cert)
andre@0: {
andre@0:     struct fake_PKIX_PL_CertStruct *fcert = NULL;
andre@0: 
andre@0:     fcert = (struct fake_PKIX_PL_CertStruct*)pkix_cert;
andre@0: 
andre@0:     return CERT_DupCertificate(fcert->nssCert);
andre@0: }
andre@0: 
andre@0: PKIX_List *cert_PKIXMakeOIDList(const SECOidTag *oids, int oidCount, void *plContext)
andre@0: {
andre@0:     PKIX_List *r = NULL;
andre@0:     PKIX_List *policyList = NULL;
andre@0:     PKIX_PL_OID *policyOID = NULL;
andre@0:     PKIX_Error *error = NULL;
andre@0:     int i;
andre@0: 
andre@0:     error = PKIX_List_Create(&policyList, plContext);
andre@0:     if (error != NULL) {
andre@0: 	goto cleanup;
andre@0:     }
andre@0: 
andre@0:     for (i=0; i<oidCount; i++) {
andre@0:         error = PKIX_PL_OID_Create(oids[i], &policyOID, plContext);
andre@0:         if (error) {
andre@0:             goto cleanup;
andre@0:         }
andre@0:         error = PKIX_List_AppendItem(policyList, 
andre@0:                 (PKIX_PL_Object *)policyOID, plContext);
andre@0:         if (error != NULL) {
andre@0:             goto cleanup;
andre@0:         }
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyOID, plContext);
andre@0:         policyOID = NULL;
andre@0:     }
andre@0: 
andre@0:     error = PKIX_List_SetImmutable(policyList, plContext);
andre@0:     if (error != NULL) goto cleanup;
andre@0: 
andre@0:     error = PKIX_PL_Object_IncRef((PKIX_PL_Object *)policyList, plContext);
andre@0:     if (error == NULL) r = policyList;
andre@0: 
andre@0: cleanup:
andre@0:     if (policyOID != NULL)  {
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyOID, plContext);
andre@0:     }
andre@0:     if (policyList != NULL)  {
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyList, plContext);
andre@0:     }
andre@0:     if (error != NULL)  {
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)error, plContext);
andre@0:     }
andre@0: 
andre@0:     return r;
andre@0: }
andre@0: 
andre@0: CERTValOutParam *
andre@0: cert_pkix_FindOutputParam(CERTValOutParam *params, const CERTValParamOutType t)
andre@0: {
andre@0:     CERTValOutParam *i;
andre@0:     if (params == NULL) {
andre@0:         return NULL;
andre@0:     }
andre@0:     for (i = params; i->type != cert_po_end; i++) {
andre@0:         if (i->type == t) {
andre@0:              return i;
andre@0:         }
andre@0:     }
andre@0:     return NULL;
andre@0: }
andre@0: 
andre@0: 
andre@0: static PKIX_Error*
andre@0: setRevocationMethod(PKIX_RevocationChecker *revChecker,
andre@0:                     PKIX_ProcessingParams *procParams,
andre@0:                     const CERTRevocationTests *revTest,
andre@0:                     CERTRevocationMethodIndex certRevMethod,
andre@0:                     PKIX_RevocationMethodType pkixRevMethod,
andre@0:                     PKIX_Boolean verifyResponderUsages,
andre@0:                     PKIX_Boolean isLeafTest,
andre@0:                     void *plContext)
andre@0: {
andre@0:     PKIX_UInt32 methodFlags = 0;
andre@0:     PKIX_Error *error = NULL;
andre@0:     int priority = 0;
andre@0:     
andre@0:     if (revTest->number_of_defined_methods <= certRevMethod) {
andre@0:         return NULL;
andre@0:     }
andre@0:     if (revTest->preferred_methods) {
andre@0:         int i = 0;
andre@0:         for (;i < revTest->number_of_preferred_methods;i++) {
andre@0:             if (revTest->preferred_methods[i] == certRevMethod) 
andre@0:                 break;
andre@0:         }
andre@0:         priority = i;
andre@0:     }
andre@0:     methodFlags = revTest->cert_rev_flags_per_method[certRevMethod];
andre@0:     if (verifyResponderUsages &&
andre@0:         pkixRevMethod == PKIX_RevocationMethod_OCSP) {
andre@0:         methodFlags |= PKIX_REV_M_FORBID_NETWORK_FETCHING;
andre@0:     }
andre@0:     error =
andre@0:         PKIX_RevocationChecker_CreateAndAddMethod(revChecker, procParams,
andre@0:                                          pkixRevMethod, methodFlags,
andre@0:                                          priority, NULL,
andre@0:                                          isLeafTest, plContext);
andre@0:     return error;
andre@0: }
andre@0: 
andre@0: 
andre@0: SECStatus
andre@0: cert_pkixSetParam(PKIX_ProcessingParams *procParams, 
andre@0:   const CERTValInParam *param, void *plContext)
andre@0: {
andre@0:     PKIX_Error * error = NULL;
andre@0:     SECStatus r=SECSuccess;
andre@0:     PKIX_PL_Date *date = NULL;
andre@0:     PKIX_List *policyOIDList = NULL;
andre@0:     PKIX_List *certListPkix = NULL;
andre@0:     const CERTRevocationFlags *flags;
andre@0:     SECErrorCodes errCode = SEC_ERROR_INVALID_ARGS;
andre@0:     const CERTCertList *certList = NULL;
andre@0:     CERTCertListNode *node;
andre@0:     PKIX_PL_Cert *certPkix = NULL;
andre@0:     PKIX_TrustAnchor *trustAnchor = NULL;
andre@0:     PKIX_PL_Date *revDate = NULL;
andre@0:     PKIX_RevocationChecker *revChecker = NULL;
andre@0:     PKIX_PL_NssContext *nssContext = (PKIX_PL_NssContext *)plContext;
andre@0: 
andre@0:     /* XXX we need a way to map generic PKIX error to generic NSS errors */
andre@0: 
andre@0:     switch (param->type) {
andre@0: 
andre@0:         case cert_pi_policyOID:
andre@0: 
andre@0:             /* needed? */
andre@0:             error = PKIX_ProcessingParams_SetExplicitPolicyRequired(
andre@0:                                 procParams, PKIX_TRUE, plContext);
andre@0: 
andre@0:             if (error != NULL) { 
andre@0:                 break;
andre@0:             }
andre@0: 
andre@0:             policyOIDList = cert_PKIXMakeOIDList(param->value.array.oids,
andre@0:                                 param->value.arraySize,plContext);
andre@0: 	    if (policyOIDList == NULL) {
andre@0: 		r = SECFailure;
andre@0: 		PORT_SetError(SEC_ERROR_INVALID_ARGS);
andre@0: 		break;
andre@0: 	    }
andre@0: 
andre@0:             error = PKIX_ProcessingParams_SetInitialPolicies(
andre@0:                                 procParams,policyOIDList,plContext);
andre@0:             break;
andre@0: 
andre@0:         case cert_pi_date:
andre@0:             if (param->value.scalar.time == 0) {
andre@0:                 error = PKIX_PL_Date_Create_UTCTime(NULL, &date, plContext);
andre@0:                 if (error != NULL) {
andre@0:                     errCode = SEC_ERROR_INVALID_TIME;
andre@0:                     break;
andre@0:                 }
andre@0:             } else {
andre@0:                 error = pkix_pl_Date_CreateFromPRTime(param->value.scalar.time,
andre@0:                                                        &date, plContext);
andre@0:                 if (error != NULL) {
andre@0:                     errCode = SEC_ERROR_INVALID_TIME;
andre@0:                     break;
andre@0:                 }
andre@0:             }
andre@0: 
andre@0:             error = PKIX_ProcessingParams_SetDate(procParams, date, plContext);
andre@0:             if (error != NULL) {
andre@0:                 errCode = SEC_ERROR_INVALID_TIME;
andre@0:             }
andre@0:             break;
andre@0: 
andre@0:         case cert_pi_revocationFlags:
andre@0:         {
andre@0:             PKIX_UInt32 leafIMFlags = 0;
andre@0:             PKIX_UInt32 chainIMFlags = 0;
andre@0:             PKIX_Boolean validatingResponderCert = PKIX_FALSE;
andre@0: 
andre@0:             flags = param->value.pointer.revocation;
andre@0:             if (!flags) {
andre@0:                 PORT_SetError(errCode);
andre@0:                 r = SECFailure;
andre@0:                 break;
andre@0:             }
andre@0: 
andre@0:             leafIMFlags = 
andre@0:                 flags->leafTests.cert_rev_method_independent_flags;
andre@0:             chainIMFlags =
andre@0:                 flags->chainTests.cert_rev_method_independent_flags;
andre@0: 
andre@0:             error =
andre@0:                 PKIX_RevocationChecker_Create(leafIMFlags, chainIMFlags,
andre@0:                                               &revChecker, plContext);
andre@0:             if (error) {
andre@0:                 break;
andre@0:             }
andre@0: 
andre@0:             error =
andre@0:                 PKIX_ProcessingParams_SetRevocationChecker(procParams,
andre@0:                                                 revChecker, plContext);
andre@0:             if (error) {
andre@0:                 break;
andre@0:             }
andre@0: 
andre@0:             if (((PKIX_PL_NssContext*)plContext)->certificateUsage &
andre@0:                 certificateUsageStatusResponder) {
andre@0:                 validatingResponderCert = PKIX_TRUE;
andre@0:             }
andre@0: 
andre@0:             error = setRevocationMethod(revChecker,
andre@0:                                         procParams, &flags->leafTests,
andre@0:                                         cert_revocation_method_crl,
andre@0:                                         PKIX_RevocationMethod_CRL,
andre@0:                                         validatingResponderCert,
andre@0:                                         PKIX_TRUE, plContext);
andre@0:             if (error) {
andre@0:                 break;
andre@0:             }
andre@0: 
andre@0:             error = setRevocationMethod(revChecker,
andre@0:                                         procParams, &flags->leafTests,
andre@0:                                         cert_revocation_method_ocsp,
andre@0:                                         PKIX_RevocationMethod_OCSP,
andre@0:                                         validatingResponderCert,
andre@0:                                         PKIX_TRUE, plContext);
andre@0:             if (error) {
andre@0:                 break;
andre@0:             }
andre@0: 
andre@0:             error = setRevocationMethod(revChecker,
andre@0:                                         procParams, &flags->chainTests,
andre@0:                                         cert_revocation_method_crl,
andre@0:                                         PKIX_RevocationMethod_CRL,
andre@0:                                         validatingResponderCert,
andre@0:                                         PKIX_FALSE, plContext);
andre@0:             if (error) {
andre@0:                 break;
andre@0:             }
andre@0: 
andre@0:             error = setRevocationMethod(revChecker,
andre@0:                                         procParams, &flags->chainTests,
andre@0:                                         cert_revocation_method_ocsp,
andre@0:                                         PKIX_RevocationMethod_OCSP,
andre@0:                                         validatingResponderCert,
andre@0:                                         PKIX_FALSE, plContext);
andre@0:             if (error) {
andre@0:                 break;
andre@0:             }
andre@0: 
andre@0:         }
andre@0:         break;
andre@0: 
andre@0:         case cert_pi_trustAnchors:
andre@0:             certList = param->value.pointer.chain;
andre@0:             if (!certList) {
andre@0:                 PORT_SetError(errCode);
andre@0:                 r = SECFailure;
andre@0:                 break;
andre@0:             }
andre@0:             error = PKIX_List_Create(&certListPkix, plContext);
andre@0:             if (error != NULL) {
andre@0:                 break;
andre@0:             }
andre@0:             for(node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
andre@0:                 node = CERT_LIST_NEXT(node) ) {
andre@0:                 error = PKIX_PL_Cert_CreateFromCERTCertificate(node->cert,
andre@0:                                                       &certPkix, plContext);
andre@0:                 if (error) {
andre@0:                     break;
andre@0:                 }
andre@0:                 error = PKIX_TrustAnchor_CreateWithCert(certPkix, &trustAnchor,
andre@0:                                                         plContext);
andre@0:                 if (error) {
andre@0:                     break;
andre@0:                 }
andre@0:                 error = PKIX_List_AppendItem(certListPkix,
andre@0:                                  (PKIX_PL_Object*)trustAnchor, plContext);
andre@0:                  if (error) {
andre@0:                     break;
andre@0:                 }
andre@0:                 PKIX_PL_Object_DecRef((PKIX_PL_Object *)trustAnchor, plContext);
andre@0:                 trustAnchor = NULL;
andre@0:                 PKIX_PL_Object_DecRef((PKIX_PL_Object *)certPkix, plContext);
andre@0:                 certPkix = NULL;
andre@0:             }
andre@0:             error =
andre@0:                 PKIX_ProcessingParams_SetTrustAnchors(procParams, certListPkix,
andre@0:                                                       plContext);
andre@0:             break;
andre@0: 
andre@0:         case cert_pi_useAIACertFetch:
andre@0:             error =
andre@0:                 PKIX_ProcessingParams_SetUseAIAForCertFetching(procParams,
andre@0:                                      (PRBool)(param->value.scalar.b != 0),
andre@0:                                                                plContext);
andre@0:             break;
andre@0: 
andre@0:         case cert_pi_chainVerifyCallback:
andre@0:         {
andre@0:             const CERTChainVerifyCallback *chainVerifyCallback =
andre@0:                 param->value.pointer.chainVerifyCallback;
andre@0:             if (!chainVerifyCallback || !chainVerifyCallback->isChainValid) {
andre@0:                 PORT_SetError(errCode);
andre@0:                 r = SECFailure;
andre@0:                 break;
andre@0:             }
andre@0: 
andre@0:             nssContext->chainVerifyCallback = *chainVerifyCallback;
andre@0:         }
andre@0:         break;
andre@0: 
andre@0:         case cert_pi_useOnlyTrustAnchors:
andre@0:             error =
andre@0:                 PKIX_ProcessingParams_SetUseOnlyTrustAnchors(procParams,
andre@0:                                       (PRBool)(param->value.scalar.b != 0),
andre@0:                                                              plContext);
andre@0:             break;
andre@0: 
andre@0:         default:
andre@0:             PORT_SetError(errCode);
andre@0:             r = SECFailure;
andre@0:             break;
andre@0:     }
andre@0: 
andre@0:     if (policyOIDList != NULL)
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyOIDList, plContext);
andre@0: 
andre@0:     if (date != NULL) 
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)date, plContext);
andre@0: 
andre@0:     if (revDate != NULL) 
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)revDate, plContext);
andre@0: 
andre@0:     if (revChecker != NULL) 
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)revChecker, plContext);
andre@0: 
andre@0:     if (certListPkix) 
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)certListPkix, plContext);
andre@0: 
andre@0:     if (trustAnchor) 
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)trustAnchor, plContext);
andre@0: 
andre@0:     if (certPkix) 
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)certPkix, plContext);
andre@0: 
andre@0:     if (error != NULL) {
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)error, plContext);
andre@0:         PORT_SetError(errCode);
andre@0:         r = SECFailure;
andre@0:     }
andre@0: 
andre@0:     return r; 
andre@0: 
andre@0: }
andre@0: 
andre@0: void
andre@0: cert_pkixDestroyValOutParam(CERTValOutParam *params)
andre@0: {
andre@0:     CERTValOutParam *i;
andre@0: 
andre@0:     if (params == NULL) {
andre@0:         return;
andre@0:     }
andre@0:     for (i = params; i->type != cert_po_end; i++) {
andre@0:         switch (i->type) {
andre@0:         case cert_po_trustAnchor:
andre@0:             if (i->value.pointer.cert) {
andre@0:                 CERT_DestroyCertificate(i->value.pointer.cert);
andre@0:                 i->value.pointer.cert = NULL;
andre@0:             }
andre@0:             break;
andre@0: 
andre@0:         case cert_po_certList:
andre@0:             if (i->value.pointer.chain) {
andre@0:                 CERT_DestroyCertList(i->value.pointer.chain);
andre@0:                 i->value.pointer.chain = NULL;
andre@0:             }
andre@0:             break;
andre@0: 
andre@0:         default:
andre@0:             break;
andre@0:         }
andre@0:     }
andre@0: }
andre@0: 
andre@0: static PRUint64 certRev_NSS_3_11_Ocsp_Enabled_Soft_Policy_LeafFlags[2] = {
andre@0:   /* crl */
andre@0:   CERT_REV_M_TEST_USING_THIS_METHOD 
andre@0:   | CERT_REV_M_FORBID_NETWORK_FETCHING
andre@0:   | CERT_REV_M_CONTINUE_TESTING_ON_FRESH_INFO,
andre@0:   /* ocsp */
andre@0:   CERT_REV_M_TEST_USING_THIS_METHOD
andre@0: };
andre@0: 
andre@0: static PRUint64 certRev_NSS_3_11_Ocsp_Enabled_Soft_Policy_ChainFlags[2] = {
andre@0:   /* crl */
andre@0:   CERT_REV_M_TEST_USING_THIS_METHOD
andre@0:   | CERT_REV_M_FORBID_NETWORK_FETCHING
andre@0:   | CERT_REV_M_CONTINUE_TESTING_ON_FRESH_INFO,
andre@0:   /* ocsp */
andre@0:   0
andre@0: };
andre@0: 
andre@0: static CERTRevocationMethodIndex 
andre@0: certRev_NSS_3_11_Ocsp_Enabled_Soft_Policy_Method_Preference = {
andre@0:   cert_revocation_method_crl
andre@0: };
andre@0: 
andre@0: static const CERTRevocationFlags certRev_NSS_3_11_Ocsp_Enabled_Soft_Policy = {
andre@0:   {
andre@0:     /* leafTests */
andre@0:     2,
andre@0:     certRev_NSS_3_11_Ocsp_Enabled_Soft_Policy_LeafFlags,
andre@0:     1,
andre@0:     &certRev_NSS_3_11_Ocsp_Enabled_Soft_Policy_Method_Preference,
andre@0:     0
andre@0:   },
andre@0:   {
andre@0:     /* chainTests */
andre@0:     2,
andre@0:     certRev_NSS_3_11_Ocsp_Enabled_Soft_Policy_ChainFlags,
andre@0:     0,
andre@0:     0,
andre@0:     0
andre@0:   }
andre@0: };
andre@0: 
andre@0: extern const CERTRevocationFlags*
andre@0: CERT_GetClassicOCSPEnabledSoftFailurePolicy()
andre@0: {
andre@0:     return &certRev_NSS_3_11_Ocsp_Enabled_Soft_Policy;
andre@0: }
andre@0: 
andre@0: 
andre@0: static PRUint64 certRev_NSS_3_11_Ocsp_Enabled_Hard_Policy_LeafFlags[2] = {
andre@0:   /* crl */
andre@0:   CERT_REV_M_TEST_USING_THIS_METHOD 
andre@0:   | CERT_REV_M_FORBID_NETWORK_FETCHING
andre@0:   | CERT_REV_M_CONTINUE_TESTING_ON_FRESH_INFO,
andre@0:   /* ocsp */
andre@0:   CERT_REV_M_TEST_USING_THIS_METHOD
andre@0:   | CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO
andre@0: };
andre@0: 
andre@0: static PRUint64 certRev_NSS_3_11_Ocsp_Enabled_Hard_Policy_ChainFlags[2] = {
andre@0:   /* crl */
andre@0:   CERT_REV_M_TEST_USING_THIS_METHOD
andre@0:   | CERT_REV_M_FORBID_NETWORK_FETCHING
andre@0:   | CERT_REV_M_CONTINUE_TESTING_ON_FRESH_INFO,
andre@0:   /* ocsp */
andre@0:   0
andre@0: };
andre@0: 
andre@0: static CERTRevocationMethodIndex 
andre@0: certRev_NSS_3_11_Ocsp_Enabled_Hard_Policy_Method_Preference = {
andre@0:   cert_revocation_method_crl
andre@0: };
andre@0: 
andre@0: static const CERTRevocationFlags certRev_NSS_3_11_Ocsp_Enabled_Hard_Policy = {
andre@0:   {
andre@0:     /* leafTests */
andre@0:     2,
andre@0:     certRev_NSS_3_11_Ocsp_Enabled_Hard_Policy_LeafFlags,
andre@0:     1,
andre@0:     &certRev_NSS_3_11_Ocsp_Enabled_Hard_Policy_Method_Preference,
andre@0:     0
andre@0:   },
andre@0:   {
andre@0:     /* chainTests */
andre@0:     2,
andre@0:     certRev_NSS_3_11_Ocsp_Enabled_Hard_Policy_ChainFlags,
andre@0:     0,
andre@0:     0,
andre@0:     0
andre@0:   }
andre@0: };
andre@0: 
andre@0: extern const CERTRevocationFlags*
andre@0: CERT_GetClassicOCSPEnabledHardFailurePolicy()
andre@0: {
andre@0:     return &certRev_NSS_3_11_Ocsp_Enabled_Hard_Policy;
andre@0: }
andre@0: 
andre@0: 
andre@0: static PRUint64 certRev_NSS_3_11_Ocsp_Disabled_Policy_LeafFlags[2] = {
andre@0:   /* crl */
andre@0:   CERT_REV_M_TEST_USING_THIS_METHOD
andre@0:   | CERT_REV_M_FORBID_NETWORK_FETCHING
andre@0:   | CERT_REV_M_CONTINUE_TESTING_ON_FRESH_INFO,
andre@0:   /* ocsp */
andre@0:   0
andre@0: };
andre@0: 
andre@0: static PRUint64 certRev_NSS_3_11_Ocsp_Disabled_Policy_ChainFlags[2] = {
andre@0:   /* crl */
andre@0:   CERT_REV_M_TEST_USING_THIS_METHOD
andre@0:   | CERT_REV_M_FORBID_NETWORK_FETCHING
andre@0:   | CERT_REV_M_CONTINUE_TESTING_ON_FRESH_INFO,
andre@0:   /* ocsp */
andre@0:   0
andre@0: };
andre@0: 
andre@0: static const CERTRevocationFlags certRev_NSS_3_11_Ocsp_Disabled_Policy = {
andre@0:   {
andre@0:     /* leafTests */
andre@0:     2,
andre@0:     certRev_NSS_3_11_Ocsp_Disabled_Policy_LeafFlags,
andre@0:     0,
andre@0:     0,
andre@0:     0
andre@0:   },
andre@0:   {
andre@0:     /* chainTests */
andre@0:     2,
andre@0:     certRev_NSS_3_11_Ocsp_Disabled_Policy_ChainFlags,
andre@0:     0,
andre@0:     0,
andre@0:     0
andre@0:   }
andre@0: };
andre@0: 
andre@0: extern const CERTRevocationFlags*
andre@0: CERT_GetClassicOCSPDisabledPolicy()
andre@0: {
andre@0:     return &certRev_NSS_3_11_Ocsp_Disabled_Policy;
andre@0: }
andre@0: 
andre@0: 
andre@0: static PRUint64 certRev_PKIX_Verify_Nist_Policy_LeafFlags[2] = {
andre@0:   /* crl */
andre@0:   CERT_REV_M_TEST_USING_THIS_METHOD
andre@0:   | CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO
andre@0:   | CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE,
andre@0:   /* ocsp */
andre@0:   0
andre@0: };
andre@0: 
andre@0: static PRUint64 certRev_PKIX_Verify_Nist_Policy_ChainFlags[2] = {
andre@0:   /* crl */
andre@0:   CERT_REV_M_TEST_USING_THIS_METHOD
andre@0:   | CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO
andre@0:   | CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE,
andre@0:   /* ocsp */
andre@0:   0
andre@0: };
andre@0: 
andre@0: static const CERTRevocationFlags certRev_PKIX_Verify_Nist_Policy = {
andre@0:   {
andre@0:     /* leafTests */
andre@0:     2,
andre@0:     certRev_PKIX_Verify_Nist_Policy_LeafFlags,
andre@0:     0,
andre@0:     0,
andre@0:     0
andre@0:   },
andre@0:   {
andre@0:     /* chainTests */
andre@0:     2,
andre@0:     certRev_PKIX_Verify_Nist_Policy_ChainFlags,
andre@0:     0,
andre@0:     0,
andre@0:     0
andre@0:   }
andre@0: };
andre@0: 
andre@0: extern const CERTRevocationFlags*
andre@0: CERT_GetPKIXVerifyNistRevocationPolicy()
andre@0: {
andre@0:     return &certRev_PKIX_Verify_Nist_Policy;
andre@0: }
andre@0: 
andre@0: CERTRevocationFlags *
andre@0: CERT_AllocCERTRevocationFlags(
andre@0:     PRUint32 number_leaf_methods, PRUint32 number_leaf_pref_methods,
andre@0:     PRUint32 number_chain_methods, PRUint32 number_chain_pref_methods)
andre@0: {
andre@0:     CERTRevocationFlags *flags;
andre@0:     
andre@0:     flags = PORT_New(CERTRevocationFlags);
andre@0:     if (!flags)
andre@0:         return(NULL);
andre@0:     
andre@0:     flags->leafTests.number_of_defined_methods = number_leaf_methods;
andre@0:     flags->leafTests.cert_rev_flags_per_method = 
andre@0:         PORT_NewArray(PRUint64, number_leaf_methods);
andre@0: 
andre@0:     flags->leafTests.number_of_preferred_methods = number_leaf_pref_methods;
andre@0:     flags->leafTests.preferred_methods = 
andre@0:         PORT_NewArray(CERTRevocationMethodIndex, number_leaf_pref_methods);
andre@0: 
andre@0:     flags->chainTests.number_of_defined_methods = number_chain_methods;
andre@0:     flags->chainTests.cert_rev_flags_per_method = 
andre@0:         PORT_NewArray(PRUint64, number_chain_methods);
andre@0: 
andre@0:     flags->chainTests.number_of_preferred_methods = number_chain_pref_methods;
andre@0:     flags->chainTests.preferred_methods = 
andre@0:         PORT_NewArray(CERTRevocationMethodIndex, number_chain_pref_methods);
andre@0:     
andre@0:     if (!flags->leafTests.cert_rev_flags_per_method
andre@0:         || !flags->leafTests.preferred_methods
andre@0:         || !flags->chainTests.cert_rev_flags_per_method
andre@0:         || !flags->chainTests.preferred_methods) {
andre@0:         CERT_DestroyCERTRevocationFlags(flags);
andre@0:         return (NULL);
andre@0:     }
andre@0:     
andre@0:     return flags;
andre@0: }
andre@0: 
andre@0: void CERT_DestroyCERTRevocationFlags(CERTRevocationFlags *flags)
andre@0: {
andre@0:     if (!flags)
andre@0: 	return;
andre@0:   
andre@0:     if (flags->leafTests.cert_rev_flags_per_method)
andre@0:         PORT_Free(flags->leafTests.cert_rev_flags_per_method);
andre@0: 
andre@0:     if (flags->leafTests.preferred_methods)
andre@0:         PORT_Free(flags->leafTests.preferred_methods);
andre@0:     
andre@0:     if (flags->chainTests.cert_rev_flags_per_method)
andre@0:         PORT_Free(flags->chainTests.cert_rev_flags_per_method);
andre@0: 
andre@0:     if (flags->chainTests.preferred_methods)
andre@0:         PORT_Free(flags->chainTests.preferred_methods);
andre@0: 
andre@0:      PORT_Free(flags);
andre@0: }
andre@0: 
andre@0: /*
andre@0:  * CERT_PKIXVerifyCert
andre@0:  *
andre@0:  * Verify a Certificate using the PKIX library.
andre@0:  *
andre@0:  * Parameters:
andre@0:  *  cert    - the target certificate to verify. Must be non-null
andre@0:  *  params  - an array of type/value parameters which can be
andre@0:  *            used to modify the behavior of the validation
andre@0:  *            algorithm, or supply additional constraints.
andre@0:  *
andre@0:  *  outputTrustAnchor - the trust anchor which the certificate
andre@0:  *                      chains to. The caller is responsible
andre@0:  *                      for freeing this.
andre@0:  *
andre@0:  * Example Usage:
andre@0:  *    CERTValParam args[3];
andre@0:  *    args[0].type = cvpt_policyOID;
andre@0:  *    args[0].value.si = oid;
andre@0:  *    args[1].type = revCheckRequired;
andre@0:  *    args[1].value.b = PR_TRUE;
andre@0:  *    args[2].type = cvpt_end;
andre@0:  *
andre@0:  *    CERT_PKIXVerifyCert(cert, &output, args
andre@0:  */
andre@0: SECStatus CERT_PKIXVerifyCert(
andre@0:  CERTCertificate *cert,
andre@0:  SECCertificateUsage usages,
andre@0:  CERTValInParam *paramsIn,
andre@0:  CERTValOutParam *paramsOut,
andre@0:  void *wincx)
andre@0: {
andre@0:     SECStatus             r = SECFailure;
andre@0:     PKIX_Error *          error = NULL;
andre@0:     PKIX_ProcessingParams *procParams = NULL;
andre@0:     PKIX_BuildResult *    buildResult = NULL;
andre@0:     void *                nbioContext = NULL;  /* for non-blocking IO */
andre@0:     void *                buildState = NULL;   /* for non-blocking IO */
andre@0:     PKIX_CertSelector *   certSelector = NULL;
andre@0:     PKIX_List *           certStores = NULL;
andre@0:     PKIX_ValidateResult * valResult = NULL;
andre@0:     PKIX_VerifyNode     * verifyNode = NULL;
andre@0:     PKIX_TrustAnchor *    trustAnchor = NULL;
andre@0:     PKIX_PL_Cert *        trustAnchorCert = NULL;
andre@0:     PKIX_List *           builtCertList = NULL;
andre@0:     CERTValOutParam *     oparam = NULL;
andre@0:     int i=0;
andre@0: 
andre@0:     void *plContext = NULL;
andre@0: 
andre@0: #ifdef PKIX_OBJECT_LEAK_TEST
andre@0:     int  leakedObjNum = 0;
andre@0:     int  memLeakLoopCount = 0;
andre@0:     int  objCountTable[PKIX_NUMTYPES];
andre@0:     int  fnInvLocalCount = 0;
andre@0:     PKIX_Boolean savedUsePkixEngFlag = usePKIXValidationEngine;
andre@0: 
andre@0:     if (usePKIXValidationEngine) {
andre@0:         /* current memory leak testing implementation does not allow
andre@0:          * to run simultaneous tests one the same or a different threads.
andre@0:          * Setting the variable to false, to make additional chain
andre@0:          * validations be handled by old nss. */
andre@0:         usePKIXValidationEngine = PR_FALSE;
andre@0:     }
andre@0:     testStartFnStackPosition = 1;
andre@0:     fnStackNameArr[0] = "CERT_PKIXVerifyCert";
andre@0:     fnStackInvCountArr[0] = 0;
andre@0:     PKIX_Boolean abortOnLeak = 
andre@0:         (PR_GetEnv("PKIX_OBJECT_LEAK_TEST_ABORT_ON_LEAK") == NULL) ?
andre@0:                                                    PKIX_FALSE : PKIX_TRUE;
andre@0:     runningLeakTest = PKIX_TRUE;
andre@0: 
andre@0:     /* Prevent multi-threaded run of object leak test */
andre@0:     fnInvLocalCount = PR_ATOMIC_INCREMENT(&parallelFnInvocationCount);
andre@0:     PORT_Assert(fnInvLocalCount == 1);
andre@0: 
andre@0: do {
andre@0:     r = SECFailure;
andre@0:     error = NULL;
andre@0:     procParams = NULL;
andre@0:     buildResult = NULL;
andre@0:     nbioContext = NULL;  /* for non-blocking IO */
andre@0:     buildState = NULL;   /* for non-blocking IO */
andre@0:     certSelector = NULL;
andre@0:     certStores = NULL;
andre@0:     valResult = NULL;
andre@0:     verifyNode = NULL;
andre@0:     trustAnchor = NULL;
andre@0:     trustAnchorCert = NULL;
andre@0:     builtCertList = NULL;
andre@0:     oparam = NULL;
andre@0:     i=0;
andre@0:     errorGenerated = PKIX_FALSE;
andre@0:     stackPosition = 0;
andre@0: 
andre@0:     if (leakedObjNum) {
andre@0:         pkix_pl_lifecycle_ObjectTableUpdate(objCountTable);
andre@0:     }
andre@0:     memLeakLoopCount += 1;
andre@0: #endif /* PKIX_OBJECT_LEAK_TEST */
andre@0: 
andre@0:     error = PKIX_PL_NssContext_Create(
andre@0:             0, PR_FALSE /*use arena*/, wincx, &plContext);
andre@0:     if (error != NULL) {        /* need pkix->nss error map */
andre@0:         PORT_SetError(SEC_ERROR_CERT_NOT_VALID);
andre@0:         goto cleanup;
andre@0:     }
andre@0: 
andre@0:     error = pkix_pl_NssContext_SetCertUsage(usages, plContext);
andre@0:     if (error != NULL) {
andre@0:         PORT_SetError(SEC_ERROR_INVALID_ARGS);
andre@0:         goto cleanup;
andre@0:     }
andre@0: 
andre@0:     error = PKIX_ProcessingParams_Create(&procParams, plContext);
andre@0:     if (error != NULL) {              /* need pkix->nss error map */
andre@0:         PORT_SetError(SEC_ERROR_CERT_NOT_VALID);
andre@0:         goto cleanup;
andre@0:     }
andre@0: 
andre@0:     /* local cert store should be set into procParams before
andre@0:      * filling in revocation settings. */
andre@0:     certStores = cert_GetCertStores(plContext);
andre@0:     if (certStores == NULL) {
andre@0:         goto cleanup;
andre@0:     }
andre@0:     error = PKIX_ProcessingParams_SetCertStores
andre@0:         (procParams, certStores, plContext);
andre@0:     if (error != NULL) {
andre@0:         goto cleanup;
andre@0:     }
andre@0: 
andre@0:     /* now process the extensible input parameters structure */
andre@0:     if (paramsIn != NULL) {
andre@0:         i=0;
andre@0:         while (paramsIn[i].type != cert_pi_end) {
andre@0:             if (paramsIn[i].type >= cert_pi_max) {
andre@0:                 PORT_SetError(SEC_ERROR_INVALID_ARGS);
andre@0:                 goto cleanup;
andre@0:             }
andre@0:             if (cert_pkixSetParam(procParams,
andre@0:                      &paramsIn[i],plContext) != SECSuccess) {
andre@0:                 PORT_SetError(SEC_ERROR_INVALID_ARGS);
andre@0:                 goto cleanup;
andre@0:             }
andre@0:             i++;
andre@0:         }
andre@0:     }
andre@0: 
andre@0:     certSelector = cert_GetTargetCertConstraints(cert, plContext);
andre@0:     if (certSelector == NULL) {
andre@0:         goto cleanup;
andre@0:     }
andre@0:     error = PKIX_ProcessingParams_SetTargetCertConstraints
andre@0:         (procParams, certSelector, plContext);
andre@0:     if (error != NULL) {
andre@0:         goto cleanup;
andre@0:     }
andre@0: 
andre@0:     error = PKIX_BuildChain( procParams, &nbioContext,
andre@0:                              &buildState, &buildResult, &verifyNode,
andre@0:                              plContext);
andre@0:     if (error != NULL) {
andre@0:         goto cleanup;
andre@0:     }
andre@0: 
andre@0:     error = PKIX_BuildResult_GetValidateResult( buildResult, &valResult,
andre@0:                                                 plContext);
andre@0:     if (error != NULL) {
andre@0:         goto cleanup;
andre@0:     }
andre@0: 
andre@0:     error = PKIX_ValidateResult_GetTrustAnchor( valResult, &trustAnchor,
andre@0:                                                 plContext);
andre@0:     if (error != NULL) {
andre@0:         goto cleanup;
andre@0:     }
andre@0: 
andre@0:     if (trustAnchor != NULL) {
andre@0:         error = PKIX_TrustAnchor_GetTrustedCert( trustAnchor, &trustAnchorCert,
andre@0:                                                  plContext);
andre@0:         if (error != NULL) {
andre@0:             goto cleanup;
andre@0:         }
andre@0:     }
andre@0: 
andre@0: #ifdef PKIX_OBJECT_LEAK_TEST
andre@0:     /* Can not continue if error was generated but not returned.
andre@0:      * Jumping to cleanup. */
andre@0:     if (errorGenerated) goto cleanup;
andre@0: #endif /* PKIX_OBJECT_LEAK_TEST */
andre@0: 
andre@0:     oparam = cert_pkix_FindOutputParam(paramsOut, cert_po_trustAnchor);
andre@0:     if (oparam != NULL) {
andre@0:         if (trustAnchorCert != NULL) {
andre@0:             oparam->value.pointer.cert =
andre@0:                     cert_NSSCertFromPKIXCert(trustAnchorCert);
andre@0:         } else {
andre@0:             oparam->value.pointer.cert = NULL;
andre@0:         }
andre@0:     }
andre@0: 
andre@0:     error = PKIX_BuildResult_GetCertChain( buildResult, &builtCertList,
andre@0:                                                 plContext);
andre@0:     if (error != NULL) {
andre@0:         goto cleanup;
andre@0:     }
andre@0: 
andre@0:     oparam = cert_pkix_FindOutputParam(paramsOut, cert_po_certList);
andre@0:     if (oparam != NULL) {
andre@0:         error = cert_PkixToNssCertsChain(builtCertList,
andre@0:                                          &oparam->value.pointer.chain,
andre@0:                                          plContext);
andre@0:         if (error) goto cleanup;
andre@0:     }
andre@0: 
andre@0:     r = SECSuccess;
andre@0: 
andre@0: cleanup:
andre@0:     if (verifyNode) {
andre@0:         /* Return validation log only upon error. */
andre@0:         oparam = cert_pkix_FindOutputParam(paramsOut, cert_po_errorLog);
andre@0: #ifdef PKIX_OBJECT_LEAK_TEST
andre@0:         if (!errorGenerated)
andre@0: #endif /* PKIX_OBJECT_LEAK_TEST */
andre@0:         if (r && oparam != NULL) {
andre@0:             PKIX_Error *tmpError =
andre@0:                 cert_GetLogFromVerifyNode(oparam->value.pointer.log,
andre@0:                                           verifyNode, plContext);
andre@0:             if (tmpError) {
andre@0:                 PKIX_PL_Object_DecRef((PKIX_PL_Object *)tmpError, plContext);
andre@0:             }
andre@0:         }
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)verifyNode, plContext);
andre@0:     }
andre@0: 
andre@0:     if (procParams != NULL) 
andre@0:        PKIX_PL_Object_DecRef((PKIX_PL_Object *)procParams, plContext);
andre@0: 
andre@0:     if (trustAnchorCert != NULL) 
andre@0:        PKIX_PL_Object_DecRef((PKIX_PL_Object *)trustAnchorCert, plContext);
andre@0: 
andre@0:     if (trustAnchor != NULL) 
andre@0:        PKIX_PL_Object_DecRef((PKIX_PL_Object *)trustAnchor, plContext);
andre@0: 
andre@0:     if (valResult != NULL) 
andre@0:        PKIX_PL_Object_DecRef((PKIX_PL_Object *)valResult, plContext);
andre@0: 
andre@0:     if (buildResult != NULL) 
andre@0:        PKIX_PL_Object_DecRef((PKIX_PL_Object *)buildResult, plContext);
andre@0: 
andre@0:     if (certStores != NULL) 
andre@0:        PKIX_PL_Object_DecRef((PKIX_PL_Object *)certStores, plContext);
andre@0: 
andre@0:     if (certSelector != NULL) 
andre@0:        PKIX_PL_Object_DecRef((PKIX_PL_Object *)certSelector, plContext);
andre@0: 
andre@0:     if (builtCertList != NULL) 
andre@0:        PKIX_PL_Object_DecRef((PKIX_PL_Object *)builtCertList, plContext);
andre@0: 
andre@0:     if (error != NULL) {
andre@0:         SECErrorCodes         nssErrorCode = 0;
andre@0: 
andre@0:         cert_PkixErrorToNssCode(error, &nssErrorCode, plContext);
andre@0:         cert_pkixDestroyValOutParam(paramsOut);
andre@0:         PORT_SetError(nssErrorCode);
andre@0:         PKIX_PL_Object_DecRef((PKIX_PL_Object *)error, plContext);
andre@0:     }
andre@0: 
andre@0:     PKIX_PL_NssContext_Destroy(plContext);
andre@0: 
andre@0: #ifdef PKIX_OBJECT_LEAK_TEST
andre@0:     leakedObjNum =
andre@0:         pkix_pl_lifecycle_ObjectLeakCheck(leakedObjNum ? objCountTable : NULL);
andre@0: 
andre@0:     if (pkixLog && leakedObjNum) {
andre@0:         PR_LOG(pkixLog, 1, ("The generated error caused an object leaks. Loop %d."
andre@0:                             "Stack %s\n", memLeakLoopCount, errorFnStackString));
andre@0:     }
andre@0:     PR_Free(errorFnStackString);
andre@0:     errorFnStackString = NULL;
andre@0:     if (abortOnLeak) {
andre@0:         PORT_Assert(leakedObjNum == 0);
andre@0:     }
andre@0:     
andre@0: } while (errorGenerated);
andre@0: 
andre@0:     runningLeakTest = PKIX_FALSE; 
andre@0:     PR_ATOMIC_DECREMENT(&parallelFnInvocationCount);
andre@0:     usePKIXValidationEngine = savedUsePkixEngFlag;
andre@0: #endif /* PKIX_OBJECT_LEAK_TEST */
andre@0: 
andre@0:     return r;
andre@0: }