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