diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /security/nss/lib/libpkix/pkix/checker | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/nss/lib/libpkix/pkix/checker')
30 files changed, 7634 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix/checker/Makefile b/security/nss/lib/libpkix/pkix/checker/Makefile new file mode 100644 index 0000000000..d714361be7 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/Makefile @@ -0,0 +1,46 @@ +#! gmake +# +# 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/. + +####################################################################### +# (1) Include initial platform-independent assignments (MANDATORY). # +####################################################################### + +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + diff --git a/security/nss/lib/libpkix/pkix/checker/checker.gyp b/security/nss/lib/libpkix/pkix/checker/checker.gyp new file mode 100644 index 0000000000..ac260fc24d --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/checker.gyp @@ -0,0 +1,35 @@ +# 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/. +{ + 'includes': [ + '../../../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'pkixchecker', + 'type': 'static_library', + 'sources': [ + 'pkix_basicconstraintschecker.c', + 'pkix_certchainchecker.c', + 'pkix_crlchecker.c', + 'pkix_ekuchecker.c', + 'pkix_expirationchecker.c', + 'pkix_namechainingchecker.c', + 'pkix_nameconstraintschecker.c', + 'pkix_ocspchecker.c', + 'pkix_policychecker.c', + 'pkix_revocationchecker.c', + 'pkix_revocationmethod.c', + 'pkix_signaturechecker.c', + 'pkix_targetcertchecker.c' + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports' + ] + } + ], + 'variables': { + 'module': 'nss' + } +}
\ No newline at end of file diff --git a/security/nss/lib/libpkix/pkix/checker/exports.gyp b/security/nss/lib/libpkix/pkix/checker/exports.gyp new file mode 100644 index 0000000000..4bd68b39c1 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/exports.gyp @@ -0,0 +1,37 @@ +# 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/. +{ + 'includes': [ + '../../../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'lib_libpkix_pkix_checker_exports', + 'type': 'none', + 'copies': [ + { + 'files': [ + 'pkix_basicconstraintschecker.h', + 'pkix_certchainchecker.h', + 'pkix_crlchecker.h', + 'pkix_ekuchecker.h', + 'pkix_expirationchecker.h', + 'pkix_namechainingchecker.h', + 'pkix_nameconstraintschecker.h', + 'pkix_ocspchecker.h', + 'pkix_policychecker.h', + 'pkix_revocationchecker.h', + 'pkix_revocationmethod.h', + 'pkix_signaturechecker.h', + 'pkix_targetcertchecker.h' + ], + 'destination': '<(nss_private_dist_dir)/<(module)' + } + ] + } + ], + 'variables': { + 'module': 'nss' + } +} diff --git a/security/nss/lib/libpkix/pkix/checker/manifest.mn b/security/nss/lib/libpkix/pkix/checker/manifest.mn new file mode 100644 index 0000000000..84a372cea9 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/manifest.mn @@ -0,0 +1,42 @@ +# +# 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/. +CORE_DEPTH = ../../../.. + +PRIVATE_EXPORTS = \ + pkix_basicconstraintschecker.h \ + pkix_certchainchecker.h \ + pkix_crlchecker.h \ + pkix_ekuchecker.h \ + pkix_expirationchecker.h \ + pkix_namechainingchecker.h \ + pkix_nameconstraintschecker.h \ + pkix_ocspchecker.h \ + pkix_policychecker.h \ + pkix_revocationmethod.h \ + pkix_revocationchecker.h \ + pkix_signaturechecker.h \ + pkix_targetcertchecker.h \ + $(NULL) + +MODULE = nss + +CSRCS = \ + pkix_basicconstraintschecker.c \ + pkix_certchainchecker.c \ + pkix_crlchecker.c \ + pkix_ekuchecker.c \ + pkix_expirationchecker.c \ + pkix_namechainingchecker.c \ + pkix_nameconstraintschecker.c \ + pkix_ocspchecker.c \ + pkix_revocationmethod.c \ + pkix_revocationchecker.c \ + pkix_policychecker.c \ + pkix_signaturechecker.c \ + pkix_targetcertchecker.c \ + $(NULL) + +LIBRARY_NAME = pkixchecker +SHARED_LIBRARY = $(NULL) diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_basicconstraintschecker.c b/security/nss/lib/libpkix/pkix/checker/pkix_basicconstraintschecker.c new file mode 100644 index 0000000000..0e7a87997d --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_basicconstraintschecker.c @@ -0,0 +1,306 @@ +/* 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/. */ +/* + * pkix_basicconstraintschecker.c + * + * Functions for basic constraints validation + * + */ + +#include "pkix_basicconstraintschecker.h" + +/* --Private-BasicConstraintsCheckerState-Functions------------------------- */ + +/* + * FUNCTION: pkix_BasicConstraintsCheckerState_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_BasicConstraintsCheckerState_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + pkix_BasicConstraintsCheckerState *state = NULL; + + PKIX_ENTER(BASICCONSTRAINTSCHECKERSTATE, + "pkix_BasicConstraintsCheckerState_Destroy"); + + PKIX_NULLCHECK_ONE(object); + + /* Check that this object is a basic constraints checker state */ + PKIX_CHECK(pkix_CheckType + (object, PKIX_BASICCONSTRAINTSCHECKERSTATE_TYPE, plContext), + PKIX_OBJECTNOTBASICCONSTRAINTSCHECKERSTATE); + + state = (pkix_BasicConstraintsCheckerState *)object; + + PKIX_DECREF(state->basicConstraintsOID); + +cleanup: + + PKIX_RETURN(BASICCONSTRAINTSCHECKERSTATE); +} + +/* + * FUNCTION: pkix_BasicConstraintsCheckerState_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERT_TYPE and its related functions with systemClasses[] + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_BasicConstraintsCheckerState_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(BASICCONSTRAINTSCHECKERSTATE, + "pkix_BasicConstraintsCheckerState_RegisterSelf"); + + entry.description = "BasicConstraintsCheckerState"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(pkix_BasicConstraintsCheckerState); + entry.destructor = pkix_BasicConstraintsCheckerState_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_BASICCONSTRAINTSCHECKERSTATE_TYPE] = entry; + + PKIX_RETURN(BASICCONSTRAINTSCHECKERSTATE); +} + +/* + * FUNCTION: pkix_BasicConstraintsCheckerState_Create + * DESCRIPTION: + * + * Creates a new BasicConstraintsCheckerState using the number of certs in + * the chain represented by "certsRemaining" and stores it at "pState". + * + * PARAMETERS: + * "certsRemaining" + * Number of certificates in the chain. + * "pState" + * Address where object pointer will be stored. Must be non-NULL. + * "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 BasicConstraintsCheckerState Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_BasicConstraintsCheckerState_Create( + PKIX_UInt32 certsRemaining, + pkix_BasicConstraintsCheckerState **pState, + void *plContext) +{ + pkix_BasicConstraintsCheckerState *state = NULL; + + PKIX_ENTER(BASICCONSTRAINTSCHECKERSTATE, + "pkix_BasicConstraintsCheckerState_Create"); + + PKIX_NULLCHECK_ONE(pState); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_BASICCONSTRAINTSCHECKERSTATE_TYPE, + sizeof (pkix_BasicConstraintsCheckerState), + (PKIX_PL_Object **)&state, + plContext), + PKIX_COULDNOTCREATEBASICCONSTRAINTSSTATEOBJECT); + + /* initialize fields */ + state->certsRemaining = certsRemaining; + state->maxPathLength = PKIX_UNLIMITED_PATH_CONSTRAINT; + + PKIX_CHECK(PKIX_PL_OID_Create + (PKIX_BASICCONSTRAINTS_OID, + &state->basicConstraintsOID, + plContext), + PKIX_OIDCREATEFAILED); + + *pState = state; + state = NULL; + +cleanup: + + PKIX_DECREF(state); + + PKIX_RETURN(BASICCONSTRAINTSCHECKERSTATE); +} + +/* --Private-BasicConstraintsChecker-Functions------------------------------ */ + +/* + * FUNCTION: pkix_BasicConstraintsChecker_Check + * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h) + */ +PKIX_Error * +pkix_BasicConstraintsChecker_Check( + PKIX_CertChainChecker *checker, + PKIX_PL_Cert *cert, + PKIX_List *unresolvedCriticalExtensions, /* list of PKIX_PL_OID */ + void **pNBIOContext, + void *plContext) +{ + PKIX_PL_CertBasicConstraints *basicConstraints = NULL; + pkix_BasicConstraintsCheckerState *state = NULL; + PKIX_Boolean caFlag = PKIX_FALSE; + PKIX_Int32 pathLength = 0; + PKIX_Int32 maxPathLength_now; + PKIX_Boolean isSelfIssued = PKIX_FALSE; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_BasicConstraintsChecker_Check"); + PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext); + + *pNBIOContext = NULL; /* we never block on pending I/O */ + + PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState + (checker, (PKIX_PL_Object **)&state, plContext), + PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); + + state->certsRemaining--; + + if (state->certsRemaining != 0) { + + PKIX_CHECK(PKIX_PL_Cert_GetBasicConstraints + (cert, &basicConstraints, plContext), + PKIX_CERTGETBASICCONSTRAINTSFAILED); + + /* get CA Flag and path length */ + if (basicConstraints != NULL) { + PKIX_CHECK(PKIX_PL_BasicConstraints_GetCAFlag + (basicConstraints, + &caFlag, + plContext), + PKIX_BASICCONSTRAINTSGETCAFLAGFAILED); + + if (caFlag == PKIX_TRUE) { + PKIX_CHECK + (PKIX_PL_BasicConstraints_GetPathLenConstraint + (basicConstraints, + &pathLength, + plContext), + PKIX_BASICCONSTRAINTSGETPATHLENCONSTRAINTFAILED); + } + + }else{ + caFlag = PKIX_FALSE; + pathLength = PKIX_UNLIMITED_PATH_CONSTRAINT; + } + + PKIX_CHECK(pkix_IsCertSelfIssued + (cert, + &isSelfIssued, + plContext), + PKIX_ISCERTSELFISSUEDFAILED); + + maxPathLength_now = state->maxPathLength; + + if (isSelfIssued != PKIX_TRUE) { + + /* Not last CA Cert, but maxPathLength is down to zero */ + if (maxPathLength_now == 0) { + PKIX_ERROR(PKIX_BASICCONSTRAINTSVALIDATIONFAILEDLN); + } + + if (caFlag == PKIX_FALSE) { + PKIX_ERROR(PKIX_BASICCONSTRAINTSVALIDATIONFAILEDCA); + } + + if (maxPathLength_now > 0) { /* can be unlimited (-1) */ + maxPathLength_now--; + } + + } + + if (caFlag == PKIX_TRUE) { + if (maxPathLength_now == PKIX_UNLIMITED_PATH_CONSTRAINT){ + maxPathLength_now = pathLength; + } else { + /* If pathLength is not specified, don't set */ + if (pathLength != PKIX_UNLIMITED_PATH_CONSTRAINT) { + maxPathLength_now = + (maxPathLength_now > pathLength)? + pathLength:maxPathLength_now; + } + } + } + + state->maxPathLength = maxPathLength_now; + } + + /* Remove Basic Constraints Extension OID from list */ + if (unresolvedCriticalExtensions != NULL) { + + PKIX_CHECK(pkix_List_Remove + (unresolvedCriticalExtensions, + (PKIX_PL_Object *) state->basicConstraintsOID, + plContext), + PKIX_LISTREMOVEFAILED); + } + + + PKIX_CHECK(PKIX_CertChainChecker_SetCertChainCheckerState + (checker, (PKIX_PL_Object *)state, plContext), + PKIX_CERTCHAINCHECKERSETCERTCHAINCHECKERSTATEFAILED); + + +cleanup: + PKIX_DECREF(state); + PKIX_DECREF(basicConstraints); + PKIX_RETURN(CERTCHAINCHECKER); + +} + +/* + * FUNCTION: pkix_BasicConstraintsChecker_Initialize + * DESCRIPTION: + * Registers PKIX_CERT_TYPE and its related functions with systemClasses[] + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_BasicConstraintsChecker_Initialize( + PKIX_UInt32 certsRemaining, + PKIX_CertChainChecker **pChecker, + void *plContext) +{ + pkix_BasicConstraintsCheckerState *state = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_BasicConstraintsChecker_Initialize"); + PKIX_NULLCHECK_ONE(pChecker); + + PKIX_CHECK(pkix_BasicConstraintsCheckerState_Create + (certsRemaining, &state, plContext), + PKIX_BASICCONSTRAINTSCHECKERSTATECREATEFAILED); + + PKIX_CHECK(PKIX_CertChainChecker_Create + (pkix_BasicConstraintsChecker_Check, + PKIX_FALSE, + PKIX_FALSE, + NULL, + (PKIX_PL_Object *)state, + pChecker, + plContext), + PKIX_CERTCHAINCHECKERCHECKFAILED); + +cleanup: + PKIX_DECREF(state); + + PKIX_RETURN(CERTCHAINCHECKER); +} diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_basicconstraintschecker.h b/security/nss/lib/libpkix/pkix/checker/pkix_basicconstraintschecker.h new file mode 100644 index 0000000000..7a8b09c379 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_basicconstraintschecker.h @@ -0,0 +1,42 @@ +/* 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/. */ +/* + * pkix_basicconstraintschecker.h + * + * Header file for basic constraints checker. + * + */ + +#ifndef _PKIX_BASICCONSTRAINTSCHECKER_H +#define _PKIX_BASICCONSTRAINTSCHECKER_H + +#include "pkix_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pkix_BasicConstraintsCheckerStateStruct \ + pkix_BasicConstraintsCheckerState; + +struct pkix_BasicConstraintsCheckerStateStruct{ + PKIX_PL_OID *basicConstraintsOID; + PKIX_Int32 certsRemaining; + PKIX_Int32 maxPathLength; +}; + +PKIX_Error * +pkix_BasicConstraintsChecker_Initialize( + PKIX_UInt32 numCerts, + PKIX_CertChainChecker **pChecker, + void *plContext); + +PKIX_Error * +pkix_BasicConstraintsCheckerState_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_BASICCONSTRAINTSCHECKER_H */ diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_certchainchecker.c b/security/nss/lib/libpkix/pkix/checker/pkix_certchainchecker.c new file mode 100644 index 0000000000..a6ea50d02d --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_certchainchecker.c @@ -0,0 +1,322 @@ +/* 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/. */ +/* + * pkix_certchainchecker.c + * + * CertChainChecker Object Functions + * + */ + +#include "pkix_certchainchecker.h" + +/* --Private-Functions-------------------------------------------- */ + +/* + * FUNCTION: pkix_CertChainChecker_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_CertChainChecker_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_CertChainChecker *checker = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_CertChainChecker_Destroy"); + PKIX_NULLCHECK_ONE(object); + + /* Check that this object is a cert chain checker */ + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTCHAINCHECKER_TYPE, plContext), + PKIX_OBJECTNOTCERTCHAINCHECKER); + + checker = (PKIX_CertChainChecker *)object; + + PKIX_DECREF(checker->extensions); + PKIX_DECREF(checker->state); + +cleanup: + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_CertChainChecker_Duplicate + * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_CertChainChecker_Duplicate( + PKIX_PL_Object *object, + PKIX_PL_Object **pNewObject, + void *plContext) +{ + PKIX_CertChainChecker *checker = NULL; + PKIX_CertChainChecker *checkerDuplicate = NULL; + PKIX_List *extensionsDuplicate = NULL; + PKIX_PL_Object *stateDuplicate = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_CertChainChecker_Duplicate"); + PKIX_NULLCHECK_TWO(object, pNewObject); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTCHAINCHECKER_TYPE, plContext), + PKIX_OBJECTNOTCERTCHAINCHECKER); + + checker = (PKIX_CertChainChecker *)object; + + if (checker->extensions){ + PKIX_CHECK(PKIX_PL_Object_Duplicate + ((PKIX_PL_Object *)checker->extensions, + (PKIX_PL_Object **)&extensionsDuplicate, + plContext), + PKIX_OBJECTDUPLICATEFAILED); + } + + if (checker->state){ + PKIX_CHECK(PKIX_PL_Object_Duplicate + ((PKIX_PL_Object *)checker->state, + (PKIX_PL_Object **)&stateDuplicate, + plContext), + PKIX_OBJECTDUPLICATEFAILED); + } + + PKIX_CHECK(PKIX_CertChainChecker_Create + (checker->checkCallback, + checker->forwardChecking, + checker->isForwardDirectionExpected, + extensionsDuplicate, + stateDuplicate, + &checkerDuplicate, + plContext), + PKIX_CERTCHAINCHECKERCREATEFAILED); + + *pNewObject = (PKIX_PL_Object *)checkerDuplicate; + +cleanup: + + PKIX_DECREF(extensionsDuplicate); + PKIX_DECREF(stateDuplicate); + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_CertChainChecker_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERTCHAINCHECKER_TYPE and its related functions with + * systemClasses[] + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_CertChainChecker_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_CertChainChecker_RegisterSelf"); + + entry.description = "CertChainChecker"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_CertChainChecker); + entry.destructor = pkix_CertChainChecker_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = pkix_CertChainChecker_Duplicate; + + systemClasses[PKIX_CERTCHAINCHECKER_TYPE] = entry; + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* --Public-Functions--------------------------------------------- */ + + +/* + * FUNCTION: PKIX_CertChainChecker_Create (see comments in pkix_checker.h) + */ +PKIX_Error * +PKIX_CertChainChecker_Create( + PKIX_CertChainChecker_CheckCallback callback, + PKIX_Boolean forwardCheckingSupported, + PKIX_Boolean isForwardDirectionExpected, + PKIX_List *list, /* list of PKIX_PL_OID */ + PKIX_PL_Object *initialState, + PKIX_CertChainChecker **pChecker, + void *plContext) +{ + PKIX_CertChainChecker *checker = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "PKIX_CertChainChecker_Create"); + PKIX_NULLCHECK_ONE(pChecker); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTCHAINCHECKER_TYPE, + sizeof (PKIX_CertChainChecker), + (PKIX_PL_Object **)&checker, + plContext), + PKIX_COULDNOTCREATECERTCHAINCHECKEROBJECT); + + /* initialize fields */ + checker->checkCallback = callback; + checker->forwardChecking = forwardCheckingSupported; + checker->isForwardDirectionExpected = isForwardDirectionExpected; + + PKIX_INCREF(list); + checker->extensions = list; + + PKIX_INCREF(initialState); + checker->state = initialState; + + *pChecker = checker; + checker = NULL; +cleanup: + + PKIX_DECREF(checker); + + PKIX_RETURN(CERTCHAINCHECKER); + +} + +/* + * FUNCTION: PKIX_CertChainChecker_GetCheckCallback + * (see comments in pkix_checker.h) + */ +PKIX_Error * +PKIX_CertChainChecker_GetCheckCallback( + PKIX_CertChainChecker *checker, + PKIX_CertChainChecker_CheckCallback *pCallback, + void *plContext) +{ + PKIX_ENTER(CERTCHAINCHECKER, "PKIX_CertChainChecker_GetCheckCallback"); + PKIX_NULLCHECK_TWO(checker, pCallback); + + *pCallback = checker->checkCallback; + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: PKIX_CertChainChecker_IsForwardCheckingSupported + * (see comments in pkix_checker.h) + */ +PKIX_Error * +PKIX_CertChainChecker_IsForwardCheckingSupported( + PKIX_CertChainChecker *checker, + PKIX_Boolean *pForwardCheckingSupported, + void *plContext) +{ + PKIX_ENTER + (CERTCHAINCHECKER, + "PKIX_CertChainChecker_IsForwardCheckingSupported"); + PKIX_NULLCHECK_TWO(checker, pForwardCheckingSupported); + + *pForwardCheckingSupported = checker->forwardChecking; + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: PKIX_CertChainChecker_IsForwardDirectionExpected + * (see comments in pkix_checker.h) + */ +PKIX_Error * +PKIX_CertChainChecker_IsForwardDirectionExpected( + PKIX_CertChainChecker *checker, + PKIX_Boolean *pForwardDirectionExpected, + void *plContext) +{ + PKIX_ENTER + (CERTCHAINCHECKER, + "PKIX_CertChainChecker_IsForwardDirectionExpected"); + PKIX_NULLCHECK_TWO(checker, pForwardDirectionExpected); + + *pForwardDirectionExpected = checker->isForwardDirectionExpected; + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: PKIX_CertChainChecker_GetCertChainCheckerState + * (see comments in pkix_checker.h) + */ +PKIX_Error * +PKIX_CertChainChecker_GetCertChainCheckerState( + PKIX_CertChainChecker *checker, + PKIX_PL_Object **pCertChainCheckerState, + void *plContext) +{ + PKIX_ENTER(CERTCHAINCHECKER, + "PKIX_CertChainChecker_GetCertChainCheckerState"); + + PKIX_NULLCHECK_TWO(checker, pCertChainCheckerState); + + PKIX_INCREF(checker->state); + + *pCertChainCheckerState = checker->state; + +cleanup: + PKIX_RETURN(CERTCHAINCHECKER); + +} + +/* + * FUNCTION: PKIX_CertChainChecker_SetCertChainCheckerState + * (see comments in pkix_checker.h) + */ +PKIX_Error * +PKIX_CertChainChecker_SetCertChainCheckerState( + PKIX_CertChainChecker *checker, + PKIX_PL_Object *certChainCheckerState, + void *plContext) +{ + PKIX_ENTER(CERTCHAINCHECKER, + "PKIX_CertChainChecker_SetCertChainCheckerState"); + + PKIX_NULLCHECK_ONE(checker); + + /* DecRef old contents */ + PKIX_DECREF(checker->state); + + PKIX_INCREF(certChainCheckerState); + checker->state = certChainCheckerState; + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)checker, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + +cleanup: + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: PKIX_CertChainChecker_GetSupportedExtensions + * (see comments in pkix_checker.h) + */ +PKIX_Error * +PKIX_CertChainChecker_GetSupportedExtensions( + PKIX_CertChainChecker *checker, + PKIX_List **pExtensions, /* list of PKIX_PL_OID */ + void *plContext) +{ + PKIX_ENTER(CERTCHAINCHECKER, + "PKIX_CertChainChecker_GetSupportedExtensions"); + + PKIX_NULLCHECK_TWO(checker, pExtensions); + + PKIX_INCREF(checker->extensions); + + *pExtensions = checker->extensions; + +cleanup: + PKIX_RETURN(CERTCHAINCHECKER); + +} diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_certchainchecker.h b/security/nss/lib/libpkix/pkix/checker/pkix_certchainchecker.h new file mode 100644 index 0000000000..ff6454761e --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_certchainchecker.h @@ -0,0 +1,36 @@ +/* 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/. */ +/* + * pkix_certchainchecker.h + * + * CertChainChecker Object Type Definition + * + */ + +#ifndef _PKIX_CERTCHAINCHECKER_H +#define _PKIX_CERTCHAINCHECKER_H + +#include "pkix_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_CertChainCheckerStruct { + PKIX_CertChainChecker_CheckCallback checkCallback; + PKIX_List *extensions; + PKIX_PL_Object *state; + PKIX_Boolean forwardChecking; + PKIX_Boolean isForwardDirectionExpected; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_CertChainChecker_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_CERTCHAINCHECKER_H */ diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_crlchecker.c b/security/nss/lib/libpkix/pkix/checker/pkix_crlchecker.c new file mode 100644 index 0000000000..d6f5b6bcc8 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_crlchecker.c @@ -0,0 +1,438 @@ +/* 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/. */ +/* + * pkix_defaultcrlchecker.c + * + * Functions for default CRL Checkers + * + */ +#include "pkix.h" +#include "pkix_crlchecker.h" +#include "pkix_tools.h" + +/* --Private-CRLChecker-Data-and-Types------------------------------- */ + +typedef struct pkix_CrlCheckerStruct { + /* RevocationMethod is the super class of CrlChecker. */ + pkix_RevocationMethod method; + PKIX_List *certStores; /* list of CertStore */ + PKIX_PL_VerifyCallback crlVerifyFn; +} pkix_CrlChecker; + + +/* --Private-CRLChecker-Functions----------------------------------- */ + +/* + * FUNCTION: pkix_CrlCheckerstate_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_CrlChecker_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + pkix_CrlChecker *state = NULL; + + PKIX_ENTER(CRLCHECKER, "pkix_CrlChecker_Destroy"); + PKIX_NULLCHECK_ONE(object); + + /* Check that this object is a default CRL checker state */ + PKIX_CHECK( + pkix_CheckType(object, PKIX_CRLCHECKER_TYPE, plContext), + PKIX_OBJECTNOTCRLCHECKER); + + state = (pkix_CrlChecker *)object; + + PKIX_DECREF(state->certStores); + +cleanup: + + PKIX_RETURN(CRLCHECKER); +} + +/* + * FUNCTION: pkix_CrlChecker_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_CRLCHECKER_TYPE and its related functions + * with systemClasses[] + * + * THREAD SAFETY: + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_CrlChecker_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry* entry = &systemClasses[PKIX_CRLCHECKER_TYPE]; + + PKIX_ENTER(CRLCHECKER, "pkix_CrlChecker_RegisterSelf"); + + entry->description = "CRLChecker"; + entry->typeObjectSize = sizeof(pkix_CrlChecker); + entry->destructor = pkix_CrlChecker_Destroy; + + PKIX_RETURN(CRLCHECKER); +} + +/* + * FUNCTION: pkix_CrlChecker_Create + * + * DESCRIPTION: + * Allocate and initialize CRLChecker state data. + * + * PARAMETERS + * "certStores" + * Address of CertStore List to be stored in state. Must be non-NULL. + * "testDate" + * Address of PKIX_PL_Date to be checked. May be NULL. + * "trustedPubKey" + * Trusted Anchor Public Key for verifying first Cert in the chain. + * Must be non-NULL. + * "certsRemaining" + * Number of certificates remaining in the chain. + * "nistCRLPolicyEnabled" + * If enabled, enforce nist crl policy. + * "pChecker" + * Address of CRLChecker that is returned. Must be non-NULL. + * "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 DefaultCrlChecker Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error + */ +PKIX_Error * +pkix_CrlChecker_Create(PKIX_RevocationMethodType methodType, + PKIX_UInt32 flags, + PKIX_UInt32 priority, + pkix_LocalRevocationCheckFn localRevChecker, + pkix_ExternalRevocationCheckFn externalRevChecker, + PKIX_List *certStores, + PKIX_PL_VerifyCallback crlVerifyFn, + pkix_RevocationMethod **pChecker, + void *plContext) +{ + pkix_CrlChecker *crlChecker = NULL; + + PKIX_ENTER(CRLCHECKER, "pkix_CrlChecker_Create"); + PKIX_NULLCHECK_TWO(certStores, pChecker); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CRLCHECKER_TYPE, + sizeof (pkix_CrlChecker), + (PKIX_PL_Object **)&crlChecker, + plContext), + PKIX_COULDNOTCREATECRLCHECKEROBJECT); + + pkixErrorResult = pkix_RevocationMethod_Init( + (pkix_RevocationMethod*)crlChecker, methodType, flags, priority, + localRevChecker, externalRevChecker, plContext); + if (pkixErrorResult) { + goto cleanup; + } + + /* Initialize fields */ + PKIX_INCREF(certStores); + crlChecker->certStores = certStores; + + crlChecker->crlVerifyFn = crlVerifyFn; + *pChecker = (pkix_RevocationMethod*)crlChecker; + crlChecker = NULL; + +cleanup: + PKIX_DECREF(crlChecker); + + PKIX_RETURN(CRLCHECKER); +} + +/* --Private-CRLChecker-Functions------------------------------------ */ + +/* + * FUNCTION: pkix_CrlChecker_CheckLocal + * + * DESCRIPTION: + * Check if the Cert has been revoked based the CRLs data. This function + * maintains the checker state to be current. + * + * PARAMETERS + * "checker" + * Address of CertChainChecker which has the state data. + * Must be non-NULL. + * "cert" + * Address of Certificate that is to be validated. Must be non-NULL. + * "unreslvdCrtExts" + * A List OIDs. Not **yet** used in this checker function. + * "plContext" + * Platform-specific context pointer. + * + * THREAD SAFETY: + * Not Thread Safe + * (see Thread Safety Definitions in Programmer's Guide) + * + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertChainChecker Error if the function fails in a non-fatal way. + * Returns a Fatal Error + */ +PKIX_Error * +pkix_CrlChecker_CheckLocal( + PKIX_PL_Cert *cert, + PKIX_PL_Cert *issuer, + PKIX_PL_Date *date, + pkix_RevocationMethod *checkerObject, + PKIX_ProcessingParams *procParams, + PKIX_UInt32 methodFlags, + PKIX_Boolean chainVerificationState, + PKIX_RevocationStatus *pRevStatus, + CERTCRLEntryReasonCode *pReasonCode, + void *plContext) +{ + PKIX_CertStore_CheckRevokationByCrlCallback storeCheckRevocationFn; + PKIX_CertStore *certStore = NULL; + pkix_CrlChecker *state = NULL; + PKIX_UInt32 crlStoreIndex = 0; + PKIX_UInt32 numCrlStores = 0; + PKIX_Boolean storeIsLocal = PKIX_FALSE; + PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_CrlChecker_CheckLocal"); + PKIX_NULLCHECK_FOUR(cert, issuer, checkerObject, checkerObject); + + state = (pkix_CrlChecker*)checkerObject; + + PKIX_CHECK( + PKIX_List_GetLength(state->certStores, &numCrlStores, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (;crlStoreIndex < numCrlStores;crlStoreIndex++) { + PKIX_CHECK( + PKIX_List_GetItem(state->certStores, crlStoreIndex, + (PKIX_PL_Object **)&certStore, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK( + PKIX_CertStore_GetLocalFlag(certStore, &storeIsLocal, + plContext), + PKIX_CERTSTOREGETLOCALFLAGFAILED); + if (storeIsLocal) { + PKIX_CHECK( + PKIX_CertStore_GetCrlCheckerFn(certStore, + &storeCheckRevocationFn, + plContext), + PKIX_CERTSTOREGETCHECKREVBYCRLFAILED); + + if (storeCheckRevocationFn) { + PKIX_CHECK( + (*storeCheckRevocationFn)(certStore, cert, issuer, + /* delay sig check if building + * a chain by not specifying the time*/ + chainVerificationState ? date : NULL, + /* crl downloading is not done. */ + PKIX_FALSE, + pReasonCode, &revStatus, plContext), + PKIX_CERTSTORECRLCHECKFAILED); + if (revStatus == PKIX_RevStatus_Revoked) { + break; + } + } + } + PKIX_DECREF(certStore); + } /* while */ + +cleanup: + *pRevStatus = revStatus; + PKIX_DECREF(certStore); + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_CrlChecker_CheckRemote + * + * DESCRIPTION: + * Check if the Cert has been revoked based the CRLs data. This function + * maintains the checker state to be current. + * + * PARAMETERS + * "checker" + * Address of CertChainChecker which has the state data. + * Must be non-NULL. + * "cert" + * Address of Certificate that is to be validated. Must be non-NULL. + * "unreslvdCrtExts" + * A List OIDs. Not **yet** used in this checker function. + * "plContext" + * Platform-specific context pointer. + * + * THREAD SAFETY: + * Not Thread Safe + * (see Thread Safety Definitions in Programmer's Guide) + * + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a CertChainChecker Error if the function fails in a non-fatal way. + * Returns a Fatal Error + */ +PKIX_Error * +pkix_CrlChecker_CheckExternal( + PKIX_PL_Cert *cert, + PKIX_PL_Cert *issuer, + PKIX_PL_Date *date, + pkix_RevocationMethod *checkerObject, + PKIX_ProcessingParams *procParams, + PKIX_UInt32 methodFlags, + PKIX_RevocationStatus *pRevStatus, + CERTCRLEntryReasonCode *pReasonCode, + void **pNBIOContext, + void *plContext) +{ + PKIX_CertStore_CheckRevokationByCrlCallback storeCheckRevocationFn = NULL; + PKIX_CertStore_ImportCrlCallback storeImportCrlFn = NULL; + PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; + PKIX_CertStore *certStore = NULL; + PKIX_CertStore *localStore = NULL; + PKIX_CRLSelector *crlSelector = NULL; + PKIX_PL_X500Name *issuerName = NULL; + pkix_CrlChecker *state = NULL; + PKIX_UInt32 crlStoreIndex = 0; + PKIX_UInt32 numCrlStores = 0; + PKIX_Boolean storeIsLocal = PKIX_FALSE; + PKIX_List *crlList = NULL; + PKIX_List *dpList = NULL; + void *nbioContext = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_CrlChecker_CheckExternal"); + PKIX_NULLCHECK_FOUR(cert, issuer, checkerObject, pNBIOContext); + + nbioContext = *pNBIOContext; + *pNBIOContext = NULL; /* prepare for Error exit */ + + state = (pkix_CrlChecker*)checkerObject; + + PKIX_CHECK( + PKIX_List_GetLength(state->certStores, &numCrlStores, plContext), + PKIX_LISTGETLENGTHFAILED); + + /* Find a cert store that is capable of storing crls */ + for (;crlStoreIndex < numCrlStores;crlStoreIndex++) { + PKIX_CHECK( + PKIX_List_GetItem(state->certStores, crlStoreIndex, + (PKIX_PL_Object **)&certStore, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK( + PKIX_CertStore_GetLocalFlag(certStore, &storeIsLocal, + plContext), + PKIX_CERTSTOREGETLOCALFLAGFAILED); + if (storeIsLocal) { + PKIX_CHECK( + PKIX_CertStore_GetImportCrlCallback(certStore, + &storeImportCrlFn, + plContext), + PKIX_CERTSTOREGETCHECKREVBYCRLFAILED); + + PKIX_CHECK( + PKIX_CertStore_GetCrlCheckerFn(certStore, + &storeCheckRevocationFn, + plContext), + PKIX_CERTSTOREGETCHECKREVBYCRLFAILED); + + if (storeImportCrlFn && storeCheckRevocationFn) { + localStore = certStore; + certStore = NULL; + break; + } + } + PKIX_DECREF(certStore); + } /* while */ + + /* Report unknown status if we can not check crl in one of the + * local stores. */ + if (!localStore) { + PKIX_ERROR_FATAL(PKIX_CRLCHECKERNOLOCALCERTSTOREFOUND); + } + PKIX_CHECK( + PKIX_PL_Cert_VerifyKeyUsage(issuer, PKIX_CRL_SIGN, plContext), + PKIX_CERTCHECKKEYUSAGEFAILED); + PKIX_CHECK( + PKIX_PL_Cert_GetCrlDp(cert, &dpList, plContext), + PKIX_CERTGETCRLDPFAILED); + if (!(methodFlags & PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE) && + (!dpList || !dpList->length)) { + goto cleanup; + } + PKIX_CHECK( + PKIX_PL_Cert_GetIssuer(cert, &issuerName, plContext), + PKIX_CERTGETISSUERFAILED); + PKIX_CHECK( + PKIX_CRLSelector_Create(issuer, dpList, date, &crlSelector, plContext), + PKIX_CRLCHECKERSETSELECTORFAILED); + /* Fetch crl and store in a local cert store */ + for (crlStoreIndex = 0;crlStoreIndex < numCrlStores;crlStoreIndex++) { + PKIX_CertStore_CRLCallback getCrlsFn; + + PKIX_CHECK( + PKIX_List_GetItem(state->certStores, crlStoreIndex, + (PKIX_PL_Object **)&certStore, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK( + PKIX_CertStore_GetCRLCallback(certStore, &getCrlsFn, + plContext), + PKIX_CERTSTOREGETCRLCALLBACKFAILED); + + PKIX_CHECK( + (*getCrlsFn)(certStore, crlSelector, &nbioContext, + &crlList, plContext), + PKIX_GETCRLSFAILED); + + PKIX_CHECK( + (*storeImportCrlFn)(localStore, issuerName, crlList, plContext), + PKIX_CERTSTOREFAILTOIMPORTCRLLIST); + + PKIX_CHECK( + (*storeCheckRevocationFn)(certStore, cert, issuer, date, + /* done with crl downloading */ + PKIX_TRUE, + pReasonCode, &revStatus, plContext), + PKIX_CERTSTORECRLCHECKFAILED); + if (revStatus != PKIX_RevStatus_NoInfo) { + break; + } + PKIX_DECREF(crlList); + PKIX_DECREF(certStore); + } /* while */ + +cleanup: + /* Update return flags */ + if (revStatus == PKIX_RevStatus_NoInfo && + ((dpList && dpList->length > 0) || + (methodFlags & PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE)) && + methodFlags & PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) { + revStatus = PKIX_RevStatus_Revoked; + } + *pRevStatus = revStatus; + + PKIX_DECREF(dpList); + PKIX_DECREF(crlList); + PKIX_DECREF(certStore); + PKIX_DECREF(issuerName); + PKIX_DECREF(localStore); + PKIX_DECREF(crlSelector); + + PKIX_RETURN(CERTCHAINCHECKER); +} diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_crlchecker.h b/security/nss/lib/libpkix/pkix/checker/pkix_crlchecker.h new file mode 100644 index 0000000000..35f1a47455 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_crlchecker.h @@ -0,0 +1,68 @@ +/* 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/. */ +/* + * pkix_defaultcrlchecker.h + * + * Header file for default CRL function + * + */ + +#ifndef _PKIX_CRLCHECKER_H +#define _PKIX_CRLCHECKER_H + +#include "pkixt.h" +#include "pkix_revocationmethod.h" +#include "pkix_crlsel.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: nbio logic removed. Will be replaced later. */ + +PKIX_Error * +pkix_CrlChecker_CheckLocal( + PKIX_PL_Cert *cert, + PKIX_PL_Cert *issuer, + PKIX_PL_Date *date, + pkix_RevocationMethod *checkerObject, + PKIX_ProcessingParams *procParams, + PKIX_UInt32 methodFlags, + PKIX_Boolean chainVerificationState, + PKIX_RevocationStatus *pRevStatus, + CERTCRLEntryReasonCode *reasonCode, + void *plContext); + +PKIX_Error * +pkix_CrlChecker_CheckExternal( + PKIX_PL_Cert *cert, + PKIX_PL_Cert *issuer, + PKIX_PL_Date *date, + pkix_RevocationMethod *checkerObject, + PKIX_ProcessingParams *procParams, + PKIX_UInt32 methodFlags, + PKIX_RevocationStatus *pRevStatus, + CERTCRLEntryReasonCode *reasonCode, + void **pNBIOContext, + void *plContext); + +PKIX_Error * +pkix_CrlChecker_Create(PKIX_RevocationMethodType methodType, + PKIX_UInt32 flags, + PKIX_UInt32 priority, + pkix_LocalRevocationCheckFn localRevChecker, + pkix_ExternalRevocationCheckFn externalRevChecker, + PKIX_List *certStores, + PKIX_PL_VerifyCallback crlVerifyFn, + pkix_RevocationMethod **pChecker, + void *plContext); + +PKIX_Error * +pkix_CrlChecker_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_CRLCHECKER_H */ diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_ekuchecker.c b/security/nss/lib/libpkix/pkix/checker/pkix_ekuchecker.c new file mode 100644 index 0000000000..a2b8437397 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_ekuchecker.c @@ -0,0 +1,328 @@ +/* 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/. */ +/* + * pkix_ekuchecker.c + * + * User Defined ExtenedKeyUsage Function Definitions + * + */ + +#include "pkix_ekuchecker.h" + +SECOidTag ekuOidStrings[] = { + PKIX_KEY_USAGE_SERVER_AUTH_OID, + PKIX_KEY_USAGE_CLIENT_AUTH_OID, + PKIX_KEY_USAGE_CODE_SIGN_OID, + PKIX_KEY_USAGE_EMAIL_PROTECT_OID, + PKIX_KEY_USAGE_TIME_STAMP_OID, + PKIX_KEY_USAGE_OCSP_RESPONDER_OID, + PKIX_UNKNOWN_OID +}; + +typedef struct pkix_EkuCheckerStruct { + PKIX_List *requiredExtKeyUsageOids; + PKIX_PL_OID *ekuOID; +} pkix_EkuChecker; + + +/* + * FUNCTION: pkix_EkuChecker_Destroy + * (see comments for PKIX_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_EkuChecker_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + pkix_EkuChecker *ekuCheckerState = NULL; + + PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_EKUCHECKER_TYPE, plContext), + PKIX_OBJECTNOTANEKUCHECKERSTATE); + + ekuCheckerState = (pkix_EkuChecker *)object; + + PKIX_DECREF(ekuCheckerState->ekuOID); + PKIX_DECREF(ekuCheckerState->requiredExtKeyUsageOids); + +cleanup: + + PKIX_RETURN(EKUCHECKER); +} + +/* + * FUNCTION: pkix_EkuChecker_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_PL_HTTPCERTSTORECONTEXT_TYPE and its related + * functions with systemClasses[] + * + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_EkuChecker_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry *entry = &systemClasses[PKIX_EKUCHECKER_TYPE]; + + PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_RegisterSelf"); + + entry->description = "EkuChecker"; + entry->typeObjectSize = sizeof(pkix_EkuChecker); + entry->destructor = pkix_EkuChecker_Destroy; + + PKIX_RETURN(EKUCHECKER); +} + +/* + * FUNCTION: pkix_EkuChecker_Create + * DESCRIPTION: + * + * Creates a new Extend Key Usage CheckerState using "params" to retrieve + * application specified EKU for verification and stores it at "pState". + * + * PARAMETERS: + * "params" + * a PKIX_ProcessingParams links to PKIX_ComCertSelParams where a list of + * Extended Key Usage OIDs specified by application can be retrieved for + * verification. + * "pState" + * Address where state pointer will be stored. Must be non-NULL. + * "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 UserDefinedModules Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_EkuChecker_Create( + PKIX_ProcessingParams *params, + pkix_EkuChecker **pState, + void *plContext) +{ + pkix_EkuChecker *state = NULL; + PKIX_CertSelector *certSelector = NULL; + PKIX_ComCertSelParams *comCertSelParams = NULL; + PKIX_List *requiredOids = NULL; + + PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_Create"); + PKIX_NULLCHECK_TWO(params, pState); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_EKUCHECKER_TYPE, + sizeof (pkix_EkuChecker), + (PKIX_PL_Object **)&state, + plContext), + PKIX_COULDNOTCREATEEKUCHECKERSTATEOBJECT); + + + PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints + (params, &certSelector, plContext), + PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED); + + if (certSelector != NULL) { + + /* Get initial EKU OIDs from ComCertSelParams, if set */ + PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams + (certSelector, &comCertSelParams, plContext), + PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED); + + if (comCertSelParams != NULL) { + PKIX_CHECK(PKIX_ComCertSelParams_GetExtendedKeyUsage + (comCertSelParams, &requiredOids, plContext), + PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED); + + } + } + + PKIX_CHECK(PKIX_PL_OID_Create + (PKIX_EXTENDEDKEYUSAGE_OID, + &state->ekuOID, + plContext), + PKIX_OIDCREATEFAILED); + + state->requiredExtKeyUsageOids = requiredOids; + requiredOids = NULL; + *pState = state; + state = NULL; + +cleanup: + + PKIX_DECREF(certSelector); + PKIX_DECREF(comCertSelParams); + PKIX_DECREF(requiredOids); + PKIX_DECREF(state); + + PKIX_RETURN(EKUCHECKER); +} + +/* + * FUNCTION: pkix_EkuChecker_Check + * DESCRIPTION: + * + * This function determines the Extended Key Usage OIDs specified by the + * application is included in the Extended Key Usage OIDs of this "cert". + * + * PARAMETERS: + * "checker" + * Address of CertChainChecker which has the state data. + * Must be non-NULL. + * "cert" + * Address of Certificate that is to be validated. Must be non-NULL. + * "unresolvedCriticalExtensions" + * A List OIDs. The OID for Extended Key Usage is removed. + * "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 UserDefinedModules Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_EkuChecker_Check( + PKIX_CertChainChecker *checker, + PKIX_PL_Cert *cert, + PKIX_List *unresolvedCriticalExtensions, + void **pNBIOContext, + void *plContext) +{ + pkix_EkuChecker *state = NULL; + PKIX_List *requiredExtKeyUsageList = NULL; + PKIX_List *certExtKeyUsageList = NULL; + PKIX_PL_OID *ekuOid = NULL; + PKIX_Boolean isContained = PKIX_FALSE; + PKIX_UInt32 numItems = 0; + PKIX_UInt32 i; + PKIX_Boolean checkResult = PKIX_TRUE; + + PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_Check"); + PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext); + + *pNBIOContext = NULL; /* no non-blocking IO */ + + PKIX_CHECK( + PKIX_CertChainChecker_GetCertChainCheckerState + (checker, (PKIX_PL_Object **)&state, plContext), + PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); + + requiredExtKeyUsageList = state->requiredExtKeyUsageOids; + if (requiredExtKeyUsageList == NULL) { + goto cleanup; + } + + PKIX_CHECK( + PKIX_List_GetLength(requiredExtKeyUsageList, &numItems, + plContext), + PKIX_LISTGETLENGTHFAILED); + if (numItems == 0) { + goto cleanup; + } + + PKIX_CHECK( + PKIX_PL_Cert_GetExtendedKeyUsage(cert, &certExtKeyUsageList, + plContext), + PKIX_CERTGETEXTENDEDKEYUSAGEFAILED); + + if (certExtKeyUsageList == NULL) { + goto cleanup; + } + + for (i = 0; i < numItems; i++) { + + PKIX_CHECK( + PKIX_List_GetItem(requiredExtKeyUsageList, i, + (PKIX_PL_Object **)&ekuOid, plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK( + pkix_List_Contains(certExtKeyUsageList, + (PKIX_PL_Object *)ekuOid, + &isContained, + plContext), + PKIX_LISTCONTAINSFAILED); + + PKIX_DECREF(ekuOid); + if (isContained != PKIX_TRUE) { + checkResult = PKIX_FALSE; + goto cleanup; + } + } + +cleanup: + if (!pkixErrorResult && checkResult == PKIX_FALSE) { + pkixErrorReceived = PKIX_TRUE; + pkixErrorCode = PKIX_EXTENDEDKEYUSAGECHECKINGFAILED; + } + + PKIX_DECREF(ekuOid); + PKIX_DECREF(certExtKeyUsageList); + PKIX_DECREF(state); + + PKIX_RETURN(EKUCHECKER); +} + +/* + * FUNCTION: pkix_EkuChecker_Initialize + * (see comments in pkix_sample_modules.h) + */ +PKIX_Error * +PKIX_EkuChecker_Create( + PKIX_ProcessingParams *params, + PKIX_CertChainChecker **pEkuChecker, + void *plContext) +{ + pkix_EkuChecker *state = NULL; + PKIX_List *critExtOIDsList = NULL; + + PKIX_ENTER(EKUCHECKER, "PKIX_EkuChecker_Initialize"); + PKIX_NULLCHECK_ONE(params); + + /* + * This function and functions in this file provide an example of how + * an application defined checker can be hooked into libpkix. + */ + + PKIX_CHECK(pkix_EkuChecker_Create + (params, &state, plContext), + PKIX_EKUCHECKERSTATECREATEFAILED); + + PKIX_CHECK(PKIX_List_Create(&critExtOIDsList, plContext), + PKIX_LISTCREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (critExtOIDsList, + (PKIX_PL_Object *)state->ekuOID, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_CHECK(PKIX_CertChainChecker_Create + (pkix_EkuChecker_Check, + PKIX_TRUE, /* forwardCheckingSupported */ + PKIX_FALSE, /* forwardDirectionExpected */ + critExtOIDsList, + (PKIX_PL_Object *) state, + pEkuChecker, + plContext), + PKIX_CERTCHAINCHECKERCREATEFAILED); +cleanup: + + PKIX_DECREF(critExtOIDsList); + PKIX_DECREF(state); + + PKIX_RETURN(EKUCHECKER); +} diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_ekuchecker.h b/security/nss/lib/libpkix/pkix/checker/pkix_ekuchecker.h new file mode 100644 index 0000000000..e542dda20b --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_ekuchecker.h @@ -0,0 +1,92 @@ +/* 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/. */ +/* + * pkix_ekuchecker.h + * + * User Defined Object Type Extended Key Usage Definition + * + */ + +#ifndef _PKIX_EKUCHECKER_H +#define _PKIX_EKUCHECKER_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * FUNCTION: PKIX_PL_EkuChecker_Create + * + * DESCRIPTION: + * Create a CertChainChecker with EkuCheckerState and add it into + * PKIX_ProcessingParams object. + * + * PARAMETERS + * "params" + * a PKIX_ProcessingParams links to PKIX_ComCertSelParams where a list of + * Extended Key Usage OIDs specified by application can be retrieved for + * verification. + * "ekuChecker" + * Address of created ekuchecker. + * "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 UserDefinedModules Error if the function fails in a non-fatal + * way. + * Returns a Fatal Error + */ +PKIX_Error * +PKIX_EkuChecker_Create( + PKIX_ProcessingParams *params, + PKIX_CertChainChecker **ekuChecker, + void *plContext); + +/* + * FUNCTION: PKIX_PL_EkuChecker_GetRequiredEku + * + * DESCRIPTION: + * This function retrieves application specified ExtenedKeyUsage(s) from + * ComCertSetparams and converts its OID representations to SECCertUsageEnum. + * The result is stored and returned in bit mask at "pRequiredExtKeyUsage". + * + * PARAMETERS + * "certSelector" + * a PKIX_CertSelector links to PKIX_ComCertSelParams where a list of + * Extended Key Usage OIDs specified by application can be retrieved for + * verification. Must be non-NULL. + * "pRequiredExtKeyUsage" + * Address where the result is returned. Must be non-NULL. + * "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 UserDefinedModules Error if the function fails in a non-fatal + * way. + * Returns a Fatal Error + */ +PKIX_Error * +pkix_EkuChecker_GetRequiredEku( + PKIX_CertSelector *certSelector, + PKIX_UInt32 *pRequiredExtKeyUsage, + void *plContext); + +/* see source file for function documentation */ +PKIX_Error *pkix_EkuChecker_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_EKUCHECKER_H */ diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_expirationchecker.c b/security/nss/lib/libpkix/pkix/checker/pkix_expirationchecker.c new file mode 100644 index 0000000000..4f101ee29b --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_expirationchecker.c @@ -0,0 +1,113 @@ +/* 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/. */ +/* + * pkix_expirationchecker.c + * + * Functions for expiration validation + * + */ + + +#include "pkix_expirationchecker.h" + +/* --Private-Functions-------------------------------------------- */ + +/* + * FUNCTION: pkix_ExpirationChecker_Check + * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h) + */ +PKIX_Error * +pkix_ExpirationChecker_Check( + PKIX_CertChainChecker *checker, + PKIX_PL_Cert *cert, + PKIX_List *unresolvedCriticalExtensions, + void **pNBIOContext, + void *plContext) +{ + PKIX_PL_Date *testDate = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_ExpirationChecker_Check"); + PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext); + + *pNBIOContext = NULL; /* we never block on pending I/O */ + + PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState + (checker, (PKIX_PL_Object **)&testDate, plContext), + PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); + + PKIX_CHECK(PKIX_PL_Cert_CheckValidity(cert, testDate, plContext), + PKIX_CERTCHECKVALIDITYFAILED); + +cleanup: + + PKIX_DECREF(testDate); + + PKIX_RETURN(CERTCHAINCHECKER); + +} + +/* + * FUNCTION: pkix_ExpirationChecker_Initialize + * DESCRIPTION: + * + * Creates a new CertChainChecker and stores it at "pChecker", where it will + * used by pkix_ExpirationChecker_Check to check that the certificate has not + * expired with respect to the Date pointed to by "testDate." If "testDate" + * is NULL, then the CertChainChecker will check that a certificate has not + * expired with respect to the current date and time. + * + * PARAMETERS: + * "testDate" + * Address of Date representing the point in time at which the cert is to + * be validated. If "testDate" is NULL, the current date and time is used. + * "pChecker" + * Address where object pointer will be stored. Must be non-NULL. + * "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 CertChainChecker Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_ExpirationChecker_Initialize( + PKIX_PL_Date *testDate, + PKIX_CertChainChecker **pChecker, + void *plContext) +{ + PKIX_PL_Date *myDate = NULL; + PKIX_PL_Date *nowDate = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_ExpirationChecker_Initialize"); + PKIX_NULLCHECK_ONE(pChecker); + + /* if testDate is NULL, we use the current time */ + if (!testDate){ + PKIX_CHECK(PKIX_PL_Date_Create_UTCTime + (NULL, &nowDate, plContext), + PKIX_DATECREATEUTCTIMEFAILED); + myDate = nowDate; + } else { + myDate = testDate; + } + + PKIX_CHECK(PKIX_CertChainChecker_Create + (pkix_ExpirationChecker_Check, + PKIX_TRUE, + PKIX_FALSE, + NULL, + (PKIX_PL_Object *)myDate, + pChecker, + plContext), + PKIX_CERTCHAINCHECKERCREATEFAILED); + +cleanup: + + PKIX_DECREF(nowDate); + + PKIX_RETURN(CERTCHAINCHECKER); + +} diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_expirationchecker.h b/security/nss/lib/libpkix/pkix/checker/pkix_expirationchecker.h new file mode 100644 index 0000000000..17b5c1bc10 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_expirationchecker.h @@ -0,0 +1,30 @@ +/* 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/. */ +/* + * pkix_expirationchecker.h + * + * Header file for validate expiration function + * + */ + +#ifndef _PKIX_EXPIRATIONCHECKER_H +#define _PKIX_EXPIRATIONCHECKER_H + +#include "pkix_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +PKIX_Error * +pkix_ExpirationChecker_Initialize( + PKIX_PL_Date *testDate, + PKIX_CertChainChecker **pChecker, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_EXPIRATIONCHECKER_H */ diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_namechainingchecker.c b/security/nss/lib/libpkix/pkix/checker/pkix_namechainingchecker.c new file mode 100644 index 0000000000..873d19cd05 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_namechainingchecker.c @@ -0,0 +1,121 @@ +/* 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/. */ +/* + * pkix_namechainingchecker.c + * + * Functions for name chaining validation + * + */ + + +#include "pkix_namechainingchecker.h" + +/* --Private-Functions-------------------------------------------- */ + +/* + * FUNCTION: pkix_NameChainingChecker_Check + * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h) + */ +PKIX_Error * +pkix_NameChainingChecker_Check( + PKIX_CertChainChecker *checker, + PKIX_PL_Cert *cert, + PKIX_List *unresolvedCriticalExtensions, + void **pNBIOContext, + void *plContext) +{ + PKIX_PL_X500Name *prevSubject = NULL; + PKIX_PL_X500Name *currIssuer = NULL; + PKIX_PL_X500Name *currSubject = NULL; + PKIX_Boolean result; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_NameChainingChecker_Check"); + PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext); + + *pNBIOContext = NULL; /* we never block on pending I/O */ + + PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState + (checker, (PKIX_PL_Object **)&prevSubject, plContext), + PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); + + PKIX_CHECK(PKIX_PL_Cert_GetIssuer(cert, &currIssuer, plContext), + PKIX_CERTGETISSUERFAILED); + + if (prevSubject){ + PKIX_CHECK(PKIX_PL_X500Name_Match + (prevSubject, currIssuer, &result, plContext), + PKIX_X500NAMEMATCHFAILED); + if (!result){ + PKIX_ERROR(PKIX_NAMECHAININGCHECKFAILED); + } + } else { + PKIX_ERROR(PKIX_NAMECHAININGCHECKFAILED); + } + + PKIX_CHECK(PKIX_PL_Cert_GetSubject(cert, &currSubject, plContext), + PKIX_CERTGETSUBJECTFAILED); + + PKIX_CHECK(PKIX_CertChainChecker_SetCertChainCheckerState + (checker, (PKIX_PL_Object *)currSubject, plContext), + PKIX_CERTCHAINCHECKERSETCERTCHAINCHECKERSTATEFAILED); + +cleanup: + + PKIX_DECREF(prevSubject); + PKIX_DECREF(currIssuer); + PKIX_DECREF(currSubject); + + PKIX_RETURN(CERTCHAINCHECKER); + +} + +/* + * FUNCTION: pkix_NameChainingChecker_Initialize + * DESCRIPTION: + * + * Creates a new CertChainChecker and stores it at "pChecker", where it will + * be used by pkix_NameChainingChecker_Check to check that the issuer name + * of the certificate matches the subject name in the checker's state. The + * X500Name pointed to by "trustedCAName" is used to initialize the checker's + * state. + * + * PARAMETERS: + * "trustedCAName" + * Address of X500Name representing the trusted CA Name used to + * initialize the state of this checker. Must be non-NULL. + * "pChecker" + * Address where object pointer will be stored. Must be non-NULL. + * "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 CertChainChecker Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_NameChainingChecker_Initialize( + PKIX_PL_X500Name *trustedCAName, + PKIX_CertChainChecker **pChecker, + void *plContext) +{ + PKIX_ENTER(CERTCHAINCHECKER, "PKIX_NameChainingChecker_Initialize"); + PKIX_NULLCHECK_TWO(pChecker, trustedCAName); + + PKIX_CHECK(PKIX_CertChainChecker_Create + (pkix_NameChainingChecker_Check, + PKIX_FALSE, + PKIX_FALSE, + NULL, + (PKIX_PL_Object *)trustedCAName, + pChecker, + plContext), + PKIX_CERTCHAINCHECKERCREATEFAILED); + +cleanup: + + PKIX_RETURN(CERTCHAINCHECKER); + +} diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_namechainingchecker.h b/security/nss/lib/libpkix/pkix/checker/pkix_namechainingchecker.h new file mode 100644 index 0000000000..bc413f4561 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_namechainingchecker.h @@ -0,0 +1,30 @@ +/* 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/. */ +/* + * pkix_namechainingchecker.h + * + * Header file for name chaining checker. + * + */ + +#ifndef _PKIX_NAMECHAININGCHECKER_H +#define _PKIX_NAMECHAININGCHECKER_H + +#include "pkix_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +PKIX_Error * +pkix_NameChainingChecker_Initialize( + PKIX_PL_X500Name *trustedCAName, + PKIX_CertChainChecker **pChecker, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_NAMECHAININGCHECKER_H */ diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_nameconstraintschecker.c b/security/nss/lib/libpkix/pkix/checker/pkix_nameconstraintschecker.c new file mode 100644 index 0000000000..28f21a6c2d --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_nameconstraintschecker.c @@ -0,0 +1,340 @@ +/* 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/. */ +/* + * pkix_nameconstraintschecker.c + * + * Functions for Name Constraints Checkers + * + */ + +#include "pkix_nameconstraintschecker.h" + +/* --Private-NameConstraintsCheckerState-Functions---------------------- */ + +/* + * FUNCTION: pkix_NameConstraintsCheckerstate_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_NameConstraintsCheckerState_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + pkix_NameConstraintsCheckerState *state = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTSCHECKERSTATE, + "pkix_NameConstraintsCheckerState_Destroy"); + PKIX_NULLCHECK_ONE(object); + + /* Check that object type */ + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTNAMECONSTRAINTSCHECKERSTATE_TYPE, plContext), + PKIX_OBJECTNOTNAMECONSTRAINTSCHECKERSTATE); + + state = (pkix_NameConstraintsCheckerState *)object; + + PKIX_DECREF(state->nameConstraints); + PKIX_DECREF(state->nameConstraintsOID); + +cleanup: + + PKIX_RETURN(CERTNAMECONSTRAINTSCHECKERSTATE); +} + +/* + * FUNCTION: pkix_NameConstraintsCheckerState_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_CERTNAMECONSTRAINTSCHECKERSTATE_TYPE and its related + * functions with systemClasses[] + * + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_NameConstraintsCheckerState_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERTNAMECONSTRAINTSCHECKERSTATE, + "pkix_NameConstraintsCheckerState_RegisterSelf"); + + entry.description = "NameConstraintsCheckerState"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(pkix_NameConstraintsCheckerState); + entry.destructor = pkix_NameConstraintsCheckerState_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_CERTNAMECONSTRAINTSCHECKERSTATE_TYPE] = entry; + + PKIX_RETURN(CERTNAMECONSTRAINTSCHECKERSTATE); +} + +/* + * FUNCTION: pkix_NameConstraintsCheckerState_Create + * + * DESCRIPTION: + * Allocate and initialize NameConstraintsChecker state data. + * + * PARAMETERS + * "nameConstraints" + * Address of NameConstraints to be stored in state. May be NULL. + * "numCerts" + * Number of certificates in the validation chain. This data is used + * to identify end-entity. + * "pCheckerState" + * Address of NameConstraintsCheckerState that is returned. Must be + * non-NULL. + * "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 CERTNAMECONSTRAINTSCHECKERSTATE Error if the function fails in + * a non-fatal way. + * Returns a Fatal Error + */ +static PKIX_Error * +pkix_NameConstraintsCheckerState_Create( + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_UInt32 numCerts, + pkix_NameConstraintsCheckerState **pCheckerState, + void *plContext) +{ + pkix_NameConstraintsCheckerState *state = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTSCHECKERSTATE, + "pkix_NameConstraintsCheckerState_Create"); + PKIX_NULLCHECK_ONE(pCheckerState); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTNAMECONSTRAINTSCHECKERSTATE_TYPE, + sizeof (pkix_NameConstraintsCheckerState), + (PKIX_PL_Object **)&state, + plContext), + PKIX_COULDNOTCREATENAMECONSTRAINTSCHECKERSTATEOBJECT); + + /* Initialize fields */ + + PKIX_CHECK(PKIX_PL_OID_Create + (PKIX_NAMECONSTRAINTS_OID, + &state->nameConstraintsOID, + plContext), + PKIX_OIDCREATEFAILED); + + PKIX_INCREF(nameConstraints); + + state->nameConstraints = nameConstraints; + state->certsRemaining = numCerts; + + *pCheckerState = state; + state = NULL; + +cleanup: + + PKIX_DECREF(state); + + PKIX_RETURN(CERTNAMECONSTRAINTSCHECKERSTATE); +} + +/* --Private-NameConstraintsChecker-Functions------------------------- */ + +/* + * FUNCTION: pkix_NameConstraintsChecker_Check + * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h) + */ +static PKIX_Error * +pkix_NameConstraintsChecker_Check( + PKIX_CertChainChecker *checker, + PKIX_PL_Cert *cert, + PKIX_List *unresolvedCriticalExtensions, + void **pNBIOContext, + void *plContext) +{ + pkix_NameConstraintsCheckerState *state = NULL; + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + PKIX_PL_CertNameConstraints *mergedNameConstraints = NULL; + PKIX_Boolean selfIssued = PKIX_FALSE; + PKIX_Boolean lastCert = PKIX_FALSE; + PKIX_Boolean treatCommonNameAsDNSName = PKIX_FALSE; + PKIX_List *extKeyUsageList = NULL; + PKIX_PL_OID *serverAuthOID = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_NameConstraintsChecker_Check"); + PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext); + + *pNBIOContext = NULL; /* we never block on pending I/O */ + + PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState + (checker, (PKIX_PL_Object **)&state, plContext), + PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); + + state->certsRemaining--; + lastCert = state->certsRemaining == 0; + + /* Get status of self issued */ + PKIX_CHECK(pkix_IsCertSelfIssued(cert, &selfIssued, plContext), + PKIX_ISCERTSELFISSUEDFAILED); + + if (lastCert) { + /* For the last cert, treat the CN as a DNS name for name + * constraint check. But only if EKU has id-kp-serverAuth + * or EKU is absent. It does not make sense to treat CN + * as a DNS name for an OCSP signing certificate, for example. + */ + PKIX_CHECK(PKIX_PL_Cert_GetExtendedKeyUsage + (cert, &extKeyUsageList, plContext), + PKIX_CERTGETEXTENDEDKEYUSAGEFAILED); + if (extKeyUsageList == NULL) { + treatCommonNameAsDNSName = PKIX_TRUE; + } else { + PKIX_CHECK(PKIX_PL_OID_Create + (PKIX_KEY_USAGE_SERVER_AUTH_OID, + &serverAuthOID, + plContext), + PKIX_OIDCREATEFAILED); + + PKIX_CHECK(pkix_List_Contains + (extKeyUsageList, + (PKIX_PL_Object *) serverAuthOID, + &treatCommonNameAsDNSName, + plContext), + PKIX_LISTCONTAINSFAILED); + } + } + + /* Check on non self-issued and if so only for last cert */ + if (selfIssued == PKIX_FALSE || + (selfIssued == PKIX_TRUE && lastCert)) { + PKIX_CHECK(PKIX_PL_Cert_CheckNameConstraints + (cert, state->nameConstraints, treatCommonNameAsDNSName, + plContext), + PKIX_CERTCHECKNAMECONSTRAINTSFAILED); + } + + if (!lastCert) { + + PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints + (cert, &nameConstraints, plContext), + PKIX_CERTGETNAMECONSTRAINTSFAILED); + + /* Merge with previous name constraints kept in state */ + + if (nameConstraints != NULL) { + + if (state->nameConstraints == NULL) { + + state->nameConstraints = nameConstraints; + + } else { + + PKIX_CHECK(PKIX_PL_Cert_MergeNameConstraints + (nameConstraints, + state->nameConstraints, + &mergedNameConstraints, + plContext), + PKIX_CERTMERGENAMECONSTRAINTSFAILED); + + PKIX_DECREF(nameConstraints); + PKIX_DECREF(state->nameConstraints); + + state->nameConstraints = mergedNameConstraints; + } + + /* Remove Name Constraints Extension OID from list */ + if (unresolvedCriticalExtensions != NULL) { + PKIX_CHECK(pkix_List_Remove + (unresolvedCriticalExtensions, + (PKIX_PL_Object *)state->nameConstraintsOID, + plContext), + PKIX_LISTREMOVEFAILED); + } + } + } + + PKIX_CHECK(PKIX_CertChainChecker_SetCertChainCheckerState + (checker, (PKIX_PL_Object *)state, plContext), + PKIX_CERTCHAINCHECKERSETCERTCHAINCHECKERSTATEFAILED); + +cleanup: + + PKIX_DECREF(state); + PKIX_DECREF(extKeyUsageList); + PKIX_DECREF(serverAuthOID); + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_NameConstraintsChecker_Initialize + * + * DESCRIPTION: + * Create a CertChainChecker with a NameConstraintsCheckerState. The + * NameConstraintsCheckerState is created with "trustedNC" and "numCerts" + * as its initial state. The CertChainChecker for the NameConstraints is + * returned at address of "pChecker". + * + * PARAMETERS + * "trustedNC" + * The NameConstraints from trusted anchor Cert is stored at "trustedNC" + * for initialization. May be NULL. + * "numCerts" + * Number of certificates in the validation chain. This data is used + * to identify end-entity. + * "pChecker" + * Address of CertChainChecker to bo created and returned. + * Must be non-NULL. + * "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 CERTCHAINCHECKER Error if the function fails in a non-fatal way. + * Returns a Fatal Error + */ +PKIX_Error * +pkix_NameConstraintsChecker_Initialize( + PKIX_PL_CertNameConstraints *trustedNC, + PKIX_UInt32 numCerts, + PKIX_CertChainChecker **pChecker, + void *plContext) +{ + pkix_NameConstraintsCheckerState *state = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_NameConstraintsChecker_Initialize"); + PKIX_NULLCHECK_ONE(pChecker); + + PKIX_CHECK(pkix_NameConstraintsCheckerState_Create + (trustedNC, numCerts, &state, plContext), + PKIX_NAMECONSTRAINTSCHECKERSTATECREATEFAILED); + + PKIX_CHECK(PKIX_CertChainChecker_Create + (pkix_NameConstraintsChecker_Check, + PKIX_FALSE, + PKIX_FALSE, + NULL, + (PKIX_PL_Object *) state, + pChecker, + plContext), + PKIX_CERTCHAINCHECKERCREATEFAILED); + +cleanup: + + PKIX_DECREF(state); + + PKIX_RETURN(CERTCHAINCHECKER); +} diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_nameconstraintschecker.h b/security/nss/lib/libpkix/pkix/checker/pkix_nameconstraintschecker.h new file mode 100644 index 0000000000..ac3de346db --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_nameconstraintschecker.h @@ -0,0 +1,43 @@ +/* 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/. */ +/* + * pkix_nameconstraintschecker.h + * + * Header file for validate Name Constraints Checker function + * + */ + +#ifndef _PKIX_NAMECONSTRAINTSCHECKER_H +#define _PKIX_NAMECONSTRAINTSCHECKER_H + +#include "pkix_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pkix_NameConstraintsCheckerState \ + pkix_NameConstraintsCheckerState; + +struct pkix_NameConstraintsCheckerState { + PKIX_PL_CertNameConstraints *nameConstraints; + PKIX_PL_OID *nameConstraintsOID; + PKIX_UInt32 certsRemaining; +}; + +PKIX_Error * +pkix_NameConstraintsChecker_Initialize( + PKIX_PL_CertNameConstraints *trustedNC, + PKIX_UInt32 numCerts, + PKIX_CertChainChecker **pChecker, + void *plContext); + +PKIX_Error * +pkix_NameConstraintsCheckerState_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_NAMECONSTRAINTSCHECKER_H */ diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_ocspchecker.c b/security/nss/lib/libpkix/pkix/checker/pkix_ocspchecker.c new file mode 100644 index 0000000000..b6fca9a354 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_ocspchecker.c @@ -0,0 +1,419 @@ +/* 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/. */ +/* + * pkix_ocspchecker.c + * + * OcspChecker Object Functions + * + */ + +#include "pkix_ocspchecker.h" +#include "pkix_pl_ocspcertid.h" +#include "pkix_error.h" + + +/* --Private-Data-and-Types--------------------------------------- */ + +typedef struct pkix_OcspCheckerStruct { + /* RevocationMethod is the super class of OcspChecker. */ + pkix_RevocationMethod method; + PKIX_PL_VerifyCallback certVerifyFcn; +} pkix_OcspChecker; + +/* --Private-Functions-------------------------------------------- */ + +/* + * FUNCTION: pkix_OcspChecker_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_OcspChecker_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + return NULL; +} + +/* + * FUNCTION: pkix_OcspChecker_RegisterSelf + * DESCRIPTION: + * Registers PKIX_OCSPCHECKER_TYPE and its related functions with + * systemClasses[] + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_OcspChecker_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry* entry = &systemClasses[PKIX_OCSPCHECKER_TYPE]; + + PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_RegisterSelf"); + + entry->description = "OcspChecker"; + entry->typeObjectSize = sizeof(pkix_OcspChecker); + entry->destructor = pkix_OcspChecker_Destroy; + + PKIX_RETURN(OCSPCHECKER); +} + + +/* + * FUNCTION: pkix_OcspChecker_Create + */ +PKIX_Error * +pkix_OcspChecker_Create(PKIX_RevocationMethodType methodType, + PKIX_UInt32 flags, + PKIX_UInt32 priority, + pkix_LocalRevocationCheckFn localRevChecker, + pkix_ExternalRevocationCheckFn externalRevChecker, + PKIX_PL_VerifyCallback verifyFn, + pkix_RevocationMethod **pChecker, + void *plContext) +{ + pkix_OcspChecker *method = NULL; + + PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_Create"); + PKIX_NULLCHECK_ONE(pChecker); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_OCSPCHECKER_TYPE, + sizeof (pkix_OcspChecker), + (PKIX_PL_Object **)&method, + plContext), + PKIX_COULDNOTCREATECERTCHAINCHECKEROBJECT); + + pkixErrorResult = pkix_RevocationMethod_Init( + (pkix_RevocationMethod*)method, methodType, flags, priority, + localRevChecker, externalRevChecker, plContext); + if (pkixErrorResult) { + goto cleanup; + } + method->certVerifyFcn = (PKIX_PL_VerifyCallback)verifyFn; + + *pChecker = (pkix_RevocationMethod*)method; + method = NULL; + +cleanup: + PKIX_DECREF(method); + + PKIX_RETURN(OCSPCHECKER); +} + +/* + * FUNCTION: pkix_OcspChecker_MapResultCodeToRevStatus + */ +PKIX_RevocationStatus +pkix_OcspChecker_MapResultCodeToRevStatus(SECErrorCodes resultCode) +{ + switch (resultCode) { + case SEC_ERROR_REVOKED_CERTIFICATE: + return PKIX_RevStatus_Revoked; + default: + return PKIX_RevStatus_NoInfo; + } +} + +/* --Public-Functions--------------------------------------------- */ + +/* + * FUNCTION: pkix_OcspChecker_Check (see comments in pkix_checker.h) + */ + +/* + * The OCSPChecker is created in an idle state, and remains in this state until + * either (a) the default Responder has been set and enabled, and a Check + * request is received with no responder specified, or (b) a Check request is + * received with a specified responder. A request message is constructed and + * given to the HttpClient. If non-blocking I/O is used the client may return + * with WOULDBLOCK, in which case the OCSPChecker returns the WOULDBLOCK + * condition to its caller in turn. On a subsequent call the I/O is resumed. + * When a response is received it is decoded and the results provided to the + * caller. + * + */ +PKIX_Error * +pkix_OcspChecker_CheckLocal( + PKIX_PL_Cert *cert, + PKIX_PL_Cert *issuer, + PKIX_PL_Date *date, + pkix_RevocationMethod *checkerObject, + PKIX_ProcessingParams *procParams, + PKIX_UInt32 methodFlags, + PKIX_Boolean chainVerificationState, + PKIX_RevocationStatus *pRevStatus, + CERTCRLEntryReasonCode *pReasonCode, + void *plContext) +{ + PKIX_PL_OcspCertID *cid = NULL; + PKIX_Boolean hasFreshStatus = PKIX_FALSE; + PKIX_Boolean statusIsGood = PKIX_FALSE; + SECErrorCodes resultCode = SEC_ERROR_REVOKED_CERTIFICATE_OCSP; + PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; + + PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_CheckLocal"); + + PKIX_CHECK( + PKIX_PL_OcspCertID_Create(cert, NULL, &cid, + plContext), + PKIX_OCSPCERTIDCREATEFAILED); + if (!cid) { + goto cleanup; + } + + PKIX_CHECK( + PKIX_PL_OcspCertID_GetFreshCacheStatus(cid, date, + &hasFreshStatus, + &statusIsGood, + &resultCode, + plContext), + PKIX_OCSPCERTIDGETFRESHCACHESTATUSFAILED); + if (hasFreshStatus) { + if (statusIsGood) { + revStatus = PKIX_RevStatus_Success; + resultCode = 0; + } else { + revStatus = pkix_OcspChecker_MapResultCodeToRevStatus(resultCode); + } + } + +cleanup: + *pRevStatus = revStatus; + + /* ocsp carries only tree statuses: good, bad, and unknown. + * revStatus is used to pass them. reasonCode is always set + * to be unknown. */ + *pReasonCode = crlEntryReasonUnspecified; + PKIX_DECREF(cid); + + PKIX_RETURN(OCSPCHECKER); +} + + +/* + * The OCSPChecker is created in an idle state, and remains in this state until + * either (a) the default Responder has been set and enabled, and a Check + * request is received with no responder specified, or (b) a Check request is + * received with a specified responder. A request message is constructed and + * given to the HttpClient. When a response is received it is decoded and the + * results provided to the caller. + * + * During the most recent enhancement of this function, it has been found that + * it doesn't correctly implement non-blocking I/O. + * + * The nbioContext is used in two places, for "response-obtaining" and + * for "response-verification". + * + * However, if this function gets called to resume, it always + * repeats the "request creation" and "response fetching" steps! + * As a result, the earlier operation is never resumed. + */ +PKIX_Error * +pkix_OcspChecker_CheckExternal( + PKIX_PL_Cert *cert, + PKIX_PL_Cert *issuer, + PKIX_PL_Date *date, + pkix_RevocationMethod *checkerObject, + PKIX_ProcessingParams *procParams, + PKIX_UInt32 methodFlags, + PKIX_RevocationStatus *pRevStatus, + CERTCRLEntryReasonCode *pReasonCode, + void **pNBIOContext, + void *plContext) +{ + SECErrorCodes resultCode = SEC_ERROR_REVOKED_CERTIFICATE_OCSP; + PKIX_Boolean uriFound = PKIX_FALSE; + PKIX_Boolean passed = PKIX_TRUE; + pkix_OcspChecker *checker = NULL; + PKIX_PL_OcspCertID *cid = NULL; + PKIX_PL_OcspRequest *request = NULL; + PKIX_PL_OcspResponse *response = NULL; + PKIX_PL_Date *validity = NULL; + PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; + void *nbioContext = NULL; + enum { stageGET, stagePOST } currentStage; + PRBool retry = PR_FALSE; + + PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_CheckExternal"); + + PKIX_CHECK( + pkix_CheckType((PKIX_PL_Object*)checkerObject, + PKIX_OCSPCHECKER_TYPE, plContext), + PKIX_OBJECTNOTOCSPCHECKER); + + checker = (pkix_OcspChecker *)checkerObject; + + PKIX_CHECK( + PKIX_PL_OcspCertID_Create(cert, NULL, &cid, + plContext), + PKIX_OCSPCERTIDCREATEFAILED); + + /* create request */ + PKIX_CHECK( + pkix_pl_OcspRequest_Create(cert, cid, validity, NULL, + methodFlags, &uriFound, &request, + plContext), + PKIX_OCSPREQUESTCREATEFAILED); + + if (uriFound == PKIX_FALSE) { + /* no caching for certs lacking URI */ + resultCode = 0; + goto cleanup; + } + + if (methodFlags & CERT_REV_M_FORCE_POST_METHOD_FOR_OCSP) { + /* Do not try HTTP GET, only HTTP POST */ + currentStage = stagePOST; + } else { + /* Try HTTP GET first, falling back to POST */ + currentStage = stageGET; + } + + do { + const char *method; + passed = PKIX_TRUE; + + retry = PR_FALSE; + if (currentStage == stageGET) { + method = "GET"; + } else { + PORT_Assert(currentStage == stagePOST); + method = "POST"; + } + + /* send request and create a response object */ + PKIX_CHECK_NO_GOTO( + pkix_pl_OcspResponse_Create(request, method, NULL, + checker->certVerifyFcn, + &nbioContext, + &response, + plContext), + PKIX_OCSPRESPONSECREATEFAILED); + + if (pkixErrorResult) { + passed = PKIX_FALSE; + } + + if (passed && nbioContext != 0) { + *pNBIOContext = nbioContext; + goto cleanup; + } + + if (passed){ + PKIX_CHECK_NO_GOTO( + pkix_pl_OcspResponse_Decode(response, &passed, + &resultCode, plContext), + PKIX_OCSPRESPONSEDECODEFAILED); + if (pkixErrorResult) { + passed = PKIX_FALSE; + } + } + + if (passed){ + PKIX_CHECK_NO_GOTO( + pkix_pl_OcspResponse_GetStatus(response, &passed, + &resultCode, plContext), + PKIX_OCSPRESPONSEGETSTATUSRETURNEDANERROR); + if (pkixErrorResult) { + passed = PKIX_FALSE; + } + } + + if (passed){ + PKIX_CHECK_NO_GOTO( + pkix_pl_OcspResponse_VerifySignature(response, cert, + procParams, &passed, + &nbioContext, plContext), + PKIX_OCSPRESPONSEVERIFYSIGNATUREFAILED); + if (pkixErrorResult) { + passed = PKIX_FALSE; + } else { + if (nbioContext != 0) { + *pNBIOContext = nbioContext; + goto cleanup; + } + } + } + + if (!passed && currentStage == stagePOST) { + /* We won't retry a POST failure, so it's final. + * Because the following block with its call to + * pkix_pl_OcspResponse_GetStatusForCert + * will take care of caching good or bad state, + * but we only execute that next block if there hasn't + * been a failure yet, we must cache the POST + * failure now. + */ + + if (cid && cid->certID) { + /* Caching MIGHT consume the cid. */ + PKIX_Error *err; + err = PKIX_PL_OcspCertID_RememberOCSPProcessingFailure( + cid, plContext); + if (err) { + PKIX_PL_Object_DecRef((PKIX_PL_Object*)err, plContext); + } + } + } + + if (passed){ + PKIX_Boolean allowCachingOfFailures = + (currentStage == stagePOST) ? PKIX_TRUE : PKIX_FALSE; + + PKIX_CHECK_NO_GOTO( + pkix_pl_OcspResponse_GetStatusForCert(cid, response, + allowCachingOfFailures, + date, + &passed, &resultCode, + plContext), + PKIX_OCSPRESPONSEGETSTATUSFORCERTFAILED); + if (pkixErrorResult) { + passed = PKIX_FALSE; + } else if (passed == PKIX_FALSE) { + revStatus = pkix_OcspChecker_MapResultCodeToRevStatus(resultCode); + } else { + revStatus = PKIX_RevStatus_Success; + } + } + + if (currentStage == stageGET && revStatus != PKIX_RevStatus_Success && + revStatus != PKIX_RevStatus_Revoked) { + /* we'll retry */ + PKIX_DECREF(response); + retry = PR_TRUE; + currentStage = stagePOST; + revStatus = PKIX_RevStatus_NoInfo; + if (pkixErrorResult) { + PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult, + plContext); + pkixErrorResult = NULL; + } + } + } while (retry); + +cleanup: + if (revStatus == PKIX_RevStatus_NoInfo && (uriFound || + methodFlags & PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE) && + methodFlags & PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) { + revStatus = PKIX_RevStatus_Revoked; + } + *pRevStatus = revStatus; + + /* ocsp carries only three statuses: good, bad, and unknown. + * revStatus is used to pass them. reasonCode is always set + * to be unknown. */ + *pReasonCode = crlEntryReasonUnspecified; + + PKIX_DECREF(cid); + PKIX_DECREF(request); + PKIX_DECREF(response); + + PKIX_RETURN(OCSPCHECKER); +} + + diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_ocspchecker.h b/security/nss/lib/libpkix/pkix/checker/pkix_ocspchecker.h new file mode 100644 index 0000000000..fbec315f96 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_ocspchecker.h @@ -0,0 +1,67 @@ +/* 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/. */ +/* + * pkix_ocspchecker.h + * + * OcspChecker Object Type Definition + * + */ + +#ifndef _PKIX_OCSPCHECKER_H +#define _PKIX_OCSPCHECKER_H + +#include "pkix_tools.h" +#include "pkix_revocationmethod.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: nbio logic removed. Will be replaced later. */ + +PKIX_Error * +pkix_OcspChecker_CheckLocal( + PKIX_PL_Cert *cert, + PKIX_PL_Cert *issuer, + PKIX_PL_Date *date, + pkix_RevocationMethod *checkerObject, + PKIX_ProcessingParams *procParams, + PKIX_UInt32 methodFlags, + PKIX_Boolean chainVerificationState, + PKIX_RevocationStatus *pRevStatus, + CERTCRLEntryReasonCode *reasonCode, + void *plContext); + +PKIX_Error * +pkix_OcspChecker_CheckExternal( + PKIX_PL_Cert *cert, + PKIX_PL_Cert *issuer, + PKIX_PL_Date *date, + pkix_RevocationMethod *checkerObject, + PKIX_ProcessingParams *procParams, + PKIX_UInt32 methodFlags, + PKIX_RevocationStatus *pRevStatus, + CERTCRLEntryReasonCode *reasonCode, + void **pNBIOContext, + void *plContext); + +PKIX_Error * +pkix_OcspChecker_Create(PKIX_RevocationMethodType methodType, + PKIX_UInt32 flags, + PKIX_UInt32 priority, + pkix_LocalRevocationCheckFn localRevChecker, + pkix_ExternalRevocationCheckFn externalRevChecker, + PKIX_PL_VerifyCallback certVerifyFn, + pkix_RevocationMethod **pChecker, + void *plContext); + +/* see source file for function documentation */ + +PKIX_Error *pkix_OcspChecker_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_OCSPCHECKER_H */ diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_policychecker.c b/security/nss/lib/libpkix/pkix/checker/pkix_policychecker.c new file mode 100644 index 0000000000..8e40596541 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_policychecker.c @@ -0,0 +1,2783 @@ +/* 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/. */ +/* + * pkix_policychecker.c + * + * Functions for Policy Checker + * + */ +#include "pkix_policychecker.h" + +/* --Forward declarations----------------------------------------------- */ + +static PKIX_Error * +pkix_PolicyChecker_MakeSingleton( + PKIX_PL_Object *listItem, + PKIX_Boolean immutability, + PKIX_List **pList, + void *plContext); + +/* --Private-PolicyCheckerState-Functions---------------------------------- */ + +/* + * FUNCTION:pkix_PolicyCheckerState_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_PolicyCheckerState_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PolicyCheckerState *checkerState = NULL; + + PKIX_ENTER(CERTPOLICYCHECKERSTATE, "pkix_PolicyCheckerState_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTPOLICYCHECKERSTATE_TYPE, plContext), + PKIX_OBJECTNOTPOLICYCHECKERSTATE); + + checkerState = (PKIX_PolicyCheckerState *)object; + + PKIX_DECREF(checkerState->certPoliciesExtension); + PKIX_DECREF(checkerState->policyMappingsExtension); + PKIX_DECREF(checkerState->policyConstraintsExtension); + PKIX_DECREF(checkerState->inhibitAnyPolicyExtension); + PKIX_DECREF(checkerState->anyPolicyOID); + PKIX_DECREF(checkerState->validPolicyTree); + PKIX_DECREF(checkerState->userInitialPolicySet); + PKIX_DECREF(checkerState->mappedUserInitialPolicySet); + + checkerState->policyQualifiersRejected = PKIX_FALSE; + checkerState->explicitPolicy = 0; + checkerState->inhibitAnyPolicy = 0; + checkerState->policyMapping = 0; + checkerState->numCerts = 0; + checkerState->certsProcessed = 0; + checkerState->certPoliciesCritical = PKIX_FALSE; + + PKIX_DECREF(checkerState->anyPolicyNodeAtBottom); + PKIX_DECREF(checkerState->newAnyPolicyNode); + PKIX_DECREF(checkerState->mappedPolicyOIDs); + +cleanup: + + PKIX_RETURN(CERTPOLICYCHECKERSTATE); +} + +/* + * FUNCTION: pkix_PolicyCheckerState_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_PolicyCheckerState_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pCheckerStateString, + void *plContext) +{ + PKIX_PolicyCheckerState *state = NULL; + PKIX_PL_String *resultString = NULL; + PKIX_PL_String *policiesExtOIDString = NULL; + PKIX_PL_String *policyMapOIDString = NULL; + PKIX_PL_String *policyConstrOIDString = NULL; + PKIX_PL_String *inhAnyPolOIDString = NULL; + PKIX_PL_String *anyPolicyOIDString = NULL; + PKIX_PL_String *validPolicyTreeString = NULL; + PKIX_PL_String *userInitialPolicySetString = NULL; + PKIX_PL_String *mappedUserPolicySetString = NULL; + PKIX_PL_String *mappedPolicyOIDsString = NULL; + PKIX_PL_String *anyAtBottomString = NULL; + PKIX_PL_String *newAnyPolicyString = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *trueString = NULL; + PKIX_PL_String *falseString = NULL; + PKIX_PL_String *nullString = NULL; + PKIX_Boolean initialPolicyMappingInhibit = PKIX_FALSE; + PKIX_Boolean initialExplicitPolicy = PKIX_FALSE; + PKIX_Boolean initialAnyPolicyInhibit = PKIX_FALSE; + PKIX_Boolean initialIsAnyPolicy = PKIX_FALSE; + PKIX_Boolean policyQualifiersRejected = PKIX_FALSE; + PKIX_Boolean certPoliciesCritical = PKIX_FALSE; + char *asciiFormat = + "{\n" + "\tcertPoliciesExtension: \t%s\n" + "\tpolicyMappingsExtension: \t%s\n" + "\tpolicyConstraintsExtension:\t%s\n" + "\tinhibitAnyPolicyExtension:\t%s\n" + "\tanyPolicyOID: \t%s\n" + "\tinitialIsAnyPolicy: \t%s\n" + "\tvalidPolicyTree: \t%s\n" + "\tuserInitialPolicySet: \t%s\n" + "\tmappedUserPolicySet: \t%s\n" + "\tpolicyQualifiersRejected: \t%s\n" + "\tinitialPolMappingInhibit: \t%s\n" + "\tinitialExplicitPolicy: \t%s\n" + "\tinitialAnyPolicyInhibit: \t%s\n" + "\texplicitPolicy: \t%d\n" + "\tinhibitAnyPolicy: \t%d\n" + "\tpolicyMapping: \t%d\n" + "\tnumCerts: \t%d\n" + "\tcertsProcessed: \t%d\n" + "\tanyPolicyNodeAtBottom: \t%s\n" + "\tnewAnyPolicyNode: \t%s\n" + "\tcertPoliciesCritical: \t%s\n" + "\tmappedPolicyOIDs: \t%s\n" + "}"; + + PKIX_ENTER(CERTPOLICYCHECKERSTATE, "pkix_PolicyCheckerState_ToString"); + + PKIX_NULLCHECK_TWO(object, pCheckerStateString); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTPOLICYCHECKERSTATE_TYPE, plContext), + PKIX_OBJECTNOTPOLICYCHECKERSTATE); + + state = (PKIX_PolicyCheckerState *)object; + PKIX_NULLCHECK_THREE + (state->certPoliciesExtension, + state->policyMappingsExtension, + state->policyConstraintsExtension); + PKIX_NULLCHECK_THREE + (state->inhibitAnyPolicyExtension, + state->anyPolicyOID, + state->userInitialPolicySet); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext), + PKIX_STRINGCREATEFAILED); + /* + * Create TRUE, FALSE, and "NULL" PKIX_PL_Strings. But creating a + * PKIX_PL_String is complicated enough, it's worth checking, for + * each, to make sure the string is needed. + */ + initialPolicyMappingInhibit = state->initialPolicyMappingInhibit; + initialExplicitPolicy = state->initialExplicitPolicy; + initialAnyPolicyInhibit = state->initialAnyPolicyInhibit; + initialIsAnyPolicy = state->initialIsAnyPolicy; + policyQualifiersRejected = state->policyQualifiersRejected; + certPoliciesCritical = state->certPoliciesCritical; + + if (initialPolicyMappingInhibit || initialExplicitPolicy || + initialAnyPolicyInhibit || initialIsAnyPolicy || + policyQualifiersRejected || certPoliciesCritical) { + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, "TRUE", 0, &trueString, plContext), + PKIX_STRINGCREATEFAILED); + } + if (!initialPolicyMappingInhibit || !initialExplicitPolicy || + !initialAnyPolicyInhibit || !initialIsAnyPolicy || + !policyQualifiersRejected || !certPoliciesCritical) { + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, "FALSE", 0, &falseString, plContext), + PKIX_STRINGCREATEFAILED); + } + if (!(state->anyPolicyNodeAtBottom) || !(state->newAnyPolicyNode)) { + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, "(null)", 0, &nullString, plContext), + PKIX_STRINGCREATEFAILED); + } + + PKIX_TOSTRING + (state->certPoliciesExtension, &policiesExtOIDString, plContext, + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_TOSTRING + (state->policyMappingsExtension, + &policyMapOIDString, + plContext, + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_TOSTRING + (state->policyConstraintsExtension, + &policyConstrOIDString, + plContext, + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_TOSTRING + (state->inhibitAnyPolicyExtension, + &inhAnyPolOIDString, + plContext, + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_TOSTRING(state->anyPolicyOID, &anyPolicyOIDString, plContext, + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_TOSTRING(state->validPolicyTree, &validPolicyTreeString, plContext, + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_TOSTRING + (state->userInitialPolicySet, + &userInitialPolicySetString, + plContext, + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_TOSTRING + (state->mappedUserInitialPolicySet, + &mappedUserPolicySetString, + plContext, + PKIX_OBJECTTOSTRINGFAILED); + + if (state->anyPolicyNodeAtBottom) { + PKIX_CHECK(pkix_SinglePolicyNode_ToString + (state->anyPolicyNodeAtBottom, + &anyAtBottomString, + plContext), + PKIX_SINGLEPOLICYNODETOSTRINGFAILED); + } else { + PKIX_INCREF(nullString); + anyAtBottomString = nullString; + } + + if (state->newAnyPolicyNode) { + PKIX_CHECK(pkix_SinglePolicyNode_ToString + (state->newAnyPolicyNode, + &newAnyPolicyString, + plContext), + PKIX_SINGLEPOLICYNODETOSTRINGFAILED); + } else { + PKIX_INCREF(nullString); + newAnyPolicyString = nullString; + } + + PKIX_TOSTRING + (state->mappedPolicyOIDs, + &mappedPolicyOIDsString, + plContext, + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&resultString, + plContext, + formatString, + policiesExtOIDString, + policyMapOIDString, + policyConstrOIDString, + inhAnyPolOIDString, + anyPolicyOIDString, + initialIsAnyPolicy?trueString:falseString, + validPolicyTreeString, + userInitialPolicySetString, + mappedUserPolicySetString, + policyQualifiersRejected?trueString:falseString, + initialPolicyMappingInhibit?trueString:falseString, + initialExplicitPolicy?trueString:falseString, + initialAnyPolicyInhibit?trueString:falseString, + state->explicitPolicy, + state->inhibitAnyPolicy, + state->policyMapping, + state->numCerts, + state->certsProcessed, + anyAtBottomString, + newAnyPolicyString, + certPoliciesCritical?trueString:falseString, + mappedPolicyOIDsString), + PKIX_SPRINTFFAILED); + + *pCheckerStateString = resultString; + +cleanup: + PKIX_DECREF(policiesExtOIDString); + PKIX_DECREF(policyMapOIDString); + PKIX_DECREF(policyConstrOIDString); + PKIX_DECREF(inhAnyPolOIDString); + PKIX_DECREF(anyPolicyOIDString); + PKIX_DECREF(validPolicyTreeString); + PKIX_DECREF(userInitialPolicySetString); + PKIX_DECREF(mappedUserPolicySetString); + PKIX_DECREF(anyAtBottomString); + PKIX_DECREF(newAnyPolicyString); + PKIX_DECREF(mappedPolicyOIDsString); + PKIX_DECREF(formatString); + PKIX_DECREF(trueString); + PKIX_DECREF(falseString); + PKIX_DECREF(nullString); + + PKIX_RETURN(CERTPOLICYCHECKERSTATE); +} + +/* + * FUNCTION: pkix_PolicyCheckerState_RegisterSelf + * DESCRIPTION: + * + * Registers PKIX_POLICYCHECKERSTATE_TYPE and its related functions + * with systemClasses[] + * + * PARAMETERS: + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_PolicyCheckerState_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER + (CERTPOLICYCHECKERSTATE, + "pkix_PolicyCheckerState_RegisterSelf"); + + entry.description = "PolicyCheckerState"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PolicyCheckerState); + entry.destructor = pkix_PolicyCheckerState_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = pkix_PolicyCheckerState_ToString; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_CERTPOLICYCHECKERSTATE_TYPE] = entry; + + PKIX_RETURN(CERTPOLICYCHECKERSTATE); +} + +/* + * FUNCTION:pkix_PolicyCheckerState_Create + * DESCRIPTION: + * + * Creates a PolicyCheckerState Object, using the List pointed to + * by "initialPolicies" for the user-initial-policy-set, the Boolean value + * of "policyQualifiersRejected" for the policyQualifiersRejected parameter, + * the Boolean value of "initialPolicyMappingInhibit" for the + * inhibitPolicyMappings parameter, the Boolean value of + * "initialExplicitPolicy" for the initialExplicitPolicy parameter, the + * Boolean value of "initialAnyPolicyInhibit" for the inhibitAnyPolicy + * parameter, and the UInt32 value of "numCerts" as the number of + * certificates in the chain; and stores the Object at "pCheckerState". + * + * PARAMETERS: + * "initialPolicies" + * Address of List of OIDs comprising the user-initial-policy-set; the List + * may be empty, but must be non-NULL + * "policyQualifiersRejected" + * Boolean value of the policyQualifiersRejected parameter + * "initialPolicyMappingInhibit" + * Boolean value of the inhibitPolicyMappings parameter + * "initialExplicitPolicy" + * Boolean value of the initialExplicitPolicy parameter + * "initialAnyPolicyInhibit" + * Boolean value of the inhibitAnyPolicy parameter + * "numCerts" + * Number of certificates in the chain to be validated + * "pCheckerState" + * Address where PolicyCheckerState will be stored. Must be non-NULL. + * "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 CertPolicyCheckerState Error if the functions fails in a + * non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +static PKIX_Error * +pkix_PolicyCheckerState_Create( + PKIX_List *initialPolicies, + PKIX_Boolean policyQualifiersRejected, + PKIX_Boolean initialPolicyMappingInhibit, + PKIX_Boolean initialExplicitPolicy, + PKIX_Boolean initialAnyPolicyInhibit, + PKIX_UInt32 numCerts, + PKIX_PolicyCheckerState **pCheckerState, + void *plContext) +{ + PKIX_PolicyCheckerState *checkerState = NULL; + PKIX_PolicyNode *policyNode = NULL; + PKIX_List *anyPolicyList = NULL; + PKIX_Boolean initialPoliciesIsEmpty = PKIX_FALSE; + + PKIX_ENTER(CERTPOLICYCHECKERSTATE, "pkix_PolicyCheckerState_Create"); + PKIX_NULLCHECK_TWO(initialPolicies, pCheckerState); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTPOLICYCHECKERSTATE_TYPE, + sizeof (PKIX_PolicyCheckerState), + (PKIX_PL_Object **)&checkerState, + plContext), + PKIX_COULDNOTCREATEPOLICYCHECKERSTATEOBJECT); + + /* Create constant PKIX_PL_OIDs: */ + + PKIX_CHECK(PKIX_PL_OID_Create + (PKIX_CERTIFICATEPOLICIES_OID, + &(checkerState->certPoliciesExtension), + plContext), + PKIX_OIDCREATEFAILED); + + PKIX_CHECK(PKIX_PL_OID_Create + (PKIX_POLICYMAPPINGS_OID, + &(checkerState->policyMappingsExtension), + plContext), + PKIX_OIDCREATEFAILED); + + PKIX_CHECK(PKIX_PL_OID_Create + (PKIX_POLICYCONSTRAINTS_OID, + &(checkerState->policyConstraintsExtension), + plContext), + PKIX_OIDCREATEFAILED); + + PKIX_CHECK(PKIX_PL_OID_Create + (PKIX_INHIBITANYPOLICY_OID, + &(checkerState->inhibitAnyPolicyExtension), + plContext), + PKIX_OIDCREATEFAILED); + + PKIX_CHECK(PKIX_PL_OID_Create + (PKIX_CERTIFICATEPOLICIES_ANYPOLICY_OID, + &(checkerState->anyPolicyOID), + plContext), + PKIX_OIDCREATEFAILED); + + /* Create an initial policy set from argument supplied */ + PKIX_INCREF(initialPolicies); + checkerState->userInitialPolicySet = initialPolicies; + PKIX_INCREF(initialPolicies); + checkerState->mappedUserInitialPolicySet = initialPolicies; + + PKIX_CHECK(PKIX_List_IsEmpty + (initialPolicies, + &initialPoliciesIsEmpty, + plContext), + PKIX_LISTISEMPTYFAILED); + if (initialPoliciesIsEmpty) { + checkerState->initialIsAnyPolicy = PKIX_TRUE; + } else { + PKIX_CHECK(pkix_List_Contains + (initialPolicies, + (PKIX_PL_Object *)(checkerState->anyPolicyOID), + &(checkerState->initialIsAnyPolicy), + plContext), + PKIX_LISTCONTAINSFAILED); + } + + checkerState->policyQualifiersRejected = + policyQualifiersRejected; + checkerState->initialExplicitPolicy = initialExplicitPolicy; + checkerState->explicitPolicy = + (initialExplicitPolicy? 0: numCerts + 1); + checkerState->initialAnyPolicyInhibit = initialAnyPolicyInhibit; + checkerState->inhibitAnyPolicy = + (initialAnyPolicyInhibit? 0: numCerts + 1); + checkerState->initialPolicyMappingInhibit = initialPolicyMappingInhibit; + checkerState->policyMapping = + (initialPolicyMappingInhibit? 0: numCerts + 1); + ; + checkerState->numCerts = numCerts; + checkerState->certsProcessed = 0; + checkerState->certPoliciesCritical = PKIX_FALSE; + + /* Create a valid_policy_tree as in RFC3280 6.1.2(a) */ + PKIX_CHECK(pkix_PolicyChecker_MakeSingleton + ((PKIX_PL_Object *)(checkerState->anyPolicyOID), + PKIX_TRUE, + &anyPolicyList, + plContext), + PKIX_POLICYCHECKERMAKESINGLETONFAILED); + + PKIX_CHECK(pkix_PolicyNode_Create + (checkerState->anyPolicyOID, /* validPolicy */ + NULL, /* qualifier set */ + PKIX_FALSE, /* criticality */ + anyPolicyList, /* expectedPolicySet */ + &policyNode, + plContext), + PKIX_POLICYNODECREATEFAILED); + checkerState->validPolicyTree = policyNode; + + /* + * Since the initial validPolicyTree specifies + * ANY_POLICY, begin with a pointer to the root node. + */ + PKIX_INCREF(policyNode); + checkerState->anyPolicyNodeAtBottom = policyNode; + + checkerState->newAnyPolicyNode = NULL; + + checkerState->mappedPolicyOIDs = NULL; + + *pCheckerState = checkerState; + checkerState = NULL; + +cleanup: + + PKIX_DECREF(checkerState); + + PKIX_DECREF(anyPolicyList); + + PKIX_RETURN(CERTPOLICYCHECKERSTATE); +} + +/* --Private-PolicyChecker-Functions--------------------------------------- */ + +/* + * FUNCTION: pkix_PolicyChecker_MapContains + * DESCRIPTION: + * + * Checks the List of CertPolicyMaps pointed to by "certPolicyMaps", to + * determine whether the OID pointed to by "policy" is among the + * issuerDomainPolicies or subjectDomainPolicies of "certPolicyMaps", and + * stores the result in "pFound". + * + * This function is intended to allow an efficient check that the proscription + * against anyPolicy being mapped, described in RFC3280 Section 6.1.4(a), is + * not violated. + * + * PARAMETERS: + * "certPolicyMaps" + * Address of List of CertPolicyMaps to be searched. May be empty, but + * must be non-NULL + * "policy" + * Address of OID to be checked for. Must be non-NULL + * "pFound" + * Address where the result of the search will be stored. Must be non-NULL. + * "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 CertChainChecker Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_PolicyChecker_MapContains( + PKIX_List *certPolicyMaps, + PKIX_PL_OID *policy, + PKIX_Boolean *pFound, + void *plContext) +{ + PKIX_PL_CertPolicyMap *map = NULL; + PKIX_UInt32 numEntries = 0; + PKIX_UInt32 index = 0; + PKIX_Boolean match = PKIX_FALSE; + PKIX_PL_OID *issuerDomainPolicy = NULL; + PKIX_PL_OID *subjectDomainPolicy = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_MapContains"); + PKIX_NULLCHECK_THREE(certPolicyMaps, policy, pFound); + + PKIX_CHECK(PKIX_List_GetLength(certPolicyMaps, &numEntries, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (index = 0; (!match) && (index < numEntries); index++) { + PKIX_CHECK(PKIX_List_GetItem + (certPolicyMaps, index, (PKIX_PL_Object **)&map, plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_NULLCHECK_ONE(map); + + PKIX_CHECK(PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy + (map, &issuerDomainPolicy, plContext), + PKIX_CERTPOLICYMAPGETISSUERDOMAINPOLICYFAILED); + + PKIX_EQUALS + (policy, issuerDomainPolicy, &match, plContext, + PKIX_OBJECTEQUALSFAILED); + + if (!match) { + PKIX_CHECK(PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy + (map, &subjectDomainPolicy, plContext), + PKIX_CERTPOLICYMAPGETSUBJECTDOMAINPOLICYFAILED); + + PKIX_EQUALS + (policy, subjectDomainPolicy, &match, plContext, + PKIX_OBJECTEQUALSFAILED); + } + + PKIX_DECREF(map); + PKIX_DECREF(issuerDomainPolicy); + PKIX_DECREF(subjectDomainPolicy); + } + + *pFound = match; + +cleanup: + + PKIX_DECREF(map); + PKIX_DECREF(issuerDomainPolicy); + PKIX_DECREF(subjectDomainPolicy); + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_PolicyChecker_MapGetSubjectDomainPolicies + * DESCRIPTION: + * + * Checks the List of CertPolicyMaps pointed to by "certPolicyMaps", to create + * a list of all SubjectDomainPolicies for which the IssuerDomainPolicy is the + * policy pointed to by "policy", and stores the result in + * "pSubjectDomainPolicies". + * + * If the List of CertPolicyMaps provided in "certPolicyMaps" is NULL, the + * resulting List will be NULL. If there are CertPolicyMaps, but none that + * include "policy" as an IssuerDomainPolicy, the returned List pointer will + * be NULL. Otherwise, the returned List will contain the SubjectDomainPolicies + * of all CertPolicyMaps for which "policy" is the IssuerDomainPolicy. If a + * List is returned it will be immutable. + * + * PARAMETERS: + * "certPolicyMaps" + * Address of List of CertPolicyMaps to be searched. May be empty or NULL. + * "policy" + * Address of OID to be checked for. Must be non-NULL + * "pSubjectDomainPolicies" + * Address where the result of the search will be stored. Must be non-NULL. + * "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 CertChainChecker Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_PolicyChecker_MapGetSubjectDomainPolicies( + PKIX_List *certPolicyMaps, + PKIX_PL_OID *policy, + PKIX_List **pSubjectDomainPolicies, + void *plContext) +{ + PKIX_PL_CertPolicyMap *map = NULL; + PKIX_List *subjectList = NULL; + PKIX_UInt32 numEntries = 0; + PKIX_UInt32 index = 0; + PKIX_Boolean match = PKIX_FALSE; + PKIX_PL_OID *issuerDomainPolicy = NULL; + PKIX_PL_OID *subjectDomainPolicy = NULL; + + PKIX_ENTER + (CERTCHAINCHECKER, + "pkix_PolicyChecker_MapGetSubjectDomainPolicies"); + PKIX_NULLCHECK_TWO(policy, pSubjectDomainPolicies); + + if (certPolicyMaps) { + PKIX_CHECK(PKIX_List_GetLength + (certPolicyMaps, + &numEntries, + plContext), + PKIX_LISTGETLENGTHFAILED); + } + + for (index = 0; index < numEntries; index++) { + PKIX_CHECK(PKIX_List_GetItem + (certPolicyMaps, index, (PKIX_PL_Object **)&map, plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_NULLCHECK_ONE(map); + + PKIX_CHECK(PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy + (map, &issuerDomainPolicy, plContext), + PKIX_CERTPOLICYMAPGETISSUERDOMAINPOLICYFAILED); + + PKIX_EQUALS + (policy, issuerDomainPolicy, &match, plContext, + PKIX_OBJECTEQUALSFAILED); + + if (match) { + if (!subjectList) { + PKIX_CHECK(PKIX_List_Create(&subjectList, plContext), + PKIX_LISTCREATEFAILED); + } + + PKIX_CHECK(PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy + (map, &subjectDomainPolicy, plContext), + PKIX_CERTPOLICYMAPGETSUBJECTDOMAINPOLICYFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (subjectList, + (PKIX_PL_Object *)subjectDomainPolicy, + plContext), + PKIX_LISTAPPENDITEMFAILED); + } + + PKIX_DECREF(map); + PKIX_DECREF(issuerDomainPolicy); + PKIX_DECREF(subjectDomainPolicy); + } + + if (subjectList) { + PKIX_CHECK(PKIX_List_SetImmutable(subjectList, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + } + + *pSubjectDomainPolicies = subjectList; + +cleanup: + + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(subjectList); + } + + PKIX_DECREF(map); + PKIX_DECREF(issuerDomainPolicy); + PKIX_DECREF(subjectDomainPolicy); + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_PolicyChecker_MapGetMappedPolicies + * DESCRIPTION: + * + * Checks the List of CertPolicyMaps pointed to by "certPolicyMaps" to create a + * List of all IssuerDomainPolicies, and stores the result in + * "pMappedPolicies". + * + * The caller may not rely on the IssuerDomainPolicies to be in any particular + * order. IssuerDomainPolicies that appear in more than one CertPolicyMap will + * only appear once in "pMappedPolicies". If "certPolicyMaps" is empty the + * result will be an empty List. The created List is mutable. + * + * PARAMETERS: + * "certPolicyMaps" + * Address of List of CertPolicyMaps to be searched. May be empty, but + * must be non-NULL. + * "pMappedPolicies" + * Address where the result will be stored. Must be non-NULL. + * "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 CertChainChecker Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_PolicyChecker_MapGetMappedPolicies( + PKIX_List *certPolicyMaps, + PKIX_List **pMappedPolicies, + void *plContext) +{ + PKIX_PL_CertPolicyMap *map = NULL; + PKIX_List *mappedList = NULL; + PKIX_UInt32 numEntries = 0; + PKIX_UInt32 index = 0; + PKIX_Boolean isContained = PKIX_FALSE; + PKIX_PL_OID *issuerDomainPolicy = NULL; + + PKIX_ENTER + (CERTCHAINCHECKER, "pkix_PolicyChecker_MapGetMappedPolicies"); + PKIX_NULLCHECK_TWO(certPolicyMaps, pMappedPolicies); + + PKIX_CHECK(PKIX_List_Create(&mappedList, plContext), + PKIX_LISTCREATEFAILED); + + PKIX_CHECK(PKIX_List_GetLength(certPolicyMaps, &numEntries, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (index = 0; index < numEntries; index++) { + PKIX_CHECK(PKIX_List_GetItem + (certPolicyMaps, index, (PKIX_PL_Object **)&map, plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_NULLCHECK_ONE(map); + + PKIX_CHECK(PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy + (map, &issuerDomainPolicy, plContext), + PKIX_CERTPOLICYMAPGETISSUERDOMAINPOLICYFAILED); + + PKIX_CHECK(pkix_List_Contains + (mappedList, + (PKIX_PL_Object *)issuerDomainPolicy, + &isContained, + plContext), + PKIX_LISTCONTAINSFAILED); + + if (isContained == PKIX_FALSE) { + PKIX_CHECK(PKIX_List_AppendItem + (mappedList, + (PKIX_PL_Object *)issuerDomainPolicy, + plContext), + PKIX_LISTAPPENDITEMFAILED); + } + + PKIX_DECREF(map); + PKIX_DECREF(issuerDomainPolicy); + } + + *pMappedPolicies = mappedList; + +cleanup: + + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(mappedList); + } + + PKIX_DECREF(map); + PKIX_DECREF(issuerDomainPolicy); + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_PolicyChecker_MakeMutableCopy + * DESCRIPTION: + * + * Creates a mutable copy of the List pointed to by "list", which may or may + * not be immutable, and stores the address at "pMutableCopy". + * + * PARAMETERS: + * "list" + * Address of List to be copied. Must be non-NULL. + * "pMutableCopy" + * Address where mutable copy will be stored. Must be non-NULL. + * "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 CertChainChecker Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +static PKIX_Error * +pkix_PolicyChecker_MakeMutableCopy( + PKIX_List *list, + PKIX_List **pMutableCopy, + void *plContext) +{ + PKIX_List *newList = NULL; + PKIX_UInt32 listLen = 0; + PKIX_UInt32 listIx = 0; + PKIX_PL_Object *object = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_MakeMutableCopy"); + PKIX_NULLCHECK_TWO(list, pMutableCopy); + + PKIX_CHECK(PKIX_List_Create(&newList, plContext), + PKIX_LISTCREATEFAILED); + + PKIX_CHECK(PKIX_List_GetLength(list, &listLen, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (listIx = 0; listIx < listLen; listIx++) { + + PKIX_CHECK(PKIX_List_GetItem(list, listIx, &object, plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(PKIX_List_AppendItem(newList, object, plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(object); + } + + *pMutableCopy = newList; + newList = NULL; + +cleanup: + PKIX_DECREF(newList); + PKIX_DECREF(object); + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_PolicyChecker_MakeSingleton + * DESCRIPTION: + * + * Creates a new List containing the Object pointed to by "listItem", using + * the Boolean value of "immutability" to determine whether to set the List + * immutable, and stores the address at "pList". + * + * PARAMETERS: + * "listItem" + * Address of Object to be inserted into the new List. Must be non-NULL. + * "immutability" + * Boolean value indicating whether new List is to be immutable + * "pList" + * Address where List will be stored. Must be non-NULL. + * "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 CertChainChecker Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +static PKIX_Error * +pkix_PolicyChecker_MakeSingleton( + PKIX_PL_Object *listItem, + PKIX_Boolean immutability, + PKIX_List **pList, + void *plContext) +{ + PKIX_List *newList = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_MakeSingleton"); + PKIX_NULLCHECK_TWO(listItem, pList); + + PKIX_CHECK(PKIX_List_Create(&newList, plContext), + PKIX_LISTCREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (newList, (PKIX_PL_Object *)listItem, plContext), + PKIX_LISTAPPENDITEMFAILED); + + if (immutability) { + PKIX_CHECK(PKIX_List_SetImmutable(newList, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + } + + *pList = newList; + +cleanup: + if (PKIX_ERROR_RECEIVED) { + PKIX_DECREF(newList); + } + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_PolicyChecker_Spawn + * DESCRIPTION: + * + * Creates a new childNode for the parent pointed to by "parent", using + * the OID pointed to by "policyOID", the List of CertPolicyQualifiers + * pointed to by "qualifiers", the List of OIDs pointed to by + * "subjectDomainPolicies", and the PolicyCheckerState pointed to by + * "state". The new node will be added to "parent". + * + * The validPolicy of the new node is set from the OID pointed to by + * "policyOID". The policy qualifiers for the new node is set from the + * List of qualifiers pointed to by "qualifiers", and may be NULL or + * empty if the argument provided was NULL or empty. The criticality is + * set according to the criticality obtained from the PolicyCheckerState. + * If "subjectDomainPolicies" is NULL, the expectedPolicySet of the + * child is set to contain the same policy as the validPolicy. If + * "subjectDomainPolicies" is not NULL, it is used as the value for + * the expectedPolicySet. + * + * The PolicyCheckerState also contains a constant, anyPolicy, which is + * compared to "policyOID". If they match, the address of the childNode + * is saved in the state's newAnyPolicyNode. + * + * PARAMETERS: + * "parent" + * Address of PolicyNode to which the child will be linked. Must be + * non-NULL. + * "policyOID" + * Address of OID of the new child's validPolicy and also, if + * subjectDomainPolicies is NULL, of the new child's expectedPolicySet. + * Must be non-NULL. + * "qualifiers" + * Address of List of CertPolicyQualifiers. May be NULL or empty. + * "subjectDomainPolicies" + * Address of List of OIDs indicating the policies to which "policy" is + * mapped. May be empty or NULL. + * "state" + * Address of the current PKIX_PolicyCheckerState. Must be non-NULL.. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds + * Returns a CertChainChecker Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +static PKIX_Error * +pkix_PolicyChecker_Spawn( + PKIX_PolicyNode *parent, + PKIX_PL_OID *policyOID, + PKIX_List *qualifiers, /* CertPolicyQualifiers */ + PKIX_List *subjectDomainPolicies, + PKIX_PolicyCheckerState *state, + void *plContext) +{ + PKIX_List *expectedSet = NULL; /* OIDs */ + PKIX_PolicyNode *childNode = NULL; + PKIX_Boolean match = PKIX_FALSE; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_Spawn"); + PKIX_NULLCHECK_THREE(policyOID, parent, state); + + if (subjectDomainPolicies) { + + PKIX_INCREF(subjectDomainPolicies); + expectedSet = subjectDomainPolicies; + + } else { + /* Create the child's ExpectedPolicy Set */ + PKIX_CHECK(pkix_PolicyChecker_MakeSingleton + ((PKIX_PL_Object *)policyOID, + PKIX_TRUE, /* make expectedPolicySet immutable */ + &expectedSet, + plContext), + PKIX_POLICYCHECKERMAKESINGLETONFAILED); + } + + PKIX_CHECK(pkix_PolicyNode_Create + (policyOID, + qualifiers, + state->certPoliciesCritical, + expectedSet, + &childNode, + plContext), + PKIX_POLICYNODECREATEFAILED); + + /* + * If we had a non-empty mapping, we know the new node could not + * have been created with a validPolicy of anyPolicy. Otherwise, + * check whether we just created a new node with anyPolicy, because + * in that case we want to save the child pointer in newAnyPolicyNode. + */ + if (!subjectDomainPolicies) { + PKIX_EQUALS(policyOID, state->anyPolicyOID, &match, plContext, + PKIX_OBJECTEQUALSFAILED); + + if (match) { + PKIX_DECREF(state->newAnyPolicyNode); + PKIX_INCREF(childNode); + state->newAnyPolicyNode = childNode; + } + } + + PKIX_CHECK(pkix_PolicyNode_AddToParent(parent, childNode, plContext), + PKIX_POLICYNODEADDTOPARENTFAILED); + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)state, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + +cleanup: + PKIX_DECREF(childNode); + PKIX_DECREF(expectedSet); + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_PolicyChecker_CheckPolicyRecursive + * DESCRIPTION: + * + * Performs policy processing for the policy whose OID is pointed to by + * "policyOID" and whose List of CertPolicyQualifiers is pointed to by + * "policyQualifiers", using the List of policy OIDs pointed to by + * "subjectDomainPolicies" and the PolicyNode pointed to by "currentNode", + * in accordance with the current PolicyCheckerState pointed to by "state", + * and setting "pChildNodeCreated" to TRUE if a new childNode is created. + * Note: "pChildNodeCreated" is not set to FALSE if no childNode is created. + * The intent of the design is that the caller can set a variable to FALSE + * initially, prior to a recursive set of calls. At the end, the variable + * can be tested to see whether *any* of the calls created a child node. + * + * If the currentNode is not at the bottom of the tree, this function + * calls itself recursively for each child of currentNode. At the bottom of + * the tree, it creates new child nodes as appropriate. This function will + * never be called with policy = anyPolicy. + * + * This function implements the processing described in RFC3280 + * Section 6.1.3(d)(1)(i). + * + * PARAMETERS: + * "policyOID" + * Address of OID of the policy to be checked for. Must be non-NULL. + * "policyQualifiers" + * Address of List of CertPolicyQualifiers of the policy to be checked for. + * May be empty or NULL. + * "subjectDomainPolicies" + * Address of List of OIDs indicating the policies to which "policy" is + * mapped. May be empty or NULL. + * "currentNode" + * Address of PolicyNode whose descendants will be checked, if not at the + * bottom of the tree; or whose expectedPolicySet will be compared to + * "policy", if at the bottom. Must be non-NULL. + * "state" + * Address of PolicyCheckerState of the current PolicyChecker. Must be + * non-NULL. + * "pChildNodeCreated" + * Address of the Boolean that will be set TRUE if this function + * creates a child node. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds + * Returns a CertChainChecker Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +static PKIX_Error * +pkix_PolicyChecker_CheckPolicyRecursive( + PKIX_PL_OID *policyOID, + PKIX_List *policyQualifiers, + PKIX_List *subjectDomainPolicies, + PKIX_PolicyNode *currentNode, + PKIX_PolicyCheckerState *state, + PKIX_Boolean *pChildNodeCreated, + void *plContext) +{ + PKIX_UInt32 depth = 0; + PKIX_UInt32 numChildren = 0; + PKIX_UInt32 childIx = 0; + PKIX_Boolean isIncluded = PKIX_FALSE; + PKIX_List *children = NULL; /* PolicyNodes */ + PKIX_PolicyNode *childNode = NULL; + PKIX_List *expectedPolicies = NULL; /* OIDs */ + + PKIX_ENTER + (CERTCHAINCHECKER, + "pkix_PolicyChecker_CheckPolicyRecursive"); + PKIX_NULLCHECK_FOUR(policyOID, currentNode, state, pChildNodeCreated); + + /* if not at the bottom of the tree */ + PKIX_CHECK(PKIX_PolicyNode_GetDepth + (currentNode, &depth, plContext), + PKIX_POLICYNODEGETDEPTHFAILED); + + if (depth < (state->certsProcessed)) { + PKIX_CHECK(pkix_PolicyNode_GetChildrenMutable + (currentNode, &children, plContext), + PKIX_POLICYNODEGETCHILDRENMUTABLEFAILED); + + if (children) { + PKIX_CHECK(PKIX_List_GetLength + (children, &numChildren, plContext), + PKIX_LISTGETLENGTHFAILED); + } + + for (childIx = 0; childIx < numChildren; childIx++) { + + PKIX_CHECK(PKIX_List_GetItem + (children, + childIx, + (PKIX_PL_Object **)&childNode, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_PolicyChecker_CheckPolicyRecursive + (policyOID, + policyQualifiers, + subjectDomainPolicies, + childNode, + state, + pChildNodeCreated, + plContext), + PKIX_POLICYCHECKERCHECKPOLICYRECURSIVEFAILED); + + PKIX_DECREF(childNode); + } + } else { /* if at the bottom of the tree */ + + /* Check whether policy is in this node's expectedPolicySet */ + PKIX_CHECK(PKIX_PolicyNode_GetExpectedPolicies + (currentNode, &expectedPolicies, plContext), + PKIX_POLICYNODEGETEXPECTEDPOLICIESFAILED); + + PKIX_NULLCHECK_ONE(expectedPolicies); + + PKIX_CHECK(pkix_List_Contains + (expectedPolicies, + (PKIX_PL_Object *)policyOID, + &isIncluded, + plContext), + PKIX_LISTCONTAINSFAILED); + + if (isIncluded) { + PKIX_CHECK(pkix_PolicyChecker_Spawn + (currentNode, + policyOID, + policyQualifiers, + subjectDomainPolicies, + state, + plContext), + PKIX_POLICYCHECKERSPAWNFAILED); + + *pChildNodeCreated = PKIX_TRUE; + } + } + +cleanup: + + PKIX_DECREF(children); + PKIX_DECREF(childNode); + PKIX_DECREF(expectedPolicies); + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_PolicyChecker_CheckPolicy + * DESCRIPTION: + * + * Performs the non-recursive portion of the policy processing for the policy + * whose OID is pointed to by "policyOID" and whose List of + * CertPolicyQualifiers is pointed to by "policyQualifiers", for the + * Certificate pointed to by "cert" with the List of CertPolicyMaps pointed + * to by "maps", in accordance with the current PolicyCheckerState pointed + * to by "state". + * + * This function implements the processing described in RFC3280 + * Section 6.1.3(d)(1)(i). + * + * PARAMETERS: + * "policyOID" + * Address of OID of the policy to be checked for. Must be non-NULL. + * "policyQualifiers" + * Address of List of CertPolicyQualifiers of the policy to be checked for. + * May be empty or NULL. + * "cert" + * Address of the current certificate. Must be non-NULL. + * "maps" + * Address of List of CertPolicyMaps for the current certificate + * "state" + * Address of PolicyCheckerState of the current PolicyChecker. Must be + * non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds + * Returns a CertChainChecker Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +static PKIX_Error * +pkix_PolicyChecker_CheckPolicy( + PKIX_PL_OID *policyOID, + PKIX_List *policyQualifiers, + PKIX_PL_Cert *cert, + PKIX_List *maps, + PKIX_PolicyCheckerState *state, + void *plContext) +{ + PKIX_Boolean childNodeCreated = PKIX_FALSE; + PKIX_Boolean okToSpawn = PKIX_FALSE; + PKIX_Boolean found = PKIX_FALSE; + PKIX_List *subjectDomainPolicies = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_CheckPolicy"); + PKIX_NULLCHECK_THREE(policyOID, cert, state); + + /* + * If this is not the last certificate, get the set of + * subjectDomainPolicies that "policy" maps to, according to the + * current cert's policy mapping extension. That set will be NULL + * if the current cert does not have a policy mapping extension, + * or if the current policy is not mapped. + */ + if (state->certsProcessed != (state->numCerts - 1)) { + PKIX_CHECK(pkix_PolicyChecker_MapGetSubjectDomainPolicies + (maps, policyOID, &subjectDomainPolicies, plContext), + PKIX_POLICYCHECKERMAPGETSUBJECTDOMAINPOLICIESFAILED); + } + + /* + * Section 6.1.4(b)(2) tells us that if policyMapping is zero, we + * will have to delete any nodes created with validPolicies equal to + * policies that appear as issuerDomainPolicies in a policy mapping + * extension. Let's avoid creating any such nodes. + */ + if ((state->policyMapping) == 0) { + if (subjectDomainPolicies) { + goto cleanup; + } + } + + PKIX_CHECK(pkix_PolicyChecker_CheckPolicyRecursive + (policyOID, + policyQualifiers, + subjectDomainPolicies, + state->validPolicyTree, + state, + &childNodeCreated, + plContext), + PKIX_POLICYCHECKERCHECKPOLICYRECURSIVEFAILED); + + if (!childNodeCreated) { + /* + * Section 6.1.3(d)(1)(ii) + * There was no match. If there was a node at + * depth i-1 with valid policy anyPolicy, + * generate a node subordinate to that. + * + * But that means this created node would be in + * the valid-policy-node-set, and will be + * pruned in 6.1.5(g)(iii)(2) unless it is in + * the user-initial-policy-set or the user- + * initial-policy-set is {anyPolicy}. So check, + * and don't create it if it will be pruned. + */ + if (state->anyPolicyNodeAtBottom) { + if (state->initialIsAnyPolicy) { + okToSpawn = PKIX_TRUE; + } else { + PKIX_CHECK(pkix_List_Contains + (state->mappedUserInitialPolicySet, + (PKIX_PL_Object *)policyOID, + &okToSpawn, + plContext), + PKIX_LISTCONTAINSFAILED); + } + if (okToSpawn) { + PKIX_CHECK(pkix_PolicyChecker_Spawn + (state->anyPolicyNodeAtBottom, + policyOID, + policyQualifiers, + subjectDomainPolicies, + state, + plContext), + PKIX_POLICYCHECKERSPAWNFAILED); + childNodeCreated = PKIX_TRUE; + } + } + } + + if (childNodeCreated) { + /* + * If this policy had qualifiers, and the certificate policies + * extension was marked critical, and the user cannot deal with + * policy qualifiers, throw an error. + */ + if (policyQualifiers && + state->certPoliciesCritical && + state->policyQualifiersRejected) { + PKIX_ERROR + (PKIX_QUALIFIERSINCRITICALCERTIFICATEPOLICYEXTENSION); + } + /* + * If the policy we just propagated was in the list of mapped + * policies, remove it from the list. That list is used, at the + * end, to determine policies that have not been propagated. + */ + if (state->mappedPolicyOIDs) { + PKIX_CHECK(pkix_List_Contains + (state->mappedPolicyOIDs, + (PKIX_PL_Object *)policyOID, + &found, + plContext), + PKIX_LISTCONTAINSFAILED); + if (found) { + PKIX_CHECK(pkix_List_Remove + (state->mappedPolicyOIDs, + (PKIX_PL_Object *)policyOID, + plContext), + PKIX_LISTREMOVEFAILED); + } + } + } + +cleanup: + + PKIX_DECREF(subjectDomainPolicies); + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_PolicyChecker_CheckAny + * DESCRIPTION: + * Performs the creation of PolicyNodes, for the PolicyNode pointed to by + * "currentNode" and PolicyNodes subordinate to it, using the List of + * qualifiers pointed to by "qualsOfAny", in accordance with the current + * certificate's PolicyMaps pointed to by "policyMaps" and the current + * PolicyCheckerState pointed to by "state". + * + * If the currentNode is not just above the bottom of the validPolicyTree, this + * function calls itself recursively for each child of currentNode. At the + * level just above the bottom, for each policy in the currentNode's + * expectedPolicySet not already present in a child node, it creates a new + * child node. The validPolicy of the child created, and its expectedPolicySet, + * will be the policy from the currentNode's expectedPolicySet. The policy + * qualifiers will be the qualifiers from the current certificate's anyPolicy, + * the "qualsOfAny" parameter. If the currentNode's expectedSet includes + * anyPolicy, a childNode will be created with a policy of anyPolicy. This is + * the only way such a node can be created. + * + * This function is called only when anyPolicy is one of the current + * certificate's policies. This function implements the processing described + * in RFC3280 Section 6.1.3(d)(2). + * + * PARAMETERS: + * "currentNode" + * Address of PolicyNode whose descendants will be checked, if not at the + * bottom of the tree; or whose expectedPolicySet will be compared to those + * in "alreadyPresent", if at the bottom. Must be non-NULL. + * "qualsOfAny" + * Address of List of qualifiers of the anyPolicy in the current + * certificate. May be empty or NULL. + * "policyMaps" + * Address of the List of PolicyMaps of the current certificate. May be + * empty or NULL. + * "state" + * Address of the current state of the PKIX_PolicyChecker. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds + * Returns a CertChainChecker Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +static PKIX_Error * +pkix_PolicyChecker_CheckAny( + PKIX_PolicyNode *currentNode, + PKIX_List *qualsOfAny, /* CertPolicyQualifiers */ + PKIX_List *policyMaps, /* CertPolicyMaps */ + PKIX_PolicyCheckerState *state, + void *plContext) +{ + PKIX_UInt32 depth = 0; + PKIX_UInt32 numChildren = 0; + PKIX_UInt32 childIx = 0; + PKIX_UInt32 numPolicies = 0; + PKIX_UInt32 polx = 0; + PKIX_Boolean isIncluded = PKIX_FALSE; + PKIX_List *children = NULL; /* PolicyNodes */ + PKIX_PolicyNode *childNode = NULL; + PKIX_List *expectedPolicies = NULL; /* OIDs */ + PKIX_PL_OID *policyOID = NULL; + PKIX_PL_OID *childPolicy = NULL; + PKIX_List *subjectDomainPolicies = NULL; /* OIDs */ + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_CheckAny"); + PKIX_NULLCHECK_TWO(currentNode, state); + + PKIX_CHECK(PKIX_PolicyNode_GetDepth + (currentNode, &depth, plContext), + PKIX_POLICYNODEGETDEPTHFAILED); + + PKIX_CHECK(pkix_PolicyNode_GetChildrenMutable + (currentNode, &children, plContext), + PKIX_POLICYNODEGETCHILDRENMUTABLEFAILED); + + if (children) { + PKIX_CHECK(PKIX_List_GetLength + (children, &numChildren, plContext), + PKIX_LISTGETLENGTHFAILED); + } + + if (depth < (state->certsProcessed)) { + for (childIx = 0; childIx < numChildren; childIx++) { + + PKIX_CHECK(PKIX_List_GetItem + (children, + childIx, + (PKIX_PL_Object **)&childNode, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_NULLCHECK_ONE(childNode); + PKIX_CHECK(pkix_PolicyChecker_CheckAny + (childNode, + qualsOfAny, + policyMaps, + state, + plContext), + PKIX_POLICYCHECKERCHECKANYFAILED); + + PKIX_DECREF(childNode); + } + } else { /* if at the bottom of the tree */ + + PKIX_CHECK(PKIX_PolicyNode_GetExpectedPolicies + (currentNode, &expectedPolicies, plContext), + PKIX_POLICYNODEGETEXPECTEDPOLICIESFAILED); + + /* Expected Policy Set is not allowed to be NULL */ + PKIX_NULLCHECK_ONE(expectedPolicies); + + PKIX_CHECK(PKIX_List_GetLength + (expectedPolicies, &numPolicies, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (polx = 0; polx < numPolicies; polx++) { + PKIX_CHECK(PKIX_List_GetItem + (expectedPolicies, + polx, + (PKIX_PL_Object **)&policyOID, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_NULLCHECK_ONE(policyOID); + + isIncluded = PKIX_FALSE; + + for (childIx = 0; + (!isIncluded && (childIx < numChildren)); + childIx++) { + + PKIX_CHECK(PKIX_List_GetItem + (children, + childIx, + (PKIX_PL_Object **)&childNode, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_NULLCHECK_ONE(childNode); + + PKIX_CHECK(PKIX_PolicyNode_GetValidPolicy + (childNode, &childPolicy, plContext), + PKIX_POLICYNODEGETVALIDPOLICYFAILED); + + PKIX_NULLCHECK_ONE(childPolicy); + + PKIX_EQUALS(policyOID, childPolicy, &isIncluded, plContext, + PKIX_OBJECTEQUALSFAILED); + + PKIX_DECREF(childNode); + PKIX_DECREF(childPolicy); + } + + if (!isIncluded) { + if (policyMaps) { + PKIX_CHECK + (pkix_PolicyChecker_MapGetSubjectDomainPolicies + (policyMaps, + policyOID, + &subjectDomainPolicies, + plContext), + PKIX_POLICYCHECKERMAPGETSUBJECTDOMAINPOLICIESFAILED); + } + PKIX_CHECK(pkix_PolicyChecker_Spawn + (currentNode, + policyOID, + qualsOfAny, + subjectDomainPolicies, + state, + plContext), + PKIX_POLICYCHECKERSPAWNFAILED); + PKIX_DECREF(subjectDomainPolicies); + } + + PKIX_DECREF(policyOID); + } + } + +cleanup: + + PKIX_DECREF(children); + PKIX_DECREF(childNode); + PKIX_DECREF(expectedPolicies); + PKIX_DECREF(policyOID); + PKIX_DECREF(childPolicy); + PKIX_DECREF(subjectDomainPolicies); + + PKIX_RETURN(CERTCHAINCHECKER); + +} + +/* + * FUNCTION: pkix_PolicyChecker_CalculateIntersection + * DESCRIPTION: + * + * Processes the PolicyNode pointed to by "currentNode", and its descendants, + * using the PolicyCheckerState pointed to by "state", using the List at + * the address pointed to by "nominees" the OIDs of policies that are in the + * user-initial-policy-set but are not represented among the nodes at the + * bottom of the tree, and storing at "pShouldBePruned" the value TRUE if + * currentNode is childless at the end of this processing, FALSE if it has + * children or is at the bottom of the tree. + * + * When this function is called at the top level, "nominees" should be the List + * of all policies in the user-initial-policy-set. Policies that are + * represented in the valid-policy-node-set are removed from this List. As a + * result when nodes are created according to 6.1.5.(g)(iii)(3)(b), a node will + * be created for each policy remaining in this List. + * + * This function implements the calculation of the intersection of the + * validPolicyTree with the user-initial-policy-set, as described in + * RFC 3280 6.1.5(g)(iii). + * + * PARAMETERS: + * "currentNode" + * Address of PolicyNode whose descendants will be processed as described. + * Must be non-NULL. + * "state" + * Address of the current state of the PKIX_PolicyChecker. Must be non-NULL + * "nominees" + * Address of List of the OIDs for which nodes should be created to replace + * anyPolicy nodes. Must be non-NULL but may be empty. + * "pShouldBePruned" + * Address where Boolean return value, set to TRUE if this PolicyNode + * should be deleted, is stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds + * Returns a CertChainChecker Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +static PKIX_Error * +pkix_PolicyChecker_CalculateIntersection( + PKIX_PolicyNode *currentNode, + PKIX_PolicyCheckerState *state, + PKIX_List *nominees, /* OIDs */ + PKIX_Boolean *pShouldBePruned, + void *plContext) +{ + PKIX_Boolean currentPolicyIsAny = PKIX_FALSE; + PKIX_Boolean parentPolicyIsAny = PKIX_FALSE; + PKIX_Boolean currentPolicyIsValid = PKIX_FALSE; + PKIX_Boolean shouldBePruned = PKIX_FALSE; + PKIX_Boolean priorCriticality = PKIX_FALSE; + PKIX_UInt32 depth = 0; + PKIX_UInt32 numChildren = 0; + PKIX_UInt32 childIndex = 0; + PKIX_UInt32 numNominees = 0; + PKIX_UInt32 polIx = 0; + PKIX_PL_OID *currentPolicy = NULL; + PKIX_PL_OID *parentPolicy = NULL; + PKIX_PL_OID *substPolicy = NULL; + PKIX_PolicyNode *parent = NULL; + PKIX_PolicyNode *child = NULL; + PKIX_List *children = NULL; /* PolicyNodes */ + PKIX_List *policyQualifiers = NULL; + + PKIX_ENTER + (CERTCHAINCHECKER, + "pkix_PolicyChecker_CalculateIntersection"); + + /* + * We call this function if the valid_policy_tree is not NULL and + * the user-initial-policy-set is not any-policy. + */ + if (!state->validPolicyTree || state->initialIsAnyPolicy) { + PKIX_ERROR(PKIX_PRECONDITIONFAILED); + } + + PKIX_NULLCHECK_FOUR(currentNode, state, nominees, pShouldBePruned); + + PKIX_CHECK(PKIX_PolicyNode_GetValidPolicy + (currentNode, ¤tPolicy, plContext), + PKIX_POLICYNODEGETVALIDPOLICYFAILED); + + PKIX_NULLCHECK_TWO(state->anyPolicyOID, currentPolicy); + + PKIX_EQUALS + (state->anyPolicyOID, + currentPolicy, + ¤tPolicyIsAny, + plContext, + PKIX_OBJECTEQUALSFAILED); + + PKIX_CHECK(PKIX_PolicyNode_GetParent(currentNode, &parent, plContext), + PKIX_POLICYNODEGETPARENTFAILED); + + if (currentPolicyIsAny == PKIX_FALSE) { + + /* + * If we are at the top of the tree, or if our + * parent's validPolicy is anyPolicy, we are in + * the valid policy node set. + */ + if (parent) { + PKIX_CHECK(PKIX_PolicyNode_GetValidPolicy + (parent, &parentPolicy, plContext), + PKIX_POLICYNODEGETVALIDPOLICYFAILED); + + PKIX_NULLCHECK_ONE(parentPolicy); + + PKIX_EQUALS + (state->anyPolicyOID, + parentPolicy, + &parentPolicyIsAny, + plContext, + PKIX_OBJECTEQUALSFAILED); + } + + /* + * Section 6.1.5(g)(iii)(2) + * If this node's policy is not in the user-initial-policy-set, + * it is not in the intersection. Prune it. + */ + if (!parent || parentPolicyIsAny) { + PKIX_CHECK(pkix_List_Contains + (state->userInitialPolicySet, + (PKIX_PL_Object *)currentPolicy, + ¤tPolicyIsValid, + plContext), + PKIX_LISTCONTAINSFAILED); + if (!currentPolicyIsValid) { + *pShouldBePruned = PKIX_TRUE; + goto cleanup; + } + + /* + * If this node's policy is in the user-initial-policy- + * set, it will propagate that policy into the next + * level of the tree. Remove the policy from the list + * of policies that an anyPolicy will spawn. + */ + PKIX_CHECK(pkix_List_Remove + (nominees, + (PKIX_PL_Object *)currentPolicy, + plContext), + PKIX_LISTREMOVEFAILED); + } + } + + + /* Are we at the bottom of the tree? */ + + PKIX_CHECK(PKIX_PolicyNode_GetDepth + (currentNode, &depth, plContext), + PKIX_POLICYNODEGETDEPTHFAILED); + + if (depth == (state->numCerts)) { + /* + * Section 6.1.5(g)(iii)(3) + * Replace anyPolicy nodes... + */ + if (currentPolicyIsAny == PKIX_TRUE) { + + /* replace this node */ + + PKIX_CHECK(PKIX_List_GetLength + (nominees, &numNominees, plContext), + PKIX_LISTGETLENGTHFAILED); + + if (numNominees) { + + PKIX_CHECK(PKIX_PolicyNode_GetPolicyQualifiers + (currentNode, + &policyQualifiers, + plContext), + PKIX_POLICYNODEGETPOLICYQUALIFIERSFAILED); + + PKIX_CHECK(PKIX_PolicyNode_IsCritical + (currentNode, &priorCriticality, plContext), + PKIX_POLICYNODEISCRITICALFAILED); + } + + PKIX_NULLCHECK_ONE(parent); + + for (polIx = 0; polIx < numNominees; polIx++) { + + PKIX_CHECK(PKIX_List_GetItem + (nominees, + polIx, + (PKIX_PL_Object **)&substPolicy, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_PolicyChecker_Spawn + (parent, + substPolicy, + policyQualifiers, + NULL, + state, + plContext), + PKIX_POLICYCHECKERSPAWNFAILED); + + PKIX_DECREF(substPolicy); + + } + /* remove currentNode from parent */ + *pShouldBePruned = PKIX_TRUE; + /* + * We can get away with augmenting the parent's List + * of children because we started at the end and went + * toward the beginning. New nodes are added at the end. + */ + } + } else { + /* + * Section 6.1.5(g)(iii)(4) + * Prune any childless nodes above the bottom level + */ + PKIX_CHECK(pkix_PolicyNode_GetChildrenMutable + (currentNode, &children, plContext), + PKIX_POLICYNODEGETCHILDRENMUTABLEFAILED); + + /* CurrentNode should have been pruned if childless. */ + PKIX_NULLCHECK_ONE(children); + + PKIX_CHECK(PKIX_List_GetLength + (children, &numChildren, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (childIndex = numChildren; childIndex > 0; childIndex--) { + + PKIX_CHECK(PKIX_List_GetItem + (children, + childIndex - 1, + (PKIX_PL_Object **)&child, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_PolicyChecker_CalculateIntersection + (child, state, nominees, &shouldBePruned, plContext), + PKIX_POLICYCHECKERCALCULATEINTERSECTIONFAILED); + + if (PKIX_TRUE == shouldBePruned) { + + PKIX_CHECK(PKIX_List_DeleteItem + (children, childIndex - 1, plContext), + PKIX_LISTDELETEITEMFAILED); + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)state, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + } + + PKIX_DECREF(child); + } + + PKIX_CHECK(PKIX_List_GetLength + (children, &numChildren, plContext), + PKIX_LISTGETLENGTHFAILED); + + if (numChildren == 0) { + *pShouldBePruned = PKIX_TRUE; + } + } +cleanup: + PKIX_DECREF(currentPolicy); + PKIX_DECREF(parentPolicy); + PKIX_DECREF(substPolicy); + PKIX_DECREF(parent); + PKIX_DECREF(child); + PKIX_DECREF(children); + PKIX_DECREF(policyQualifiers); + + PKIX_RETURN(CERTCHAINCHECKER); + +} + +/* + * FUNCTION: pkix_PolicyChecker_PolicyMapProcessing + * DESCRIPTION: + * + * Performs the processing of Policies in the List of CertPolicyMaps pointed + * to by "policyMaps", using and updating the PolicyCheckerState pointed to by + * "state". + * + * This function implements the policyMap processing described in RFC3280 + * Section 6.1.4(b)(1), after certificate i has been processed, in preparation + * for certificate i+1. Section references are to that document. + * + * PARAMETERS: + * "policyMaps" + * Address of the List of CertPolicyMaps presented by certificate i. + * Must be non-NULL. + * "certPoliciesIncludeAny" + * Boolean value which is PKIX_TRUE if the current certificate asserts + * anyPolicy, PKIX_FALSE otherwise. + * "qualsOfAny" + * Address of List of qualifiers of the anyPolicy in the current + * certificate. May be empty or NULL. + * "state" + * Address of the current state of the PKIX_PolicyChecker. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds + * Returns a CertChainChecker Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +static PKIX_Error * +pkix_PolicyChecker_PolicyMapProcessing( + PKIX_List *policyMaps, /* CertPolicyMaps */ + PKIX_Boolean certPoliciesIncludeAny, + PKIX_List *qualsOfAny, + PKIX_PolicyCheckerState *state, + void *plContext) +{ + PKIX_UInt32 numPolicies = 0; + PKIX_UInt32 polX = 0; + PKIX_PL_OID *policyOID = NULL; + PKIX_List *newMappedPolicies = NULL; /* OIDs */ + PKIX_List *subjectDomainPolicies = NULL; /* OIDs */ + + PKIX_ENTER + (CERTCHAINCHECKER, + "pkix_PolicyChecker_PolicyMapProcessing"); + PKIX_NULLCHECK_THREE + (policyMaps, + state, + state->mappedUserInitialPolicySet); + + /* + * For each policy in mappedUserInitialPolicySet, if it is not mapped, + * append it to new policySet; if it is mapped, append its + * subjectDomainPolicies to new policySet. When done, this new + * policySet will replace mappedUserInitialPolicySet. + */ + PKIX_CHECK(PKIX_List_Create + (&newMappedPolicies, plContext), + PKIX_LISTCREATEFAILED); + + PKIX_CHECK(PKIX_List_GetLength + (state->mappedUserInitialPolicySet, + &numPolicies, + plContext), + PKIX_LISTGETLENGTHFAILED); + + for (polX = 0; polX < numPolicies; polX++) { + + PKIX_CHECK(PKIX_List_GetItem + (state->mappedUserInitialPolicySet, + polX, + (PKIX_PL_Object **)&policyOID, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_PolicyChecker_MapGetSubjectDomainPolicies + (policyMaps, + policyOID, + &subjectDomainPolicies, + plContext), + PKIX_POLICYCHECKERMAPGETSUBJECTDOMAINPOLICIESFAILED); + + if (subjectDomainPolicies) { + + PKIX_CHECK(pkix_List_AppendUnique + (newMappedPolicies, + subjectDomainPolicies, + plContext), + PKIX_LISTAPPENDUNIQUEFAILED); + + PKIX_DECREF(subjectDomainPolicies); + + } else { + PKIX_CHECK(PKIX_List_AppendItem + (newMappedPolicies, + (PKIX_PL_Object *)policyOID, + plContext), + PKIX_LISTAPPENDITEMFAILED); + } + PKIX_DECREF(policyOID); + } + + /* + * For each policy ID-P remaining in mappedPolicyOIDs, it has not been + * propagated to the bottom of the tree (depth i). If policyMapping + * is greater than zero and this cert contains anyPolicy and the tree + * contains an anyPolicy node at depth i-1, then we must create a node + * with validPolicy ID-P, the policy qualifiers of anyPolicy in + * this certificate, and expectedPolicySet the subjectDomainPolicies + * that ID-P maps to. We also then add those subjectDomainPolicies to + * the list of policies that will be accepted in the next certificate, + * the mappedUserInitialPolicySet. + */ + + if ((state->policyMapping > 0) && (certPoliciesIncludeAny) && + (state->anyPolicyNodeAtBottom) && (state->mappedPolicyOIDs)) { + + PKIX_CHECK(PKIX_List_GetLength + (state->mappedPolicyOIDs, + &numPolicies, + plContext), + PKIX_LISTGETLENGTHFAILED); + + for (polX = 0; polX < numPolicies; polX++) { + + PKIX_CHECK(PKIX_List_GetItem + (state->mappedPolicyOIDs, + polX, + (PKIX_PL_Object **)&policyOID, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_PolicyChecker_MapGetSubjectDomainPolicies + (policyMaps, + policyOID, + &subjectDomainPolicies, + plContext), + PKIX_POLICYCHECKERMAPGETSUBJECTDOMAINPOLICIESFAILED); + + PKIX_CHECK(pkix_PolicyChecker_Spawn + (state->anyPolicyNodeAtBottom, + policyOID, + qualsOfAny, + subjectDomainPolicies, + state, + plContext), + PKIX_POLICYCHECKERSPAWNFAILED); + + PKIX_CHECK(pkix_List_AppendUnique + (newMappedPolicies, + subjectDomainPolicies, + plContext), + PKIX_LISTAPPENDUNIQUEFAILED); + + PKIX_DECREF(subjectDomainPolicies); + PKIX_DECREF(policyOID); + } + } + + PKIX_CHECK(PKIX_List_SetImmutable(newMappedPolicies, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + PKIX_DECREF(state->mappedUserInitialPolicySet); + PKIX_INCREF(newMappedPolicies); + + state->mappedUserInitialPolicySet = newMappedPolicies; + +cleanup: + + PKIX_DECREF(policyOID); + PKIX_DECREF(newMappedPolicies); + PKIX_DECREF(subjectDomainPolicies); + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_PolicyChecker_WrapUpProcessing + * DESCRIPTION: + * + * Performs the wrap-up processing for the Cert pointed to by "cert", + * using and updating the PolicyCheckerState pointed to by "state". + * + * This function implements the wrap-up processing described in RFC3280 + * Section 6.1.5, after the final certificate has been processed. Section + * references in the comments are to that document. + * + * PARAMETERS: + * "cert" + * Address of the current (presumably the end entity) certificate. + * Must be non-NULL. + * "state" + * Address of the current state of the PKIX_PolicyChecker. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds + * Returns a CertChainChecker Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +static PKIX_Error * +pkix_PolicyChecker_WrapUpProcessing( + PKIX_PL_Cert *cert, + PKIX_PolicyCheckerState *state, + void *plContext) +{ + PKIX_Int32 explicitPolicySkipCerts = 0; + PKIX_Boolean isSelfIssued = PKIX_FALSE; + PKIX_Boolean shouldBePruned = PKIX_FALSE; + PKIX_List *nominees = NULL; /* OIDs */ +#if PKIX_CERTPOLICYCHECKERSTATEDEBUG + PKIX_PL_String *stateString = NULL; + char *stateAscii = NULL; + PKIX_UInt32 length; +#endif + + PKIX_ENTER + (CERTCHAINCHECKER, + "pkix_PolicyChecker_WrapUpProcessing"); + PKIX_NULLCHECK_THREE(cert, state, state->userInitialPolicySet); + +#if PKIX_CERTPOLICYCHECKERSTATEDEBUG + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object*)state, &stateString, plContext), + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (stateString, + PKIX_ESCASCII, + (void **)&stateAscii, + &length, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + PKIX_DEBUG_ARG("%s\n", stateAscii); + + PKIX_FREE(stateAscii); + PKIX_DECREF(stateString); +#endif + + /* Section 6.1.5(a) ... */ + PKIX_CHECK(pkix_IsCertSelfIssued + (cert, &isSelfIssued, plContext), + PKIX_ISCERTSELFISSUEDFAILED); + + if (!isSelfIssued) { + if (state->explicitPolicy > 0) { + + state->explicitPolicy--; + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)state, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + } + } + + /* Section 6.1.5(b) ... */ + PKIX_CHECK(PKIX_PL_Cert_GetRequireExplicitPolicy + (cert, &explicitPolicySkipCerts, plContext), + PKIX_CERTGETREQUIREEXPLICITPOLICYFAILED); + + if (explicitPolicySkipCerts == 0) { + state->explicitPolicy = 0; + } + + /* Section 6.1.5(g)(i) ... */ + + if (!(state->validPolicyTree)) { + goto cleanup; + } + + /* Section 6.1.5(g)(ii) ... */ + + if (state->initialIsAnyPolicy) { + goto cleanup; + } + + /* + * Section 6.1.5(g)(iii) ... + * Create a list of policies which could be substituted for anyPolicy. + * Start with a (mutable) copy of user-initial-policy-set. + */ + PKIX_CHECK(pkix_PolicyChecker_MakeMutableCopy + (state->userInitialPolicySet, &nominees, plContext), + PKIX_POLICYCHECKERMAKEMUTABLECOPYFAILED); + + PKIX_CHECK(pkix_PolicyChecker_CalculateIntersection + (state->validPolicyTree, /* node at top of tree */ + state, + nominees, + &shouldBePruned, + plContext), + PKIX_POLICYCHECKERCALCULATEINTERSECTIONFAILED); + + if (PKIX_TRUE == shouldBePruned) { + PKIX_DECREF(state->validPolicyTree); + } + + if (state->validPolicyTree) { + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)state->validPolicyTree, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + } + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)state, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + +#if PKIX_CERTPOLICYCHECKERSTATEDEBUG + if (state->validPolicyTree) { + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object*)state, &stateString, plContext), + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (stateString, + PKIX_ESCASCII, + (void **)&stateAscii, + &length, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + PKIX_DEBUG_ARG + ("After CalculateIntersection:\n%s\n", stateAscii); + + PKIX_FREE(stateAscii); + PKIX_DECREF(stateString); + } else { + PKIX_DEBUG("validPolicyTree is NULL\n"); + } +#endif + + /* Section 6.1.5(g)(iii)(4) ... */ + + if (state->validPolicyTree) { + + PKIX_CHECK(pkix_PolicyNode_Prune + (state->validPolicyTree, + state->numCerts, + &shouldBePruned, + plContext), + PKIX_POLICYNODEPRUNEFAILED); + + if (shouldBePruned) { + PKIX_DECREF(state->validPolicyTree); + } + } + + if (state->validPolicyTree) { + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)state->validPolicyTree, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + } + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)state, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + +#if PKIX_CERTPOLICYCHECKERSTATEDEBUG + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object*)state, &stateString, plContext), + PKIX_OBJECTTOSTRINGFAILED); + PKIX_CHECK(PKIX_PL_String_GetEncoded + (stateString, + PKIX_ESCASCII, + (void **)&stateAscii, + &length, + plContext), + PKIX_STRINGGETENCODEDFAILED); + PKIX_DEBUG_ARG("%s\n", stateAscii); + + PKIX_FREE(stateAscii); + PKIX_DECREF(stateString); +#endif + +cleanup: + + PKIX_DECREF(nominees); + + PKIX_RETURN(CERTCHAINCHECKER); +} + + +/* + * FUNCTION: pkix_PolicyChecker_Check + * (see comments in pkix_checker.h for PKIX_CertChainChecker_CheckCallback) + * + * Labels referring to sections, such as "Section 6.1.3(d)", refer to + * sections of RFC3280, Section 6.1.3 Basic Certificate Processing. + * + * If a non-fatal error occurs, it is unlikely that policy processing can + * continue. But it is still possible that chain validation could succeed if + * policy processing is non-critical. So if this function receives a non-fatal + * error from a lower level routine, it aborts policy processing by setting + * the validPolicyTree to NULL and tries to continue. + * + */ +static PKIX_Error * +pkix_PolicyChecker_Check( + PKIX_CertChainChecker *checker, + PKIX_PL_Cert *cert, + PKIX_List *unresolvedCriticals, /* OIDs */ + void **pNBIOContext, + void *plContext) +{ + PKIX_UInt32 numPolicies = 0; + PKIX_UInt32 polX = 0; + PKIX_Boolean result = PKIX_FALSE; + PKIX_Int32 inhibitMappingSkipCerts = 0; + PKIX_Int32 explicitPolicySkipCerts = 0; + PKIX_Int32 inhibitAnyPolicySkipCerts = 0; + PKIX_Boolean shouldBePruned = PKIX_FALSE; + PKIX_Boolean isSelfIssued = PKIX_FALSE; + PKIX_Boolean certPoliciesIncludeAny = PKIX_FALSE; + PKIX_Boolean doAnyPolicyProcessing = PKIX_FALSE; + + PKIX_PolicyCheckerState *state = NULL; + PKIX_List *certPolicyInfos = NULL; /* CertPolicyInfos */ + PKIX_PL_CertPolicyInfo *policy = NULL; + PKIX_PL_OID *policyOID = NULL; + PKIX_List *qualsOfAny = NULL; /* CertPolicyQualifiers */ + PKIX_List *policyQualifiers = NULL; /* CertPolicyQualifiers */ + PKIX_List *policyMaps = NULL; /* CertPolicyMaps */ + PKIX_List *mappedPolicies = NULL; /* OIDs */ + PKIX_Error *subroutineErr = NULL; +#if PKIX_CERTPOLICYCHECKERSTATEDEBUG + PKIX_PL_String *stateString = NULL; + char *stateAscii = NULL; + PKIX_PL_String *certString = NULL; + char *certAscii = NULL; + PKIX_UInt32 length; +#endif + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_Check"); + PKIX_NULLCHECK_FOUR(checker, cert, unresolvedCriticals, pNBIOContext); + + *pNBIOContext = NULL; /* we never block on pending I/O */ + + PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState + (checker, (PKIX_PL_Object **)&state, plContext), + PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); + + PKIX_NULLCHECK_TWO(state, state->certPoliciesExtension); + +#if PKIX_CERTPOLICYCHECKERSTATEDEBUG + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object*)state, &stateString, plContext), + PKIX_OBJECTTOSTRINGFAILED); + PKIX_CHECK(PKIX_PL_String_GetEncoded + (stateString, + PKIX_ESCASCII, + (void **)&stateAscii, + &length, + plContext), + PKIX_STRINGGETENCODEDFAILED); + PKIX_DEBUG_ARG("On entry %s\n", stateAscii); + PKIX_FREE(stateAscii); + PKIX_DECREF(stateString); +#endif + + /* + * Section 6.1.4(a) + * If this is not the last certificate, and if + * policyMapping extension is present, check that no + * issuerDomainPolicy or subjectDomainPolicy is equal to the + * special policy anyPolicy. + */ + if (state->certsProcessed != (state->numCerts - 1)) { + PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappings + (cert, &policyMaps, plContext), + PKIX_CERTGETPOLICYMAPPINGSFAILED); + } + + if (policyMaps) { + + PKIX_CHECK(pkix_PolicyChecker_MapContains + (policyMaps, state->anyPolicyOID, &result, plContext), + PKIX_POLICYCHECKERMAPCONTAINSFAILED); + + if (result) { + PKIX_ERROR(PKIX_INVALIDPOLICYMAPPINGINCLUDESANYPOLICY); + } + + PKIX_CHECK(pkix_PolicyChecker_MapGetMappedPolicies + (policyMaps, &mappedPolicies, plContext), + PKIX_POLICYCHECKERMAPGETMAPPEDPOLICIESFAILED); + + PKIX_DECREF(state->mappedPolicyOIDs); + PKIX_INCREF(mappedPolicies); + state->mappedPolicyOIDs = mappedPolicies; + } + + /* Section 6.1.3(d) */ + if (state->validPolicyTree) { + + PKIX_CHECK(PKIX_PL_Cert_GetPolicyInformation + (cert, &certPolicyInfos, plContext), + PKIX_CERTGETPOLICYINFORMATIONFAILED); + + if (certPolicyInfos) { + PKIX_CHECK(PKIX_List_GetLength + (certPolicyInfos, &numPolicies, plContext), + PKIX_LISTGETLENGTHFAILED); + } + + if (numPolicies > 0) { + + PKIX_CHECK(PKIX_PL_Cert_AreCertPoliciesCritical + (cert, &(state->certPoliciesCritical), plContext), + PKIX_CERTARECERTPOLICIESCRITICALFAILED); + + /* Section 6.1.3(d)(1) For each policy not equal to anyPolicy */ + for (polX = 0; polX < numPolicies; polX++) { + + PKIX_CHECK(PKIX_List_GetItem + (certPolicyInfos, + polX, + (PKIX_PL_Object **)&policy, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(PKIX_PL_CertPolicyInfo_GetPolicyId + (policy, &policyOID, plContext), + PKIX_CERTPOLICYINFOGETPOLICYIDFAILED); + + PKIX_CHECK(PKIX_PL_CertPolicyInfo_GetPolQualifiers + (policy, &policyQualifiers, plContext), + PKIX_CERTPOLICYINFOGETPOLQUALIFIERSFAILED); + + PKIX_EQUALS + (state->anyPolicyOID, + policyOID, + &result, + plContext, + PKIX_OIDEQUALFAILED); + + if (result == PKIX_FALSE) { + + /* Section 6.1.3(d)(1)(i) */ + subroutineErr = pkix_PolicyChecker_CheckPolicy + (policyOID, + policyQualifiers, + cert, + policyMaps, + state, + plContext); + if (subroutineErr) { + goto subrErrorCleanup; + } + + } else { + /* + * No descent (yet) for anyPolicy, but we will need + * the policyQualifiers for anyPolicy in 6.1.3(d)(2) + */ + PKIX_DECREF(qualsOfAny); + PKIX_INCREF(policyQualifiers); + qualsOfAny = policyQualifiers; + certPoliciesIncludeAny = PKIX_TRUE; + } + PKIX_DECREF(policy); + PKIX_DECREF(policyOID); + PKIX_DECREF(policyQualifiers); + } + + /* Section 6.1.3(d)(2) */ + if (certPoliciesIncludeAny == PKIX_TRUE) { + if (state->inhibitAnyPolicy > 0) { + doAnyPolicyProcessing = PKIX_TRUE; + } else { + /* We haven't yet counted the current cert */ + if (((state->certsProcessed) + 1) < + (state->numCerts)) { + + PKIX_CHECK(pkix_IsCertSelfIssued + (cert, + &doAnyPolicyProcessing, + plContext), + PKIX_ISCERTSELFISSUEDFAILED); + } + } + if (doAnyPolicyProcessing) { + subroutineErr = pkix_PolicyChecker_CheckAny + (state->validPolicyTree, + qualsOfAny, + policyMaps, + state, + plContext); + if (subroutineErr) { + goto subrErrorCleanup; + } + } + } + + /* Section 6.1.3(d)(3) */ + if (state->validPolicyTree) { + subroutineErr = pkix_PolicyNode_Prune + (state->validPolicyTree, + state->certsProcessed + 1, + &shouldBePruned, + plContext); + if (subroutineErr) { + goto subrErrorCleanup; + } + if (shouldBePruned) { + PKIX_DECREF(state->validPolicyTree); + PKIX_DECREF(state->anyPolicyNodeAtBottom); + } + } + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)state, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + + } else { + /* Section 6.1.3(e) */ + PKIX_DECREF(state->validPolicyTree); + PKIX_DECREF(state->anyPolicyNodeAtBottom); + PKIX_DECREF(state->newAnyPolicyNode); + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)state, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + } + } + + /* Section 6.1.3(f) */ + if ((0 == state->explicitPolicy) && (!state->validPolicyTree)) { + PKIX_ERROR(PKIX_CERTCHAINFAILSCERTIFICATEPOLICYVALIDATION); + } + + /* + * Remove Policy OIDs from list of unresolved critical + * extensions, if present. + */ + PKIX_CHECK(pkix_List_Remove + (unresolvedCriticals, + (PKIX_PL_Object *)state->certPoliciesExtension, + plContext), + PKIX_LISTREMOVEFAILED); + + PKIX_CHECK(pkix_List_Remove + (unresolvedCriticals, + (PKIX_PL_Object *)state->policyMappingsExtension, + plContext), + PKIX_LISTREMOVEFAILED); + + PKIX_CHECK(pkix_List_Remove + (unresolvedCriticals, + (PKIX_PL_Object *)state->policyConstraintsExtension, + plContext), + PKIX_LISTREMOVEFAILED); + + PKIX_CHECK(pkix_List_Remove + (unresolvedCriticals, + (PKIX_PL_Object *)state->inhibitAnyPolicyExtension, + plContext), + PKIX_LISTREMOVEFAILED); + + state->certsProcessed++; + + /* If this was not the last certificate, do next-cert preparation */ + if (state->certsProcessed != state->numCerts) { + + if (policyMaps) { + subroutineErr = pkix_PolicyChecker_PolicyMapProcessing + (policyMaps, + certPoliciesIncludeAny, + qualsOfAny, + state, + plContext); + if (subroutineErr) { + goto subrErrorCleanup; + } + } + + /* update anyPolicyNodeAtBottom pointer */ + PKIX_DECREF(state->anyPolicyNodeAtBottom); + state->anyPolicyNodeAtBottom = state->newAnyPolicyNode; + state->newAnyPolicyNode = NULL; + + /* Section 6.1.4(h) */ + PKIX_CHECK(pkix_IsCertSelfIssued + (cert, &isSelfIssued, plContext), + PKIX_ISCERTSELFISSUEDFAILED); + + if (!isSelfIssued) { + if (state->explicitPolicy > 0) { + state->explicitPolicy--; + } + if (state->policyMapping > 0) { + state->policyMapping--; + } + if (state->inhibitAnyPolicy > 0) { + state->inhibitAnyPolicy--; + } + } + + /* Section 6.1.4(i) */ + PKIX_CHECK(PKIX_PL_Cert_GetRequireExplicitPolicy + (cert, &explicitPolicySkipCerts, plContext), + PKIX_CERTGETREQUIREEXPLICITPOLICYFAILED); + + if (explicitPolicySkipCerts != -1) { + if (((PKIX_UInt32)explicitPolicySkipCerts) < + (state->explicitPolicy)) { + state->explicitPolicy = + ((PKIX_UInt32) explicitPolicySkipCerts); + } + } + + PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappingInhibited + (cert, &inhibitMappingSkipCerts, plContext), + PKIX_CERTGETPOLICYMAPPINGINHIBITEDFAILED); + + if (inhibitMappingSkipCerts != -1) { + if (((PKIX_UInt32)inhibitMappingSkipCerts) < + (state->policyMapping)) { + state->policyMapping = + ((PKIX_UInt32)inhibitMappingSkipCerts); + } + } + + PKIX_CHECK(PKIX_PL_Cert_GetInhibitAnyPolicy + (cert, &inhibitAnyPolicySkipCerts, plContext), + PKIX_CERTGETINHIBITANYPOLICYFAILED); + + if (inhibitAnyPolicySkipCerts != -1) { + if (((PKIX_UInt32)inhibitAnyPolicySkipCerts) < + (state->inhibitAnyPolicy)) { + state->inhibitAnyPolicy = + ((PKIX_UInt32)inhibitAnyPolicySkipCerts); + } + } + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)state, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + + } else { /* If this was the last certificate, do wrap-up processing */ + + /* Section 6.1.5 */ + subroutineErr = pkix_PolicyChecker_WrapUpProcessing + (cert, state, plContext); + if (subroutineErr) { + goto subrErrorCleanup; + } + + if ((0 == state->explicitPolicy) && (!state->validPolicyTree)) { + PKIX_ERROR(PKIX_CERTCHAINFAILSCERTIFICATEPOLICYVALIDATION); + } + + PKIX_DECREF(state->anyPolicyNodeAtBottom); + PKIX_DECREF(state->newAnyPolicyNode); + } + + + if (subroutineErr) { + +subrErrorCleanup: + /* We had an error. Was it a fatal error? */ + pkixErrorClass = subroutineErr->errClass; + if (pkixErrorClass == PKIX_FATAL_ERROR) { + pkixErrorResult = subroutineErr; + subroutineErr = NULL; + goto cleanup; + } + /* + * Abort policy processing, and then determine whether + * we can continue without policy processing. + */ + PKIX_DECREF(state->validPolicyTree); + PKIX_DECREF(state->anyPolicyNodeAtBottom); + PKIX_DECREF(state->newAnyPolicyNode); + if (state->explicitPolicy == 0) { + PKIX_ERROR + (PKIX_CERTCHAINFAILSCERTIFICATEPOLICYVALIDATION); + } + } + + /* Checking is complete. Save state for the next certificate. */ + PKIX_CHECK(PKIX_CertChainChecker_SetCertChainCheckerState + (checker, (PKIX_PL_Object *)state, plContext), + PKIX_CERTCHAINCHECKERSETCERTCHAINCHECKERSTATEFAILED); + +cleanup: + +#if PKIX_CERTPOLICYCHECKERSTATEDEBUG + if (cert) { + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object*)cert, &certString, plContext), + PKIX_OBJECTTOSTRINGFAILED); + PKIX_CHECK(PKIX_PL_String_GetEncoded + (certString, + PKIX_ESCASCII, + (void **)&certAscii, + &length, + plContext), + PKIX_STRINGGETENCODEDFAILED); + PKIX_DEBUG_ARG("Cert was %s\n", certAscii); + PKIX_FREE(certAscii); + PKIX_DECREF(certString); + } + if (state) { + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object*)state, &stateString, plContext), + PKIX_OBJECTTOSTRINGFAILED); + PKIX_CHECK(PKIX_PL_String_GetEncoded + (stateString, + PKIX_ESCASCII, + (void **)&stateAscii, + &length, + plContext), + PKIX_STRINGGETENCODEDFAILED); + PKIX_DEBUG_ARG("On exit %s\n", stateAscii); + PKIX_FREE(stateAscii); + PKIX_DECREF(stateString); + } +#endif + + PKIX_DECREF(state); + PKIX_DECREF(certPolicyInfos); + PKIX_DECREF(policy); + PKIX_DECREF(qualsOfAny); + PKIX_DECREF(policyQualifiers); + PKIX_DECREF(policyOID); + PKIX_DECREF(subroutineErr); + PKIX_DECREF(policyMaps); + PKIX_DECREF(mappedPolicies); + + PKIX_RETURN(CERTCHAINCHECKER); +} + +/* + * FUNCTION: pkix_PolicyChecker_Initialize + * DESCRIPTION: + * + * Creates and initializes a PolicyChecker, using the List pointed to + * by "initialPolicies" for the user-initial-policy-set, the Boolean value + * of "policyQualifiersRejected" for the policyQualifiersRejected parameter, + * the Boolean value of "initialPolicyMappingInhibit" for the + * inhibitPolicyMappings parameter, the Boolean value of + * "initialExplicitPolicy" for the initialExplicitPolicy parameter, the + * Boolean value of "initialAnyPolicyInhibit" for the inhibitAnyPolicy + * parameter, and the UInt32 value of "numCerts" as the number of + * certificates in the chain; and stores the Checker at "pChecker". + * + * PARAMETERS: + * "initialPolicies" + * Address of List of OIDs comprising the user-initial-policy-set; the List + * may be empty or NULL + * "policyQualifiersRejected" + * Boolean value of the policyQualifiersRejected parameter + * "initialPolicyMappingInhibit" + * Boolean value of the inhibitPolicyMappings parameter + * "initialExplicitPolicy" + * Boolean value of the initialExplicitPolicy parameter + * "initialAnyPolicyInhibit" + * Boolean value of the inhibitAnyPolicy parameter + * "numCerts" + * Number of certificates in the chain to be validated + * "pChecker" + * Address to store the created PolicyChecker. Must be non-NULL. + * "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 CertChainChecker Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_PolicyChecker_Initialize( + PKIX_List *initialPolicies, + PKIX_Boolean policyQualifiersRejected, + PKIX_Boolean initialPolicyMappingInhibit, + PKIX_Boolean initialExplicitPolicy, + PKIX_Boolean initialAnyPolicyInhibit, + PKIX_UInt32 numCerts, + PKIX_CertChainChecker **pChecker, + void *plContext) +{ + PKIX_PolicyCheckerState *polCheckerState = NULL; + PKIX_List *policyExtensions = NULL; /* OIDs */ + PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_Initialize"); + PKIX_NULLCHECK_ONE(pChecker); + + PKIX_CHECK(pkix_PolicyCheckerState_Create + (initialPolicies, + policyQualifiersRejected, + initialPolicyMappingInhibit, + initialExplicitPolicy, + initialAnyPolicyInhibit, + numCerts, + &polCheckerState, + plContext), + PKIX_POLICYCHECKERSTATECREATEFAILED); + + /* Create the list of extensions that we handle */ + PKIX_CHECK(pkix_PolicyChecker_MakeSingleton + ((PKIX_PL_Object *)(polCheckerState->certPoliciesExtension), + PKIX_TRUE, + &policyExtensions, + plContext), + PKIX_POLICYCHECKERMAKESINGLETONFAILED); + + PKIX_CHECK(PKIX_CertChainChecker_Create + (pkix_PolicyChecker_Check, + PKIX_FALSE, /* forwardCheckingSupported */ + PKIX_FALSE, + policyExtensions, + (PKIX_PL_Object *)polCheckerState, + pChecker, + plContext), + PKIX_CERTCHAINCHECKERCREATEFAILED); + +cleanup: + PKIX_DECREF(polCheckerState); + PKIX_DECREF(policyExtensions); + PKIX_RETURN(CERTCHAINCHECKER); + +} diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_policychecker.h b/security/nss/lib/libpkix/pkix/checker/pkix_policychecker.h new file mode 100644 index 0000000000..8b87ac1224 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_policychecker.h @@ -0,0 +1,73 @@ +/* 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/. */ +/* + * pkix_policychecker.h + * + * Header file for policy checker. + * + */ + +#ifndef _PKIX_POLICYCHECKER_H +#define _PKIX_POLICYCHECKER_H + +#include "pkix_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PKIX_PolicyCheckerStateStruct PKIX_PolicyCheckerState; + +struct PKIX_PolicyCheckerStateStruct{ + PKIX_PL_OID *certPoliciesExtension; /* const */ + PKIX_PL_OID *policyMappingsExtension; /* const */ + PKIX_PL_OID *policyConstraintsExtension; /* const */ + PKIX_PL_OID *inhibitAnyPolicyExtension; /* const */ + PKIX_PL_OID *anyPolicyOID; /* const */ + PKIX_Boolean initialIsAnyPolicy; /* const */ + PKIX_PolicyNode *validPolicyTree; + PKIX_List *userInitialPolicySet; /* immutable */ + PKIX_List *mappedUserInitialPolicySet; + PKIX_Boolean policyQualifiersRejected; + PKIX_Boolean initialPolicyMappingInhibit; + PKIX_Boolean initialExplicitPolicy; + PKIX_Boolean initialAnyPolicyInhibit; + PKIX_UInt32 explicitPolicy; + PKIX_UInt32 inhibitAnyPolicy; + PKIX_UInt32 policyMapping; + PKIX_UInt32 numCerts; + PKIX_UInt32 certsProcessed; + PKIX_PolicyNode *anyPolicyNodeAtBottom; + PKIX_PolicyNode *newAnyPolicyNode; + /* + * The following variables do not survive from one + * certificate to the next. They are needed at each + * level of recursive routines, any by placing them + * in the state object we can pass fewer arguments. + */ + PKIX_Boolean certPoliciesCritical; + PKIX_List *mappedPolicyOIDs; +}; + +PKIX_Error * +pkix_PolicyChecker_Initialize( + PKIX_List *initialPolicies, + PKIX_Boolean policyQualifiersRejected, + PKIX_Boolean initialPolicyMappingInhibit, + PKIX_Boolean initialExplicitPolicy, + PKIX_Boolean initialAnyPolicyInhibit, + PKIX_UInt32 numCerts, + PKIX_CertChainChecker **pChecker, + void *plContext); + +/* --Private-Functions-------------------------------------------- */ + +PKIX_Error * +pkix_PolicyCheckerState_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_POLICYCHECKER_H */ diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_revocationchecker.c b/security/nss/lib/libpkix/pkix/checker/pkix_revocationchecker.c new file mode 100644 index 0000000000..7bed9b8860 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_revocationchecker.c @@ -0,0 +1,475 @@ +/* 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/. */ +/* + * pkix_revocationchecker.c + * + * RevocationChecker Object Functions + * + */ + +#include "pkix_revocationchecker.h" +#include "pkix_tools.h" + +/* --Private-Functions-------------------------------------------- */ + +/* + * FUNCTION: pkix_RevocationChecker_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_RevocationChecker_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_RevocationChecker *checker = NULL; + + PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_Destroy"); + PKIX_NULLCHECK_ONE(object); + + /* Check that this object is a revocation checker */ + PKIX_CHECK(pkix_CheckType + (object, PKIX_REVOCATIONCHECKER_TYPE, plContext), + PKIX_OBJECTNOTREVOCATIONCHECKER); + + checker = (PKIX_RevocationChecker *)object; + + PKIX_DECREF(checker->leafMethodList); + PKIX_DECREF(checker->chainMethodList); + +cleanup: + + PKIX_RETURN(REVOCATIONCHECKER); +} + +/* + * FUNCTION: pkix_RevocationChecker_Duplicate + * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_RevocationChecker_Duplicate( + PKIX_PL_Object *object, + PKIX_PL_Object **pNewObject, + void *plContext) +{ + PKIX_RevocationChecker *checker = NULL; + PKIX_RevocationChecker *checkerDuplicate = NULL; + PKIX_List *dupLeafList = NULL; + PKIX_List *dupChainList = NULL; + + PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_Duplicate"); + PKIX_NULLCHECK_TWO(object, pNewObject); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_REVOCATIONCHECKER_TYPE, plContext), + PKIX_OBJECTNOTCERTCHAINCHECKER); + + checker = (PKIX_RevocationChecker *)object; + + if (checker->leafMethodList){ + PKIX_CHECK(PKIX_PL_Object_Duplicate + ((PKIX_PL_Object *)checker->leafMethodList, + (PKIX_PL_Object **)&dupLeafList, + plContext), + PKIX_OBJECTDUPLICATEFAILED); + } + if (checker->chainMethodList){ + PKIX_CHECK(PKIX_PL_Object_Duplicate + ((PKIX_PL_Object *)checker->chainMethodList, + (PKIX_PL_Object **)&dupChainList, + plContext), + PKIX_OBJECTDUPLICATEFAILED); + } + + PKIX_CHECK( + PKIX_RevocationChecker_Create(checker->leafMethodListFlags, + checker->chainMethodListFlags, + &checkerDuplicate, + plContext), + PKIX_REVOCATIONCHECKERCREATEFAILED); + + checkerDuplicate->leafMethodList = dupLeafList; + checkerDuplicate->chainMethodList = dupChainList; + dupLeafList = NULL; + dupChainList = NULL; + + *pNewObject = (PKIX_PL_Object *)checkerDuplicate; + +cleanup: + PKIX_DECREF(dupLeafList); + PKIX_DECREF(dupChainList); + + PKIX_RETURN(REVOCATIONCHECKER); +} + +/* + * FUNCTION: pkix_RevocationChecker_RegisterSelf + * DESCRIPTION: + * Registers PKIX_REVOCATIONCHECKER_TYPE and its related functions with + * systemClasses[] + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_RevocationChecker_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(REVOCATIONCHECKER, "pkix_RevocationChecker_RegisterSelf"); + + entry.description = "RevocationChecker"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_RevocationChecker); + entry.destructor = pkix_RevocationChecker_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = pkix_RevocationChecker_Duplicate; + + systemClasses[PKIX_REVOCATIONCHECKER_TYPE] = entry; + + PKIX_RETURN(REVOCATIONCHECKER); +} + +/* Sort methods by their priorities (lower priority = higher preference) */ +static PKIX_Error * +pkix_RevocationChecker_SortComparator( + PKIX_PL_Object *obj1, + PKIX_PL_Object *obj2, + PKIX_Int32 *pResult, + void *plContext) +{ + pkix_RevocationMethod *method1 = NULL, *method2 = NULL; + + PKIX_ENTER(BUILD, "pkix_RevocationChecker_SortComparator"); + + method1 = (pkix_RevocationMethod *)obj1; + method2 = (pkix_RevocationMethod *)obj2; + + if (method1->priority < method2->priority) { + *pResult = -1; + } else if (method1->priority > method2->priority) { + *pResult = 1; + } else { + *pResult = 0; + } + + PKIX_RETURN(BUILD); +} + + +/* --Public-Functions--------------------------------------------- */ + + +/* + * FUNCTION: PKIX_RevocationChecker_Create (see comments in pkix_revchecker.h) + */ +PKIX_Error * +PKIX_RevocationChecker_Create( + PKIX_UInt32 leafMethodListFlags, + PKIX_UInt32 chainMethodListFlags, + PKIX_RevocationChecker **pChecker, + void *plContext) +{ + PKIX_RevocationChecker *checker = NULL; + + PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Create"); + PKIX_NULLCHECK_ONE(pChecker); + + PKIX_CHECK( + PKIX_PL_Object_Alloc(PKIX_REVOCATIONCHECKER_TYPE, + sizeof (PKIX_RevocationChecker), + (PKIX_PL_Object **)&checker, + plContext), + PKIX_COULDNOTCREATECERTCHAINCHECKEROBJECT); + + checker->leafMethodListFlags = leafMethodListFlags; + checker->chainMethodListFlags = chainMethodListFlags; + checker->leafMethodList = NULL; + checker->chainMethodList = NULL; + + *pChecker = checker; + checker = NULL; + +cleanup: + PKIX_DECREF(checker); + + PKIX_RETURN(REVOCATIONCHECKER); +} + +/* + * FUNCTION: PKIX_RevocationChecker_CreateAndAddMethod + */ +PKIX_Error * +PKIX_RevocationChecker_CreateAndAddMethod( + PKIX_RevocationChecker *revChecker, + PKIX_ProcessingParams *params, + PKIX_RevocationMethodType methodType, + PKIX_UInt32 flags, + PKIX_UInt32 priority, + PKIX_PL_VerifyCallback verificationFn, + PKIX_Boolean isLeafMethod, + void *plContext) +{ + PKIX_List **methodList = NULL; + PKIX_List *unsortedList = NULL; + PKIX_List *certStores = NULL; + pkix_RevocationMethod *method = NULL; + pkix_LocalRevocationCheckFn *localRevChecker = NULL; + pkix_ExternalRevocationCheckFn *externRevChecker = NULL; + PKIX_UInt32 miFlags; + + PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_CreateAndAddMethod"); + PKIX_NULLCHECK_ONE(revChecker); + + /* If the caller has said "Either one is sufficient, then don't let the + * absence of any one method's info lead to an overall failure. + */ + miFlags = isLeafMethod ? revChecker->leafMethodListFlags + : revChecker->chainMethodListFlags; + if (miFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE) + flags &= ~PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO; + + switch (methodType) { + case PKIX_RevocationMethod_CRL: + localRevChecker = pkix_CrlChecker_CheckLocal; + externRevChecker = pkix_CrlChecker_CheckExternal; + PKIX_CHECK( + PKIX_ProcessingParams_GetCertStores(params, &certStores, + plContext), + PKIX_PROCESSINGPARAMSGETCERTSTORESFAILED); + PKIX_CHECK( + pkix_CrlChecker_Create(methodType, flags, priority, + localRevChecker, externRevChecker, + certStores, verificationFn, + &method, + plContext), + PKIX_COULDNOTCREATECRLCHECKEROBJECT); + break; + case PKIX_RevocationMethod_OCSP: + localRevChecker = pkix_OcspChecker_CheckLocal; + externRevChecker = pkix_OcspChecker_CheckExternal; + PKIX_CHECK( + pkix_OcspChecker_Create(methodType, flags, priority, + localRevChecker, externRevChecker, + verificationFn, + &method, + plContext), + PKIX_COULDNOTCREATEOCSPCHECKEROBJECT); + break; + default: + PKIX_ERROR(PKIX_INVALIDREVOCATIONMETHOD); + } + + if (isLeafMethod) { + methodList = &revChecker->leafMethodList; + } else { + methodList = &revChecker->chainMethodList; + } + + if (*methodList == NULL) { + PKIX_CHECK( + PKIX_List_Create(methodList, plContext), + PKIX_LISTCREATEFAILED); + } + unsortedList = *methodList; + PKIX_CHECK( + PKIX_List_AppendItem(unsortedList, (PKIX_PL_Object*)method, plContext), + PKIX_LISTAPPENDITEMFAILED); + PKIX_CHECK( + pkix_List_BubbleSort(unsortedList, + pkix_RevocationChecker_SortComparator, + methodList, plContext), + PKIX_LISTBUBBLESORTFAILED); + +cleanup: + PKIX_DECREF(method); + PKIX_DECREF(unsortedList); + PKIX_DECREF(certStores); + + PKIX_RETURN(REVOCATIONCHECKER); +} + +/* + * FUNCTION: PKIX_RevocationChecker_Check + */ +PKIX_Error * +PKIX_RevocationChecker_Check( + PKIX_PL_Cert *cert, + PKIX_PL_Cert *issuer, + PKIX_RevocationChecker *revChecker, + PKIX_ProcessingParams *procParams, + PKIX_Boolean chainVerificationState, + PKIX_Boolean testingLeafCert, + PKIX_RevocationStatus *pRevStatus, + PKIX_UInt32 *pReasonCode, + void **pNbioContext, + void *plContext) +{ + PKIX_RevocationStatus overallStatus = PKIX_RevStatus_NoInfo; + PKIX_RevocationStatus methodStatus[PKIX_RevocationMethod_MAX]; + PKIX_Boolean onlyUseRemoteMethods = PKIX_FALSE; + PKIX_UInt32 revFlags = 0; + PKIX_List *revList = NULL; + PKIX_PL_Date *date = NULL; + pkix_RevocationMethod *method = NULL; + void *nbioContext; + int tries; + + PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Check"); + PKIX_NULLCHECK_TWO(revChecker, procParams); + + nbioContext = *pNbioContext; + *pNbioContext = NULL; + + if (testingLeafCert) { + revList = revChecker->leafMethodList; + revFlags = revChecker->leafMethodListFlags; + } else { + revList = revChecker->chainMethodList; + revFlags = revChecker->chainMethodListFlags; + } + if (!revList) { + /* Return NoInfo status */ + goto cleanup; + } + + PORT_Memset(methodStatus, PKIX_RevStatus_NoInfo, + sizeof(PKIX_RevocationStatus) * PKIX_RevocationMethod_MAX); + + date = procParams->date; + + /* Need to have two loops if we testing all local info first: + * first we are going to test all local(cached) info + * second, all remote info(fetching) */ + for (tries = 0;tries < 2;tries++) { + unsigned int methodNum = 0; + for (;methodNum < revList->length;methodNum++) { + PKIX_UInt32 methodFlags = 0; + + PKIX_DECREF(method); + PKIX_CHECK( + PKIX_List_GetItem(revList, methodNum, + (PKIX_PL_Object**)&method, plContext), + PKIX_LISTGETITEMFAILED); + methodFlags = method->flags; + if (!(methodFlags & PKIX_REV_M_TEST_USING_THIS_METHOD)) { + /* Will not check with this method. Skipping... */ + continue; + } + if (!onlyUseRemoteMethods && + methodStatus[methodNum] == PKIX_RevStatus_NoInfo) { + PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; + PKIX_CHECK_NO_GOTO( + (*method->localRevChecker)(cert, issuer, date, + method, procParams, + methodFlags, + chainVerificationState, + &revStatus, + (CERTCRLEntryReasonCode *)pReasonCode, + plContext), + PKIX_REVCHECKERCHECKFAILED); + methodStatus[methodNum] = revStatus; + if (revStatus == PKIX_RevStatus_Revoked) { + /* if error was generated use it as final error. */ + overallStatus = PKIX_RevStatus_Revoked; + goto cleanup; + } + if (pkixErrorResult) { + /* Disregard errors. Only returned revStatus matters. */ + PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult, + plContext); + pkixErrorResult = NULL; + } + } + if ((!(revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST) || + onlyUseRemoteMethods) && + chainVerificationState && + methodStatus[methodNum] == PKIX_RevStatus_NoInfo) { + if (!(methodFlags & PKIX_REV_M_FORBID_NETWORK_FETCHING)) { + PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; + PKIX_CHECK_NO_GOTO( + (*method->externalRevChecker)(cert, issuer, date, + method, + procParams, methodFlags, + &revStatus, + (CERTCRLEntryReasonCode *)pReasonCode, + &nbioContext, plContext), + PKIX_REVCHECKERCHECKFAILED); + methodStatus[methodNum] = revStatus; + if (revStatus == PKIX_RevStatus_Revoked) { + /* if error was generated use it as final error. */ + overallStatus = PKIX_RevStatus_Revoked; + goto cleanup; + } + if (pkixErrorResult) { + /* Disregard errors. Only returned revStatus matters. */ + PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult, + plContext); + pkixErrorResult = NULL; + } + } else if (methodFlags & + PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) { + /* Info is not in the local cache. Network fetching is not + * allowed. If need to fail on missing fresh info for the + * the method, then we should fail right here.*/ + overallStatus = PKIX_RevStatus_Revoked; + goto cleanup; + } + } + /* If success and we should not check the next method, then + * return a success. */ + if (methodStatus[methodNum] == PKIX_RevStatus_Success && + !(methodFlags & PKIX_REV_M_CONTINUE_TESTING_ON_FRESH_INFO)) { + overallStatus = PKIX_RevStatus_Success; + goto cleanup; + } + } /* inner loop */ + if (!onlyUseRemoteMethods && + revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST && + chainVerificationState) { + onlyUseRemoteMethods = PKIX_TRUE; + continue; + } + break; + } /* outer loop */ + + if (overallStatus == PKIX_RevStatus_NoInfo && + chainVerificationState) { + /* The following check makes sence only for chain + * validation step, sinse we do not fetch info while + * in the process of finding trusted anchor. + * For chain building step it is enough to know, that + * the cert was not directly revoked by any of the + * methods. */ + + /* Still have no info. But one of the method could + * have returned success status(possible if CONTINUE + * TESTING ON FRESH INFO flag was used). + * If any of the methods have returned Success status, + * the overallStatus should be success. */ + int methodNum = 0; + for (;methodNum < PKIX_RevocationMethod_MAX;methodNum++) { + if (methodStatus[methodNum] == PKIX_RevStatus_Success) { + overallStatus = PKIX_RevStatus_Success; + goto cleanup; + } + } + if (revFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE) { + overallStatus = PKIX_RevStatus_Revoked; + } + } + +cleanup: + *pRevStatus = overallStatus; + PKIX_DECREF(method); + + PKIX_RETURN(REVOCATIONCHECKER); +} + diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_revocationchecker.h b/security/nss/lib/libpkix/pkix/checker/pkix_revocationchecker.h new file mode 100644 index 0000000000..20dfe37787 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_revocationchecker.h @@ -0,0 +1,151 @@ +/* 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/. */ +/* + * pkix_revocationchecker.h + * + * RevocationChecker Object Type Definition + * + */ + +#ifndef _PKIX_REVOCATIONCHECKER_H +#define _PKIX_REVOCATIONCHECKER_H + +#include "pkixt.h" +#include "certt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: nbio logistic removed. Will be replaced later. */ + +/* + * All Flags are prefixed by CERT_REV_M_, where _M_ indicates + * this is a method dependent flag. + */ + +/* + * Whether or not to use a method for revocation testing. + * If set to "do not test", then all other flags are ignored. + */ +#define PKIX_REV_M_DO_NOT_TEST_USING_THIS_METHOD 0x00L +#define PKIX_REV_M_TEST_USING_THIS_METHOD 0x01L + +/* + * Whether or not NSS is allowed to attempt to fetch fresh information + * from the network. + * (Although fetching will never happen if fresh information for the + * method is already locally available.) + */ +#define PKIX_REV_M_ALLOW_NETWORK_FETCHING 0x00L +#define PKIX_REV_M_FORBID_NETWORK_FETCHING 0x02L + +/* + * Example for an implicit default source: + * The globally configured default OCSP responder. + * IGNORE means: + * ignore the implicit default source, whether it's configured or not. + * ALLOW means: + * if an implicit default source is configured, + * then it overrides any available or missing source in the cert. + * if no implicit default source is configured, + * then we continue to use what's available (or not available) + * in the certs. + */ +#define PKIX_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE 0x00L +#define PKIX_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE 0x04L /* OCSP only */ + +/* + * Defines the behavior if no fresh information is available, + * fetching from the network is allowed, but the source of revocation + * information is unknown (even after considering implicit sources, + * if allowed by other flags). + * SKIPT_TEST means: + * We ignore that no fresh information is available and + * skip this test. + * REQUIRE_INFO means: + * We still require that fresh information is available. + * Other flags define what happens on missing fresh info. + */ + +#define PKIX_REV_M_SKIP_TEST_ON_MISSING_SOURCE 0x00L +#define PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE 0x08L + +/* + * Defines the behavior if we are unable to obtain fresh information. + * INGORE means: + * Return "cert status unknown" + * FAIL means: + * Return "cert revoked". + */ + +#define PKIX_REV_M_IGNORE_MISSING_FRESH_INFO 0x00L +#define PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO 0x10L + +/* + * What should happen if we were able to find fresh information using + * this method, and the data indicated the cert is good? + * STOP_TESTING means: + * Our success is sufficient, do not continue testing + * other methods. + * CONTINUE_TESTING means: + * We will continue and test the next allowed + * specified method. + */ + +#define PKIX_REV_M_STOP_TESTING_ON_FRESH_INFO 0x00L +#define PKIX_REV_M_CONTINUE_TESTING_ON_FRESH_INFO 0x20L + +/* + * All Flags are prefixed by PKIX_REV_MI_, where _MI_ indicates + * this is a method independent flag. + */ + +/* + * This defines the order to checking. + * EACH_METHOD_SEPARATELY means: + * Do all tests related to a particular allowed method + * (both local information and network fetching) in a single step. + * Only after testing for a particular method is done, + * then switching to the next method will happen. + * ALL_LOCAL_INFORMATION_FIRST means: + * Start by testing the information for all allowed methods + * which are already locally available. Only after that is done + * consider to fetch from the network (as allowed by other flags). + */ +#define PKIX_REV_MI_TEST_EACH_METHOD_SEPARATELY 0x00L +#define PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST 0x01L + +/* + * Use this flag to specify that it's necessary that fresh information + * is available for at least one of the allowed methods, but it's + * irrelevant which of the mechanisms succeeded. + * NO_OVERALL_INFO_REQUIREMENT means: + * We strictly follow the requirements for each individual method. + * REQUIRE_SOME_FRESH_INFO_AVAILABLE means: + * After the individual tests have been executed, we must have + * been able to find fresh information using at least one method. + * If we were unable to find fresh info, it's a failure. + */ +#define PKIX_REV_MI_NO_OVERALL_INFO_REQUIREMENT 0x00L +#define PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE 0x02L + +/* Defines check time for the cert, revocation methods lists and + * flags for leaf and chain certs revocation tests. */ +struct PKIX_RevocationCheckerStruct { + PKIX_List *leafMethodList; + PKIX_List *chainMethodList; + PKIX_UInt32 leafMethodListFlags; + PKIX_UInt32 chainMethodListFlags; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_RevocationChecker_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_REVOCATIONCHECKER_H */ diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_revocationmethod.c b/security/nss/lib/libpkix/pkix/checker/pkix_revocationmethod.c new file mode 100644 index 0000000000..ee18ddef95 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_revocationmethod.c @@ -0,0 +1,66 @@ +/* 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/. */ +/* + * pkix_revocationmethod.c + * + * RevocationMethod Object Functions + * + */ + +#include "pkix_revocationmethod.h" +#include "pkix_tools.h" + +/* Constructor of revocation method object. Does not create an object, + * but just initializez PKIX_RevocationMethodStruct fields. Object + * suppose to be already created. */ +PKIX_Error * +pkix_RevocationMethod_Init( + pkix_RevocationMethod *method, + PKIX_RevocationMethodType methodType, + PKIX_UInt32 flags, + PKIX_UInt32 priority, + pkix_LocalRevocationCheckFn localRevChecker, + pkix_ExternalRevocationCheckFn externalRevChecker, + void *plContext) +{ + PKIX_ENTER(REVOCATIONMETHOD, "PKIX_RevocationMethod_Init"); + + method->methodType = methodType; + method->flags = flags; + method->priority = priority; + method->localRevChecker = localRevChecker; + method->externalRevChecker = externalRevChecker; + + PKIX_RETURN(REVOCATIONMETHOD); +} + +/* Data duplication data. Not create an object. Only initializes fields + * in the new object by data from "object". */ +PKIX_Error * +pkix_RevocationMethod_Duplicate( + PKIX_PL_Object *object, + PKIX_PL_Object *newObject, + void *plContext) +{ + pkix_RevocationMethod *method = NULL; + + PKIX_ENTER(REVOCATIONMETHOD, "pkix_RevocationMethod_Duplicate"); + PKIX_NULLCHECK_TWO(object, newObject); + + method = (pkix_RevocationMethod *)object; + + PKIX_CHECK( + pkix_RevocationMethod_Init((pkix_RevocationMethod*)newObject, + method->methodType, + method->flags, + method->priority, + method->localRevChecker, + method->externalRevChecker, + plContext), + PKIX_COULDNOTCREATEREVOCATIONMETHODOBJECT); + +cleanup: + + PKIX_RETURN(REVOCATIONMETHOD); +} diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_revocationmethod.h b/security/nss/lib/libpkix/pkix/checker/pkix_revocationmethod.h new file mode 100644 index 0000000000..a97c7620ae --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_revocationmethod.h @@ -0,0 +1,81 @@ +/* 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/. */ +/* + * pkix_revocationmethod.h + * + * RevocationMethod Object + * + */ + +#ifndef _PKIX_REVOCATIONMETHOD_H +#define _PKIX_REVOCATIONMETHOD_H + +#include "pkixt.h" +#include "pkix_revocationchecker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pkix_RevocationMethodStruct pkix_RevocationMethod; + +/* Local revocation check function prototype definition. + * Revocation methods capable of checking revocation though local + * means(cache) should implement this prototype. */ +typedef PKIX_Error * +pkix_LocalRevocationCheckFn(PKIX_PL_Cert *cert, PKIX_PL_Cert *issuer, + PKIX_PL_Date *date, + pkix_RevocationMethod *checkerObject, + PKIX_ProcessingParams *procParams, + PKIX_UInt32 methodFlags, + PKIX_Boolean chainVerificationState, + PKIX_RevocationStatus *pRevStatus, + CERTCRLEntryReasonCode *reasonCode, + void *plContext); + +/* External revocation check function prototype definition. + * Revocation methods that required external communications(crldp + * ocsp) shoult implement this prototype. */ +typedef PKIX_Error * +pkix_ExternalRevocationCheckFn(PKIX_PL_Cert *cert, PKIX_PL_Cert *issuer, + PKIX_PL_Date *date, + pkix_RevocationMethod *checkerObject, + PKIX_ProcessingParams *procParams, + PKIX_UInt32 methodFlags, + PKIX_RevocationStatus *pRevStatus, + CERTCRLEntryReasonCode *reasonCode, + void **pNBIOContext, void *plContext); + +/* Revocation method structure assosiates revocation types with + * a set of flags on the method, a priority of the method (0 + * corresponds to the highest priority), and method local/external + * checker functions. */ +struct pkix_RevocationMethodStruct { + PKIX_RevocationMethodType methodType; + PKIX_UInt32 flags; + PKIX_UInt32 priority; + pkix_LocalRevocationCheckFn (*localRevChecker); + pkix_ExternalRevocationCheckFn (*externalRevChecker); +}; + +PKIX_Error * +pkix_RevocationMethod_Duplicate(PKIX_PL_Object *object, + PKIX_PL_Object *newObject, + void *plContext); + +PKIX_Error * +pkix_RevocationMethod_Init(pkix_RevocationMethod *method, + PKIX_RevocationMethodType methodType, + PKIX_UInt32 flags, + PKIX_UInt32 priority, + pkix_LocalRevocationCheckFn localRevChecker, + pkix_ExternalRevocationCheckFn externalRevChecker, + void *plContext); + + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_REVOCATIONMETHOD_H */ diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_signaturechecker.c b/security/nss/lib/libpkix/pkix/checker/pkix_signaturechecker.c new file mode 100644 index 0000000000..0ed9ffaecc --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_signaturechecker.c @@ -0,0 +1,443 @@ +/* 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/. */ +/* + * pkix_signaturechecker.c + * + * Functions for signature validation + * + */ + +#include "pkix_signaturechecker.h" + +/* + * FUNCTION: pkix_SignatureCheckerstate_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_SignatureCheckerState_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + pkix_SignatureCheckerState *state = NULL; + + PKIX_ENTER(SIGNATURECHECKERSTATE, + "pkix_SignatureCheckerState_Destroy"); + PKIX_NULLCHECK_ONE(object); + + /* Check that this object is a signature checker state */ + PKIX_CHECK(pkix_CheckType + (object, PKIX_SIGNATURECHECKERSTATE_TYPE, plContext), + PKIX_OBJECTNOTSIGNATURECHECKERSTATE); + + state = (pkix_SignatureCheckerState *) object; + + state->prevCertCertSign = PKIX_FALSE; + + PKIX_DECREF(state->prevPublicKey); + PKIX_DECREF(state->prevPublicKeyList); + PKIX_DECREF(state->keyUsageOID); + +cleanup: + + PKIX_RETURN(SIGNATURECHECKERSTATE); +} + +/* + * FUNCTION: pkix_SignatureCheckerState_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_SIGNATURECHECKERSTATE_TYPE and its related functions + * with systemClasses[] + * + * THREAD SAFETY: + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_SignatureCheckerState_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(SIGNATURECHECKERSTATE, + "pkix_SignatureCheckerState_RegisterSelf"); + + entry.description = "SignatureCheckerState"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(pkix_SignatureCheckerState); + entry.destructor = pkix_SignatureCheckerState_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_SIGNATURECHECKERSTATE_TYPE] = entry; + + PKIX_RETURN(SIGNATURECHECKERSTATE); +} + +/* + * FUNCTION: pkix_SignatureCheckerState_Create + * + * DESCRIPTION: + * Allocate and initialize SignatureChecker state data. + * + * PARAMETERS + * "trustedPubKey" + * Address of trusted Anchor Public Key for verifying first Cert in the + * chain. Must be non-NULL. + * "certsRemaining" + * Number of certificates remaining in the chain. + * "pCheckerState" + * Address where SignatureCheckerState will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * + * THREAD SAFETY: + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a SignatureCheckerState Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_SignatureCheckerState_Create( + PKIX_PL_PublicKey *trustedPubKey, + PKIX_UInt32 certsRemaining, + pkix_SignatureCheckerState **pCheckerState, + void *plContext) +{ + pkix_SignatureCheckerState *state = NULL; + PKIX_PL_OID *keyUsageOID = NULL; + + PKIX_ENTER(SIGNATURECHECKERSTATE, "pkix_SignatureCheckerState_Create"); + PKIX_NULLCHECK_TWO(trustedPubKey, pCheckerState); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_SIGNATURECHECKERSTATE_TYPE, + sizeof (pkix_SignatureCheckerState), + (PKIX_PL_Object **)&state, + plContext), + PKIX_COULDNOTCREATESIGNATURECHECKERSTATEOBJECT); + + /* Initialize fields */ + + state->prevCertCertSign = PKIX_TRUE; + state->prevPublicKeyList = NULL; + state->certsRemaining = certsRemaining; + + PKIX_INCREF(trustedPubKey); + state->prevPublicKey = trustedPubKey; + + PKIX_CHECK(PKIX_PL_OID_Create + (PKIX_CERTKEYUSAGE_OID, + &keyUsageOID, + plContext), + PKIX_OIDCREATEFAILED); + + state->keyUsageOID = keyUsageOID; + keyUsageOID = NULL; + + *pCheckerState = state; + state = NULL; + +cleanup: + + PKIX_DECREF(keyUsageOID); + PKIX_DECREF(state); + + PKIX_RETURN(SIGNATURECHECKERSTATE); +} + +/* --Private-Functions-------------------------------------------- */ + +/* + * FUNCTION: pkix_SignatureChecker_Check + * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h) + */ +PKIX_Error * +pkix_SignatureChecker_Check( + PKIX_CertChainChecker *checker, + PKIX_PL_Cert *cert, + PKIX_List *unresolvedCriticalExtensions, + void **pNBIOContext, + void *plContext) +{ + pkix_SignatureCheckerState *state = NULL; + PKIX_PL_PublicKey *prevPubKey = NULL; + PKIX_PL_PublicKey *currPubKey = NULL; + PKIX_PL_PublicKey *newPubKey = NULL; + PKIX_PL_PublicKey *pKey = NULL; + PKIX_PL_CertBasicConstraints *basicConstraints = NULL; + PKIX_Error *checkKeyUsageFail = NULL; + PKIX_Error *verifyFail = NULL; + PKIX_Boolean certVerified = PKIX_FALSE; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_SignatureChecker_Check"); + PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext); + + *pNBIOContext = NULL; /* we never block on pending I/O */ + + PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState + (checker, (PKIX_PL_Object **)&state, plContext), + PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); + + (state->certsRemaining)--; + + PKIX_INCREF(state->prevPublicKey); + prevPubKey = state->prevPublicKey; + + /* + * Previous Cert doesn't have CertSign bit on for signature + * verification and it is not a self-issued Cert so there is no + * old key saved. This is considered error. + */ + if (state->prevCertCertSign == PKIX_FALSE && + state->prevPublicKeyList == NULL) { + PKIX_ERROR(PKIX_KEYUSAGEKEYCERTSIGNBITNOTON); + } + + /* Previous Cert is valid for signature verification, try it first */ + if (state->prevCertCertSign == PKIX_TRUE) { + verifyFail = PKIX_PL_Cert_VerifySignature + (cert, prevPubKey, plContext); + if (verifyFail == NULL) { + certVerified = PKIX_TRUE; + } else { + certVerified = PKIX_FALSE; + } + } + +#ifdef NIST_TEST_4_5_4_AND_4_5_6 + + /* + * Following codes under this compiler flag is implemented for + * special cases of NIST tests 4.5.4 and 4.5.6. We are not sure + * we should handle these two tests as what is implemented so the + * codes are commented out, and the tests fails (for now). + * For Cert chain validation, our assumption is all the Certs on + * the chain are using its previous Cert's public key to decode + * its current key. But for thses two tests, keys are used not + * in this precedent order, we can either + * 1) Use what is implemented here: take in what Cert order NIST + * specified and for continuous self-issued Certs, stacking up + * their keys and tries all of them in FILO order. + * But this method breaks the idea of chain key presdency. + * 2) Use Build Chain facility: we will specify the valid Certs + * order (means key precedency is kept) and count on Build Chain + * to get the Certs that can fill for the needed keys. This may have + * performance impact. + * 3) Fetch Certs from CertStore: we will specifiy the valid Certs + * order and use CertSelector on SubjectName to get a list of + * candidates Certs to fill in for the needed keys. + * Anyhow, the codes are kept around just in case we want to use + * solution one... + */ + + /* If failed and previous key is self-issued, try its old key(s) */ + if (certVerified == PKIX_FALSE && state->prevPublicKeyList != NULL) { + + /* Verify from keys on the list */ + PKIX_CHECK(PKIX_List_GetLength + (state->prevPublicKeyList, &numKeys, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (i = numKeys - 1; i >= 0; i--) { + + PKIX_CHECK(PKIX_List_GetItem + (state->prevPublicKeyList, + i, + (PKIX_PL_Object **) &pKey, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_DECREF(verifyFail); + verifyFail = PKIX_PL_Cert_VerifySignature + (cert, pKey, plContext); + + if (verifyFail == NULL) { + certVerified = PKIX_TRUE; + break; + } else { + certVerified = PKIX_FALSE; + } + + PKIX_DECREF(pKey); + } + } +#endif + + if (certVerified == PKIX_FALSE) { + pkixErrorResult = verifyFail; + verifyFail = NULL; + PKIX_ERROR(PKIX_VALIDATIONFAILEDCERTSIGNATURECHECKING); + } + +#ifdef NIST_TEST_4_5_4_AND_4_5_6 + /* + * Check if Cert is self-issued. If so, the old key(s) is saved, in + * conjunction to the new key, for verifying CERT validity later. + */ + PKIX_CHECK(pkix_IsCertSelfIssued(cert, &selfIssued, plContext), + PKIX_ISCERTSELFISSUEFAILED); + + /* + * Check if Cert is self-issued. If so, the public key of the Cert + * that issues this Cert (old key) can be used together with this + * current key (new key) for key verification. If there are multiple + * self-issued certs, keys of those Certs (old keys) can also be used + * for key verification. Old key(s) is saved in a list (PrevPublickKey- + * List) and cleared when a Cert is no longer self-issued. PrevPublic- + * Key keep key of the previous Cert. + */ + if (selfIssued == PKIX_TRUE) { + + /* Make sure previous Cert is valid for signature verification */ + if (state->prevCertCertSign == PKIX_TRUE) { + + if (state->prevPublicKeyList == NULL) { + + PKIX_CHECK(PKIX_List_Create + (&state->prevPublicKeyList, plContext), + PKIX_LISTCREATEFALIED); + + } + + PKIX_CHECK(PKIX_List_AppendItem + (state->prevPublicKeyList, + (PKIX_PL_Object *) state->prevPublicKey, + plContext), + PKIX_LISTAPPENDITEMFAILED); + } + + } else { + /* Not self-issued Cert any more, clear old key(s) saved */ + PKIX_DECREF(state->prevPublicKeyList); + } +#endif + + /* Save current key as prevPublicKey */ + PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey + (cert, &currPubKey, plContext), + PKIX_CERTGETSUBJECTPUBLICKEYFAILED); + + PKIX_CHECK(PKIX_PL_PublicKey_MakeInheritedDSAPublicKey + (currPubKey, prevPubKey, &newPubKey, plContext), + PKIX_PUBLICKEYMAKEINHERITEDDSAPUBLICKEYFAILED); + + if (newPubKey == NULL){ + PKIX_INCREF(currPubKey); + newPubKey = currPubKey; + } + + PKIX_INCREF(newPubKey); + PKIX_DECREF(state->prevPublicKey); + + state->prevPublicKey = newPubKey; + + /* Save this Cert key usage CertSign bit */ + if (state->certsRemaining != 0) { + checkKeyUsageFail = PKIX_PL_Cert_VerifyKeyUsage + (cert, PKIX_KEY_CERT_SIGN, plContext); + + state->prevCertCertSign = (checkKeyUsageFail == NULL)? + PKIX_TRUE:PKIX_FALSE; + + PKIX_DECREF(checkKeyUsageFail); + } + + /* Remove Key Usage Extension OID from list */ + if (unresolvedCriticalExtensions != NULL) { + + PKIX_CHECK(pkix_List_Remove + (unresolvedCriticalExtensions, + (PKIX_PL_Object *) state->keyUsageOID, + plContext), + PKIX_LISTREMOVEFAILED); + } + + PKIX_CHECK(PKIX_CertChainChecker_SetCertChainCheckerState + (checker, (PKIX_PL_Object *)state, plContext), + PKIX_CERTCHAINCHECKERSETCERTCHAINCHECKERSTATEFAILED); + +cleanup: + + PKIX_DECREF(state); + PKIX_DECREF(pKey); + PKIX_DECREF(prevPubKey); + PKIX_DECREF(currPubKey); + PKIX_DECREF(newPubKey); + PKIX_DECREF(basicConstraints); + PKIX_DECREF(verifyFail); + PKIX_DECREF(checkKeyUsageFail); + + PKIX_RETURN(CERTCHAINCHECKER); + +} + +/* + * FUNCTION: pkix_SignatureChecker_Initialize + * DESCRIPTION: + * + * Creates a new CertChainChecker and stores it at "pChecker", where it will + * be used by pkix_SignatureChecker_Check to check that the public key in + * the checker's state is able to successfully validate the certificate's + * signature. The PublicKey pointed to by "trustedPubKey" is used to + * initialize the checker's state. + * + * PARAMETERS: + * "trustedPubKey" + * Address of PublicKey representing the trusted public key used to + * initialize the state of this checker. Must be non-NULL. + * "certsRemaining" + * Number of certificates remaining in the chain. + * "pChecker" + * Address where object pointer will be stored. Must be non-NULL. + * "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 CertChainChecker Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_SignatureChecker_Initialize( + PKIX_PL_PublicKey *trustedPubKey, + PKIX_UInt32 certsRemaining, + PKIX_CertChainChecker **pChecker, + void *plContext) +{ + pkix_SignatureCheckerState* state = NULL; + PKIX_ENTER(CERTCHAINCHECKER, "PKIX_SignatureChecker_Initialize"); + PKIX_NULLCHECK_TWO(pChecker, trustedPubKey); + + PKIX_CHECK(pkix_SignatureCheckerState_Create + (trustedPubKey, certsRemaining, &state, plContext), + PKIX_SIGNATURECHECKERSTATECREATEFAILED); + + PKIX_CHECK(PKIX_CertChainChecker_Create + (pkix_SignatureChecker_Check, + PKIX_FALSE, + PKIX_FALSE, + NULL, + (PKIX_PL_Object *) state, + pChecker, + plContext), + PKIX_CERTCHAINCHECKERCREATEFAILED); + +cleanup: + + PKIX_DECREF(state); + + PKIX_RETURN(CERTCHAINCHECKER); + +} diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_signaturechecker.h b/security/nss/lib/libpkix/pkix/checker/pkix_signaturechecker.h new file mode 100644 index 0000000000..ccfb578579 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_signaturechecker.h @@ -0,0 +1,44 @@ +/* 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/. */ +/* + * pkix_signaturechecker.h + * + * Header file for validate signature function + * + */ + +#ifndef _PKIX_SIGNATURECHECKER_H +#define _PKIX_SIGNATURECHECKER_H + +#include "pkix_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pkix_SignatureCheckerState pkix_SignatureCheckerState; + +struct pkix_SignatureCheckerState { + PKIX_Boolean prevCertCertSign; + PKIX_UInt32 certsRemaining; + PKIX_PL_PublicKey *prevPublicKey; /* Subject PubKey of last cert */ + PKIX_List *prevPublicKeyList; /* of PKIX_PL_PublicKey */ + PKIX_PL_OID *keyUsageOID; +}; + +PKIX_Error * +pkix_SignatureChecker_Initialize( + PKIX_PL_PublicKey *trustedPubKey, + PKIX_UInt32 certsRemaining, + PKIX_CertChainChecker **pChecker, + void *plContext); + +PKIX_Error * +pkix_SignatureCheckerState_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_SIGNATURECHECKER_H */ diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_targetcertchecker.c b/security/nss/lib/libpkix/pkix/checker/pkix_targetcertchecker.c new file mode 100644 index 0000000000..46fe07112b --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_targetcertchecker.c @@ -0,0 +1,516 @@ +/* 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/. */ +/* + * pkix_targetcertchecker.c + * + * Functions for target cert validation + * + */ + + +#include "pkix_targetcertchecker.h" + +/* --Private-TargetCertCheckerState-Functions------------------------------- */ + +/* + * FUNCTION: pkix_TargetCertCheckerState_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_TargetCertCheckerState_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + pkix_TargetCertCheckerState *state = NULL; + + PKIX_ENTER(TARGETCERTCHECKERSTATE, + "pkix_TargetCertCheckerState_Destroy"); + PKIX_NULLCHECK_ONE(object); + + /* Check that this object is a target cert checker state */ + PKIX_CHECK(pkix_CheckType + (object, PKIX_TARGETCERTCHECKERSTATE_TYPE, plContext), + PKIX_OBJECTNOTTARGETCERTCHECKERSTATE); + + state = (pkix_TargetCertCheckerState *)object; + + PKIX_DECREF(state->certSelector); + PKIX_DECREF(state->extKeyUsageOID); + PKIX_DECREF(state->subjAltNameOID); + PKIX_DECREF(state->pathToNameList); + PKIX_DECREF(state->extKeyUsageList); + PKIX_DECREF(state->subjAltNameList); + +cleanup: + + PKIX_RETURN(TARGETCERTCHECKERSTATE); +} + +/* + * FUNCTION: pkix_TargetCertCheckerState_RegisterSelf + * DESCRIPTION: + * Registers PKIX_TARGETCERTCHECKERSTATE_TYPE and its related functions with + * systemClasses[] + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_TargetCertCheckerState_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(TARGETCERTCHECKERSTATE, + "pkix_TargetCertCheckerState_RegisterSelf"); + + entry.description = "TargetCertCheckerState"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(pkix_TargetCertCheckerState); + entry.destructor = pkix_TargetCertCheckerState_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_TARGETCERTCHECKERSTATE_TYPE] = entry; + + PKIX_RETURN(TARGETCERTCHECKERSTATE); +} + +/* + * FUNCTION: pkix_TargetCertCheckerState_Create + * DESCRIPTION: + * + * Creates a new TargetCertCheckerState using the CertSelector pointed to + * by "certSelector" and the number of certs represented by "certsRemaining" + * and stores it at "pState". + * + * PARAMETERS: + * "certSelector" + * Address of CertSelector representing the criteria against which the + * final certificate in a chain is to be matched. Must be non-NULL. + * "certsRemaining" + * Number of certificates remaining in the chain. + * "pState" + * Address where object pointer will be stored. Must be non-NULL. + * "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 TargetCertCheckerState Error if the function fails in a + * non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_TargetCertCheckerState_Create( + PKIX_CertSelector *certSelector, + PKIX_UInt32 certsRemaining, + pkix_TargetCertCheckerState **pState, + void *plContext) +{ + pkix_TargetCertCheckerState *state = NULL; + PKIX_ComCertSelParams *certSelectorParams = NULL; + PKIX_List *pathToNameList = NULL; + PKIX_List *extKeyUsageList = NULL; + PKIX_List *subjAltNameList = NULL; + PKIX_PL_OID *extKeyUsageOID = NULL; + PKIX_PL_OID *subjAltNameOID = NULL; + PKIX_Boolean subjAltNameMatchAll = PKIX_TRUE; + + PKIX_ENTER(TARGETCERTCHECKERSTATE, + "pkix_TargetCertCheckerState_Create"); + PKIX_NULLCHECK_ONE(pState); + + PKIX_CHECK(PKIX_PL_OID_Create + (PKIX_EXTENDEDKEYUSAGE_OID, + &extKeyUsageOID, + plContext), + PKIX_OIDCREATEFAILED); + + PKIX_CHECK(PKIX_PL_OID_Create + (PKIX_CERTSUBJALTNAME_OID, + &subjAltNameOID, + plContext), + PKIX_OIDCREATEFAILED); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_TARGETCERTCHECKERSTATE_TYPE, + sizeof (pkix_TargetCertCheckerState), + (PKIX_PL_Object **)&state, + plContext), + PKIX_COULDNOTCREATETARGETCERTCHECKERSTATEOBJECT); + + /* initialize fields */ + + if (certSelector != NULL) { + + PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams + (certSelector, &certSelectorParams, plContext), + PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMFAILED); + + if (certSelectorParams != NULL) { + + PKIX_CHECK(PKIX_ComCertSelParams_GetPathToNames + (certSelectorParams, + &pathToNameList, + plContext), + PKIX_COMCERTSELPARAMSGETPATHTONAMESFAILED); + + PKIX_CHECK(PKIX_ComCertSelParams_GetExtendedKeyUsage + (certSelectorParams, + &extKeyUsageList, + plContext), + PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED); + + PKIX_CHECK(PKIX_ComCertSelParams_GetSubjAltNames + (certSelectorParams, + &subjAltNameList, + plContext), + PKIX_COMCERTSELPARAMSGETSUBJALTNAMESFAILED); + + PKIX_CHECK(PKIX_ComCertSelParams_GetMatchAllSubjAltNames + (certSelectorParams, + &subjAltNameMatchAll, + plContext), + PKIX_COMCERTSELPARAMSGETSUBJALTNAMESFAILED); + } + } + + state->certsRemaining = certsRemaining; + state->subjAltNameMatchAll = subjAltNameMatchAll; + + PKIX_INCREF(certSelector); + state->certSelector = certSelector; + + state->pathToNameList = pathToNameList; + pathToNameList = NULL; + + state->extKeyUsageList = extKeyUsageList; + extKeyUsageList = NULL; + + state->subjAltNameList = subjAltNameList; + subjAltNameList = NULL; + + state->extKeyUsageOID = extKeyUsageOID; + extKeyUsageOID = NULL; + + state->subjAltNameOID = subjAltNameOID; + subjAltNameOID = NULL; + + *pState = state; + state = NULL; + +cleanup: + + PKIX_DECREF(extKeyUsageOID); + PKIX_DECREF(subjAltNameOID); + PKIX_DECREF(pathToNameList); + PKIX_DECREF(extKeyUsageList); + PKIX_DECREF(subjAltNameList); + PKIX_DECREF(state); + + PKIX_DECREF(certSelectorParams); + + PKIX_RETURN(TARGETCERTCHECKERSTATE); + +} + +/* --Private-TargetCertChecker-Functions------------------------------- */ + +/* + * FUNCTION: pkix_TargetCertChecker_Check + * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h) + */ +PKIX_Error * +pkix_TargetCertChecker_Check( + PKIX_CertChainChecker *checker, + PKIX_PL_Cert *cert, + PKIX_List *unresolvedCriticalExtensions, + void **pNBIOContext, + void *plContext) +{ + pkix_TargetCertCheckerState *state = NULL; + PKIX_CertSelector_MatchCallback certSelectorMatch = NULL; + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + PKIX_List *certSubjAltNames = NULL; + PKIX_List *certExtKeyUsageList = NULL; + PKIX_PL_GeneralName *name = NULL; + PKIX_PL_X500Name *certSubjectName = NULL; + PKIX_Boolean checkPassed = PKIX_FALSE; + PKIX_UInt32 numItems, i; + PKIX_UInt32 matchCount = 0; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_TargetCertChecker_Check"); + PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext); + + *pNBIOContext = NULL; /* we never block on pending I/O */ + + PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState + (checker, (PKIX_PL_Object **)&state, plContext), + PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); + + (state->certsRemaining)--; + + if (state->pathToNameList != NULL) { + + PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints + (cert, &nameConstraints, plContext), + PKIX_CERTGETNAMECONSTRAINTSFAILED); + + /* + * XXX We should either make the following call a public one + * so it is legal to call from the portability layer or we + * should try to create pathToNameList as CertNameConstraints + * then call the existing check function. + */ + PKIX_CHECK(PKIX_PL_CertNameConstraints_CheckNamesInNameSpace + (state->pathToNameList, + nameConstraints, + &checkPassed, + plContext), + PKIX_CERTNAMECONSTRAINTSCHECKNAMEINNAMESPACEFAILED); + + if (checkPassed != PKIX_TRUE) { + PKIX_ERROR(PKIX_VALIDATIONFAILEDPATHTONAMECHECKFAILED); + } + + } + + PKIX_CHECK(PKIX_PL_Cert_GetSubjectAltNames + (cert, &certSubjAltNames, plContext), + PKIX_CERTGETSUBJALTNAMESFAILED); + + if (state->subjAltNameList != NULL && certSubjAltNames != NULL) { + + PKIX_CHECK(PKIX_List_GetLength + (state->subjAltNameList, &numItems, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (i = 0; i < numItems; i++) { + + PKIX_CHECK(PKIX_List_GetItem + (state->subjAltNameList, + i, + (PKIX_PL_Object **) &name, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_List_Contains + (certSubjAltNames, + (PKIX_PL_Object *) name, + &checkPassed, + plContext), + PKIX_LISTCONTAINSFAILED); + + PKIX_DECREF(name); + + if (checkPassed == PKIX_TRUE) { + + if (state->subjAltNameMatchAll == PKIX_FALSE) { + matchCount = numItems; + break; + } else { + /* else continue checking next */ + matchCount++; + } + + } + } + + if (matchCount != numItems) { + PKIX_ERROR(PKIX_SUBJALTNAMECHECKFAILED); + + } + } + + if (state->certsRemaining == 0) { + + if (state->certSelector != NULL) { + PKIX_CHECK(PKIX_CertSelector_GetMatchCallback + (state->certSelector, + &certSelectorMatch, + plContext), + PKIX_CERTSELECTORGETMATCHCALLBACKFAILED); + + PKIX_CHECK(certSelectorMatch + (state->certSelector, + cert, + plContext), + PKIX_CERTSELECTORMATCHFAILED); + } else { + /* Check at least cert/key usages if target cert selector + * is not set. */ + PKIX_CHECK(PKIX_PL_Cert_VerifyCertAndKeyType(cert, + PKIX_FALSE /* is chain cert*/, + plContext), + PKIX_CERTVERIFYCERTTYPEFAILED); + } + /* + * There are two Extended Key Usage Checkings + * available : + * 1) here at the targetcertchecker where we + * verify the Extended Key Usage OIDs application + * specifies via ComCertSelParams are included + * in Cert's Extended Key Usage OID's. Note, + * this is an OID to OID comparison and only last + * Cert is checked. + * 2) at user defined ekuchecker where checking + * is applied to all Certs on the chain and + * the NSS Extended Key Usage algorithm is + * used. In order to invoke this checking, not + * only does the ComCertSelparams needs to be + * set, the EKU initialize call is required to + * activate the checking. + * + * XXX We use the same ComCertSelParams Set/Get + * functions to set the parameters for both cases. + * We may want to separate them in the future. + */ + + PKIX_CHECK(PKIX_PL_Cert_GetExtendedKeyUsage + (cert, &certExtKeyUsageList, plContext), + PKIX_CERTGETEXTENDEDKEYUSAGEFAILED); + + + if (state->extKeyUsageList != NULL && + certExtKeyUsageList != NULL) { + + PKIX_CHECK(PKIX_List_GetLength + (state->extKeyUsageList, &numItems, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (i = 0; i < numItems; i++) { + + PKIX_CHECK(PKIX_List_GetItem + (state->extKeyUsageList, + i, + (PKIX_PL_Object **) &name, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_List_Contains + (certExtKeyUsageList, + (PKIX_PL_Object *) name, + &checkPassed, + plContext), + PKIX_LISTCONTAINSFAILED); + + PKIX_DECREF(name); + + if (checkPassed != PKIX_TRUE) { + PKIX_ERROR + (PKIX_EXTENDEDKEYUSAGECHECKINGFAILED); + + } + } + } + } else { + /* Check key usage and cert type based on certificate usage. */ + PKIX_CHECK(PKIX_PL_Cert_VerifyCertAndKeyType(cert, PKIX_TRUE, + plContext), + PKIX_CERTVERIFYCERTTYPEFAILED); + } + + /* Remove Critical Extension OID from list */ + if (unresolvedCriticalExtensions != NULL) { + + PKIX_CHECK(pkix_List_Remove + (unresolvedCriticalExtensions, + (PKIX_PL_Object *) state->extKeyUsageOID, + plContext), + PKIX_LISTREMOVEFAILED); + + PKIX_CHECK(PKIX_PL_Cert_GetSubject + (cert, &certSubjectName, plContext), + PKIX_CERTGETSUBJECTFAILED); + + if (certSubjAltNames != NULL) { + PKIX_CHECK(pkix_List_Remove + (unresolvedCriticalExtensions, + (PKIX_PL_Object *) state->subjAltNameOID, + plContext), + PKIX_LISTREMOVEFAILED); + } + + } + +cleanup: + + PKIX_DECREF(name); + PKIX_DECREF(nameConstraints); + PKIX_DECREF(certSubjAltNames); + PKIX_DECREF(certExtKeyUsageList); + PKIX_DECREF(certSubjectName); + PKIX_DECREF(state); + + PKIX_RETURN(CERTCHAINCHECKER); + +} + +/* + * FUNCTION: pkix_TargetCertChecker_Initialize + * DESCRIPTION: + * + * Creates a new CertChainChecker and stores it at "pChecker", where it will + * used by pkix_TargetCertChecker_Check to check that the final certificate + * of a chain meets the criteria of the CertSelector pointed to by + * "certSelector". The number of certs remaining in the chain, represented by + * "certsRemaining" is used to initialize the checker's state. + * + * PARAMETERS: + * "certSelector" + * Address of CertSelector representing the criteria against which the + * final certificate in a chain is to be matched. May be NULL. + * "certsRemaining" + * Number of certificates remaining in the chain. + * "pChecker" + * Address where object pointer will be stored. Must be non-NULL. + * "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 CertChainChecker Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_TargetCertChecker_Initialize( + PKIX_CertSelector *certSelector, + PKIX_UInt32 certsRemaining, + PKIX_CertChainChecker **pChecker, + void *plContext) +{ + pkix_TargetCertCheckerState *state = NULL; + + PKIX_ENTER(CERTCHAINCHECKER, "pkix_TargetCertChecker_Initialize"); + PKIX_NULLCHECK_ONE(pChecker); + + PKIX_CHECK(pkix_TargetCertCheckerState_Create + (certSelector, certsRemaining, &state, plContext), + PKIX_TARGETCERTCHECKERSTATECREATEFAILED); + + PKIX_CHECK(PKIX_CertChainChecker_Create + (pkix_TargetCertChecker_Check, + PKIX_FALSE, + PKIX_FALSE, + NULL, + (PKIX_PL_Object *)state, + pChecker, + plContext), + PKIX_CERTCHAINCHECKERCREATEFAILED); + +cleanup: + + PKIX_DECREF(state); + + PKIX_RETURN(CERTCHAINCHECKER); +} diff --git a/security/nss/lib/libpkix/pkix/checker/pkix_targetcertchecker.h b/security/nss/lib/libpkix/pkix/checker/pkix_targetcertchecker.h new file mode 100644 index 0000000000..4592d10a94 --- /dev/null +++ b/security/nss/lib/libpkix/pkix/checker/pkix_targetcertchecker.h @@ -0,0 +1,47 @@ +/* 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/. */ +/* + * pkix_targetcertchecker.h + * + * Header file for validate target cert function + * + */ + +#ifndef _PKIX_TARGETCERTCHECKER_H +#define _PKIX_TARGETCERTCHECKER_H + +#include "pkix_tools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pkix_TargetCertCheckerState pkix_TargetCertCheckerState; + +struct pkix_TargetCertCheckerState { + PKIX_CertSelector *certSelector; + PKIX_List *pathToNameList; + PKIX_List *extKeyUsageList; /* List of PKIX_PL_OID */ + PKIX_List *subjAltNameList; + PKIX_Boolean subjAltNameMatchAll; + PKIX_UInt32 certsRemaining; + PKIX_PL_OID *extKeyUsageOID; + PKIX_PL_OID *subjAltNameOID; +}; + +PKIX_Error * +pkix_TargetCertChecker_Initialize( + PKIX_CertSelector *certSelector, + PKIX_UInt32 certsRemaining, + PKIX_CertChainChecker **pChecker, + void *plContext); + +PKIX_Error * +pkix_TargetCertCheckerState_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_TARGETCERTCHECKER_H */ |