Доверять / белый список сертификата в OkHttp (не найден доверенный якорь для пути сертификации)
У меня проблема с устройствами Android 4, которые получают следующее исключение при подключении к серверу:
java.security.cert.CertPathValidatorException: доверенная привязка для пути сертификации не найдена. по адресу com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:410) по адресу okhttp3.internal.connection.RealConnection.connectTls(SourceFile:319) по адресу okhttp3.internal.connection.RealConnection (присоединение к источнику) okhttp3.internal.connection.RealConnection.connect(SourceFile:168) по адресу okhttp3.internal.connection.StreamAllocation.findConnection(SourceFile:257) по адресу okhttp3.internal.connection.StreamAllocation.findHealthyConnection(источник: 135. точка доступа:135).StreamAllocation.newStream(SourceFile:114) в файле okhttp3.internal.connection.ConnectInterceptor.intercept(SourceFile:42) в файле okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:147) в файле okhttp3.internal.http.Rex. SourceFile:121) по адресу okhttp3.internal.cache.CacheInterceptor.intercept(SourceFile:93) по адресу okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:147) по адресу okhttp3.internal.http.RealInterceptorChain.proceed) в источнике (okhttp3.internal.http. BridgeInterceptor.intercept (SourceFile: 93) в файле okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:147) в файле okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(SourceFile:126) в файле okhttp3.inha.Interh.: 147) в okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:121) в okhttp3.RealCall.getResponseWithInterceptorChain(SourceFile:254) в okhttp3.RealCall.execute(SourceFile:92)
Сертификат сервера от Cloudflare, я проверил его с помощью нескольких инструментов, таких как https://www.digicert.com/help/ и, похоже, все в порядке.
Но по некоторым причинам я не понимаю, что это начало терпеть неудачу в версиях Android 4.
Пробовал решение доверять всем сертификатам [ССЫЛКА], и это работает, но это, очевидно, имеет проблемы с безопасностью, такие как подвергание вашего приложения атаке "человек посередине"
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[]{};
}
}
};
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
okHttpBuilder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
Как я могу реализовать TrustManager с поведением по умолчанию, но в белый список входит только сертификат сервера.
Спасибо
Изменить: следуя примеру в OkHttp @ CustomTrust (спасибо CommonsWare)
Использовал команду:
openssl s_client -showcerts -servername www.serverdomain.com -connect www.serverdomain.com:443
В цепочке сертификатов дали мне два сертификата в формате:
-----BEGIN CERTIFICATE-----
....
-----END CERTIFICATE-----
Заменили URL и сертификаты в примере на полученные, но он все еще не работает, есть идеи?
1 ответ
Вам нужно сохранить ваш сертификат в сырой папке, а затем:
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());
Больше информации здесь: Безопасность SSL