/**
   * Search the given Set of TrustAnchor's for one that is the issuer of the given X509 certificate.
   * Uses the specified provider for signature verification, or the default provider if null.
   *
   * @param cert the X509 certificate
   * @param trustAnchors a Set of TrustAnchor's
   * @param sigProvider the provider to use for signature verification
   * @return the <code>TrustAnchor</code> object if found or <code>null</code> if not.
   * @throws AnnotatedException if a TrustAnchor was found but the signature verification on the
   *     given certificate has thrown an exception.
   */
  protected static TrustAnchor findTrustAnchor(
      X509Certificate cert, Set trustAnchors, String sigProvider) throws AnnotatedException {
    TrustAnchor trust = null;
    PublicKey trustPublicKey = null;
    Exception invalidKeyEx = null;

    X509CertSelector certSelectX509 = new X509CertSelector();
    X500Principal certIssuer = getEncodedIssuerPrincipal(cert);

    try {
      certSelectX509.setSubject(certIssuer.getEncoded());
    } catch (IOException ex) {
      throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex);
    }

    Iterator iter = trustAnchors.iterator();
    while (iter.hasNext() && trust == null) {
      trust = (TrustAnchor) iter.next();
      if (trust.getTrustedCert() != null) {
        if (certSelectX509.match(trust.getTrustedCert())) {
          trustPublicKey = trust.getTrustedCert().getPublicKey();
        } else {
          trust = null;
        }
      } else if (trust.getCAName() != null && trust.getCAPublicKey() != null) {
        try {
          X500Principal caName = new X500Principal(trust.getCAName());
          if (certIssuer.equals(caName)) {
            trustPublicKey = trust.getCAPublicKey();
          } else {
            trust = null;
          }
        } catch (IllegalArgumentException ex) {
          trust = null;
        }
      } else {
        trust = null;
      }

      if (trustPublicKey != null) {
        try {
          verifyX509Certificate(cert, trustPublicKey, sigProvider);
        } catch (Exception ex) {
          invalidKeyEx = ex;
          trust = null;
          trustPublicKey = null;
        }
      }
    }

    if (trust == null && invalidKeyEx != null) {
      throw new AnnotatedException(
          "TrustAnchor found but certificate validation failed.", invalidKeyEx);
    }

    return trust;
  }
  /**
   * Search the given Set of TrustAnchor's for one that is the issuer of the given X509 certificate.
   *
   * @param cert the X509 certificate
   * @param params with trust anchors
   * @return the <code>TrustAnchor</code> object if found or <code>null</code> if not.
   * @exception CertPathValidatorException if a TrustAnchor was found but the signature verification
   *     on the given certificate has thrown an exception. This Exception can be obtainted with
   *     <code>getCause()</code> method.
   */
  static final TrustAnchor findTrustAnchor(
      X509Certificate cert, CertPath certPath, int index, PKIXParameters params)
      throws CertPathValidatorException {
    // If we have a trust anchor index, use it.
    if (params instanceof IndexedPKIXParameters) {
      IndexedPKIXParameters indexed = (IndexedPKIXParameters) params;
      return indexed.findTrustAnchor(cert, certPath, index);
    }

    Iterator iter = params.getTrustAnchors().iterator();
    TrustAnchor found = null;
    PublicKey trustPublicKey = null;
    Exception invalidKeyEx = null;

    X509CertSelector certSelectX509 = new X509CertSelector();

    try {
      certSelectX509.setSubject(getEncodedIssuerPrincipal(cert).getEncoded());
    } catch (IOException ex) {
      throw new CertPathValidatorException(ex);
    }

    byte[] certBytes = null;
    try {
      certBytes = cert.getEncoded();
    } catch (Exception e) {
      // ignore, just continue
    }
    while (iter.hasNext() && found == null) {
      found = (TrustAnchor) iter.next();
      X509Certificate foundCert = found.getTrustedCert();
      if (foundCert != null) {
        // If the trust anchor is identical to the certificate we're
        // done. Just return the anchor.
        // There is similar code in PKIXCertPathValidatorSpi.
        try {
          byte[] foundBytes = foundCert.getEncoded();
          if (certBytes != null && Arrays.equals(foundBytes, certBytes)) {
            return found;
          }
        } catch (Exception e) {
          // ignore, continue and verify the certificate
        }
        if (certSelectX509.match(foundCert)) {
          trustPublicKey = foundCert.getPublicKey();
        } else {
          found = null;
        }
      } else if (found.getCAName() != null && found.getCAPublicKey() != null) {
        try {
          X500Principal certIssuer = getEncodedIssuerPrincipal(cert);
          X500Principal caName = new X500Principal(found.getCAName());
          if (certIssuer.equals(caName)) {
            trustPublicKey = found.getCAPublicKey();
          } else {
            found = null;
          }
        } catch (IllegalArgumentException ex) {
          found = null;
        }
      } else {
        found = null;
      }

      if (trustPublicKey != null) {
        try {
          cert.verify(trustPublicKey);
        } catch (Exception ex) {
          invalidKeyEx = ex;
          found = null;
        }
      }
    }

    if (found == null && invalidKeyEx != null) {
      throw new CertPathValidatorException(
          "TrustAnchor found but certificate validation failed.", invalidKeyEx, certPath, index);
    }

    return found;
  }