【问题标题】:unable to connect to ssl server Received fatal alert: certificate_unknown and ReadDataRecord(SSLSocketImpl无法连接到 ssl 服务器收到致命警报:certificate_unknown 和 ReadDataRecord(SSLSocketImpl
【发布时间】:2015-07-12 08:53:39
【问题描述】:

我有一种情况,客户端 A 应该连接到服务器 B,服务器 B 应该连接到服务器 C。并且连接必须是安全套接字。

我尝试并成功建立了 b/w A 到 B 和 B 到 C 的单独连接。但是当我尝试同时建立到 A 到 B 和 B 到 C 的连接时,它会引发错误

javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2011)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1113)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
    at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:916)
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.fill(BufferedReader.java:161)
    at java.io.BufferedReader.readLine(BufferedReader.java:324)
    at java.io.BufferedReader.readLine(BufferedReader.java:389)
    at VfSer.main(VfSer.java:51)

这是我尝试过的代码,我为 A 到 B 和 B 到 C 连接使用了两个不同的证书。

这是A代码

            System.setProperty("javax.net.ssl.trustStore", "vaserkey");
            System.setProperty("javax.net.ssl.trustStoreSSN", "123456");
        try {
            SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(args[0], Integer.parseInt(args[1]));
//.....
}

这是B代码

            System.setProperty("javax.net.ssl.keyStore", "vaserkey");
            System.setProperty("javax.net.ssl.keyStorePassword", "123456");
            //adding ssl layer to socket connection
            SSLServerSocketFactory sslserversocketfactory =(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
            SSLServerSocket sslserversocket =(SSLServerSocket) sslserversocketfactory.createServerSocket(Integer.parseInt(args[0]));
            //taking infinite connection one by one
            while(true){
            //accepting incoming connection
            SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();//....
}catch(Exception e){}
        //after receiving data trying to establish connection with C
            System.setProperty("javax.net.ssl.trustStore", "vfserkey");
            System.setProperty("javax.net.ssl.trustStoreSSN", "123456");
            SSLSocketFactory sslsocketfactory1 = (SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket sslsocket1 = (SSLSocket) sslsocketfactory1.createSocket(ip, port);

//..向 C 发送数据 这是C代码:

        System.setProperty("javax.net.ssl.keyStore", "vfserkey");
        System.setProperty("javax.net.ssl.keyStorePassword", "123456");
    try {
        //adding ssl layer to socket connection
        SSLServerSocketFactory sslserversocketfactory =(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
        SSLServerSocket sslserversocket =(SSLServerSocket) sslserversocketfactory.createServerSocket(Integer.parseInt(args[0]));

      SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();

//获取连接并从C接收数据 } 最后是我用来生成证书的工具。

keytool -genkey vaserkey -keyalg RSA
keytool -genkey vfserkey -keyalg RSA

对不起,如果我说错了什么,我是 SSL 编程的新手,如果我错了,请纠正我..

【问题讨论】:

  • “0 票最喜欢”?
  • 对不起先生。我没有得到你。我做错了什么吗?
  • 你为什么在你的帖子开头加上“0 反对票”?
  • 对不起先生。这是我的错误。我没有注意到。
  • 这意味着他们从另一个帖子中复制并粘贴它,可能是一个已关闭和/或删除的帖子。 @CupawnTae

标签: java sockets ssl ssl-certificate keytool


【解决方案1】:

首先设置所有 SSL 属性。 DefaultSSLContext 默认由 SSLSocketFactory 和 SSLServerSocketFactory 使用,但它仅在第一次使用时构造。更改任何相关的系统属性或它们指向的文件,在第一次使用之后会被忽略并且没有任何效果。所以你需要在调用 either 工厂之前设置 all javax.net.ssl.* 属性。

还有:

无法正确复制那些 keytool 命令。你需要-keystore 在每个文件名之前。他们生成私钥和(自签名)证书;你不能只生成一个证书,如果可以的话,它几乎不能用于包括 SSL/TLS 在内的任何东西。 最后,现在首选的操作是-genkeypair;支持拼写 -genkey 以实现向后兼容性,但最终可能会被丢弃。

将密钥库(条目)用于信任库是不明智的。 虽然 TrustManager 逻辑确实会在私钥条目中找到并使用证书(见上文),但复制密钥库(或只是私钥条目/ ies) 到依赖者/客户是不好的做法。 [编辑] 任何获得您私钥的人通常都可以冒充您,其结果包括窃取您的敏感数据和其他资源(例如金钱)。即使一个特定的客户不是恶意的,他们也很少像你一样小心你的密钥,如果有很多客户,他们可能有多台机器、备份、替换、虚拟化、外包、测试、临时工、承包商等。这种风险成倍增加。

正确/更好的方法是仅从服务器密钥库导出证书,并将仅证书导入客户端信任库(以“Java KeyStore”格式,但实际上不是钥匙)类似:

 keytool -keystore vaserkey -exportcert -file vasercert
 keytool -keystore vasertrust -importcert -file vasercert
 # same again for vf...
 # use vasertrust for A-trust and vfserTrust for B-trust in your example

【讨论】:

  • 在任何地方复制私钥,即使是通过密钥库,已经是一个副本,而且它已经是一个表面上的安全漏洞,甚至在之前你提到的可能的后果。另一个主要后果是收件人现在可以冒充您。
  • @EJP 您控制的副本不是违规,但其他任何人通常都会被编辑。另请注意,我不清楚这个 OP 是在复制,还是只是在一个地方运行所有三个程序(使用相同的实际文件,而不仅仅是内容),这通常便于测试。
  • @dave_thompson_085 谢谢先生。它帮了我很多。终于我解决了我的问题
【解决方案2】:

我在这里发布可能对其他人有帮助的答案。

我按照 @dave_thompson_085

的建议修改了代码

首先设置所有 SSL 属性。默认情况下使用 DefaultSSLContext SSLSocketFactory 和 SSLServerSocketFactory,但它是 仅在第一次使用时构建。改变任何一个 之后相关的系统属性或它们指向的文件 第一次使用被忽略,没有效果。所以你需要设置所有 调用任一工厂之前的 javax.net.ssl.* 属性。

i replaced 
SSLServerSocketFactory sslserversocketfactory =(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
with 
SSLServerSocketFactory sslserversocketfactory =(SSLServerSocketFactory)SSLContext.getDefault().getServerSocketFactory();

这是A代码

            System.setProperty("javax.net.ssl.trustStore", "vaserkey");
            System.setProperty("javax.net.ssl.trustStoreSSN", "123456");
        try {
            SSLSocketFactory sslsocketfactory =  (SSLSocketFactory) SSLContext.getDefault().getSocketFactory();
            SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(args[0], Integer.parseInt(args[1]));
//.....
}

这是B代码

            System.setProperty("javax.net.ssl.keyStore", "vaserkey");
            System.setProperty("javax.net.ssl.keyStorePassword", "123456");
            //adding ssl layer to socket connection
            SSLServerSocketFactory sslserversocketfactory =SSLServerSocketFactory) SSLContext.getDefault().getServerSocketFactory();                SSLServerSocket sslserversocket =(SSLServerSocket) sslserversocketfactory.createServerSocket(Integer.parseInt(args[0]));
            //taking infinite connection one by one
            while(true){
            //accepting incoming connection
            SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();//....
}catch(Exception e){}
        //after receiving data trying to establish connection with C
            System.setProperty("javax.net.ssl.trustStore", "vfserkey");
            System.setProperty("javax.net.ssl.trustStoreSSN", "123456");
            SSLSocketFactory sslsocketfactory1 = (SSLServerSocketFactory) SSLContext.getDefault().getServerSocketFactory();
            SSLSocket sslsocket1 = (SSLSocket) sslsocketfactory1.createSocket(ip, port);

//..向 C 发送数据 这是C代码:

        System.setProperty("javax.net.ssl.keyStore", "vfserkey");
        System.setProperty("javax.net.ssl.keyStorePassword", "123456");
    try {
        //adding ssl layer to socket connection
        SSLServerSocketFactory sslserversocketfactory =((SSLServerSocketFactory)SSLContext.getDefault().getServerSocketFactory();           SSLServerSocket sslserversocket =(SSLServerSocket) sslserversocketfactory.createServerSocket(Integer.parseInt(args[0]));

      SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();//getting the connection and receiving the data from C}

【讨论】:

    猜你喜欢
    • 2018-01-21
    • 1970-01-01
    • 2012-10-19
    • 2014-05-10
    • 2018-02-09
    • 2021-08-20
    • 2016-10-09
    • 2016-07-22
    • 2013-05-09
    相关资源
    最近更新 更多