我正在制作一个金融交易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文件中存储证书。我尝试了另一种方式描述here,但无法成功。 (我想稍后在我的应用程序中使用此证书进行客户端身份验证) 我的问题是问:如何存储此证书,以便只能通过我的应用访问?此外,我还可以在用户注册过期时删除此证书。
请提前帮助和谢谢。
答案 0 :(得分:2)