michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: /* michael@0: * pkix_basicconstraintschecker.c michael@0: * michael@0: * Functions for basic constraints validation michael@0: * michael@0: */ michael@0: michael@0: #include "pkix_basicconstraintschecker.h" michael@0: michael@0: /* --Private-BasicConstraintsCheckerState-Functions------------------------- */ michael@0: michael@0: /* michael@0: * FUNCTION: pkix_BasicConstraintsCheckerState_Destroy michael@0: * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) michael@0: */ michael@0: static PKIX_Error * michael@0: pkix_BasicConstraintsCheckerState_Destroy( michael@0: PKIX_PL_Object *object, michael@0: void *plContext) michael@0: { michael@0: pkix_BasicConstraintsCheckerState *state = NULL; michael@0: michael@0: PKIX_ENTER(BASICCONSTRAINTSCHECKERSTATE, michael@0: "pkix_BasicConstraintsCheckerState_Destroy"); michael@0: michael@0: PKIX_NULLCHECK_ONE(object); michael@0: michael@0: /* Check that this object is a basic constraints checker state */ michael@0: PKIX_CHECK(pkix_CheckType michael@0: (object, PKIX_BASICCONSTRAINTSCHECKERSTATE_TYPE, plContext), michael@0: PKIX_OBJECTNOTBASICCONSTRAINTSCHECKERSTATE); michael@0: michael@0: state = (pkix_BasicConstraintsCheckerState *)object; michael@0: michael@0: PKIX_DECREF(state->basicConstraintsOID); michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_RETURN(BASICCONSTRAINTSCHECKERSTATE); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_BasicConstraintsCheckerState_RegisterSelf michael@0: * DESCRIPTION: michael@0: * Registers PKIX_CERT_TYPE and its related functions with systemClasses[] michael@0: * THREAD SAFETY: michael@0: * Not Thread Safe - for performance and complexity reasons michael@0: * michael@0: * Since this function is only called by PKIX_PL_Initialize, which should michael@0: * only be called once, it is acceptable that this function is not michael@0: * thread-safe. michael@0: */ michael@0: PKIX_Error * michael@0: pkix_BasicConstraintsCheckerState_RegisterSelf(void *plContext) michael@0: { michael@0: extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; michael@0: pkix_ClassTable_Entry entry; michael@0: michael@0: PKIX_ENTER(BASICCONSTRAINTSCHECKERSTATE, michael@0: "pkix_BasicConstraintsCheckerState_RegisterSelf"); michael@0: michael@0: entry.description = "BasicConstraintsCheckerState"; michael@0: entry.objCounter = 0; michael@0: entry.typeObjectSize = sizeof(pkix_BasicConstraintsCheckerState); michael@0: entry.destructor = pkix_BasicConstraintsCheckerState_Destroy; michael@0: entry.equalsFunction = NULL; michael@0: entry.hashcodeFunction = NULL; michael@0: entry.toStringFunction = NULL; michael@0: entry.comparator = NULL; michael@0: entry.duplicateFunction = NULL; michael@0: michael@0: systemClasses[PKIX_BASICCONSTRAINTSCHECKERSTATE_TYPE] = entry; michael@0: michael@0: PKIX_RETURN(BASICCONSTRAINTSCHECKERSTATE); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_BasicConstraintsCheckerState_Create michael@0: * DESCRIPTION: michael@0: * michael@0: * Creates a new BasicConstraintsCheckerState using the number of certs in michael@0: * the chain represented by "certsRemaining" and stores it at "pState". michael@0: * michael@0: * PARAMETERS: michael@0: * "certsRemaining" michael@0: * Number of certificates in the chain. michael@0: * "pState" michael@0: * Address where object pointer will be stored. Must be non-NULL. michael@0: * "plContext" michael@0: * Platform-specific context pointer. michael@0: * THREAD SAFETY: michael@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) michael@0: * RETURNS: michael@0: * Returns NULL if the function succeeds. michael@0: * Returns a BasicConstraintsCheckerState Error if the function fails in a michael@0: * non-fatal way. michael@0: * Returns a Fatal Error if the function fails in an unrecoverable way. michael@0: */ michael@0: static PKIX_Error * michael@0: pkix_BasicConstraintsCheckerState_Create( michael@0: PKIX_UInt32 certsRemaining, michael@0: pkix_BasicConstraintsCheckerState **pState, michael@0: void *plContext) michael@0: { michael@0: pkix_BasicConstraintsCheckerState *state = NULL; michael@0: michael@0: PKIX_ENTER(BASICCONSTRAINTSCHECKERSTATE, michael@0: "pkix_BasicConstraintsCheckerState_Create"); michael@0: michael@0: PKIX_NULLCHECK_ONE(pState); michael@0: michael@0: PKIX_CHECK(PKIX_PL_Object_Alloc michael@0: (PKIX_BASICCONSTRAINTSCHECKERSTATE_TYPE, michael@0: sizeof (pkix_BasicConstraintsCheckerState), michael@0: (PKIX_PL_Object **)&state, michael@0: plContext), michael@0: PKIX_COULDNOTCREATEBASICCONSTRAINTSSTATEOBJECT); michael@0: michael@0: /* initialize fields */ michael@0: state->certsRemaining = certsRemaining; michael@0: state->maxPathLength = PKIX_UNLIMITED_PATH_CONSTRAINT; michael@0: michael@0: PKIX_CHECK(PKIX_PL_OID_Create michael@0: (PKIX_BASICCONSTRAINTS_OID, michael@0: &state->basicConstraintsOID, michael@0: plContext), michael@0: PKIX_OIDCREATEFAILED); michael@0: michael@0: *pState = state; michael@0: state = NULL; michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_DECREF(state); michael@0: michael@0: PKIX_RETURN(BASICCONSTRAINTSCHECKERSTATE); michael@0: } michael@0: michael@0: /* --Private-BasicConstraintsChecker-Functions------------------------------ */ michael@0: michael@0: /* michael@0: * FUNCTION: pkix_BasicConstraintsChecker_Check michael@0: * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h) michael@0: */ michael@0: PKIX_Error * michael@0: pkix_BasicConstraintsChecker_Check( michael@0: PKIX_CertChainChecker *checker, michael@0: PKIX_PL_Cert *cert, michael@0: PKIX_List *unresolvedCriticalExtensions, /* list of PKIX_PL_OID */ michael@0: void **pNBIOContext, michael@0: void *plContext) michael@0: { michael@0: PKIX_PL_CertBasicConstraints *basicConstraints = NULL; michael@0: pkix_BasicConstraintsCheckerState *state = NULL; michael@0: PKIX_Boolean caFlag = PKIX_FALSE; michael@0: PKIX_Int32 pathLength = 0; michael@0: PKIX_Int32 maxPathLength_now; michael@0: PKIX_Boolean isSelfIssued = PKIX_FALSE; michael@0: michael@0: PKIX_ENTER(CERTCHAINCHECKER, "pkix_BasicConstraintsChecker_Check"); michael@0: PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext); michael@0: michael@0: *pNBIOContext = NULL; /* we never block on pending I/O */ michael@0: michael@0: PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState michael@0: (checker, (PKIX_PL_Object **)&state, plContext), michael@0: PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); michael@0: michael@0: state->certsRemaining--; michael@0: michael@0: if (state->certsRemaining != 0) { michael@0: michael@0: PKIX_CHECK(PKIX_PL_Cert_GetBasicConstraints michael@0: (cert, &basicConstraints, plContext), michael@0: PKIX_CERTGETBASICCONSTRAINTSFAILED); michael@0: michael@0: /* get CA Flag and path length */ michael@0: if (basicConstraints != NULL) { michael@0: PKIX_CHECK(PKIX_PL_BasicConstraints_GetCAFlag michael@0: (basicConstraints, michael@0: &caFlag, michael@0: plContext), michael@0: PKIX_BASICCONSTRAINTSGETCAFLAGFAILED); michael@0: michael@0: if (caFlag == PKIX_TRUE) { michael@0: PKIX_CHECK michael@0: (PKIX_PL_BasicConstraints_GetPathLenConstraint michael@0: (basicConstraints, michael@0: &pathLength, michael@0: plContext), michael@0: PKIX_BASICCONSTRAINTSGETPATHLENCONSTRAINTFAILED); michael@0: } michael@0: michael@0: }else{ michael@0: caFlag = PKIX_FALSE; michael@0: pathLength = PKIX_UNLIMITED_PATH_CONSTRAINT; michael@0: } michael@0: michael@0: PKIX_CHECK(pkix_IsCertSelfIssued michael@0: (cert, michael@0: &isSelfIssued, michael@0: plContext), michael@0: PKIX_ISCERTSELFISSUEDFAILED); michael@0: michael@0: maxPathLength_now = state->maxPathLength; michael@0: michael@0: if (isSelfIssued != PKIX_TRUE) { michael@0: michael@0: /* Not last CA Cert, but maxPathLength is down to zero */ michael@0: if (maxPathLength_now == 0) { michael@0: PKIX_ERROR(PKIX_BASICCONSTRAINTSVALIDATIONFAILEDLN); michael@0: } michael@0: michael@0: if (caFlag == PKIX_FALSE) { michael@0: PKIX_ERROR(PKIX_BASICCONSTRAINTSVALIDATIONFAILEDCA); michael@0: } michael@0: michael@0: if (maxPathLength_now > 0) { /* can be unlimited (-1) */ michael@0: maxPathLength_now--; michael@0: } michael@0: michael@0: } michael@0: michael@0: if (caFlag == PKIX_TRUE) { michael@0: if (maxPathLength_now == PKIX_UNLIMITED_PATH_CONSTRAINT){ michael@0: maxPathLength_now = pathLength; michael@0: } else { michael@0: /* If pathLength is not specified, don't set */ michael@0: if (pathLength != PKIX_UNLIMITED_PATH_CONSTRAINT) { michael@0: maxPathLength_now = michael@0: (maxPathLength_now > pathLength)? michael@0: pathLength:maxPathLength_now; michael@0: } michael@0: } michael@0: } michael@0: michael@0: state->maxPathLength = maxPathLength_now; michael@0: } michael@0: michael@0: /* Remove Basic Constraints Extension OID from list */ michael@0: if (unresolvedCriticalExtensions != NULL) { michael@0: michael@0: PKIX_CHECK(pkix_List_Remove michael@0: (unresolvedCriticalExtensions, michael@0: (PKIX_PL_Object *) state->basicConstraintsOID, michael@0: plContext), michael@0: PKIX_LISTREMOVEFAILED); michael@0: } michael@0: michael@0: michael@0: PKIX_CHECK(PKIX_CertChainChecker_SetCertChainCheckerState michael@0: (checker, (PKIX_PL_Object *)state, plContext), michael@0: PKIX_CERTCHAINCHECKERSETCERTCHAINCHECKERSTATEFAILED); michael@0: michael@0: michael@0: cleanup: michael@0: PKIX_DECREF(state); michael@0: PKIX_DECREF(basicConstraints); michael@0: PKIX_RETURN(CERTCHAINCHECKER); michael@0: michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_BasicConstraintsChecker_Initialize michael@0: * DESCRIPTION: michael@0: * Registers PKIX_CERT_TYPE and its related functions with systemClasses[] michael@0: * THREAD SAFETY: michael@0: * Not Thread Safe - for performance and complexity reasons michael@0: * michael@0: * Since this function is only called by PKIX_PL_Initialize, which should michael@0: * only be called once, it is acceptable that this function is not michael@0: * thread-safe. michael@0: */ michael@0: PKIX_Error * michael@0: pkix_BasicConstraintsChecker_Initialize( michael@0: PKIX_UInt32 certsRemaining, michael@0: PKIX_CertChainChecker **pChecker, michael@0: void *plContext) michael@0: { michael@0: pkix_BasicConstraintsCheckerState *state = NULL; michael@0: michael@0: PKIX_ENTER(CERTCHAINCHECKER, "pkix_BasicConstraintsChecker_Initialize"); michael@0: PKIX_NULLCHECK_ONE(pChecker); michael@0: michael@0: PKIX_CHECK(pkix_BasicConstraintsCheckerState_Create michael@0: (certsRemaining, &state, plContext), michael@0: PKIX_BASICCONSTRAINTSCHECKERSTATECREATEFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_CertChainChecker_Create michael@0: (pkix_BasicConstraintsChecker_Check, michael@0: PKIX_FALSE, michael@0: PKIX_FALSE, michael@0: NULL, michael@0: (PKIX_PL_Object *)state, michael@0: pChecker, michael@0: plContext), michael@0: PKIX_CERTCHAINCHECKERCHECKFAILED); michael@0: michael@0: cleanup: michael@0: PKIX_DECREF(state); michael@0: michael@0: PKIX_RETURN(CERTCHAINCHECKER); michael@0: }