最近跟華為做合作項(xiàng)目,主要是我這邊提供sdk集成到華為的app里,對(duì)方要求sdk與我方服務(wù)器的數(shù)據(jù)通信必須使用證書綁定,這里簡(jiǎn)單記錄一下流程。
//證書的public key 真實(shí)key這里就不放出來了, 可以通過 keytool -printcert -rfc -file xxx.crt得到
private static final String cert = "-----BEGIN CERTIFICATE-----\n" +
"-----END CERTIFICATE-----";
SSLSocketFactory sslSocketFactory = null;
try {
InputStream certStream = new Buffer().writeUtf8(certString).inputStream();
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
if (certificates.isEmpty()) {
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
}
char[] password = "".toCharArray(); // Any password will work.
KeyStore keyStore;
try {
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream in = null; // By convention, 'null' creates an empty key store.
keyStore.load(in, password);
} catch (IOException e) {
throw new AssertionError(e);
}
int index = 0;
for (Certificate certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificate);
}
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}
SSLContext ssContext = SSLContext.getInstance("TLS");
ssContext.init(keyManagerFactory.getKeyManagers(), trustManagers, null);
SslSocketFactory sslSocketFactory = sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
}
OkHttpClient client = new OkHttpClient().newBuilder().sslSocketFactory(sslSocketFactory).hostnameVerifier(STRICT_HOSTNAME_VERIFIER) .build();
主要流程是根據(jù)證書創(chuàng)建trustmanager,并以此創(chuàng)建SslSocketFactory對(duì)象設(shè)置到okhttpclient上,同時(shí)要記得配置hostnameVerifier,兩者前者負(fù)責(zé)檢驗(yàn)證書,后者負(fù)責(zé)檢驗(yàn)域名。目前測(cè)試下來會(huì)對(duì)所有使用該client的https網(wǎng)絡(luò)請(qǐng)求做證書驗(yàn)證,如何在同一個(gè)client下只篩選特定域名請(qǐng)求暫時(shí)不知道如何實(shí)現(xiàn),不過也已經(jīng)滿足功能需求。中間嘗試跟了一下證書驗(yàn)證的源碼,發(fā)現(xiàn)實(shí)際實(shí)現(xiàn)并不在andorid的jar包里,后續(xù)有機(jī)會(huì)再跟。