Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling WebService and having SSL / cert issue

Tags:

java

soap

tomcat

I'll begin with the fact that I have not much knowledge about setting up keystore, etc in Java

I am trying to call a SOAP web service, I got the wsdl, generated the code, etc. Everything seems okay until I deployed it and trying to trigger the WS call.

Here's my setup:

  • Tomcat 7.0.35
  • Java, jdk 1.6.0_39
  • pfx file and the password
  • project deployed as standard web app (war) to tomcat

When I run the code, I got the following exception:

Caused by: javax.net.ssl.SSLHandshakeException: SSLHandshakeException invoking https://tallyservices-qa.olson.com/tallyDemo2WebServices/tallyDemo2/sms: Received fatal alert: certificate_unknown
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.mapException(HTTPConduit.java:1336)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1320)
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:622)
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
    ... 27 more
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1837)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1019)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1203)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1230)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1214)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1031)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
    at org.apache.cxf.transport.http.URLConnectionHTTPConduit$URLConnectionWrappedOutputStream.setupWrappedStream(URLConnectionHTTPConduit.java:170)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleHeadersTrustCaching(HTTPConduit.java:1280)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.onFirstWrite(HTTPConduit.java:1231)
    at org.apache.cxf.transport.http.URLConnectionHTTPConduit$URLConnectionWrappedOutputStream.onFirstWrite(URLConnectionHTTPConduit.java:183)
    at org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:47)
    at org.apache.cxf.io.AbstractThresholdOutputStream.write(AbstractThresholdOutputStream.java:69)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1293)
    ... 30 more

I followed the suggestion here: How to convert .pfx file to keystore with private key? to install the cert to my keystore:

keytool -importkeystore -srckeystore C:\somefolder\mypfxfile.pxf -srcstoretype pkcs12 
-destkeystore C:\somefolder\clientcert.jks -deststoretype JKS

and I got:

Enter destination keystore password: <mypassword>
Re-enter new password: <mypassword>
Enter source keystore password: <pxf_password>
Entry for alias 67eb31f6 successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or
cancelled

So everything looks good so far, I bounced my tomcat and hitting the Servlet again and I still get the same error.

What else am I missing here? Do I need to tell tomcat about the certificate or something?

Thanks in advance for the help and apology for my noob-ness in keystore and certificate area.

EDIT: So I figured from Carlo Pellegrini`s help, that I need to add the keystore to tomcat: so now, my tomcat is started with additional JAVA_OPTS parameter:

"-Djavax.net.ssl.trustStore=C:\somefolder\clientcert.jks -Djavax.net.ssl.trustStorePassword=somepassword"

and now I got:

Caused by: javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

From here: Error - trustAnchors parameter must be non-empty and got java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty when using cas - seems like my truststore is not found?

I figured my earlier command:

keytool -importkeystore -srckeystore C:\somefolder\mypfxfile.pxf -srcstoretype pkcs12 -destkeystore C:\somefolder\clientcert.jks -deststoretype JKS

Actually put the pxf into the keystore, not the truststore ?

When I check keystore list:

C:\somefolder>keytool -list -keystore "C:\somefolder\clientcert.jks"
Enter keystore password:

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

67eb31f6, 13-Feb-2013, PrivateKeyEntry,
Certificate fingerprint (MD5): ... some fingerprint ...

So I am not sure what am I missing here

like image 923
TS- Avatar asked Feb 13 '13 16:02

TS-


People also ask

Who needs SSL certificate in web service?

Companies and organizations need to add SSL certificates to their websites to secure online transactions and keep customer information private and secure. In short: SSL keeps internet connections secure and prevents criminals from reading or modifying information transferred between two systems.


2 Answers

You need to trust the server certificate. Here is how to do it:

Using Chrome (instructions for other borwsers may vary):

  • Surf to the service site. (example. https://localhost/myService)
  • If the browser does not trust it, click Proceed anyway, click on the padlock icon in your addressbar, and no the popup window, select the Connection tab and the Certificate Information link.
  • This should open the certificate viewer window where, selecting Details, you should view the Export ... button. Select Base 64 encoded, single certificate and save it as mysite.cer file.

This gets the certificate, now you need to import it in the truststore.

Now import the certificate in a keystore:

keytool -import -file mysite.cer -keystore mykeystore

This creates a new file keystore file mykeystore in the current directory.

Finally launch the web service client application using the JVM parameter javax.net.ssl.trustStore as in:

java -Djavax.net.ssl.trustStore=mykeystore ... MyClientClass

Or if you are using Tomcat in Windows:

set JAVA_OPTS=-Djavax.net.ssl.trustStore=mykeystore
startup.bat

Or if you are using Tomcat in Unix:

export JAVA_OPTS="-Djavax.net.ssl.trustStore=mykeystore"
startup.sh
like image 195
Carlo Pellegrini Avatar answered Oct 13 '22 06:10

Carlo Pellegrini


I found solution, I should be using keyStore rather than trustStore, but more importantly, there seem to be problem with the library I am using (cxf 2.7.1) that I have to set up the SSL property directly in the code:

// BEGIN FIX to avoid certificate error, need to set this up in the code for cxf
String storePath = System.getProperty("javax.net.ssl.keyStore");
String storePassword = System.getProperty("javax.net.ssl.keyStorePassword");
String storeType = System.getProperty("javax.net.ssl.keyStoreType");
KeyStore keyStore = KeyStore.getInstance(storeType);
keyStore.load(new FileInputStream(storePath), storePassword.toCharArray());
KeyManagerFactory factory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
factory.init(keyStore, storePassword.toCharArray());
KeyManager[] keyManagers = factory.getKeyManagers();
Client client = ClientProxy.getClient(port);
HTTPConduit conduit = (HTTPConduit) client.getConduit();
conduit.setTlsClientParameters(new TLSClientParameters());
conduit.getTlsClientParameters().setKeyManagers(keyManagers);
like image 40
TS- Avatar answered Oct 13 '22 07:10

TS-