0

Apologies for yet another "unable to find certificate" question.

I'm developing on a Windows 7 machine. I am using multiple Java versions and because of that am explicit about paths to the used java version (here Java6). I achieve this by the following two lines:

set path=c:\Program Files\Java\jdk1.6.0_45\bin;%path%
set java_home=c:\Program Files\Java\jdk1.6.0_45

I need to use a 3rd party web service https://service.gov/Service.svc?wsdl that provides a certificate.PFX certificate (both service URI and certificate file are renamed as a way to protect the 3rd party's interests). I have made sure that after importing the certificate file in Windows I can open the WSDL file in my browser.

I first import the certificate in my keystore (using Administrator Command Prompt to get access to write in the system folder):

keytool -importkeystore -srckeystore certificate.pfx -srcstoretype pkcs12 -keystore "c:\Program Files\Java\jdk1.6.0_45\jre\lib\security\cacerts"

I get a success notification. Still, I make sure that the new certificate is present in the output of:

keytool -list -keystore "c:\Program Files\Java\jdk1.6.0_45\jre\lib\security\cacerts"

Then I create a new folder containing blank subfolders called src and classes. Once this is done, I run wsimport from that new folder (using Java class instead of binary to make sure I am explicit about the truststore being used):

java -classpath "c:\Program Files\Java\jdk1.6.0_45\lib\tools.jar" -Djavax.net.ssl.trustStore="c:\Program Files\Java\jdk1.6.0_45\jre\lib\security\cacerts" -Djavax.net.ssl.trustStorePassword=changeit com.sun.tools.internal.ws.WsImport https://service.gov/Service.svc?wsdl -s src -d classes

The output is the following:

parsing WSDL...

[ERROR] sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Failed to read the WSDL document: https://service.gov/Service.svc?wsdl, because 1) could not find the document; /2) the document could not be read; 3) the root element of the document is not <wsdl:definitions>.

[ERROR] failed.noservice=Could not find wsdl:service in the provided WSDL(s):

At least one WSDL with at least one service definition needs to be provided.

Failed to parse the WSDL.

The WSDL file contains and is used by other organisations, so the problem is pretty certainly not on the 3rd party's side.

Am I missing something? To me it all seems obvious by now, but it still doesn't work. I have also tried this with Java8, and the result is pretty much the same. The only difference is that in Java8, the WsImport class no longer exists, so I am using the wsimport.exe binary.

Thanks in advance for any ideas or hints.

mapto
  • 605
  • 9
  • 23

1 Answers1

1

The pfx file (which contains a certificate and also a private key) is for client authentication, while a truststore is for validating the server certificate. It is important to understand the difference between a keystore and a truststore.

You have imported the client certificate (and key) into the default truststore (cacerts). What you should have done instead is:

  1. Import the issuer (CA) of the SSL certificate of the server into cacerts. You can skip this step if the CA certificate is already in cacerts, which is probably the case here.
  2. Use the pfx file as your keystore for client authentication. The easiest way is to convert it to jks: https://stackoverflow.com/a/3054034/2672392 The properties to pass to wsimport are "javax.net.ssl.keyStore" and "javax.net.ssl.keyStorePassword".

See this answer for a list of important SSL properties: https://stackoverflow.com/a/5871352/2672392

Community
  • 1
  • 1
Omikron
  • 4,072
  • 1
  • 27
  • 28
  • I have been only provided client certificate. How can I get the server certificate? I've tried to get it from the browser when I open the WSDL, but it looks very similar to my client certificate and I cannot verify that it is not the same. I am now working with their test environment, so it is very probable that the certificate is self-issued (thus the "unable to find valid certification path to requested target" part). – mapto Apr 11 '16 at 17:03
  • 1
    @mapto Yes, you can simply get the server certificate from the browser. It does not really matter if it is self-signed or not. In both cases you have to add the issuer to the truststore. If it is self-signed, the issuer is the certificate itself. – Omikron Apr 11 '16 at 17:11
  • While debugging this the stub TrustManager provided in this link (https://gist.github.com/michalbcz/4170520) was also very useful. Still, it is a security vulnerability to use it in a production environment. – mapto Apr 13 '16 at 15:44