I have an application which connects to SAP systems via SSL. The application makes use of JAX-WS (for Web-Service calls) and Apache HttPComponent 4.5.3 for all other SSL calls. Everything works fine unless I run the application with Java 1.8 131 or 144. I'm getting the following exception:
javax.net.ssl.SSLHandshakeException:
java.security.cert.CertificateException: Certificates does not conform
to algorithm constraints at sun.security.ssl.Alerts.getSSLException(Unknown Source) at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source) at sun.security.ssl.Handshaker.fatalSE(Unknown Source) at sun.security.ssl.Handshaker.fatalSE(Unknown Source) at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source) at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source) at sun.security.ssl.Handshaker.processLoop(Unknown Source) at sun.security.ssl.Handshaker.process_record(Unknown Source) at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source) at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source) at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source) Caused by: java.security.cert.CertificateException: Certificates does not conform to algorithm constraints at
security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(Unknow at
security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(Unknown at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(Unknown
I have read java.security.cert.CertificateException: Certificates does not conform to algorithm constraints but it doesn't apply to my case, because...
- Everything works fine when I connect to SAP server 1
- When connecting to SAP Server 2 afterwards (also via SSL) I get "certificate does not conform" error
- When I reverse the sequence and connect to SAP Server 2 first, everything works fine
- but then I get the same error when I connect to SAP server 1 (which worked before)
- And this problem only occurs with Java 1.8 131 and 144. It works fine with 1.7 and Java 1.8.121
All this indicates to me that the root cause is not a problem with the certificates and ciphers but something is going wrong when mixing JAX-WS and Apache HTTPS calls in Java 1.8.144
This is code for disabling SSL checks for JAX-WS (based on https://log.rowanto.com/java-8-turning-off-ssl-certificate-check/):
public static final void disableCertificateValidationForWebServices() {
    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[] {
new X509ExtendedTrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] 
x509Certificates, String s) { }
        @Override
        public void checkServerTrusted(X509Certificate[] 
x509Certificates, String s) { }
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        @Override
        public void checkClientTrusted(X509Certificate[] 
            x509Certificates, String s, Socket socket) {
        }
        @Override
        public void checkServerTrusted(X509Certificate[] 
            x509Certificates, String s, Socket socket) {
        }
        @Override
        public void checkClientTrusted(X509Certificate[] 
             x509Certificates, String s, SSLEngine sslEngine) {
        }
        @Override
        public void checkServerTrusted(X509Certificate[] 
           x509Certificates, String s, SSLEngine sslEngine) {
        }
    } };
    // Install the all-trusting trust manager
    try {
        final SSLContext sc = SSLContext.getInstance("SSL"); // or TLS?
        sc.init(null, trustAllCerts, new SecureRandom());     
 HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
       .setDefaultHostnameVerifier(NoopHostnameVerifier.INSTANCE);      } catch (Exception e) {
    }
}
and this is the code for disabling SSL checks for the Apache HTTPS calls (based on http://stackoverflow.com/questions/22606579/apache-httpclient-4-3-and-x509-client-certificate-to-authenticate):
public static SSLConnectionSocketFactory getInstance() {
    if (instance == null) {
        Log.info("Disabling SSL Certificate Checks");
        final SSLContextBuilder builder = SSLContexts.custom();
        // here in the loadTrustMaterial the SSL Provider is loaded.
        try {
            builder.loadTrustMaterial(null, new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] arg0, String 
  arg1) {
                    return true;
                }
            });
            final SSLContext sslContext = builder.build();
            instance = new SSLConnectionSocketFactory(sslContext, 
   NoopHostnameVerifier.INSTANCE);
        } catch (NoSuchAlgorithmException e) {
            Log.error("disableCertificateValidation() failed with 
  NoSuchAlgorithmException. Detail message:", e);
            listTrustManagers(null);
        } catch (KeyStoreException e) {
            Log.error("disableCertificateValidation() failed with 
 KeyStoreException. Detail message: ", e);
            listTrustManagers(null);
        } catch (KeyManagementException e) {
            Log.error("disableCertificateValidation() failed with 
  KeyManagementException. Detail message: ", e);
        }
    }
    return instance;
}
And yes, we are using a PoolingConnectionManager:
public final class MyPoolingHttpClientConnectionManager {
private static PoolingHttpClientConnectionManager instance = null;
private final static Object LOCK = new Object();
protected MyPoolingHttpClientConnectionManager() {
    // Exists only to defeat instantiation.
}
public static PoolingHttpClientConnectionManager getInstance() {
    synchronized (LOCK) {
        if (instance == null) {
            instance = new 
PoolingHttpClientConnectionManager(disableCertificateValidation());
            // Increase max total connection to 50
            instance.setMaxTotal(50);
            // Increase default max connection per route to 20
            instance.setDefaultMaxPerRoute(20);
        }
    }
    return instance;
}
/*
 * This is called when we create the HTTPConnectionPool
 * 
 * 
 */
private final static Registry<ConnectionSocketFactory> 
disableCertificateValidation() {
    return RegistryBuilder.<ConnectionSocketFactory>
create().register("https", MySSLContext.getInstance())
            .register("http", new 
 PlainConnectionSocketFactory()).build();
}
}
Any ideas are highly welcome
