Java SSL: сбой рукопожатия клиента и сервер не имеют общих наборов шифров - PullRequest
0 голосов
/ 02 ноября 2019

Я пытаюсь подключиться от клиента к серверу через сокет SSL в Java. Получение handshake_failure на стороне клиента и никаких общих наборов шифров на стороне сервера (www).

Сервер настроен для SSL Tomcat 9, здесь есть соединитель:

        <Connector SSLEnabled="true" acceptCount="100" clientAuth="false"
            disableUploadTimeout="true" enableLookups="false" maxThreads="25"
            port="8443" keystoreFile="C:/Users/xxx/.keystore" keystorePass="xxx"
            keystoreType="PKCS12"
            protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https"
            secure="true" sslProtocol="TLS" />

Клиент - проект Java. Обе стороны имеют сертификаты в Keytool. Сертификат был экспортирован из keytool и импортирован на стороне клиента с помощью keytool. Итак, на стороне клиента и на стороне сервера мы импортировали server.cer. Tomcat запускается через порт 8443, сокеты используют порт 443.

Что я пробую? -установка протоколов в коде -установка наборов шифров -перемена портов -запуск tomcat с 8080 и 8443 порта

Сервер:

    void mySSLServerSocket(int port) throws IOException {

        SSLServerSocketFactory sslServerSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
        SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(port);
        sslServerSocket.setEnabledProtocols(new String[] {"TLSv1.2"});
        sslServerSocket.setEnabledCipherSuites(new String[] {"TLS_RSA_WITH_AES_256_CBC_SHA"});
        SSLSocket socket = (SSLSocket) sslServerSocket.accept();
        OutputStream out = socket.getOutputStream();
        InputStream in = socket.getInputStream();
        while(true) {
            int orderNumber = in.read();
            System.out.println("order number readed: " + orderNumber);
        }
    }

Клиент:

    void mySocket(String ip, int port) throws IOException {

        SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
        SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(ip, port);
        sslSocket.setEnabledProtocols(new String[] {"TLSv1.2"});
        sslSocket.setEnabledCipherSuites( new String[] {"TLS_RSA_WITH_AES_256_CBC_SHA"});
        sslSocket.startHandshake();
        InputStream in = sslSocket.getInputStream();
        OutputStream out = sslSocket.getOutputStream();
        out.write(1);
        while (in.available() > 0) {
            System.out.print(in.read());
        }

    }

Ошибка клиента:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2020)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1127)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
    at com.company.SocketUtil.mySocket(SocketUtil.java:31)
    at com.company.Main.main(Main.java:15)

Сервер (ошибка с веб-страницы JSP):

Type Exception Report

Message no cipher suites in common

Description The server encountered an unexpected condition that prevented it from fulfilling the request.

Exception

javax.net.ssl.SSLHandshakeException: no cipher suites in common
    java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
    java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:307)
    java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:263)
    java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:254)
    java.base/sun.security.ssl.ServerHello$T12ServerHelloProducer.chooseCipherSuite(ServerHello.java:460)
    java.base/sun.security.ssl.ServerHello$T12ServerHelloProducer.produce(ServerHello.java:295)
    java.base/sun.security.ssl.SSLHandshake.produce(SSLHandshake.java:436)
    java.base/sun.security.ssl.ClientHello$T12ClientHelloConsumer.consume(ClientHello.java:1102)
    java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.onClientHello(ClientHello.java:854)
    java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.consume(ClientHello.java:813)
    java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
    java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
    java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421)
    java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:177)
    java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164)
    java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1180)
    java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1091)
    java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402)
    java.base/sun.security.ssl.SSLSocketImpl.ensureNegotiated(SSLSocketImpl.java:721)
    java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:804)
    java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:763)
    ServerSocketUtils.mySSLServerSocket(ServerSocketUtils.java:38)
    MusicControl.doPost(MusicControl.java:24)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Note The full stack trace of the root cause is available in the server logs.

Ошибка говорит о том, что нет комплектов шифров, но я проверил поддерживаемые шифры и выбрал один, доступный дляобе стороны. Объявленный протокол TSL и до сих пор не увенчался успехом.

Я хотел бы подключиться от клиента к серверу успешно, но понятия не имею, что мне делать дальше, потому что в интернете нет советов.

Я прочиталчто-то о закрытом ключе требуется для подключения. Где это находится? Я предполагаю, что у server.cer есть только открытый ключ.

Правильно ли использовать порт 443 для сокетов, когда tomcat работает на 8443? Может мне где-то указать эти порты?

1 Ответ

1 голос
/ 02 ноября 2019

Одна часть вашего вопроса касается "сертификатов", которые, как я полагаю, означает сертификат.

Вы правы, сертификат содержит только открытый ключ, который подписан центром сертификации (ЦС). Открытый ключ является только открытой частью пары ассиметричных ключей (например, RSA). Сервер должен иметь закрытый ключ. В противном случае он не сможет расшифровать контент, зашифрованный с помощью открытого ключа, и не сможет подписать контент, отправленный клиенту.

При этом вам необходимо создать пару ключей RSA и сделать ее доступной для tomcat. Либо вы позволяете подписать его хорошо известным центром сертификации (создает сертификат), либо вы создаете собственный сертификат с помощью ключевого инструмента. В первом случае не требуется никаких специальных действий на стороне клиента, потому что java (или браузеры) уже знают общеизвестные открытые ключи CA, которые необходимы для проверки сертификата, выданного вашим сервером. В случае самозаверяющего сертификата вы должны импортировать его на стороне клиента как доверенный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...