private List<X509Certificate> verifyChain(List<X509Certificate> untrustedChain,
            List<TrustAnchor> trustAnchorChain, String host, boolean clientAuth, byte[] ocspData,
            byte[] tlsSctData)
            throws CertificateException {
        try {
            // build the cert path from the list of certs sans trust anchors
            // TODO: check whether this is slow and should be replaced by a minimalistic CertPath impl
            // since we already have built the path.
            CertPath certPath = factory.generateCertPath(untrustedChain);

            // Check that there are at least some trust anchors
            if (trustAnchorChain.isEmpty()) {
                throw new CertificateException(new CertPathValidatorException(
                        "Trust anchor for certification path not found.", null, certPath, -1));
            }

            List<X509Certificate> wholeChain = new ArrayList<>(untrustedChain);
            for (TrustAnchor anchor : trustAnchorChain) {
                wholeChain.add(anchor.getTrustedCert());
            }

            if (pinManager != null) {
                pinManager.checkChainPinning(host, wholeChain);
            }
            // Check whole chain against the blocklist
            for (X509Certificate cert : wholeChain) {
                checkBlocklist(cert);
            }

            // Check Certificate Transparency (if required).
            if (!clientAuth && host != null && ct != null && ct.isCTVerificationRequired(host)) {
                ct.checkCT(wholeChain, ocspData, tlsSctData, host);
            }

            if (untrustedChain.isEmpty()) {
                // The chain consists of only trust anchors, skip the validator
                return wholeChain;
            }

            ChainStrengthAnalyzer.check(untrustedChain);

            // Validate the untrusted part of the chain
            try {
                Set<TrustAnchor> anchorSet = new HashSet<>();
                // We know that untrusted chains to the first trust anchor, only add that.
                anchorSet.add(trustAnchorChain.get(0));
                PKIXParameters params = new PKIXParameters(anchorSet);
                params.setRevocationEnabled(false);
                X509Certificate endPointCert = untrustedChain.get(0);
                setOcspResponses(params, endPointCert, ocspData);
                params.addCertPathChecker(
                        new ExtendedKeyUsagePKIXCertPathChecker(clientAuth, endPointCert));
                validator.validate(certPath, params);
            } catch (InvalidAlgorithmParameterException e) {
                throw new CertificateException("Chain validation failed", e);
            } catch (CertPathValidatorException e) {
                throw new CertificateException("Chain validation failed", e);
            }
            // Add intermediate CAs to the index to tolerate sites
            // that assume that the browser will have cached these.
            // http://b/3404902
            for (int i = 1; i < untrustedChain.size(); i++) {
                intermediateIndex.index(untrustedChain.get(i));
            }
            return wholeChain;
        } catch (CertificateException e) {
            logger.fine("Rejected candidate cert chain due to error: " + e.getMessage());
            throw e;
        }
    }
Recursively build certificate chains until a valid chain is found or all possible paths are
exhausted.
<p>
The chain is built in two sections, the complete trusted path is the the combination of
{@code untrustedChain} and {@code trustAnchorChain}. The chain begins at the leaf
certificate and ends in the final trusted root certificate.

@param certs the bag of certs provided by the peer. No order is assumed.
@param host the host being connected to.
@param clientAuth if a client is being authorized instead of a server.
@param untrustedChain the untrusted section of the chain built so far. Must be mutable.
@param trustAnchorChain the trusted section of the chain built so far. Must be mutable.
@param used the set certificates used so far in path building. Must be mutable.

@return The entire valid chain starting with the leaf certificate. This is the
concatenation of untrustedChain and trustAnchorChain.

@throws CertificateException If no valid chain could be constructed. Note that there may be
multiple reasons why no valid chain exists and there is no guarantee that the most severe is
reported in this exception. As such applications MUST NOT use the specifics of this error
for trust decisions (e.g. showing the user a click through page based on the specific error).
common/src/main/java/org/conscrypt/TrustManagerImpl.java