4

I am using java's SSLSocket to securely connect an android application to a server. The certificate is located in a truststore. But the passcode to the truststore seems to be required for the connection and so it is currently hardcoded into the device. I don't know much about PKI but that doesn't seem secure. I am bundling the truststore with the application in the raw resources folder. Is there a better approach to securely allow an application to connect to a server using TLS? I am very much new to TLS/SSL so I would appreciate any help or recommendations.

Here is the client side of the code.

        store = KeyStore.getInstance("BKS"); 
        InputStream in = appcontext.getResources().openRawResource(R.raw.truststore);
        store.load(in, "PASSWORD".toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        tmf.init(store);
        sslcontext = SSLContext.getInstance("TLS");
        sslcontext.init(null, tmf.getTrustManagers(), new SecureRandom());

        SSLSocketFactory sslsocketfactory = sslcontext.getSocketFactory();

        // connect to socket
        SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(
                "192.168.1.16", 9999);
minhaz1
  • 733
  • 1
  • 5
  • 13
  • When you say "insecure", are you concerned about someone decrypting and reading your network communication, or are you worried about other programs (or individuals) impersonating your app? – Connor Brinton Aug 05 '13 at 22:23

2 Answers2

5

I haven't tried on Android, but here is how it works in plain Java.

You're using your keystore as a truststore here, so (hopefully) it doesn't contain any private key or secret material. In this case, the purpose of the password is to verify the integrity of the store.

From the Keystore.load(InputStream, char[]) documentation:

A password may be given to unlock the keystore (e.g. the keystore resides on a hardware token device), or to check the integrity of the keystore data. If a password is not given for integrity checking, then integrity checking is not performed.

Either you use null as the password (in which case you'll always be able to load the certificates) or you use a non-null char array with the actual password (in which case an incorrect password will fail with something like "java.io.IOException: Keystore was tampered with, or password was incorrect").

Using a password here is meant to increase the security (to prevent the truststore to be tampered with). This being said, if you're bundling both this truststore and this application together, it's likely that an attacker able to replace the truststore would also gain access to the password (by decompiling) anyway. (I'm not too familiar with Android app distribution, but if apps are signed, it's possible that tampering with raw resources such as your truststore would invalidate the signature too, so that might be a more realistic way of having this protection. Otherwise, I guess you can ask the user to input the truststore's password every time, but that seems unrealistic.)


It's not really part of your question, but to secure the SSL/TLS connection, you also need to verify that the certificate sent by the server is valid for the host name you were trying to reach, after SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("192.168.1.16", 9999);.

This was discussed recently in this question in Java. (Unfortunately, you won't be able to use the new Java 7 API to do this automatically for you on Android, so you'll have to check the certificate a bit more manually. You might also be interested in this recent question.)


EDIT (following your comment):

I'm concerned about someone recompiling the application, retrieving the passcode and the truststore and using it to connect to my server. If it is possible then it kind of defeats the purpose of the TLS in the first place.

It's not clear from this comment you understand the purpose of the truststore (see this question, for example).

The purpose of the truststore in your client app isn't to authenticate your app to the server, it is to make sure your client can verify the identity of the server it connects to, so that it can't be tricked into connecting to a MITM attacker. It's not about how your server trusts your app/client/user, but it's about how your app trusts your server.

Authenticating the app user to the server would be the purpose of a keystore. This is fine for authenticating the user (but it would make more sense if each user had a different certificate). Making sure connections can only come from your app is another, much more difficult problem (a lost cause, if you don't have complete control of the client hardware at all times). Using a common client certificate in your app could buy you a bit of time, but anyone who has got hold of the client code could certainly reverse engineer it eventually. I wouldn't spend too much time on it. You might be interested in these questions:

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
0

Problem: Anything you include in your source code is readable by anyone who has obtained the apk file. Therefore, if you include your passcode and truststore in your source code (or your resource files), it can be read by anyone with the apk.

In fact, it is impossible to guarantee that the app connecting to your server is your own app. Imagine a modified Dalvik VM, which waits until your app has run SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("192.168.1.16", 9999);, and then passes sslsocket to another app.

Solution:

  1. Move your trusted code to the server. For example, if you have a method in your app called addNewProductDirectlyToDatabaseOnServer, replace it with a method called addNewProductToServer, and have it call a REST API for your server, that adds a new user, without letting evil apps directly control your databases.
  2. Authenticate individual users using passwords. This isn't strictly necessary, but it helps make sure that the right people are accessing your server, and if a badguy ever gets someone's password (or if someone becomes a badguy), you can revoke their access to the server by disabling their password/login.

If you're interested in learning more about how attackers could pull your source code out of your apk file, I would recommend looking at these tools:

Connor Brinton
  • 361
  • 3
  • 9