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