[英]Trust anchor for certification path not found. Using self-signed client certificates on android
I have a simple web api running on a raspberry pi that sits behind an nginx server on the same pi.我有一个简单的 web api 在树莓派上运行,它位于同一个 pi 上的 nginx 服务器后面。 I'm using self-signed client certificates to authenticate calls from an android app.
我正在使用自签名客户端证书来验证来自 android 应用程序的调用。 This worked completely fine in the past, but I recently came back to this project after rebuilding some hardware, and when I try and use it on my Pixel 2 running Android 8.1, it gives the following exception:
这在过去完全正常,但我最近在重建一些硬件后又回到了这个项目,当我尝试在运行 Android 8.1 的 Pixel 2 上使用它时,它给出了以下异常:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:219)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:268)
...
I generated certs and keys according to: http://nategood.com/client-side-certificate-authentication-in-ngi我根据: http : //nategood.com/client-side-certificate-authentication-in-ngi生成了证书和密钥
Testing with curl
works fine.使用
curl
测试工作正常。
I created keystore for the app to use with:我为应用程序创建了密钥库以用于:
openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12
I followed the following article to setup the client certs in Android and connect to the server: http://chariotsolutions.com/blog/post/https-with-client-certificates-on/我按照以下文章在 Android 中设置客户端证书并连接到服务器: http : //chariotsolutions.com/blog/post/https-with-client-certificates-on/
but I rewrote it in Kotlin, using OkHttp:但我在 Kotlin 中使用 OkHttp 重写了它:
private const val SERVER = "https://my.server"
/**
* trustManagers is used to authorize the server's self-signed cert
*/
private val trustManagers by lazy {
val cert = CertificateFactory.getInstance("X.509")
.generateCertificate(appCtx.assets.open("ca.crt")) as X509Certificate
val trustStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
load(null, null)
setCertificateEntry(cert.subjectX500Principal.name, cert)
}
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply {
init(trustStore)
}.trustManagers
}
/**
* keyManagers is used to load the client-authentication cert
*/
private val keyManagers by lazy {
// assuming this can only be called after Application is created
val keyStore = KeyStore.getInstance("PKCS12").apply {
load(appCtx.assets.open("client.p12"), "".toCharArray())
}
KeyManagerFactory.getInstance("X509").apply {
init(keyStore, "".toCharArray())
}.keyManagers
}
/**
* sslContext for opening TLS connection to server
*/
private val sslContext by lazy {
SSLContext.getInstance("TLS").apply {
init(keyManagers, trustManagers, null)
}
}
/**
* pass an HTTPS request to server
*/
suspend fun request(url: String): ByteArray? {
return try {
val request = Request.Builder()
.url(url)
.build()
val client = OkHttpClient.Builder()
.sslSocketFactory(sslContext.socketFactory, trustManagers[0] as X509TrustManager)
.build()
client.newCall(request).await().body().byteStream().readBytes()
} catch (e: Exception) {
err(e) { "failed to send request" }
null
}
}
This use to work, but now it does not.这使用工作,但现在它没有。 I spent a day and a half searching for an answer and I've tried the following:
我花了一天半的时间寻找答案,并尝试了以下方法:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config> <trust-anchors> <!-- Additionally trust user added CAs --> <certificates src="user" /> <certificates src="@raw/ca"/> </trust-anchors> </base-config> </network-security-config>
I've read all the examples I can find on creating custom trust managers, and they are all pretty much the same, even https://developer.android.com/training/articles/security-ssl.html#UnknownCa我已经阅读了所有关于创建自定义信任管理器的示例,它们几乎都相同,甚至是https://developer.android.com/training/articles/security-ssl.html#UnknownCa
Everythign I've tried produces the same exception, am I missing something?我试过的一切都会产生同样的异常,我错过了什么吗?
This is how I was able to get it to work in my project, using a self-signed cert on GoDaddy:这就是我使用 GoDaddy 上的自签名证书让它在我的项目中工作的方式:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <debug-overrides> <trust-anchors> <certificates src="user"/> <certificates src="@raw/gdcert"/> </trust-anchors> </debug-overrides> </network-security-config>
android:networkSecurityConfig="@xml/network_security_config"
SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); SSLSocketFactory ssf = sc.getSocketFactory(); SSLSocket sslsocket = (SSLSocket) ssf.createSocket("yourwebsitename.com", 443);
Followed by whatever code you are trying to run to connect to the server.其次是您尝试运行以连接到服务器的任何代码。
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }};
Save your project and run it.保存您的项目并运行它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.