mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
009fb15221
r=wtc
2278 lines
69 KiB
C
2278 lines
69 KiB
C
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is the Netscape security libraries.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1994-2000
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Sun Microsystems
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
/*
|
|
* 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"
|
|
|
|
#include "pkix_pl_common.h"
|
|
|
|
extern PRLogModuleInfo *pkixLog;
|
|
|
|
#ifdef DEBUG_volkov
|
|
/* Temporary declarations of functioins. Will be removed with fix for
|
|
* 391183 */
|
|
extern char *
|
|
pkix_Error2ASCII(PKIX_Error *error, void *plContext);
|
|
|
|
extern void
|
|
cert_PrintCert(PKIX_PL_Cert *pkixCert, void *plContext);
|
|
|
|
extern PKIX_Error *
|
|
cert_PrintCertChain(PKIX_List *pkixCertChain, void *plContext);
|
|
|
|
#endif /* DEBUG */
|
|
|
|
#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;
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
usePKIXValidationEngine = (enable > 0) ? PR_TRUE : PR_FALSE;
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* 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()
|
|
{
|
|
return usePKIXValidationEngine;
|
|
}
|
|
|
|
#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},
|
|
{certUsageSSLServerWithStepUp, ekuIndexSSLServer}, /* need to add oids to
|
|
* the list of eku.
|
|
* see 390381*/
|
|
{certUsageSSLCA, ekuIndexSSLServer},
|
|
{certUsageEmailSigner, ekuIndexEmail},
|
|
{certUsageEmailRecipient, ekuIndexEmail},
|
|
{certUsageObjectSigner, ekuIndexCodeSigner},
|
|
{certUsageUserCertImport, ekuIndexUnknown},
|
|
{certUsageVerifyCA, ekuIndexUnknown},
|
|
{certUsageProtectedObjectSigner, ekuIndexUnknown},
|
|
{certUsageStatusResponder, ekuIndexStatusResponder},
|
|
{certUsageAnyCA, ekuIndexUnknown},
|
|
};
|
|
|
|
#define CERT_USAGE_EKU_STRING_MAPS_TOTAL 12
|
|
|
|
/*
|
|
* 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 < CERT_USAGE_EKU_STRING_MAPS_TOTAL;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, /* not used yet. See bug 391476 */
|
|
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;
|
|
|
|
#ifdef PKIX_NOTDEF
|
|
/* Functions should be implemented in patch for 390532 */
|
|
PKIX_CHECK(
|
|
pkix_pl_NssContext_SetCertSignatureCheck(checkSig,
|
|
(PKIX_PL_NssContext*)plContext),
|
|
PKIX_NSSCONTEXTSETCERTSIGNCHECKFAILED);
|
|
|
|
#endif /* PKIX_NOTDEF */
|
|
|
|
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)
|
|
{
|
|
PRArenaPool *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_UInt32 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) {
|
|
#ifdef DEBUG_volkov
|
|
char *string = pkix_Error2ASCII(node->error, plContext);
|
|
fprintf(stderr, "Branch search finished with error: \t%s\n", string);
|
|
PKIX_PL_Free(string, NULL);
|
|
#endif
|
|
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;
|
|
#ifdef DEBUG_volkov
|
|
PKIX_Error *tmpPkixError = NULL;
|
|
#endif /* DEBUG */
|
|
|
|
PKIX_ENTER(CERTVFYPKIX, "cert_GetBuildResults");
|
|
if (buildResult == NULL && error == NULL) {
|
|
PKIX_ERROR(PKIX_NULLARGUMENT);
|
|
}
|
|
|
|
if (error) {
|
|
SECErrorCodes nssErrorCode = 0;
|
|
#ifdef DEBUG_volkov
|
|
char *temp = pkix_Error2ASCII(error, plContext);
|
|
fprintf(stderr, "BUILD ERROR:\n%s\n", temp);
|
|
PKIX_PL_Free(temp, NULL);
|
|
#endif /* DEBUG */
|
|
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);
|
|
|
|
#ifdef DEBUG_volkov
|
|
tmpPkixError = cert_PrintCertChain(pkixCertChain, plContext);
|
|
if (tmpPkixError) {
|
|
PKIX_PL_Object_DecRef((PKIX_PL_Object*)tmpPkixError, plContext);
|
|
}
|
|
#endif
|
|
|
|
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);
|
|
|
|
#ifdef DEBUG_volkov
|
|
if (pvalidChain == NULL) {
|
|
cert_PrintCert(trustedCert, plContext);
|
|
}
|
|
#endif
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
PKIX_ProcessingParams *procParams = NULL;
|
|
PKIX_BuildResult *result = NULL;
|
|
PKIX_VerifyNode *verifyNode = NULL;
|
|
PKIX_Error *error = NULL;
|
|
|
|
SECStatus rv = SECFailure;
|
|
void *plContext = NULL;
|
|
#ifdef DEBUG_volkov
|
|
CERTCertificate *trustedRoot = NULL;
|
|
CERTCertList *validChain = NULL;
|
|
#endif /* DEBUG */
|
|
|
|
#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_GetEnv("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;
|
|
#ifdef DEBUG_volkov
|
|
trustedRoot = NULL;
|
|
validChain = NULL;
|
|
#endif /* DEBUG */
|
|
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,
|
|
#ifdef DEBUG_volkov
|
|
&trustedRoot, &validChain,
|
|
#else
|
|
NULL, NULL,
|
|
#endif /* DEBUG */
|
|
plContext);
|
|
if (error) {
|
|
#ifdef DEBUG_volkov
|
|
char *temp = pkix_Error2ASCII(error, plContext);
|
|
fprintf(stderr, "GET BUILD RES ERRORS:\n%s\n", temp);
|
|
PKIX_PL_Free(temp, NULL);
|
|
#endif /* DEBUG */
|
|
PKIX_PL_Object_DecRef((PKIX_PL_Object *)error, plContext);
|
|
}
|
|
#ifdef DEBUG_volkov
|
|
if (trustedRoot) {
|
|
CERT_DestroyCertificate(trustedRoot);
|
|
}
|
|
if (validChain) {
|
|
CERT_DestroyCertList(validChain);
|
|
}
|
|
#endif /* DEBUG */
|
|
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;
|
|
}
|
|
|
|
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 */
|
|
CERTCertificate *
|
|
cert_NSSCertFromPKIXCert(const PKIX_PL_Cert *pkix_cert, void *plContext)
|
|
{
|
|
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) {
|
|
PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyOID, plContext);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
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;
|
|
int priority = 0;
|
|
|
|
if (revTest->number_of_defined_methods <= certRevMethod) {
|
|
return NULL;
|
|
}
|
|
if (revTest->preferred_methods) {
|
|
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_PL_Date *revDate = NULL;
|
|
PKIX_RevocationChecker *revChecker = NULL;
|
|
|
|
/* 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;
|
|
|
|
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 (revDate != NULL)
|
|
PKIX_PL_Object_DecRef((PKIX_PL_Object *)revDate, 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
|
|
}
|
|
};
|
|
|
|
extern const CERTRevocationFlags*
|
|
CERT_GetClassicOCSPEnabledSoftFailurePolicy()
|
|
{
|
|
return &certRev_NSS_3_11_Ocsp_Enabled_Soft_Policy;
|
|
}
|
|
|
|
|
|
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
|
|
}
|
|
};
|
|
|
|
extern const CERTRevocationFlags*
|
|
CERT_GetClassicOCSPEnabledHardFailurePolicy()
|
|
{
|
|
return &certRev_NSS_3_11_Ocsp_Enabled_Hard_Policy;
|
|
}
|
|
|
|
|
|
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
|
|
}
|
|
};
|
|
|
|
extern const CERTRevocationFlags*
|
|
CERT_GetClassicOCSPDisabledPolicy()
|
|
{
|
|
return &certRev_NSS_3_11_Ocsp_Disabled_Policy;
|
|
}
|
|
|
|
|
|
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
|
|
}
|
|
};
|
|
|
|
extern const CERTRevocationFlags*
|
|
CERT_GetPKIXVerifyNistRevocationPolicy()
|
|
{
|
|
return &certRev_PKIX_Verify_Nist_Policy;
|
|
}
|
|
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
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_GetEnv("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;
|
|
}
|
|
|
|
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) {
|
|
oparam->value.pointer.cert =
|
|
cert_NSSCertFromPKIXCert(trustAnchorCert,plContext);
|
|
}
|
|
|
|
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;
|
|
}
|