I am working on an Android application that requires client and server certificate authentication. I have an SSLClient class that I created that works great on regular desktop Java SE 6. I moved it to my Android project and I get the following error: "KeyStore JKS implementation not found".
I looked a bit on the Internet and it looks like Java Keystores is not supported on Android (awesome!), But I have a feeling that this is more than because none of the code examples that I found looks like I trying to do at all. All I found is talking about using an http client, not raw SSL sockets. I need SSL sockets for this application.
Below is the code in the SSLClient.java file. It reads the keystore and trust store, creates an SSL socket connection to the server, then starts a loop, waiting for input from the server, and then processes them when they enter, calling the method in another class. I am very interested to hear from anyone who has experience with SSL sockets on the Android platform.
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.security.AccessControlException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; import otherpackege.OtherClass; import android.content.Context; import android.util.Log; public class SSLClient { static SSLContext ssl_ctx; public SSLClient(Context context) { try { // Setup truststore KeyStore trustStore = KeyStore.getInstance("BKS"); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); InputStream trustStoreStream = context.getResources().openRawResource(R.raw.mysrvtruststore); trustStore.load(trustStoreStream, "testtest".toCharArray()); trustManagerFactory.init(trustStore); // Setup keystore KeyStore keyStore = KeyStore.getInstance("BKS"); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); InputStream keyStoreStream = context.getResources().openRawResource(R.raw.clientkeystore); keyStore.load(keyStoreStream, "testtest".toCharArray()); keyManagerFactory.init(keyStore, "testtest".toCharArray()); Log.d("SSL", "Key " + keyStore.size()); Log.d("SSL", "Trust " + trustStore.size()); // Setup the SSL context to use the truststore and keystore ssl_ctx = SSLContext.getInstance("TLS"); ssl_ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); Log.d("SSL", "keyManagerFactory " + keyManagerFactory.getKeyManagers().length); Log.d("SSL", "trustManagerFactory " + trustManagerFactory.getTrustManagers().length); } catch (NoSuchAlgorithmException nsae) { Log.d("SSL", nsae.getMessage()); } catch (KeyStoreException kse) { Log.d("SSL", kse.getMessage()); } catch (IOException ioe) { Log.d("SSL", ioe.getMessage()); } catch (CertificateException ce) { Log.d("SSL", ce.getMessage()); } catch (KeyManagementException kme) { Log.d("SSL", kme.getMessage()); } catch(AccessControlException ace) { Log.d("SSL", ace.getMessage()); } catch(UnrecoverableKeyException uke) { Log.d("SSL", uke.getMessage()); } try { Handler handler = new Handler(); handler.start(); } catch (IOException ioException) { ioException.printStackTrace(); } } } //class Handler implements Runnable class Handler extends Thread { private SSLSocket socket; private BufferedReader input; static public PrintWriter output; private String serverUrl = "174.61.103.206"; private String serverPort = "6000"; Handler(SSLSocket socket) throws IOException { } Handler() throws IOException { } public void sendMessagameInfoge(String message) { Handler.output.println(message); } @Override public void run() { String line; try { SSLSocketFactory socketFactory = (SSLSocketFactory) SSLClient.ssl_ctx.getSocketFactory(); socket = (SSLSocket) socketFactory.createSocket(serverUrl, Integer.parseInt(serverPort)); this.input = new BufferedReader(new InputStreamReader(socket.getInputStream())); Handler.output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream())); Log.d("SSL", "Created the socket, input, and output!!"); do { line = input.readLine(); while (line == null) { line = input.readLine(); } // Parse the message and do something with it // Done in a different class OtherClass.parseMessageString(line); } while ( !line.equals("exit|") ); } catch (IOException ioe) { System.out.println(ioe); } finally { try { input.close(); output.close(); socket.close(); } catch(IOException ioe) { } finally { } } } }
Update:
Making some progress on this issue. It turned out that JKS is really not supported, and the SunX509 type is not directly selected. I updated my code above to reflect these changes. I still have a problem with this, apparently not loading the keystore and trust store. I will update when I find out more.
Update2:
I was loading the keystore and truststore file on the Java desktop, and not on the correct Android path. Files must be placed in the res / raw folder and loaded using getResources (). Now I get a score of 1 and 1 for the keystore and trust size, which means they load. I was still crashing into an exception, but getting closer! I will update when I get this work.
Update3:
Everything seems to be working now, except that my keystore is configured incorrectly. If I disable client-side authentication on the server, it will be connected without problems. When I leave it turned on, I get the error handling exception: javax.net.ssl.SSLHandshakeException: null cert chain . So it looks like I'm not setting up the certificate chain correctly. I asked one more question about how to create a client key store in BKS format with a proper certificate chain: How to create a Java Keystore BKS (BouncyCastle) format that contains a client certificate chain