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