ews-java-api icon indicating copy to clipboard operation
ews-java-api copied to clipboard

How to trust SSL certificate?

Open bvn13 opened this issue 5 years ago • 7 comments

Our Exchange Server is hosted on domain with self-signed certificate therefore I have this exception:

Caused by: microsoft.exchange.webservices.data.core.exception.service.remote.ServiceRequestException: The request failed. sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at microsoft.exchange.webservices.data.core.request.ServiceRequestBase.getEwsHttpWebResponse(ServiceRequestBase.java:729) ~[ews-java-api-2.0.jar:na]
	at microsoft.exchange.webservices.data.core.request.ServiceRequestBase.validateAndEmitRequest(ServiceRequestBase.java:639) ~[ews-java-api-2.0.jar:na]
	at microsoft.exchange.webservices.data.core.request.SimpleServiceRequestBase.internalExecute(SimpleServiceRequestBase.java:62) ~[ews-java-api-2.0.jar:na]
	... 18 common frames omitted
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ~[na:1.8.0_222]
	at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1946) ~[na:1.8.0_222]
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316) ~[na:1.8.0_222]
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310) ~[na:1.8.0_222]
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639) ~[na:1.8.0_222]
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223) ~[na:1.8.0_222]
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037) ~[na:1.8.0_222]
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:965) ~[na:1.8.0_222]
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064) ~[na:1.8.0_222]
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367) ~[na:1.8.0_222]
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395) ~[na:1.8.0_222]
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379) ~[na:1.8.0_222]
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.conn.BasicHttpClientConnectionManager.connect(BasicHttpClientConnectionManager.java:313) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) ~[httpclient-4.5.10.jar:4.5.10]
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) ~[httpclient-4.5.10.jar:4.5.10]
	at microsoft.exchange.webservices.data.core.request.HttpClientWebRequest.executeRequest(HttpClientWebRequest.java:292) ~[ews-java-api-2.0.jar:na]
	at microsoft.exchange.webservices.data.core.request.ServiceRequestBase.getEwsHttpWebResponse(ServiceRequestBase.java:720) ~[ews-java-api-2.0.jar:na]
	... 20 common frames omitted
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397) ~[na:1.8.0_222]
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302) ~[na:1.8.0_222]
	at sun.security.validator.Validator.validate(Validator.java:262) ~[na:1.8.0_222]
	at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:330) ~[na:1.8.0_222]
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:237) ~[na:1.8.0_222]
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:113) ~[na:1.8.0_222]
	at microsoft.exchange.webservices.data.core.EwsX509TrustManager.checkServerTrusted(EwsX509TrustManager.java:83) ~[ews-java-api-2.0.jar:na]
	at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:1099) ~[na:1.8.0_222]
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621) ~[na:1.8.0_222]
	... 40 common frames omitted
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) ~[na:1.8.0_222]
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[na:1.8.0_222]
	at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) ~[na:1.8.0_222]
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392) ~[na:1.8.0_222]
	... 48 common frames omitted

How to trust self-signed certificate?

bvn13 avatar Oct 21 '19 13:10 bvn13

Ok. I found a solution creating TrustAllTrustManager. Will a PR be reviewed and accepted if I create it? Willn't it be a your policy violation?

bvn13 avatar Oct 21 '19 15:10 bvn13

How do we trust server's self signed certificate? We are currently having this issue.

rashad-farajullayev avatar May 05 '20 08:05 rashad-farajullayev

This can be solved outside of this library I think. All you need to do is add the self-signed certificate to the trust store of the jre being used by the client.

https://docs.oracle.com/cd/E76310_01/pdf/1411/html/merch_sg/apps-chapter%207.htm#CHDJBIJD

davidmoten avatar May 07 '20 03:05 davidmoten

By the way if you don't want to change the jre truststore you can also do this sort of thing locally in a webapp by modifying the SSLContext to use a truststore from the classpath (optionally extending the default truststore from the jre). Let me know if you need the code.

davidmoten avatar May 07 '20 03:05 davidmoten

We are using system property to set trust-store and key-store. -Djavax.net.ssl.truststore=FILE_PATH_TS -Djavax.net.ssl.keystore=FILE_PATH_KS

and corresponding passwords

dvgaba avatar May 14 '20 03:05 dvgaba

By the way if you don't want to change the jre truststore you can also do this sort of thing locally in a webapp by modifying the SSLContext to use a truststore from the classpath (optionally extending the default truststore from the jre). Let me know if you need the code.

Could you provide a sample code how to do this? Thanks in advance!

peter-szrnka avatar Jul 02 '20 20:07 peter-szrnka

@szrnka-peter

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;

public final class ExtendedTrustManager extends X509ExtendedTrustManager {

    private final X509TrustManager defaultTm;
    private final X509TrustManager customTm;

    public ExtendedTrustManager(InputStream trustStoreInputStream, char[] trustStorePassword) {
        try {
            X509TrustManager defaultTm = null;
            {
                TrustManagerFactory tmf = TrustManagerFactory
                        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
                tmf.init((KeyStore) null);
                for (TrustManager tm : tmf.getTrustManagers()) {
                    if (tm instanceof X509TrustManager) {
                        defaultTm = (X509TrustManager) tm;
                        break;
                    }
                }
            }
            this.defaultTm = defaultTm;
            final KeyStore trustStore;
            trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(trustStoreInputStream, trustStorePassword);

            TrustManagerFactory tmf = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(trustStore);
            X509TrustManager customTm = null;
            for (TrustManager tm : tmf.getTrustManagers()) {
                if (tm instanceof X509TrustManager) {
                    customTm = (X509TrustManager) tm;
                    break;
                }
            }
            this.customTm = customTm;
        } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
                | IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        defaultTm.checkClientTrusted(chain, authType);
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        try {
            customTm.checkServerTrusted(chain, authType);
        } catch (CertificateException e) {
            defaultTm.checkServerTrusted(chain, authType);
        }

    }

    @Override
    public final X509Certificate[] getAcceptedIssuers() {
        return defaultTm.getAcceptedIssuers();
    }

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)
            throws CertificateException {
        checkClientTrusted(chain, authType);
    }

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
            throws CertificateException {
        checkClientTrusted(chain, authType);
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)
            throws CertificateException {
        checkServerTrusted(chain, authType);
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
            throws CertificateException {
        checkServerTrusted(chain, authType);
    }

    public static SSLContext createTlsContextWithExtendedTrustManager(InputStream trustStore,
            String trustStorePassword) throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        TrustManager trustManager = new ExtendedTrustManager(trustStore,
                trustStorePassword.toCharArray());
        TrustManager[] trustManagers = new TrustManager[] { trustManager };
        sslContext.init(null, trustManagers, new java.security.SecureRandom());
        return sslContext;
    }

}

To use:

String trustStorePassword = ...;
SSLContext context;
try (InputStream is = SomeClass.class.getResourceAsStream("/trustStore.jks")) {
    context = ExtendedTrustManager.createTlsContextWithExtendedTrustManager(is,
                    trustStorePassword);
}
SSLSocketFactory factory = context.getSocketFactory();
Socket socket = factory.createSocket(host, port);
socket.setKeepAlive(true);
socket.setSoTimeout(readTimeoutMs);
Reader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

davidmoten avatar Jul 04 '20 07:07 davidmoten