如何将受信任的证书添加到OkHttp [英] How to ADD trusted certificate to OkHttp
问题描述
我需要使用OkHttp客户端信任一个特定站点的证书.我在这里找到了解决方案: https://jebware.com/blog/?p=340
此代码与我想信任的服务器配合使用.唯一的问题是,现在没有其他服务器可以信任了!:D所以显然不是很理想...
我只希望OkHttp保留其默认行为,并只需添加我自己的受信任证书即可.
当前行为::除了 myaccount.esbecars.com
预期的行为::OkHttp可以连接到默认情况下受信任的所有服务器(我不想不想盲目地信任所有服务器)包括 myaccount.esbecars.com
感谢您的建议!
我正在使用以下代码:
SSLContext sslContext;TrustManager [] trustManagers;尝试 {KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());keyStore.load(null,null);InputStream certInputStream = context.getAssets().open("esb_ireland.pem");BufferedInputStream bis =新的BufferedInputStream(certInputStream);CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");而(bis.available()> 0){证书cert = certificateFactory.generateCertificate(bis);keyStore.setCertificateEntry("myaccount.esbecars.com",cert);}TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());trustManagerFactory.init(keyStore);trustManagers = trustManagerFactory.getTrustManagers();sslContext = SSLContext.getInstance("TLS");sslContext.init(null,trustManagers,null);实例=新的OkHttpClient.Builder().cache(myCache).connectTimeout(FrontendConstants.NETWORK_CONNECT_TIMEOUT,TimeUnit.MILLISECONDS).readTimeout(FrontendConstants.NETWORK_READ_TIMEOUT,TimeUnit.MILLISECONDS).addInterceptor(new ObedientCacheInterceptor()).sslSocketFactory(sslContext.getSocketFactory(),(X509TrustManager)trustManagers [0]).建造();} catch(Exception e){e.printStackTrace();//TODO替换为适合您需求的实际异常处理}
尝试连接到除 myaccount.esbecars.com
以外的所有服务器时出现异常:
javax.net.ssl.SSLHandshakeException:java.security.cert.CertPathValidatorException:找不到证书路径的信任锚.在com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:361)在okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:336)在okhttp3.internal.connection.RealConnection.EstablishmentProtocol(RealConnection.java:300)在okhttp3.internal.connection.RealConnection.connect(RealConnection.java:185)在okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224)在okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.java:107)在okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.java:87)在okhttp3.internal.connection.Transmitter.newExchange(Transmitter.java:169)在okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:41)在okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)在okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)在okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)在okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)在okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)在okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)在okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)在okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)在okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)在okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)在com.sanctusmedia.android.WattsUp.network.OkHttpSingleton $ ObedientCacheInterceptor.intercept(OkHttpSingleton.java:121)在okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)在okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)在okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:221)在okhttp3.RealCall.execute(RealCall.java:81)
第一个选项是添加到本地密钥库文件中,该文件存储在JRE目录中.
但是我还使用了一个自定义的信任管理器,它可以合并证书 https://github.com/yschimke/okurl/blob/0520489d697d49b179010e468a87ef0749ff95be/src/main/kotlin/com/baulsupp/okurl/security/CertificateUtils.kt
程序包com.baulsupp.okurl.security导入java.security.cert.CertificateException导入java.security.cert.X509Certificate导入javax.net.ssl.X509TrustManager类MergedX509TrustManager(私有val管理器:List< X509TrustManager>):X509TrustManager {重写fun checkClientTrusted(链:Array< X509Certificate> ;, authType:字符串){抛出UnsupportedOperationException()}重写fun checkServerTrusted(链:Array< X509Certificate> ;, authType:字符串){val例外= mutableListOf< CertificateException>()为(经理人中的tm){尝试 {tm.checkServerTrusted(chain,authType)返回} catch(e:CertificateException){exceptions.add(e)}}抛出bestException(exceptions)}fun bestException(例外:List< CertificateException>):CertificateException {如果(exceptions.isNotEmpty()){//最后一个可能是系统密钥库抛出异常[exceptions.size-1]} 别的 {抛出CertificateException(没有X509TrustManager可以检查")}}重写fun getAcceptedIssuers():Array< X509Certificate>{val证书= mutableListOf< X509Certificate>()为(经理人中的tm){certificate.addAll(tm.acceptedIssuers.toList())}返回certificate.toTypedArray()}}
I need to trust certificate of one specific site using OkHttp client. I have found a solution here: https://jebware.com/blog/?p=340
This code works well with the server I wanted to trust. The only problem is that no other servers are now trusted! :D So obviously not very ideal...
I just want OkHttp to keep its default behaviour, and just add my own trusted certificate.
Current behaviour: OkHttp fails to connect to any server using HTTPS except of myaccount.esbecars.com
Expected behaviour: OkHttp can connect to all servers trusted by default (I do not want to blindly trust all the servers) including myaccount.esbecars.com
I will be thankful for your advice!
I am using this code:
SSLContext sslContext;
TrustManager[] trustManagers;
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
InputStream certInputStream = context.getAssets().open("esb_ireland.pem");
BufferedInputStream bis = new BufferedInputStream(certInputStream);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
Certificate cert = certificateFactory.generateCertificate(bis);
keyStore.setCertificateEntry("myaccount.esbecars.com", cert);
}
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
trustManagers = trustManagerFactory.getTrustManagers();
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, null);
instance = new OkHttpClient.Builder()
.cache(myCache)
.connectTimeout(FrontendConstants.NETWORK_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(FrontendConstants.NETWORK_READ_TIMEOUT, TimeUnit.MILLISECONDS)
.addInterceptor(new ObedientCacheInterceptor())
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagers[0])
.build();
} catch (Exception e) {
e.printStackTrace(); //TODO replace with real exception handling tailored to your needs
}
Exception I am getting when trying to connect to all the servers except of myaccount.esbecars.com
:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:361)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:336)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:300)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:185)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224)
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.java:107)
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.java:87)
at okhttp3.internal.connection.Transmitter.newExchange(Transmitter.java:169)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:41)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at com.sanctusmedia.android.WattsUp.network.OkHttpSingleton$ObedientCacheInterceptor.intercept(OkHttpSingleton.java:121)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:221)
at okhttp3.RealCall.execute(RealCall.java:81)
The first option is to add to the local keystore file, stored in the JRE directory.
But I've also used a custom trust manager that merges certificates https://github.com/yschimke/okurl/blob/07e79795e14b9163bcf4342f39c23020f51ecf64/src/main/kotlin/com/baulsupp/okurl/security/MergedX509TrustManager.kt
package com.baulsupp.okurl.security
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.X509TrustManager
class MergedX509TrustManager(private val managers: List<X509TrustManager>) : X509TrustManager {
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
throw UnsupportedOperationException()
}
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
val exceptions = mutableListOf<CertificateException>()
for (tm in managers) {
try {
tm.checkServerTrusted(chain, authType)
return
} catch (e: CertificateException) {
exceptions.add(e)
}
}
throw bestException(exceptions)
}
fun bestException(exceptions: List<CertificateException>): CertificateException {
if (exceptions.isNotEmpty()) {
// last is probably system keystore
throw exceptions[exceptions.size - 1]
} else {
throw CertificateException("no X509TrustManager to check")
}
}
override fun getAcceptedIssuers(): Array<X509Certificate> {
val certificates = mutableListOf<X509Certificate>()
for (tm in managers) {
certificates.addAll(tm.acceptedIssuers.toList())
}
return certificates.toTypedArray()
}
}
这篇关于如何将受信任的证书添加到OkHttp的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!