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_nameconstraintschecker.c michael@0: * michael@0: * Functions for Name Constraints Checkers michael@0: * michael@0: */ michael@0: michael@0: #include "pkix_nameconstraintschecker.h" michael@0: michael@0: /* --Private-NameConstraintsCheckerState-Functions---------------------- */ michael@0: michael@0: /* michael@0: * FUNCTION: pkix_NameConstraintsCheckerstate_Destroy michael@0: * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) michael@0: */ michael@0: static PKIX_Error * michael@0: pkix_NameConstraintsCheckerState_Destroy( michael@0: PKIX_PL_Object *object, michael@0: void *plContext) michael@0: { michael@0: pkix_NameConstraintsCheckerState *state = NULL; michael@0: michael@0: PKIX_ENTER(CERTNAMECONSTRAINTSCHECKERSTATE, michael@0: "pkix_NameConstraintsCheckerState_Destroy"); michael@0: PKIX_NULLCHECK_ONE(object); michael@0: michael@0: /* Check that object type */ michael@0: PKIX_CHECK(pkix_CheckType michael@0: (object, PKIX_CERTNAMECONSTRAINTSCHECKERSTATE_TYPE, plContext), michael@0: PKIX_OBJECTNOTNAMECONSTRAINTSCHECKERSTATE); michael@0: michael@0: state = (pkix_NameConstraintsCheckerState *)object; michael@0: michael@0: PKIX_DECREF(state->nameConstraints); michael@0: PKIX_DECREF(state->nameConstraintsOID); michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_RETURN(CERTNAMECONSTRAINTSCHECKERSTATE); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_NameConstraintsCheckerState_RegisterSelf michael@0: * michael@0: * DESCRIPTION: michael@0: * Registers PKIX_CERTNAMECONSTRAINTSCHECKERSTATE_TYPE and its related michael@0: * functions with systemClasses[] michael@0: * 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_NameConstraintsCheckerState_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(CERTNAMECONSTRAINTSCHECKERSTATE, michael@0: "pkix_NameConstraintsCheckerState_RegisterSelf"); michael@0: michael@0: entry.description = "NameConstraintsCheckerState"; michael@0: entry.objCounter = 0; michael@0: entry.typeObjectSize = sizeof(pkix_NameConstraintsCheckerState); michael@0: entry.destructor = pkix_NameConstraintsCheckerState_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_CERTNAMECONSTRAINTSCHECKERSTATE_TYPE] = entry; michael@0: michael@0: PKIX_RETURN(CERTNAMECONSTRAINTSCHECKERSTATE); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_NameConstraintsCheckerState_Create michael@0: * michael@0: * DESCRIPTION: michael@0: * Allocate and initialize NameConstraintsChecker state data. michael@0: * michael@0: * PARAMETERS michael@0: * "nameConstraints" michael@0: * Address of NameConstraints to be stored in state. May be NULL. michael@0: * "numCerts" michael@0: * Number of certificates in the validation chain. This data is used michael@0: * to identify end-entity. michael@0: * "pCheckerState" michael@0: * Address of NameConstraintsCheckerState that is returned. Must be michael@0: * non-NULL. michael@0: * "plContext" - Platform-specific context pointer. michael@0: * michael@0: * THREAD SAFETY: michael@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) michael@0: * michael@0: * RETURNS: michael@0: * Returns NULL if the function succeeds. michael@0: * Returns a CERTNAMECONSTRAINTSCHECKERSTATE Error if the function fails in michael@0: * a non-fatal way. michael@0: * Returns a Fatal Error michael@0: */ michael@0: static PKIX_Error * michael@0: pkix_NameConstraintsCheckerState_Create( michael@0: PKIX_PL_CertNameConstraints *nameConstraints, michael@0: PKIX_UInt32 numCerts, michael@0: pkix_NameConstraintsCheckerState **pCheckerState, michael@0: void *plContext) michael@0: { michael@0: pkix_NameConstraintsCheckerState *state = NULL; michael@0: michael@0: PKIX_ENTER(CERTNAMECONSTRAINTSCHECKERSTATE, michael@0: "pkix_NameConstraintsCheckerState_Create"); michael@0: PKIX_NULLCHECK_ONE(pCheckerState); michael@0: michael@0: PKIX_CHECK(PKIX_PL_Object_Alloc michael@0: (PKIX_CERTNAMECONSTRAINTSCHECKERSTATE_TYPE, michael@0: sizeof (pkix_NameConstraintsCheckerState), michael@0: (PKIX_PL_Object **)&state, michael@0: plContext), michael@0: PKIX_COULDNOTCREATENAMECONSTRAINTSCHECKERSTATEOBJECT); michael@0: michael@0: /* Initialize fields */ michael@0: michael@0: PKIX_CHECK(PKIX_PL_OID_Create michael@0: (PKIX_NAMECONSTRAINTS_OID, michael@0: &state->nameConstraintsOID, michael@0: plContext), michael@0: PKIX_OIDCREATEFAILED); michael@0: michael@0: PKIX_INCREF(nameConstraints); michael@0: michael@0: state->nameConstraints = nameConstraints; michael@0: state->certsRemaining = numCerts; michael@0: michael@0: *pCheckerState = state; michael@0: state = NULL; michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_DECREF(state); michael@0: michael@0: PKIX_RETURN(CERTNAMECONSTRAINTSCHECKERSTATE); michael@0: } michael@0: michael@0: /* --Private-NameConstraintsChecker-Functions------------------------- */ michael@0: michael@0: /* michael@0: * FUNCTION: pkix_NameConstraintsChecker_Check michael@0: * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h) michael@0: */ michael@0: static PKIX_Error * michael@0: pkix_NameConstraintsChecker_Check( michael@0: PKIX_CertChainChecker *checker, michael@0: PKIX_PL_Cert *cert, michael@0: PKIX_List *unresolvedCriticalExtensions, michael@0: void **pNBIOContext, michael@0: void *plContext) michael@0: { michael@0: pkix_NameConstraintsCheckerState *state = NULL; michael@0: PKIX_PL_CertNameConstraints *nameConstraints = NULL; michael@0: PKIX_PL_CertNameConstraints *mergedNameConstraints = NULL; michael@0: PKIX_Boolean selfIssued = PKIX_FALSE; michael@0: PKIX_Boolean lastCert = PKIX_FALSE; michael@0: michael@0: PKIX_ENTER(CERTCHAINCHECKER, "pkix_NameConstraintsChecker_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: lastCert = state->certsRemaining == 0; michael@0: michael@0: /* Get status of self issued */ michael@0: PKIX_CHECK(pkix_IsCertSelfIssued(cert, &selfIssued, plContext), michael@0: PKIX_ISCERTSELFISSUEDFAILED); michael@0: michael@0: /* Check on non self-issued and if so only for last cert */ michael@0: if (selfIssued == PKIX_FALSE || michael@0: (selfIssued == PKIX_TRUE && lastCert)) { michael@0: PKIX_CHECK(PKIX_PL_Cert_CheckNameConstraints michael@0: (cert, state->nameConstraints, lastCert, michael@0: plContext), michael@0: PKIX_CERTCHECKNAMECONSTRAINTSFAILED); michael@0: } michael@0: michael@0: if (!lastCert) { michael@0: michael@0: PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints michael@0: (cert, &nameConstraints, plContext), michael@0: PKIX_CERTGETNAMECONSTRAINTSFAILED); michael@0: michael@0: /* Merge with previous name constraints kept in state */ michael@0: michael@0: if (nameConstraints != NULL) { michael@0: michael@0: if (state->nameConstraints == NULL) { michael@0: michael@0: state->nameConstraints = nameConstraints; michael@0: michael@0: } else { michael@0: michael@0: PKIX_CHECK(PKIX_PL_Cert_MergeNameConstraints michael@0: (nameConstraints, michael@0: state->nameConstraints, michael@0: &mergedNameConstraints, michael@0: plContext), michael@0: PKIX_CERTMERGENAMECONSTRAINTSFAILED); michael@0: michael@0: PKIX_DECREF(nameConstraints); michael@0: PKIX_DECREF(state->nameConstraints); michael@0: michael@0: state->nameConstraints = mergedNameConstraints; michael@0: } michael@0: michael@0: /* Remove Name Constraints Extension OID from list */ michael@0: if (unresolvedCriticalExtensions != NULL) { michael@0: PKIX_CHECK(pkix_List_Remove michael@0: (unresolvedCriticalExtensions, michael@0: (PKIX_PL_Object *)state->nameConstraintsOID, michael@0: plContext), michael@0: PKIX_LISTREMOVEFAILED); michael@0: } 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: cleanup: michael@0: michael@0: PKIX_DECREF(state); michael@0: michael@0: PKIX_RETURN(CERTCHAINCHECKER); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_NameConstraintsChecker_Initialize michael@0: * michael@0: * DESCRIPTION: michael@0: * Create a CertChainChecker with a NameConstraintsCheckerState. The michael@0: * NameConstraintsCheckerState is created with "trustedNC" and "numCerts" michael@0: * as its initial state. The CertChainChecker for the NameConstraints is michael@0: * returned at address of "pChecker". michael@0: * michael@0: * PARAMETERS michael@0: * "trustedNC" michael@0: * The NameConstraints from trusted anchor Cert is stored at "trustedNC" michael@0: * for initialization. May be NULL. michael@0: * "numCerts" michael@0: * Number of certificates in the validation chain. This data is used michael@0: * to identify end-entity. michael@0: * "pChecker" michael@0: * Address of CertChainChecker to bo created and returned. michael@0: * Must be non-NULL. michael@0: * "plContext" - Platform-specific context pointer. michael@0: * michael@0: * THREAD SAFETY: michael@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) michael@0: * michael@0: * RETURNS: michael@0: * Returns NULL if the function succeeds. michael@0: * Returns a CERTCHAINCHECKER Error if the function fails in a non-fatal way. michael@0: * Returns a Fatal Error michael@0: */ michael@0: PKIX_Error * michael@0: pkix_NameConstraintsChecker_Initialize( michael@0: PKIX_PL_CertNameConstraints *trustedNC, michael@0: PKIX_UInt32 numCerts, michael@0: PKIX_CertChainChecker **pChecker, michael@0: void *plContext) michael@0: { michael@0: pkix_NameConstraintsCheckerState *state = NULL; michael@0: michael@0: PKIX_ENTER(CERTCHAINCHECKER, "pkix_NameConstraintsChecker_Initialize"); michael@0: PKIX_NULLCHECK_ONE(pChecker); michael@0: michael@0: PKIX_CHECK(pkix_NameConstraintsCheckerState_Create michael@0: (trustedNC, numCerts, &state, plContext), michael@0: PKIX_NAMECONSTRAINTSCHECKERSTATECREATEFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_CertChainChecker_Create michael@0: (pkix_NameConstraintsChecker_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_CERTCHAINCHECKERCREATEFAILED); michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_DECREF(state); michael@0: michael@0: PKIX_RETURN(CERTCHAINCHECKER); michael@0: }