OpenJDK 11问题-客户在上一次UNWRAP之前完成了握手

时间:2018-12-20 22:15:35

标签: java ssl java-8 nio java-11

我正在将代码库从Oracle Java 1.8.0_131迁移到OpenJDK 11.0.1。我们有实现nio-ssl套接字通道的代码。在Java 8中,客户端/服务器握手可以正常工作。在Java 11中,客户端在结束包装来自服务器的最后一次握手消息之前完成了握手。

要产生此问题,我只是在客户端和服务器之间建立连接,并让它们执行SSL握手。我不会通过发送任何其他数据。

我使用Java 8建立连接并获得以下输出。 然后,我使用Java 11编译,构建和运行相同的代码,并在下面获取其他输出。我不更改任何代码。

我在客户端和服务器上都进行了一些登录,以显示它们在握手中处于哪一步。

日志输出Java 8-客户端

SSL Handshake Started
WRAP:OK -   BytesProduced=172  BytesConsumed=0
UNWRAP:OK - BytesProduced=0    BytesConsumed=2295
TASK
WRAP:OK -   BytesProduced=1815 BytesConsumed=0
WRAP:OK -   BytesProduced=269  BytesConsumed=0
WRAP:OK -   BytesProduced=6    BytesConsumed=0
WRAP:OK -   BytesProduced=85   BytesConsumed=0
UNWRAP:OK - BytesProduced=0    BytesConsumed=6
UNWRAP:OK - BytesProduced=0    BytesConsumed=85
SSL Handshake complete

日志输出Java 8-服务器

SSL Handshake Started
UNWRAP:OK - BytesProduced=0    BytesConsumed=172
TASK
WRAP:OK -   BytesProduced=2295 BytesConsumed=0
UNWRAP:OK - BytesProduced=0    BytesConsumed=1815
TASK
UNWRAP:OK - BytesProduced=0    BytesConsumed=269
TASK
UNWRAP:OK - BytesProduced=0    BytesConsumed=6
UNWRAP:OK - BytesProduced=0    BytesConsumed=85
WRAP:OK -   BytesProduced=6    BytesConsumed=6
WRAP:OK -   BytesProduced=85   BytesConsumed=0
SSL Handshake complete

日志输出Java 11-客户端

SSL Handshake Started
WRAP:OK -   BytesProduced=422  BytesConsumed=0
UNWRAP:OK - BytesProduced=0    BytesConsumed=160
TASK
WRAP:OK -   BytesProduced=6    BytesConsumed=0
UNWRAP:OK - BytesProduced=0    BytesConsumed=6
UNWRAP:OK - BytesProduced=0    BytesConsumed=2204
TASK
WRAP:OK -   BytesProduced=2067 BytesConsumed=0
SSL Handshake complete
UNWRAP:OK - BytesProduced=0    BytesConsumed=72

日志输出Java 11-服务器

SSL Handshake Started
UNWRAP:OK - BytesProduced=0    BytesConsumed=422
TASK
WRAP:OK -   BytesProduced=160  BytesConsumed=0
WRAP:OK -   BytesProduced=6    BytesConsumed=0
WRAP:OK -   BytesProduced=2204 BytesConsumed=0
UNWRAP:OK - BytesProduced=0    BytesConsumed=6
UNWRAP:OK - BytesProduced=0    BytesConsumed=2067
TASK
WRAP:OK -   BytesProduced=72    BytesConsumed=0
SSL Handshake complete

握手代码

engine.beginHandshake();
HandshakeStatus hs = engine.getHandshakeStatus();
while(hs != HandshakeStatus.FINISHED && hs != HandshakeStatus.NOT_HANDSHAKING){
  switch(hs){
    case NEED_WRAP:
      SSLEngineResult res = engine.wrap(myAppData, myNetData)
      hs = res.getHandshakeStatus();
      switch(res.getStatus()){
        case OK:
          // write myNetData
        case BUFFER_OVERFLOW:
          // increase size of myNetData
        case BUFFER_UNDERFLOW:
          // throw exception
        case CLOSED:
          // clean up
        default:
          // throw illegal state exception
      }
      break;
    case NEED_UNWRAP:
      boolean complete = false;
      while(!complete){
        /*
         * First handle any encrypted data left on buffer
         * If there is none, read in more
         */
        if(peerNetData.position() > 0 || channel.read(peerNetData) > 0){
          peerNetData.flip();
          res = engine.unwrap(peerNetData, peerAppData);
          hs = res.getHandshakeStatus();
          switch(res.getStatus()){
            case OK:
              complete = true;
              peerNetData.compact();
              break;
            case BUFFER_UNDERFLOW:
              // if buffer is full, increase size
              // if buffer isn't full, compact and read
            case BUFFER_OVERFLOW:
              // increase size of peerAppData
            case CLOSED:
              // cleanup
            default:
              // throw illegal state exception
          }
        }
      }
      break;
    case NEED_TASK:
      // Run task
      hs = engine.getHandshakeStatus();
      break;
    case FINISHED:
      break;
    case NOT_HANDSHAKING:
      break;
    default:
      // illegal state
  }
}

不幸的是,我的代码驻留在有空隙的环境中,因此将其粘贴到此处并不容易。我是手动输入的,因此括号和制表符可能无法对齐。

要点是hs = res.getHandshakeStatus(...)在看起来应该返回FINISHED的情况下,在2067字节的换行之后在客户端计算机上返回NEED_UNWRAP。如果我将其更改为hs = engine.getHandshakeStatus(),它将返回NOT_HANDSHAKING

在服务器计算机上,hs = engine.getHandshakeStatus()在运行最后一个任务后NEED_WRAP返回import numpy as np import cv2 # Store the sequence in an array seq = [] cap = cv2.VideoCapture('my_video.avi') while(cap.isOpened()) : ret, frame = cap.read() if (ret == False) : break seq.append(frame) # Possibly convert list to np.array here # Finding the most distant images distance_matrix = np.zeros( (len(seq), len(seq)) ) for i in range(len(seq)) : for j in range(i+1,len(seq)) : distance_matrix[i][j] = cv2.norm(seq[i], seq[j], cv2.NORM_L1) # Get max index (method given on scipy doc) im1, im2 = np.unravel_index(np.argmax(distance_matrix), distance_matrix.shape) print("The most distant frames are n°", im1, "and n°", im2)

当从服务器到UNWRAP仍有72个字节的数据时,为什么客户机上的SSLEngine会给我一个握手状态“完成”?其他人是否对Java 11的自定义握手逻辑有任何疑问?

2 个答案:

答案 0 :(得分:3)

JavaDoc of SSLEngine在类描述的末尾有关于并发的注释。

因此,我根据竞争条件假设您的问题看起来像是一个并发问题。从JDK 8迁移到JDK 11后,同时调用wrapunwrap函数的方式可能会有所不同。您提供的示例代码没有任何同步语句。

如果您将两个函数调用与一个共享对象同步,则握手应该在上一次解包之后每次完成。

答案 1 :(得分:0)

对于寻求使用 SSLEngine 解决此问题的任何人,此问题的原因是 TLS 1.3 中定义的握手后消息:https://tools.ietf.org/html/rfc8446#section-4.6 要在您的应用程序中正确处理此类消息,您必须检查 unwrap 调用的握手状态,如果状态为 FINISHED,但握手已经完成,这很可能是由握手后消息引起的,必须再次读取和解包数据。 另见:https://stackoverflow.com/a/57409789/6561198