Search code examples
javac#androidssltcp

SSL TCP connection on Android (with cert)


I'm new on Android platform, coming from .NET world. I need to write a TCP/SSL client class in my app, which send/recieve text messages with some Java server. I also need to use server public certificate (.cer file) in that communication. In C# I have SSLStream class that do all the job, and a lot of examples for it. However for Android (Lolipop) I cannot find any good examples on this subject, especially without http protocol on top. Any hint would be appreciated.


Solution

  • Below is basially steps to create ssl connection in android :

    Step 1 : Get public key of ur server (.cert file), which you already have.

    Step 2: Create keystore via bouncycastle jar

    Below is commands :

    keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/myKeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
    

    Verify if the certificates were imported correctly into the keystore:

    keytool -list -keystore "res/raw/myKeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
    

    Should output the whole chain:

    RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
    

    Now you can copy the keystore as a raw resource in your android app under res/raw/

    Step 3:

    Create HttpsClient like below and query you service with this client only :

    public class HttpsClient extends DefaultHttpClient {
    
        final Context context;
    
        public HttpsClient(Context context) {
            this.context = context;
        }
    
        @Override
        protected ClientConnectionManager createClientConnectionManager() {
            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory
                    .getSocketFactory(), 80));
            // Register for port 443 our SSLSocketFactory with our keystore
            // to the ConnectionManager
            registry.register(new Scheme("https", newSslSocketFactory(), 443));
            return new SingleClientConnManager(getParams(), registry);
        }
    
        private SSLSocketFactory newSslSocketFactory() {
            try {
                // Get an instance of the Bouncy Castle KeyStore format
                KeyStore trusted = KeyStore.getInstance("BKS");
                // Get the raw resource, which contains the keystore with
                // your trusted certificates (root and any intermediate certs)
                InputStream in = context.getResources().openRawResource(
                        R.raw.mykeystore);
                try {
                    // Initialize the keystore with the provided trusted
                    // certificates
                    // Also provide the password of the keystore
                    trusted.load(in, "mysecret".toCharArray());
                } finally {
                    in.close();
                }
                // Pass the keystore to the SSLSocketFactory. The factory is
                // responsible
                // for the verification of the server certificate.
                SSLSocketFactory sf = new SSLSocketFactory(trusted);
                // Hostname verification from certificate
                sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                return sf;
            } catch (Exception e) {
                throw new AssertionError(e);
            }
        }
    }
    

    The Above Case holds true for connection over http , if you need to have connection without http , the keystore procedure remains the same and you need to use sockets to open and close the connection :

    String keyStorePath = "absolute path to your JKS keystore file";
    String keyStorePass = "keystore password";
    
    System.setProperty("javax.net.ssl.keyStore", keyStorePath);
    System.setProperty("javax.net.ssl.keyStorePassword", keyStorePass);
    
    SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
    SSLServerSocket serverSocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(port_number);
    
    while (true) {
        new ClientThread((SSLSocket) serverSocket.accept()).start();
    }