Ejemplo n.º 1
0
/*
 * FUNCTION: pkix_List_RemoveItems
 * DESCRIPTION:
 *
 *  Traverses the List pointed to by "list", to find and delete an entry
 *  that is equal to the Object in the "deleteList". If no such entry
 *  is found the function does not return an error.
 *
 * PARAMETERS:
 *  "list"
 *      Object in "list" is checked for object in "deleteList" and deleted if
 *      found; may be empty; must be non-NULL
 *  "deleteList"
 *      List of objects to be searched ; may be empty; 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 functions fails in a non-fatal way
 *  Returns a Fatal Error if the function fails in an unrecoverable way
 */
PKIX_Error *
pkix_List_RemoveItems(
        PKIX_List *list,
        PKIX_List *deleteList,
        void *plContext)
{
        PKIX_PL_Object *current = NULL;
        PKIX_UInt32 numEntries = 0;
        PKIX_UInt32 index = 0;

        PKIX_ENTER(LIST, "pkix_List_RemoveItems");
        PKIX_NULLCHECK_TWO(list, deleteList);

        PKIX_CHECK(PKIX_List_GetLength(deleteList, &numEntries, plContext),
                PKIX_LISTGETLENGTHFAILED);

        for (index = 0; index < numEntries; index++) {
                PKIX_CHECK(PKIX_List_GetItem
                        (deleteList, index, &current, plContext),
                        PKIX_LISTGETITEMFAILED);

                if (current) {
                        PKIX_CHECK(pkix_List_Remove
                                (list, current, plContext),
                                PKIX_OBJECTEQUALSFAILED);

                        PKIX_DECREF(current);
                }
        }

cleanup:

        PKIX_DECREF(current);
        PKIX_RETURN(LIST);
}
/*
 * FUNCTION: pkix_TargetCertChecker_Check
 * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h)
 */
PKIX_Error *
pkix_TargetCertChecker_Check(
        PKIX_CertChainChecker *checker,
        PKIX_PL_Cert *cert,
        PKIX_List *unresolvedCriticalExtensions,
        void **pNBIOContext,
        void *plContext)
{
        pkix_TargetCertCheckerState *state = NULL;
        PKIX_CertSelector_MatchCallback certSelectorMatch = NULL;
        PKIX_PL_CertNameConstraints *nameConstraints = NULL;
        PKIX_List *certSubjAltNames = NULL;
        PKIX_List *certExtKeyUsageList = NULL;
        PKIX_PL_GeneralName *name = NULL;
        PKIX_PL_X500Name *certSubjectName = NULL;
        PKIX_Boolean checkPassed = PKIX_FALSE;
        PKIX_UInt32 numItems, i;
        PKIX_UInt32 matchCount = 0;

        PKIX_ENTER(CERTCHAINCHECKER, "pkix_TargetCertChecker_Check");
        PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext);

        *pNBIOContext = NULL; /* we never block on pending I/O */

        PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState
                    (checker, (PKIX_PL_Object **)&state, plContext),
                    PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED);

        (state->certsRemaining)--;

        if (state->pathToNameList != NULL) {

                PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints
                    (cert, &nameConstraints, plContext),
                    PKIX_CERTGETNAMECONSTRAINTSFAILED);

                /*
                 * XXX We should either make the following call a public one
                 * so it is legal to call from the portability layer or we
                 * should try to create pathToNameList as CertNameConstraints
                 * then call the existing check function.
                 */
                PKIX_CHECK(PKIX_PL_CertNameConstraints_CheckNamesInNameSpace
                    (state->pathToNameList,
                    nameConstraints,
                    &checkPassed,
                    plContext),
                    PKIX_CERTNAMECONSTRAINTSCHECKNAMEINNAMESPACEFAILED);

                if (checkPassed != PKIX_TRUE) {
                    PKIX_ERROR(PKIX_VALIDATIONFAILEDPATHTONAMECHECKFAILED);
                }

        }

        PKIX_CHECK(PKIX_PL_Cert_GetSubjectAltNames
                    (cert, &certSubjAltNames, plContext),
                    PKIX_CERTGETSUBJALTNAMESFAILED);

        if (state->subjAltNameList != NULL && certSubjAltNames != NULL) {

                PKIX_CHECK(PKIX_List_GetLength
                        (state->subjAltNameList, &numItems, plContext),
                        PKIX_LISTGETLENGTHFAILED);

                for (i = 0; i < numItems; i++) {

                        PKIX_CHECK(PKIX_List_GetItem
                            (state->subjAltNameList,
                            i,
                            (PKIX_PL_Object **) &name,
                            plContext),
                            PKIX_LISTGETITEMFAILED);

                        PKIX_CHECK(pkix_List_Contains
                            (certSubjAltNames,
                            (PKIX_PL_Object *) name,
                            &checkPassed,
                            plContext),
                            PKIX_LISTCONTAINSFAILED);

                        PKIX_DECREF(name);

                        if (checkPassed == PKIX_TRUE) {

                            if (state->subjAltNameMatchAll == PKIX_FALSE) {
                                matchCount = numItems;
                                break;
                            } else {
                                /* else continue checking next */
                                matchCount++;
                            }

                        }
                }

                if (matchCount != numItems) {
                        PKIX_ERROR(PKIX_SUBJALTNAMECHECKFAILED);

                }
        }

        if (state->certsRemaining == 0) {

            if (state->certSelector != NULL) {
                PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
                           (state->certSelector,
                            &certSelectorMatch,
                            plContext),
                           PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);

                PKIX_CHECK(certSelectorMatch
                           (state->certSelector,
                            cert,
                            plContext),
                           PKIX_CERTSELECTORMATCHFAILED);
            } else {
                /* Check at least cert/key usages if target cert selector
                 * is not set. */
                PKIX_CHECK(PKIX_PL_Cert_VerifyCertAndKeyType(cert,
                                         PKIX_FALSE  /* is chain cert*/,
                                         plContext),
                           PKIX_CERTVERIFYCERTTYPEFAILED);
            }
            /*
             * There are two Extended Key Usage Checkings
             * available :
             * 1) here at the targetcertchecker where we
             *    verify the Extended Key Usage OIDs application
             *    specifies via ComCertSelParams are included
             *    in Cert's Extended Key Usage OID's. Note,
             *    this is an OID to OID comparison and only last
             *    Cert is checked.
             * 2) at user defined ekuchecker where checking
             *    is applied to all Certs on the chain and
             *    the NSS Extended Key Usage algorithm is
             *    used. In order to invoke this checking, not
             *    only does the ComCertSelparams needs to be
             *    set, the EKU initialize call is required to
             *    activate the checking.
             *
             * XXX We use the same ComCertSelParams Set/Get
             * functions to set the parameters for both cases.
             * We may want to separate them in the future.
             */
            
            PKIX_CHECK(PKIX_PL_Cert_GetExtendedKeyUsage
                       (cert, &certExtKeyUsageList, plContext),
                       PKIX_CERTGETEXTENDEDKEYUSAGEFAILED);
            
            
            if (state->extKeyUsageList != NULL &&
                certExtKeyUsageList != NULL) {
                
                PKIX_CHECK(PKIX_List_GetLength
                           (state->extKeyUsageList, &numItems, plContext),
                           PKIX_LISTGETLENGTHFAILED);
                
                for (i = 0; i < numItems; i++) {
                    
                    PKIX_CHECK(PKIX_List_GetItem
                               (state->extKeyUsageList,
                                i,
                                (PKIX_PL_Object **) &name,
                                plContext),
                               PKIX_LISTGETITEMFAILED);
                    
                    PKIX_CHECK(pkix_List_Contains
                               (certExtKeyUsageList,
                                (PKIX_PL_Object *) name,
                                &checkPassed,
                                plContext),
                               PKIX_LISTCONTAINSFAILED);
                    
                    PKIX_DECREF(name);
                    
                    if (checkPassed != PKIX_TRUE) {
                        PKIX_ERROR
                            (PKIX_EXTENDEDKEYUSAGECHECKINGFAILED);
                        
                    }
                }
            }
        } else {
            /* Check key usage and cert type based on certificate usage. */
            PKIX_CHECK(PKIX_PL_Cert_VerifyCertAndKeyType(cert, PKIX_TRUE,
                                                         plContext),
                       PKIX_CERTVERIFYCERTTYPEFAILED);
        }

        /* Remove Critical Extension OID from list */
        if (unresolvedCriticalExtensions != NULL) {

                PKIX_CHECK(pkix_List_Remove
                            (unresolvedCriticalExtensions,
                            (PKIX_PL_Object *) state->extKeyUsageOID,
                            plContext),
                            PKIX_LISTREMOVEFAILED);

                PKIX_CHECK(PKIX_PL_Cert_GetSubject
                            (cert, &certSubjectName, plContext),
                            PKIX_CERTGETSUBJECTFAILED);

                if (certSubjAltNames != NULL) {
                        PKIX_CHECK(pkix_List_Remove
                            (unresolvedCriticalExtensions,
                            (PKIX_PL_Object *) state->subjAltNameOID,
                            plContext),
                            PKIX_LISTREMOVEFAILED);
                }

        }

cleanup:

        PKIX_DECREF(name);
        PKIX_DECREF(nameConstraints);
        PKIX_DECREF(certSubjAltNames);
        PKIX_DECREF(certExtKeyUsageList);
        PKIX_DECREF(certSubjectName);
        PKIX_DECREF(state);

        PKIX_RETURN(CERTCHAINCHECKER);

}
/*
 * FUNCTION: pkix_NameConstraintsChecker_Check
 * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h)
 */
static PKIX_Error *
pkix_NameConstraintsChecker_Check(
        PKIX_CertChainChecker *checker,
        PKIX_PL_Cert *cert,
        PKIX_List *unresolvedCriticalExtensions,
        void **pNBIOContext,
        void *plContext)
{
        pkix_NameConstraintsCheckerState *state = NULL;
        PKIX_PL_CertNameConstraints *nameConstraints = NULL;
        PKIX_PL_CertNameConstraints *mergedNameConstraints = NULL;
        PKIX_Boolean selfIssued = PKIX_FALSE;
        PKIX_Boolean lastCert = PKIX_FALSE;

        PKIX_ENTER(CERTCHAINCHECKER, "pkix_NameConstraintsChecker_Check");
        PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext);

        *pNBIOContext = NULL; /* we never block on pending I/O */

        PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState
                    (checker, (PKIX_PL_Object **)&state, plContext),
                    PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED);

        state->certsRemaining--;
        lastCert = state->certsRemaining == 0;

        /* Get status of self issued */
        PKIX_CHECK(pkix_IsCertSelfIssued(cert, &selfIssued, plContext),
                    PKIX_ISCERTSELFISSUEDFAILED);

        /* Check on non self-issued and if so only for last cert */
        if (selfIssued == PKIX_FALSE ||
            (selfIssued == PKIX_TRUE && lastCert)) {
                PKIX_CHECK(PKIX_PL_Cert_CheckNameConstraints
                    (cert, state->nameConstraints, lastCert,
                      plContext),
                    PKIX_CERTCHECKNAMECONSTRAINTSFAILED);
        }

        if (!lastCert) {

            PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints
                    (cert, &nameConstraints, plContext),
                    PKIX_CERTGETNAMECONSTRAINTSFAILED);

            /* Merge with previous name constraints kept in state */

            if (nameConstraints != NULL) {

                if (state->nameConstraints == NULL) {

                        state->nameConstraints = nameConstraints;

                } else {

                        PKIX_CHECK(PKIX_PL_Cert_MergeNameConstraints
                                (nameConstraints,
                                state->nameConstraints,
                                &mergedNameConstraints,
                                plContext),
                                PKIX_CERTMERGENAMECONSTRAINTSFAILED);

                        PKIX_DECREF(nameConstraints);
                        PKIX_DECREF(state->nameConstraints);

                        state->nameConstraints = mergedNameConstraints;
                }

                /* Remove Name Constraints Extension OID from list */
                if (unresolvedCriticalExtensions != NULL) {
                        PKIX_CHECK(pkix_List_Remove
                                    (unresolvedCriticalExtensions,
                                    (PKIX_PL_Object *)state->nameConstraintsOID,
                                    plContext),
                                    PKIX_LISTREMOVEFAILED);
                }
            }
        }

        PKIX_CHECK(PKIX_CertChainChecker_SetCertChainCheckerState
                    (checker, (PKIX_PL_Object *)state, plContext),
                    PKIX_CERTCHAINCHECKERSETCERTCHAINCHECKERSTATEFAILED);

cleanup:

        PKIX_DECREF(state);

        PKIX_RETURN(CERTCHAINCHECKER);
}
/*
 * FUNCTION: pkix_DefaultCRLChecker_CheckCRLs
 *
 * DESCRIPTION:
 *  Check validity of "cert" based on CRLs at "crlList" that has correct
 *  signature verification with "publicKey".
 *
 * PARAMETERS
 *  "cert"
 *      Address of Cert which has the certificate data. Must be non-NULL.
 *  "certIssuer"
 *      Address of Issuer that associates with the Cert. Must be non-NULL.
 *  "certSerialNumber"
 *      Address of Serial Number that associates with the Cert. Must be 
 *      non-NULL.
 *  "publicKey"
 *      Address of Public Key that associates with the Cert Issuer.
 *      Must be non-NULL.
 *  "crlList"
 *      A List CRLs that the certificate is verified upon. Must be non-NULL.
 *  "state"
 *      Address of DefaultCRLCheckerState which keeps dynamic state data.
 *      Must be non-NULL.
 *  "pCrlEntryList"
 *      Address of PKIX_PL_CrlEntry List that contains valid CrlEntries for
 *      this Cert. May be NULL.
 *  "plContext"
 *      Platform-specific context pointer.
 *
 * THREAD SAFETY:
 *  Conditionally Thread Safe
 *      (see Thread Safety Definitions in Programmer's Guide)
 *
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a CertChainChecker Error if the function fails in a non-fatal way.
 *  Returns a Fatal Error
 */
static PKIX_Error *
pkix_DefaultCRLChecker_CheckCRLs(
        PKIX_PL_Cert *cert,
        PKIX_PL_X500Name *certIssuer,
        PKIX_PL_BigInt *certSerialNumber,
        PKIX_PL_PublicKey *publicKey,
        PKIX_List *crlList,
        pkix_DefaultCRLCheckerState *state,
        PKIX_List **pCrlEntryList,
        void *plContext)
{
        PKIX_PL_CRL *crl = NULL;
        PKIX_PL_CRLEntry *crlEntry = NULL;
        PKIX_PL_PublicKey *pKey = NULL;
        PKIX_List *unresCrlCritExtOIDs = NULL;
        PKIX_List *unresCrlEntryCritExtOIDs = NULL;
        PKIX_List *crlEntryList = NULL;
        PKIX_Error *verifyFail = NULL;
        PKIX_UInt32 numCrls = 0;
        PKIX_UInt32 numKeys = 0;
        PKIX_UInt32 numCritExtOIDs = 0;
        PKIX_Boolean crlVerified = PKIX_FALSE;
        PKIX_Boolean crlRevoking = PKIX_FALSE;
        PKIX_Int32 reasonCode = 0;
        PKIX_UInt32 i;
        PKIX_Int32 j;

        PKIX_ENTER(CERTCHAINCHECKER,
                    "pkix_DefaultCRLChecker_CheckCRLs");
        PKIX_NULLCHECK_FOUR(cert, publicKey, crlList, state);

        PKIX_CHECK(PKIX_List_GetLength(crlList, &numCrls, plContext),
                    PKIX_LISTGETLENGTHFAILED);

        if (state->prevPublicKeyList != NULL) {

                PKIX_CHECK(PKIX_List_GetLength
                    (state->prevPublicKeyList, &numKeys, plContext),
                    PKIX_LISTGETLENGTHFAILED);
        }

        /* Check if Cert is not revoked by any the the CRLs */

        for (i = 0; i < numCrls; i++){

                PKIX_CHECK(PKIX_List_GetItem
                            (crlList, i, (PKIX_PL_Object **)&crl, plContext),
                            PKIX_LISTGETITEMFAILED);

                /*
                 * Checking serial number (issuer done in selector) then
                 * verify signature. If matches, get the CRL reason(s).
                 */

                if (state->prevCertCrlSign == PKIX_TRUE) {
                        verifyFail = PKIX_PL_CRL_VerifySignature
                                (crl, publicKey, plContext);
                        if (verifyFail == NULL) {
                                crlVerified = PKIX_TRUE;
                        } else {
                                crlVerified = PKIX_FALSE;
                                PKIX_DECREF(verifyFail);
                        }
                }

                if (crlVerified == PKIX_FALSE) {

                    /* Verify from old key(s) on the list */
                    for (j = numKeys - 1; j >= 0; j--) {

                            PKIX_CHECK(PKIX_List_GetItem
                                (state->prevPublicKeyList,
                                j,
                                (PKIX_PL_Object **) &pKey,
                                plContext),
                                PKIX_LISTGETITEMFAILED);

                            verifyFail = PKIX_PL_CRL_VerifySignature
                                (crl, pKey, plContext);

                            if (verifyFail == NULL) {
                                crlVerified = PKIX_TRUE;
                                break;
                            } else {
                                crlVerified = PKIX_FALSE;
                                PKIX_DECREF(verifyFail);
                            }

                            PKIX_DECREF(pKey);
                    }
                }

                if (crlVerified == PKIX_FALSE) {
                    /* try next one ... */
                    goto cleanup_loop;
                }

                state->certHasValidCrl = PKIX_TRUE;

                PKIX_CHECK(PKIX_PL_CRL_GetCriticalExtensionOIDs
                            (crl, &unresCrlCritExtOIDs, plContext),
                            PKIX_CRLGETCRITICALEXTENSIONOIDSFAILED);

                /*
                 * XXX Advanced CRL work - should put a
                 * Loop here to process and remove critical
                 * extension oids.
                 */

                if (unresCrlCritExtOIDs) {

                    PKIX_CHECK(PKIX_List_GetLength(unresCrlCritExtOIDs,
                        &numCritExtOIDs,
                        plContext),
                        PKIX_LISTGETLENGTHFAILED);

                    if (numCritExtOIDs != 0) {
                        PKIX_DEFAULTCRLCHECKERSTATE_DEBUG
                                (PKIX_CRLCRITICALEXTENSIONOIDSNOTPROCESSED);
                        /*
                         * Uncomment this after we have implemented
                         * checkers for all the critical extensions.
                         *
                         * PKIX_ERROR
                         *      ("Unrecognized CRL Critical Extension");
                         */
                    }
                }

                PKIX_CHECK(PKIX_PL_CRL_GetCRLEntryForSerialNumber
                            (crl, certSerialNumber, &crlEntry, plContext),
                            PKIX_CRLGETCRLENTRYFORSERIALNUMBERFAILED);

                if (crlEntry == NULL) {
                    goto cleanup_loop;
                }

                crlRevoking = PKIX_TRUE;

                PKIX_CHECK(PKIX_PL_CRLEntry_GetCRLEntryReasonCode
                            (crlEntry,
                            &reasonCode,
                            plContext),
                            PKIX_CRLENTRYGETCRLENTRYREASONCODEFAILED);

                /* This is a valid CRLEntry, return it for caching */
                if (crlEntryList == NULL) {
                    PKIX_CHECK(PKIX_List_Create(&crlEntryList, plContext),
                            PKIX_LISTCREATEFAILED);

                }

                PKIX_CHECK(PKIX_List_AppendItem
                        (crlEntryList, (PKIX_PL_Object *) crlEntry, plContext),
                        PKIX_LISTAPPENDITEMFAILED);

                /* Set reason code in state for advance CRL reviewing */

                if (reasonCode >= 0) {
                    if (reasonCode >= numReasonCodes) 
		        reasonCode = 0;

                    state->reasonCodeMask |= 1 << reasonCode;
                    PKIX_DEFAULTCRLCHECKERSTATE_DEBUG_ARG
                        ("CRL revocation Reason: %s\n ",
                        reasonCodeMsgString[reasonCode]);

                } else {
                    PKIX_DEFAULTCRLCHECKERSTATE_DEBUG
                        ("Revoked by Unknown CRL ReasonCode");
                }

                PKIX_CHECK(PKIX_PL_CRLEntry_GetCriticalExtensionOIDs
                            (crlEntry, &unresCrlEntryCritExtOIDs, plContext),
                            PKIX_CRLENTRYGETCRITICALEXTENSIONOIDSFAILED);
                if (unresCrlEntryCritExtOIDs) {

                    PKIX_CHECK(pkix_List_Remove
                            (unresCrlEntryCritExtOIDs,
                            (PKIX_PL_Object *) state->crlReasonCodeOID,
                            plContext),
                            PKIX_LISTREMOVEFAILED);

                    PKIX_CHECK(PKIX_List_GetLength(unresCrlEntryCritExtOIDs,
                        &numCritExtOIDs,
                        plContext),
                        PKIX_LISTGETLENGTHFAILED);

                    if (numCritExtOIDs != 0) {

                        PKIX_DEFAULTCRLCHECKERSTATE_DEBUG
                            (PKIX_CRLENTRYCRITICALEXTENSIONWASNOTPROCESSED);
                        PKIX_ERROR(PKIX_UNRECOGNIZEDCRLENTRYCRITICALEXTENSION);
                    }
                }

        cleanup_loop:

                PKIX_DECREF(pKey);
                PKIX_DECREF(verifyFail);
                PKIX_DECREF(pKey);
                PKIX_DECREF(crlEntry);
                PKIX_DECREF(crl);
                PKIX_DECREF(unresCrlCritExtOIDs);
                PKIX_DECREF(unresCrlEntryCritExtOIDs);
        }

        *pCrlEntryList = crlEntryList;

        if (crlRevoking == PKIX_TRUE) {

                PKIX_ERROR(PKIX_CERTIFICATEREVOKEDBYCRL);
        }

cleanup:

        PKIX_DECREF(pKey);
        PKIX_DECREF(verifyFail);
        PKIX_DECREF(crlEntry);
        PKIX_DECREF(crl);
        PKIX_DECREF(unresCrlCritExtOIDs);
        PKIX_DECREF(unresCrlEntryCritExtOIDs);

        PKIX_RETURN(CERTCHAINCHECKER);
}