Следующие основные шаги необходимы для обеспечения защищенного соединения от центров сертификации, которые не считаются доверенными для платформы Android.
По просьбе многих пользователей, я отразил самые важные части из моей статьи в блоге здесь:
- Получите все необходимые сертификаты (root и любые промежуточные CA)
- Создайте хранилище ключей с помощью keytool и поставщика BouncyCastle и импортируйте сертификаты
- Загрузите хранилище ключей в ваше приложение для Android и используйте его для защищенных соединений (я рекомендую использовать Apache HttpClient вместо стандартного
java.net.ssl.HttpsURLConnection
(проще для понимания, более производительным)
Хватай сертификаты
Вы должны получить все сертификаты, которые формируют цепочку от сертификата конечной точки до самого корневого центра сертификации. Это означает любые (если имеются) промежуточные сертификаты CA, а также сертификат корневого CA. Вам не нужно получать сертификат конечной точки.
Создать хранилище ключей
Загрузите BouncyCastle Provider и сохраните его в известном месте. Также убедитесь, что вы можете вызвать команду keytool (обычно находится в папке bin вашей установки JRE).
Теперь импортируйте полученные сертификаты (не импортируйте сертификат конечной точки) в отформатированное хранилище ключей BouncyCastle.
Я не проверял это, но я думаю, что порядок импорта сертификатов важен. Это означает, что сначала нужно импортировать самый нижний сертификат промежуточного ЦС, а затем весь путь до сертификата корневого ЦС.
С помощью следующей команды будет создано новое хранилище ключей (если оно еще не существует) с паролем mysecret и будет импортирован сертификат промежуточного ЦС. Я также определил поставщика BouncyCastle, где его можно найти в моей файловой системе и в формате хранилища ключей. Выполните эту команду для каждого сертификата в цепочке.
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
Проверьте, правильно ли были импортированы сертификаты в хранилище ключей:
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
Должен выводить всю цепочку:
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
Теперь вы можете скопировать хранилище ключей как необработанный ресурс в ваше приложение для Android под res/raw/
Используйте хранилище ключей в вашем приложении
Прежде всего мы должны создать пользовательский Apache HttpClient, который использует наше хранилище ключей для соединений 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);
}
}
}
Мы создали наш собственный HttpClient, теперь мы можем использовать его для безопасных соединений. Например, когда мы делаем вызов GET для ресурса 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();
Это оно ;)