2014-10-09 333 views
2

我正在使用非阻塞socketChannel和SSLEngine ssl服務器。因此,在成功握手之後,我讀取了套接字(第一次讀取了184字節/ 384字節),然後將此緩衝區傳遞給解包方法。解包方法拋出以下異常:SSLEngine:成功握手後解包時無效的TLS填充數據

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) 

但在情況下,我在第一時間閱讀所有字節(三百八十四分之三百八十四),然後我沒有得到這個例外。

我認爲,如果sslengine沒有足夠的字節來展開它將返回一個bufferUnderflow狀態。

我真的需要所有字節來調用unwrap方法嗎?如果是的話我怎麼能確定我讀取了非阻塞套接字的所有字節?


編輯:代碼:

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; 

    } 

然後我讀取使用非阻塞信道184/384字節。

read = _socketChannel.read(buffer);

然後傳遞到buffer進行解密:

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; 
    } 

異常在engine.unwrap被拋出 engineRes = engine.unwrap(inNetData,outAppData);

+0

發佈一些代碼。 – EJP 2014-10-09 21:17:48

+0

完成。請幫助 – user3791570 2014-10-10 03:08:12

回答

0

這裏有幾個問題。

  1. 如果你BUFFER_OVERFLOW你必須flip(), write(), compact(),和重複wrap()。不只是打印它,並放棄如上。

  2. 如果您得到BUFFER_UNDERFLOW您必須閱讀()並重復unwrap()。這是你的具體問題。

  3. 如果您收到任何類型的Exception,僅僅打印異常並繼續就好像它沒有發生那樣是不夠的。

  4. FINISHED永遠不會由getHandshakeStatus()返回。它只在SSLEngineResult的握手狀態中設置,由wrap()unwrap()返回。

  5. 您正在從decrypt()方法中調用encrypt()。這沒有意義。

  6. 您的整體技術將無法使用。握手可以隨時發生,在閱讀或寫作的過程中,您必須編寫代碼以應對這種情況。當你取得成功時,你根本不需要調用你自己的doHandshake()方法,因爲無論如何你的代碼都可以應付它。

SSLEngine是一個狀態機。你必須完成它告訴你要做的事情。

+0

是的,我知道嘗試聊天塊只是爲了顯示異常是由unwrap()拋出。我的問題是,爲什麼當我通過解開()384字節中的184個字節時,它會拋出一個exeception而不是指向bufferunderflow?以及爲什麼當我傳遞384字節384它運作良好? – user3791570 2014-10-10 13:10:23

+0

在我的情況下:unwrap方法拋出一個異常,並且當字節數不夠時不返回BUFFER_UNDERFLOW – user3791570 2014-10-10 20:16:20