Подтвердить что ты не робот

Безопасное исправление: javax.net.ssl.SSLPeerUnverifiedException: нет однорангового сертификата

Есть несколько сообщений об этой проблеме (javax.net.ssl.SSLPeerUnverifiedException: no peer certificate), но я не нашел ничего, что сработало бы для меня.

Многие сообщения (например this и this) "разрешают" это, разрешая всем сертификатам но, конечно, это нехорошее решение для чего угодно, кроме тестирования.

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

Итак, моя проблема: я тестирую на сервере, доступном только через локальную сеть, подключаясь через HTTPS. Выполнение вызова, которое мне нужно через браузер, отлично работает. Не жалуйтесь на сертификаты, и если вы проверяете сертификаты, все выглядит хорошо.

Когда я пытаюсь использовать Android-устройство, я получаю javax.net.ssl.SSLPeerUnverifiedException: No peer certificate

Здесь код, который его вызывает:

StringBuilder builder = new StringBuilder();
builder.append( /* stuff goes here*/ );

httpGet.setEntity(new UrlEncodedFormEntity(nameValuePairs));
ResponseHandler<String> responseHandler = new BasicResponseHandler();

// Execute HTTP Post Request. Response body returned as a string
HttpClient httpClient = MyActivity.getHttpClient();
HttpGet httpGet = new HttpGet(builder.toString());

String jsonResponse = httpClient.execute(httpGet, responseHandler); //Line causing the Exception

Мой код для MyActivity.getHttpClient():

protected synchronized static HttpClient getHttpClient(){
    if (httpClient != null)
        return httpClient;

    HttpParams httpParameters = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(httpParameters, TIMEOUT_CONNECTION);
    HttpConnectionParams.setSoTimeout(httpParameters, TIMEOUT_SOCKET);
    HttpProtocolParams.setVersion(httpParameters, HttpVersion.HTTP_1_1);

    //Thread safe in case various AsyncTasks try to access it concurrently
    SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
    ClientConnectionManager cm = new ThreadSafeClientConnManager(httpParameters, schemeRegistry);

    httpClient = new DefaultHttpClient(cm, httpParameters);

    CookieStore cookieStore = httpClient.getCookieStore();
    HttpContext localContext = new BasicHttpContext();
    localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);

    return httpClient;
}

Любая помощь будет высоко оценена.

Edit

Также просто упомянуть, что у меня были другие проблемы с SSL с другим приложением, но добавление части SchemeRegistry исправлено для меня раньше.

Изменить 2

До сих пор я тестировал только на Android 3.1, но мне нужно, чтобы он работал на Android 2.2+ независимо. Я только что протестировал в браузере на вкладке Android (Android 3.1), и он жалуется на сертификат. Это нормально в моем браузере ПК, но не в браузере Android или в моем приложении.

Изменить 3

Оказывается, браузер iOS также жалуется на это. Я начинаю думать, что проблема с цепочкой сертификатов, описанная здесь (SSL-сертификат не доверяет - только на мобильных устройствах)

4b9b3361

Ответ 1

Оказывается, мой код был в порядке, и проблема заключалась в том, что сервер не возвращал полную цепочку сертификатов. Для получения дополнительной информации см. Этот пост SO и этот пост суперпользователя:

Сертификат SSL не поддерживается - только на мобильных устройствах

https://superuser.com/questions/347588/how-do-ssl-chains-work

Ответ 2

Попробуйте ввести код: -

        BasicHttpResponse httpResponse = null;

        HttpPost httppost = new HttpPost(URL);

        HttpParams httpParameters = new BasicHttpParams();
        // Set the timeout in milliseconds until a connection is
        // established.
        int timeoutConnection = ConstantLib.CONNECTION_TIMEOUT;
        HttpConnectionParams.setConnectionTimeout(httpParameters,
                timeoutConnection);
        // Set the default socket timeout (SO_TIMEOUT)
        // in milliseconds which is the timeout for waiting for data.
        int timeoutSocket = ConstantLib.CONNECTION_TIMEOUT;
        HttpConnectionParams
                .setSoTimeout(httpParameters, timeoutSocket);

        DefaultHttpClient httpClient = new DefaultHttpClient(
                httpParameters);
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
        nameValuePairs.add(new BasicNameValuePair(ConstantLib.locale,
                locale));

Ответ 3

В моем случае все работало нормально. Внезапно через 2 дня у моего устройства не было никаких ссылок на сайт https или ссылки на изображение.

После некоторого расследования выясняется, что настройки My time не были обновлены на устройстве.

Я правильно изменил настройки времени и работал.

Ответ 4

У меня было это исключение, когда я использовал самоподписанный сертификат + ip-адрес. Просто добавьте эти строки

HostnameVerifier allHostsValid = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);

и ваше HttpURLConnection будет работать. Этот трюк не связан с проверкой CA! Поэтому, если я укажу неправильный CA и использую этот трюк, я получу другое исключение. Таким образом, хост остается доверенным

На всякий случай, я оставлю код для указания вашего собственного ЦС здесь:

String certStr = context.getString(R.string.caApi);
X509Certificate ca = SecurityHelper.readCert(certStr);

TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
ks.setCertificateEntry("caCert", ca);

tmf.init(ks);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

Не забудьте использовать классные функции buildTypes и поместить различные CA для отладки/выпуска в папке res.