[英]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文件中存儲證書。 我嘗試另一種方式描述了這里 ,但未能成功。 (我想稍后在我的應用程序中使用此證書進行客戶端身份驗證)我的問題是問:如何存儲此證書,以便只能通過我的應用程序訪問? 此外,我還可以在用戶注冊過期時刪除此證書。
請提前幫助和感謝。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.