Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XMPPFramework - Connect via SSL on Openfire

I'm trying to connect my users via SSL from my iOS XMPP chat client to Openfire server.

In my iOS client:

- (void)setupStream 
{
    ...
    // BOOL values for security settings
    customCertEvaluation = NO;
    allowSelfSignedCertificates = YES;
    allowSSLHostNameMismatch = NO;
}

In my Openfire server's Security Settings > Client Connection Security, I've set:

Required - Clients can only connect to the server using secured connections.

Thus, the following delegate method will be called:

- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings 
{
    NSString *expectedCertName = [xmppStream.myJID domain];

    if (customCertEvaluation)
        [settings setObject:@(YES) forKey:GCDAsyncSocketManuallyEvaluateTrust];

    if (allowSelfSignedCertificates)
        [settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];

    if (allowSSLHostNameMismatch)
        [settings setObject:[NSNull null] forKey:(NSString *)kCFStreamSSLPeerName];

    else
        if (expectedCertName)
            [settings setObject:expectedCertName forKey:(NSString *)kCFStreamSSLPeerName];
}

I attempted this solution from this thread: XMPPFramework TLS/SSL connection with Openfire

However, when I run my application and attempt to connect to the server, I'd receive this error:

Security option unavailable - kCFStreamSSLAllowsAnyRoot - You must use manual trust evaluation

I looked through the GCDAsyncSocket class and realized kCFStreamSSLAllowsAnyRoot is stated as deprecated. An NSAssert was implemented to deliberately throw the error.

Next, I decided to change my BOOL values as such:

- (void)setupStream 
{
    ...
    // BOOL values for security settings
    // Manually evaluate trust
    customCertEvaluation = YES;
    allowSelfSignedCertificates = NO;
    allowSSLHostNameMismatch = NO;
}

This time, again, no connection could be made to the server but, no error was prompted.

I could connect to Openfire fine if I changed the Client Connection Security back to the original setting > Optional. But, I wouldn't be connected via SSL as indicated by a lock icon beside every user's status in Client Sessions.

My Android client (using Smack API for XMPP) connects to Openfire via SSL without issues. So I'm wondering if there's workaround I have to implement for my iOS client using XMPPFramework.

I would greatly appreciate any advices.

like image 370
Keith OYS Avatar asked Jun 19 '14 04:06

Keith OYS


People also ask

How do I enable SSL for the Openfire chat server?

Complete the following steps to enable a secure sockets layer (SSL) for the Openfire chat server that runs with Smart IT. Obtain a valid, signed certificate from a trusted certificate authority (CA). The certificate can be in any format, such as .pem, .cer, or .crt. Import the certificate provided by the CA.

What port does XMPP use for SSL?

xmpp.socket.ssl.port -- the port to use for SSL (default is 5223 for XMPP) xmpp.socket.ssl.storeType -- the store type used ("JKS" is the Sun Java Keystore format used by the JDK keytool). If this property is not defined, Openfire will assume a value of "jks".

What security tools do I need to configure SSL with Openfire?

The Sun JDK (version 1.5.x) ships with all the security tools you need to configure SSL with Openfire. The most important is the keytool located in the JAVA_HOME/bin directory of the JDK. Sun JVMs persist keystores and truststores on the filesystem as encrypted files.

How do I get a certificate for Openfire?

Obtain a valid, signed certificate from a trusted certificate authority (CA). The certificate can be in any format, such as .pem, .cer, or .crt. Import the certificate provided by the CA. Do these steps for all Openfire nodes, if installed in a cluster.


1 Answers

Explanation

In the latest version of XMPP (after April 22), you can no longer use allowSelfSignedCertificates = YES with the following:

if (allowSelfSignedCertificates)
    [settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];`

This is because kCFStreamSSLAllowsAnyRoot & SSLSetAllowsAnyRoot have been deprecated.

 /* 
  * ==== The following UNAVAILABLE KEYS are: (with throw an exception)
  * - kCFStreamSSLAllowsAnyRoot (UNAVAILABLE)
  *     You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust).
  *     Corresponding deprecated method: SSLSetAllowsAnyRoot
  */

See XMPPFramework/GCDAsyncSocket.h & Deprecated Secure Transport Functions.


Solution

  1. Go to Openfire server > Security Settings > Client Connection Security

    Check: Required - Clients can only connect to the server using secured connections.

  2. Define variable in AppDelegate

    BOOL customCertEvaluation;
    
  3. Set variable in setupStream

    - (void)setupStream 
    {
        ...
        customCertEvaluation = YES;
    }
    
  4. Set security settings in willSecureWithSettings

    - (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
    {
        /*
         * Properly secure your connection by setting kCFStreamSSLPeerName 
         * to your server domain name
         */
        [settings setObject:xmppStream.myJID.domain forKey:(NSString *)kCFStreamSSLPeerName];
    
        /*
         * Use manual trust evaluation
         * as stated in the XMPPFramework/GCDAsyncSocket code documentation
         */
        if (customCertEvaluation)
            [settings setObject:@(YES) forKey:GCDAsyncSocketManuallyEvaluateTrust];
    }
    
  5. Validate peer manually

    /*
     * This is only called if the stream is secured with settings that include:
     * - GCDAsyncSocketManuallyEvaluateTrust == YES
     * That is, if a delegate implements xmppStream:willSecureWithSettings:, and plugs in that key/value pair.
     */
     - (void)xmppStream:(XMPPStream *)sender didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler
     {
         /* Custom validation for your certificate on server should be performed */
    
         completionHandler(YES); // After this line, SSL connection will be established
     }
    
like image 92
Keith OYS Avatar answered Oct 05 '22 22:10

Keith OYS