我正在创建一个使用 https
与服务器通信的 android 应用程序。我正在使用 retrofit
和 OkHttp
发出请求。这些适用于标准 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 中安装证书,它说文件已安装,但是当我运行应用程序时,抛出了相同的异常。
错误日志 这是我执行的错误日志...
贴在那里以便于阅读..
最佳答案
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 一样,我正在尝试使用 Retrofit 和 OkHttp 连接到启用自签名 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/