internal static void ProcessAttrCert7(
            IX509AttributeCertificate attrCert,
            PkixCertPath certPath,
            PkixCertPath holderCertPath,
            PkixParameters pkixParams)
        {
            // TODO:
            // AA Controls
            // Attribute encryption
            // Proxy
            ISet critExtOids = attrCert.GetCriticalExtensionOids();

            // 7.1
            // process extensions

            // target information checked in step 6 / X509AttributeCertStoreSelector
            if (critExtOids.Contains(X509Extensions.TargetInformation.Id))
            {
                try
                {
                    TargetInformation.GetInstance(PkixCertPathValidatorUtilities
                                                  .GetExtensionValue(attrCert, X509Extensions.TargetInformation));
                }
                catch (Exception e)
                {
                    throw new PkixCertPathValidatorException(
                              "Target information extension could not be read.", e);
                }
            }
            critExtOids.Remove(X509Extensions.TargetInformation.Id);
            foreach (PkixAttrCertChecker checker in pkixParams.GetAttrCertCheckers())
            {
                checker.Check(attrCert, certPath, holderCertPath, critExtOids);
            }
            if (!critExtOids.IsEmpty)
            {
                throw new PkixCertPathValidatorException(
                          "Attribute certificate contains unsupported critical extensions: "
                          + critExtOids);
            }
        }
        /**
         * Checks if an attribute certificate is revoked.
         *
         * @param attrCert Attribute certificate to check if it is revoked.
         * @param paramsPKIX PKIX parameters.
         * @param issuerCert The issuer certificate of the attribute certificate
         *            <code>attrCert</code>.
         * @param validDate The date when the certificate revocation status should
         *            be checked.
         * @param certPathCerts The certificates of the certification path to be
         *            checked.
         *
         * @throws CertPathValidatorException if the certificate is revoked or the
         *             status cannot be checked or some error occurs.
         */
        internal static void CheckCrls(
            IX509AttributeCertificate attrCert,
            PkixParameters paramsPKIX,
            X509Certificate issuerCert,
            DateTime validDate,
            IList certPathCerts)
        {
            if (paramsPKIX.IsRevocationEnabled)
            {
                // check if revocation is available
                if (attrCert.GetExtensionValue(X509Extensions.NoRevAvail) == null)
                {
                    CrlDistPoint crldp = null;
                    try
                    {
                        crldp = CrlDistPoint.GetInstance(
                            PkixCertPathValidatorUtilities.GetExtensionValue(
                                attrCert, X509Extensions.CrlDistributionPoints));
                    }
                    catch (Exception e)
                    {
                        throw new PkixCertPathValidatorException(
                                  "CRL distribution point extension could not be read.", e);
                    }
                    try
                    {
                        PkixCertPathValidatorUtilities
                        .AddAdditionalStoresFromCrlDistributionPoint(crldp, paramsPKIX);
                    }
                    catch (Exception e)
                    {
                        throw new PkixCertPathValidatorException(
                                  "No additional CRL locations could be decoded from CRL distribution point extension.", e);
                    }
                    CertStatus  certStatus  = new CertStatus();
                    ReasonsMask reasonsMask = new ReasonsMask();

                    Exception lastException = null;
                    bool      validCrlFound = false;
                    // for each distribution point
                    if (crldp != null)
                    {
                        DistributionPoint[] dps = null;
                        try
                        {
                            dps = crldp.GetDistributionPoints();
                        }
                        catch (Exception e)
                        {
                            throw new PkixCertPathValidatorException(
                                      "Distribution points could not be read.", e);
                        }
                        try
                        {
                            for (int i = 0; i < dps.Length &&
                                 certStatus.Status == CertStatus.Unrevoked &&
                                 !reasonsMask.IsAllReasons; i++)
                            {
                                PkixParameters paramsPKIXClone = (PkixParameters)paramsPKIX
                                                                 .Clone();
                                CheckCrl(dps[i], attrCert, paramsPKIXClone,
                                         validDate, issuerCert, certStatus, reasonsMask,
                                         certPathCerts);
                                validCrlFound = true;
                            }
                        }
                        catch (Exception e)
                        {
                            lastException = new Exception(
                                "No valid CRL for distribution point found.", e);
                        }
                    }

                    /*
                     * If the revocation status has not been determined, repeat the
                     * process above with any available CRLs not specified in a
                     * distribution point but issued by the certificate issuer.
                     */

                    if (certStatus.Status == CertStatus.Unrevoked &&
                        !reasonsMask.IsAllReasons)
                    {
                        try
                        {
                            /*
                             * assume a DP with both the reasons and the cRLIssuer
                             * fields omitted and a distribution point name of the
                             * certificate issuer.
                             */
                            Asn1Object issuer = null;
                            try
                            {
                                issuer = new Asn1InputStream(
                                    attrCert.Issuer.GetPrincipals()[0].GetEncoded()).ReadObject();
                            }
                            catch (Exception e)
                            {
                                throw new Exception(
                                          "Issuer from certificate for CRL could not be reencoded.",
                                          e);
                            }
                            DistributionPoint dp = new DistributionPoint(
                                new DistributionPointName(0, new GeneralNames(
                                                              new GeneralName(GeneralName.DirectoryName, issuer))), null, null);
                            PkixParameters paramsPKIXClone = (PkixParameters)paramsPKIX.Clone();
                            CheckCrl(dp, attrCert, paramsPKIXClone, validDate,
                                     issuerCert, certStatus, reasonsMask, certPathCerts);
                            validCrlFound = true;
                        }
                        catch (Exception e)
                        {
                            lastException = new Exception(
                                "No valid CRL for distribution point found.", e);
                        }
                    }

                    if (!validCrlFound)
                    {
                        throw new PkixCertPathValidatorException(
                                  "No valid CRL found.", lastException);
                    }
                    if (certStatus.Status != CertStatus.Unrevoked)
                    {
                        // TODO This format is forced by the NistCertPath tests
                        string formattedDate = certStatus.RevocationDate.Value.ToString(
                            "G", new CultureInfo("en-us"));
                        string message = "Attribute certificate revocation after "
                                         + formattedDate;
                        message += ", reason: "
                                   + Rfc3280CertPathUtilities.CrlReasons[certStatus.Status];
                        throw new PkixCertPathValidatorException(message);
                    }
                    if (!reasonsMask.IsAllReasons &&
                        certStatus.Status == CertStatus.Unrevoked)
                    {
                        certStatus.Status = CertStatus.Undetermined;
                    }
                    if (certStatus.Status == CertStatus.Undetermined)
                    {
                        throw new PkixCertPathValidatorException(
                                  "Attribute certificate status could not be determined.");
                    }
                }
                else
                {
                    if (attrCert.GetExtensionValue(X509Extensions.CrlDistributionPoints) != null ||
                        attrCert.GetExtensionValue(X509Extensions.AuthorityInfoAccess) != null)
                    {
                        throw new PkixCertPathValidatorException(
                                  "No rev avail extension is set, but also an AC revocation pointer.");
                    }
                }
            }
        }