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

CertPathValidatorException: привязка доверия для пути сертификата не найдена - обновите Android

Я создаю приложение для Android, которое использует https для связи с сервером. Я использую retrofit и OkHttp для запросов. Они отлично работают для стандартных запросов http. Ниже приведены шаги, которые я выполнил.

Шаг 1: Приобрел файл сертификата с сервера с помощью команды

echo -n | openssl s_client -connect api.****.tk:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > gtux.cert

Шаг 2: Преобразовал сертификат в формат BKS с помощью следующих команд

keytool -importcert -v -trustcacerts -file "gtux.cert" -alias imeto_alias -keystore "my_keystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-146.jar" -storetype BKS

Он запросил у меня пароль и файл был успешно создан.

Шаг 3:

Создайте OkHttpClient и используйте его для создания запросов https

public class MySSLTrust {
public static OkHttpClient trustcert(Context context){
    OkHttpClient okHttpClient = new OkHttpClient();
    try {
        KeyStore ksTrust = KeyStore.getInstance("BKS");
        InputStream instream = context.getResources().openRawResource(R.raw.my_keystore);
        ksTrust.load(instream, "secret".toCharArray());
        // TrustManager decides which certificate authorities to use.
        TrustManagerFactory tmf = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ksTrust);
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);
        okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
    } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | KeyManagementException e) {
        e.printStackTrace();
    }
    return okHttpClient;
}
}

Шаг 4:

Необходимо создать RestAdapter

RestAdapter.Builder()
.setRequestInterceptor(intercept)
.setEndpoint("https://api.****.tk")
.setClient(new OkClient(this))
.setLogLevel(RestAdapter.LogLevel.FULL)
.setLog(new AndroidLog("RETROFIT"))
.build();

Но, наконец, при запуске приложения он бросает меня CertPathValidatorException : Trust anchor for certificate path not found. Пожалуйста, помогите мне решить эту проблему. Спасибо.

Другие попытки отказа: Попробовал установить сертификат в моем Xperia Z2, и он говорит, что файл был установлен, но когда я запускаю приложение, выдается одно и то же исключение.

Журнал ошибок Вот журнал ошибок, который я получил при выполнении...

Журнал ошибок

Вставить там, чтобы было легко читать..

4b9b3361

Ответ 1

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: этот ответ от июль 2015 и с этого времени использует "Дооснащение" и OkHttp.
> Проверьте эту ссылку для получения дополнительной информации о Retrofit v2 и этот для текущих методов OkHttp.

Хорошо, я начал работать, используя руководство для разработчиков Android.

Как и в OP, я пытаюсь использовать Retrofit и OkHttp для подключения к самоподписанному серверу с поддержкой SSL.

Вот код, в котором все работает (я удалил блоки try/catch):

public static RestAdapter createAdapter(Context context) {
  // loading CAs from an InputStream
  CertificateFactory cf = CertificateFactory.getInstance("X.509");
  InputStream cert = context.getResources().openRawResource(R.raw.my_cert);
  Certificate ca;
  try {
    ca = cf.generateCertificate(cert);
  } finally { cert.close(); }

  // creating a KeyStore containing our trusted CAs
  String keyStoreType = KeyStore.getDefaultType();
  KeyStore keyStore = KeyStore.getInstance(keyStoreType);
  keyStore.load(null, null);
  keyStore.setCertificateEntry("ca", ca);

  // creating a TrustManager that trusts the CAs in our KeyStore
  String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
  TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
  tmf.init(keyStore);

  // creating an SSLSocketFactory that uses our TrustManager
  SSLContext sslContext = SSLContext.getInstance("TLS");
  sslContext.init(null, tmf.getTrustManagers(), null);

  // creating an OkHttpClient that uses our SSLSocketFactory
  OkHttpClient okHttpClient = new OkHttpClient();
  okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());

  // creating a RestAdapter that uses this custom client
  return new RestAdapter.Builder()
              .setEndpoint(UrlRepository.API_BASE)
              .setClient(new OkClient(okHttpClient))
              .build();
}

Чтобы помочь в отладке, я также добавил .setLogLevel(RestAdapter.LogLevel.FULL) в мои команды создания RestAdapter, и я мог видеть, как он соединяется и получает ответ от сервера.

Все, что было, это мой оригинальный .crt файл, сохраненный в main/res/raw. Файл .crt, также известный как сертификат, является одним из двух файлов, созданных при создании сертификата с помощью openssl. Как правило, это файл .crt или .cert, а другой - файл .key.

Afaik, файл .crt - это ваш открытый ключ, а файл .key - это ваш закрытый ключ.

Как я вижу, у вас уже есть файл .cert, который является тем же самым, поэтому попробуйте его использовать.


PS: Для тех, кто читает его в будущем и имеет только .pem файл, в соответствии с этот ответ, вам нужно только это, чтобы преобразовать один в другой:

openssl x509 -outform der -in your-cert.pem -out your-cert.crt

PS²: Для тех, у кого вообще нет файла, вы можете использовать следующую команду (bash) для извлечения открытого ключа (aka сертификата) с любого сервера:

echo -n | openssl s_client -connect your.server.com:443 | \
  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/my_cert.crt

Просто замените your.server.com и порт (если он не является стандартным HTTPS) и выберите допустимый путь для создаваемого файла вывода.

Ответ 2

 Use the below code to solve the CertPathValidatorException issue.


 Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(YOUR_BASE_URL)
        .client(getUnsafeOkHttpClient().build())
        .build();


  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);
    }
}

Для получения более подробной информации посетите https://mobikul.com/android-retrofit-handling-sslhandshakeexception/

Ответ 3

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

  • Получите сертификат с нашего сайта, как в вопросе Gowtham, и поместите его в res/raw dir проекта:

    echo -n | openssl s_client -connect elkews.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ./res/raw/elkews_cert.crt
    
  • Используйте Paulo answer, чтобы установить ssl factory (в настоящее время используется OkHttpClient.Builder()), но без RestAdapter.

  • Затем добавьте следующее решение для исправления: SSLPeerUnverifiedException: Имя хоста не проверено

Итак, конец кода Пауло (после инициализации sslContext), который работает для меня, выглядит следующим образом:

...
OkHttpClient.Builder builder = new OkHttpClient.Builder().sslSocketFactory(sslContext.getSocketFactory());
builder.hostnameVerifier(new HostnameVerifier() {
  @Override
  public boolean verify(String hostname, SSLSession session) {
    return "secure.elkews.com".equalsIgnoreCase(hostname);
});
OkHttpClient okHttpClient = builder.build();

Ответ 4

Модернизация 2.3.0

    // Load CAs from an InputStream
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

    InputStream inputStream = context.getResources().openRawResource(R.raw.ssl_certificate); //(.crt)
    Certificate certificate = certificateFactory.generateCertificate(inputStream);
    inputStream.close();

    // Create a KeyStore containing our trusted CAs
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", certificate);

    // Create a TrustManager that trusts the CAs in our KeyStore.
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm);
    trustManagerFactory.init(keyStore);

    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
    X509TrustManager x509TrustManager = (X509TrustManager) trustManagers[0];


    // Create an SSLSocketFactory that uses our TrustManager
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, new TrustManager[]{x509TrustManager}, null);
    sslSocketFactory = sslContext.getSocketFactory();

    //create Okhttp client
    OkHttpClient client = new OkHttpClient.Builder()
                .sslSocketFactory(sslSocketFactory,x509TrustManager)
                .build();

    Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(url)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(client)
                    .build();

Ответ 5

Вы конвертируете cert в BKS Keystore, почему вы не используете .cert напрямую, из https://developer.android.com/training/articles/security-ssl.html:

CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream instream = context.getResources().openRawResource(R.raw.gtux_cert);
Certificate ca;
try {
    ca = cf.generateCertificate(instream);
} finally {
    caInput.close();
}

KeyStore kStore = KeyStore.getInstance(KeyStore.getDefaultType());
kStore.load(null, null);
kStore.setCertificateEntry("ca", ca);

TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm(););
tmf.init(kStore);

SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);

okHttpClient.setSslSocketFactory(context.getSocketFactory());

Ответ 6

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

 // creating a KeyStore containing our trusted CAs
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);

    // creating a TrustManager that trusts the CAs in our KeyStore
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    // creating an SSLSocketFactory that uses our TrustManager
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tmf.getTrustManagers(), null);
    okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
    // creating a RestAdapter using the custom client
    return new RestAdapter.Builder()
            .setEndpoint(UrlRepository.API_BASE)
            .setClient(new OkClient(okHttpClient))
            .build();

Ответ 7

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

Как получить хеш-контакт для сертификата?

Изначально используйте неправильный вывод хэша, и ваш класс java будет вызывать ошибку с правильными выводами хэша или цепочкой контактов, просто скопируйте и вставьте в свой код.

Это решение устранило мою проблему: fooobar.com/questions/117795/...

Ответ 8

Реализация в Котлине: дооснащение 2.3.0

private fun getUnsafeOkHttpClient(mContext: Context) : 
OkHttpClient.Builder? {


var mCertificateFactory : CertificateFactory = 
CertificateFactory.getInstance("X.509")
var mInputStream = mContext.resources.openRawResource(R.raw.cert)
            var mCertificate : Certificate = mCertificateFactory.generateCertificate(mInputStream)
        mInputStream.close()
val mKeyStoreType = KeyStore.getDefaultType()
val mKeyStore = KeyStore.getInstance(mKeyStoreType)
mKeyStore.load(null, null)
mKeyStore.setCertificateEntry("ca", mCertificate)

val mTmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm()
val mTrustManagerFactory = TrustManagerFactory.getInstance(mTmfAlgorithm)
mTrustManagerFactory.init(mKeyStore)

val mTrustManagers = mTrustManagerFactory.trustManagers

val mSslContext = SSLContext.getInstance("SSL")
mSslContext.init(null, mTrustManagers, null)
val mSslSocketFactory = mSslContext.socketFactory

val builder = OkHttpClient.Builder()
builder.sslSocketFactory(mSslSocketFactory, mTrustManagers[0] as X509TrustManager)
builder.hostnameVerifier { _, _ -> true }
return builder

}

Ответ 9

Вот версия Kotlin.
Спасибо тебе :)

         fun unSafeOkHttpClient() :OkHttpClient.Builder {
            val okHttpClient = OkHttpClient.Builder()
            try {
                // Create a trust manager that does not validate certificate chains
                val trustAllCerts:  Array<TrustManager> = arrayOf(object : X509TrustManager {
                    override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?){}
                    override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {}
                    override fun getAcceptedIssuers(): Array<X509Certificate>  = arrayOf()
                })

                // Install the all-trusting trust manager
                val  sslContext = SSLContext.getInstance("SSL")
                sslContext.init(null, trustAllCerts, SecureRandom())

                // Create an ssl socket factory with our all-trusting manager
                val sslSocketFactory = sslContext.socketFactory
                if (trustAllCerts.isNotEmpty() &&  trustAllCerts.first() is X509TrustManager) {
                    okHttpClient.sslSocketFactory(sslSocketFactory, trustAllCerts.first() as X509TrustManager)
                    okHttpClient.hostnameVerifier { _, _ -> true }
                }

                return okHttpClient
            } catch (e: Exception) {
                return okHttpClient
            }
        }