android - CertPathValidatorException : Trust anchor for certificate path not found - Retrofit Android

标签 android ssl retrofit okhttp

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

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

echo -n | openssl s_client -connect api.****.tk:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > gtux.cert

第 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

它要求我输入密码并且文件已成功创建。

第 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;
}
}

第 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 中安装证书,它说文件已安装,但是当我运行应用程序时,抛出了相同的异常。

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

Error Log

贴在那里以便于阅读..

最佳答案

DISCLAIMER: this answer is from Jul 2015 and uses Retrofit and OkHttp from that time.
Check this link for more info on Retrofit v2 and this one for the current OkHttp methods.

好的,我使用 Android Developers guide 让它工作了.

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

这是让事情正常运行的代码(我已经删除了 try/catch block ):

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

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

只需要保存在 main/res/raw 中的原始 .crt 文件。 .crt 文件,即证书,是您使用 openssl 创建证书时创建的两个文件之一。一般是 .crt 或 .cert 文件,另一个是 .key 文件。

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

如我所见,您已经有一个 .cert 文件,它是一样的,所以尝试使用它。


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

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)并为要创建的输出文件选择有效路径。

关于android - CertPathValidatorException : Trust anchor for certificate path not found - Retrofit Android,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29273387/

相关文章:

sockets - 可以在其中插入服务器证书构建的应用程序吗?

java - 应为 BEGIN_OBJECT,但在第 5 行第 1 列路径$ 处为字符串。我收到此错误,结果发现任何解决方案都不起作用

java - 抽象类的 Jacoco 代码覆盖率部分显示

Android 4.0 Eclipse 编译失败

android - 使用动画对象而不是资源 ID 覆盖挂起的过渡

android - 如何使用Retrofit同时发送图像和文本

php - 在 Android 中将 Retrofit 发布到 Rest 服务器

android - 错误: Please install Android target: "android-22" when SDK manager shows it is installed

iis - 如何将通配符 SSL 证书从 IIS 导出到 Heroku?

security - 什么时候应该启用 HSTS?