Bas Velden
Bas Velden

Reputation: 428

Java can't send https request "unable to find valid certification path"

I am trying to access a sandbox api over https: https://api-sandbox.rabobank.nl/openapi/sandbox but I get this error when sending request: https://pastebin.com/5X4h3wsu

I tried adding the certificate from above mentioned url to jre11, jdk8, jdk7 truststores and tried switching my project jdk/jre to those versions. the error doesn't change however. I also tried setting this as vm options: -Dcom.sun.net.ssl.checkRevocation=false also no luck. when i enable: -Djavax.net.debug=ssl (with java 8, option doesn't work with 11) I got this output to console: https://pastebin.com/5L7Lei8J

And here's all my code, it's not much because this app was meant to test the api with a minimal working example. Application.java:

package com.thebooks;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.security.KeyStore;

@SpringBootApplication
public class Application {

    static {
        System.setProperty("jdk.tls.client.protocols", "TLSv1.2");
        System.setProperty("https.protocols", "TLSv1.2");
        System.setProperty("javax.net.ssl.trustStore", System.getProperty("user.dir") + "/key/cert.p12");
        System.setProperty("javax.net.ssl.trustStorePassword", "secret");
        System.setProperty("javax.net.ssl.keyStore",  System.getProperty("user.dir") + "/key/key.p12");
        System.setProperty("javax.net.ssl.keyStorePassword", "secret");

        javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
                new javax.net.ssl.HostnameVerifier() {

                    public boolean verify(String hostname,
                                          javax.net.ssl.SSLSession sslSession) {
                        // TODO: CODE TO VERIFY Host
                        return true;
                    }
                });
    }

    @Bean
    public RestTemplate template() throws Exception {
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

HttpClient.java:

package com.thebooks.httpclient;

import com.thebooks.enums.EScope;
import com.thebooks.providers.PropertyProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component
public class HttpClient implements CommandLineRunner {
    private String apiUrl = "https://api-sandbox.rabobank.nl/openapi/sandbox/";

    private final RestTemplate template;
    private PropertyProvider propProvider = new PropertyProvider();
    private final String CLIENT_ID = propProvider.get("client.id");

    public HttpClient(RestTemplate template) {
        this.template = template;
    }

    @Override
    public void run(String... args) throws Exception {
        ResponseEntity<Object> response = template.getForEntity(
                apiUrl + "oauth2/authorize?client_id=" + CLIENT_ID +
                        "&response_type=code&scope=" + EScope.AIS_BALANCES_READ.getValue(),
                Object.class);
        System.out.println(response.getStatusCode());
        System.out.println(response.getBody());
        System.out.println(response.getHeaders());
    }
}

I got most of this code from this website who owns the api I'm trying to use: https://developer-sandbox.rabobank.nl/mutual-tls I'm pretty sure it has to do with their certificate not being trusted by my pc/app. But like I said I added their certificate to all 3 cacerts of all 3 versions of java that I have...

Upvotes: 0

Views: 1518

Answers (2)

Bimlendu
Bimlendu

Reputation: 21

The api sandbox URL has certs issued by Digicert, which is a valid CA provider. But as per the spring boot starter code, you are starting a server with a self signed cert. As a result, the PKIK exception comes in when handshaking is being done in between a CA signed SSL and Non-CA signed certificate.

Please include the the cert that you are using in the spring boot start and include in the cacert file of java.

Th real essence of a SSL is the handshaking, where they exchange encryption key. Data between two SSL enabled sites happen where first they exchange encryption key and going ahead they use that encryption key to encrypt data. And they do not have decryption key (same as a SSH ).

@BasVelden basically for JAVA to trust any custom generated (NON-CA generated) key, we do the following:

keytool -import -trustcacerts -noprompt -keystore <full path to cacerts> -storepass changeit -alias $REMHOST -file $REMHOST.pem

Now, explanation for the above code is : keytool is a java provided utility : normall the location is $JAVA_HOME/jre/lib/security/cacerts. And it has entry of all the verified (CA) certificate providers. You are modifying this entry

System.setProperty("javax.net.ssl.trustStore", System.getProperty("user.dir") + "/key/cert.p12");
        System.setProperty("javax.net.ssl.trustStorePassword", "secret");

Modifying cacerts file is ok, but you should not remove the original entries. So , removing that entry helped you rather than providing path to your version provider, you should provide the above path of all the providers.

Upvotes: 1

EOhm
EOhm

Reputation: 656

What I see in Your logs is:

trustStore is: C:\Projects\Java\rabobank-test\key\cert.p12
trustStore type is : jks
trustStore provider is :
init truststore
adding as trusted cert:
  Subject: CN=BAS, O=Internet Widgits Pty Ltd, L=rotterdam, ST=Zuid-Holland, C=NL
  Issuer:  CN=BAS, O=Internet Widgits Pty Ltd, L=rotterdam, ST=Zuid-Holland, C=NL
  Algorithm: RSA; Serial number: 0x28038baf12a3bb7ac23561ced39bccfcd39f4320
  Valid from Sat Oct 05 01:53:40 CEST 2019 until Sun Oct 04 01:53:40 CEST 2020

 keyStore is : C:\Projects\Java\rabobank-test/key/key.p12
...

That is, You have had only one self-signed certificate in trusstore. But the server is using:

*** Certificate chain
chain [0] = [
[
  Version: V3
  Subject: CN=api-sandbox.rabobank.nl, OU=IT Infrastructure, O=Cooperatieve Rabobank U.A., L=Utrecht, ST=Utrecht, C=NL
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

  Key:  Sun RSA public key, 2048 bits
  modulus: 27656546023135416343313786390568312089793225750931433930372419682926699102088570108432798752674580685572610333594008304037355692016847885153850390570343526804649453871166596416120002483261389717541107277089107192149483397960566607102497541257381555870488778889499740452903944947628925771418610305207680346062007754393210604748206767028477705328447039960783496889675884109837662283459562174450768283022227873621702545924115688805804041495718666206232889227995689049914624465380330588827667219738388577693826776185042246003908945385397658276988973592052614956050490934357249690728764920020238886239735311604792591584317
  public exponent: 65537
  Validity: [From: Mon Aug 05 02:00:00 CEST 2019,
               To: Mon Aug 09 14:00:00 CEST 2021]
  Issuer: CN=DigiCert SHA2 High Assurance Server CA, OU=www.digicert.com, O=DigiCert Inc, C=US
  SerialNumber: [    05d8fed0 ed99a7c7 20081752 711f1798]
...
chain [1] = [
[
  Version: V3
  Subject: CN=DigiCert SHA2 High Assurance Server CA, OU=www.digicert.com, O=DigiCert Inc, C=US
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

  Key:  Sun RSA public key, 2048 bits
  modulus: 23085922014910748503624791917480115148492919026914207610707020942093828159221184419960399297678177590153378092714640886296044490661625022319263060388275515964365478738040978664516396912933675650257207760237777280773935047177225664304566903694731631728916260237117586511459590661362255543750987738241463266555577715629664656907640120826399947323444556799362651693283202076722872218490347588587929811327918605576169523712767591239193274840826201053308722900104999956283622772648025895714833602740679819670062830777938157004975732087864164660384513848296643542134747514357423990884765641067184766081973460304136714018531
  public exponent: 65537
  Validity: [From: Tue Oct 22 14:00:00 CEST 2013,
               To: Sun Oct 22 14:00:00 CEST 2028]
  Issuer: CN=DigiCert High Assurance EV Root CA, OU=www.digicert.com, O=DigiCert Inc, C=US
  SerialNumber: [    04e1e7a4 dc5cf2f3 6dc02b42 b85d159f]
...

Which is neighther self-signed nor looks at any place to be not verifyable with default truststore and SSL settings.

So just disable the lines

        System.setProperty("javax.net.ssl.trustStore", System.getProperty("user.dir") + "/key/cert.p12");
        System.setProperty("javax.net.ssl.trustStorePassword", "secret");

of if You need that cert in truststore, optimally take the official trustore delivered with java and add the cert you have in yout cert.p12 to that - or add any other certificates from the chain the server offers to that stripped down custom truststore. (Ideally the root certificate "CN=DigiCert High Assurance EV Root CA, OU=www.digicert.com, O=DigiCert Inc, C=US" which You get at digicert or probably in all current default trustsores and the like delivered with andy application or operating system.)

Upvotes: 1

Related Questions