簡體   English   中英

Android - 如何以編程方式在密鑰庫中存儲證書?

[英]Android - How to store certificate in keystore programmatically?

我正在制作一個金融交易Android應用程序。 它需要SSL身份驗證,我成功完成了它(Android和Tomcat之間的握手)。 我使用keytool和openSSL生成服務器和客戶端證書。 Tomcat certifcate格式是JKS,而android formate是BKS。 我將此BKS文件存儲在Raw文件夾中,並按如下方式使用:

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

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

現在我想使用此HTTPS連接注冊用戶。 該過程是從用戶獲取詳細信息並將其發送到服務器。 服務器將驗證這些詳細信息並在用戶移動設備上發送確認PIN(在用戶詳細信息中獲取此MSISDN)。 用戶將輸入此PIN,服務器將驗證PIN是否相同。 用戶驗證后,客戶端應用程序(用戶移動)將生成CSR並將其發送到服務器。 服務器將使用此CSR生成證書並將其發送到客戶端(移動應用程序)。 現在我的問題是我想存儲此證書,只有我的應用程序可以訪問此證書。 我試圖將此保存在我的原始文件夾中的BKS文件中使用:

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

此代碼成功運行,但無法在BKS文件中存儲證書。 我嘗試另一種方式描述了這里 ,但未能成功。 (我想稍后在我的應用程序中使用此證書進行客戶端身份驗證)我的問題是問:如何存儲此證書,以便只能通過我的應用程序訪問? 此外,我還可以在用戶注冊過期時刪除此證書。

請提前幫助和感謝。

  • 您的問題不在於密鑰庫本身,而在於您嘗試存儲新客戶端證書的文件的位置!
  • “RAW-folder”是已安裝的應用程序包的一部分。 所以你可以“虛擬”訪問它,只讀,而不是寫!
  • 如果您希望密鑰庫是私有的,那么您的最佳選擇是應用程序sandboxed-private-folder(內部存儲)。
    您不能在RAW文件夾中寫入,但可以在應用程序私有文件夾中寫入。
  • 在您提供的鏈接中,存儲/寫入位置實際上是私人文件夾。 所以它不適合你,因為你試圖“ 寫入原始文件夾
  • 您可能已經知道了,但您可以將文件(R.raw.client)從“Raw-folder”復制到應用程序專用文件夾。 這樣,您只使用一個密鑰庫文件(可讀寫)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM