Android - How to programmatically save a certificate in a keystore?

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) { // should never happen e.printStackTrace(); Log.d("Err", e.toString()); } return "no result"; } @Override protected void onPostExecute(String result) { responseListener.getResponse(result,code); } } 

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.

+5
source share
1 answer
  • Your problem is not with the keystore itself, but with the location of the file where you are trying to save the new client certificate!
  • The "RAW folder" is part of your installed application package. So you can "actually" access it, and only READ, not WRITE!
  • Your best option if you want your keystore to be private is your application sandboxed-private-folder (Internal storage).
    You cannot write in a RAW folder, but you can write in your private application folder.
  • In the link you provided, the storage / recording location is in the fact of the private folder. So this did not work for you, because you are trying to "write to Raw-Folder"
  • You may already know this, but you can copy the file (R.raw.client) from the "Raw-folder" folder to your personal application folder. This way you use only one keystore file (readable and writable).
+2
source

Source: https://habr.com/ru/post/1235947/


All Articles