0

I have tried several of the usual methods of accessing a rest service using httpclient, urlconnection, etc., to no avail.

I have read countless Stack Overflow articles on how to do this, nothing works in my eclipse mobilefirst/RSA environment. I am running jdk 1.7 with mobilefirst 7.1.1 And RSA 9.1.1.

From what I have read, you have to set the SSLContext to talk to a tls1.2 server...As the same code works fine on other servers. There is only one way I have seen that allows you to set the SSLContext and that is with ClientHTTPBuilder.

So here are a couple of examples:

This example works for this URL...But not the one using tls1.2

URL url = new URL("https://wikipedia.org");
        URLConnection urlConnection = url.openConnection();
        InputStream in = urlConnection.getInputStream();
        str = getStringByBufferedReader(in);

Second example:

SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, null, null);
HttpClientBuilder clientBuilder = HttpClientBuilder.create().setSslcontext(context);
HttpGet request = new HttpGet(baseURL);
request.addHeader("Authorization", basicAuthorization);
request.addHeader("Accept", "text/plain");
CloseableHttpClient httpClient = clientBuilder.build();
CloseableHttpResponse httpResponse = httpClient.execute(request);

Both connection types get the following error:

Exception in Test method = javax.net.ssl.SSLException: Received fatal alert: protocol_version

I have imported the certificate as well. I have also tried jdk 1.8 to no avail.

Remi Guan
  • 21,506
  • 17
  • 64
  • 87
Tim
  • 597
  • 8
  • 18

2 Answers2

0

TLS in JRE7 resolves to TLSv1. Explicitly set protocol to TLSv1.2:

SSLContext context = SSLContext.getInstance("TLSv1.2");

Otherwise your example with HttpClientBuilder is OK.

EDIT:

If you want to disable host name check (it is bad idea in production system):

With Apache httpclient < 4.3:

package hello;

import java.net.URI;

import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;


public class client {

    public static void main(String args[]) throws Exception {

//      System.setProperty("javax.net.debug", "ssl:handshake:verbose");

        SSLSocketFactory socketFactory = null ;

        // Set benevolent host name verifier            
        socketFactory = new SSLSocketFactory( "TLS" , null /* Keystore*/ , 
                null /* keystore passwd */ ,null /* trusts store */ , null , 
                SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER ) ;

        Scheme sch = new Scheme("https", 443, socketFactory);
        DefaultHttpClient httpClient = new DefaultHttpClient() ;        
        httpClient.getConnectionManager().getSchemeRegistry().register(sch);        

        HttpGet request = new HttpGet(new URI("https://www.wikipedia.org/"));
//        request.addHeader("Authorization", basicAuthorization);
//        request.addHeader("Accept", "text/plain");
        CloseableHttpResponse httpResponse = httpClient.execute(request);
        System.out.println(httpResponse.getStatusLine());

        httpClient.close(); 
    }
}

With Apache httpclient >= 4.3:

package hello;

import java.net.URI;
import java.util.Arrays;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;

import sun.security.ssl.SSLSocketFactoryImpl;

public class client {

    public static void main(String args[]) throws Exception {

//      System.setProperty("javax.net.debug", "ssl:handshake:verbose");

        SSLContext context = SSLContext.getInstance("TLSv1.2");
        context.init(null, null, null);

        SSLConnectionSocketFactory sslCF = new SSLConnectionSocketFactory(context, new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                // or add your own test here
                return true;
            }
        });

        CloseableHttpClient httpClient = HttpClientBuilder
                .create()
                .setSSLSocketFactory(sslCF)
                .build();

        HttpGet request = new HttpGet(new URI("https://www.wikipedia.org/"));
//        request.addHeader("Authorization", basicAuthorization);
//        request.addHeader("Accept", "text/plain");
        CloseableHttpResponse httpResponse = httpClient.execute(request);
        System.out.println(httpResponse.getStatusLine());           
    }
}
Michal Foksa
  • 11,225
  • 9
  • 50
  • 68
  • javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name – Tim Jan 07 '16 at 16:05
  • I think now we are getting to the real issue...could this be a certificate issue? The certificate I imported from the server is a self signed cert...not sure if that is allowed in TLS 1.2 or not. I can get this to work via curl with the --insecure option added. It also works from various rest clients for Chrome and Firefox. – Tim Jan 07 '16 at 16:07
  • @tim see e.g. http://stackoverflow.com/questions/7615645/ssl-handshake-alert-unrecognized-name-error-since-upgrade-to-java-1-7-0 – nos Jan 07 '16 at 18:38
  • added System.setProperty ("jsse.enableSNIExtension", "false"); ....now get this error....javax.net.ssl.SSLPeerUnverifiedException: Host name 'xxxx' does not match the certificate subject provided by the peer (EMAILADDRESS=xxx, CN=xxx, OU=SomeOrganizationalUnit, O=SomeOrganization, L=SomeCity, ST=SomeState, C=--) – Tim Jan 07 '16 at 19:12
  • That means you are accessing server over different domain name than the one stated in the server certificate. Quick workaround: add the domain name from certificate into ‘hosts’ file and the server actual IP. Another solution is to disable hostname check in Java. – Michal Foksa Jan 07 '16 at 19:16
  • What version of Apache `httpclient` do you have? – Michal Foksa Jan 07 '16 at 19:52
  • I finally did get it to work using your code in a java project in eclipse. My last comment showed up before your response.... – Tim Jan 08 '16 at 00:02
  • before I hit enter again.....I am very pleased and grateful for your help Michal! The last issue I think I have now is that the hostnameverifyer will not compile inside a mobilefirst java adapter. This appears to be due to mobilefirst using its own jar file instead of httpclient...so I get an error saying that ...The constructor SSLConnectionSocketFactory(SSLContext, new HostnameVerifier(){}) is undefined – Tim Jan 08 '16 at 00:07
  • This works fine outside of Mobilefirst adapter...so trying to figure out a way to get mobilefirst to use httpclient or another way to do this....I have to be able to get this to work in an adapter... – Tim Jan 08 '16 at 00:09
  • How do I enable System.setProperty in a mobilefirst adapter? The ones I used in the java app have no affect. I need to be able to set System.setProperty("jsse.enableSNIExtension", "false"); – Tim Jan 08 '16 at 02:28
0

I was able to fix it with one line in main class:

 System.setProperty("https.protocols", "SSLv3,TLSv1,TLSv1.1,TLSv1.2");
Payam
  • 1,068
  • 12
  • 15