Spring RestTemplate: SSL connection failure

I am trying to use sed sed ws with basic auth. I did not import any certificate into the keystore. When I use the chrome plugin Advance Rest client to check it (using base auth with base64 encoding username: pass). I see the answer back. So far, so good. But when I develop Java code to use this ws, I get denied access to SSL:

 org.springframework.web.client.ResourceAccessException: I/O error: Received fatal alert: handshake_failure; nested exception is javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:453) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401) at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:377) at test.Rest.main(Rest.java:37) Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure at sun.security.ssl.Alerts.getSSLException(Unknown Source) at sun.security.ssl.Alerts.getSSLException(Unknown Source) 

My question is: if the problem is that I did not import cert into my keystore, then both the Java code and the plugin should not work together. Here the plugin works, but my code does not. What is the reason? Is there something wrong with my code?

Below is my code

 RestTemplate restTemplate = new RestTemplate(); String plainCreds = "username:pass"; byte[] plainCredsBytes = plainCreds.getBytes(Charset.forName("US-ASCII") ); byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes); String base64Creds = new String(base64CredsBytes); HttpHeaders headers = new HttpHeaders(); headers.add("Authorization", "Basic " + base64Creds); ResponseEntity<String> response = restTemplate.exchange("https://url",HttpMethod.GET,new HttpEntity(headers),String.class); 

Here is the link to the log file: (I am replacing my server_name with XXXXXX) http://www.filedropper.com/ssllog

After launch: openssl s_client -showcerts -tls1 -connect host: port

 WARNING: can't open config file: /usr/local/ssl/openssl.cnf CONNECTED(00000164) 8088:error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number:.\ssl\s3_pkt.c:362: --- no peer certificate available --- No client certificate CA names sent --- SSL handshake has read 5 bytes and written 0 bytes --- New, (NONE), Cipher is (NONE) Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1 Cipher : 0000 Session-ID: Session-ID-ctx: Master-Key: Key-Arg : None PSK identity: None PSK identity hint: None SRP username: None Start Time: 1452011344 Timeout : 7200 (sec) Verify return code: 0 (ok) --- 

and this is the result when I run the openssl s_client -connect server: port command

 WARNING: can't open config file: /usr/local/ssl/openssl.cnf CONNECTED(00000164) depth=0 C = US, ST = "XXXXXX", L = XXXXXX, O = XXXXXX, OU = xxxxx, CN = XXXXXXXXX.test.intranet, emailAddress = xxxxx@xxxxx verify error:num=20:unable to get local issuer certificate verify return:1 depth=0 C = US, ST = "XXXXXXX ", L = XXXXX, O = XXXXXX, OU = xxxxxx, CN = XXXXXXXXX.test.intranet, emailAddress = xxxxx@xxxxx verify error:num=21:unable to verify the first certificate verify return:1 --- Certificate chain 0 s:/C=US/ST=XXXXXXX /L=XXXXX/O=XXXXXX/OU=XXXXX/CN=XXXXXX.test.intranet/ emailAddress=xxxxx@xxxxx i:/DC=intranet/DC=xxxx/CN=XXXXXX DEV Issuing CA --- Server certificate -----BEGIN CERTIFICATE----- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXX..... -----END CERTIFICATE----- subject=/C=US/ST=XXXXXXX /L=XXXXX/O=XXXXXX/OU=XXXXX/CN=XXXXXX.test.intranet/ emailAddress=xxxxx@xxxxx issuer=/DC=intranet/DC=XXX/CN=XXXXX DEV Issuing CA --- No client certificate CA names sent Peer signing digest: SHA512 Server Temp Key: XXXXX, P-256, 256 bits --- SSL handshake has read 1895 bytes and written 443 bytes --- New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256 Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1.2 Cipher : ECDHE-RSA-AES128-GCM-SHA256 Session-ID: 568BF22A5CDBF103155264BBC056B272168AE0777CBC10F055705EB2DD907E5A Session-ID-ctx: Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Key-Arg : None PSK identity: None PSK identity hint: None SRP username: None Start Time: 1452012074 Timeout : 300 (sec) Verify return code: 21 (unable to verify the first certificate) --- read:errno=0 
+5
source share
2 answers

From javax.net.debug log, I see that you are using Java 7, and the client allows TLSv1. From openssl , deduce that your server does not support TLSv1.

TLS ver. 1.1 and 1.2 are disabled in Java 7 by default.

Although SunJSSE in the Java SE 7 release supports TLS 1.1 and TLS 1.2, no version is enabled by default for client connections. Some servers do not provide the correct compatibility; refuse to talk with TLS 1.1 or TLS 1.2 clients. For compatibility, SunJSSE does not include TLS 1.1 or TLS 1.2 by default for a connection client.

Enable TLSv1.1 and TLSv1.2 either:

  • JVM argument:

     -Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1 
  • Or set the same property from Java code:

     System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,TLSv1"); 
  • Or install the JCE Unlimited Strength policy files for Java 7 . I am not 100% sure if this single step will solve the problem, although it is always worth installing JCE, while the JVM allows you to use stronger versions of existing algorithms.

UPDATE 29 / September / 2016 :

The protocol order has been changed from best to worst (TLS versions 1.2 to 1) in options 1 and 2.

+7
source

If you are using Java 7, you need to explicitly tell Java to use the TLSv1.2 protocol. The following is an example of using the Spring XML configuration.

 ***In any Spring bean (ie a controller)*** import org.apache.http.client.HttpClient; import org.apache.http.ssl.SSLContexts; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.HttpClients; import javax.net.ssl.SSLContext; @Bean(name="client") public HttpClient make() throws NoSuchAlgorithmException, KeyManagementException { SSLContext sslContext = SSLContexts.custom().build(); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1.2", "TLSv1.1"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier()); return HttpClients.custom() .setSSLSocketFactory(sslConnectionSocketFactory) .build(); } ***In XML configuration files*** <bean id="factory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory"> <property name="httpClient" ref="client"/> </bean> <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"> <property name="requestFactory" ref="factory"/> </bean> 

You can do the same without XML with something like this:

 RestTemplate restTemplate; public HttpClient getHttpClient() throws NoSuchAlgorithmException, KeyManagementException { SSLContext sslContext = SSLContexts.custom().build(); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1.2", "TLSv1.1"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier()); return HttpClients.custom() .setSSLSocketFactory(sslConnectionSocketFactory) .build(); } public void setUp() throws Exception { restTemplate = new RestTemplate( new HttpComponentsClientHttpRequestFactory( getHttpClient())); ... } 
+1
source

Source: https://habr.com/ru/post/1239655/


All Articles