"Received fatal alert: handshake_failure" when trying to connect to https web service

17,628

If you are not doing a two-way SSL authentication meaning, your server does not care about who the client is so it does not need to check and verify the client certificate; then in that case all you need on the client side is just a trust store which contains a list of trusted server certificates. In your case, your client truststore would just contain the self signed server certificate and thats all. It is usual practice in java to have your truststore in .jks format. If you manage to generate a the truststore then you are set. On the server side you need not worry about the truststore but need to configure the server to have a valid server certificate.

In a two-way SSL authentication, you need keystore and truststore both configured on both the client and server side . Client truststore would remain same as in the case of 1-way authentication. Server truststore should contain the self signed client certificate. Both client and server should be configured to use their respective certificates which they present to each othe during SSL handshake. During handshake both parties verify each other's certificate against their truststore and establish the opposite party's identity. And once the identities are established then you should be able to establish the connection.

For generating stores I would suggest to use a tool called Portecle which can be quite handy.

Share:
17,628
Dave
Author by

Dave

Updated on June 04, 2022

Comments

  • Dave
    Dave almost 2 years

    I want to build a Spring 3 (v 3.1.1.RELEASE) application (on Java 1.6) to communicate with an HTTPS web service, which is using a self-signed certificate that I created. I'm confused about how to set up my truststores and keystones. Using my self-signed certificate, I generated a keystone using the below commands ...

    openssl pkcs12 -export -in server.crt -inkey server.key \
               -out server.p12 -name myalias 
    
    keytool -importkeystore -deststorepass password -destkeypass password -deststoretype jks -destkeystore server.keystore -srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass password -alias myalias
    

    Then I configured my Spring application like so …

        <http-conf:conduit name="*.http-conduit">
                <http-conf:tlsClientParameters secureSocketProtocol="SSL" disableCNCheck="true">
                        <sec:trustManagers>
                            <sec:keyStore type="JKS" password="password" resource="server.keystore" />
                        </sec:trustManagers>
                        <sec:keyManagers keyPassword="password">
                            <sec:keyStore type="pkcs12" password="password" resource="server.p12" />
                        </sec:keyManagers>
                </http-conf:tlsClientParameters>
        </http-conf:conduit>
    
        <jaxws:client id="orgWebServiceClient"
                serviceClass="org.mainco.bsorg.OrganizationWebService" address="${wsdl.url}" />
    

    but when I run my application, I get the below error. What have I missed?

    Caused by: javax.net.ssl.SSLHandshakeException: SSLHandshakeException invoking https://nonprod.cbapis.org/qa2/bsorg/OrganizationService: Received fatal alert: handshake_failure
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) [classes.jar:1.6.0_45]
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) [classes.jar:1.6.0  _45]
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) [classes.jar:1.6.0_45]
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513) [classes.jar:1.6.0_45]
        at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.mapException(HTTPConduit.java:1458) [cxf-rt-transports-http-2.6.0.jar:2.6.0]
        at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1443) [cxf-rt-transports-http-2.6.0.jar:2.6.0]
        at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56) [cxf-api-2.6.0.jar:2.6.0]
        at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:659) [cxf-rt-transports-http-2.6.0.jar:2.6.0]
        at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62) [cxf-api-2.6.0.jar:2.6.0]
        at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:262) [cxf-api-2.6.0.jar:2.6.0  ]
        at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:532) [cxf-api-2.6.0.jar:2.6.0]
        at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:464) [cxf-api-2.6.0.jar:2.6.0]
        at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:367) [cxf-api-2.6.0.jar:2.6.0]
        at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:320) [cxf-api-2.6.0.jar:2.6.0]
        at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:89) [cxf-rt-frontend-simple-2.6.0.jar:2.6.0]
        at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:134) [cxf-rt-frontend-jaxws-2.6.0.jar:2.6.0]
    ... 5 more
    Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) [jsse.jar:1.6]
        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136) [jsse.jar:1.6]
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1822) [jsse.jar:1.6]
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1004) [jsse.jar:1.6]
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1188) [jsse.jar:1.6]
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1215) [jsse.jar:1.6]
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1199) [jsse.jar:1.6]
        at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434) [jsse.jar:1.6]
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166) [jsse.jar:1.6]
        at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1014) [classes.jar:1.6.0_45]
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230) [jsse.jar:1.6]
        at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleHeadersTrustCaching(HTTPConduit.java:1395) [cxf-rt-transports-http-2.6.0.jar:2.6.0]
        at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.onFirstWrite(HTTPConduit.java:1337) [cxf-rt-transports-http-2.6.0.jar:2.6.0]
        at org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:42) [cxf-api-2.6.0.jar:2.6.0]
        at org.apache.cxf.io.AbstractThresholdOutputStream.write(AbstractThresholdOutputStream.java:69) [cxf-api-2.6.0.jar:2.6.0]
        at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1415) [cxf-rt-transports-http-2.6.0.jar:2.6.0]
    ... 15 more
    
  • Rose
    Rose over 8 years
    "then in that case all you need on the client side is just a trust store which contains a list of trusted server certificates" What if you are hitting https servers based on user's input dynamically. So you don't know the servers ahead of time. What would you do in that case?
  • Raymond
    Raymond over 7 years
    Your certificate should be in the keystore, the certificates of the servers whom you are trying to connect should be either in the trust store or the java cert store.