0

I am connecting to a service through my Java code. Let's call FQDN or hostname of service as: abc.xyz.com.

My Java implementation returns exception:

java.net.UnknownHostException: dfour6gtsg5a.streaming.us-phoenix-1.oci.oraclecloud.com
    at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:567)
    at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
    at java.base/java.net.Socket.connect(Socket.java:633)
    at java.base/sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:304)
    at java.base/sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:174)
    at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:183)
    at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:532)
    at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:637)
    at java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:266)
    at java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:380)
    at 

Now, when I include entry of FQDN of service and IPAddress in /etc/hosts as below:

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
...
100.70.125.57 abc.xyz.com

Same Java implementation works correctly as service FQDN get resolved to IP address correctly.

If I try to run Java implementation with IPAddress, I get below error:

javax.net.ssl.SSLHandshakeException: No subject alternative names matching IP address 100.70.125.57 found
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:371)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:314)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:309)
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:654)
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:473)
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:369)
    at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:396)

In production environment, I will not have access to /etc/hosts for editing.

How can I resolve the Service FQDN to the IPAddress inside my Java implementation?

Om Sao
  • 7,064
  • 2
  • 47
  • 61
  • 1
    The SAN (subject alternative name) is the **name** of the server in the TLS (SSL is *ancient*) certificate. You can [disable hostname verification](https://stackoverflow.com/questions/6031258/java-ssl-how-to-disable-hostname-verification). Or you can modify DNS to actually resolve abc.xyz.com. This behavior is required by the protocol. And you'd see a very similar message if you tried to access the URL in a browser. – Elliott Frisch May 17 '23 at 11:52
  • @ElliottFrisch: Thank you. I am using `HttpURLConnection` class in Java. I found that there is API available in `HttpsURLConnection` class to disable SSL validation. – Om Sao May 17 '23 at 13:37

1 Answers1

0

The simplest way I found is to provide value true to HttpsURLConnection.setHostnameVerifier()

You need to override the method public boolean verify(String hostname, SSLSession session) for returning true everytime.

Below is an example:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.Exception;
import java.net.URL;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

public class SkipVerification implements Runnable {

    private static final String TAG = SkipVerification.class.toString();
    private String server_port;
    private String serverIP;

    public SkipVerification(String serverIP, String server_port){
        this.serverIP = serverIP;
        this.server_port = server_port;
    }

    public void run() {
        try {
            HostnameVerifier hostnameVerifier = new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };

            URL url = new URL("https://" + serverIP + ":" + server_port + "/json");
            InputStream inStream = null;

            try {
                HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
                urlConnection.setRequestProperty("Content-Type", "application/json");
                urlConnection.setHostnameVerifier(hostnameVerifier);
                inStream = urlConnection.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
            } catch (Exception e) {
                Log.e(TAG, "error fetching data from server", e);
            } finally {
                if (inStream != null) {
                    inStream.close();
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "error initializing SkipVerificationn thread", e);
        }
    }
}

This works when using HttpsURLConnection class. For other implementation, please refer to comment to question by @Elliott Frisch.

Om Sao
  • 7,064
  • 2
  • 47
  • 61