当前位置: 首页 > 知识库问答 >
问题:

无法连接到ssl服务器收到致命警报:certificate_unknown和ReadDataRecords(SSLSocketImpl

巫马阳飙
2023-03-14

我有一种情况,客户端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编程新手。如果我说错了,请纠正我。。

共有2个答案

易炳
2023-03-14

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

我按照@dave_thompson_085的建议修改了代码

首先设置所有SSL属性。默认情况下,SSLSocketFactory和SSLServerSocketFactory都使用DefaultSSLContext,但它仅在第一次使用时构造。在第一次使用后更改任何相关的系统属性或它们指向的文件将被忽略,并且没有任何效果。所以你需要设置所有的javax。网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}
郎鸿
2023-03-14

首先设置所有SSL属性<默认情况下,SSLSocketFactorySSLServerSocketFactory都使用code>DefaultSSLContext,但它仅在第一次使用时构造。在第一次使用后更改任何相关的系统属性或它们指向的文件将被忽略,并且没有任何效果。所以你需要设置所有的javax。网ssl* 属性,然后再调用任一工厂。

也:

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

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

正确/更好的方法是仅从服务器密钥库导出证书,并仅将证书导入客户端信任库(采用“Java密钥库”格式,但实际上不是密钥),如下所示:

 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

 类似资料: