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_validate.c michael@0: * michael@0: * Top level validateChain function michael@0: * michael@0: */ michael@0: michael@0: #include "pkix_validate.h" michael@0: #include "pkix_pl_common.h" michael@0: michael@0: /* --Private-Functions-------------------------------------------- */ michael@0: michael@0: /* michael@0: * FUNCTION: pkix_AddToVerifyLog michael@0: * DESCRIPTION: michael@0: * michael@0: * This function returns immediately if the address for the VerifyNode tree michael@0: * pointed to by "pVerifyTree" is NULL. Otherwise it creates a new VerifyNode michael@0: * from the Cert pointed to by "cert" and the Error pointed to by "error", michael@0: * and inserts it at the depth in the VerifyNode tree determined by "depth". A michael@0: * depth of zero means that this function creates the root node of a new tree. michael@0: * michael@0: * Note: this function does not include the means of choosing among branches michael@0: * of a tree. It is intended for non-branching trees, that is, where each michael@0: * parent node has only a single child node. michael@0: * michael@0: * PARAMETERS: michael@0: * "cert" michael@0: * The address of the Cert to be included in the new VerifyNode. Must be michael@0: * non-NULL. michael@0: * "depth" michael@0: * The UInt32 value of the depth. michael@0: * "error" michael@0: * The address of the Error to be included in the new VerifyNode. michael@0: * "pVerifyTree" michael@0: * The address of the VerifyNode tree into which the created VerifyNode michael@0: * is to be inserted. The node is not created if VerifyTree is 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 Validate Error if the function fails in 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_AddToVerifyLog( michael@0: PKIX_PL_Cert *cert, michael@0: PKIX_UInt32 depth, michael@0: PKIX_Error *error, michael@0: PKIX_VerifyNode **pVerifyTree, michael@0: void *plContext) michael@0: { michael@0: michael@0: PKIX_VerifyNode *verifyNode = NULL; michael@0: michael@0: PKIX_ENTER(VALIDATE, "pkix_AddToVerifyLog"); michael@0: PKIX_NULLCHECK_ONE(cert); michael@0: michael@0: if (pVerifyTree) { /* nothing to do if no address given for log */ michael@0: michael@0: PKIX_CHECK(pkix_VerifyNode_Create michael@0: (cert, depth, error, &verifyNode, plContext), michael@0: PKIX_VERIFYNODECREATEFAILED); michael@0: michael@0: if (depth == 0) { michael@0: /* We just created the root node */ michael@0: *pVerifyTree = verifyNode; michael@0: } else { michael@0: PKIX_CHECK(pkix_VerifyNode_AddToChain michael@0: (*pVerifyTree, verifyNode, plContext), michael@0: PKIX_VERIFYNODEADDTOCHAINFAILED); michael@0: } michael@0: } michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_RETURN(VALIDATE); michael@0: michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_CheckCert michael@0: * DESCRIPTION: michael@0: * michael@0: * Checks whether the Cert pointed to by "cert" successfully validates michael@0: * using the List of CertChainCheckers pointed to by "checkers". If the michael@0: * certificate does not validate, an Error pointer is returned. michael@0: * michael@0: * This function should be called initially with the UInt32 pointed to by michael@0: * "pCheckerIndex" containing zero, and the pointer at "pNBIOContext" michael@0: * containing NULL. If a checker does non-blocking I/O, this function will michael@0: * return with the index of that checker stored at "pCheckerIndex" and a michael@0: * platform-dependent non-blocking I/O context stored at "pNBIOContext". michael@0: * A subsequent call to this function with those values intact will allow the michael@0: * checking to resume where it left off. This should be repeated until the michael@0: * function returns with NULL stored at "pNBIOContext". michael@0: * michael@0: * PARAMETERS: michael@0: * "cert" michael@0: * Address of Cert to validate. Must be non-NULL. michael@0: * "checkers" michael@0: * List of CertChainCheckers which must each validate the certificate. michael@0: * Must be non-NULL. michael@0: * "checkedExtOIDs" michael@0: * List of PKIX_PL_OID that has been processed. If called from building michael@0: * chain, it is the list of critical extension OIDs that has been michael@0: * processed prior to validation. May be NULL. michael@0: * "pCheckerIndex" michael@0: * Address at which is stored the the index, within the List "checkers", michael@0: * of a checker whose processing was interrupted by non-blocking I/O. michael@0: * Must be non-NULL. michael@0: * "pNBIOContext" michael@0: * Address at which is stored platform-specific non-blocking I/O context. michael@0: * 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 Validate Error if the function fails in 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_CheckCert( michael@0: PKIX_PL_Cert *cert, michael@0: PKIX_List *checkers, michael@0: PKIX_List *checkedExtOIDsList, michael@0: PKIX_UInt32 *pCheckerIndex, michael@0: void **pNBIOContext, michael@0: void *plContext) michael@0: { michael@0: PKIX_CertChainChecker_CheckCallback checkerCheck = NULL; michael@0: PKIX_CertChainChecker *checker = NULL; michael@0: PKIX_List *unresCritExtOIDs = NULL; michael@0: PKIX_UInt32 numCheckers; michael@0: PKIX_UInt32 numUnresCritExtOIDs = 0; michael@0: PKIX_UInt32 checkerIndex = 0; michael@0: void *nbioContext = NULL; michael@0: michael@0: PKIX_ENTER(VALIDATE, "pkix_CheckCert"); michael@0: PKIX_NULLCHECK_FOUR(cert, checkers, pCheckerIndex, pNBIOContext); michael@0: michael@0: nbioContext = *pNBIOContext; michael@0: *pNBIOContext = NULL; /* prepare for case of error exit */ michael@0: michael@0: PKIX_CHECK(PKIX_PL_Cert_GetCriticalExtensionOIDs michael@0: (cert, &unresCritExtOIDs, plContext), michael@0: PKIX_CERTGETCRITICALEXTENSIONOIDSFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_GetLength(checkers, &numCheckers, plContext), michael@0: PKIX_LISTGETLENGTHFAILED); michael@0: michael@0: for (checkerIndex = *pCheckerIndex; michael@0: checkerIndex < numCheckers; michael@0: checkerIndex++) { michael@0: michael@0: PKIX_CHECK(PKIX_List_GetItem michael@0: (checkers, michael@0: checkerIndex, michael@0: (PKIX_PL_Object **)&checker, michael@0: plContext), michael@0: PKIX_LISTGETITEMFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_CertChainChecker_GetCheckCallback michael@0: (checker, &checkerCheck, plContext), michael@0: PKIX_CERTCHAINCHECKERGETCHECKCALLBACKFAILED); michael@0: michael@0: PKIX_CHECK(checkerCheck(checker, cert, unresCritExtOIDs, michael@0: &nbioContext, plContext), michael@0: PKIX_CERTCHAINCHECKERCHECKFAILED); michael@0: michael@0: if (nbioContext != NULL) { michael@0: *pCheckerIndex = checkerIndex; michael@0: *pNBIOContext = nbioContext; michael@0: goto cleanup; michael@0: } michael@0: michael@0: PKIX_DECREF(checker); michael@0: } michael@0: michael@0: if (unresCritExtOIDs){ michael@0: michael@0: #ifdef PKIX_VALIDATEDEBUG michael@0: { michael@0: PKIX_PL_String *oidString = NULL; michael@0: PKIX_UInt32 length; michael@0: char *oidAscii = NULL; michael@0: PKIX_TOSTRING(unresCritExtOIDs, &oidString, plContext, michael@0: PKIX_LISTTOSTRINGFAILED); michael@0: PKIX_CHECK(PKIX_PL_String_GetEncoded michael@0: (oidString, michael@0: PKIX_ESCASCII, michael@0: (void **) &oidAscii, michael@0: &length, michael@0: plContext), michael@0: PKIX_STRINGGETENCODEDFAILED); michael@0: PKIX_VALIDATE_DEBUG_ARG michael@0: ("unrecognized critical extension OIDs:" michael@0: " %s\n", oidAscii); michael@0: PKIX_DECREF(oidString); michael@0: PKIX_PL_Free(oidAscii, plContext); michael@0: } michael@0: #endif michael@0: michael@0: if (checkedExtOIDsList != NULL) { michael@0: /* Take out OID's that had been processed, if any */ michael@0: PKIX_CHECK(pkix_List_RemoveItems michael@0: (unresCritExtOIDs, michael@0: checkedExtOIDsList, michael@0: plContext), michael@0: PKIX_LISTREMOVEITEMSFAILED); michael@0: } michael@0: michael@0: PKIX_CHECK(PKIX_List_GetLength michael@0: (unresCritExtOIDs, &numUnresCritExtOIDs, plContext), michael@0: PKIX_LISTGETLENGTHFAILED); michael@0: michael@0: if (numUnresCritExtOIDs != 0){ michael@0: PKIX_ERROR(PKIX_UNRECOGNIZEDCRITICALEXTENSION); michael@0: } michael@0: michael@0: } michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_DECREF(checker); michael@0: PKIX_DECREF(unresCritExtOIDs); michael@0: michael@0: PKIX_RETURN(VALIDATE); michael@0: michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_InitializeCheckers michael@0: * DESCRIPTION: michael@0: * michael@0: * Creates several checkers and initializes them with values derived from the michael@0: * TrustAnchor pointed to by "anchor", the ProcessingParams pointed to by michael@0: * "procParams", and the number of Certs in the Chain, represented by michael@0: * "numCerts". The List of checkers is stored at "pCheckers". michael@0: * michael@0: * PARAMETERS: michael@0: * "anchor" michael@0: * Address of TrustAnchor used to initialize the SignatureChecker and michael@0: * NameChainingChecker. Must be non-NULL. michael@0: * "procParams" michael@0: * Address of ProcessingParams used to initialize the ExpirationChecker michael@0: * and TargetCertChecker. Must be non-NULL. michael@0: * "numCerts" michael@0: * Number of certificates in the CertChain. michael@0: * "pCheckers" michael@0: * Address where object 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 Validate Error if the function fails in 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_InitializeCheckers( michael@0: PKIX_TrustAnchor *anchor, michael@0: PKIX_ProcessingParams *procParams, michael@0: PKIX_UInt32 numCerts, michael@0: PKIX_List **pCheckers, michael@0: void *plContext) michael@0: { michael@0: PKIX_CertChainChecker *targetCertChecker = NULL; michael@0: PKIX_CertChainChecker *expirationChecker = NULL; michael@0: PKIX_CertChainChecker *nameChainingChecker = NULL; michael@0: PKIX_CertChainChecker *nameConstraintsChecker = NULL; michael@0: PKIX_CertChainChecker *basicConstraintsChecker = NULL; michael@0: PKIX_CertChainChecker *policyChecker = NULL; michael@0: PKIX_CertChainChecker *sigChecker = NULL; michael@0: PKIX_CertChainChecker *defaultCrlChecker = NULL; michael@0: PKIX_CertChainChecker *userChecker = NULL; michael@0: PKIX_PL_X500Name *trustedCAName = NULL; michael@0: PKIX_PL_PublicKey *trustedPubKey = NULL; michael@0: PKIX_List *checkers = NULL; michael@0: PKIX_PL_Date *testDate = NULL; michael@0: PKIX_CertSelector *certSelector = NULL; michael@0: PKIX_PL_Cert *trustedCert = NULL; michael@0: PKIX_PL_CertNameConstraints *trustedNC = NULL; michael@0: PKIX_List *initialPolicies = NULL; michael@0: PKIX_Boolean policyQualifiersRejected = PKIX_FALSE; michael@0: PKIX_Boolean initialPolicyMappingInhibit = PKIX_FALSE; michael@0: PKIX_Boolean initialAnyPolicyInhibit = PKIX_FALSE; michael@0: PKIX_Boolean initialExplicitPolicy = PKIX_FALSE; michael@0: PKIX_List *userCheckersList = NULL; michael@0: PKIX_List *certStores = NULL; michael@0: PKIX_UInt32 numCertCheckers = 0; michael@0: PKIX_UInt32 i; michael@0: michael@0: PKIX_ENTER(VALIDATE, "pkix_InitializeCheckers"); michael@0: PKIX_NULLCHECK_THREE(anchor, procParams, pCheckers); michael@0: PKIX_CHECK(PKIX_List_Create(&checkers, plContext), michael@0: PKIX_LISTCREATEFAILED); michael@0: michael@0: /* michael@0: * The TrustAnchor may have been created using CreateWithCert michael@0: * (in which case GetCAPublicKey and GetCAName will return NULL) michael@0: * or may have been created using CreateWithNameKeyPair (in which michael@0: * case GetTrustedCert will return NULL. So we call GetTrustedCert michael@0: * and populate trustedPubKey and trustedCAName accordingly. michael@0: */ michael@0: michael@0: PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert michael@0: (anchor, &trustedCert, plContext), michael@0: PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED); michael@0: michael@0: if (trustedCert){ michael@0: PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey michael@0: (trustedCert, &trustedPubKey, plContext), michael@0: PKIX_CERTGETSUBJECTPUBLICKEYFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_PL_Cert_GetSubject michael@0: (trustedCert, &trustedCAName, plContext), michael@0: PKIX_CERTGETSUBJECTFAILED); michael@0: } else { michael@0: PKIX_CHECK(PKIX_TrustAnchor_GetCAPublicKey michael@0: (anchor, &trustedPubKey, plContext), michael@0: PKIX_TRUSTANCHORGETCAPUBLICKEYFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_TrustAnchor_GetCAName michael@0: (anchor, &trustedCAName, plContext), michael@0: PKIX_TRUSTANCHORGETCANAMEFAILED); michael@0: } michael@0: michael@0: PKIX_NULLCHECK_TWO(trustedPubKey, trustedCAName); michael@0: michael@0: PKIX_CHECK(PKIX_TrustAnchor_GetNameConstraints michael@0: (anchor, &trustedNC, plContext), michael@0: PKIX_TRUSTANCHORGETNAMECONSTRAINTSFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints michael@0: (procParams, &certSelector, plContext), michael@0: PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_GetDate michael@0: (procParams, &testDate, plContext), michael@0: PKIX_PROCESSINGPARAMSGETDATEFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_GetInitialPolicies michael@0: (procParams, &initialPolicies, plContext), michael@0: PKIX_PROCESSINGPARAMSGETINITIALPOLICIESFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_GetPolicyQualifiersRejected michael@0: (procParams, &policyQualifiersRejected, plContext), michael@0: PKIX_PROCESSINGPARAMSGETPOLICYQUALIFIERSREJECTEDFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_IsPolicyMappingInhibited michael@0: (procParams, &initialPolicyMappingInhibit, plContext), michael@0: PKIX_PROCESSINGPARAMSISPOLICYMAPPINGINHIBITEDFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_IsAnyPolicyInhibited michael@0: (procParams, &initialAnyPolicyInhibit, plContext), michael@0: PKIX_PROCESSINGPARAMSISANYPOLICYINHIBITEDFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_IsExplicitPolicyRequired michael@0: (procParams, &initialExplicitPolicy, plContext), michael@0: PKIX_PROCESSINGPARAMSISEXPLICITPOLICYREQUIREDFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_GetCertStores michael@0: (procParams, &certStores, plContext), michael@0: PKIX_PROCESSINGPARAMSGETCERTSTORESFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_GetCertChainCheckers michael@0: (procParams, &userCheckersList, plContext), michael@0: PKIX_PROCESSINGPARAMSGETCERTCHAINCHECKERSFAILED); michael@0: michael@0: /* now, initialize all the checkers */ michael@0: PKIX_CHECK(pkix_TargetCertChecker_Initialize michael@0: (certSelector, numCerts, &targetCertChecker, plContext), michael@0: PKIX_TARGETCERTCHECKERINITIALIZEFAILED); michael@0: michael@0: PKIX_CHECK(pkix_ExpirationChecker_Initialize michael@0: (testDate, &expirationChecker, plContext), michael@0: PKIX_EXPIRATIONCHECKERINITIALIZEFAILED); michael@0: michael@0: PKIX_CHECK(pkix_NameChainingChecker_Initialize michael@0: (trustedCAName, &nameChainingChecker, plContext), michael@0: PKIX_NAMECHAININGCHECKERINITIALIZEFAILED); michael@0: michael@0: PKIX_CHECK(pkix_NameConstraintsChecker_Initialize michael@0: (trustedNC, numCerts, &nameConstraintsChecker, plContext), michael@0: PKIX_NAMECONSTRAINTSCHECKERINITIALIZEFAILED); michael@0: michael@0: PKIX_CHECK(pkix_BasicConstraintsChecker_Initialize michael@0: (numCerts, &basicConstraintsChecker, plContext), michael@0: PKIX_BASICCONSTRAINTSCHECKERINITIALIZEFAILED); michael@0: michael@0: PKIX_CHECK(pkix_PolicyChecker_Initialize michael@0: (initialPolicies, michael@0: policyQualifiersRejected, michael@0: initialPolicyMappingInhibit, michael@0: initialExplicitPolicy, michael@0: initialAnyPolicyInhibit, michael@0: numCerts, michael@0: &policyChecker, michael@0: plContext), michael@0: PKIX_POLICYCHECKERINITIALIZEFAILED); michael@0: michael@0: PKIX_CHECK(pkix_SignatureChecker_Initialize michael@0: (trustedPubKey, numCerts, &sigChecker, plContext), michael@0: PKIX_SIGNATURECHECKERINITIALIZEFAILED); michael@0: michael@0: if (userCheckersList != NULL) { michael@0: michael@0: PKIX_CHECK(PKIX_List_GetLength michael@0: (userCheckersList, &numCertCheckers, plContext), michael@0: PKIX_LISTGETLENGTHFAILED); michael@0: michael@0: for (i = 0; i < numCertCheckers; i++) { michael@0: michael@0: PKIX_CHECK(PKIX_List_GetItem michael@0: (userCheckersList, michael@0: i, michael@0: (PKIX_PL_Object **) &userChecker, michael@0: plContext), michael@0: PKIX_LISTGETITEMFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_AppendItem michael@0: (checkers, michael@0: (PKIX_PL_Object *)userChecker, michael@0: plContext), michael@0: PKIX_LISTAPPENDITEMFAILED); michael@0: michael@0: PKIX_DECREF(userChecker); michael@0: } michael@0: } michael@0: michael@0: PKIX_CHECK(PKIX_List_AppendItem michael@0: (checkers, (PKIX_PL_Object *)targetCertChecker, plContext), michael@0: PKIX_LISTAPPENDITEMFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_AppendItem michael@0: (checkers, (PKIX_PL_Object *)expirationChecker, plContext), michael@0: PKIX_LISTAPPENDITEMFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_AppendItem michael@0: (checkers, (PKIX_PL_Object *)nameChainingChecker, plContext), michael@0: PKIX_LISTAPPENDITEMFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_AppendItem michael@0: (checkers, (PKIX_PL_Object *)nameConstraintsChecker, plContext), michael@0: PKIX_LISTAPPENDITEMFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_AppendItem michael@0: (checkers, (PKIX_PL_Object *)basicConstraintsChecker, plContext), michael@0: PKIX_LISTAPPENDITEMFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_AppendItem michael@0: (checkers, (PKIX_PL_Object *)policyChecker, plContext), michael@0: PKIX_LISTAPPENDITEMFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_AppendItem michael@0: (checkers, (PKIX_PL_Object *)sigChecker, plContext), michael@0: PKIX_LISTAPPENDITEMFAILED); michael@0: michael@0: *pCheckers = checkers; michael@0: michael@0: cleanup: michael@0: michael@0: if (PKIX_ERROR_RECEIVED){ michael@0: PKIX_DECREF(checkers); michael@0: } michael@0: michael@0: PKIX_DECREF(certSelector); michael@0: PKIX_DECREF(testDate); michael@0: PKIX_DECREF(initialPolicies); michael@0: PKIX_DECREF(targetCertChecker); michael@0: PKIX_DECREF(expirationChecker); michael@0: PKIX_DECREF(nameChainingChecker); michael@0: PKIX_DECREF(nameConstraintsChecker); michael@0: PKIX_DECREF(basicConstraintsChecker); michael@0: PKIX_DECREF(policyChecker); michael@0: PKIX_DECREF(sigChecker); michael@0: PKIX_DECREF(trustedCAName); michael@0: PKIX_DECREF(trustedPubKey); michael@0: PKIX_DECREF(trustedNC); michael@0: PKIX_DECREF(trustedCert); michael@0: PKIX_DECREF(defaultCrlChecker); michael@0: PKIX_DECREF(userCheckersList); michael@0: PKIX_DECREF(certStores); michael@0: PKIX_DECREF(userChecker); michael@0: michael@0: PKIX_RETURN(VALIDATE); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_RetrieveOutputs michael@0: * DESCRIPTION: michael@0: * michael@0: * This function queries the respective states of the List of checkers in michael@0: * "checkers" to to obtain the final public key from the SignatureChecker michael@0: * and the policy tree from the PolicyChecker, storing those values at michael@0: * "pFinalSubjPubKey" and "pPolicyTree", respectively. michael@0: * michael@0: * PARAMETERS: michael@0: * "checkers" michael@0: * Address of List of checkers to be queried. Must be non-NULL. michael@0: * "pFinalSubjPubKey" michael@0: * Address where final public key will be stored. Must be non-NULL. michael@0: * "pPolicyTree" michael@0: * Address where policy tree 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 Validate Error if the function fails in 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_RetrieveOutputs( michael@0: PKIX_List *checkers, michael@0: PKIX_PL_PublicKey **pFinalSubjPubKey, michael@0: PKIX_PolicyNode **pPolicyTree, michael@0: void *plContext) michael@0: { michael@0: PKIX_PL_PublicKey *finalSubjPubKey = NULL; michael@0: PKIX_PolicyNode *validPolicyTree = NULL; michael@0: PKIX_CertChainChecker *checker = NULL; michael@0: PKIX_PL_Object *state = NULL; michael@0: PKIX_UInt32 numCheckers = 0; michael@0: PKIX_UInt32 type; michael@0: PKIX_Int32 j; michael@0: michael@0: PKIX_ENTER(VALIDATE, "pkix_RetrieveOutputs"); michael@0: michael@0: PKIX_NULLCHECK_TWO(checkers, pPolicyTree); michael@0: michael@0: /* michael@0: * To optimize the search, we guess that the sigChecker is michael@0: * last in the tree and is preceded by the policyChecker. We michael@0: * search toward the front of the chain. Remember that List michael@0: * items are indexed 0..(numItems - 1). michael@0: */ michael@0: michael@0: PKIX_CHECK(PKIX_List_GetLength(checkers, &numCheckers, plContext), michael@0: PKIX_LISTGETLENGTHFAILED); michael@0: michael@0: for (j = numCheckers - 1; j >= 0; j--){ michael@0: PKIX_CHECK(PKIX_List_GetItem michael@0: (checkers, j, (PKIX_PL_Object **)&checker, plContext), michael@0: PKIX_LISTGETITEMFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState michael@0: (checker, &state, plContext), michael@0: PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED); michael@0: michael@0: /* user defined checker may have no state */ michael@0: if (state != NULL) { michael@0: michael@0: PKIX_CHECK(PKIX_PL_Object_GetType(state, &type, plContext), michael@0: PKIX_OBJECTGETTYPEFAILED); michael@0: michael@0: if (type == PKIX_SIGNATURECHECKERSTATE_TYPE){ michael@0: /* final pubKey will include any inherited DSA params */ michael@0: finalSubjPubKey = michael@0: ((pkix_SignatureCheckerState *)state)-> michael@0: prevPublicKey; michael@0: PKIX_INCREF(finalSubjPubKey); michael@0: *pFinalSubjPubKey = finalSubjPubKey; michael@0: } michael@0: michael@0: if (type == PKIX_CERTPOLICYCHECKERSTATE_TYPE) { michael@0: validPolicyTree = michael@0: ((PKIX_PolicyCheckerState *)state)->validPolicyTree; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: PKIX_DECREF(checker); michael@0: PKIX_DECREF(state); michael@0: } michael@0: michael@0: PKIX_INCREF(validPolicyTree); michael@0: *pPolicyTree = validPolicyTree; michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_DECREF(checker); michael@0: PKIX_DECREF(state); michael@0: michael@0: PKIX_RETURN(VALIDATE); michael@0: michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_CheckChain michael@0: * DESCRIPTION: michael@0: * michael@0: * Checks whether the List of Certs pointed to by "certs", containing michael@0: * "numCerts" entries, successfully validates using each CertChainChecker in michael@0: * the List pointed to by "checkers" and has not been revoked, according to any michael@0: * of the Revocation Checkers in the List pointed to by "revChecker". Checkers michael@0: * are expected to remove from "removeCheckedExtOIDs" and extensions that they michael@0: * process. Indices to the certChain and the checkerChain are obtained and michael@0: * returned in "pCertCheckedIndex" and "pCheckerIndex", respectively. These michael@0: * should be set to zero prior to the initial call, but may be changed (and michael@0: * must be supplied on subsequent calls) if processing is suspended for non- michael@0: * blocking I/O. Each time a Cert passes from being validated by one of the michael@0: * CertChainCheckers to being checked by a Revocation Checker, the Boolean michael@0: * stored at "pRevChecking" is changed from FALSE to TRUE. If the Cert is michael@0: * rejected by a Revocation Checker, its reason code is returned at michael@0: * "pReasonCode. If the List of Certs successfully validates, the public key i michael@0: * the final certificate is obtained and stored at "pFinalSubjPubKey" and the michael@0: * validPolicyTree, which could be NULL, is stored at pPolicyTree. If the List michael@0: * of Certs fails to validate, an Error pointer is returned. michael@0: * michael@0: * If "pVerifyTree" is non-NULL, a chain of VerifyNodes is created which michael@0: * tracks the results of the validation. That is, either each node in the michael@0: * chain has a NULL Error component, or the last node contains an Error michael@0: * which indicates why the validation failed. michael@0: * michael@0: * The number of Certs in the List, represented by "numCerts", is used to michael@0: * determine which Cert is the final Cert. michael@0: * michael@0: * PARAMETERS: michael@0: * "certs" michael@0: * Address of List of Certs to validate. Must be non-NULL. michael@0: * "numCerts" michael@0: * Number of certificates in the List of certificates. michael@0: * "checkers" michael@0: * List of CertChainCheckers which must each validate the List of michael@0: * certificates. Must be non-NULL. michael@0: * "revChecker" michael@0: * List of RevocationCheckers which must each not reject the List of michael@0: * certificates. May be empty, but must be non-NULL. michael@0: * "removeCheckedExtOIDs" michael@0: * List of PKIX_PL_OID that has been processed. If called from building michael@0: * chain, it is the list of critical extension OIDs that has been michael@0: * processed prior to validation. Extension OIDs that may be processed by michael@0: * user defined checker processes are also in the list. May be NULL. michael@0: * "procParams" michael@0: * Address of ProcessingParams used to initialize various checkers. Must michael@0: * be non-NULL. michael@0: * "pCertCheckedIndex" michael@0: * Address where Int32 index to the Cert chain is obtained and michael@0: * returned. Must be non-NULL. michael@0: * "pCheckerIndex" michael@0: * Address where Int32 index to the CheckerChain is obtained and michael@0: * returned. Must be non-NULL. michael@0: * "pRevChecking" michael@0: * Address where Boolean is obtained and returned, indicating, if FALSE, michael@0: * that CertChainCheckers are being called; or, if TRUE, that RevChecker michael@0: * are being called. Must be non-NULL. michael@0: * "pReasonCode" michael@0: * Address where UInt32 results of revocation checking are stored. Must be michael@0: * non-NULL. michael@0: * "pNBIOContext" michael@0: * Address where platform-dependent context is stored if checking is michael@0: * suspended for non-blocking I/O. Must be non-NULL. michael@0: * "pFinalSubjPubKey" michael@0: * Address where the final public key will be stored. Must be non-NULL. michael@0: * "pPolicyTree" michael@0: * Address where the final validPolicyTree is stored. Must be non-NULL. michael@0: * "pVerifyTree" michael@0: * Address where a VerifyTree is stored, if 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 Validate Error if the function fails in a non-fatal way. michael@0: * Returns a Fatal Error if the function fails in an unrecoverable way. michael@0: */ michael@0: PKIX_Error * michael@0: pkix_CheckChain( michael@0: PKIX_List *certs, michael@0: PKIX_UInt32 numCerts, michael@0: PKIX_TrustAnchor *anchor, michael@0: PKIX_List *checkers, michael@0: PKIX_RevocationChecker *revChecker, michael@0: PKIX_List *removeCheckedExtOIDs, michael@0: PKIX_ProcessingParams *procParams, michael@0: PKIX_UInt32 *pCertCheckedIndex, michael@0: PKIX_UInt32 *pCheckerIndex, michael@0: PKIX_Boolean *pRevChecking, michael@0: PKIX_UInt32 *pReasonCode, michael@0: void **pNBIOContext, michael@0: PKIX_PL_PublicKey **pFinalSubjPubKey, michael@0: PKIX_PolicyNode **pPolicyTree, michael@0: PKIX_VerifyNode **pVerifyTree, michael@0: void *plContext) michael@0: { michael@0: PKIX_UInt32 j = 0; michael@0: PKIX_Boolean revChecking = PKIX_FALSE; michael@0: PKIX_Error *checkCertError = NULL; michael@0: void *nbioContext = NULL; michael@0: PKIX_PL_Cert *cert = NULL; michael@0: PKIX_PL_Cert *issuer = NULL; michael@0: PKIX_PL_NssContext *nssContext = NULL; michael@0: CERTCertList *certList = NULL; michael@0: const CERTChainVerifyCallback *chainVerifyCallback = NULL; michael@0: CERTCertificate *nssCert = NULL; michael@0: michael@0: PKIX_ENTER(VALIDATE, "pkix_CheckChain"); michael@0: PKIX_NULLCHECK_FOUR(certs, checkers, revChecker, pCertCheckedIndex); michael@0: PKIX_NULLCHECK_FOUR(pCheckerIndex, pRevChecking, pReasonCode, anchor); michael@0: PKIX_NULLCHECK_THREE(pNBIOContext, pFinalSubjPubKey, pPolicyTree); michael@0: michael@0: nbioContext = *pNBIOContext; michael@0: *pNBIOContext = NULL; michael@0: revChecking = *pRevChecking; michael@0: nssContext = (PKIX_PL_NssContext *)plContext; michael@0: chainVerifyCallback = &nssContext->chainVerifyCallback; michael@0: michael@0: if (chainVerifyCallback->isChainValid != NULL) { michael@0: PRBool chainOK = PR_FALSE; /*assume failure*/ michael@0: SECStatus rv; michael@0: michael@0: certList = CERT_NewCertList(); michael@0: if (certList == NULL) { michael@0: PKIX_ERROR_ALLOC_ERROR(); michael@0: } michael@0: michael@0: /* Add the trust anchor to the list */ michael@0: PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert michael@0: (anchor, &cert, plContext), michael@0: PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED); michael@0: michael@0: PKIX_CHECK( michael@0: PKIX_PL_Cert_GetCERTCertificate(cert, &nssCert, plContext), michael@0: PKIX_CERTGETCERTCERTIFICATEFAILED); michael@0: michael@0: rv = CERT_AddCertToListHead(certList, nssCert); michael@0: if (rv != SECSuccess) { michael@0: PKIX_ERROR_ALLOC_ERROR(); michael@0: } michael@0: /* the certList takes ownership of nssCert on success */ michael@0: nssCert = NULL; michael@0: PKIX_DECREF(cert); michael@0: michael@0: /* Add the rest of the chain to the list */ michael@0: for (j = *pCertCheckedIndex; j < numCerts; j++) { michael@0: PKIX_CHECK(PKIX_List_GetItem( michael@0: certs, j, (PKIX_PL_Object **)&cert, plContext), michael@0: PKIX_LISTGETITEMFAILED); michael@0: michael@0: PKIX_CHECK( michael@0: PKIX_PL_Cert_GetCERTCertificate(cert, &nssCert, plContext), michael@0: PKIX_CERTGETCERTCERTIFICATEFAILED); michael@0: michael@0: rv = CERT_AddCertToListHead(certList, nssCert); michael@0: if (rv != SECSuccess) { michael@0: PKIX_ERROR_ALLOC_ERROR(); michael@0: } michael@0: /* the certList takes ownership of nssCert on success */ michael@0: nssCert = NULL; michael@0: PKIX_DECREF(cert); michael@0: } michael@0: michael@0: rv = (*chainVerifyCallback->isChainValid) michael@0: (chainVerifyCallback->isChainValidArg, certList, &chainOK); michael@0: if (rv != SECSuccess) { michael@0: PKIX_ERROR_FATAL(PKIX_CHAINVERIFYCALLBACKFAILED); michael@0: } michael@0: michael@0: if (!chainOK) { michael@0: PKIX_ERROR(PKIX_CHAINVERIFYCALLBACKFAILED); michael@0: } michael@0: michael@0: } michael@0: michael@0: PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert michael@0: (anchor, &cert, plContext), michael@0: PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED); michael@0: michael@0: for (j = *pCertCheckedIndex; j < numCerts; j++) { michael@0: michael@0: PORT_Assert(cert); michael@0: PKIX_DECREF(issuer); michael@0: issuer = cert; michael@0: cert = NULL; michael@0: michael@0: PKIX_CHECK(PKIX_List_GetItem( michael@0: certs, j, (PKIX_PL_Object **)&cert, plContext), michael@0: PKIX_LISTGETITEMFAILED); michael@0: michael@0: /* check if cert pointer is valid */ michael@0: PORT_Assert(cert); michael@0: if (cert == NULL) { michael@0: continue; michael@0: } michael@0: michael@0: if (revChecking == PKIX_FALSE) { michael@0: michael@0: PKIX_CHECK(pkix_CheckCert michael@0: (cert, michael@0: checkers, michael@0: removeCheckedExtOIDs, michael@0: pCheckerIndex, michael@0: &nbioContext, michael@0: plContext), michael@0: PKIX_CHECKCERTFAILED); michael@0: michael@0: if (nbioContext != NULL) { michael@0: *pCertCheckedIndex = j; michael@0: *pRevChecking = revChecking; michael@0: *pNBIOContext = nbioContext; michael@0: goto cleanup; michael@0: } michael@0: michael@0: revChecking = PKIX_TRUE; michael@0: *pCheckerIndex = 0; michael@0: } michael@0: michael@0: if (revChecking == PKIX_TRUE) { michael@0: PKIX_RevocationStatus revStatus; michael@0: pkixErrorResult = michael@0: PKIX_RevocationChecker_Check( michael@0: cert, issuer, revChecker, michael@0: procParams, PKIX_TRUE, michael@0: (j == numCerts - 1) ? PKIX_TRUE : PKIX_FALSE, michael@0: &revStatus, pReasonCode, michael@0: &nbioContext, plContext); michael@0: if (nbioContext != NULL) { michael@0: *pCertCheckedIndex = j; michael@0: *pRevChecking = revChecking; michael@0: *pNBIOContext = nbioContext; michael@0: goto cleanup; michael@0: } michael@0: if (revStatus == PKIX_RevStatus_Revoked || michael@0: pkixErrorResult) { michael@0: if (!pkixErrorResult) { michael@0: /* if pkixErrorResult is returned then michael@0: * use it as it has a detailed revocation michael@0: * error code. Otherwise create a new error */ michael@0: PKIX_ERROR_CREATE(VALIDATE, michael@0: PKIX_CERTIFICATEREVOKED, michael@0: pkixErrorResult); michael@0: } michael@0: goto cleanup; michael@0: } michael@0: revChecking = PKIX_FALSE; michael@0: *pCheckerIndex = 0; michael@0: } michael@0: michael@0: PKIX_CHECK(pkix_AddToVerifyLog michael@0: (cert, j, NULL, pVerifyTree, plContext), michael@0: PKIX_ADDTOVERIFYLOGFAILED); michael@0: } michael@0: michael@0: PKIX_CHECK(pkix_RetrieveOutputs michael@0: (checkers, pFinalSubjPubKey, pPolicyTree, plContext), michael@0: PKIX_RETRIEVEOUTPUTSFAILED); michael@0: michael@0: *pNBIOContext = NULL; michael@0: michael@0: cleanup: michael@0: if (PKIX_ERROR_RECEIVED && cert) { michael@0: checkCertError = pkixErrorResult; michael@0: michael@0: PKIX_CHECK_FATAL( michael@0: pkix_AddToVerifyLog(cert, j, checkCertError, pVerifyTree, michael@0: plContext), michael@0: PKIX_ADDTOVERIFYLOGFAILED); michael@0: pkixErrorResult = checkCertError; michael@0: pkixErrorCode = pkixErrorResult->errCode; michael@0: checkCertError = NULL; michael@0: } michael@0: michael@0: fatal: michael@0: if (nssCert) { michael@0: CERT_DestroyCertificate(nssCert); michael@0: } michael@0: michael@0: if (certList) { michael@0: CERT_DestroyCertList(certList); michael@0: } michael@0: michael@0: PKIX_DECREF(checkCertError); michael@0: PKIX_DECREF(cert); michael@0: PKIX_DECREF(issuer); michael@0: michael@0: PKIX_RETURN(VALIDATE); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_ExtractParameters michael@0: * DESCRIPTION: michael@0: * michael@0: * Extracts several parameters from the ValidateParams object pointed to by michael@0: * "valParams" and stores the CertChain at "pChain", the List of Certs at michael@0: * "pCerts", the number of Certs in the chain at "pNumCerts", the michael@0: * ProcessingParams object at "pProcParams", the List of TrustAnchors at michael@0: * "pAnchors", and the number of TrustAnchors at "pNumAnchors". michael@0: * michael@0: * PARAMETERS: michael@0: * "valParams" michael@0: * Address of ValidateParams from which the parameters are extracted. michael@0: * Must be non-NULL. michael@0: * "pCerts" michael@0: * Address where object pointer for List of Certs will be stored. michael@0: * Must be non-NULL. michael@0: * "pNumCerts" michael@0: * Address where number of Certs will be stored. Must be non-NULL. michael@0: * "pProcParams" michael@0: * Address where object pointer for ProcessingParams will be stored. michael@0: * Must be non-NULL. michael@0: * "pAnchors" michael@0: * Address where object pointer for List of Anchors will be stored. michael@0: * Must be non-NULL. michael@0: * "pNumAnchors" michael@0: * Address where number of Anchors 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 Validate Error if the function fails in 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_ExtractParameters( michael@0: PKIX_ValidateParams *valParams, michael@0: PKIX_List **pCerts, michael@0: PKIX_UInt32 *pNumCerts, michael@0: PKIX_ProcessingParams **pProcParams, michael@0: PKIX_List **pAnchors, michael@0: PKIX_UInt32 *pNumAnchors, michael@0: void *plContext) michael@0: { michael@0: PKIX_ENTER(VALIDATE, "pkix_ExtractParameters"); michael@0: PKIX_NULLCHECK_THREE(valParams, pCerts, pNumCerts); michael@0: PKIX_NULLCHECK_THREE(pProcParams, pAnchors, pNumAnchors); michael@0: michael@0: /* extract relevant parameters from chain */ michael@0: PKIX_CHECK(PKIX_ValidateParams_GetCertChain michael@0: (valParams, pCerts, plContext), michael@0: PKIX_VALIDATEPARAMSGETCERTCHAINFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_GetLength(*pCerts, pNumCerts, plContext), michael@0: PKIX_LISTGETLENGTHFAILED); michael@0: michael@0: /* extract relevant parameters from procParams */ michael@0: PKIX_CHECK(PKIX_ValidateParams_GetProcessingParams michael@0: (valParams, pProcParams, plContext), michael@0: PKIX_VALIDATEPARAMSGETPROCESSINGPARAMSFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_GetTrustAnchors michael@0: (*pProcParams, pAnchors, plContext), michael@0: PKIX_PROCESSINGPARAMSGETTRUSTANCHORSFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_GetLength(*pAnchors, pNumAnchors, plContext), michael@0: PKIX_LISTGETLENGTHFAILED); michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_RETURN(VALIDATE); michael@0: } michael@0: michael@0: /* --Public-Functions--------------------------------------------- */ michael@0: michael@0: /* michael@0: * FUNCTION: PKIX_ValidateChain (see comments in pkix.h) michael@0: */ michael@0: PKIX_Error * michael@0: PKIX_ValidateChain( michael@0: PKIX_ValidateParams *valParams, michael@0: PKIX_ValidateResult **pResult, michael@0: PKIX_VerifyNode **pVerifyTree, michael@0: void *plContext) michael@0: { michael@0: PKIX_Error *chainFailed = NULL; michael@0: michael@0: PKIX_ProcessingParams *procParams = NULL; michael@0: PKIX_CertChainChecker *userChecker = NULL; michael@0: PKIX_RevocationChecker *revChecker = NULL; michael@0: PKIX_List *certs = NULL; michael@0: PKIX_List *checkers = NULL; michael@0: PKIX_List *anchors = NULL; michael@0: PKIX_List *userCheckers = NULL; michael@0: PKIX_List *userCheckerExtOIDs = NULL; michael@0: PKIX_List *validateCheckedCritExtOIDsList = NULL; michael@0: PKIX_TrustAnchor *anchor = NULL; michael@0: PKIX_ValidateResult *valResult = NULL; michael@0: PKIX_PL_PublicKey *finalPubKey = NULL; michael@0: PKIX_PolicyNode *validPolicyTree = NULL; michael@0: PKIX_Boolean supportForwarding = PKIX_FALSE; michael@0: PKIX_Boolean revChecking = PKIX_FALSE; michael@0: PKIX_UInt32 i, numCerts, numAnchors; michael@0: PKIX_UInt32 numUserCheckers = 0; michael@0: PKIX_UInt32 certCheckedIndex = 0; michael@0: PKIX_UInt32 checkerIndex = 0; michael@0: PKIX_UInt32 reasonCode = 0; michael@0: void *nbioContext = NULL; michael@0: michael@0: PKIX_ENTER(VALIDATE, "PKIX_ValidateChain"); michael@0: PKIX_NULLCHECK_TWO(valParams, pResult); michael@0: michael@0: /* extract various parameters from valParams */ michael@0: PKIX_CHECK(pkix_ExtractParameters michael@0: (valParams, michael@0: &certs, michael@0: &numCerts, michael@0: &procParams, michael@0: &anchors, michael@0: &numAnchors, michael@0: plContext), michael@0: PKIX_EXTRACTPARAMETERSFAILED); michael@0: michael@0: /* michael@0: * setup an extension OID list that user had defined for his checker michael@0: * processing. User checker is not responsible for taking out OIDs michael@0: * from unresolved critical extension list as the libpkix checker michael@0: * is doing. Here we add those user checkers' OIDs to the removal michael@0: * list to be taken out by CheckChain michael@0: */ michael@0: PKIX_CHECK(PKIX_ProcessingParams_GetCertChainCheckers michael@0: (procParams, &userCheckers, plContext), michael@0: PKIX_PROCESSINGPARAMSGETCERTCHAINCHECKERSFAILED); michael@0: michael@0: if (userCheckers != NULL) { michael@0: michael@0: PKIX_CHECK(PKIX_List_Create michael@0: (&validateCheckedCritExtOIDsList, michael@0: plContext), michael@0: PKIX_LISTCREATEFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_GetLength michael@0: (userCheckers, &numUserCheckers, plContext), michael@0: PKIX_LISTGETLENGTHFAILED); michael@0: michael@0: for (i = 0; i < numUserCheckers; i++) { michael@0: michael@0: PKIX_CHECK(PKIX_List_GetItem michael@0: (userCheckers, michael@0: i, michael@0: (PKIX_PL_Object **) &userChecker, michael@0: plContext), michael@0: PKIX_LISTGETITEMFAILED); michael@0: michael@0: PKIX_CHECK michael@0: (PKIX_CertChainChecker_IsForwardCheckingSupported michael@0: (userChecker, &supportForwarding, plContext), michael@0: PKIX_CERTCHAINCHECKERISFORWARDCHECKINGSUPPORTEDFAILED); michael@0: michael@0: if (supportForwarding == PKIX_FALSE) { michael@0: michael@0: PKIX_CHECK michael@0: (PKIX_CertChainChecker_GetSupportedExtensions michael@0: (userChecker, &userCheckerExtOIDs, plContext), michael@0: PKIX_CERTCHAINCHECKERGETSUPPORTEDEXTENSIONSFAILED); michael@0: michael@0: if (userCheckerExtOIDs != NULL) { michael@0: PKIX_CHECK(pkix_List_AppendList michael@0: (validateCheckedCritExtOIDsList, michael@0: userCheckerExtOIDs, michael@0: plContext), michael@0: PKIX_LISTAPPENDLISTFAILED); michael@0: } michael@0: } michael@0: michael@0: PKIX_DECREF(userCheckerExtOIDs); michael@0: PKIX_DECREF(userChecker); michael@0: } michael@0: } michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_GetRevocationChecker michael@0: (procParams, &revChecker, plContext), michael@0: PKIX_PROCESSINGPARAMSGETREVOCATIONCHECKERFAILED); michael@0: michael@0: /* try to validate the chain with each anchor */ michael@0: for (i = 0; i < numAnchors; i++){ michael@0: michael@0: /* get trust anchor */ michael@0: PKIX_CHECK(PKIX_List_GetItem michael@0: (anchors, i, (PKIX_PL_Object **)&anchor, plContext), michael@0: PKIX_LISTGETITEMFAILED); michael@0: michael@0: /* initialize checkers using information from trust anchor */ michael@0: PKIX_CHECK(pkix_InitializeCheckers michael@0: (anchor, procParams, numCerts, &checkers, plContext), michael@0: PKIX_INITIALIZECHECKERSFAILED); michael@0: michael@0: /* michael@0: * Validate the chain using this trust anchor and these michael@0: * checkers. (WARNING: checkers that use non-blocking I/O michael@0: * are not currently supported.) michael@0: */ michael@0: certCheckedIndex = 0; michael@0: checkerIndex = 0; michael@0: revChecking = PKIX_FALSE; michael@0: chainFailed = pkix_CheckChain michael@0: (certs, michael@0: numCerts, michael@0: anchor, michael@0: checkers, michael@0: revChecker, michael@0: validateCheckedCritExtOIDsList, michael@0: procParams, michael@0: &certCheckedIndex, michael@0: &checkerIndex, michael@0: &revChecking, michael@0: &reasonCode, michael@0: &nbioContext, michael@0: &finalPubKey, michael@0: &validPolicyTree, michael@0: pVerifyTree, michael@0: plContext); michael@0: michael@0: if (chainFailed) { michael@0: michael@0: /* cert chain failed to validate */ michael@0: michael@0: PKIX_DECREF(chainFailed); michael@0: PKIX_DECREF(anchor); michael@0: PKIX_DECREF(checkers); michael@0: PKIX_DECREF(validPolicyTree); michael@0: michael@0: /* if last anchor, we fail; else, we try next anchor */ michael@0: if (i == (numAnchors - 1)) { /* last anchor */ michael@0: PKIX_ERROR(PKIX_VALIDATECHAINFAILED); michael@0: } michael@0: michael@0: } else { michael@0: michael@0: /* XXX Remove this assertion after 2014-12-31. michael@0: * See bug 946984. */ michael@0: PORT_Assert(reasonCode == 0); michael@0: michael@0: /* cert chain successfully validated! */ michael@0: PKIX_CHECK(pkix_ValidateResult_Create michael@0: (finalPubKey, michael@0: anchor, michael@0: validPolicyTree, michael@0: &valResult, michael@0: plContext), michael@0: PKIX_VALIDATERESULTCREATEFAILED); michael@0: michael@0: *pResult = valResult; michael@0: michael@0: /* no need to try any more anchors in the loop */ michael@0: goto cleanup; michael@0: } michael@0: } michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_DECREF(finalPubKey); michael@0: PKIX_DECREF(certs); michael@0: PKIX_DECREF(anchors); michael@0: PKIX_DECREF(anchor); michael@0: PKIX_DECREF(checkers); michael@0: PKIX_DECREF(revChecker); michael@0: PKIX_DECREF(validPolicyTree); michael@0: PKIX_DECREF(chainFailed); michael@0: PKIX_DECREF(procParams); michael@0: PKIX_DECREF(userCheckers); michael@0: PKIX_DECREF(validateCheckedCritExtOIDsList); michael@0: michael@0: PKIX_RETURN(VALIDATE); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_Validate_BuildUserOIDs michael@0: * DESCRIPTION: michael@0: * michael@0: * This function creates a List of the OIDs that are processed by the user michael@0: * checkers in the List pointed to by "userCheckers", storing the resulting michael@0: * List at "pUserCritOIDs". If the List of userCheckers is NULL, the output michael@0: * List will be NULL. Otherwise the output List will be non-NULL, but may be michael@0: * empty. michael@0: * michael@0: * PARAMETERS: michael@0: * "userCheckers" michael@0: * The address of the List of userCheckers. michael@0: * "pUserCritOIDs" michael@0: * The address at which the List is 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 VALIDATE Error if the function fails in 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_Validate_BuildUserOIDs( michael@0: PKIX_List *userCheckers, michael@0: PKIX_List **pUserCritOIDs, michael@0: void *plContext) michael@0: { michael@0: PKIX_UInt32 numUserCheckers = 0; michael@0: PKIX_UInt32 i = 0; michael@0: PKIX_List *userCritOIDs = NULL; michael@0: PKIX_List *userCheckerExtOIDs = NULL; michael@0: PKIX_Boolean supportForwarding = PKIX_FALSE; michael@0: PKIX_CertChainChecker *userChecker = NULL; michael@0: michael@0: PKIX_ENTER(VALIDATE, "pkix_Validate_BuildUserOIDs"); michael@0: PKIX_NULLCHECK_ONE(pUserCritOIDs); michael@0: michael@0: if (userCheckers != NULL) { michael@0: PKIX_CHECK(PKIX_List_Create(&userCritOIDs, plContext), michael@0: PKIX_LISTCREATEFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_List_GetLength michael@0: (userCheckers, &numUserCheckers, plContext), michael@0: PKIX_LISTGETLENGTHFAILED); michael@0: michael@0: for (i = 0; i < numUserCheckers; i++) { michael@0: PKIX_CHECK(PKIX_List_GetItem michael@0: (userCheckers, michael@0: i, michael@0: (PKIX_PL_Object **) &userChecker, michael@0: plContext), michael@0: PKIX_LISTGETITEMFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_CertChainChecker_IsForwardCheckingSupported michael@0: (userChecker, &supportForwarding, plContext), michael@0: PKIX_CERTCHAINCHECKERISFORWARDCHECKINGSUPPORTEDFAILED); michael@0: michael@0: if (supportForwarding == PKIX_FALSE) { michael@0: michael@0: PKIX_CHECK(PKIX_CertChainChecker_GetSupportedExtensions michael@0: (userChecker, &userCheckerExtOIDs, plContext), michael@0: PKIX_CERTCHAINCHECKERGETSUPPORTEDEXTENSIONSFAILED); michael@0: michael@0: if (userCheckerExtOIDs != NULL) { michael@0: PKIX_CHECK(pkix_List_AppendList michael@0: (userCritOIDs, userCheckerExtOIDs, plContext), michael@0: PKIX_LISTAPPENDLISTFAILED); michael@0: } michael@0: } michael@0: michael@0: PKIX_DECREF(userCheckerExtOIDs); michael@0: PKIX_DECREF(userChecker); michael@0: } michael@0: } michael@0: michael@0: *pUserCritOIDs = userCritOIDs; michael@0: michael@0: cleanup: michael@0: michael@0: if (PKIX_ERROR_RECEIVED){ michael@0: PKIX_DECREF(userCritOIDs); michael@0: } michael@0: michael@0: PKIX_DECREF(userCheckerExtOIDs); michael@0: PKIX_DECREF(userChecker); michael@0: michael@0: PKIX_RETURN(VALIDATE); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: PKIX_ValidateChain_nb (see comments in pkix.h) michael@0: */ michael@0: PKIX_Error * michael@0: PKIX_ValidateChain_NB( michael@0: PKIX_ValidateParams *valParams, michael@0: PKIX_UInt32 *pCertIndex, michael@0: PKIX_UInt32 *pAnchorIndex, michael@0: PKIX_UInt32 *pCheckerIndex, michael@0: PKIX_Boolean *pRevChecking, michael@0: PKIX_List **pCheckers, michael@0: void **pNBIOContext, michael@0: PKIX_ValidateResult **pResult, michael@0: PKIX_VerifyNode **pVerifyTree, michael@0: void *plContext) michael@0: { michael@0: PKIX_UInt32 numCerts = 0; michael@0: PKIX_UInt32 numAnchors = 0; michael@0: PKIX_UInt32 i = 0; michael@0: PKIX_UInt32 certIndex = 0; michael@0: PKIX_UInt32 anchorIndex = 0; michael@0: PKIX_UInt32 checkerIndex = 0; michael@0: PKIX_UInt32 reasonCode = 0; michael@0: PKIX_Boolean revChecking = PKIX_FALSE; michael@0: PKIX_List *certs = NULL; michael@0: PKIX_List *anchors = NULL; michael@0: PKIX_List *checkers = NULL; michael@0: PKIX_List *userCheckers = NULL; michael@0: PKIX_List *validateCheckedCritExtOIDsList = NULL; michael@0: PKIX_TrustAnchor *anchor = NULL; michael@0: PKIX_ValidateResult *valResult = NULL; michael@0: PKIX_PL_PublicKey *finalPubKey = NULL; michael@0: PKIX_PolicyNode *validPolicyTree = NULL; michael@0: PKIX_ProcessingParams *procParams = NULL; michael@0: PKIX_RevocationChecker *revChecker = NULL; michael@0: PKIX_Error *chainFailed = NULL; michael@0: void *nbioContext = NULL; michael@0: michael@0: PKIX_ENTER(VALIDATE, "PKIX_ValidateChain_NB"); michael@0: PKIX_NULLCHECK_FOUR michael@0: (valParams, pCertIndex, pAnchorIndex, pCheckerIndex); michael@0: PKIX_NULLCHECK_FOUR(pRevChecking, pCheckers, pNBIOContext, pResult); michael@0: michael@0: nbioContext = *pNBIOContext; michael@0: *pNBIOContext = NULL; michael@0: michael@0: /* extract various parameters from valParams */ michael@0: PKIX_CHECK(pkix_ExtractParameters michael@0: (valParams, michael@0: &certs, michael@0: &numCerts, michael@0: &procParams, michael@0: &anchors, michael@0: &numAnchors, michael@0: plContext), michael@0: PKIX_EXTRACTPARAMETERSFAILED); michael@0: michael@0: /* michael@0: * Create a List of the OIDs that will be processed by the user michael@0: * checkers. User checkers are not responsible for removing OIDs from michael@0: * the List of unresolved critical extensions, as libpkix checkers are. michael@0: * So we add those user checkers' OIDs to the removal list to be taken michael@0: * out by CheckChain. michael@0: */ michael@0: PKIX_CHECK(PKIX_ProcessingParams_GetCertChainCheckers michael@0: (procParams, &userCheckers, plContext), michael@0: PKIX_PROCESSINGPARAMSGETCERTCHAINCHECKERSFAILED); michael@0: michael@0: PKIX_CHECK(pkix_Validate_BuildUserOIDs michael@0: (userCheckers, &validateCheckedCritExtOIDsList, plContext), michael@0: PKIX_VALIDATEBUILDUSEROIDSFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_ProcessingParams_GetRevocationChecker michael@0: (procParams, &revChecker, plContext), michael@0: PKIX_PROCESSINGPARAMSGETREVOCATIONCHECKERFAILED); michael@0: michael@0: /* Are we resuming after a WOULDBLOCK return, or starting anew ? */ michael@0: if (nbioContext != NULL) { michael@0: /* Resuming */ michael@0: certIndex = *pCertIndex; michael@0: anchorIndex = *pAnchorIndex; michael@0: checkerIndex = *pCheckerIndex; michael@0: revChecking = *pRevChecking; michael@0: checkers = *pCheckers; michael@0: *pCheckers = NULL; michael@0: } michael@0: michael@0: /* try to validate the chain with each anchor */ michael@0: for (i = anchorIndex; i < numAnchors; i++) { michael@0: michael@0: /* get trust anchor */ michael@0: PKIX_CHECK(PKIX_List_GetItem michael@0: (anchors, i, (PKIX_PL_Object **)&anchor, plContext), michael@0: PKIX_LISTGETITEMFAILED); michael@0: michael@0: /* initialize checkers using information from trust anchor */ michael@0: if (nbioContext == NULL) { michael@0: PKIX_CHECK(pkix_InitializeCheckers michael@0: (anchor, michael@0: procParams, michael@0: numCerts, michael@0: &checkers, michael@0: plContext), michael@0: PKIX_INITIALIZECHECKERSFAILED); michael@0: } michael@0: michael@0: /* michael@0: * Validate the chain using this trust anchor and these michael@0: * checkers. michael@0: */ michael@0: chainFailed = pkix_CheckChain michael@0: (certs, michael@0: numCerts, michael@0: anchor, michael@0: checkers, michael@0: revChecker, michael@0: validateCheckedCritExtOIDsList, michael@0: procParams, michael@0: &certIndex, michael@0: &checkerIndex, michael@0: &revChecking, michael@0: &reasonCode, michael@0: &nbioContext, michael@0: &finalPubKey, michael@0: &validPolicyTree, michael@0: pVerifyTree, michael@0: plContext); michael@0: michael@0: if (nbioContext != NULL) { michael@0: *pCertIndex = certIndex; michael@0: *pAnchorIndex = anchorIndex; michael@0: *pCheckerIndex = checkerIndex; michael@0: *pRevChecking = revChecking; michael@0: PKIX_INCREF(checkers); michael@0: *pCheckers = checkers; michael@0: *pNBIOContext = nbioContext; michael@0: goto cleanup; michael@0: } michael@0: michael@0: if (chainFailed) { michael@0: michael@0: /* cert chain failed to validate */ michael@0: michael@0: PKIX_DECREF(chainFailed); michael@0: PKIX_DECREF(anchor); michael@0: PKIX_DECREF(checkers); michael@0: PKIX_DECREF(validPolicyTree); michael@0: michael@0: /* if last anchor, we fail; else, we try next anchor */ michael@0: if (i == (numAnchors - 1)) { /* last anchor */ michael@0: PKIX_ERROR(PKIX_VALIDATECHAINFAILED); michael@0: } michael@0: michael@0: } else { michael@0: michael@0: /* XXX Remove this assertion after 2014-12-31. michael@0: * See bug 946984. */ michael@0: PORT_Assert(reasonCode == 0); michael@0: michael@0: /* cert chain successfully validated! */ michael@0: PKIX_CHECK(pkix_ValidateResult_Create michael@0: (finalPubKey, michael@0: anchor, michael@0: validPolicyTree, michael@0: &valResult, michael@0: plContext), michael@0: PKIX_VALIDATERESULTCREATEFAILED); michael@0: michael@0: *pResult = valResult; michael@0: michael@0: /* no need to try any more anchors in the loop */ michael@0: goto cleanup; michael@0: } michael@0: } michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_DECREF(finalPubKey); michael@0: PKIX_DECREF(certs); michael@0: PKIX_DECREF(anchors); michael@0: PKIX_DECREF(anchor); michael@0: PKIX_DECREF(checkers); michael@0: PKIX_DECREF(revChecker); michael@0: PKIX_DECREF(validPolicyTree); michael@0: PKIX_DECREF(chainFailed); michael@0: PKIX_DECREF(procParams); michael@0: PKIX_DECREF(userCheckers); michael@0: PKIX_DECREF(validateCheckedCritExtOIDsList); michael@0: michael@0: PKIX_RETURN(VALIDATE); michael@0: }