8

we had a client made with Apache CXF which was working Ok, using certain server(i.e: https://serverexample.com/application/webservice?wsdl).

But the server has moved to another IP, and now it has two SSL Certificates with TLS and SNI(Server Name Indication) in the same IP, and now our applications fails with this error:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching serverexample.com found

I understand that this occurs when the https is getting the wrong certificate (it has another server name), and thus is not matching mine.

I tried to find out what happening with openssl, and the url only works if I put servername:

# openssl s_client -connect serverexample.com:443 -tls1
Certificate chain
 0 s:/CN=otherserver.com/OU=Servers/O=MyOrganization/C=ES
   i:/CN=ACV20/OU=PKACV/O=ACV/C=ES

# openssl s_client -connect serverexample.com:443 -servername serverexample.com
Certificate chain
 0 s:/CN=serverexample.com/OU=Servers/O=MyOrganization/C=ES
   i:/CN=ACV220/OU=PKACV1/O=ACV2/C=ES

The error happened in the generated apache client in this point:

final URL wsdlURL = new URL("https://serverexample.com/application/webservice?wsdl");
final Operation_Service ss = new Operation_Service(wsdlURL, SERVICE_NAME);

Fails in the new Operation_Service:

@WebServiceClient(name = "ENI.Operation", 
                  wsdlLocation = "https://serverexample.com/application/webservice?wsdl",
                  targetNamespace = "http://inter.ra.es/awrp/wsdl") 
public class Operation_Service extends Service {
    public final static URL WSDL_LOCATION;
    public final static QName SERVICE = new QName("http://inter.ra.es/awrp/wsdl", "ENI.Operation");
    public final static QName Operation = new QName("http://inter.ra.es/awrp/wsdl", "ENI.Operation");
    static {
        URL url = null;
        try {
            url = new URL("https://serverexample.com/application/webservice?wsdl");
        } catch (final MalformedURLException e) {
            java.util.logging.Logger.getLogger(Operation_Service.class.getName())
                .log(java.util.logging.Level.INFO, 
                     "Can not initialize the default wsdl from {0}", "https://serverexample.com/application/webservice?wsdl");
        }
        WSDL_LOCATION = url;
    }

     public Operation_Service(final URL wsdlLocation, final QName serviceName) {
        super(wsdlLocation, serviceName);
    }

javax.xml.ws.Service calls javax.xml.ws.spi.ServiceDelegate, an abastract class implemented by some class in org.apache.cxf.jaxws.. but here I'm losing it, I don't know what to look...

Our client is runnring in java 7.0 with apache cxf 3.0.4 on a weblogic 12.1.1.0. I read that in Java 6 there was problems with SNI, but we are using 7.0 here.

I don't know what can I do. Is there some option in java or in our client to indicate the servername (like in openssl) we're trying to connect?

Aitor
  • 3,309
  • 2
  • 27
  • 32
  • Can anyone provide me the solution for this : https://stackoverflow.com/questions/52252184/sni-configuration-in-cxf-client3-1-2 – Parul Mahajan Sep 11 '18 at 16:52

2 Answers2

5

It is a combination of "improvements" in JDK 1.8 and the fact that the server has several certificates.

What is broken in JDK 1.8 is explained here: http://lea-ka.blogspot.com/2015/09/wtf-collection-how-not-to-add-api.html

It goes like this:

  • No SNI extension is sent due to bug https://bugs.openjdk.java.net/browse/JDK-8072464.
  • The server returns the certificate "CN=otherserver.com", which probably also has SAN (SubjectAlternativeName) "otherserver.com" and no other.
  • The default "URL spoofing" checks in JDK are perofrmed and compare "serverexample.com" from the URL and "otherserver.com" from the certificate. Ooops, you get your exception.

The easiest fix is to download all WSDL and XSD files and package them somewhere in your jar.

If you really need to fetch the WSDL from the remote server, this might help:

final URL wsdlURL = new URL("https://otherserver.com/application/webservice?wsdl");

But this might not work because "/application/webservice" might be known only to serverexample.com. In this case you get TLS connection and then HTTP 404 response code.

If this does not work you will have to resort to all sorts of SSL factories (which is verbose but sure possible) and attempts to hook them into javax.ws.... classes (which should be possible but I have never done that part).

user568826
  • 581
  • 5
  • 16
  • I doubt it's due to JDK-8072464 since the default hostname verifier doesn't seem to be modified. Maybe it's the other bug that makes it fails also when an endpoint identification algorithm is set. They are some examples around about how to work it around with custom factories, but not for the CXF case. – jmd Nov 28 '16 at 18:23
  • Sure, the verifier is not modified. But some other code sees that the hostname verifier is present and behaves differently. It is all explaived in the linked post. – user568826 Nov 29 '16 at 06:34
0

hope this will helpful for you:

for resolve SSL handshake exception you can choose 2 ways: set this system property in beginning of your code:

System.setProperty("jsse.enableSNIExtension", "false");

or

set VM argument for your program as: -Djsse.enableSNIExtension=false

pinokio
  • 97
  • 4
  • No, this is not the answer. Here we *want* the client to send the SNI extension and Java doesn't because of a bug. – jmd Nov 28 '16 at 18:10