7

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

Community
  • 1
  • 1
TS-
  • 4,311
  • 8
  • 40
  • 52
  • I don't know the exact setup in this case, but if you are signing up or encrypting your messages with your private key, the server should have the public key. If it is only the ssl/tls as the exception suggests, there might be an issue with the server certificate not being trusted? – jhexp Feb 13 '13 at 16:52

2 Answers2

5

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
Carlo Pellegrini
  • 5,656
  • 40
  • 45
  • In this case, the web service client is my tomcat? because my webapp that connects to the web service is running inside tomcat. How do I set tomcat to look at the keystore? – TS- Feb 13 '13 at 18:17
  • Edited as per your request. – Carlo Pellegrini Feb 13 '13 at 18:32
  • Thanks, I made progress ... but seems like now I ran into truststore vs keystore issue – TS- Feb 13 '13 at 20:30
  • Worked fine, but I had to combine it with `HttpsURLConnection.setDefaultHostnameVerifier(...)` to solve the `"Got java.security.cert.CertificateException: No subject alternative names present while opening stream from"` error message. – bvdb Feb 06 '15 at 17:18
3

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);
TS-
  • 4,311
  • 8
  • 40
  • 52