简体   繁体   中英

web-service client - with keystore

I need to create a web service client with a keystore. But this is the error:

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

My code:

private SSLSocketFactory getFactory() throws Exception {

          File pKeyFile = new ClassPathResource("jks/dex-client-issuer-wss.jks").getFile();

          KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX");
          KeyStore keyStore = KeyStore.getInstance("JKS");

          InputStream keyInput = new FileInputStream(pKeyFile);
          keyStore.load(keyInput, pass.toCharArray());
          keyInput.close();

          keyManagerFactory.init(keyStore, pass.toCharArray());

          SSLContext context = SSLContext.getInstance("TLS");
          context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());

          return context.getSocketFactory();
    }

this is the http conection:

URL url = new URL("https://dexxis-demo1.gemalto.com/DEX/communication/issuer-interface");
        HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
        con.setSSLSocketFactory(getFactory());

I only have a dex-client-issuer-wss.jks file which works with soap ui, how can I create a connection with this certificate file?

'unable to find valid certification path' (during SSL/TLS handshake) has nothing to do with your keystore -- it means that the server cert does not validate against your truststore , which since you passed null as the 2nd arg to context.init is the JRE's default, which is the file specified by sysprop javax.net.ssl.trustStore if set otherwise JRE/lib/security/cacerts (or .../jssecacerts if it exists).

That server is using a cert issued under the root cert Gemalto Business Root Certificate Authority which is not included in the cacerts supplied with Oracle Java packages, or any other established truststores I know, and is not known by the public transparency logs (per https://crt.sh ). SoapUI, presumably because it is designed as a development, test and debug tool, ignores invalid or suspect certs, but a browser or curl or wget on that URL should fail unless the truststore(s) on your system(s) have been modified or are otherwise unusual. OTOH openssl s_client which is also primarily a debug tool reports an error but makes the connection anyway.

If you do want to trust that CA, or one of its (two) intermediates, or the site anyway, you need to have the appropriate cert in your truststore. The usual practice is to trust the root CA cert, but Java supports using any cert in the chain, including the EE cert, as an anchor. Since you are already creating your own context, and keymanager, you might as well create your own trustmanager rather than modifying the JRE default, which is (usually) platform/environment dependent and sometimes tricky. You could fetch the desired cert and put it in a separate keystore file (see below), load that and use it to create a trustmanager. Or since you already have a keystore file for your own key+cert(s), Java supports having both a privateKey entry or entries and a trustedCert entry or entries for other party/parties in the same file, so you could just add their cert to your existing JKS and use the same KeyStore object in a TrustManagerFactory just like you have for KeyManagerFactory to create the trustmanager array for your context.

Easy ways to get the cert are:

  • openssl s_client -showcerts -connect host:port </dev/null (on Windows <NUL: ) -- with port 443; many servers nowadays need the Server Name Indication extension (aka SNI) and for OpenSSL below 1.1.1 you must add -servername host to provide it, but this server doesn't. This outputs a PEM block for each cert from the server, with labels before each showing s: (subjectname) and i: (issuername) . Note that after the first cert, which is as required the EE cert, this server sends the CA certs in top-down order not bottom-up. This is technically in violation of RFC 5246 (or earlier 4346 or 2246); RFC 8446 for TLS1.3 allows it because it was already a common extension, and Java JSSE in particular supports it.

  • keytool -printcert -rfc -sslserver host -- also supports host:port but the default is 443 which is okay for you. This outputs only the PEM blocks, so if you didn't already know from my previous item about the order, you would have to decode each one to find out which is which, or just experiment until you found the correct one.

In either case take the desired PEM block and put it in a file, and do

keytool -importcert -keystore jksfile -alias somealias -file thecertfile

somealias is only required to be unique within the file (which is trivial if you put it in its own file) and case-insensitive (conventionally lowercase), but should be descriptive or mnemonic, and alphanumeric only if possible. Then use the resulting file as above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM