Java SSLEngine:成功握手后展开时TLS填充数据无效

Java SSLEngine:成功握手后展开时TLS填充数据无效,java,rest,http,ssl,sslengine,Java,Rest,Http,Ssl,Sslengine,我正在使用非阻塞socketChannel和SSLEngine作为ssl服务器。因此,在成功握手之后,我读取套接字(第一次读取184字节/384字节),然后将此缓冲区传递给unwrap方法。“展开”方法引发以下异常: javax.net.ssl.SSLHandshakeException: Invalid TLS padding data at sun.security.ssl.Alerts.getSSLException(Unknown Source) at sun.secur

我正在使用非阻塞socketChannel和SSLEngine作为ssl服务器。因此,在成功握手之后,我读取套接字(第一次读取184字节/384字节),然后将此缓冲区传递给unwrap方法。“展开”方法引发以下异常:

javax.net.ssl.SSLHandshakeException: Invalid TLS padding data
    at sun.security.ssl.Alerts.getSSLException(Unknown Source)
    at sun.security.ssl.SSLEngineImpl.fatal(Unknown Source)
    at sun.security.ssl.SSLEngineImpl.readRecord(Unknown Source)
    at sun.security.ssl.SSLEngineImpl.readNetRecord(Unknown Source)
    at sun.security.ssl.SSLEngineImpl.unwrap(Unknown Source)
    at javax.net.ssl.SSLEngine.unwrap(Unknown Source)
但是如果我第一次读取所有字节(384/384),那么我不会得到这个异常

我认为如果sslengine没有足够的字节来展开,它将返回缓冲区下溢状态

我真的需要所有字节来调用展开方法吗?如果是,如何确保读取非阻塞套接字的所有字节


编辑:代码:

public boolean doHandShake(SocketChannel socket) throws Exception{

        if(!socket.isConnected()){
            return false;
        }

        outAppData.clear();
        inAppData.clear();
        inNetData.clear();
        outNetData.clear();

        if(engine==null || socket==null)
         return false;


          engine.beginHandshake();
          SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();

          while (hs != SSLEngineResult.HandshakeStatus.FINISHED &&
                    hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {

              switch (hs) {

              case NEED_UNWRAP:
                   int read=1;
                  while (read > 0) {
                            read=socket.read(inNetData);
                            if(read==-1){
                                throw new IOException ("channel closed");
                            }
                        }

                  inNetData.flip();
                  engineRes=engine.unwrap(inNetData, outAppData);
                  inNetData.compact();

                  switch(engineRes.getStatus()){
                            case BUFFER_OVERFLOW:
                                System.out.println("overFlow");
                                break;
                            case CLOSED:
                                return false;
                            case OK:
                                //outAppData.clear();
                            //  inNetData.clear();
                                break;
                            default:
                                break;
                  }

              break;

              case NEED_WRAP :
                 outNetData.clear();
                  engineRes=engine.wrap(inAppData, outNetData);
                  outNetData.flip();
                  switch (engineRes.getStatus()){
                            case BUFFER_OVERFLOW:
                                System.out.println("overFlow");
                                break;
                            case BUFFER_UNDERFLOW:
                                System.out.println("underFlowa");
                                break;
                            case CLOSED:
                                return false;
                            case OK:
                                //outNetData.flip();
                                while(outNetData.hasRemaining()){
                                    if(socket.write(outNetData)<0){
                                        throw new Exception("Channel Has been Closed");
                                    }
                                }

                                break;
                            default:
                                break;


                  }

              break;

              case NEED_TASK :
                  Runnable r=engine.getDelegatedTask();
                  r.run();
                  break;

              case FINISHED:
                  System.out.println("finished");
                    break;

              case NOT_HANDSHAKING:
                    break;

                  default: 
                      throw new IllegalArgumentException("Inexpected/Unhadled SSLEngineResult :"+hs);

              }

              hs = engine.getHandshakeStatus();

          }
          return true;

    }
正在engine.unwrap中引发异常 engineRes=engine.unwrap(inNetData,outAppData)

这里有几个问题

  • 如果出现
    BUFFER\u溢出
    ,则必须
    flip()、write()、compact()、
    并重复
    wrap()
    。不只是打印出来,然后像上面那样放弃

  • 如果出现
    BUFFER\u下溢
    ,则必须读取()并重复展开()。这是你的具体问题

  • 如果您得到任何类型的
    异常
    ,仅打印异常并像没有发生一样继续是不够的

  • getHandshakeStatus()
    从不返回
    FINISHED
    。它仅在由
    wrap()
    unwrap()
    返回的
    sslenginresult
    中的握手状态下设置

  • 您正在从
    decrypt()
    方法中调用
    encrypt()
    。这没有道理

  • 你的整体技术不起作用。握手可能发生在任何时间,在读或写的中间,你必须编写你的代码,以应付这种情况。当您成功地做到这一点时,您根本不需要调用自己的
    doHandshake()
    方法,因为您的代码无论如何都会处理它


  • SSLEngine是一个状态机。您必须完全按照它的指示执行。

    是的,我知道try-chatch块只是为了显示unwrap()正在抛出异常。我的问题是,为什么当我将384字节中的184字节传递给unwrap()时,它会抛出一个exeception而不是指向bufferunderflow???为什么当我从384中传递384字节时,它工作得很好?在我的例子中:unwrap方法抛出一个异常,当字节数不够时,它不会返回缓冲区溢出
    public ByteBuffer decrypt(ByteBuffer inNetData) throws SSLException{
    
            if(!isValidSession()){
                return null;
            }
                outAppData.clear();
    
                try{
                  engineRes=engine.unwrap(inNetData, outAppData);
                }catch(Exception e){
                    e.printStackTrace();
                }
                  inNetData.compact();
    
                  switch(engineRes.getStatus()){
                        case BUFFER_OVERFLOW:
                            outAppData=ByteBuffer.allocate(outNetData.capacity()*2);
                            inNetData.position(0);
                            return encrypt(inNetData);
                        case BUFFER_UNDERFLOW:
                            return null;
                        case CLOSED:
                            return null;
                        case OK:
                            outAppData.flip();
                            System.out.println(new String(outAppData.array(),0,400));
    
                            return outAppData;
                        default:
                            break;
                  }
    
    
            return null;
        }