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