1

I have a java application calling external api which is hosted on address like https://10.20.30.40:1234/test/myurl

this have a domain base certifcate with CN like *.myappdomain.au

We have done registration on our linux server of the certificate. I have even tried loading the certificate with following code but it is of no use and we are getting same error

private static SSLSocketFactory createSSLSocketFactory(String certificatePath) throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        File crtFile = new File(certificatePath);
        
        Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));

        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, null);
        keyStore.setCertificateEntry("server", certificate);

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

        return sslContext.getSocketFactory();
    }

One thing i tried which work is adding entry in host like 10.20.30.40 myappdomain.au and then using url like https://myappdomain.au:1234/test/myurl

then application works

Any idea what more i need to do

Kamran Shahid
  • 3,954
  • 5
  • 48
  • 93

2 Answers2

2

Well, if the API is hosted on an IP address, the SSL certificate has to define that IP address as Subject Alternative Name. This however won't work for services like Let's Encrypt.

I guess the main cause of the issue is that you're trying to access the API by its IP address rather than its FQDN. Changing the URL of the API to the appropriate DNS name for the IP address in your source code should yield in everything working, as long as the DNS name resolves to something related to the domain the wildcard certificate was issued for (e.g. api.myappdomain.au).

maio290
  • 6,440
  • 1
  • 21
  • 38
  • 1
    mean's if certificate doesn't have subject alternative name then Ip base url will not work even we try to register the certificate by any mean't to our server? I have done calling api by domain address after adding address in host. is that a correct approach? – Kamran Shahid Apr 20 '21 at 20:51
  • 1
    Why would someone even bother getting a wildcard certificate for the domain when he's not even using it properly? That is what bothers me the most about this whole issue. The correct approach would be to act according to your SSL certificates or to get one which is issued according to your needs. Modifying the hosts file however is nothing which belongs in a productive environment. Also, using the IP address for accessing an API has other implications, especially when relying on external hosting companies. Your workaround may work, but it's just a workaround which I can only condemn. – maio290 Apr 20 '21 at 20:56
  • 1
    I was just been provided with ip base address with some external api integration and sharing the experience how it eventually worked. frankly i have mostly done development in .net and generally doesn't faced any such problem – Kamran Shahid Apr 20 '21 at 21:04
  • 1
    Upvoted. This line specifically sums up the issue nicely: "I guess the main cause of the issue is that you're trying to access the API by its IP address rather than its FQDN. Changing the URL of the API to the appropriate DNS name for the IP address in your source code should yield in everything working". – Atmas Apr 21 '21 at 00:20
1

try to run this code before connect:

public static void trustAllCerts() {
    TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(
                    java.security.cert.X509Certificate[] certs, String authType) {
                }
                public void checkServerTrusted(
                    java.security.cert.X509Certificate[] certs, String authType) {
                }
            }
        };
    
    try {
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (Exception e) {
            
        e.printStackTrace();

    }
}
  • 1
    Trusting everyone isn't really the purpose of SSL... – maio290 Apr 21 '21 at 05:37
  • 1
    yes. i know this code of trusting everything which is not recommended so as per advice i avoid it. i have other production implementation with ssl also running on the server perfecctly. problem is with only particular case – Kamran Shahid Apr 21 '21 at 06:15
  • 1
    Also one problem with this approach is it will do for all type of https connection call from the application. i have multiple api intergrated and problem is only with one api where i might needed to skip this certificate check if enforced – Kamran Shahid Apr 22 '21 at 16:36