Можно ли удалить часть расширения рукопожатия 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 локальный, и я просто хотел подключиться к нему, безопасный или нет), но я не смог найти любой другой способ сделать это.

Другие вопросы по тегам