How to Fix : java.security.cert.CertificateException: No name matching localhost found

7 Flares Twitter 1 Facebook 0 Google+ 5 LinkedIn 1 Email -- Filament.io 7 Flares ×

How to Fix the exception ” java.security.cert.CertificateException: No name matching localhost found”, when client uses URL with “localhost” as host name to access some secure service over HTTPS? In this article we will check the root cause of the issue and will try two different solutions two fix the same.
There are other similar issues related the SSL certificates. One of the common situation is the missing certificate in trust store. In that case you may see the following error message.

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

See the following article to read more about the above error and its solution.

PKIX Path Building Failed (Validation) : sun.security.validator.ValidatorException

When Do You Encounter the Error : java.security.cert.CertificateException: No name matching localhost found?

When you use self signed certificate for services such as secure web service and try to access the service over HTTPS from a client using “localhost”, you may encounter the error “java.security.cert.CertificateException: No name matching localhost found”.
The error can also be something like “java.security.cert.CertificateException: No name matching <hostname> found”, where, the “hostname” can be anything.

…..
Caused by: javax.net.ssl.SSLHandshakeException: 
    java.security.cert.CertificateException: No name matching localhost found
	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1611)
	at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:187)
	at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:181)
	......
Caused by: java.security.cert.CertificateException: No name matching localhost found
	at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:210)
	at sun.security.util.HostnameChecker.match(HostnameChecker.java:77)
…….

Root Cause of the Exception: java.security.cert.CertificateException: No name matching <host> found

At run-time, Java check host name against the names specified in a digital certificate as required for TLS and LDAP.
So if you are using for example, https://localhost:8443/MyService/.. , the runtime will check if the certificate allows use of the given DNS name, in this case “localhost”. This matching is performed using the matching rules specified by RFC2459.

As per the java doc, “If a subjectAltName extension of type dNSName is present, that MUST be used as the identity. Otherwise, the (most specific) Common Name field in the Subject field of the certificate MUST be used. Although the use of the Common Name is existing practice, it is deprecated and Certification Authorities are encouraged to use the dNSName instead.
Also “If more than one identity of a given type is present in the certificate (e.g., more than one dNSName name, a match in any one of the set is considered acceptable.)

The above points indicate that, the certificate CN (Common Name) should be the same as host name in the URL. If the CN in the certificate is not the same as the host name, you will get the error “java.security.cert.CertificateException: No name matching <the_host_name_used> found”, where , “the_host_name_used” is the host name you used as part of the URL in your client application.

How to solve the error “java.security.cert.CertificateException: No name matching localhost found”?

Method 1: Change the Certificate CN name

The first step is to verify the CN (Common Name) in the certificate. Please not that, you cannot change the CN in an already created certificate. This is because, a certificate is designed specifically so that this data can’t be modified after its creation. It is part of the certificate.

CN=localhost, OU=home, O=home, L=city,ST=state, C=in

So you need to create a new certificate with the hostname as “localhost” or any other hostname you want to use. Example is given below. You can use the java keytool tool to create your self-signed certificate with the “localhost” CN.

F:\myservice\src>keytool -genkey -alias serverkey -keypass nosecret -keyalg RSA -sigalg SHA1withRSA -keystore server.keystore -storepass nostoresecret
What is your first and last name?
  [Unknown]:  localhost
What is the name of your organizational unit?
  [Unknown]:  globinch ws
What is the name of your organization?
  [Unknown]:  globinch
What is the name of your City or Locality?
  [Unknown]:  Bangalore
What is the name of your State or Province?
  [Unknown]:  KAR
What is the two-letter country code for this unit?
  [Unknown]:  IN
Is CN=localhost, OU=globinch ws, O=globinch, L=Bangalore, ST=KAR, C=IN correct?
  [no]:  yes

That’s all. You need to apply this certificate and setup the web server. Now if you use endpoint such as https://localhost:8443/MyService/..” ,the java security run-time will accept it.

Implement the verify() method of HostnameVerifier

HostnameVerifier is the base interface for hostname verification. As per java doc “During handshaking, if the URL’s hostname and the server’s identification hostname mismatch, the verification mechanism can call back to implementers of this interface to determine if this connection should be allowed”.
These callbacks are used when the default rules for URL hostname verification fail.
The HttpsURLConnection class uses HostnameVerifier and SSLSocketFactory. You can set the HostnameVerifier using the setDefaultHostnameVerifier(setDefaultHostnameVerifier) method. See example below.

javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
    new javax.net.ssl.HostnameVerifier(){
 
        public boolean verify(String hostname,
                javax.net.ssl.SSLSession sslSession) {
            if (hostname.equals("localhost")) {
                return true;
            }
            return false;
        }
    });

So during handshaking, if the URL’s hostname and the server’s identification hostname mismatch, it will invoke the above verify implementation. The above code returns “true” for hostname localhost”, and the connection is allowed.

References:

Incoming search terms:

7 Flares Twitter 1 Facebook 0 Google+ 5 LinkedIn 1 Email -- Filament.io 7 Flares ×

Related Posts

This Post Has 8 Comments

  1. NIce article..I have question about Method 1: Change the Certificate CN name:When i am using any external name other than localhost..e.g xyz.company.com then it is not working
    cold you please tell me what is another reason

  2. Well explained, but the first fix does not work. I see the same error message as when the CN did not match.

  3. I have solved the issue by the following way.

    1. Creating a class . The class has some empty implementations

    class MyTrustManager implements X509TrustManager {
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
    return null;
    }

    public void checkClientTrusted(X509Certificate[] certs, String authType) {
    }

    public void checkServerTrusted(X509Certificate[] certs, String authType) {
    }

    @Override
    public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString)
    throws CertificateException {
    // TODO Auto-generated method stub

    }

    @Override
    public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString)
    throws CertificateException {
    // TODO Auto-generated method stub

    }
    2. Creating a method

    private static void disableSSL() {
    try {
    TrustManager[] trustAllCerts = new TrustManager[] { new MyTrustManager() };

    // Install the all-trusting trust manager
    SSLContext sc = SSLContext.getInstance(“SSL”);
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HostnameVerifier allHostsValid = new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
    return true;
    }
    };
    HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    3. Call the disableSSL() method where the exception is thrown. It worked fine.

Leave a Reply

Your email address will not be published. Required fields are marked *

Paged comment generated by AJAX Comment Page
© 2024 Globinch Java Forum - Theme by WPEnjoy · Powered by WordPress