Search code examples
javaspringhttpstruststore

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...


Solution

  • 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.)