如何使用 Smack XMPP 库创建 SSL 连接?

Posted

技术标签:

【中文标题】如何使用 Smack XMPP 库创建 SSL 连接?【英文标题】:How to create an SSL connection using the Smack XMPP library? 【发布时间】:2009-02-13 07:44:19 【问题描述】:

我正在构建一个充当 XMPP 客户端的小程序,并且我正在使用 Smack 库。现在,我要连接的服务器需要 SSL(在 Pidgin 中我必须检查“强制旧(端口 5223)SSL”)。我无法让 Smack 连接到此服务器。有可能吗?

【问题讨论】:

【参考方案1】:

看看这个帖子。

http://www.igniterealtime.org/community/thread/37678

基本上,您需要将这两行添加到您的代码中:

connConfig.setSecurityMode(ConnectionConfiguration.SecurityMode.enabled);
connConfig.setSocketFactory(new DummySSLSocketFactory());

其中 connConfig 是您的 ConnectionConfiguration 对象。从 Spark 源代码存储库中获取 DummySSLSocketFactory。它所做的只是接受几乎任何证书。这似乎对我有用。祝你好运!

【讨论】:

这个 DummySSLSocketFactory 允许任何证书过去,即使它已过期或未被根 CA 签发。所以我建议获取 CA 证书并将其存储在 KeyStore 中并将其添加到应用程序中并使用相同的方法。详情请参考我的回答。 IOException: Unconnected sockets not implemented smack 4.2.3【参考方案2】:

您可以通过以下方式实现:

将 CA 证书存储在密钥库中

要将证书存储在密钥库中,请按以下步骤操作。

第 1 步:下载 bouncycastle JAR 文件。可以从这里下载:Bouncy Castle JAVA Releases

第 2 步: 使用以下命令将证书存储在密钥库中

keytool -importcert -v -trustcacerts -file "<certificate_file_with_path>" -alias "<some_name_for_certificate>" -keystore "<file_name_for_the_output_keystore>" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "<bouncy_castle_jar_file_with_path>" -storetype BKS -storepass "<password_for_the_keystore>"

第 3 步:验证密钥库文件

keytool -importcert -v -list -keystore "<file_name_for_the_keystore_with_path>" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "<bouncy_castle_jar_file_with_path>" -storetype BKS -storepass "<password_for_the_keystore>"

这将列出我们包含在密钥库中的证书。

我们有一个可以在代码中使用的密钥库。

使用密钥库

生成此密钥库后,将其保存在应用程序的原始文件夹中。使用以下代码获取与 openfire 服务器的证书握手。

要使用 XMPP 创建与 openfire 的连接,您可能需要获取配置。同样,使用以下方法:

public ConnectionConfiguration getConfigForXMPPCon(Context context) 
        ConnectionConfiguration config = new ConnectionConfiguration(URLConstants.XMPP_HOST, URLConstants.XMPP_PORT);
        config.setSASLAuthenticationEnabled(false);
        config.setSecurityMode(ConnectionConfiguration.SecurityMode.enabled);
        config.setCompressionEnabled(false);
        SSLContext sslContext = null;
        try 
            sslContext = createSSLContext(context);
         catch (KeyStoreException e) 
            e.printStackTrace();
         catch (NoSuchAlgorithmException e) 
            e.printStackTrace();
         catch (KeyManagementException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
         catch (CertificateException e) 
            e.printStackTrace();
        

        config.setCustomSSLContext(sslContext);
        config.setSocketFactory(sslContext.getSocketFactory());

        return config;
 

private SSLContext createSSLContext(Context context) throws KeyStoreException,
            NoSuchAlgorithmException, KeyManagementException, IOException, CertificateException 
        KeyStore trustStore;
        InputStream in = null;
        trustStore = KeyStore.getInstance("BKS");

        if (StringConstants.DEV_SERVER_IP.equals(URLConstants.XMPP_HOST) || StringConstants.TEST_SERVER_IP.equals(URLConstants.XMPP_HOST))
            in = context.getResources().openRawResource(R.raw.ssl_keystore_dev_test);
        else if(StringConstants.STAGE_SERVER_IP.equals(URLConstants.XMPP_HOST) || StringConstants.STAGE2_SERVER_IP.equals(URLConstants.XMPP_HOST))
            in = context.getResources().openRawResource(R.raw.ssl_keystore_stage);
        else if(StringConstants.PROD_SERVER_IP.equals(URLConstants.XMPP_HOST) || StringConstants.PROD1_SERVER_IP.equals(URLConstants.XMPP_HOST))
            in = context.getResources().openRawResource(R.raw.ssl_keystore_prod);

        trustStore.load(in, "<keystore_password>".toCharArray());

        TrustManagerFactory trustManagerFactory = TrustManagerFactory
                .getInstance(KeyManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(trustStore);
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustManagerFactory.getTrustManagers(),
                new SecureRandom());
        return sslContext;

全部完成..!!只需连接.. 现在您的连接是安全的。

所有人都在我的博客smackssl.blogspot.in中关注相同的内容

【讨论】:

ContextR 类是什么? @Alastair Context 是应用程序或类级别的上下文,您可以使用this 传递它。 R 是一个类,我从中获取存储在我的硬盘中的原始目录中的密钥存储,您也可以通过任何其他方式将该资源直接传递给 in。 听起来你在一个特定的框架中工作。安卓?我不是,所以这让我有点困惑。但我想通了。无论如何,谢谢。 是的,您是正确的,代码是特定于域的,但您可以将其应用于任何域。需要小的改动。希望您的回答对您有所帮助,将不胜感激。 ;-) 谢谢。 @Priya 在 android 中,当用户安装应用程序时会询问所有权限,因此我们不会为用户询问任何权限。如果您正在使用不同的框架,或者甚至在 Android 中如果您想获得用户的许可,那么您可以在加载信任库之前使用确认框来询问用户是否要继续加载它或不..希望这会有所帮助!【参考方案3】:

是的,这很容易实现。查看ConnectionConfiguration 类,特别是接受 ConnectionConfiguration.SecurityMode 枚举作为参数的 setSecurityMode 方法。将此设置为“必需”会强制 Smack 使用 TLS。

来自 Javadoc:

通过 TLS 加密的安全性是 需要才能连接。如果 服务器不提供 TLS,或者如果 TLS 协商失败,连接 到服务器会失败。

【讨论】:

以上是关于如何使用 Smack XMPP 库创建 SSL 连接?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 java 中使用 Smack XMPP 库处理 TLS 证书

我在使用 smack 4.2 Openfire 创建 XMPP 客户端时遇到问题

XMPP 注销(Smack API)

无法使用 Smack 4.1 从 Android 连接 apache vysper XMPP 服务器

如何使用 TLS/SSL 连接 xmpp 服务器?

android中的XMPP连接使用smack