【问题标题】:java ssl tcp connection ok but data received to server is incorrectjava ssl tcp 连接正常,但接收到服务器的数据不正确
【发布时间】:2014-07-31 07:05:14
【问题描述】:

我的问题是我在 java iso 客户端和测试服务器之间有 ssl 连接。连接正常,握手没有问题,但服务器接收到的数据不正确。

正如我在日志服务器中看到的那样,在一次读取操作期间仅接收到部分数据,并且输入流中还存在一些奇怪的数据 - 可能与证书信息有关。

请注意,如果没有 ssl,此客户端和服务器可以正常工作。此外,当我通过 java keyTool 简单地创建 jks 标准证书时,一切正常,不会发生问题。

但是当我使用 x509 时,无论我是通过从 cmd 生成 jks 将证书作为服务器 jvm 的参数发送,还是使用下面的代码在代码中生成 jks,都会发生问题。连接和握手始终正常,但输入流中的数据已损坏。

这是我使用 boucycastle 库获得证书的方式。客户端和服务器几乎一样

private SSLServerSocketFactory handleCertificate() throws KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException {
    Security.addProvider(new BouncyCastleProvider());

    PEMReader pr = new PEMReader(new FileReader("p.pem"));
    X509CertificateObject cert = (X509CertificateObject) pr.readObject();

    PEMReader pr2 = new PEMReader(new FileReader("klient.cer"));
    X509CertificateObject cert2 = (X509CertificateObject) pr2.readObject();

    PEMReader kr = new PEMReader(new FileReader("001.key"),
            new PasswordFinder() {
                public char[] getPassword() {
                    return "password".toCharArray();
                }
            });

    KeyStore trustKeys = KeyStore.getInstance("JKS");
    trustKeys.load(null, "".toCharArray());
    trustKeys.setCertificateEntry("1", cert);

    KeyStore ksKeys = KeyStore.getInstance("JKS");
    ksKeys.load(null, "password".toCharArray());
    ksKeys.setCertificateEntry("1", cert2);

    org.bouncycastle.jce.provider.JCERSAPrivateCrtKey key;
    Object PK = kr.readObject();

    if (PK instanceof KeyPair) {
        key = (JCERSAPrivateCrtKey) ((KeyPair) PK).getPrivate();
    } else {
        key = (JCERSAPrivateCrtKey) PK;
    }

    ksKeys.setKeyEntry("1", key, "password".toCharArray(), new Certificate[] { cert2 });

    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(ksKeys, "password".toCharArray());

    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
    tmf.init(trustKeys);

    SSLContext sslContext = SSLContext.getInstance("SSLv3");
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new java.security.SecureRandom());

    SSLServerSocketFactory factory = sslContext.getServerSocketFactory();
    return factory;
}

服务器代码:

    InputStream is = new BufferedInputStream(socket.getInputStream());
        while (!Thread.currentThread().isInterrupted()) {
            int size = 0;
            String mess_length = "";
            byte[] lenbuf = new byte[4];
            if (socket != null && socket.isConnected()) {
                socket.getInputStream().read(lenbuf);
                mess_length = new String(lenbuf);
                log.debug("Lenth of received message: " + mess_length);
            }
            int responseSize = 0;
            try {
                responseSize = Integer.valueOf(mess_length);
                size = responseSize;
            } catch (Exception int_e) {
                log.debug("Error of message lenth numbering: ", int_e);

            }
            byte[] buf = new byte[size];
            if (socket.isConnected() && socket.getInputStream().read(buf) == size) {
                log.debug("Message received.");
            }

            // -----------------------------------------------------------------------------------------------------------
            OutputStream out = new BufferedOutputStream(socket.getOutputStream());
            if ("echo".equals(EnvironmentProperties.getMode())) {
                log.info("responsing in echo mode");
                log.debug("Data to send from server: {} in connection id={}", new String(buf,
                        "UTF-8"), uuid);
                out.write(buf);
            }
            out.flush();
            bytesSet.clear();
            log.info("responded");

来自服务器的日志:

17:37:26.166 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 混乱 收到的年龄。 17:37:26.166 [pool-1-thread-13] 信息 r.b.t.app.server.ConnectionCallable - resp 回声模式 17:37:26.166 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 数据 从服务器发送:连接 id=ee7f73ac-6be9-4e7b-876f-35d31845d69e 17:37:26.166 [pool-1-thread-13] 信息 r.b.t.app.server.ConnectionCallable - resp 过时的 17:37:26.166 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 借出 收到消息的 h:200r 17:37:26.167 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - : java.lang.NumberFormatException:对于输入字符串:“200r” 在 java.lang.NumberFormatException.forInputString(Unknown Source) ~[na:1 .8.0_05] 在 java.lang.Integer.parseInt(Unknown Source) ~[na:1.8.0_05] 在 java.lang.Integer.valueOf(Unknown Source) ~[na:1.8.0_05] 在 ru.billing.tcpipServerDummy.app.server.ConnectionCallable.call(Connec tionCallable.java:87) [TcpipServerDummy-0.0.1-SNAPSHOT.jar:na] 在 ru.billing.tcpipServerDummy.app.server.ConnectionCallable.call(Connec tionCallable.java:1) [TcpipServerDummy-0.0.1-SNAPSHOT.jar:na] 在 java.util.concurrent.FutureTask.run(未知来源)[na:1.8.0_05] 在 java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na :1.8.0_05] 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [n 一个:1.8.0_05] 在 java.lang.Thread.run(未知来源)[na:1.8.0_05] 17:37:26.167 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 混乱 收到的年龄。 17:37:26.167 [pool-1-thread-13] 信息 r.b.t.app.server.ConnectionCallable - resp 回声模式 17:37:26.167 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 数据 从服务器发送:连接 id=ee7f73ac-6be9-4e7b-876f-35d31845d69e 17:37:26.168 [pool-1-thread-13] 信息 r.b.t.app.server.ConnectionCallable - resp 过时的 17:37:26.168 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 借出 收到消息的 h:4♦А 17:37:26.168 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - ╬°шс ър яЁхюсЁрчютрэш  фышэ√ ёююс∙хэш: java.lang.NumberFormatException:对于输入字符串:“4♦А” 在 java.lang.NumberFormatException.forInputString(Unknown Source) ~[na:1 .8.0_05] 在 java.lang.Integer.parseInt(Unknown Source) ~[na:1.8.0_05] 在 java.lang.Integer.valueOf(Unknown Source) ~[na:1.8.0_05] 在 ru.billing.tcpipServerDummy.app.server.ConnectionCallable.call(Connec tionCallable.java:87) [TcpipServerDummy-0.0.1-SNAPSHOT.jar:na] 在 ru.billing.tcpipServerDummy.app.server.ConnectionCallable.call(Connec tionCallable.java:1) [TcpipServerDummy-0.0.1-SNAPSHOT.jar:na] 在 java.util.concurrent.FutureTask.run(未知来源)[na:1.8.0_05] 在 java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na :1.8.0_05] 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [n 一个:1.8.0_05] 在 java.lang.Thread.run(未知来源)[na:1.8.0_05] 17:37:26.168 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 混乱 收到的年龄。 17:37:26.168 [pool-1-thread-13] 信息 r.b.t.app.server.ConnectionCallable - resp 回声模式 17:37:26.168 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 数据 从服务器发送:连接 id=ee7f73ac-6be9-4e7b-876f-35d31845d69e 17:37:26.168 [pool-1-thread-13] 信息 r.b.t.app.server.ConnectionCallable - resp 过时的 17:37:26.168 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 借出 收到消息的 h:┴А 2 17:37:26.169 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - ╬°шс ър яЁхюсЁрчютрэш  фышэ√ ёююс∙хэш: java.lang.NumberFormatException:对于输入字符串:“┴А 2” 在 java.lang.NumberFormatException.forInputString(Unknown Source) ~[na:1 .8.0_05] 在 java.lang.Integer.parseInt(Unknown Source) ~[na:1.8.0_05] 在 java.lang.Integer.valueOf(Unknown Source) ~[na:1.8.0_05] 在 ru.billing.tcpipServerDummy.app.server.ConnectionCallable.call(Connec tionCallable.java:87) [TcpipServerDummy-0.0.1-SNAPSHOT.jar:na] 在 ru.billing.tcpipServerDummy.app.server.ConnectionCallable.call(Connec tionCallable.java:1) [TcpipServerDummy-0.0.1-SNAPSHOT.jar:na] 在 java.util.concurrent.FutureTask.run(未知来源)[na:1.8.0_05] 在 java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na :1.8.0_05] 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [n 一个:1.8.0_05] 在 java.lang.Thread.run(未知来源)[na:1.8.0_05] 17:37:26.169 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 混乱 收到的年龄。 17:37:26.169 [pool-1-thread-13] 信息 r.b.t.app.server.ConnectionCallable - resp 回声模式 17:37:26.169 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 数据 从服务器发送:连接 id=ee7f73ac-6be9-4e7b-876f-35d31845d69e 17:37:26.169 [pool-1-thread-13] 信息 r.b.t.app.server.ConnectionCallable - resp 过时的 17:37:26.169 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 借出 收到消息的小时数:1194 17:37:26.169 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - ╧Ёхю сЁрчютрээр  фышээр ёююс∙хэш: 1194 17:37:26.169 [pool-1-thread-13] 信息 r.b.t.app.server.ConnectionCallable - resp 回声模式 17:37:26.169 [pool-1-thread-13] 调试 r.b.t.app.server.ConnectionCallable - 数据 从服务器发送:6817121021052420000000000000000100000730173724000048001121 101581111310001749439 749138 00809203123643 在连接 id=ee7f73ac-6be9-4e7b-876f-35d31845d69e

【问题讨论】:

  • 您介意告诉我们更多有关您的客户端和服务器的操作系统的信息吗?服务器和客户端是否运行在同一个系统上?
  • 客户端和服务器在本地主机上的 Win7 上运行。 JVM 8

标签: java ssl tcp x509


【解决方案1】:

常见问题。您在某一时刻忽略了read() 返回的结果,并假设它填充了长度缓冲区,然后如果下一次读取没有返回确切的字节数,那么您也忽略了实际返回的字节数。您需要将read()返回的结果存储到一个变量中,并且:

  • 测试它是否为 -1,表示流结束
  • 否则会一直循环,直到您收到完整的消息,但这是在您的应用程序协议中定义的。

其他问题:

  • 这里的Socket.isConnected() 测试毫无意义。如果对等方断开连接,它不会神奇地变为假。您必须通过从read() 获取-1、从readLine(), 获取null 等来检测这一点。

  • 同上socket == null 测试。它必须是非空的,否则你会在 socket.getOutputStream(). 中抛出 NPE

  • 您每次都在创建一个新的BufferedOutputStream。您应该在套接字的整个生命周期中使用一个。

【讨论】:

  • 谢谢,一些问题消失了。
猜你喜欢
  • 2018-08-22
  • 2011-05-19
  • 1970-01-01
  • 1970-01-01
  • 2016-05-11
  • 2014-02-21
  • 2015-10-14
  • 2021-05-09
  • 2017-07-17
相关资源
最近更新 更多