Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apache CXF client error in testing server which needs Server Name Indication (SNI)

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?

like image 930
Aitor Avatar asked Sep 11 '15 12:09

Aitor


1 Answers

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

like image 195
user568826 Avatar answered Nov 01 '22 03:11

user568826