Java SSLEngine говорит NEED_WRAP, вызывает .wrap () и все еще NEED_WRAP - PullRequest
7 голосов
/ 21 июня 2019

Я вижу странную проблему с SSLEngine и задаюсь вопросом, есть ли проблема с моим кодом или SSLEngine.Вот порядок, в котором я вижу вещи

  1. HandshakeStatus - NEED_WRAP
  2. Мы вызываем SSLEngine.WRAP
  3. после того, как в буфер записываются НУЛЬНЫЕ данные, иSSLEngineResult.result = OK (не переполнение и не переполнение :() и HandshakeStatus STILL NEED_WRAP

Самый важный вопрос: как тщательно отладить? Как «увидеть» каждое сообщение как-то? Я могу перехватить байтПоток достаточно легко, но есть ли какая-нибудь библиотека, которая может анализировать это в объектах рукопожатия SSL?

строка 298 (запись статуса предыдущего рукопожатия) в строку 328 (где мы выкидываем исключение с информацией) - это соответствующий код здесь

https://github.com/deanhiller/webpieces/blob/sslEngineFartingExample/core/core-ssl/src/main/java/org/webpieces/ssl/impl/AsyncSSLEngine3Impl.java

Трассировка стека была

2019-06-21 08:58:24,562 [-] [webpiecesThreadPool6] Caller+1  at org.webpieces.util.threading.SessionExecutorImpl$RunnableWithKey.run(SessionExecutorImpl.java:123)
  ERROR: Uncaught Exception
java.lang.IllegalStateException: Engine issue.  hsStatus=NEED_WRAP status=OK previous hsStatus=NEED_WRAP
    at org.webpieces.ssl.impl.AsyncSSLEngine3Impl.sendHandshakeMessageImpl(AsyncSSLEngine3Impl.java:328)
    at org.webpieces.ssl.impl.AsyncSSLEngine3Impl.sendHandshakeMessage(AsyncSSLEngine3Impl.java:286)
    at org.webpieces.ssl.impl.AsyncSSLEngine3Impl.doHandshakeWork(AsyncSSLEngine3Impl.java:133)
    at org.webpieces.ssl.impl.AsyncSSLEngine3Impl.doHandshakeLoop(AsyncSSLEngine3Impl.java:246)
    at org.webpieces.ssl.impl.AsyncSSLEngine3Impl.unwrapPacket(AsyncSSLEngine3Impl.java:210)
    at org.webpieces.ssl.impl.AsyncSSLEngine3Impl.doWork(AsyncSSLEngine3Impl.java:109)
    at org.webpieces.ssl.impl.AsyncSSLEngine3Impl.feedEncryptedPacket(AsyncSSLEngine3Impl.java:82)
    at org.webpieces.nio.impl.ssl.SslTCPChannel$SocketDataListener.incomingData(SslTCPChannel.java:175)
    at org.webpieces.nio.impl.threading.ThreadDataListener$1.run(ThreadDataListener.java:26)
    at org.webpieces.util.threading.SessionExecutorImpl$RunnableWithKey.run(SessionExecutorImpl.java:121)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)

Любые идеи? Как я могу действительно углубиться в это дальше? Я предпочитаю библиотеку, которая принимает байты и выплевывает sslобъекты, представляющие каждое сообщение рукопожатия или дешифрованный пакет (с любой информацией заголовка, которая идет с оригинальной зашифрованной вещью).

В частности, вот кодупомянутое выше

        HandshakeStatus previousStatus = sslEngine.getHandshakeStatus();
    //CLOSE and all the threads that call feedPlainPacket can have contention on wrapping to encrypt and
    //must synchronize on sslEngine.wrap
    Status lastStatus;
    HandshakeStatus hsStatus;
    synchronized (wrapLock ) {

        HandshakeStatus beforeWrapHandshakeStatus = sslEngine.getHandshakeStatus();
        if (beforeWrapHandshakeStatus != HandshakeStatus.NEED_WRAP)
            throw new IllegalStateException("we should only be calling this method when hsStatus=NEED_WRAP.  hsStatus=" + beforeWrapHandshakeStatus);

        //KEEEEEP This very small.  wrap and then listener.packetEncrypted
        SSLEngineResult result = sslEngine.wrap(SslMementoImpl.EMPTY, engineToSocketData);
        lastStatus = result.getStatus();
        hsStatus = result.getHandshakeStatus();
    }

    log.trace(()->mem+"write packet pos="+engineToSocketData.position()+" lim="+
                    engineToSocketData.limit()+" status="+lastStatus+" hs="+hsStatus);

    if(lastStatus == Status.BUFFER_OVERFLOW || lastStatus == Status.BUFFER_UNDERFLOW)
        throw new RuntimeException("status not right, status="+lastStatus+" even though we sized the buffer to consume all?");

    boolean readNoData = engineToSocketData.position() == 0;
    engineToSocketData.flip();
    try {
        CompletableFuture<Void> sentMsgFuture;
        if(readNoData) {
            log.trace(() -> "ssl engine is farting. READ 0 data.  hsStatus="+hsStatus+" status="+lastStatus);

            throw new IllegalStateException("Engine issue.  hsStatus="+hsStatus+" status="+lastStatus+" previous hsStatus="+previousStatus);
            //A big hack since the Engine was not working in live testing with FireFox and it would tell us to wrap
            //and NOT output any data AND not BufferOverflow.....you have to do 1 or the other, right!
            //instead cut out of looping since there seems to be no data
            //sslEngineIsFarting = true;
            //sentMsgFuture = CompletableFuture.completedFuture(null);

спасибо, Дин

Ответы [ 2 ]

1 голос
/ 30 июня 2019

о, еще лучше, снижение до 1.8.0_111 дает успех

2019-06-30 00:11:54,813 [main] Caller+1  at 
WEBPIECESxPACKAGE.DevelopmentServer.main(DevelopmentServer.java:32)
 INFO: Starting Development Server under java version=1.8.0_111

webpiecesThreadPool5, READ: TLSv1.2 Alert, length = 26
webpiecesThreadPool2, RECV TLSv1.2 ALERT:  warning, close_notify
webpiecesThreadPool2, closeInboundInternal()
webpiecesThreadPool2, closeOutboundInternal()
webpiecesThreadPool5, RECV TLSv1.2 ALERT:  warning, close_notify
webpiecesThreadPool5, closeInboundInternal()
webpiecesThreadPool5, closeOutboundInternal()
webpiecesThreadPool2, SEND TLSv1.2 ALERT:  warning, description = close_notify
webpiecesThreadPool5, SEND TLSv1.2 ALERT:  warning, description = close_notify
webpiecesThreadPool2, WRITE: TLSv1.2 Alert, length = 26
webpiecesThreadPool5, WRITE: TLSv1.2 Alert, length = 26
1 голос
/ 30 июня 2019

Хорошо, все больше и больше это похоже на ошибку jdk, и это, кажется, доказывает это сейчас.Мой журнал показывает, что я был на jdk11.0.3 (на MAC)

2019-06-29 23: 37: 18,793 [main] [] [-] Caller + 1 на WEBPIECESxPACKAGE.DevelopmentServer.main(DevelopmentServer.java:32) ИНФОРМАЦИЯ: Запуск сервера разработки под версией java = 11.0.3

Я использовал параметры флага отладки ssl

-Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack

Я окружил все свои вызовыsslEngine.wrap и sslEngine.unwrap с моими собственными журналами, и, к счастью, у всех также было имя потока в их журналах.

Кажется, когда клиенты отправляют предупреждение об этом

javax.net.ssl|DEBUG|14|webpiecesThreadPool1|2019-06-29 23:27:14.860 
MDT|Alert.java:232|Received alert message (
"Alert": {
  "level"      : "warning",
  "description": "close_notify"
}
)

SSLEngine говорит нам, что нам нужно WRAP, что является правильным, так как мы должны отвечать также close_notify, чтобы предотвратить атаки усечения, НО вместо этого движок возвращает 0 байтов и сообщает нам, что состояние движка все еще NEED_WRAP.

ТАКЖЕ, между моими журналами были до и после вызова sslEngine.wrap журналы отладки ssl ZERO, почти как sslEngine, пукнул и ничего не делал.

Тогда я думал, что буду действительнокруто и добавил это как первые строки в методе main ()

        System.setProperty("jdk.tls.server.protocols", "TLSv1.2");
        System.setProperty("jdk.tls.client.protocols", "TLSv1.2");

, но выбранная версия в отладочной информации была все еще TLSv1.3 .... grrrrrr ... о хорошо, я сдаюсь.

...