2017-02-10 15 views
2

Вещь, которую я пытаюсь сделать, довольно проста - я хочу получить полную цепочку сертификатов при подключении к серверу из приложений iOS и Android.Не удается получить корневой сертификат CA из цепочки в Android

В прошивке, я использую NSURLSession и первостепенную URLSession:didReceiveChallenge: метода, в котором я нахожусь в состоянии получить цепочку сертификатов, которая в данном случае выглядит как ожидался:

[leaf certificate] - [intermediate certificate] - [root certificate]

симпатично.

Теперь я пытаюсь сделать то же самое на устройстве Android с использованием HttpsURLConnection. После подключения к серверу я получаю цепочку сертификатов (или, по крайней мере, я надеюсь, что это метод для нее) с использованием метода getServerCertificates(). Это возвращает меня Certificate[] объект, в котором я получаю цепь, которая выглядит следующим образом:

[leaf certificate] - [intermediate certificate]

Таким образом, нет корневого сертификата на Android устройства.

Вы знаете, как получить корневой сертификат из цепочки в Android?

Заранее спасибо.

ответ

2

Ваш вопрос прост, очевидно. Я просматривал раздел сертификатов сервера в спецификации TLS. Смотрите это post

Сервер должен послать заказчику сертификации цепь начиная с сертификатом сервера и промежуточных но корень CA является необязательным, так как требуется в соответствии со стандартом, что корневой сертификат быть распределены независимо друг от друга. Для серверов не обязательно включать CA корень

Клиент проверяет цепочку, ищущую корневой центр сертификации в доверительном магазине. Проверка выполняется X509TrustManager Было бы желательно, чтобы вернуть корневой сертификат найден, но, как вы можете видеть, метод заряда конца проверки беззвучно

public void checkServerTrusted(X509Certificate[] chain, String authType) 

EDITED - Как получить доверенный привиться от HTTPS подключение

Вы можете проверить промежуточный сертификат на список доступных доверенных сертификатов, чтобы проверить, кто из них является эмитентом. (Выдержки код из из here и here

TrustManagerFactory tmf = TrustManagerFactory.getInstance(
     TrustManagerFactory.getDefaultAlgorithm()); 
// Initialise the TMF as you normally would, for example: 
tmf.init((KeyStore)null); 

//get default X509TrustManager 
TrustManager[] trustManagers = tmf.getTrustManagers(); 
final X509TrustManager x509Tm = (X509TrustManager)trustManagers[0]; 

//trusted certificate issuers 
X509Certificate issuers[] = x509Tm.getAcceptedIssuers(); 

//Perform connection... 
HttpsURLConnection conn =.... 

//get the last intermediate certificate from server certificates. 
//Fixme: if the server returns alsothe root certificate... 
Certificate cert[] = conn.getServerCertificates(); 
X509Certificate intermediate = (X509Certificate)cert[cert.length-1]; 

for (int i = 0; i < issuers.length;i++){ 
    try{ 
     intermediate.verify(issuers[i].getPublicKey()); 
      //Verification ok. issuers[i] is the issuer 
      return issuers[i]; 
     } catch (Exception e){} 
    } 
} 
+0

Спасибо за ответ. Есть ли у вас какое-либо объяснение, почему я получаю корневой сертификат в случае IOS, но на Android нет? Я посылаю запрос на идентичную конечную точку в оба – uerceg

+0

Предполагая, что сервер не предоставляет корневой ЦС в цепочке (вы можете проверить его на ssllabs.com), iOS строит полную цепочку сертификации, используя соответствующий сертификат хранилища доверия, в то время как Android проверяет то же самое, но не добавляя корневой сертификат. На мой взгляд, Android (и Java) должен предоставить эту информацию. – pedrofb

+0

Да, спасибо за информацию, имеет смысл. Я пытался переопределить 'X509TrustManager', но все равно не повезло. Возможно, вы знаете, есть ли путь в Андр oid, чтобы получить корневой сертификат от устройства, который использовался для проверки промежуточного из цепочки?(в значительной степени для получения этого корня, который iOS возвращается в его API, но, вероятно, его читает из самого устройства) – uerceg