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