Пример Android SSLEngine

Мне нужно работать с сокетом TCP поверх TLS для приложения, над которым я работаю. Я прошел через десятки примеров, и, хотя у меня нет проблем с прохождением рукопожатия, я не могу прочитать поток ввода любыми способами (много пробовал, включая readline(), чтение в массив символов и т. Д.). каждый раз, когда я пытаюсь, приложение зависает на этом месте. Если я отлаживаю, он никогда не переходит к следующей строке кода.

В попытке решения я решил перейти на использование SSLEngine, поскольку это должен быть ответ Java 1.5 на java.nio для SSL. Тем не менее, я нашел один пример (здесь: http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/samples/sslengine/SSLEngineSimpleDemo.java), который несколько смущает меня, и я не был успешным в его реализации. Когда я пытаюсь, вызов unwrap() возвращает пустой буфер, где я знаю (используя OpenSSL в командной строке), что рассматриваемая служба отправляет данные обратно в канал.

Предложения приветствуются, я уже потратил слишком много времени на это. Вот соответствующий код:

SSLEngine engine = sslContext.createSSLEngine(uri.getHost(), uri.getPort());
            engine.setUseClientMode(true);
            engine.beginHandshake();
            SSLSession session = engine.getSession();
            int bufferMax = session.getPacketBufferSize();
            int appBufferMax = session.getApplicationBufferSize() + 50;
            ByteBuffer cTo = ByteBuffer.allocateDirect(bufferMax);
            ByteBuffer sTo = ByteBuffer.allocateDirect(bufferMax);

            ByteBuffer out = ByteBuffer.wrap(sessionId.getBytes());
            ByteBuffer in = ByteBuffer.allocate(appBufferMax);


            debug("sending secret");
            SSLEngineResult rslt = engine.wrap(out, cTo);
            debug("first result: " + rslt.toString());
            sTo.flip();
            rslt = engine.unwrap(sTo, in);
            debug("next result" + rslt.toString());

4 ответа

Решение

В этой реализации отсутствуют некоторые ключевые элементы. А именно, рукопожатие может отскочить между несколькими состояниями NEED_WRAP, NEED_UNWRAP, NEED_TASK для согласования соединения. Это означает, что вы не можете просто позвонить одному, а затем другому. Вам нужно будет переключаться между состояниями, пока рукопожатие не завершится.

   while (handshaking) {
      switch (state) {
          case NEED_WRAP:
              doWrap();
              break;
          case NEED_UNWRAP:
              doUnwrap();
              break;
          case NEED_TASK:
              doTask();
              break;
        }
    }

Полный рабочий пример Java SSL и NIO

Теперь вы должны знать, что SSLEngine на Android сломан. Google рекомендует использовать потоки и блокировать сокеты в соответствии с этим потоком.

Я написал что-то, чтобы сделать использование SSLEngine проще. Может использоваться с NIO или для других случаев использования. Доступный здесь SSLFacade

unwrap() может привести к пустому буферу, если распакованное было SSL-сообщением или предупреждением, а не данными приложения. Здесь недостаточно информации, чтобы сказать больше. Каково было состояние двигателя после этого?

beginHandshake не выполняет квитирование, оно просто используется для информирования SSLEngine о том, что вы хотите выполнить квитирование для следующих вызовов wrap / unwrap. Это полезно, когда вы хотите сделать еще одно рукопожатие. Для первоначального, он не нужен, так как первый вызов для переноса инициирует рукопожатие.

Кроме того, вы должны проверить результат методов переноса и развертывания, чтобы узнать, все ли данные были правильно закодированы. Может случиться так, что вам придется вызывать методы несколько раз, чтобы обработать все данные.

Следующая ссылка может помочь: http://onjava.com/onjava/2004/11/03/ssl-nio.html

Или этот вопрос: SSL Handshaking с использованием самоподписанных сертификатов и SSLEngine (JSSE)

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