在握手过程中从 SSLEngine Wrap 方法获取 SSLException

2023-12-27

当我在 Java 应用程序上运行客户端握手进程以建立 SSL 连接时,我得到SSLException第二次调用 wrap 方法时。我知道此时客户端发送了CLientKeyExchange and ChangeCipherSpec到服务器。我从异常中得到的错误消息是“General SSLEngine Problem”。也许我需要发送的证书有问题?

这是异常堆栈详细信息:

Details: General SSLEngine problem
Trace detail #0: com.sun.net.ssl.internal.ssl.Handshaker.checkThrown(Handshaker.java:994)
Trace detail #1: com.sun.net.ssl.internal.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:459)
Trace detail #2: com.sun.net.ssl.internal.ssl.SSLEngineImpl.writeAppRecord(SSLEngineImpl.java:1058)
Trace detail #3: com.sun.net.ssl.internal.ssl.SSLEngineImpl.wrap(SSLEngineImpl.java:1030)
Trace detail #4: javax.net.ssl.SSLEngine.wrap(SSLEngine.java:411)
Trace detail #5: epic.clarity.extract.CRSslSocketHandler.doHandshake(CRSslSocketHandler.java:333)
Trace detail #6: epic.clarity.extract.CRSslSocketHandler.readAndUnwrap(CRSslSocketHandler.java:282)
Trace detail #7: epic.clarity.extract.CRSslSocketHandler.doHandshake(CRSslSocketHandler.java:322)
Trace detail #8: epic.clarity.extract.CRSslSocketHandler.readAndUnwrap(CRSslSocketHandler.java:282)
Trace detail #9: epic.clarity.extract.CRSslSocketHandler.doHandshake(CRSslSocketHandler.java:322)
Trace detail #10: epic.clarity.extract.CRSslSocketHandler.ReadExtFile(CRSslSocketHandler.java:159)

这是我的代码,握手开始于Read method:

public class CRSslSocketHandler extends CRSocketHandler{

    private SSLEngine _engine;
    private SSLEngineResult.HandshakeStatus hsStatus;

    /**
    * Stores the result from the last operation performed by the SSLEngine 
    */
    private SSLEngineResult.Status status = null;

    /** Application data decrypted from the data received from the peer.
    * This buffer must have enough space for a full unwrap operation,
    * so we can't use the buffer provided by the application, since we
    * have no control over its size.
    */
    private final ByteBuffer peerAppData;
    /** Network data received from the peer. Encrypted. */  
    private final ByteBuffer peerNetData;
    /** Network data to be sent to the peer. Encrypted. */
    private final ByteBuffer netData;  

    /** Used during handshake, for the operations that don't consume any data */
    private ByteBuffer dummy;   


    private boolean initialHandshake = false;  

    private final String[] AvailProtocol = {"TLSv1"};

    private boolean FirstTime = true;

    //Debug
    private BufferedWriter  debugFile;
    private BufferedWriter  test;


    /** Creates a new instance of CRSslSocketHandler */
   public CRSslSocketHandler(SocketChannel channel, DualKeyHashtable queryCollection, DualKeyHashtable routineCollection, long sn, String hostName, int portNum) throws Exception {
       super(channel, queryCollection, routineCollection, sn);


       // Debug purposes
       debugFile = new BufferedWriter(new FileWriter("SslDebug.txt",true));
       test = new BufferedWriter(new FileWriter("ssltest.txt",true));
       try{
           System.out.println("Create Ssl Context");
            test.write("Create Ssl Context");  

            SSLContext sslContext = SSLContext.getInstance("TLSv1");
            System.out.println("Init Ssl Context");
            test.write("Init Ssl Context");

            /String Pass = "password";
            char[] passphrase = Pass.toCharArray();

            System.out.println("Get keys");
            test.write("Get keys");
            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream("keystore.ks"), passphrase);
             System.out.println("Get trust");
            test.write("Get trust");          
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            System.out.println("Init trust");
            test.write("Init trust");           
            tmf.init(ks); 

            System.out.println("Init context");
            test.write("Init context");         
            sslContext.init(null, tmf.getTrustManagers(), null);
             System.out.println("Create engine host name: " + hostName + " port number: " + portNum);
            test.write("Create engine host name: " + hostName + " port number: " + portNum);
            _engine = sslContext.createSSLEngine(hostName, portNum);
            // _engine = sslContext.createSSLEngine();
            System.out.println("Set client mode");
            test.write("Set client mode");            
            _engine.setUseClientMode(true);
            _engine.setEnabledProtocols(AvailProtocol);



            test.write("Begin Hanshaking");
            System.out.println("Begin Hanshaking");
            _engine.beginHandshake();
            hsStatus = _engine.getHandshakeStatus();
       }
       catch (IOException e){

       }
       catch (Exception e) {
           System.out.println("Exception: " + e.getMessage());
           test.write("Exception: " + e.getMessage());
           test.close();
       }
     System.out.println("Alocate buffers");
      test.write("Alocate buffers");
      SSLSession  session = _engine.getSession();
      peerNetData = ByteBuffer.allocate(session.getPacketBufferSize());
      peerAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
      netData = ByteBuffer.allocate(session.getPacketBufferSize());
      // Change the position of the buffers so that a 
      // call to hasRemaining() returns false. A buffer is considered
      // empty when the position is set to its limit, that is when
      // hasRemaining() returns false.      
      peerAppData.position(peerAppData.limit());
      netData.position(netData.limit());
      char c = (char)(28);
      String msg = "OK" + c;
      dummy = ByteBuffer.wrap(msg.getBytes());
      // dummy = ByteBuffer.allocate(0);
      initialHandshake = true;
      test.close();
    }

    protected int ReadExtFile(ByteBuffer buffer) throws IOException{
        if (initialHandshake) {
            doHandshake();
        }        
        // Check if the stream is closed.
        if (_engine.isInboundDone()) {
            // We reached EOF.
            return EOF;
        }
        // First check if there is decrypted data waiting in the buffers
        if (!peerAppData.hasRemaining()) {
            int appBytesProduced = readAndUnwrap();
            if (appBytesProduced == EOF){
                debugFile.write("Failed to read");
                debugFile.close();
                return appBytesProduced;
            }
            if (appBytesProduced == 0) {
                return appBytesProduced;
            } 
        }

        // It's not certain that we will have some data decrypted ready to 
        // be sent to the application. Anyway, copy as much data as possible
        int limit = Math.min(peerAppData.remaining(), buffer.remaining());
        for (int i = 0; i < limit; i++) {
            buffer.put(peerAppData.get());
        }
        return limit;
    }
    private int readAndUnwrap() throws IOException {
        // No decrypted data left on the buffers.
        // Try to read from the socket. There may be some data
        // on the peerNetData buffer, but it might not be sufficient.
        int bytesRead = _client.read(peerNetData);
        // decoder.decode(peerNetData, charBuffer, false);
        // charBuffer.flip();               
        System.out.println("Read bytes " + bytesRead);


        if (bytesRead == EOF) {
            // We will not receive any more data. Closing the engine
            // is a signal that the end of stream was reached.
            _engine.closeInbound();         
            // EOF. But do we still have some useful data available? 
            if (peerNetData.position() == 0 ||
            status == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
                // Yup. Either the buffer is empty or it's in underflow,
                // meaning that there is not enough data to reassemble a
                // TLS packet. So we can return EOF.
                return EOF;
            }
            // Although we reach EOF, we still have some data left to
            // be decrypted. We must process it 
        }

        // Prepare the application buffer to receive decrypted data
        peerAppData.clear();

        // Prepare the net data for reading. 
        peerNetData.flip();
        SSLEngineResult res;
        System.out.println("Do unwrap " + bytesRead);
        try{
            do {
                res = _engine.unwrap(peerNetData, peerAppData);
                System.out.println("Read status" + res.getHandshakeStatus().toString());
                // During an handshake renegotiation we might need to perform
                // several unwraps to consume e handshake data.
            } while (res.getStatus() == SSLEngineResult.Status.OK &&
            res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP &&
            res.bytesProduced() == 0);

            System.out.println("Read status" + res.getHandshakeStatus().toString());
            // If the initial handshake finish after an unwrap, we must activate
            // the application interestes, if any were set during the handshake
            if (res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) {
                initialHandshake = false;
            }
           // If no data was produced, and the status is still ok, try to read once more
           if (peerAppData.position() == 0 && 
            res.getStatus() == SSLEngineResult.Status.OK &&
            peerNetData.hasRemaining()) {
               res = _engine.unwrap(peerNetData, peerAppData);                             
            }
           /*
            * The status may be:
            * OK - Normal operation
            * OVERFLOW - Should never happen since the application buffer is 
            *   sized to hold the maximum packet size.
            * UNDERFLOW - Need to read more data from the socket. It's normal.
            * CLOSED - The other peer closed the socket. Also normal.
            */
            status = res.getStatus();
            hsStatus = res.getHandshakeStatus();
            // Should never happen, the peerAppData must always have enough space
            // for an unwrap operation
            assert status != SSLEngineResult.Status.BUFFER_OVERFLOW : 
            "Buffer should not overflow: " + res.toString();  
        }
        catch (Exception e){
            System.out.println("Error: " + e.getMessage());
        }




        // The handshake status here can be different than NOT_HANDSHAKING
        // if the other peer closed the connection. So only check for it
        // after testing for closure.
        if (status == SSLEngineResult.Status.CLOSED) {
            debugFile.write("Connection is being closed by peer.");
            return EOF;
        }   

        // Prepare the buffer to be written again.
        peerNetData.compact();
        // And the app buffer to be read.
        peerAppData.flip();

        if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK ||
                hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP ||
                hsStatus == SSLEngineResult.HandshakeStatus.FINISHED) 
        {
            debugFile.write("Rehandshaking...");
            doHandshake();
        }

        return peerAppData.remaining();
    }

        public void closeSocket(boolean timeout){

            super.closeSocket(timeout);
            try{
                debugFile.write("Close");
                debugFile.close();
            }catch(IOException e){}
        }

    /**
     * Execute delegated tasks in the main thread. These are compute
     * intensive tasks, so there's no point in scheduling them in a different
     * thread.
     */
    private void doTasks() {
        Runnable task;
        while ((task = _engine.getDelegatedTask()) != null) {
            task.run();
        }
        hsStatus = _engine.getHandshakeStatus();
    }
        private void doHandshake() throws IOException {
            while (true) {
                SSLEngineResult res;
                System.out.println("Handshake status: " + hsStatus.toString());
                switch (hsStatus) {
                    case FINISHED:
                        initialHandshake = false;
                        return; 
                    case NEED_TASK:
                        doTasks();
                        // The hs status was updated, so go back to the switch
                        break;
                    case NEED_UNWRAP:
                        readAndUnwrap();
                        return;
                    case NEED_WRAP:

                        if (netData.hasRemaining()) {
                            return;
                        }
                        // Prepare to write
                            netData.clear();

                            try{
                            res = _engine.wrap(dummy, netData);

                            if (res.bytesProduced() == 0){
                                System.out.println("No net data produced during handshake wrap.");
                            }
                            else{
                                System.out.println("Result status: " + res.getStatus() + "Bytes porduced: " + res.bytesProduced());
                            }
                            if (res.bytesConsumed() != 0){
                                System.out.println("App data consumed during handshake wrap.");
                            }
                            hsStatus = res.getHandshakeStatus();
                        }catch(SSLException se){

                            System.out.println("Error: " + se.getMessage());
                            System.out.println("Details: " + se.getLocalizedMessage());
                            throw se;
                        }

                        System.out.println(hsStatus.toString());
                        netData.flip();
                        try{
                            int writebytes = _client.write(netData);
                            System.out.println("Number of bytes sent: " + writebytes);
                            if (netData.hasRemaining()) {
                                System.out.println("netdata has remaining");
                            }
                         }
                         catch(Exception e){
                             System.out.println(e.getMessage());
                         } 
                        break;
                    case NOT_HANDSHAKING:
                        assert false : "doHandshake() should never reach the NOT_HANDSHAKING state";
                        return;
            }
        }
    }


}

The SSLEngine严重难以使用。您的代码有几个问题。

例如NEED_WRAP意味着引擎想要写一些东西。如果传出的网络缓冲区中有数据,它不会写入任何内容,因此,如果是这种情况,您需要把它写出来从而清空缓冲区,然后进行换行。仅仅忽略条件是不够的。

其中还有一个微妙之处FINISHEDstatus:在每次返回的握手状态中设置SSLEngine method except getHandshakeStatus():即这是一个非常短暂的情况。

可能还有更多,但我没有时间看,抱歉。我可以推荐SSLEngine中的章节。它包含一个工作的 SSLEngine 管理器。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在握手过程中从 SSLEngine Wrap 方法获取 SSLException 的相关文章

  • Hashmap并发问题

    我有一个哈希图 出于速度原因 我希望不需要锁定 假设我不介意过时的数据 同时更新它和访问它会导致任何问题吗 我的访问是获取 而不是迭代 删除是更新的一部分 是的 这会导致重大问题 一个例子是向散列映射添加值时可能发生的情况 这可能会导致表重
  • 位图内存不足错误

    我对这个错误有疑问 我从 URL 制作网站图标解析器 我这样做是这样的 public class GrabIconsFromWebPage public static String replaceUrl String url StringB
  • JavaFX 图像未在舞台中显示

    我尝试了很多次 尝试了很多方法 但都无法让自己的形象在舞台上如我所愿 我认为这可能与java寻找资源的路径有关 但我不确定 因为我刚刚开始使用视觉库 在本例中为JavaFX 这是我的目录结构 MyProject assets img myI
  • 使用 Java 在 WebDriver 中按 Ctrl+F5 刷新浏览器

    我已经使用 java 刷新了 WebDriver 中的浏览器 代码如下 driver navigate refresh 如何使用 Java 在 WebDriver 中按 Ctrl F5 来做到这一点 我认为您可以使用 WebDriver 和
  • Junit maven构建错误(maven-surefire-plugin:2.19.1:测试失败:分叉进程中出现错误)[重复]

    这个问题在这里已经有答案了 我通过引用创建了一个示例 struts 2 项目和 J unit 测试用例link http self learning java tutorial blogspot com au 2015 04 struts2
  • 如何在远程 WebSphere 上进行 JNDI 查找期间解决 sun/io/MalformedInputException

    我使用 WebSphere 8 5 来托管我的应用程序 并在应用程序服务器上配置了一些 JDBC 资源 我还使用瘦客户端运行时库开发了一个客户端应用程序 当按以下方式执行 JNDI 查找时 env put Context INITIAL C
  • 使用 ChannelExec 的命令未执行 - Jsch

    我正在使用 Jsch 在服务器中创建一个文件并执行一些命令 对于文件创建 它工作正常 但是对于命令执行 则不然 它保持状态 1 仍在处理它 并永远保持该状态 这种情况发生在 shell 执行或我尝试成为 root 时 请按照以下方法操作 p
  • Spring3/Hibernate3/TestNG:有些测试给出 LazyInitializationException,有些则没有

    前言 我在单元测试中遇到了 LazyInitializationException 的问题 而且我很难理解它 正如你从我的问题中看到的那样Spring 中的数据库会话 https stackoverflow com questions 13
  • 将过滤器添加到 Eclipse 中的 Project Explorer

    我想向 Project Explorer 添加一个新的过滤器 以向用户隐藏一些在 Eclipse RCP 应用程序中自动创建的项目 到目前为止我已经找到了两个扩展点 org eclipse ui ide resourceFilters 允许
  • 字符串池可以包含两个具有相同值的字符串吗? [复制]

    这个问题在这里已经有答案了 字符串池可以包含两个具有相同值的字符串吗 String str abc String str1 new String abc Will the second statement with new operator
  • 定期更新 SWT 会导致 GUI 冻结

    Problem 当 GUI 字段定期更新时 SWT 会冻结 我想要一个基于 SWT 的 GUI 其中文本字段的值会定期递增 最初我从单独的线程访问 textField 导致抛出异常 线程 Thread 0 org eclipse swt S
  • 有多少种方法可以将位图转换为字符串,反之亦然?

    在我的应用程序中 我想以字符串的形式将位图图像发送到服务器 我想知道有多少种方法可以将位图转换为字符串 现在我使用 Base64 格式进行编码和解码 它需要更多的内存 是否有其他可能性以不同的方式做同样的事情 从而消耗更少的内存 现在我正在
  • 所有平台上的java

    如果您想用 java 为 Windows Mac 和 Linux 编写桌面应用程序 那么所有这些代码都相同吗 您只需更改 GUI 即可使 Windows 应用程序更像 Windows 等等 如果不深入细节 它是如何工作的 Java 的卖点之
  • 异步迭代器

    我有以下代码 while slowIterator hasNext performLengthTask slowIterator next 由于迭代器和任务都很慢 因此将它们放入单独的线程中是有意义的 这是对迭代器包装器的快速而肮脏的尝试
  • Jenkins 的代码覆盖率 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 在 Java 中将弯音发送到 MIDI 音序器

    我了解启动和运行 MIDI 音序器的基础知识 并且希望能够在播放过程中增加 减小序列的音高 但弯音是发送到合成器而不是音序器的消息 我尝试将音序器的接收器设置为合成器的发射器 当我发送弯音短消息时 音序器保持相同的音调 但随后合成器以新的弯
  • 改变for循环的顺序?

    我遇到一种情况 我需要根据用户输入以不同的顺序循环遍历 xyz 坐标 所以我是 3D 空间中的一个区域 然后是一组像这样的 for 循环 for int x 0 x lt build getWidth x for int y 0 y lt
  • 如何初始化静态地图?

    你会如何初始化静态Map在Java中 方法一 静态初始化方法二 实例初始化 匿名子类 或者 还有其他方法吗 各自的优点和缺点是什么 这是说明这两种方法的示例 import java util HashMap import java util
  • 公共方法与公共 API

    在干净的代码书中 有一个观点是 公共 API 中的 Javadocs 同样 Effective java 一书也有这样的内容 项目 56 为所有公开的 API 元素编写文档注释 所以这就是我的问题 所有公共方法都被视为公共 API 吗 它们
  • 为什么应该首选 Java 类的接口?

    PMD https pmd github io 将举报以下违规行为 ArrayList list new ArrayList 违规行为是 避免使用 ArrayList 等实现类型 而是使用接口 以下行将纠正违规行为 List list ne

随机推荐