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

6

我正在开发一个小程序,作为XMPP客户端,并且我正在使用Smack库。现在,我连接的服务器需要SSL(在Pidgin中,我必须勾选“强制旧版(端口5223)SSL”)。我无法让Smack连接到这个服务器。这是否可能?

3个回答

8

请查看这个帖子。

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

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

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

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


2
这个DummySSLSocketFactory允许通过任何证书,即使它已过期或未被根CA签名。因此,我建议获取CA证书并将其存储在KeyStore中,并将其添加到应用程序中并使用相同的证书。有关更多详细信息,请参阅我的答案。 - Iqbal S
1
IOException: 未连接套接字未实现Smack 4.2.3 - Alp Altunel

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

将CA证书存储在Keystore中

要将证书存储在Keystore中,请按照以下步骤进行操作。

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

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

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>"

步骤三:验证密钥库文件

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 Brayne
@Alastair Context 是应用程序或类级别的上下文,您可以使用 this 传递。而 R 则是一个类,我可以从中获取存储在硬盘原始目录中的密钥库,您也可以通过其他方式直接将该资源传递给它。 - Iqbal S
听起来你正在使用特定的框架。Android?我不是,所以这让我有点困惑。但我最终弄明白了。无论如何,还是谢谢你。 - Alastair Brayne
是的,你说得对,这段代码是特定于领域的,但你可以将其应用于任何领域。需要进行一些小的更改。希望你觉得这个答案有帮助,如果能给个点赞就更好了。;-) 谢谢。 - Iqbal S
1
@Priya 在Android中,所有的权限都是在用户安装应用程序时询问的,因此我们不会要求用户提供任何权限。如果您正在使用不同的框架工作,或者即使在Android中,如果您想要向用户请求权限,则可以在加载信任存储之前使用确认框来询问用户是否要继续加载。希望这可以帮助到您! - Iqbal S
显示剩余3条评论

3
是的,这很容易实现。看一下ConnectionConfiguration类,特别是接受ConnectionConfiguration.SecurityMode枚举作为参数的setSecurityMode方法。将其设置为“required”会强制Smack使用TLS。
来自Javadoc:
通过TLS加密进行安全性是连接所必需的。如果服务器不提供TLS或TLS协商失败,则与服务器的连接将失败。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接