Why does HttpsURLConnection.getServerCertificates () return different results in Java6 vs Java7?

I have a code like this:

// configure the SSLContext with a TrustManager SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom()); SSLContext.setDefault(ctx); URL url = new URL(urlString); // https://abc.myhost.com HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String arg0, SSLSession arg1) { System.out.println("verify:" + arg0); return true; } }); System.out.println("HTTP status: " + conn.getResponseCode()); Certificate[] certs = conn.getServerCertificates(); int c=0; for (Certificate cert : certs){ String t = cert.getType(); System.out.println(String.format("\ncert[%d]: %s",c,t)); c++; if (pi.verbose) { System.out.println(cert); } else if (cert instanceof X509Certificate) { X509Certificate x509cert = (X509Certificate) cert; System.out.println(x509cert.getSubjectDN().getName()); } } 

By running this code on a specific website, in Java 6, I get a different certificate than I get for Java 7. Say the host name is abc.myhost.com.

on Java6 I get:

 cert[0]: X.509 CN=example.com,OU=Secure Link SSL Pro,O=Company Name Here, STREET=2001 Space Odyssey Dr,L=Weirton,ST=Wv,2.5.4.17=#13053330303034,C=US 

on Java7 I get:

 cert[0]: X.509 CN=abc.myhost.com,OU=Secure Link SSL Pro,O=Company Name Here, STREET=2001 Space Odyssey Dr,L=Weirton,ST=Wv,2.5.4.17=#13053330303034,C=US 

If I print out valid dates, they are also different. Like serial numbers. These are different certificates.

In Java 7, this looks right; In Java 6, I have a disagreement between the host name and CN. The certificate does not look right.

It is possible that this server is located behind the proxy server. It is also possible that the owner of this server (the partner in the project I'm working on) has recently changed the certificate. There may be two certificates: one on the proxy server and one on the server behind the proxy server. I study them.

I have a question: why don't I get the same results in Java7 as in Java6? Has Java replaced anything in HttpsURLConnection.getServerCertificates() ?


For the curious, this is just a diagnostic job. The real mistake:

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

The problem in this case is usually the disagreement between the host name and CN in the certificate. I checked the odds, but only in Java 6. I would like to understand why Java6 and Java7 are different.


EDIT: Python 2.7.1 script returns the same certificate as Java6. SSLConnection.get_peer_cert() shows me a certificate with an inconsistent CN.

+4
source share
1 answer

I would suspect that this is due to support for server name support provided on the client side in Java 7.

SNI allows the client to specify the host name in the original SSL / TLS request, in particular to be able to host multiple host names on the same IP address / port with different certificates (which Apache Httpd invokes virtual hosts based on the name). Knowing the requested host name during the SSL / TLS connection establishment, the server can download the correct certificate before using any HTTP traffic (the HTTP Host header is used at the HTTP level, but too late for HTTPS).

When the client does not support it, the server does not know which hostname the client really needs, and usually refuses the default host value and maintains the default certificate.

(Note that you will have the same problem with any version of IE on Win XP, and possibly with some browsers.)

EDIT: After editing ( URL url = new URL(urlString); // https://abc.myhost.com ).

This seems to confirm the SNI problem. (You can check the use of Wireshark to see if there is a server name extension in the TLS client's Hello message.)

With Java 7 and any SNI-enabled client, when you request https://abc.myhost.com you really get a certificate valid for abc.myhost.com (assuming the server is configured correctly), because HttpsURLConnection also reports JSSE ( Java SSL / TLS) to use the server name extension and initiate an SSL / TLS connection with the host name for this URL.

With Java 6 and any client that does not support SNI (Python 2.7, at least without other libraries), you will receive a certificate that the server presents by default when connecting to this IP address and port.

This has nothing to do with HttpsURLConnection.getServerCertificates() or SSLConnection.get_peer_cert() . Rather, it is because the server expects the client to support SNI, which some older clients / platforms do not have.

If you need support for Java 6, Python 2.x, Internet Explorer (or other clients using the MS API by default) in Windows XP, you will not be able to use SNI. In this case, you should contact the server administrator to change the configuration to not use SNI (this requires an additional IP address if these several hosts are required).

+10
source

Source: https://habr.com/ru/post/1447619/


All Articles