1

We have mobile hybrid project running on MobileFirst 7.1.0.00.20170627-0807.

We have changed our Servers configuration to stop supporting TLS 1.0 and 1.1 and force it to use TLS 1.2 which broke our mobile app running on android devices 4.4.2 as it requires a native development to support it based on the references below:

ANDROID VERSIONS 4.4.2 AND EARLIER CANNOT CONNECT TO SERVER USING HTTPS IF ONLY TLS 1.2 IS ENABLED

We tried multiple solutions as referenced in the below blogs but with no luck:

Custom SSLSocketFactory Implementation to enable tls 1.1 and tls 1.2 for android 4.1 (16+)

How to enable TLS 1.2 support in an Android application

in my native code directory ca.company.project I have added a Java file to support the custom SSLSocketFactory:

package ca.company.project;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

/**
 * @author fkrauthan
 */
public class TLSSocketFactory extends SSLSocketFactory {

    private SSLSocketFactory internalSSLSocketFactory;

    public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, null, null);
        internalSSLSocketFactory = context.getSocketFactory();
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return internalSSLSocketFactory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return internalSSLSocketFactory.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket() throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
    }

    private Socket enableTLSOnSocket(Socket socket) {
        if(socket != null && (socket instanceof SSLSocket)) {
            ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
        }
        return socket;
    }
}

And in my native code which is under the same directory MobileBanking.java I have added the below code for onCreate():

 package ca.company.project;

    import org.apache.cordova.CordovaActivity;

    import android.app.Activity;
    import android.app.AlertDialog;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.DialogInterface.OnClickListener;
    import android.content.pm.ActivityInfo;
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.util.DisplayMetrics;
    import android.view.WindowManager.LayoutParams;
    import android.content.pm.PackageManager;
    import com.adobe.mobile.*;

    import com.worklight.androidgap.api.WL;
    import com.worklight.androidgap.api.WLInitWebFrameworkListener;
    import com.worklight.androidgap.api.WLInitWebFrameworkResult;
    import com.worklight.wlclient.api.WLClient;


    import javax.net.ssl.SSLSocketFactory;

    import java.security.KeyManagementException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;

    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;


    import android.os.*;

    public class MobileBanking extends CordovaActivity implements WLInitWebFrameworkListener {

        @Override
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);


            /*getWindow().setFlags(LayoutParams.FLAG_SECURE,
                    LayoutParams.FLAG_SECURE);*/

            WL.createInstance(this);


    try{
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, null, null);
        SSLSocketFactory noSSLv3Factory = null;
        if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.KITKAT) {
            noSSLv3Factory = new TLSSocketFactory();
        } else {
            noSSLv3Factory = sslContext.getSocketFactory();
        }
        HttpsURLConnection.setDefaultSSLSocketFactory(noSSLv3Factory);

    }  catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    }




            WL.getInstance().showSplashScreen(this);

            WL.getInstance().initializeWebFramework(getApplicationContext(), this);

            if(isTabletDevice(this)){
                //Tablet
    //          System.out.println("isTablet oncreate");
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
            } else {
                //Phone
                 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            }
            // Allow the SDK access to the application context
            Config.setContext(this.getApplicationContext());
        }

And it is not working, Any idea what I'm missing or what I need to change?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Sami
  • 572
  • 8
  • 22

1 Answers1

0

I can't immediately comment on the code you've provided, but here is a solution that I know has worked for another MFP user facing the same issue:

1) Go to this GitHub repo, and take the classes in "TlsSniSocketFactory.java", "IgnoreSSLTrustManager.java", and "SelfSignedTrustManager.java". Keep in mind, this open source code is not provided by IBM, and IBM doesn't provide any support for it.

2) Include these classes in your application - change the package name to agree with your application.

3) Include this method in the application main activity extending CordovaActivity:

private void replaceSocketFactory(LayeredSocketFactory tlsSocketFactory) {
        HttpClientManager manager = HttpClientManager.getInstance();
        HttpClient client=  manager.getHttpClient();
        SchemeRegistry schemeRegistry =  client.getConnectionManager().getSchemeRegistry();  
        Scheme httpsScheme = schemeRegistry.getScheme("https");
        schemeRegistry.unregister("https");
        Scheme newScheme = new Scheme("https", tlsSocketFactory, httpsScheme.getDefaultPort());
        schemeRegistry.register(newScheme);
    }

4) Call this method from Activity.onCreate() method right after WL.createInstance(this);

@Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        WL.createInstance(this);
        replaceSocketFactory(new TlsSniSocketFactory());

        WL.getInstance().showSplashScreen(this);

        WL.getInstance().initializeWebFramework(getApplicationContext(), this);
    }

I'm not sure why you're seeing this issue, as the build of MFP 7.1 that you're using includes the fix for this problem. You may need to remove the "android" environment from your application and add it back again, if you had previously updated from an iFix version that did not include the fix.

patbarron
  • 1,364
  • 12
  • 17
  • thank you for replying, just to clarify, are you saying that our MFP server should have the fix for this problem without any extra native coding required? we have removed the android environment, re-created it with the MFP version provided above, imported the classes again but still same issue. Do you recommend opening a PMR?on other hand, the code above didn't work for us and we are still trying to figure out why. – Sami Jul 24 '17 at 16:21
  • The fix for the APAR you've mentioned first appears in MFP 7.1 IF20160709-0639 (and later builds), so you should not encounter this issue, and should not have to do any additional native coding. Note that this is an SDK fix, not a server fix - so the version of MFP Studio (or CLI) you're using to build the app must be IF20160709-0639 or later, the server build in use has no effect on this issue. – patbarron Jul 24 '17 at 16:27
  • If you still see this issue, you most likely have a different problem (than is corrected by that APAR). Opening a PMR would be a reasonable option if detailed investigation is required. – patbarron Jul 24 '17 at 16:28
  • Thank you, my CLI version is:[echo] Worklight Ant task version 7.1.0.00.20170627-0807. I have recreated the android env again and signed the apk, installed it on two emulators, one is running 4.4.2 and the other is 5.0. The 5.0 worked but the 4.4.2 throws this error (log file shared): https://www.dropbox.com/s/0jdk9rct6s05v7k/ADB_LogCat_1.txt?dl=0 – Sami Jul 24 '17 at 17:45
  • Thanks for providing the log. I'd recommend to open a PMR if possible - the error in the log is being generated from the certificate pinning code, and I'm not sure if the APAR fix we've been discussing affects that code path. It might be an interesting experiment to try this without using certificate pinning and see if the same type of error is generated. – patbarron Jul 24 '17 at 19:38
  • Thank you for checking the logs, would you please elaborate more on "try this without using certificate pinning"! as we are not using certificate pinning in our project. I just need to know if I need to try another solution before going through the PMR path. – Sami Jul 24 '17 at 19:43
  • Hmm.... If you take a look at the stack traces in the log, you see that the error is passing through "com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning.verify(HostNameVerifierWithCertificatePinning.java:42)". That's what led me to suggest an issue with certificate pinning, and caused me to assume that you were using that. – patbarron Jul 24 '17 at 19:46