Почему соединение сокета сервера SSL блокируется в Java, а не сокет сервера SSL - нет? - PullRequest
0 голосов
/ 19 ноября 2018

Рассмотрим следующий код для сокет-сервера и клиента, не использующих SSL, в одном потоке:

import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerClient {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(0); // open a random free port.

        Socket c = new Socket(ss.getInetAddress(), ss.getLocalPort());

        Socket s = ss.accept();

        final byte[] bytes = "Hello World!".getBytes();
        final OutputStream out = c.getOutputStream();
        System.out.println("writing to stream");
        out.write(bytes.length);
        out.write(bytes);

        System.out.println("reading from stream");

        final DataInputStream in = new DataInputStream(s.getInputStream());
        int len = in.read();
        final byte[] b = new byte[len];
        in.readFully(b);
        System.out.println(new String(b));

        c.close();
        ss.close();
    }
}

Это приведет к следующему выводу:

writing to stream
reading from stream
Hello World!

Этот процесс открылсокет сервера - соединен с сокетом клиента.Передал данные в сокет и затем закрыл.Не было проблем с передачей данных.

Рассмотрим версию для проверки точки с сокетами SSL:

import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.logging.Logger;

public class SSLServerClient {

    private static Logger log = Logger.getLogger("InfoLogging");

    public static void main(String[] args) throws IOException {

        System.setProperty("javax.net.ssl.keyStore", "/path/KeyStore.jks");
        System.setProperty("javax.net.ssl.keyStorePassword", "password");

        SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();

        SSLServerSocket serverListeningSSLSocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(4380);
        log.info("Server started");

        SSLSocketFactory sslSocketFactory=(SSLSocketFactory) SSLSocketFactory.getDefault();
        SSLSocket clientSocket =  (SSLSocket) sslSocketFactory.createSocket(serverListeningSSLSocket.getInetAddress(),
                serverListeningSSLSocket.getLocalPort());

        SSLSocket serverCommsSSLSocket = (SSLSocket) serverListeningSSLSocket.accept();
        log.info("new client");

        final byte[] bytes = "Hello World!".getBytes();
        final OutputStream out = clientSocket.getOutputStream();
        System.out.println("writing to stream");
        out.write(bytes.length);
        out.write(bytes);

        System.out.println("reading from stream");

        final DataInputStream in = new DataInputStream(serverCommsSSLSocket.getInputStream());
        int len = in.read();
        final byte[] b = new byte[len];
        in.readFully(b);
        System.out.println(new String(b));

        clientSocket.close();
        serverCommsSSLSocket.close();
        serverListeningSSLSocket.close();
    }
}

Это дает следующий вывод:

Nov 21, 2018 10:23:51 PM com.gamble.ssl.SSLServerClient main INFO: Server started
Nov 21, 2018 10:23:52 PM com.gamble.ssl.SSLServerClient main INFO: new client
writing to stream

т.е. он блокируется при запуске сокета сервера,

У меня такой вопрос: Почему соединение с сокетом сервера SSL блокируется в Java, а без сокета сервера без SSL?

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Простой ответ на вопрос:

Поскольку SSL Handshake является асинхронным и , сокет без SSL не должен выполнять этот шаг.

Хорошо - с исходным кодом SSL возникли две проблемы:

  1. Не было TrustStore:

    System.setProperty( "javax.net.ssl.trustStore", "/path/KeyStore.jks");
    
  2. Поскольку Рукопожатие является синхронным - вы должны запустить клиента в другом потоке. а именно:

    (new Thread() {
      public void run() {
        // do stuff
      }
     }).start();
    

Код выглядит так:

    import javax.net.ssl.SSLServerSocket;
    import javax.net.ssl.SSLServerSocketFactory;
    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.SSLSocketFactory;
    import java.io.DataInputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.logging.Logger;

    public class SSLServerClient {

        public static void main(String[] args) throws IOException {

            System.setProperty("javax.net.ssl.keyStore", "/path/KeyStore.jks");
            System.setProperty( "javax.net.ssl.trustStore", "/path/KeyStore.jks");

            System.setProperty("javax.net.ssl.keyStorePassword", "password");

            SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();

            SSLServerSocket serverListeningSSLSocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(4380);
            System.out.println("--server started");

            SSLSocketFactory sslSocketFactory=(SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket clientSocket =  (SSLSocket) sslSocketFactory.createSocket(serverListeningSSLSocket.getInetAddress(),
                    serverListeningSSLSocket.getLocalPort());

            SSLSocket serverCommsSSLSocket = (SSLSocket) serverListeningSSLSocket.accept();
            System.out.println("--new client");

            final byte[] bytes = "--Hello World!".getBytes();
            final OutputStream out = clientSocket.getOutputStream();
            System.out.println("--Gotten output stream");
            final DataInputStream in = new DataInputStream(serverCommsSSLSocket.getInputStream());

            (new Thread() {
                public void run() {
                    System.out.println("--reading from stream");

                    int len = 0;
                    try {
                        len = in.read();
                        final byte[] b = new byte[len];
                        in.readFully(b);
                        System.out.println(new String(b));

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();


            System.out.println("--writing to stream");
            out.write(bytes.length);
            System.out.println("--writing to stream - length");
            out.write(bytes);

            clientSocket.close();
            serverCommsSSLSocket.close();
            serverListeningSSLSocket.close();
        }
    }

И вывод выглядит как

    --server started
    --new client
    --Gotten output stream
    --writing to stream
    --reading from stream
    --writing to stream - length
    --Hello World!

    Process finished with exit code 0

Готово

(Обратите внимание, что я добавил ведущий -- к выводу, чтобы помочь при чтении вывода отладки SSL.

0 голосов
/ 21 ноября 2018

Что значит "перевернуть в открытый текст"?значит?

Вот что вы делаете:

  • Создание сокета сервера SSL
  • Создание обычного сокета, подключенного к сокету сервера SSL
  • Отправка некоторых данных со стороны клиента
  • Чтение некоторых данных со стороны сервера

Теперь сокет SSL ожидает зашифрованной передачи данных.Но данные, которые вы не отправляете, не зашифрованы, поэтому они не являются действительным SSL и выдают исключение - как говорится, «Нераспознанное сообщение SSL», потому что вы не отправляете действительное сообщение SSL, а «соединение в незашифрованном виде?»подсказка о том, что может быть не так.

Вы должны использовать SSL на обеих сторонах соединения, или они не могут нормально общаться друг с другом.

...