CertPathValidatorException:找不到证书路径的信任锚 - Retrofit Android

Gow*_*Raj 54 ssl android retrofit okhttp

我正在创建一个https用于与服务器通信的android应用程序.我正在使用retrofitOkHttp提出请求.这些适用于标准http请求.以下是我遵循的步骤.

步骤1: 使用该命令从服务器获取cert文件

echo -n | openssl s_client -connect api.****.tk:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > gtux.cert
Run Code Online (Sandbox Code Playgroud)

步骤2: 使用以下命令将证书转换为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
Run Code Online (Sandbox Code Playgroud)

它问我密码并且文件已成功创建.

第3步:

创建一个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;
}
}
Run Code Online (Sandbox Code Playgroud)

第4步:

必须创建RestAdapter

RestAdapter.Builder()
.setRequestInterceptor(intercept)
.setEndpoint("https://api.****.tk")
.setClient(new OkClient(this))
.setLogLevel(RestAdapter.LogLevel.FULL)
.setLog(new AndroidLog("RETROFIT"))
.build();
Run Code Online (Sandbox Code Playgroud)

但最后在运行应用程序时它会抛弃我CertPathValidatorException : Trust anchor for certificate path not found.请帮我解决这个问题.谢谢.

其他失败尝试: 试图在我的Xperia Z2中安装证书,它说文件已安装,但是当我运行应用程序时,会抛出相同的异常.

错误日志 这是我执行时的错误日志...

错误日志

贴在那里,以便它易于阅读..

Pau*_*lar 86

免责声明:这个答案是从2015年7月开始的,并使用了当时的RetrofitOkHttp.
检查这个环节上改造v2的更多信息和这一个当前OkHttp方法.

好的,我使用Android开发者指南了解它.

就像OP一样,我正在尝试使用RetrofitOkHttp连接到自签名的SSL服务器.

这是使事情有效的代码(我删除了try/catch块):

public static RestAdapter createAdapter(Context context) {
  // loading CAs from an InputStream
  CertificateFactory cf = CertificateFactory.getInstance("X.509");
  InputStream cert = context.getResources().openRawResource(R.raw.my_cert);
  Certificate ca;
  try {
    ca = cf.generateCertificate(cert);
  } finally { cert.close(); }

  // creating a KeyStore containing our trusted CAs
  String keyStoreType = KeyStore.getDefaultType();
  KeyStore keyStore = KeyStore.getInstance(keyStoreType);
  keyStore.load(null, null);
  keyStore.setCertificateEntry("ca", ca);

  // creating a TrustManager that trusts the CAs in our KeyStore
  String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
  TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
  tmf.init(keyStore);

  // creating an SSLSocketFactory that uses our TrustManager
  SSLContext sslContext = SSLContext.getInstance("TLS");
  sslContext.init(null, tmf.getTrustManagers(), null);

  // creating an OkHttpClient that uses our SSLSocketFactory
  OkHttpClient okHttpClient = new OkHttpClient();
  okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());

  // creating a RestAdapter that uses this custom client
  return new RestAdapter.Builder()
              .setEndpoint(UrlRepository.API_BASE)
              .setClient(new OkClient(okHttpClient))
              .build();
}
Run Code Online (Sandbox Code Playgroud)

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

所有这一切都是我保存的原始.crt文件main/res/raw.该.CRT文件,又名证书,是当你创建使用证书创建的两个文件之一openssl.通常,它是.crt或.cert文件,而另一个是.key文件.

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

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


PS:对于那些将来读它并且只有.pem文件的人,根据这个答案,你只需要将它转换成另一个:

openssl x509 -outform der -in your-cert.pem -out your-cert.crt
Run Code Online (Sandbox Code Playgroud)

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

echo -n | openssl s_client -connect your.server.com:443 | \
  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/my_cert.crt
Run Code Online (Sandbox Code Playgroud)

只需替换your.server.com和端口(如果它不是标准HTTPS)并选择要创建的输出文件的有效路径.

  • 如果okHttpClient.setSslSocketFactory(...)方法无法解析,则可以使用okHttpClient = new OkHttpClient.Builder().sslSocketFactory(new TLSSocketFactory()).build();。 (2认同)

vis*_*156 23

 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请访问https://mobikul.com/android-retrofit-handling-sslhandshakeexception/

  • 这种实现是不安全的。不要将其用于生产代码:/sf/answers/2732270341/ (2认同)

小智 11

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

         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
            }
        }
Run Code Online (Sandbox Code Playgroud)

  • 问题不在于如何禁用 SSL 证书检查 (4认同)

goR*_*Gon 10

我不使用Retrofit,对于OkHttp,这是我自己签署的自签名证书的唯一解决方案:

  1. 从我们的网站获取证书,如Gowtham的问题,并将其放入项目的res/raw目录:

    echo -n | openssl s_client -connect elkews.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ./res/raw/elkews_cert.crt
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用Paulo答案来设置ssl工厂(现在使用OkHttpClient.Builder())但没有创建RestAdapter.

  3. 然后添加以下解决方案进行修复: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();
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你补充答案.但有一个问题:仅通过在没有SSL会话的情况下检查主机名,您是否容易受到中间人攻击?我不是其他验证的内容,但我记得你覆盖的那个非常重要. (2认同)

Gow*_*K C 9

改造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();
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

86336 次

最近记录:

6 年,3 月 前