I am making a transaction application for financial transactions. This requires SSL authentication, and I will successfully complete it (handshake between Android and Tomcat). I used keytool and openSSL to create server and client certificates. Tomcat certification format is JKS, android formate is BKS. I saved this BKS file in the Raw folder and use it as follows:
public class NetworkCallSecure extends AsyncTask<String, Void, String> { ResponseListener responseListener; Activity activity; ResultCodes code; public NetworkCallSecure(Activity activity, ResponseListener responseListener, ResultCodes code) { this.responseListener = responseListener; this.activity = activity; this.code = code; } @Override protected String doInBackground(String... params) { try{ System.setProperty("http.keepAlive", "false"); HttpsURLConnection .setDefaultHostnameVerifier(new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { Log.d("HTTPS",hostname+":"+session); return true; } }); char[] passwKey = "mypass".toCharArray(); KeyStore ks = KeyStore.getInstance("BKS"); InputStream in = activity.getResources().openRawResource( R.raw.client); InputStream is = activity.getResources().openRawResource( R.raw.client); ks.load(in, passwKey); KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509"); kmf.init(ks, passwKey); SSLContext context = SSLContext.getInstance("TLS"); context.init(kmf.getKeyManagers(), new X509TrustManager[] { new MyX509TrustManager(is, passwKey) }, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(context .getSocketFactory()); URL url = new URL(params[0]); HttpsURLConnection connection = (HttpsURLConnection) url .openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("Content-Length", "" + Integer.toString(params[1].getBytes().length)); connection.setDoOutput(true); byte[] outputInBytes = params[1].getBytes("UTF-8"); OutputStream os = connection.getOutputStream(); os.write( outputInBytes ); os.close(); BufferedReader bin = new BufferedReader(new InputStreamReader( connection.getInputStream())); StringBuffer sb = new StringBuffer(); String line; while ((line = bin.readLine()) != null) { sb.append(line); } in.close(); is.close(); return sb.toString(); } catch (Exception e) {
My Trustmanager class:
public class MyX509TrustManager implements X509TrustManager { X509TrustManager pkixTrustManager; public MyX509TrustManager(InputStream trustStore, char[] password) throws Exception { // create a "default" JSSE X509TrustManager. KeyStore ks = KeyStore.getInstance("BKS"); ks.load(trustStore, password); TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); tmf.init(ks); TrustManager tms[] = tmf.getTrustManagers(); /* * Iterate over the returned trustmanagers, look for an instance of * X509TrustManager. If found, use that as our "default" trust manager. */ for (int i = 0; i < tms.length; i++) { if (tms[i] instanceof X509TrustManager) { pkixTrustManager = (X509TrustManager) tms[i]; return; } } /* * Find some other way to initialize, or else we have to fail the * constructor. */ throw new Exception("Couldn't initialize"); } public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { // TODO Auto-generated method stub try { pkixTrustManager.checkClientTrusted(arg0, arg1); } catch (CertificateException excep) { // do any special handling here, or rethrow exception. } } public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { // TODO Auto-generated method stub try { pkixTrustManager.checkServerTrusted(arg0, arg1); } catch (CertificateException excep) { /* * Possibly pop up a dialog box asking whether to trust the cert * chain. */ } } public X509Certificate[] getAcceptedIssuers() { // TODO Auto-generated method stub return pkixTrustManager.getAcceptedIssuers(); } }
Now I want to register a user using this HTTPS connection. The process receives information from the user and sends it to the server. The server will verify this data and send a confirmation PIN-code on the user's mobile device (received the MSISDN data in the user's details). The user enters this PIN and the server verifies that the PIN is the same. After checking the user, the client application (user mobile device) generates CSR and sends it to the server. The server will generate a certificate using this CSR and send it to the client (mobile application). Now my problem is that I want to keep this certificate where only my application can access this certificate. I am trying to save this in my BKS file in a raw folder using this:
private boolean storeCertInKeystore(byte[] cert) { try { InputStream is = getResources().openRawResource( R.raw.client); CertificateFactory cf = CertificateFactory.getInstance("X.509"); InputStream certstream = new ByteArrayInputStream(cert); X509Certificate certificate = (X509Certificate) cf.generateCertificate(certstream); KeyStore keyStore = KeyStore.getInstance("BKS"); keyStore.load(is, "mypass".toCharArray()); keyStore.setCertificateEntry("mycert", certificate); Log.d("My App Cert: ", "true"); return true; } catch(Exception e) { e.printStackTrace(); } return false; }
This code works successfully, but cannot store the certificate in the BKS file. I tried another way to describe here , but could not succeed. (I want to use this certificate later in my application for client authentication) My question is: Q. How can I store this certificate so that it can only be accessed by my application? And also I can delete this certificate when the user registration expires.
Please help and thanks in advance.