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_ekuchecker.c michael@0: * michael@0: * User Defined ExtenedKeyUsage Function Definitions michael@0: * michael@0: */ michael@0: michael@0: #include "pkix_ekuchecker.h" michael@0: michael@0: SECOidTag ekuOidStrings[] = { michael@0: PKIX_KEY_USAGE_SERVER_AUTH_OID, michael@0: PKIX_KEY_USAGE_CLIENT_AUTH_OID, michael@0: PKIX_KEY_USAGE_CODE_SIGN_OID, michael@0: PKIX_KEY_USAGE_EMAIL_PROTECT_OID, michael@0: PKIX_KEY_USAGE_TIME_STAMP_OID, michael@0: PKIX_KEY_USAGE_OCSP_RESPONDER_OID, michael@0: PKIX_UNKNOWN_OID michael@0: }; michael@0: michael@0: typedef struct pkix_EkuCheckerStruct { michael@0: PKIX_List *requiredExtKeyUsageOids; michael@0: PKIX_PL_OID *ekuOID; michael@0: } pkix_EkuChecker; michael@0: michael@0: michael@0: /* michael@0: * FUNCTION: pkix_EkuChecker_Destroy michael@0: * (see comments for PKIX_DestructorCallback in pkix_pl_system.h) michael@0: */ michael@0: static PKIX_Error * michael@0: pkix_EkuChecker_Destroy( michael@0: PKIX_PL_Object *object, michael@0: void *plContext) michael@0: { michael@0: pkix_EkuChecker *ekuCheckerState = NULL; michael@0: michael@0: PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_Destroy"); michael@0: PKIX_NULLCHECK_ONE(object); michael@0: michael@0: PKIX_CHECK(pkix_CheckType(object, PKIX_EKUCHECKER_TYPE, plContext), michael@0: PKIX_OBJECTNOTANEKUCHECKERSTATE); michael@0: michael@0: ekuCheckerState = (pkix_EkuChecker *)object; michael@0: michael@0: PKIX_DECREF(ekuCheckerState->ekuOID); michael@0: PKIX_DECREF(ekuCheckerState->requiredExtKeyUsageOids); michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_RETURN(EKUCHECKER); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_EkuChecker_RegisterSelf michael@0: * michael@0: * DESCRIPTION: michael@0: * Registers PKIX_PL_HTTPCERTSTORECONTEXT_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_EkuChecker_RegisterSelf(void *plContext) michael@0: { michael@0: extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; michael@0: pkix_ClassTable_Entry *entry = &systemClasses[PKIX_EKUCHECKER_TYPE]; michael@0: michael@0: PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_RegisterSelf"); michael@0: michael@0: entry->description = "EkuChecker"; michael@0: entry->typeObjectSize = sizeof(pkix_EkuChecker); michael@0: entry->destructor = pkix_EkuChecker_Destroy; michael@0: michael@0: PKIX_RETURN(EKUCHECKER); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_EkuChecker_Create michael@0: * DESCRIPTION: michael@0: * michael@0: * Creates a new Extend Key Usage CheckerState using "params" to retrieve michael@0: * application specified EKU for verification and stores it at "pState". michael@0: * michael@0: * PARAMETERS: michael@0: * "params" michael@0: * a PKIX_ProcessingParams links to PKIX_ComCertSelParams where a list of michael@0: * Extended Key Usage OIDs specified by application can be retrieved for michael@0: * verification. michael@0: * "pState" michael@0: * Address where state 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 UserDefinedModules 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_EkuChecker_Create( michael@0: PKIX_ProcessingParams *params, michael@0: pkix_EkuChecker **pState, michael@0: void *plContext) michael@0: { michael@0: pkix_EkuChecker *state = NULL; michael@0: PKIX_CertSelector *certSelector = NULL; michael@0: PKIX_ComCertSelParams *comCertSelParams = NULL; michael@0: PKIX_List *requiredOids = NULL; michael@0: michael@0: PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_Create"); michael@0: PKIX_NULLCHECK_TWO(params, pState); michael@0: michael@0: PKIX_CHECK(PKIX_PL_Object_Alloc michael@0: (PKIX_EKUCHECKER_TYPE, michael@0: sizeof (pkix_EkuChecker), michael@0: (PKIX_PL_Object **)&state, michael@0: plContext), michael@0: PKIX_COULDNOTCREATEEKUCHECKERSTATEOBJECT); michael@0: michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints michael@0: (params, &certSelector, plContext), michael@0: PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED); michael@0: michael@0: if (certSelector != NULL) { michael@0: michael@0: /* Get initial EKU OIDs from ComCertSelParams, if set */ michael@0: PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams michael@0: (certSelector, &comCertSelParams, plContext), michael@0: PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED); michael@0: michael@0: if (comCertSelParams != NULL) { michael@0: PKIX_CHECK(PKIX_ComCertSelParams_GetExtendedKeyUsage michael@0: (comCertSelParams, &requiredOids, plContext), michael@0: PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED); michael@0: michael@0: } michael@0: } michael@0: michael@0: PKIX_CHECK(PKIX_PL_OID_Create michael@0: (PKIX_EXTENDEDKEYUSAGE_OID, michael@0: &state->ekuOID, michael@0: plContext), michael@0: PKIX_OIDCREATEFAILED); michael@0: michael@0: state->requiredExtKeyUsageOids = requiredOids; michael@0: requiredOids = NULL; michael@0: *pState = state; michael@0: state = NULL; michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_DECREF(certSelector); michael@0: PKIX_DECREF(comCertSelParams); michael@0: PKIX_DECREF(requiredOids); michael@0: PKIX_DECREF(state); michael@0: michael@0: PKIX_RETURN(EKUCHECKER); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_EkuChecker_Check michael@0: * DESCRIPTION: michael@0: * michael@0: * This function determines the Extended Key Usage OIDs specified by the michael@0: * application is included in the Extended Key Usage OIDs of this "cert". michael@0: * michael@0: * PARAMETERS: michael@0: * "checker" michael@0: * Address of CertChainChecker which has the state data. michael@0: * Must be non-NULL. michael@0: * "cert" michael@0: * Address of Certificate that is to be validated. Must be non-NULL. michael@0: * "unresolvedCriticalExtensions" michael@0: * A List OIDs. The OID for Extended Key Usage is removed. 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 UserDefinedModules Error if the function fails in michael@0: * a 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_EkuChecker_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_EkuChecker *state = NULL; michael@0: PKIX_List *requiredExtKeyUsageList = NULL; michael@0: PKIX_List *certExtKeyUsageList = NULL; michael@0: PKIX_PL_OID *ekuOid = NULL; michael@0: PKIX_Boolean isContained = PKIX_FALSE; michael@0: PKIX_UInt32 numItems = 0; michael@0: PKIX_UInt32 i; michael@0: PKIX_Boolean checkResult = PKIX_TRUE; michael@0: michael@0: PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_Check"); michael@0: PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext); michael@0: michael@0: *pNBIOContext = NULL; /* no non-blocking IO */ michael@0: michael@0: PKIX_CHECK( michael@0: PKIX_CertChainChecker_GetCertChainCheckerState michael@0: (checker, (PKIX_PL_Object **)&state, plContext), michael@0: PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); michael@0: michael@0: requiredExtKeyUsageList = state->requiredExtKeyUsageOids; michael@0: if (requiredExtKeyUsageList == NULL) { michael@0: goto cleanup; michael@0: } michael@0: michael@0: PKIX_CHECK( michael@0: PKIX_List_GetLength(requiredExtKeyUsageList, &numItems, michael@0: plContext), michael@0: PKIX_LISTGETLENGTHFAILED); michael@0: if (numItems == 0) { michael@0: goto cleanup; michael@0: } michael@0: michael@0: PKIX_CHECK( michael@0: PKIX_PL_Cert_GetExtendedKeyUsage(cert, &certExtKeyUsageList, michael@0: plContext), michael@0: PKIX_CERTGETEXTENDEDKEYUSAGEFAILED); michael@0: michael@0: if (certExtKeyUsageList == NULL) { michael@0: goto cleanup; michael@0: } michael@0: michael@0: for (i = 0; i < numItems; i++) { michael@0: michael@0: PKIX_CHECK( michael@0: PKIX_List_GetItem(requiredExtKeyUsageList, i, michael@0: (PKIX_PL_Object **)&ekuOid, plContext), michael@0: PKIX_LISTGETITEMFAILED); michael@0: michael@0: PKIX_CHECK( michael@0: pkix_List_Contains(certExtKeyUsageList, michael@0: (PKIX_PL_Object *)ekuOid, michael@0: &isContained, michael@0: plContext), michael@0: PKIX_LISTCONTAINSFAILED); michael@0: michael@0: PKIX_DECREF(ekuOid); michael@0: if (isContained != PKIX_TRUE) { michael@0: checkResult = PKIX_FALSE; michael@0: goto cleanup; michael@0: } michael@0: } michael@0: michael@0: cleanup: michael@0: if (!pkixErrorResult && checkResult == PKIX_FALSE) { michael@0: pkixErrorReceived = PKIX_TRUE; michael@0: pkixErrorCode = PKIX_EXTENDEDKEYUSAGECHECKINGFAILED; michael@0: } michael@0: michael@0: PKIX_DECREF(ekuOid); michael@0: PKIX_DECREF(certExtKeyUsageList); michael@0: PKIX_DECREF(state); michael@0: michael@0: PKIX_RETURN(EKUCHECKER); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_EkuChecker_Initialize michael@0: * (see comments in pkix_sample_modules.h) michael@0: */ michael@0: PKIX_Error * michael@0: PKIX_EkuChecker_Create( michael@0: PKIX_ProcessingParams *params, michael@0: PKIX_CertChainChecker **pEkuChecker, michael@0: void *plContext) michael@0: { michael@0: pkix_EkuChecker *state = NULL; michael@0: PKIX_List *critExtOIDsList = NULL; michael@0: michael@0: PKIX_ENTER(EKUCHECKER, "PKIX_EkuChecker_Initialize"); michael@0: PKIX_NULLCHECK_ONE(params); michael@0: michael@0: /* michael@0: * This function and functions in this file provide an example of how michael@0: * an application defined checker can be hooked into libpkix. michael@0: */ michael@0: michael@0: PKIX_CHECK(pkix_EkuChecker_Create michael@0: (params, &state, plContext), michael@0: PKIX_EKUCHECKERSTATECREATEFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_Create(&critExtOIDsList, plContext), michael@0: PKIX_LISTCREATEFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_AppendItem michael@0: (critExtOIDsList, michael@0: (PKIX_PL_Object *)state->ekuOID, michael@0: plContext), michael@0: PKIX_LISTAPPENDITEMFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_CertChainChecker_Create michael@0: (pkix_EkuChecker_Check, michael@0: PKIX_TRUE, /* forwardCheckingSupported */ michael@0: PKIX_FALSE, /* forwardDirectionExpected */ michael@0: critExtOIDsList, michael@0: (PKIX_PL_Object *) state, michael@0: pEkuChecker, michael@0: plContext), michael@0: PKIX_CERTCHAINCHECKERCREATEFAILED); michael@0: cleanup: michael@0: michael@0: PKIX_DECREF(critExtOIDsList); michael@0: PKIX_DECREF(state); michael@0: michael@0: PKIX_RETURN(EKUCHECKER); michael@0: }