java - SSLEngine:在成功握手后展开时无效的 TLS 填充数据

标签 java rest http ssl sslengine

我正在使用非阻塞 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;

    }

然后我使用非阻塞 channel 读取 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);

最佳答案

这里有几个问题。

  1. 如果你得到 BUFFER_OVERFLOW 你必须 flip(), write(), compact(), 并重复 wrap()。而不是像上面那样打印出来就放弃。

  2. 如果您得到 BUFFER_UNDERFLOW,您必须 read() 并重复 unwrap()。这是您的具体问题。

  3. 如果您遇到任何类型的异常,仅仅打印异常并继续就好像它没有发生一样是不够的。

  4. FINISHED 永远不会被 getHandshakeStatus() 返回。它仅在 wrap()unwrap() 返回的 SSLEngineResult 中的握手状态中设置。

  5. 您正在从 decrypt() 方法中调用 encrypt()。这没有意义。

  6. 您的整体技术行不通。握手随时可能发生,在读取或写入过程中,您必须编写代码来应对这种情况。成功后,您根本不需要调用自己的 doHandshake() 方法,因为您的代码无论如何都会处理它。

SSLEngine 是一个状态机。您必须完全按照它告诉您的去做。

关于java - SSLEngine:在成功握手后展开时无效的 TLS 填充数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26286491/

相关文章:

java - REST API - 嵌套对象

rest - 微服务认证

javascript - 我如何将输入文本传递到 React 应用程序中的过滤器组件

ruby - 具有自定义 IP 的域上的 HTTP 请求

angular - 连续休息 API http 调用 Angular 4

java - 在 Java 中标记字符串

java - 在 JAR 中强制系统属性

java - Haxe Java 窗口

java - @PrimaryKeyJoinColumn 在 Hibernate 中的一对一映射中无法按预期工作

http - http.StatusFound 是否是点击重定向的正确状态?