CertPathValidatorException:找不到证书路径的信任锚点-改装Android

CertPathValidatorException:找不到证书路径的信任锚点-改装Android,android,ssl,retrofit,okhttp,Android,Ssl,Retrofit,Okhttp,我正在创建一个android应用程序,它使用https与服务器通信。我正在使用改装和OkHttp进行请求。对于标准的http请求,这些方法非常有效。以下是我遵循的步骤 第1步: 使用命令从服务器获取证书文件 echo -n | openssl s_client -connect api.****.tk:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > gtux.cert 第二步: 使用以下命令将证书转换为BKS格式

我正在创建一个android应用程序,它使用https与服务器通信。我正在使用
改装
OkHttp
进行请求。对于标准的
http
请求,这些方法非常有效。以下是我遵循的步骤

第1步: 使用命令从服务器获取证书文件

echo -n | openssl s_client -connect api.****.tk:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > gtux.cert
第二步: 使用以下命令将证书转换为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
它要求我输入密码,文件已成功创建

第三步:

创建一个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中安装证书,它说文件已安装,但当我运行应用程序时,引发了相同的异常

错误日志 这是我在执行时得到的错误日志


粘贴在那里以便阅读。

您正在将证书转换为BKS密钥库,为什么不直接使用
.cert
,从:

免责声明:此答案来自2015年7月并从那时起使用改装OkHttp
查看有关改装v2和当前OkHttp方法的更多信息

好的,我用它工作了

正如OP一样,我正在尝试使用改造OkHttp连接到一个启用自签名SSL的服务器

下面是使事情正常工作的代码(我已经删除了try/catch块):

为了帮助调试,我还将
.setLogLevel(RestAdapter.LogLevel.FULL)
添加到我的RestAdapter创建命令中,我可以看到它正在连接并从服务器获取响应

只需要保存在
main/res/raw
中的原始.crt文件。 .crt文件也称为证书,是使用
openssl
创建证书时创建的两个文件之一。通常,它是一个.crt或.cert文件,而另一个是一个.key文件

好的,.crt文件是您的公钥,而.key文件是您的私钥

正如我所看到的,您已经有一个.cert文件,它是相同的,所以请尝试使用它


PS:对于那些将来阅读它并且只有.pem文件的人,根据,您只需要将一个文件转换为另一个文件:

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

PS²:对于那些根本没有任何文件的服务器,您可以使用以下命令(bash)从任何服务器提取公钥(也称为证书):

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

只需更换
your.server.com
和端口(如果不是标准的HTTPS),然后为要创建的输出文件选择一个有效路径。

我不使用改型,对于OkHttp,以下是对我有效的自签名证书的唯一解决方案:

  • 从我们的网站获得一份证书,如Gowtham的问题中所述,并将其放入项目的res/raw目录中:

    echo -n | openssl s_client -connect elkews.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ./res/raw/elkews_cert.crt
    
  • 用于设置ssl工厂(现在使用的是OkHttpClient.Builder()),但不带RestAdapter创建

  • 然后添加解决方案以修复:SSLPeerUnverifiedException:主机名未验证

  • 因此Paulo代码的结尾(在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();
    

    经过长时间的研究和深入挖掘,我在android中找到了证书固定的解决方案,是的,它与iOS不同,iOS需要证书本身,但在android中,我们只需要一个散列pin,就是这样

    如何获取证书的哈希pin?

    最初只是使用了一个错误的散列pin,您的java类将抛出一个错误,并带有正确的散列pin或pin链,只需复制并粘贴到您的代码中即可


    此解决方案解决了我的问题:

    改装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();
    

    有关更多详细信息,请访问Kotlin中的实施:改装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
    

    }这是Kotlin的版本。Okhttp 4.9.0
    谢谢你:)

    fun unSafeOkHttpClient():OkHttpClient.Builder{
    val okHttpClient=okHttpClient.Builder()
    试一试{
    //创建不验证证书链的信任管理器
    val trustAllCerts:Array=arrayOf(对象:X509TrustManager{
    重写fun checkClientTrusted(链:数组?,身份类型:字符串?{}
    重写fun checkServerTrusted(链:数组?,身份类型:字符串?{}
    重写GetAcceptedAssuers():Array=arrayOf()
    })
    //安装所有信任管理器
    val sslContext=sslContext.getInstance(“SSL”)
    init(null,trustAllCerts,SecureRandom())
    //使用我们的全信任管理器创建ssl套接字工厂
    val sslSocketFactory=sslContext.socketFactory
    if(trustAllCerts.isNotEmpty()&&trustAllCerts.first()是X509TrustManager){
    okHttpClient.sslSocketFactory(sslSocketFactory,trustAllCerts.first()作为X509TrustManager)
    okHttpClient.hostnameVerifier{hostnameVerifier{{{uu,{uu->true}
    }
    返回okHttpClient
    }捕获(e:例外){
    返回okHttpClient
    }
    }
    
    android应用程序中的gtux.cert应该保存在哪里?我的方法没有奏效有什么特别的原因吗@moonzai如果cer
        // 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();
    
     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);
        }
    }
    
    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
    
             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 {HostnameVerifier { _, _ -> true } }
                    }
    
                    return okHttpClient
                } catch (e: Exception) {
                    return okHttpClient
                }
            }