javax.net.ssl.SSLPeerUnverifiedException: Host name does not match the certificate subject provided by the peer
Asked Answered
K

5

36

I follow many links on stackoverflow and tried many solutions, but none of them worked for me. I'm using WSO2 API manager version 1.9.1. I am facing following error:

Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: Host name 'XXXXXXXXX' does not match the certificate subject provided by the peer (CN=localhost, O=WSO2, L=Mountain View, ST=CA, C=US)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:465)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:395)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
    at com.java.pushNotifications.WSO2DemoClient.main(WSO2DemoClient.java:49)

I developed the following Java code. Please help me what's going wrong here. I need to connect insecure way and allow connections to SSL sites without certs.

public static void main(String[] args) throws ClientProtocolException, IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        SSLContextBuilder builder = new SSLContextBuilder();
        builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());

        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", new PlainConnectionSocketFactory())
                .register("https", sslsf)
                .build();

        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
        cm.setMaxTotal(2000);//max connection

    CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf)
                .setConnectionManager(cm).build();

        HttpGet httpGet = new HttpGet("https://XXXXXXXXXX:8243/token");
        CloseableHttpResponse response = httpclient.execute(httpGet);

        String json =" {\"data\":\"grant_type=password&username=test&password=test123\"}";

        try {
            HttpPost httpost = new HttpPost(url);
            httpost.setHeader("Content-Type", "application/x-www-form-urlencoded");
            httpost.setHeader("Authorization", "Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");

            httpost.setEntity(new StringEntity(json));

            HttpResponse httpResponse = httpclient.execute(httpost);

            System.out.println(httpResponse.getStatusLine());
        }
        finally {
            response.close();
        }

        String responseString1 = new BasicResponseHandler().handleResponse(response);
        System.out.println("Response : "+responseString1);
    }
Karilla answered 7/1, 2016 at 12:22 Comment(3)
You need to compare the host name in the certificate plus the subject alternate names within it + the host name that you call in your code (above "XXXXXXXXXXXXXX"). Those do not seem to match. The concept behind it is the http hostname verification, see linkFiberboard
This only works because you are using the "-k" option which is the same as "--insecure". Then the certificate verification is not done.Fiberboard
See linkFiberboard
A
55

I have spent an hour trying to fix the same issue. This is what I come up with:

final SSLConnectionSocketFactory sslsf;
try {
    sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault(),
            NoopHostnameVerifier.INSTANCE);
} catch (NoSuchAlgorithmException e) {
    throw new RuntimeException(e);
}

final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", new PlainConnectionSocketFactory())
        .register("https", sslsf)
        .build();

final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
cm.setMaxTotal(100);
httpClient = HttpClients.custom()
        .setSSLSocketFactory(sslsf)
        .setConnectionManager(cm)
        .build();

Hopefully, it works and does not use any deprecated code (httpclient 4.4.1).

Aerodyne answered 8/4, 2016 at 19:11 Comment(2)
You save my day! Don't know why this doesn't have much votes... Like 30 min lost with this.Menes
I've been reading about this topic closely since I came across this issue. Thanks for saving me time.Horselaugh
Q
19

Replace this

CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf)
            .setConnectionManager(cm).build();

with

CloseableHttpClient httpclient = HttpClients.custom()
            .setSSLSocketFactory(sslsf)
            .setConnectionManager(cm)
            .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
            .build();

If the certificate isn't signed (not even self-signed), then you can do

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class TrustAllStrategy implements TrustStrategy {
    @Override
    public boolean isTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        return true;
    }
}

Then

builder.loadTrustMaterial(new TrustAllStrategy());

EDIT: this

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
            sslcontext, //for you this is builder.build()
            SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
);
Quadrillion answered 7/1, 2016 at 14:23 Comment(9)
Which version of HttpClient you're suggesting to use for above?Karilla
4.3.x or 4.4.x I think both would work, I haven't used the HttpClient above those versions. I was using 4.3.5.Quadrillion
Thnx, Now I see Exception in thread "main" javax.net.ssl.SSLException: hostname in certificate didn't match: <XX.XX.XX> != <localhost>Karilla
Ah. In that case, it didn't work yet. You need to also give SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER) to your SSLConnectionSocketFactory that you create with new, it's one of the parameters for the constructor.Quadrillion
I am not clear in this? Its not allowing me to add SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER in sslsfKarilla
Let us continue this discussion in chat.Karilla
This is deprecated now, but one can use org.apache.http.conn.ssl.NoopHostnameVerifierInsulting
use NoopHostnameVerifier.INSTANCE instead of the deprecated SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)Democracy
that TrustStrategy can be shortened with a lambdaSheela
G
17

Thanks to all the solutions. I have been trying all the solutions available online for 1.5 days now and finally it worked now. Here is the working code

 SSLContextBuilder builder = new SSLContextBuilder();
 builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
 SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE);
 Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", new PlainConnectionSocketFactory())
            .register("https", sslConnectionSocketFactory)
            .build();

 PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
 cm.setMaxTotal(100);
 CloseableHttpClient httpclient = HttpClients.custom()
            .setSSLSocketFactory(sslConnectionSocketFactory)
            .setConnectionManager(cm)
            .build();
 HttpPost httpPost = new HttpPost(url);
 httpPost.setEntity(postEntity);
 httpPost.expectContinue();
 CloseableHttpResponse response = httpclient.execute(httpPost);
Gigantes answered 11/4, 2017 at 21:24 Comment(0)
T
6

This is what I came up with:

 SSLContextBuilder sslcontext = new SSLContextBuilder();
 sslcontext.loadTrustMaterial(null, new TrustSelfSignedStrategy());
 httpclient = HttpAsyncClients.custom().setSSLContext(sslcontext.build()).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
      .build();
Text answered 14/11, 2016 at 10:48 Comment(0)
B
4

After trying most of the solution suggested on this page and other related stackoverflow discussions, I found AJC's response above works with apache httpclient version 4.5.

Reason: While creating SSLConnectionSocketFactory if the HostVerifier is not specified in the constructor, it does not get set and the DefaultHostVerifier is used. So line 3 of AJC's solutionmakes the difference.

(Atleast this is the behavior in apache httpclient 4.5.3 )

Bolshevism answered 27/10, 2017 at 18:53 Comment(2)
I presume you simply would've commented on AJC's solution, had you enough rep to do so. Nice touch to add the reason to enhance what otherwise could've been accomplished by simply upvoting AJC's solution.Suite
Thanks for this answer. It got me thinking about the reason for the failure. In my case, the server was using a Wildcard certificate and therefore, using the "BrowserCompatHostnameVerifier" fixed the issue for me. The "BrowserCompatHostnameVerifier" allows wildcard certificates just like a Browser would.Stout

© 2022 - 2024 — McMap. All rights reserved.