我看到 SSLEngine 有一个奇怪的问题,想知道我的代码或 SSLEngine 是否有问题。这是我看到事物的顺序
- HandshakeStatus 是 NEED_WRAP
- 我们调用 SSLEngine.WRAP
- 之后,有零数据写入缓冲区,并且 SSLEngineResult.result=OK(not overflow or underflow :( ) 并且 HandshakeStatus 是 STILL NEED_WRAP
最重要的问题:如何彻底调试?如何以某种方式“看到”每条消息?我可以很容易地捕获字节流,但是是否有一些库可以将其解析为 SSL 握手对象?
第 298 行(记录之前的握手状态)到第 328 行(我们用信息抛出异常)是这里的相关代码
堆栈跟踪是
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);
谢谢,院长