3

I'm trying to call POST Rest call using Spring RestTemplate:

HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();

RestTemplate restTemplate = new RestTemplate(requestFactory);

HttpHeaders headers = new HttpHeaders();

headers.setContentType(MediaType.APPLICATION_XML);

HttpEntity<GetBalanceHistoryRequest> request1 = new     HttpEntity<GetBalanceHistoryRequest>(request, headers);
String result = restTemplate.postForObject("https://server.com/getBalance", request1, String.class);

The https://server.com have a certificate :webapi.tartu-x86.p12 I import the certificate to C:\Java_8\jre\lib\security\cacerts usinf keytool

after running my code i get the following error:

SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
trustStore is: C:\Java_8\jre\lib\security\cacerts
trustStore type is : jks
trustStore provider is : 
init truststore
adding as trusted cert:
  Subject: CN=Equifax Secure Global eBusiness CA-1, O=Equifax Secure Inc., C=US
  Issuer:  CN=Equifax Secure Global eBusiness CA-1, O=Equifax Secure Inc., C=US
  Algorithm: RSA; Serial number: 0xc3517
  Valid from Mon Jun 21 07:00:00 IDT 1999 until Mon Jun 22 07:00:00 IDT 2020

adding as trusted cert:
  Subject: CN=SecureTrust CA, O=SecureTrust Corporation, C=US
  Issuer:  CN=SecureTrust CA, O=SecureTrust Corporation, C=US
....
....

** Finished
verify_data:  { 31, 64, 180, 145, 192, 1, 180, 119, 86, 70, 247, 140 }
***
[write] MD5 and SHA1 hashes:  len = 16
0000: 14 00 00 0C 1F 40 B4 91   C0 01 B4 77 56 46 F7 8C  [email protected]..
Padded plaintext before ENCRYPTION:  len = 48
0000: 14 00 00 0C 1F 40 B4 91   C0 01 B4 77 56 46 F7 8C  [email protected]..
0010: 3F 56 B1 14 65 F3 18 C6   B3 98 D3 50 65 AC 74 1A  ?V..e......Pe.t.
0020: 48 11 50 C0 0B 0B 0B 0B   0B 0B 0B 0B 0B 0B 0B 0B  H.P.............
main, WRITE: TLSv1 Handshake, length = 48
[Raw write]: length = 53
0000: 16 03 01 00 30 B6 A0 43   3D 91 3A C1 F6 34 F5 73  ....0..C=.:..4.s
0010: 54 A7 1A 46 84 42 1A DC   0D 4D B9 4A C1 3F CB A6  T..F.B...M.J.?..
0020: 57 C6 5D DF C4 1D 62 22   92 FB 1F 3E F1 05 0C 5C  W.]...b"...>...\
0030: 56 9E 9B 02 2D                                     V...-
[Raw read]: length = 5
0000: 15 03 01 00 02                                     .....
[Raw read]: length = 2
0000: 02 28                                              .(
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT:  fatal, handshake_failure
%% Invalidated:  [Session-1, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA]
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received                 fatal alert: handshake_failure
 main, called close()
 main, called closeInternal(true)

I'm using Java 1.8.0_91

any one can help here?

2 Answers 2

4

The cause of java SSL problems like handshake_failure are usually these:

  • Incompatible cipher suites: The client has to use a cipher suite enabled by the server
  • Incompatible versions of SSL/TLS: The client have to ensure that it uses a compatible version. For example the server might force TLS1.2 that is not enabled by default in java7 (not is your case)
  • Incomplete trust path for the server certificate: the server certificate is probably not trusted by the client. Usually the fix is to import the server certificate chain in into the client trust store.
  • Bad server config, like certificate issued to a different domain or certificate chain incomplete. In the case the fix is on server part

In your case seems that has been selected TLSv1 when java8 use TLSv1.2 by default, so is possible that the server is not updated with latest versions.

I suggest to debug the protocol messages ClientHello and ServerHello to watch the selected protocol and cipher from the suite.

-Djavax.net.debug=ssl

Also you can check the status of your server in SSLLabs

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your replay, how could i tell java to use TLSv1 ?
java8 will use TLSv1.2 by default, but if it is not available, it will use TLSv1.1 or TLSv1. If the connection is selecting TLSv1 it is because the server does not support TLSv1.2 or no ciphers in common
0

I had same problem and i solved this way:

1 - Convert your p12 file to a Java KeyStore file (.jks extension) and put in resources folder of your project:

keytool -importkeystore -srckeystore <pfxfilename.pfx> -srcstoretype pkcs12 -destkeystore <jks-filename.jks> -deststoretype JKS

2 - Implement a Request Factory to use you JKS file:

RestTemplate restTemplate = new RestTemplate();

ClientHttpRequestFactory requestFactory = null;
try {
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(
            this.getClass().getClassLoader().getResourceAsStream("jks-filename.jks"), //put your .jks file name here.
            "password".toCharArray()); //the .jks file password.

    SSLConnectionSocketFactory socketFactory = 
            new SSLConnectionSocketFactory(
                    new SSLContextBuilder()
                    .loadTrustMaterial(null, new TrustSelfSignedStrategy())
                    .loadKeyMaterial(keyStore, "password".toCharArray()).build()); //the .jks file password again...

    HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
    requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

} catch (Exception e) {
    e.printStackTrace();
}

restTemplate.setRequestFactory(requestFactory);

3 - You may need to add Apache Httpclient to your project. In a Gradle project, add:

compile ("org.apache.httpcomponents:httpclient")

Ready!

Another fast solution is just generate the JKS file and put the file and password as JVM parameter:

-Djavax.net.ssl.keyStore=/absolute/file/location/java/application/keystore.jks
-Djavax.net.ssl.keyStorePassword=jkspassword

or put in a java class static block:

System.setProperty("javax.net.ssl.keyStore", "/absolute/file/location/java/application/keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "jkspassword");

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.