未找到 Android SSL 连接的信任锚
Posted
技术标签:
【中文标题】未找到 Android SSL 连接的信任锚【英文标题】:Trust Anchor not found for Android SSL Connection 【发布时间】:2011-10-13 02:31:00 【问题描述】:我正在尝试连接到运行 Godaddy 256 位 SSL 证书的 IIS6 机器,但出现错误:
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());
【问题讨论】:
【参考方案1】:Relpcae 你的客户喜欢下面 var httpClient = new HttpClient(new System.Net.Http.HttpClientHandler());
把 https 改成 http
【讨论】:
【参考方案2】:我使用这些方法,其中一种在上述解决方案中对我有用: 第一:
public okhttp3.OkHttpClient 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();
okhttp3.OkHttpClient.Builder builder = new
okhttp3.OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory,
(X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier()
@Override
public boolean verify(String hostname, SSLSession
session)
return true;
);
okhttp3.OkHttpClient okHttpClient = builder.build();
return okHttpClient;
catch (Exception e)
throw new RuntimeException(e);
第二:
@SuppressLint("TrulyRandom")
public static void handleSSLHandshake()
try
TrustManager[] trustAllCerts = new TrustManager[]new
X509TrustManager()
public X509Certificate[] getAcceptedIssuers()
return new X509Certificate[0];
@Override
public void checkClientTrusted(X509Certificate[]
certs, String authType)
@Override
public void checkServerTrusted(X509Certificate[]
certs, String authType)
;
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new
HostnameVerifier()
@Override
public boolean verify(String arg0, SSLSession arg1)
return true;
);
catch (Exception ignored)
和: 把这个库放到你的类路径中:
implementation 'com.squareup.okhttp:okhttp:2.3.0'
implementation 'com.squareup.okhttp:okhttp-urlconnection:2.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-
core:3.3.0'
确保你在课堂上给他们打电话
【讨论】:
【参考方案3】:如果你使用改造,你需要自定义你的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;
【讨论】:
我正在尝试使用代码,但我再次收到以下错误。“javax.net.ssl.SSLHandshakeException:java.security.cert.CertPathValidatorException:找不到证书路径的信任锚。”你能帮忙吗 这是非常不安全的。不要使用。 谢谢!在 Kotlin 中重写了getUnsafeOkHttpClient()
方法:***.com/a/60507560/2914140。【参考方案4】:
在我的情况下,根证书和中间证书已成功安装,但我仍然收到“未找到证书路径的信任锚”。例外!。在挖掘android document 之后,发现默认情况下,来自所有应用程序的安全连接(使用 TLS 和 HTTPS 等协议)信任预安装的系统 CA,以及针对 Android 6.0(API 级别 23)及更低版本的应用程序默认信任用户添加的 CA 存储。如果您的应用在 api 级别高于 23 的操作系统上运行,您应该明确允许应用信任用户添加的 CA,方法是将其地址添加到 network_security_config,如下所示:
<domain-config>
<domain includeSubdomains="true">PUT_YOUR_SERVER_ADDERESS</domain>
<trust-anchors>
<certificates src="user" />
</trust-anchors>
</domain-config>
【讨论】:
【参考方案5】:我通过改变解决了我的问题
https://example.com/
到
http://example.com/
因为服务器没有 SSL 证书。
所以,请检查您的服务器的 url 并相应地更改
【讨论】:
【参考方案6】:使用https://www.ssllabs.com/ssltest/ 测试域。
Shihab Uddin 在 Kotlin 中的解决方案。
import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.*
import javax.security.cert.CertificateException
object
val okHttpClient: OkHttpClient
val gson: Gson
val retrofit: Retrofit
init
okHttpClient = getOkHttpBuilder()
// Other parameters like connectTimeout(15, TimeUnit.SECONDS)
.build()
gson = GsonBuilder().setLenient().create()
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
fun getOkHttpBuilder(): OkHttpClient.Builder =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
OkHttpClient().newBuilder()
else
// Workaround for the error "Caused by: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate: Certificate expired at".
getUnsafeOkHttpClient()
private fun getUnsafeOkHttpClient(): OkHttpClient.Builder =
try
// Create a trust manager that does not validate certificate chains
val trustAllCerts: Array<TrustManager> = arrayOf(
object : X509TrustManager
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<X509Certificate?>?,
authType: String?) = Unit
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<X509Certificate?>?,
authType: String?) = Unit
override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
)
// Install the all-trusting trust manager
val sslContext: SSLContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, SecureRandom())
// Create an ssl socket factory with our all-trusting manager
val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory
val builder = OkHttpClient.Builder()
builder.sslSocketFactory(sslSocketFactory,
trustAllCerts[0] as X509TrustManager)
builder.hostnameVerifier _, _ -> true
builder
catch (e: Exception)
throw RuntimeException(e)
如果您使用Glide
,也会出现同样的错误,图像不会显示。要克服它,请参阅 Glide - javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found 和 How to set OkHttpClient for glide。
@GlideModule
class MyAppGlideModule : AppGlideModule()
val okHttpClient = Api.getOkHttpBuilder().build() // Api is the class written above.
// It is better to create okHttpClient here and not use Api.okHttpClient,
// because their settings may differ. For instance, it can use its own
// `addInterceptor` and `addNetworkInterceptor` that can affect on a read JSON.
override fun registerComponents(context: Context, glide: Glide, registry: Registry)
registry.replace(GlideUrl::class.java, InputStream::class.java,
OkHttpUrlLoader.Factory(okHttpClient))
build.gradle:
// Glide.
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'
更新
我在 API 16 模拟器上也遇到了另一个错误:
routines:SSL23_GET_SERVER_HELLO:tlsv1 警报协议版本 (外部/openssl/ssl/s23_clnt.c:741'.
阅读1 和2,我更改了代码:
okHttpClient = getOkHttpBuilder().build()
private fun getOkHttpBuilder(): OkHttpClient.Builder
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
Security.insertProviderAt(Conscrypt.newProvider(), 1)
return OkHttpClient().newBuilder()
// build.gradle:
implementation 'org.conscrypt:conscrypt-android:2.5.1'
我还从MyApplication
中删除了这些行:
try
ProviderInstaller.installIfNeeded(applicationContext)
val sslContext = SSLContext.getInstance("TLSv1.2")
sslContext.init(null, null, null)
sslContext.createSSLEngine()
catch (e: GooglePlayServicesRepairableException)
Timber.e(e.stackTraceToString())
// Prompt the user to install/update/enable Google Play services.
GoogleApiAvailability.getInstance().showErrorNotification(this, e.connectionStatusCode)
catch (e: GooglePlayServicesNotAvailableException)
Timber.e(e.stackTraceToString())
// Prompt the user to install/update/enable Google Play services.
// GoogleApiAvailability.getInstance().showErrorNotification(this, e.errorCode)
catch (e: NoSuchAlgorithmException)
Timber.e(e.stackTraceToString())
catch (e: KeyManagementException)
Timber.e(e.stackTraceToString())
但是library 增加了 3.4 Mb 到 apk。
【讨论】:
非常感谢,这对我很有效。【参考方案7】:有时当管理员错误地设置证书时会发生这种情况 在此处查看网址 https://www.sslshopper.com/ssl-checker.html
就我而言,有一个错误
并非所有网络浏览器都信任该证书。您可能需要安装中间/链证书以将其链接到受信任的根证书。了解有关此错误的更多信息。您可以按照针对您的服务器平台的 GlobalSign 证书安装说明来解决此问题。注意中间证书部分。
【讨论】:
【参考方案8】:我知道这是一篇非常古老的文章,但我在尝试解决我的信任锚问题时遇到了这篇文章。我已经发布了我如何修复它。如果您已经预安装了根 CA,则需要向清单中添加配置。
https://***.com/a/60102517/114265
【讨论】:
仅适用于 API 24+ @BekaBot - 这可能是真的,但根据文档 23 及以下默认情况下信任用户证书默认情况下,来自所有应用程序的安全连接(使用 TLS 和 HTTPS 等协议)信任预安装的系统 CA 和面向 Android 6.0(API 级别 23)及更低版本的应用默认也信任用户添加的 CA 商店【参考方案9】:我也遇到过类似的问题,完全排除了信任所有来源的策略。
我在这里分享我应用于 Kotlin 实现的应用程序的解决方案
我首先建议使用the following website 来获取有关证书及其有效性的信息
如果它没有在 Android 默认信任库 中显示为 'Accepted Issuers',我们必须获取该证书并将其合并到应用程序中以创建自定义信任商店
就我而言,理想的解决方案是创建一个高级信任管理器,将自定义信任库和 Android 默认信任库结合起来
在这里,他公开了用于配置他与 Retrofit 一起使用的 OkHttpClient 的高级代码。
override fun onBuildHttpClient(httpClientBuild: OkHttpClient.Builder)
val trustManagerWrapper = createX509TrustManagerWrapper(
arrayOf(
getCustomX509TrustManager(),
getDefaultX509TrustManager()
)
)
printX509TrustManagerAcceptedIssuers(trustManagerWrapper)
val sslSocketFactory = createSocketFactory(trustManagerWrapper)
httpClientBuild.sslSocketFactory(sslSocketFactory, trustManagerWrapper)
通过这种方式,我可以使用自签名证书与服务器通信,并使用受信任的证书实体颁发的证书与其他服务器通信
就是这样,希望对大家有所帮助。
【讨论】:
【参考方案10】:回复非常老的帖子。但也许它会帮助一些新手,如果以上都没有解决的话。
解释:我知道没有人想要解释废话;而是解决方案。但是在一个班轮中,您正试图从本地机器访问服务到不信任您的机器的远程机器。您请求需要获得远程服务器的信任。
解决方案:以下解决方案假设您满足以下条件
-
尝试从您的本地计算机访问远程 API。
您正在为 Android 应用构建
您的远程服务器正在接受代理过滤(您在浏览器设置中使用代理来访问远程 api 服务,通常是暂存服务器或开发服务器)
您正在真实设备上进行测试
步骤:
您需要一个 .keystore 扩展文件来注册您的应用。如果您不知道如何创建 .keystore 文件;然后按照以下创建 .keystore 文件部分或跳到下一部分 签署 Apk 文件
创建 .keystore 文件
打开 Android Studio。点击顶部菜单 Build > Generate Signed APK。在下一个窗口中单击 新建... 按钮。在新窗口中,请在所有字段中输入数据。记住我推荐的两个密码字段应该有相同的密码;不要使用不同的密码;并记住最顶部字段 Key store path: 的保存路径。输入所有字段后单击确定按钮。
签署 Apk 文件
现在您需要使用刚刚创建的 .keystore 文件构建一个签名的应用程序。请按照以下步骤操作
-
构建 > 清理项目,等待清理完成
构建 > 生成签名的 APK
点击
Choose existing...
按钮
选择我们刚刚在创建 .keystore 文件部分中创建的 .keystore 文件
输入您在创建 .keystore 文件部分创建时创建的相同密码。对Key store password
和Key password
字段使用相同的密码。同时输入别名
点击下一步按钮
在下一个屏幕中;根据您在build.gradle
文件中的设置可能会有所不同,您需要选择Build Types
和Flavors
。
对于Build Types
,从下拉列表中选择release
对于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"
点击底部的两个Signature Versions
复选框并点击Finish
按钮。
快到了:
所有的努力都完成了,现在是真理的运动。为了访问代理备份的 Staging 服务器,您需要在实际测试的 Android 设备中进行一些设置。
Android 设备中的代理设置:
-
点击Android手机里面的设置,然后点击wifi
长按连接的wifi并选择
Modify network
如果看不到Proxy Hostname
字段,请单击Advanced options
在Proxy Hostname
中输入您要连接的主机IP 或名称。典型的登台服务器将命名为stg.api.mygoodcompany.com
对于端口,输入四位端口号,例如9502
点击Save
按钮
最后一站:
请记住,我们在 Sign APK File 部分生成了已签名的 apk 文件。现在是安装该 APK 文件的时候了。
-
打开终端,切换到已签名的apk文件夹
将您的 Android 设备连接到您的机器
从 Android 设备中删除任何以前安装的 apk 文件
运行
adb install
name of the apk file
如果由于某种原因上述命令返回adb command not found
。输入完整路径为C:\Users\shah\AppData\Local\Android\sdk\platform-tools\adb.exe
install
name of the apk file
我希望问题能得到解决。如果没有,请给我一个 cmets。
萨拉姆!
【讨论】:
【参考方案11】:我知道您不需要信任所有证书,但在我的情况下,我在一些调试环境中遇到了问题,我们有自签名证书,我需要一个肮脏的解决方案。
我所要做的就是改变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
;
希望这会派上用场。
【讨论】:
这就是我想找到的!谢谢 我收到错误Hostname '192.168.0.16' was not verified
。我正在通过我的调试器(IIS Express)在本地测试我的 webapi。知道如何解决这个问题吗?谢谢:)
这是非常不安全的。不要使用。【参考方案12】:
@Chrispix 的解决方案很危险! 信任所有证书允许任何人进行中间人攻击!只需将任何证书发送给客户端,它就会接受它!
将您的证书添加到自定义信任管理器中,如本文所述:Trusting all certificates using HttpClient over HTTPS
虽然用自定义证书建立安全连接有点复杂,但它会给你带来想要的 ssl 加密安全,没有中间人攻击的危险!
【讨论】:
这对于使用自行生成的证书来说是可以的,但对于具有返回根 CA 的有效链的人(如 OP)来说,它只是配置错误的服务器的一种解决方法 - 请参阅我的回答。 @Stevie 接受每个证书只是概念验证测试的一个选项,其中 SSL 连接不是您要测试的部分。否则,如果您接受每个证书,则不必使用 SSL,因为连接不安全! 啊,对不起,我认为这是一个误解——我完全同意没有人应该接受每一个证书! :) 我的评论是关于您的第二段 - 使用自定义信任管理器的建议 - 恕我直言,这应该是最后的解决方法,而不是推荐的解决方案。 提个醒。我删除了我粘贴的“解决方案”作为一种变通方法,以免引起更多问题,因为人们不认为它是一种“临时变通方法”。 @Chrispix,您不应该删除部分修复,它仅用于测试目的【参考方案13】:发生信任锚错误的原因有很多。对我来说,这只是我试图访问https://example.com/
而不是https://www.example.com/
。
因此,在开始构建自己的信任管理器之前,您可能需要仔细检查您的 URL(就像我所做的那样)。
【讨论】:
【参考方案14】:在我的情况下,这是在更新到 Android 8.0 之后发生的。 Android 设置为信任的自签名证书使用签名算法 SHA1withRSA。切换到新证书,使用签名算法 SHA256withRSA 解决了这个问题。
【讨论】:
【参考方案15】:我在从 Android 客户端连接到 Kurento 服务器时遇到了同样的问题。 Kurento 服务器使用 jks 证书,所以我不得不将 pem 转换为它。 作为转换的输入,我使用了 cert.pem 文件,它会导致此类错误。 但是如果使用 fullchain.pem 而不是 cert.pem - 一切正常。
【讨论】:
【参考方案16】:基于最新 Android 文档的更新(2017 年 3 月):
当您收到此类错误时:
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)
问题可能是以下之一:
-
颁发服务器证书的 CA 未知
服务器证书不是由 CA 签名的,而是自签名的
服务器配置缺少中间 CA
解决方案是教 HttpsURLConnection
信任一组特定的 CA。如何?请查看https://developer.android.com/training/articles/security-ssl.html#CommonProblems
其他使用来自com.loopj.android:android-async-http
库的AsyncHTTPClient
,请查看Setup AsyncHttpClient to use HTTPS。
【讨论】:
如果使用 okhttp 客户端呢? 对于 okhttp,请查看@mklimek 的答案。 我认为他的意思是 @klimat 的回答 - 这里:***.com/a/39883606/1617737【参考方案17】:您可以在运行时信任特定证书。 只需从服务器下载它,放入资产并使用 ssl-utils-android 像这样加载:
OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());
在上面的示例中,我使用了OkHttpClient
,但SSLContext
可以与Java 中的任何客户端一起使用。
如果您有任何问题,请随时提出。我是这个小图书馆的作者。
【讨论】:
.pfx 怎么样? 这不是不安全吗,因为任何用户一旦拥有 apk 就可以访问应用程序的资产文件夹? @PatriceAndala,根 CA 是公开的,所以没关系 谢谢,如果ssl每2个月更新一次,我们是否必须每2个月更换一次应用程序中的新cer文件?【参考方案18】:**Set proper alias name**
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509","BC");
X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(derInputStream);
String alias = cert.getSubjectX500Principal().getName();
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
trustStore.setCertificateEntry(alias, cert);
【讨论】:
【参考方案19】:我遇到了同样的问题,我发现我提供的证书 .crt 文件缺少中间证书。所以我从我的服务器管理员那里询问了所有 .crt 文件,然后以相反的顺序连接它们。
例如。 1.根.crt 2. Inter.crt 3.myCrt.crt
在我执行的窗口中 复制 Inter.crt + Root.crt newCertificate.crt
(这里我忽略了myCrt.crt)
然后我通过输入流将 newCertificate.crt 文件提供到代码中。 工作完成。
【讨论】:
我们也遇到了同样的问题。缺少中间证书【参考方案20】:在 Gingerbread 手机中,我总是收到此错误:Trust Anchor not found for Android SSL Connection
,即使我设置为依赖我的证书。
这是我使用的代码(Scala 语言):
object Security
private def createCtxSsl(ctx: Context) =
val cer =
val is = ctx.getAssets.open("mycertificate.crt")
try
CertificateFactory.getInstance("X.509").generateCertificate(is)
finally
is.close()
val key = KeyStore.getInstance(KeyStore.getDefaultType)
key.load(null, null)
key.setCertificateEntry("ca", cer)
val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
tmf.init(key)
val c = SSLContext.getInstance("TLS")
c.init(null, tmf.getTrustManagers, null)
c
def prepare(url: HttpURLConnection)(implicit ctx: Context)
url match
case https: HttpsURLConnection ⇒
val cSsl = ctxSsl match
case None ⇒
val res = createCtxSsl(ctx)
ctxSsl = Some(res)
res
case Some(c) ⇒ c
https.setSSLSocketFactory(cSsl.getSocketFactory)
case _ ⇒
def noSecurity(url: HttpURLConnection)
url match
case https: HttpsURLConnection ⇒
https.setHostnameVerifier(new HostnameVerifier
override def verify(hostname: String, session: SSLSession) = true
)
case _ ⇒
这是连接代码:
def connect(securize: HttpURLConnection ⇒ Unit)
val conn = url.openConnection().asInstanceOf[HttpURLConnection]
securize(conn)
conn.connect();
....
try
connect(Security.prepare)
catch
case ex: SSLHandshakeException /*if ex.getMessage != null && ex.getMessage.contains("Trust anchor for certification path not found")*/ ⇒
connect(Security.noSecurity)
基本上,我设置信任我的自定义证书。如果失败,那么我禁用安全性。这不是最好的选择,但我所知道的旧手机的唯一选择。
这个示例代码,可以很容易地翻译成Java。
【讨论】:
android 2.3.x 的解决方案,以防有人需要,***.com/a/46465722/7125370【参考方案21】:我收到的错误消息类似,但原因是自签名证书已过期。 当尝试使用 openssl 客户端时,它给出了我从 firefox 检查证书对话框时忽略的原因。
所以一般来说,如果证书在密钥库中并且它的“VALID”存在,这个错误就会消失。
【讨论】:
如果证书过期,那么根据许多标准,它是无效的。可以使用自定义TrustManager
并使用一组不同的标准。但开箱即用,这就是您必须使用的。【参考方案22】:
与接受的答案相反,您不需要需要自定义信任管理器,您需要修复服务器配置!
我在连接到具有错误安装的 dynadot/alphassl 证书的 Apache 服务器时遇到了同样的问题。我正在使用正在抛出的 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
配置服务器的说明(和中间证书)通常由颁发证书的机构提供,例如:http://www.alphassl.com/support/install-root-certificate.html
安装证书颁发者提供的中间证书后,现在使用 HttpsUrlConnection 连接时没有错误。
【讨论】:
如果 OP 有权访问他正在连接的服务器 SSL 配置,这可能是一个解决方案。但如果他不是托管他所连接的服务的人,他必须自己解决问题,这意味着实施自定义信任管理器。 毫无疑问,您的解决方案有效,但您不同意这是一种解决方法,而不是解决根本原因的方法吗?如果我必须从 3 个客户端(Android、ios、Windows Mobile)连接到服务器,那么我必须在所有 3 个客户端上应用解决方法,而我可以修复服务器一次,它们都会“正常工作”。 感谢 Stevie,我的服务器配置错误 3 个月,直到现在我才发现!现在我的 android 应用程序正在 100% 运行 @Stevie 我对共享同一域的不同 API 进行了多次调用,但只有一个调用失败并出现 (javax.net.ssl.SSLHandshakeException) ...知道为什么会发生这种情况吗?顺便说一下,SSL 证书不受信任。所以,我认为所有的调用都应该失败并出现相同的异常。 @dvaey 与拥有服务器的人取得联系,并告诉他们他们的配置已损坏并且他们的 https 无法正常工作 - 给他们这个链接以证明这一点digicert.com/help ...我想他们将不胜感激并迅速解决。否则,您将不得不采取其他答案中的解决方法步骤之一,但是当证书过期并且您的自定义信任存储不再与新的匹配时,您将不得不接受不安全(忽略证书)或重新部署您的应用程序证书。以上是关于未找到 Android SSL 连接的信任锚的主要内容,如果未能解决你的问题,请参考以下文章
使用超过 3g 时未找到证书路径的信任锚,但在 WiFi 上工作正常
certificatePinner 无法使用 okhttp 抛出 SSLHandshakeException:CertPathValidatorException 未找到证书路径的信任锚
调试 javax.net.ssl.SSLHandshakeException:java.security.cert.CertPathValidatorException:找不到证书路径的信任锚