javarestweb-servicessslcxf

cxf webclient call api using TLSV1


I have a requirement to call and rest endpoint hosted by a third party. their service is only supporting TLSv1 and does not support any newer versions at the moment. I tried to set the webclient configuration to use it to TLSV1 as below.

WebClient client = WebClient
    .create(serviceEndPoint,
        Collections.singletonList(new JacksonJsonProvider()));
client.path(requestTokenService);

HTTPConduit conduit =
    (HTTPConduit) WebClient.getConfig(client).getConduit();
HTTPClientPolicy policy = conduit.getClient();
try {
  SSLContext sslContext = SSLContext.getInstance("TLSv1");
  sslContext.init(null, null, null);
  TLSClientParameters tlsParams = new TLSClientParameters();
  tlsParams.setSSLSocketFactory(sslContext.getSocketFactory());
  tlsParams.setSecureSocketProtocol("TLSv1");
  conduit.setTlsClientParameters(tlsParams);
  logger.info("TLS set to 1.0");
} catch (NoSuchAlgorithmException e) {
  logger.error("Setting the tls failed with  NoSuchAlgorithmException ["+e.getMessage()+"]");
} catch (KeyManagementException e) {
  logger.error("Setting the tls failed with KeyManagementException ["+e.getMessage()+"]");
}
policy.setProxyServer(proxyUrl);
policy.setProxyServerPort(proxyPort);

ClientConfiguration config = WebClient.getConfig(client);

config.getInInterceptors().add(new LoggingInInterceptor());
config.getOutInterceptors().add(new LoggingOutInterceptor());
Response response = client.get();

I'm getting following error when calling the get method.

2018-01-03 05:30:19,207 [eb46095f-71d9-4a3f-98c3-beec8d97dbf5] ERROR [ServiceClass] - Persist failed with error [javax.net.ssl.SSLHandshakeException: SSLHandshakeException invoking https:abc.com/thepath: Server chose TLSv1, but that protocol version is not enabled or not supported by the client.]

A help would be appreciated here on how to enable TLSv1 on this connection.


Solution

  • See Configure Oracle's JDK and JRE Cryptography Algorithms, the section titled How to change the protocol version on client side:

    Several options exist for changing the default client-side TLS protocol version in the JDK.

    Option 1. Use the "jdk.tls.client.protocols" system property

    This property was introduced to JDK 7 in 7u95 and to JDK 6 in 6u121.

    To enable specific TLS protocols on the client, specify them in a comma-separated list within quotation marks; all other supported protocols are then disabled on the client. For example, if the value of this property is "TLSv1.1,TLSv1.2", then the default protocol settings on the client for TLSv1.1 and TLSv1.2 are enabled on the client, while SSLv3, TLSv1, and SSLv2Hello are disabled on the client.

    // Set the client default protocol versions to TLS 1.0, 1.1 and 1.2.
    $ java -Djdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2" myApp
    
    // Set the client default protocol version to TLS 1.0.
    $ java -Djdk.tls.client.protocols="TLSv1" myApp
    

    Note that the standard TLS protocol version names used in the JDK are SSLv3, TLSv1, TLSv1.1 and TLSv1.2.

    Option 2. Use SSLContext to set TLS version

    SSLContext of "TLSv1.2" protocol supports TLS 1.2. For example:

    // Get SSLContext instance for "TLSv1.2".
    SSLContext context = SSLContext.getInstance("TLSv1.2");
    
    // Create SSLEngine object that enables TLS version 1.2.
    SSLEngine sslEngine = context.createSSLEngine("www.example.com", 443);
    

    Or

    // Create SSLSocket object that enables TLS version 1.2.
    SSLSocketFactory socketFac = context.getSocketFactory();
    SSLSocekt sslSocket = (SSLSocekt)socketFac.createSocket("www.example.com", 443);
    
    An SSLContext with "TLSv1" protocol supports TLS versions up to TLS 1.0 (no TLS 1.1 and 1.2).
    An SSLContext created with "TLSv1.1" supports versions up to TLS 1.1 (no TLS 1.2).
    // Get SSLContext instance that supports TLS versions up to TLS 1.0.
    SSLContext context = SSLContext.getInstance("TLSv1");
    

    Option 3. Use the SSLSocket/SSLEngine.setEnabledProtocols() API

    Applications can set the enabled protocols explicitly in an SSLSocket/SSLEngine object. For example:

    // Enable TLS 1.0, 1.1 and 1.2 in an SSLSocket object.
    sslSocket.setEnabledProtocols(new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"});
    
    // Enable TLS 1.0, 1.1 and 1.2 in an SSLEngine object.
    sslEngine.setEnabledProtocols(new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"});
    

    Or

    // Enable TLS 1.0 only in an SSLSocket object.
    sslSocket.setEnabledProtocols(new String[] {"TLSv1"});
    
    // Enable TLS 1.0 only in an SSLEngine object.
    sslEngine.setEnabledProtocols(new String[] {"TLSv1"});
    

    Option 4. Use the SSLParameters.setProtocols() API

    Applications can set the protocols in an SSLParameters object, and then apply it to a connection via the SSLSocket.setSSLParameters() and SSLEngine.setSSLParameters() methods. For example:

    // Set TLS 1.0, 1.1 and 1.2 in an SSLParameters object.
    sslParameters.setProtocols(new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"});
    

    Or

    // Set TLS 1.0 only in an SSLParameters object.
    sslParameters.setProtocols(new String[] {"TLSv1"});
    
    // Apply the parameters to an SSLSocket object.
    sslSocket.setSSLParameters(sslParameters);
    
    // Apply the parameters to an SSLEngine object.
    sslEngine.setSSLParameters(sslParameters);
    

    For client applications, administrators may have to remove TLS 1.1 or TLS 1.2 from the default enabled protocol list to work around a TLS version intolerance issue on the server side.