【问题标题】:Setting up multiple SSL Socket Factories设置多个 SSL 套接字工厂
【发布时间】:2014-09-08 13:58:08
【问题描述】:

我有一段 Java 代码(实际上是一个 servlet)需要与之安全通信:

  1. 另一个 java 进程,通过 RMI,进行安全的远程方法调用和
  2. Google GCM 服务器,向移动设备发送通知。

这是安全绑定到远程对象的代码:

    // let's set some system properties needed for RMI on SSL
    Properties sysProps = System.getProperties();
    sysProps.setProperty("javax.net.ssl.keyStore", ...);
    sysProps.setProperty("javax.net.ssl.keyStorePassword", ...);
    sysProps.setProperty("javax.net.ssl.trustStore", ...);
    sysProps.setProperty("javax.net.ssl.trustStorePassword", ...);

    try {
        String registryHost = ...;
        int registryPort = ...;

        Registry registry = LocateRegistry.getRegistry(registryHost, registryPort, new SslRMIClientSocketFactory());
        MyRemoteObject obj = (MyRemoteObject) registry.lookup(...);
    } catch (Exception e) {
        log.error("RMI Exception",e);
    } 

然后,要连接到 Google GCM 服务器,我有 Google 提供的唯一代码以及我阅读过的任何教程:

    config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
    config.setSecurityMode(SecurityMode.enabled);
    config.setReconnectionAllowed(true);
    config.setRosterLoadedAtLogin(false);
    config.setSendPresence(false);
    config.setSocketFactory(SSLSocketFactory.getDefault());

    // NOTE: Set to true to launch a window with information about packets
    // sent and received
    config.setDebuggerEnabled(true);

    // -Dsmack.debugEnabled=true
    XMPPConnection.DEBUG_ENABLED = false;

    connection = new XMPPConnection(config);
    connection.connect();

我可以一次使这些代码中的一个工作,但我无法同时建立两个安全连接。我可以使用默认的 SSLSocketFactory 或设置 RMI SSL 套接字工厂,但不能同时使用两者。如果我先连接到 RMI 服务器,当我尝试连接到 Google GCM 服务器时会收到以下错误:

2014-09-08 16:14:05,172 ERROR [pool-4-thread-1] (GcmManager.java:109) - Problems connecting with Google XMPP servers
Connection failed. No response from server.: 
at org.jivesoftware.smack.PacketReader.startup(PacketReader.java:121)
at org.jivesoftware.smack.XMPPConnection.initConnection(XMPPConnection.java:636)
at org.jivesoftware.smack.XMPPConnection.connectUsingConfiguration(XMPPConnection.java:596)
at org.jivesoftware.smack.XMPPConnection.connect(XMPPConnection.java:1010)
at com.tigratelecom.server.callback.web.notification.GcmManager.connect(GcmManager.java:171)
at com.tigratelecom.server.callback.web.notification.GcmManager.sendNotification(GcmManager.java:107)
at com.tigratelecom.server.callback.web.notification.NotificationSender.sendNotifications(NotificationSender.java:24)
at com.tigratelecom.server.callback.web.servlet.CallbackServlet$1.run(CallbackServlet.java:107)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:351)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)

而如果我首先连接到 Google 服务器,在我尝试连接到 RMI 服务器之前一切正常,但会失败并出现以下错误:

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
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:304)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:340)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at ...

你能指点我正确的方向吗?

谢谢

【问题讨论】:

  • 您看到了什么错误?堆栈跟踪会很有用。
  • 抱歉,我编辑了问题并添加了堆栈跟踪
  • 在第二种情况下,您真的在 getRegistry() 调用之前立即执行 setProperty() 调用吗?如果没有,您能否检查一下 Google 代码是否与 truststore 属性混淆了?
  • 是的,对 setProperty() 的调用是在 getRegistry() 之前立即完成的,因为它们出现在我发布的代码中。为了安全起见,在第二种情况下,我在连接到 Google 服务器之前和之后打印了系统属性,但没有任何变化。

标签: java ssl rmi google-cloud-messaging


【解决方案1】:

我继续摆弄这个问题,直到找到一些东西。我的工作假设是连接到 Google GCM 服务器的代码(来自 Smack 库),因为它使用默认的 SSLSocketFactory,正在使用在 jre/lib/security/cacerts 中找到的默认 java 信任库中已经存在的一些证书在 java SDK 安装中。由于我必须创建自己的信任库和密钥库来设置 RmiSSLSocketFactory,因此我假设 Smack 库代码无法找到它需要的任何证书。

所以我决定将 cacerts 中可用的所有证书导入我自己的密钥库。为此,我跑了:

keytool -importkeystore -srckeystore "c:\Program Files\Java\jdk1.7.0_25\jre\lib\security\cacerts" -destkeystore my_truststore  -srcstorepass changeit -deststorepass mypass

之后,一切顺利,两个安全连接都建立起来没有问题。

我希望这对将来的某人有所帮助。

【讨论】:

    猜你喜欢
    • 2012-02-29
    • 2010-11-04
    • 1970-01-01
    • 2019-12-15
    • 2018-06-03
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多