Привязка доверия не найдена для Android SSL-соединения - PullRequest
147 голосов
/ 26 июля 2011

Я пытаюсь подключиться к блоку IIS6, на котором запущен годовой 256-битный SSL-сертификат, и я получаю сообщение об ошибке:

java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

Пытаюсь определить, что может быть причиной этого, но сейчас рисует пробелы.

Вот как я подключаюсь:

HttpsURLConnection conn;              
conn = (HttpsURLConnection) (new URL(mURL)).openConnection();
conn.setConnectTimeout(20000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.connect();
String tempString = toString(conn.getInputStream()); 

Ответы [ 14 ]

191 голосов
/ 30 апреля 2013

Вопреки принятому ответу вам не нужен специальный менеджер доверия, вам нужно исправить конфигурацию вашего сервера!

Я столкнулся с той же проблемой при подключениина сервер Apache с неправильно установленным сертификатом dynadot / alphassl.Я подключаюсь с помощью HttpsUrlConnection (Java / Android), который выдавал -

javax.net.ssl.SSLHandshakeException: 
  java.security.cert.CertPathValidatorException: 
    Trust anchor for certification path not found.

Фактическая проблема - неверная конфигурация сервера - протестируйте его с http://www.digicert.com/help/ или подобным, и он даже скажетвам решение:

"Сертификат не подписан доверенным органом (проверка по отношению к корневому хранилищу Mozilla). Если вы купили сертификат в доверенном органе, вам, вероятно, просто нужно установитьодин или несколько промежуточных сертификатов . Обратитесь к поставщику сертификатов за помощью, выполнив это для вашей серверной платформы. "

Вы также можете проверить сертификат с помощью openssl:

openssl s_client -debug -connect www.thedomaintocheck.com:443

Вы, вероятно, увидите:

Verify return code: 21 (unable to verify the first certificate)

, а ранее в выводе:

depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=21:unable to verify the first certificate`

Цепочка сертификатов будет содержать только 1элемент (ваш сертификат):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
  i:/O=AlphaSSL/CN=AlphaSSL CA - G2

... но должен ссылаться на подписывающие органы в цепочке обратно на тот, которому доверяет Android (Verisign, GlobalSign и т. д.):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
   i:/O=AlphaSSL/CN=AlphaSSL CA - G2
 1 s:/O=AlphaSSL/CN=AlphaSSL CA - G2
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
 2 s:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA

IИнструкции (и промежуточные сертификаты) для настройки вашего сервера обычно предоставляются органом, выпустившим ваш сертификат, например: http://www.alphassl.com/support/install-root-certificate.html

После установки промежуточных сертификатов, предоставленных моим издателем сертификатов, у меня теперь нет ошибок, когдаподключение с использованием HttpsUrlConnection.

64 голосов
/ 21 октября 2011

Решение @Chrispix опасно! Доверие ко всем сертификатам позволяет кому-либо сделать человека в середине атаки! Просто отправьте ЛЮБОЙ сертификат клиенту, и он примет его!

Добавьте свой сертификат (ы) в пользовательский менеджер довериякак описано в этом посте: Доверие всем сертификатам с использованием HttpClient через HTTPS

Хотя установить безопасное соединение с настраиваемым сертификатом немного сложнее, оно принесет вам требуемое шифрование sslбезопасность без опасности человека в середине атаки!

16 голосов
/ 06 октября 2016

Вы можете доверять конкретному сертификату во время выполнения.Просто скачайте его с сервера, вставьте ресурсы и загрузите таким образом, используя ssl-utils-android :

OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());

В приведенном выше примере я использовал OkHttpClient, но SSLContext может бытьиспользуется с любым клиентом в Java.

Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать.Я автор этой маленькой библиотеки.

11 голосов
/ 16 марта 2017

Обновление на основе последней документации по Android (март 2017 года):

Когда вы получаете этот тип ошибки:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
        at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:374)
        at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
        at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
        at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
        at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
        at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
        at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
        at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
        at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)

, проблема может быть одной изследующее:

  1. ЦС, выдавший сертификат сервера, был неизвестен
  2. Сертификат сервера не был подписан ЦС, но был самоподписан
  3. Конфигурация сервераотсутствует промежуточный CA

Решение состоит в том, чтобы научить HttpsURLConnection доверять определенному набору CA.Как?Пожалуйста, отметьте https://developer.android.com/training/articles/security-ssl.html#CommonProblems

Другие, которые используют AsyncHTTPClient из com.loopj.android:android-async-http библиотеки, проверьте Настройте AsyncHttpClient для использования HTTPS .

7 голосов
/ 16 марта 2018

Отвечая на очень старый пост.Но, может быть, это поможет новичку, и если ничего из вышеперечисленного не сработает.

Объяснение: Я знаю, что никто не хочет дерьма с объяснениями;скорее решение.Но в одном случае вы пытаетесь получить доступ к услуге с локального компьютера на удаленный компьютер, который не доверяет вашему компьютеру.Вы запрашиваете необходимость получить доверие от удаленного сервера.

Решение: Следующее решение предполагает выполнение следующих условий

  1. Попытка получить доступ к удаленному API с локального компьютера.
  2. Вы создаете приложение для Android
  3. Ваш удаленный сервер находится в режиме фильтрации прокси (вы используете прокси-сервер в настройках браузера для доступа к удаленной службе API, обычно к промежуточному серверу или серверу разработки)
  4. Вы находитесьтестирование на реальном устройстве

Шаги:

Вам необходим файл расширения .keystore для регистрации вашего приложения.Если вы не знаете, как создать файл .keystore;затем следуйте вместе со следующим разделом. Создайте файл .keystore или перейдите к следующему разделу Sign Apk File

Создайте файл .keystore

Откройте Android Studio.Нажмите верхнее меню Build> Generate Signed APK.В следующем окне нажмите кнопку Создать новый ... .В новом окне, пожалуйста, введите данные во все поля.Помните, что поле «Пароль», которое я рекомендую, должно иметь одинаковый пароль;не используйте другой пароль;а также запомните путь сохранения в самом верхнем поле Путь хранилища ключей: .После ввода всех полей нажмите кнопку ОК.

Подписать файл Apk

Теперь вам нужно создать подписанное приложение с файлом .keystore, который вы только что создали.Выполните следующие действия

  1. Build> Clean Project, дождитесь окончания очистки
  2. Build> Generated Signed APK
  3. Нажмите кнопку Choose existing...
  4. Выберите файл .keystore, который мы только что создали, в Создать файл .keystore , раздел
  5. Введите тот же пароль, который вы создали при создании в Создать .keystore файл .Используйте один и тот же пароль для полей Key store password и Key password.Также введите псевдоним
  6. Нажмите кнопку Далее
  7. На следующем экране;которые могут отличаться в зависимости от ваших настроек в build.gradle файлах, вам нужно выбрать Build Types и Flavors.
  8. . Для Build Types выбрать release из выпадающего списка
  9. Для Flavors однако это будет зависеть от ваших настроек в файле build.gradle.Выберите staging из этого поля.Я использовал следующие настройки в build.gradle, вы можете использовать то же самое, что и у меня, но убедитесь, что вы изменили applicationId на ваше имя пакета

    productFlavors {
        staging {
            applicationId "com.yourapplication.package"
            manifestPlaceholders = [icon: "@drawable/ic_launcher"]
            buildConfigField "boolean", "CATALYST_DEBUG", "true"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "true"
        }
        production {
            buildConfigField "boolean", "CATALYST_DEBUG", "false"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "false"
        }
    }
    
  10. Нажмите внизудва Signature Versions флажка и нажмите кнопку Finish.

Почти там:

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

Настройка прокси в устройстве Android:

  1. Нажмите Настройка в телефоне Android и затем wi-fi
  2. Длительное нажатие на подключенном Wi-Fiи выберите Modify network
  3. Нажмите Advanced options, если вы не видите поле Proxy Hostname
  4. . В Proxy Hostname введите IP-адрес хоста или имя, которое вы хотите подключить.Типичный промежуточный сервер будет называться stg.api.mygoodcompany.com
  5. . Для порта введите четырехзначный номер порта, например 9502
  6. Нажмите кнопку Save

Одна последняя остановка:

Помните, что мы создали подписанный файл apk в Sign APK File section.Настало время установить этот файл APK.

  1. Откройте терминал и перейдите в папку с подписанным файлом apk
  2. Подключите устройство Android к компьютеру
  3. Удалитьлюбой предыдущий установленный файл apk с устройства Android
  4. Запуск adb install name of the apk file
  5. Если по какой-либо причине указанная выше команда возвращается с adb command not found. Введите полный путь как C:\Users\shah\AppData\Local\Android\sdk\platform-tools\adb.exe install name of the apk file

Я надеюсь, что проблема может быть решена. Если нет, пожалуйста, оставьте мне комментарий.

Салам!

4 голосов
/ 01 января 2019

Если вы используете модернизацию, вам нужно настроить ваш OkHttpClient.

retrofit = new Retrofit.Builder()
                        .baseUrl(ApplicationData.FINAL_URL)
                        .client(getUnsafeOkHttpClient().build())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

Полный код указан ниже.

    public class RestAdapter {

    private static Retrofit retrofit = null;
    private static ApiInterface apiInterface;

    public static OkHttpClient.Builder getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            return builder;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static ApiInterface getApiClient() {
        if (apiInterface == null) {

            try {
                retrofit = new Retrofit.Builder()
                        .baseUrl(ApplicationData.FINAL_URL)
                        .client(getUnsafeOkHttpClient().build())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

            } catch (Exception e) {

                e.printStackTrace();
            }


            apiInterface = retrofit.create(ApiInterface.class);
        }
        return apiInterface;
    }

}
4 голосов
/ 28 июня 2013

Сообщение об ошибке, которое я получал, было схожим, но причина в том, что срок действия самозаверяющего сертификата истек. Когда была предпринята попытка клиента openssl, он дал мне причину, которая была упущена из виду при проверке диалогового окна сертификата из firefox.

Таким образом, в общем случае, если сертификат находится в хранилище ключей и имеет значение «VALID», эта ошибка исчезнет.

3 голосов
/ 11 октября 2017

У меня была такая же проблема при подключении с Android-клиента к серверу Kurento.Сервер Kurento использует jks-сертификаты, поэтому мне пришлось конвертировать в него pem.В качестве входных данных для преобразования я использовал файл cert.pem, и это привело к таким ошибкам.Но если использовать fullchain.pem вместо cert.pem - все в порядке.

2 голосов
/ 04 декабря 2018

Я знаю, что вам не нужно доверять всем сертификатам, но в моем случае у меня были проблемы с некоторыми средами отладки, где у нас были самозаверяющие сертификаты, и мне требовалось грязное решение.

Все, что мне нужно было сделать, это изменить инициализацию sslContext

mySSLContext.init(null, trustAllCerts, null); 

где trustAllCerts было создано так:

private final TrustManager[] trustAllCerts= new TrustManager[] { new X509TrustManager() {
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[]{};
    }

    public void checkClientTrusted(X509Certificate[] chain,
                                   String authType) throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] chain,
                                   String authType) throws CertificateException {
    }
} };

Надеюсь, что это пригодится.

2 голосов
/ 12 августа 2015

У меня была та же проблема, что я обнаружил в том, что в предоставленном мною файле .crt отсутствовал промежуточный сертификат.Поэтому я спросил все файлы .crt у администратора сервера, а затем объединил их в обратном порядке.

Пример.1. Root.crt 2. Inter.crt 3. myCrt.crt

в windows я выполнил копию Inter.crt + Root.crt newCertificate.crt

(Здесь я проигнорировал myCrt.crt)

Затем я предоставил файл newCertificate.crt в код через inputtream.Работа сделана.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...