Các bước chính sau đây được yêu cầu để đạt được kết nối an toàn từ Tổ chức chứng nhận không được coi là đáng tin cậy bởi nền tảng Android.
Theo yêu cầu của nhiều người dùng, tôi đã nhân đôi những phần quan trọng nhất từ bài viết trên blog của tôi ở đây:
- Lấy tất cả các chứng chỉ cần thiết (root và bất kỳ CA trung gian nào)
- Tạo kho lưu trữ khóa với keytool và nhà cung cấp BouncyCastle và nhập certs
- Tải kho khóa trong ứng dụng Android của bạn và sử dụng nó cho các kết nối được bảo mật (Tôi khuyên bạn nên sử dụng ApacheClClient thay vì tiêu chuẩn
java.net.ssl.HttpsURLConnection
(dễ hiểu hơn, hiệu quả hơn)
Lấy certs
Bạn phải có được tất cả các chứng chỉ xây dựng chuỗi từ chứng chỉ điểm cuối cho đến tận gốc CA. Điều này có nghĩa là, bất kỳ (nếu có) các cer CA trung gian và cả chứng chỉ Root CA. Bạn không cần phải có được chứng chỉ điểm cuối.
Tạo kho khóa
Tải xuống Nhà cung cấp BouncyCastle và lưu trữ nó đến một vị trí đã biết. Cũng đảm bảo rằng bạn có thể gọi lệnh keytool (thường nằm trong thư mục bin của bản cài đặt JRE của bạn).
Bây giờ, nhập các certs thu được (không nhập chứng chỉ điểm cuối) vào kho khóa được định dạng BouncyCastle.
Tôi đã không kiểm tra nó, nhưng tôi nghĩ thứ tự nhập chứng chỉ là quan trọng. Điều này có nghĩa là, nhập chứng chỉ CA trung gian thấp nhất trước tiên và sau đó đến tận chứng chỉ CA gốc.
Với lệnh sau, kho khóa mới (nếu chưa có) với mật khẩu mysecret sẽ được tạo và chứng chỉ CA trung gian sẽ được nhập. Tôi cũng đã xác định nhà cung cấp BouncyCastle, nơi có thể tìm thấy nó trên hệ thống tệp của tôi và định dạng kho khóa. Thực hiện lệnh này cho mỗi chứng chỉ trong chuỗi.
keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Xác minh nếu các chứng chỉ được nhập chính xác vào kho khóa:
keytool -list -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Nên xuất toàn bộ chuỗi:
RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
Bây giờ bạn có thể sao chép kho khóa dưới dạng tài nguyên thô trong ứng dụng Android của mình bên dưới res/raw/
Sử dụng kho khóa trong ứng dụng của bạn
Trước hết, chúng ta phải tạo một ApacheClClient tùy chỉnh sử dụng kho khóa của chúng tôi cho các kết nối HTTPS:
import org.apache.http.*
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "mysecret".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
Chúng tôi đã tạo ra httpClient tùy chỉnh của mình, bây giờ chúng tôi có thể sử dụng nó cho các kết nối an toàn. Ví dụ: khi chúng tôi thực hiện cuộc gọi GET tới tài nguyên REST:
// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.mydomain.ch/rest/contacts/23");
// Execute the GET call and obtain the response
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();
Đó là nó ;)