简单的双向RMI SSL连接,PKIX路径构建失败

Nuutrino

我有一个程序,该程序有两个可运行文件,一个称为ServerImpl,另一个称为ClientImpl。我的目标是能够使ClientImpl使用带有SSL的RMI连接到ServerImpl并调用方法。服务器还应该能够通过回调使用RMI和SSL在客户端上调用方法。我可以使客户端使用SSL连接到服务器并在该服务器上调用方法,但是我无法使服务器使用带有SSL的RMI重新连接到客户端。

该程序还有两个目录,其中包含两组不同的证书,密钥库和信任库文件:

resources/client/
    client_cert.cer
    client_keystore.jks
    client_truststore.jks

 resources/server/
     server_cert.cer
     server_keystore.jks
     server_truststore.jks

ServerImpl.java文件:

public class ServerImpl implements ServerInt {

    private ClientInt client;

    public static void main(String[] args) {
        ServerImpl server = new ServerImpl();
        server.bind();
    }

    public void bind() {
        System.setProperty("java.rmi.server.hostname", "192.168.0.32");
        System.setProperty("javax.net.ssl.keyStore", "./resources/server/server_keystore.jks");
        System.setProperty("javax.net.ssl.keyStorePassword", "password");

        RMIClientSocketFactory rmiClientSocketFactory = new SslRMIClientSocketFactory();
        RMIServerSocketFactory rmiServerSocketFactory = new SslRMIServerSocketFactory();

        try {
            ServerInt si = (ServerInt) UnicastRemoteObject.exportObject(this, 0, rmiClientSocketFactory, rmiServerSocketFactory);
            Registry reg = LocateRegistry.createRegistry(1099);

            reg.rebind("server", si);
            System.out.println("RMIServer is bound in registry");
        } catch (RemoteException ex) {
            Logger.getLogger(ServerImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void connect(ClientInt ci) throws RemoteException {
        System.out.println("client connected");
    }

}

ClientImpl.java文件:

public class ClientImpl implements ClientInt {

    private ServerInt server;

    public static void main(String[] args) {
        ClientImpl client = new ClientImpl();
        client.bind();
        client.initConnection();
        client.connectToServer();

    }

    public void initConnection() {
        System.setProperty("javax.net.ssl.trustStore", "./resources/client/client_truststore.jks");
        System.setProperty("javax.net.ssl.trustStorePassword", "password");
        try {
            Registry reg = LocateRegistry.getRegistry("192.168.0.32", 1099);
            server = (ServerInt) reg.lookup("server");

        } catch (RemoteException ex) {
            Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NotBoundException ex) {
            Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void bind() {
        System.setProperty("java.rmi.server.hostname", "192.168.0.32");
        System.setProperty("javax.net.ssl.keyStore", "./resources/client/client_keystore.jks");
        System.setProperty("javax.net.ssl.keyStorePassword", "password");

        RMIClientSocketFactory rmiClientSocketFactory = new SslRMIClientSocketFactory();
        RMIServerSocketFactory rmiServerSockeyFactory = new SslRMIServerSocketFactory();
        try {

            ClientInt ci = (ClientInt) UnicastRemoteObject.exportObject(this, 0, rmiClientSocketFactory, rmiServerSockeyFactory);
            Registry reg = LocateRegistry.createRegistry(5001);
            reg.rebind("client", ci);
            System.out.println("RMIClient is bound in registry");
        } catch (RemoteException ex) {
            Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void connectToServer() {
        try {
            server.connect(this);
        } catch (RemoteException ex) {
            Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void sayHelloToClient(String helloText) throws RemoteException {
        System.out.println(helloText);
    }
}

然后,我运行ServerImpl.java文件,并且运行正常。然后,我运行ClientImpl.java文件,并在调用connectToServer方法时收到错误消息:

java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is: 
    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

任何人都可以阐明这里存在的问题以及如何解决该问题吗?失败了,谁能给我指向一个好的教程,该教程中有两个使用SSL进行对话的RMI实体?谢谢。

Nuutrino

好的,我知道了。问题在于相应的客户端/服务器Java文件仍在使用默认的Java TrustStore,而不是我在原始问题代码中定义的自定义Truststore文件。对于正在寻找使用SSL进行双向RMI客户端-服务器连接的简单演示的任何其他人,这是完整的正确代码。

创建空白Java项目后,将“资源”文件夹添加到具有两个子目录“客户端”和“服务器”的顶级目录中。然后生成两组独立的证书,密钥库和信任库,并将它们放在相应的子目录中,如下所示:

resources/client/
    client_cert.cer
    client_keystore.jks
    client_truststore.jks

resources/server/
    server_cert.cer
    server_keystore.jks
    server_truststore.jks

然后为服务器创建一个名为“ ServerInt”的接口:

public interface ServerInt extends Remote {
    public void connect(ClientInt ci) throws RemoteException;
}

客户端的另一个接口称为“ ClientInt”:

public interface ClientInt extends Remote {
    public void sayHelloToClient(String helloText) throws RemoteException;
}

现在为服务器创建一个名为“ ServerImpl”的新Java类:

public class ServerImpl implements ServerInt {

    public static void main(String[] args) {
        ServerImpl server = new ServerImpl();
        server.bind();
    }

    public void bind() {
//        System.setProperty("javax.net.debug", "all");        
        System.setProperty("javax.net.ssl.trustStore", "./resources/server/server_truststore.jks");
        System.setProperty("javax.net.ssl.trustStorePassword", "password");
        System.setProperty("java.rmi.server.hostname", "192.168.0.32");
        System.setProperty("javax.net.ssl.keyStore", "./resources/server/server_keystore.jks");
        System.setProperty("javax.net.ssl.keyStorePassword", "password");


        RMIClientSocketFactory rmiClientSocketFactory = new SslRMIClientSocketFactory();
        RMIServerSocketFactory rmiServerSocketFactory = new SslRMIServerSocketFactory();

        try {


            // Uncomment this line...
            //ServerInt si = (ServerInt) UnicastRemoteObject.exportObject(this, 0);
            // and then comment out this line to turn off SSL (do the same in the ClientImpl.java file)
            ServerInt si = (ServerInt) UnicastRemoteObject.exportObject(this, 0, rmiClientSocketFactory, rmiServerSocketFactory);



            Registry reg = LocateRegistry.createRegistry(1099);
            reg.rebind("server", si);
            System.out.println("Server is bound in registry");
        } catch (RemoteException ex) {
            Logger.getLogger(ServerImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void connect(ClientInt ci) throws RemoteException {
        System.out.println("Client is connected");

        // Generate a really big block of text to send to the client, that way it will be easy to see in a packet
        // capture tool like wireshark and verify that it is in fact encrypted.
        String helloText = "";
        for (int i = 0; i < 10000; i++) {
            helloText += "A";
        }

        ci.sayHelloToClient(helloText);
    }

}

最后,我们需要为客户端提供一个名为“ ClientImpl”的类:

public class ClientImpl implements ClientInt {

    private ServerInt server; 

    public static void main(String[] args) {
        ClientImpl client = new ClientImpl();
        client.bind();
        client.initConnection();
        client.connectToServer();

    }

    public void initConnection() {
        try {
            Registry reg = LocateRegistry.getRegistry("192.168.0.32", 1099);
            server = (ServerInt) reg.lookup("server");

        } catch (RemoteException ex) {
            Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NotBoundException ex) {
            Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void bind() {
//        System.setProperty("javax.net.debug", "all");        
        System.setProperty("javax.net.ssl.trustStore", "./resources/client/client_truststore.jks");
        System.setProperty("javax.net.ssl.trustStorePassword", "password");

        System.setProperty("java.rmi.server.hostname", "192.168.0.32");
        System.setProperty("javax.net.ssl.keyStore", "./resources/client/client_keystore.jks");
        System.setProperty("javax.net.ssl.keyStorePassword", "password");


        RMIClientSocketFactory rmiClientSocketFactory = new SslRMIClientSocketFactory();
        RMIServerSocketFactory rmiServerSockeyFactory = new SslRMIServerSocketFactory();
        try {

            // Uncomment this line...
            // ClientInt ci = (ClientInt) UnicastRemoteObject.exportObject(this, 0);
            // and comment out this line to turn off SSL (do the same in the ServerImpl.java file)
            ClientInt ci = (ClientInt) UnicastRemoteObject.exportObject(this, 0, rmiClientSocketFactory, rmiServerSockeyFactory);


            Registry reg = LocateRegistry.createRegistry(5001);
            reg.rebind("client", ci);
            System.out.println("Client is bound in registry");
        } catch (RemoteException ex) {
            Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void connectToServer() {
        try {
            server.connect(this);
        } catch (RemoteException ex) {
            Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void sayHelloToClient(String helloText) throws RemoteException {
        System.out.println(helloText);
    }
}

这里的所有都是它的。首先运行“ ServerImpl”文件,这将创建RMI服务器。然后运行“ ClientImpl”文件,这将创建它自己的RMI注册表,然后使用connectToServer方法将其自身发送到服务器。服务器将与客户端RMI对象一起接收此消息,然后使用客户端RMI对象的该实例来调用客户端方法。全部使用SSL。

为了验证它是否使用SSL,服务器会生成一个很长的文本字符串,并将其发送回客户端。通过使用诸如Wireshark的数据包捕获工具,您可以轻松地看到此消息已加密。我在代码中添加了注释,可轻松关闭SSL,以便您无需加密即可查看此文本。

我花了比我更愿意承认所有这些的时间,而且与此同时,我找不到关于该主题的任何优秀教程。因此,希望如果有人在这个问题上陷入困境,这将有所帮助。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

建立SSL连接时PKIX路径构建失败

PKIX路径构建失败

使用SSL连接到Kafka集群时,Apache Camel导致PKIX路径构建失败异常

JDBC连接池SSL错误PKIX构建失败

Jenkins 因“PKIX 路径构建”错误而失败

Kubernetes AutoDevOps 上的 PKIX 路径构建失败

javax.net.ssl.SSLHandshakeException:PKIX 路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:

javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX路径构建失败

解决javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX路径构建失败错误?

RMI远程连接失败

Java应用程序中的PKIX路径构建失败

PKIX路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException

更新到AS 3.3后,“ PKIX路径构建失败”

GlassFish 4和Java Mail:PKIX路径构建失败

Keycloak 适配器 pkix 路径构建失败

带有SSL的Java邮件-PKIX路径验证失败

libldap openldap设置选项对于简单的SSL连接失败

内部CA的PKIX路径构建

Maven错误,PKIX路径构建失败:无法找到请求目标的有效证书路径

PKIX路径构建失败:无法找到请求的目标的有效证书路径-导入的CERT

SonarQube安装-Github身份验证插件失败,“ PKIX路径构建失败”

带有SSL的RMI:握手失败

请求PKIX路径时,获取PKIX路径失败

如何与ssl证书建立双向连接?

为什么在处理贝宝付款时突然出现“ PKIX路径构建失败”错误

PKIX 路径构建失败,受信任证书和所有信任管理

Spring RestTemplate接收sun.security.validator.ValidatorException:PKIX路径构建失败:

引起原因:sun.security.validator.ValidatorException:PKIX路径构建失败

在Intranet中使用https获取sun.security.validator.ValidatorException:PKIX路径构建失败