protected void verifyTrust()

in ws-security-common/src/main/java/org/apache/wss4j/common/crypto/Merlin.java [755:900]


    protected void verifyTrust(
        X509Certificate[] certs,
        boolean enableRevocation,
        Collection<Pattern> subjectCertConstraints
    ) throws WSSecurityException {
        //
        // FIRST step - Search the keystore for the transmitted certificate
        //
        if (certs.length == 1 && !enableRevocation) {
            String issuerString = certs[0].getIssuerX500Principal().getName();
            BigInteger issuerSerial = certs[0].getSerialNumber();

            CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ISSUER_SERIAL);
            cryptoType.setIssuerSerial(issuerString, issuerSerial);
            X509Certificate[] foundCerts = getX509Certificates(cryptoType);

            //
            // If a certificate has been found, the certificates must be compared
            // to ensure against phony DNs (compare encoded form including signature)
            //
            if (foundCerts != null && foundCerts.length > 0 && foundCerts[0] != null && foundCerts[0].equals(certs[0])) {
                try {
                    certs[0].checkValidity();
                } catch (CertificateExpiredException | CertificateNotYetValidException e) {
                    throw new WSSecurityException(
                        WSSecurityException.ErrorCode.FAILED_CHECK, e, "invalidCert"
                    );
                }
                LOG.debug(
                    "Direct trust for certificate with {}", certs[0].getSubjectX500Principal().getName()
                );
                return;
            }
        }

        //
        // SECOND step - Search for the issuer cert (chain) of the transmitted certificate in the
        // keystore or the truststore
        //
        List<Certificate[]> foundIssuingCertChains = null;
        String issuerString = certs[0].getIssuerX500Principal().getName();
        if (certs.length == 1) {

            Object subject = convertSubjectToPrincipal(issuerString);

            if (keystore != null) {
                foundIssuingCertChains = getCertificates(subject, keystore, false);
            }

            //If we can't find the issuer in the keystore then look at the truststore
            if ((foundIssuingCertChains == null || foundIssuingCertChains.isEmpty()) && truststore != null) {
                foundIssuingCertChains = getCertificates(subject, truststore, true);
            }

            if (foundIssuingCertChains == null || foundIssuingCertChains.isEmpty()
                || foundIssuingCertChains.get(0).length < 1) {
                String subjectString = certs[0].getSubjectX500Principal().getName();
                LOG.debug(
                    "No certs found in keystore for issuer {} of certificate for {}",
                     issuerString, subjectString
                );
                throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "certpath", new Object[] {"No trusted certs found"}
                );
            }
        }

        //
        // THIRD step
        // Check the certificate trust path for the issuer cert chain
        //
        LOG.debug(
            "Preparing to validate certificate path for issuer {}", issuerString
        );

        try {
            Set<TrustAnchor> set = new HashSet<>();
            if (truststore != null) {
                addTrustAnchors(set, truststore);
            }

            //
            // Add certificates from the keystore - only if there is no TrustStore, apart from
            // the case that the truststore is the JDK CA certs. This behaviour is preserved
            // for backwards compatibility reasons
            //
            if (keystore != null && (truststore == null || loadCACerts)) {
                addTrustAnchors(set, keystore);
            }

            // Verify the trust path using the above settings
            String provider = getCryptoProvider();
            CertPathValidator validator = null;
            if (provider == null || provider.length() == 0) {
                validator = CertPathValidator.getInstance("PKIX");
            } else {
                validator = CertPathValidator.getInstance("PKIX", provider);
            }

            PKIXParameters param = createPKIXParameters(set, enableRevocation);

            // Generate cert path
            if (foundIssuingCertChains != null && !foundIssuingCertChains.isEmpty()) {
                java.security.cert.CertPathValidatorException validatorException = null;
                // Try each potential issuing cert path for a match
                for (Certificate[] foundCertChain : foundIssuingCertChains) {
                    X509Certificate[] x509certs = new X509Certificate[foundCertChain.length + 1];
                    x509certs[0] = certs[0];
                    System.arraycopy(foundCertChain, 0, x509certs, 1, foundCertChain.length);

                    List<X509Certificate> certList = Arrays.asList(x509certs);
                    CertPath path = getCertificateFactory().generateCertPath(certList);

                    try {
                        validator.validate(path, param);
                        // We have a valid cert path at this point so break
                        validatorException = null;
                        break;
                    } catch (java.security.cert.CertPathValidatorException e) {
                        validatorException = e;
                    }
                }

                if (validatorException != null) {
                    throw validatorException;
                }
            } else {
                List<X509Certificate> certList = Arrays.asList(certs);
                CertPath path = getCertificateFactory().generateCertPath(certList);

                validator.validate(path, param);
            }
        } catch (NoSuchProviderException | NoSuchAlgorithmException
            | CertificateException | InvalidAlgorithmParameterException
            | java.security.cert.CertPathValidatorException
            | KeyStoreException e) {
                throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, e, "certpath"
                );
        }

        // Finally check Cert Constraints
        if (!matchesSubjectDnPattern(certs[0], subjectCertConstraints)) {
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
        }
    }