4
votes

I've been developing a WS client using JAVA and I'm having a problem with SSL authentication. The WS are created on WCF and I have no access to the server, they work through HTTPS and uses a client certificate that needs to be installed on the client first. The server guys sent me a PFX certificate which I successfully installed on the OS (I'm using OS X) and I could then access the WS via a browser (Safari or FF are both that I tried which previously couldn't access the WSs). I thought any app in the OS would use this certs but when I'm tried my JAVA app it didn't work; at first the following error was being thrown:

"javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target"

I solved this by exporting the certificate to a CER file and using the keytool command line tool to add the certificate into the "cacerts" keyStore JAVA uses. But after this error went away the following started appearing: "403, forbidden". This is obviously because it's not using the SSL client cert for the site but I haven't been able to find a way to send it to it. Any help would be appreciated.

The following is the code I use to post to the WS:

URL url = new URL(p_url);

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true);

conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", contentType);

OutputStream out = conn.getOutputStream(); // on this line it shows the error
3

3 Answers

5
votes

You can either create a specific SSLContext (using a KeyManager initialised with the keystore containing your client cert + private key), from which you derive an SSLSocketFactory, which you set into your HttpsURLConnection, or use the global settings.

You could set the following system properties (for the global settings):

  • javax.net.ssl.keyStore=path/to/keystore.pfx
  • javax.net.ssl.keyStoreType=PKCS12
  • javax.net.ssl.keyStorePassword=xxxxxxxxx

Alternatively, you can create your own KeyManagerFactory/KeyManager as described in this answer.

Since you've imported the server certificate in your cacerts, use null for the TrustManager[] argument of SSLContext.init() (it will pick up the default values).

In addition, since you're on OSX, you could use the KeychainStore directly. To do so, use ....keyStore=NONE, keyStoreType=KeychainStore and keyStorePassword=- (any password will do, since access to the key will be granted when you need it from the OS). I'm not sure if it works on Lion, though. Note that it may fail if you have more than one cert+private key in your store (see this issue).

0
votes

Looks like you probably need to set up your own SSL SocketFactory,

http://vafer.org/blog/20061010073725/

I would think things have gotten better since 2006, so you may just need to specify a bunch of properties on the command line:

http://stackoverflow.com/questions/875467/java-client-certificates-over-https-ssl
0
votes

You need to load the keystore they send you in your java application.
You can load it as a file from the file system in a Keystore object and use it. Read this example and especially the part about KeyManager i.e. createKeyManagers method.

Another option would be to load the keystore from windows. Read about Windows-MY provider