2

非ブロックの socketChannel と SSLEngine を ssl サーバーとして使用しています。したがって、ハンドシェイクが成功した後、ソケットを読み取り(184バイト/ 384バイトが最初に読み取られます)、このバッファーをunwrapメソッドに渡します。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 にアンラップするのに十分なバイトがない場合、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次に、復号化する を渡します。

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); で例外がスローされています。

4

1 に答える 1

0

ここでいくつかの問題。

  1. あなたがBUFFER_OVERFLOWしなければならない場合はflip(), write(), compact(),、 を繰り返しますwrap()。上記のように印刷してあきらめるだけではありません。

  2. 取得したBUFFER_UNDERFLOW場合は、read() と unwrap() を繰り返す必要があります。これはあなたの特定の問題です。

  3. 何らかのエラーが発生した場合Exception、例外を出力して、発生しなかったかのように処理を続行するだけでは十分ではありません。

  4. FINISHEDによって返されることはありませんgetHandshakeStatus()。およびSSLEngineResultによって返されるのハンドシェイク ステータスでのみ設定されます。wrap()unwrap()

  5. encrypt()メソッド内から呼び出していますdecrypt()。これは意味がありません。

  6. あなたの全体的なテクニックは機能しません。ハンドシェイクは、読み取りまたは書き込みの途中でいつでも発生する可能性があり、それに対処できるようにコードを作成する必要があります。doHandshake()これに成功すると、コードがとにかくそれを処理するため、独自のメソッドを呼び出す必要はまったくありません。

SSLEngine はステート マシンです。指示されたことを正確に実行する必要があります。

于 2014-10-10T03:54:08.307 に答える