| /* 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); |
| } |