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