我试图连接到一个运行godaddy 256bit 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());

当前回答

我得到的错误消息与此类似,但原因是自签名证书已经过期。 当尝试openssl客户端时,它给了我一个原因,当我在firefox中检查证书对话框时忽略了这个原因。

因此,通常情况下,如果证书在密钥存储库中并且它是“VALID”,则此错误将消失。

其他回答

使用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.certpathvalidatorexcexception:未找到认证路径的信任锚以及如何为Glide设置OkHttpClient。

@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模拟器上得到了另一个错误:

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

但是这个库给apk增加了3.4 Mb。

我得到的错误消息与此类似,但原因是自签名证书已经过期。 当尝试openssl客户端时,它给了我一个原因,当我在firefox中检查证书对话框时忽略了这个原因。

因此,通常情况下,如果证书在密钥存储库中并且它是“VALID”,则此错误将消失。

与公认的答案相反,您不需要自定义信任管理器,您需要修复您的服务器配置!

我在连接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

你可能会看到:

验证返回码:21(无法验证第一个证书)

在前面的输出中:

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连接时没有错误。

In my case, the root & intermediate certificates was successfully installed but I still got "Trust anchor for certification path not found." exception!. After digging the android document, found out that by default, secure connections (using protocols like TLS and HTTPS) from all apps trust the pre-installed system CAs, and apps targeting Android 6.0 (API level 23) and lower also trust the user-added CA store by default. If your app running on a OS with api level higher than 23 you should explicitly allow the app to trust user-added CA by adding its address to network_security_config like bellow:

<domain-config>
        <domain includeSubdomains="true">PUT_YOUR_SERVER_ADDERESS</domain>
        <trust-anchors>
            <certificates src="user" />
        </trust-anchors>
</domain-config>

产生信任锚错误的原因有很多。对我来说,我只是想访问https://example.com/而不是https://www.example.com/。

因此,在开始构建自己的信任管理器(就像我做的那样)之前,您可能需要仔细检查您的url。