一些知識點
1.服務(wù)端生成證書文件谜叹,其實只需要利用keyTool工具生成jks后辫封,再利用KeyTool工具根據(jù)這個jks去簽發(fā)出來一個證書就可以了厉熟。具體步驟為
1. 通過keytool命令生成 jks 秘鑰文件
keytool -genkey -alias zhy_server
-keyalg RSA -keystore zhy_server.jks
-validity 3600 -storepass 123456
2. 通過keytool命令對 jks 進行簽發(fā)證書
keytool -export -alias zhy_server
-file zhy_server.cer
-keystore zhy_server.jks
-storepass 123456
2.在加載證書的代碼中,Java平臺默認識別jks
格式的證書文件溉潭,但是android平臺只識別bks
格式的證書文件净响。所以你需要將'jks'轉(zhuǎn)換成bks
文件,放入項目中喳瓣。
3.加載證書有兩種實現(xiàn)方式(訪問自簽名的網(wǎng)站馋贤,單向驗證):
1.你可以通過將證書文件.cer
放入到項目可讀取的位置,如'assest'文件夾畏陕。
private static SSLSocketFactory getSSLSocketFactory_Certificate(Context context, String keyStoreType, int keystoreResId)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = context.getResources().openRawResource(keystoreResId);
Certificate ca = cf.generateCertificate(caInput);
caInput.close();
if (keyStoreType == null || keyStoreType.length() == 0) {
keyStoreType = KeyStore.getDefaultType();
}
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, wrappedTrustManagers, null);
return sslContext.getSocketFactory();
}
2.你可以通過keytool命令配乓,將.cer
文件以.rfc
格式輸出(其實也就是文本格式),然后加載這段文本就行惠毁。
keytool -printcert -rfc -file srca.cer
4.Android中 自帶的SSLContext的TrustManager無法進行工作犹芹,具體原因目前不清楚,可能是自帶的TrustManager的內(nèi)部實現(xiàn)不符合場景需求仁讨。
TrustManager的主要責任是去決定提出的認證證書應(yīng)該是可信任的。如果證書是不可信任的实昨,那么連接將會被終止
完整加載證書代碼:
private static TrustManager[] getWrappedTrustManagers(TrustManager[] trustManagers) {
final X509TrustManager originalTrustManager = (X509TrustManager) trustManagers[0];
return new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return originalTrustManager.getAcceptedIssuers();
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
try {
originalTrustManager.checkClientTrusted(certs, authType);
} catch (CertificateException e) {
e.printStackTrace();
}
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
try {
originalTrustManager.checkServerTrusted(certs, authType);
} catch (CertificateException e) {
e.printStackTrace();
}
}
}
};
}
/**
*
* @param context
* @param keyStoreType Keystore類型洞豁,一般都是jks 或者 bks,but荒给,Android平臺只識別bks丈挟,所以如果你要做這種
* 加密通信的話,你需要將你的秘鑰轉(zhuǎn)成bks格式
* @param keystoreResId
* @return
* @throws CertificateException
* @throws KeyStoreException
* @throws IOException
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
private static SSLSocketFactory getSSLSocketFactory_Certificate(Context context, String keyStoreType, int keystoreResId)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = context.getResources().openRawResource(keystoreResId);
Certificate ca = cf.generateCertificate(caInput);
caInput.close();
if (keyStoreType == null || keyStoreType.length() == 0) {
keyStoreType = KeyStore.getDefaultType();
}
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, wrappedTrustManagers, null);
return sslContext.getSocketFactory();
}
5. 默認信任所有證書
上面的代碼都是在有證書的條件下志电,而如果沒有證書呢曙咽?如果跳過這個環(huán)節(jié)還保證不出錯?那么只能信任所有的證書
client.sslSocketFactory(createSSLSocketFactory());
client.hostnameVerifier(new TrustAllHostnameVerifier());
private static class TrustAllManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
private static class TrustAllHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}