Я пытаюсь заменить текущее работающее HTTP-соединение на HTTPS-соединение в приложении для Android, которое я пишу. Необходима дополнительная безопасность HTTPS-соединения, поэтому я не могу игнорировать этот шаг.
У меня есть следующее:
SSLSocketFactory.getSocketFactory ()
, соединение работает нормально, но сертификат клиента является обязательной частью этих спецификаций приложения, поэтому: javax.net. ssl.SSLPeerUnverifiedException: нет исключения однорангового сертификата
, когда я пытаюсь подключиться с помощью моего пользовательского SSLSocketFactory
, но я не совсем уверен, почему. Это исключение кажется немного двусмысленным после поиска в Интернете различных решений. Вот соответствующий код для клиента:
SSLSocketFactory socketFactory = null;
public void onCreate(Bundle savedInstanceState) {
loadCertificateData();
}
private void loadCertificateData() {
try {
File[] pfxFiles = Environment.getExternalStorageDirectory().listFiles(new FileFilter() {
public boolean accept(File file) {
if (file.getName().toLowerCase().endsWith("pfx")) {
return true;
}
return false;
}
});
InputStream certificateStream = null;
if (pfxFiles.length==1) {
certificateStream = new FileInputStream(pfxFiles[0]);
}
KeyStore keyStore = KeyStore.getInstance("PKCS12");
char[] password = "somePassword".toCharArray();
keyStore.load(certificateStream, password);
System.out.println("I have loaded [" + keyStore.size() + "] certificates");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password);
socketFactory = new SSLSocketFactory(keyStore);
} catch (Exceptions e) {
// Actually a bunch of catch blocks here, but shortened!
}
}
private void someMethodInvokedToEstablishAHttpsConnection() {
try {
HttpParams standardParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(standardParams, 5000);
HttpConnectionParams.setSoTimeout(standardParams, 30000);
SchemeRegistry schRegistry = new SchemeRegistry();
schRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schRegistry.register(new Scheme("https", socketFactory, 443));
ClientConnectionManager connectionManager = new ThreadSafeClientConnManager(standardParams, schRegistry);
HttpClient client = new DefaultHttpClient(connectionManager, standardParams);
HttpPost request = new HttpPost();
request.setURI(new URI("https://TheUrlOfTheServerIWantToConnectTo));
request.setEntity("Some set of data used by the server serialized into string format");
HttpResponse response = client.execute(request);
resultData = EntityUtils.toString(response.getEntity());
} catch (Exception e) {
// Catch some exceptions (Actually multiple catch blocks, shortened)
}
}
Я проверил это, да, действительно, хранилище ключей загружает сертификат, и все это устраивает.
У меня есть две теории относительно того, чего мне не хватает в чтении о HTTPS / SSL-соединениях, но поскольку это действительно мой первый набег, я немного озадачен тем, что мне действительно нужно для решения этой проблемы.
Первая возможность, насколько я могу судить, состоит в том, что мне нужно настроить этот SSLSocketFactory с хранилищем доверенных сертификатов устройств, которое включает все стандартные промежуточные центры сертификации и центры сертификации конечных точек. То есть устройство по умолчанию SSLSocketFactory.getSocketFactory ()
загружает некоторый набор центров сертификации в хранилище доверенных сертификатов фабрики, которое используется для доверия серверу, когда он отправляет свой сертификат, и это то, что дает сбой в моем коде, потому что у меня неправильно загружено хранилище доверенных сертификатов. Если это правда, как мне лучше всего загрузить эти данные?
Вторая возможность связана с тем, что сертификат клиента самоподписан (или выпущен внутренним центром сертификации - поправьте меня, если я неправильно, но на самом деле это одно и то же, для всех намерений и целей здесь). На самом деле мне не хватает этого хранилища доверенных сертификатов, и в основном мне нужно предоставить серверу возможность проверить сертификат с помощью внутреннего ЦС, а также подтвердить, что этот внутренний ЦС на самом деле является "надежный" . Если это правда, то что именно я ищу? Я видел некоторые ссылки на это, которые заставляют меня думать, что это может быть моя проблема, как в здесь , но я действительно не уверен.Если это действительно моя проблема, что бы я попросил у человека, обслуживающего внутренний центр сертификации, и как мне добавить это в свой код, чтобы мое HTTPS-соединение работало?
Третье и, надеюсь, менее возможное решение , заключается в том, что я совершенно не прав в каком-то моменте здесь и пропустил важный шаг или полностью игнорирую часть HTTPS / SSL, о которой я просто в настоящее время ничего не знаю. Если это так, не могли бы вы дать мне небольшое руководство, чтобы я мог пойти и узнать, что мне нужно выучить?
Спасибо за чтение!