received handshake warning: unrecognized_name
Okay, I went through the source and found a way, although I'm not sure how enthusiastically I recommend it.
Although the javadoc for SSLParameters.setServerNames
doesn't say so, if the value set is an empty List
(with no elements), then ClientHandshaker actually sends no SNI at all. I suspect this is because the RFCs e.g. for 1.2 specify the min size as 1, prohibiting an empty list. (Compare to certificate_list in the Certificate message in TLS vs SSL; in SSL the min size was 1, and a client with no cert&key suitable for a server request didn't send the message at all, while in TLS it is 0, and a client with no suitable cert&key is explicitly specified to send a message containing an empty list.) While this is logical, since it is neither documented nor explicitly commented, I wouldn't be really happy relying on it.
Since it is pretty complicated (and fragile) to directly determine the other parameters needed, I think the best approach is to start from the existing parameters and modify, e.g. for SSLSocket
:
SSLSocket s = SSLSocketFactory.getDefault() /* or other */ .createSocket("host", 443);
SSLParameters p = s.getSSLParameters();
p.setServerNames( new ArrayList<SNIServerName>() );
/* or j9+ p.setServerNames( List<SNIServerName>.of() ); */
s.setSSLParameters(p);
...
and for HttpsURLConnection
, your original SSLSocketFactoryWrapper approach is quite close, except as above I would modify based on the actual parameters for the created SSLSocket
and you must use the empty new ArrayList<SNIServerName>()
and not .add
anything to it.
Something very similar should work for Apache HttpClient, but I haven't gone through it, because I find that annoyingly like a maze of twisty little classes all alike.
PS: the source also confirms why varying sysprop jsse.enableSNIExtension
won't work; that (like many others) is read and cached when JSSE is first loaded and not read subsequently. You could use reflection to break into the class and change the cached value, but let's not go there.
How to fix SSLProtocolException: handshake alert: unrecognized_name without disabling SNI
I managed to solve the issue by extending the SSLSocketConnection and by sending null instead of the hostname when the createSocket is called. That way java disables the SNI. Then I just pass a instance of the new class to Jsoup where I know the SNI will fail.
import javax.net.ssl.*;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
public class CustomSSLSocketFactory extends SSLSocketFactory {
private SSLSocketFactory defaultFactory;
public CustomSSLSocketFactory() throws IOException {
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init((KeyManager[])null, trustAllCerts, new SecureRandom());
defaultFactory = sslContext.getSocketFactory();
} catch (KeyManagementException | NoSuchAlgorithmException var3) {
throw new IOException("Can't create unsecure trust manager");
}
}
@Override
public String[] getDefaultCipherSuites() {
return defaultFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return defaultFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException {
//magic happens here, we send null as hostname
return defaultFactory.createSocket(socket, null, i, b);
}
@Override
public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
return defaultFactory.createSocket(s,i);
}
@Override
public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException {
return defaultFactory.createSocket(s,i,inetAddress,i1);
}
@Override
public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
return defaultFactory.createSocket(inetAddress, i);
}
@Override
public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
return defaultFactory.createSocket(inetAddress,i, inetAddress1, i1);
}
}
Jsoup initialization.
Connection conn = Jsoup.connect(url);
conn.sslSocketFactory(new CustomSSLSocketFactory());
SNI : SSLHandshakeException unrecognized_name
We found a solution by changing something in karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java
:
SSLConnectionSocketFactory socketFactory = new LenientSslConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
becomes
SSLConnectionSocketFactory socketFactory = new SslConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
@Peter, do you think a parameter to use strict or lenient SSL connection can be a possibility?
Related Topics
Android - Save Image into Gallery
Differencebetween List and Arraylist
How to Deserialise a Subclass in Firebase Using Getvalue(Subclass.Class)
Change Unix Password with Java
Exception in Thread "Main" Java.Lang.Noclassdeffounderror: Org/Apache/Hadoop/Util/Platformname
Set Environment Variable in Shell Script/Access in Java Program
Jaspersoft Studio 6.2 Build Path Warning
How to Avoid Installing "Unlimited Strength" Jce Policy Files When Deploying an Application
Line-Breaking Widget Layout for Android
Limit Decimal Places in Android Edittext
Cannot Load R Xlsx Package on MAC Os 10.11