Weird certificate error when trying to generate web service client from secure site
I get a weird error when trying to use AXIS1.4 Wsdl2Java tool to generate client code for the web service that is installed on the secure IIS site. When I run the tool I get the following SSL e开发者_如何学运维xception:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No
name matching XXXXXXX.net found
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1
591)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:187)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:181)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Clien
tHandshaker.java:975)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHa
ndshaker.java:123)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:5
16)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.jav
a:454)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.j
ava:884)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SS
LSocketImpl.java:1096)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketIm
pl.java:1123)
Weird thing is that this error only occurs when I run WSDL2Java, and only for this particular server. I have another web server with the identical set-up and everything works fine there. I triple checked all the keystores and it looks like all the CA certificates are loaded correctly. I tried using another server with the identical setup, and was able to generate the client proxy code without any problems. Weird thing is that if I use the code generated from the other server against the weird server everything works fine. It is only Wsdl2Java that is giving me a problem.
There is very likely a mismatch between the DNS name of the host (e.g. machine1.mydomain.tld) and the CommonName
value from the certificate, hence the CertificateException
. From this blog post:
- if you'd like to connect via using IP as hostname;
your certificate should include that ip value as a subject alternative name value (of type IPAddress : key=7).- if you'd like to connect via using DNS as hostname;
your certificate should either include that DNS name as a subject alternative name value (of type DNS : key=2) or as a CommonName(CN) value.
You may find using the SSL debugging system properties can be helpful to investigate this problem:
-Djavax.net.debug=ssl
If there's too much printed out, you can filter some things, perhaps this:
-Djavax.net.debug=ssl,trustmanager
The output is not necessarily obvious to read, but it should tell you where the error is in more detail.
The problem is that WSDL2Java has rejected the Server certificate because of name. In Java, the hostname you use to connect to the remote system much match the common name in the certificate. It will not reverse lookup based on the IP Address. You must connect using the hostname.
Other replies indicated that you are connecting via the IP Address. This is not the correct way to do things. Java will validate the certificate against the hostname it is connecting to.
If you are connecting using the IP Address you might not have DNS set up in your environment. The easiest way to get around this is to add the hostname to your hosts file. In windows this is located in 'C:\Windows\System32\drivers\etc\hosts'.
xx.xx.xx.xx XXXXXXXXXX.net
This will allow you to use the hostname to get the WSDL through WSDL2Java.
Alternative:
There is an alternative if that still does not work. Download the .wsdl file using your web browser. Have WSDL2Java create your Java stubs from the local file on disk instead of on the web server. The code generated will be identical but it will not have to go through SSL to get the WSDL.
If you have the server certificate at hand and openssl installed you can dump the contents of the certificate with something like:
$ openssl x509 -noout -text -in filename-here.pem
You'll see "CN=" as part of the Subject, and if it has the altSubjectName extension in the certificate, you'll see that below under X509v3 extensions, as X509v3 Subject Alternative Name, and you'll be looking for something like DNS:host-name-here.
If that matches the hostname you are connecting to, then just check if you are connecting by IP address, or by hostname, in whatever SSL interface you go through, and make sure it is by hostname and not by IP address.
If there is no matching name in the certificate (that matches the hostname you are connecting to), some SSL interfaces will let you ignore the "name mismatch". (I don't know how to do that in your specific case.)
EDIT:
Try connecting by hostname instead of IP address and see if there is a difference.
If the IP is listed in the certificate, you'll see something like IP:xx.xx.xx.xx under X509v3 Subject Alternative Name in the openssl output.
If the IP is not listed, run nslookup from a shell prompt and compare the output for both the working and non-working server addresses. This may be how the working server is matching the hostname (i.e. by way of getnetbyaddr).
EDIT 2:
Have you tried connecting by hostname (in your connect string) and still get the same error? It doesn't matter if connecting via browser using the IP address works -- the browser may not be verifying the hostname using the same algorithm. Have you tried connecting to the good server using an IP address in the connect? Also, look here for something to try: found with quick Google
Could it be that you are missing the appropriate GlobalSign root certificate for Java.
# Import a root or intermediate CA certificate to an existing Java keystore
keytool -import -trustcacerts -alias root -file Thawte.crt -keystore keystore.jks
Another possibility relates to the combination of the root and intermediate certificate. More from the GlobalSign website:
"Some Apache and Java-based applications require the root and intermediate certificates to be bundled in one certificate..."
精彩评论