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:
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
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.
You need to trust the server certificate. Here is how to do it:
Using Chrome (instructions for other borwsers may vary):
https://localhost/myService
)Proceed anyway
, click on the padlock icon in your addressbar, and no the popup window, select the Connection
tab and the Certificate Information
link. 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
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With