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