2015-11-14 15 views
5

Sto facendo un'app per Android per le transazioni finanziarie. Richiede l'autenticazione SSL e riesco a completarlo con successo (handshake tra Android e Tomcat). Ho usato keytool e openSSL per generare certificati server e client. Il formato di certificazione di Tomcat è JKS e Android Formate è BKS. Ho memorizzato il file nella cartella BKS Raw e uso questo come segue:Android - Come conservare il certificato nel keystore a livello di programmazione?

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); 
} 
} 

La mia classe è TrustManager:

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(); 
} 
} 

Ora voglio registrare utente che utilizza questa connessione HTTPS. Il processo è ottenere dettagli dall'utente e inviarlo al server. Il server verificherà questi dettagli e invierà il PIN di conferma sul cellulare dell'utente (ottenuto questo MSISDN nei dettagli dell'utente). L'utente inserirà questo PIN e il server verificherà che il PIN sia lo stesso. Dopo che l'utente è stato verificato, l'app client (utente mobile) genererà un CSR e lo invierà al server. Il server genera un certificato utilizzando questo CSR e lo invia al client (app per dispositivi mobili). Ora il mio problema è che voglio archiviare questo certificato dove solo la mia App può accedere a questo certificato. Sto cercando di salvare questo nel mio file BKS nella cartella RAW utilizzando questo:

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; 
} 

Questo codice viene eseguito con successo, ma non si poteva conservare cert nel file di BKS. Ho provato un altro modo per descrivere here ma non ci sono riuscito. (Voglio utilizzare questo certificato più avanti nella mia app per l'autenticazione del client) La mia domanda è Q. Come posso conservare questo certificato in modo che possa essere accessibile solo dalla mia app? E inoltre posso cancellare questo certificato quando la registrazione dell'utente scade.

Si prega di aiutare e grazie in anticipo.

risposta

2
  • il problema non è con il keystore in sé, ma piuttosto con la posizione del file in cui si sta cercando di memorizzare il nuovo certificato client !
  • La "cartella RAW" fa parte del pacchetto dell'applicazione installata. Quindi, puoi "virtualmente" accedervi, e solo LEGGERE, non SCRIVERE!
  • L'opzione migliore, se si desidera che il proprio keystore sia privato, è l'applicazione sandboxed-private-folder (memoria interna).
    Non è possibile scrivere nella cartella RAW, ma è possibile scrivere nella cartella privata dell'applicazione.
  • Nel link che hai fornito, la posizione/scrittura di archiviazione è in infatti la cartella privata. Quindi non ha funzionato per voi, perché si sta cercando di "scrittura nella cruda-Folder"
  • Probabilmente sapete già, ma è possibile copiare il file (R.raw.client) dal "Raw-folder" nella cartella privata dell'applicazione. In questo modo, si utilizza solo un file keystore (leggibile e scrivibile).
+0

Per favore, puoi dire come posso creare un nuovo keystore e quindi memorizzare il mio certificato in quel keystore per un uso successivo. Userò questo certificato per l'handshake SSL. –

Problemi correlati