How to create an SSL connection using the Smack XMPP library?

15,385

Solution 1

You can achieve this by the following:

Storing the CA Certificate in Keystore

To store the certificate in a Keystore follow these steps.

Step 1: Download the bouncycastle JAR file. It can be downloaded from the here: Bouncy Castle JAVA Releases

Step 2: Use the following command to store the certificate in 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>"

Step 3: Verify the keystore file

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

This shall list us the certificate included in the keystore.

We have a keystore which we can use in our code.

Using the keystore

After generating this keystore, save it in the raw folder of your application. The use the below code to get the certificate handshake with the openfire server.

To create a connection with openfire using XMPP, you may need to get the config. For the same, use the below method:

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;
}

All done..!! Just connect.. Now your connection is secured.

All follow the same in my blog at smackssl.blogspot.in

Solution 2

Yes, it's quite easy to achieve. Take a look at the ConnectionConfiguration class, and in particular the setSecurityMode method which accepts a ConnectionConfiguration.SecurityMode enum as a parameter. Setting this to "required" forces Smack to use TLS.

from the Javadoc:

Securirty via TLS encryption is required in order to connect. If the server does not offer TLS or if the TLS negotiaton fails, the connection to the server will fail.

Share:
15,385
staffan
Author by

staffan

I'm the serviceability architect/tech lead for the Java SE platform at Oracle. I've previously been the chief architect for JRockit.

Updated on June 28, 2022

Comments

  • staffan
    staffan almost 2 years

    I'm building a small program that acts as an XMPP client and I am using the Smack library. Now, the server I am connecting to requires SSL (in Pidgin I have to check "Force old (port 5223) SSL"). I'm having trouble getting Smack to connect to this server. Is it possible?

  • Alastair Brayne
    Alastair Brayne about 8 years
    What are the Context and R classes?
  • Iqbal S
    Iqbal S about 8 years
    @Alastair Context is the application or class level context, which you can pass using this. And R is a class from which I get the key stores stored in my hard drive in the raw directory, you can directly pass that resource to the in by any other means as you like too.
  • Alastair Brayne
    Alastair Brayne about 8 years
    Sounds like you're working in a specific framework. Android? I'm not, so this just confused me for a bit. But I figured it out. Thanks anyway.
  • Iqbal S
    Iqbal S about 8 years
    Yes you are correct, the code is domain specific, but you can apply the same to any domain. Small changes required. Hope you felt the answer helpful, upvote shall be appreciated. ;-) Thanks.
  • Priya
    Priya over 7 years
    @Iqbal, will this cetificate ask persmission from the user to allow ?
  • Iqbal S
    Iqbal S over 7 years
    @Priya In Android all the permissions are asked when the user installs the application, so we do not ask any permission for the user. If you are working on a different framework, or even in Android if you want to ask the permission from the user, then you can do it before loading the trust store, using a confirm box, to ask user wants to continue by loading it or no.. Hope this helps!!
  • Priya
    Priya over 7 years
    thank u Iqbal.., what does <certificate_file_with_path> meant her ?
  • Iqbal S
    Iqbal S over 7 years
    @Priya it is the local path of your certificate with full name.