SSLEngine: неверные данные заполнения TLS при развертывании после успешного рукопожатия

Я использую неблокирующий 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) в первый раз, я не получаю этого исключения.

Я думал, что если ssengine не имеет достаточного количества байтов для распаковки, он вернет статус 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 байта, используя неблокирующий канал.

читать = _socketChannel.read (буфер);

а затем передайте 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);


person user3791570    schedule 09.10.2014    source источник


Ответы (1)


Здесь несколько вопросов.

  1. Если вы получаете BUFFER_OVERFLOW, вы должны flip(), write(), compact(), и повторить wrap(). Не просто распечатать его и отказаться, как указано выше.

  2. Если вы получили BUFFER_UNDERFLOW, вы должны прочитать() и повторить развертку(). Это ваша конкретная проблема.

  3. Если вы получаете Exception любого вида, недостаточно просто напечатать исключение и продолжить, как будто этого не произошло.

  4. FINISHED никогда не возвращается getHandshakeStatus(). Он всегда устанавливается только в статусе рукопожатия в SSLEngineResult, который возвращается wrap() и unwrap().

  5. Вы вызываете encrypt() из метода decrypt(). Это не имеет смысла.

  6. Ваша общая техника не будет работать. Рукопожатие может произойти в любое время, в середине чтения или записи, и вы должны написать свой код, чтобы справиться с этим. Когда вам это удастся, вам вообще не нужно будет вызывать собственный метод doHandshake(), так как ваш код все равно справится с этим.

SSLEngine — это конечный автомат. Вы должны делать именно то, что он говорит вам делать.

person user207421    schedule 10.10.2014
comment
да, я знаю, что блок try chatch был просто для того, чтобы показать, что исключение вызывается unwrap(). Мой вопрос заключался в том, почему, когда я передаю unwrap() 184 байта из 384, он выдает исключение вместо указания на буферный поток??? и почему, когда я передаю 384 байта из 384, он работает хорошо ?? - person user3791570; 10.10.2014
comment
в моем случае: метод unwrap выдает исключение и не возвращает BUFFER_UNDERFLOW, когда количество байтов недостаточно - person user3791570; 11.10.2014