Можно ли удалить часть расширения рукопожатия SSL в Java?
Существует устаревший сервер Cisco IPS, к которому я пытаюсь подключиться по протоколу https. Проблема в том, что этот сервер принимает рукопожатия только при определенных условиях:
Версия должна быть TLSv1.0, набор шифров должен быть SSL_RSA_WITH_RC4_128_MD5 или SSL_RSA_WITH_RC4_128_SHA, и не должно быть никаких расширений.
Я реализовал ручную "ClientHello", которая отправляет следующую информацию как рукопожатие (вывод Wireshark):
Secure Sockets Layer
TLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 45
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 41
Version: TLS 1.0 (0x0301)
Random
Session ID Length: 0
Cipher Suites Length: 2
Cipher Suites (1 suite)
Compression Methods Length: 1
Compression Methods (1 method)
Сервер отправляет обратно сообщение ServerHello.
Теперь я хочу использовать реализацию SSL Java для отправки точно такого же ClientHello. Следующий код:
System.setProperty("https.protocols", "TLSv1");
System.setProperty("javax.net.debug", "ssl:handshake");
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket("ips-server", 443);
socket.setEnabledProtocols(new String[] {"TLSv1"});
socket.setEnabledCipherSuites(new String[] {"SSL_RSA_WITH_RC4_128_MD5"});
socket.startHandshake();
производит следующее рукопожатие:
Secure Sockets Layer
TLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 52
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 48
Version: TLS 1.0 (0x0301)
Random
Session ID Length: 0
Cipher Suites Length: 2
Cipher Suites (1 suite)
Compression Methods Length: 1
Compression Methods (1 method)
Extensions Length: 5
Extension: renegotiation_info
Type: renegotiation_info (0xff01)
Length: 1
Renegotiation Info extension
Это заставляет сервер отправлять обратно следующий пакет:
TLSv1.2 Record Layer: Alert (Level: Fatal, Description: Handshake Failure)
Можно ли заставить Java не отправлять "расширенную" часть пакета?
1 ответ
Если кто-то хочет знать ответ, вам нужно использовать SSLv2Hello для свойства системы https.protocols.
System.setProperty("https.protocols", "TLSv1,SSLv2Hello");
Я использовал следующий код для подключения к серверу:
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
} }, new SecureRandom());
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);
HttpsURLConnection conn = (HttpsURLConnection) new URL(url).openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String string, SSLSession ssls) {
return true;
}
});
РЕДАКТИРОВАТЬ Больше объяснений - @EJP упомянул, что этот код не отвечает на вопрос в заголовке. Я написал небольшой тест, чтобы показать, удалена ли часть расширения SSL-клиента hello в качестве побочного эффекта изменения клиента hello на SSLv2.
public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException, MalformedURLException, IOException {
System.setProperty("https.protocols", "TLSv1,SSLv2Hello");
String url = "https://www.google.com";
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] xcs, String string) {
}
@Override
public void checkServerTrusted(X509Certificate[] xcs, String string) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}}, new SecureRandom());
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);
HttpsURLConnection conn = (HttpsURLConnection) new URL(url).openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String string, SSLSession ssls) {
return true;
}
});
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
Stream<String> lines = br.lines();
lines.forEach(l -> { System.out.println(l);});
}
Вот что я получаю в Wireshark, если я запускаю эту программу:
И если я закомментирую часть SSLv2Client, я получу это:
Ясно, что это дает то, что я искал: удаление части расширения рукопожатия SSL. Может быть, это не самый лучший способ, и, как упомянуто @EJP, создает много дыр в безопасности (не моя проблема здесь, так как мой сервер CISCO IPS локальный, и я просто хотел подключиться к нему, безопасный или нет), но я не смог найти любой другой способ сделать это.