‘throwExceptionFromBoringSSLError called with no error’ with Android 9 + Conscrypt
See original GitHub issueApologies for reporting this here instead of the AOSP tracker. In my experience that tracker is a black hole!
We saw this crash across many different app releases and device manufacturers. The only thing in common was it was always Android 9.
Looks like the offending line of code is here in Conscrypt:
if (X509_verify(x509, pkey) != 1) {
conscrypt::jniutil::throwExceptionFromBoringSSLError(
env, "X509_verify", conscrypt::jniutil::throwCertificateException);
JNI_TRACE("X509_verify(%p, %p) => verify failure", x509, pkey);
return;
}
The exception is:
throwExceptionFromBoringSSLError called with no error
at com.android.org.conscrypt.NativeCrypto.X509_verify(NativeCrypto.java:-2)
at com.android.org.conscrypt.OpenSSLX509Certificate.verifyOpenSSL(OpenSSLX509Certificate.java:379)
at com.android.org.conscrypt.OpenSSLX509Certificate.verify(OpenSSLX509Certificate.java:409)
at com.android.org.conscrypt.TrustedCertificateIndex.findAllByIssuerAndSignature(TrustedCertificateIndex.java:197)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:618)
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:495)
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:418)
at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:339)
at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88)
at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:208)
at com.android.org.conscrypt.ConscryptFileDescriptorSocket.verifyCertificateChain(ConscryptFileDescriptorSocket.java:404)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(NativeCrypto.java:-2)
at com.android.org.conscrypt.NativeSsl.doHandshake(NativeSsl.java:375)
at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:224)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:379)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:337)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:209)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder:74)
at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall:255)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:204)
The crashes coincide with us updating our TLS certificates. The new certificates share the same root and intermediary as the previous certificate. The leaf certificate has a different expiration date.
Is it possible that Android 9’s Conscrypt crashes as-above when certificates are rotated? Perhaps it was remembering the certificate from a previous HTTPS connection? Is Conscrypt configured differently in any meaningful way in Android 9 vs. 8 or 10?
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (1 by maintainers)
Top GitHub Comments
Nah, don’t worry. Unfortunately AOSP issues sometimes bounce around in triage for a while before they find their way to us.
Android 9’s BoringSSL’s
X509_verify()
is rejecting one of your intermediate certificates but for some reason failing to set the error queue before returning. I skimmed the code path and I don’t see any obvious ways it can return without doing that but I wasn’t exhaustive. @davidben has been fixing issues around the error queue during verification recently so he might remember if there were issues here in the Android P timeframe.The higher level code is trying to built a trust chain through the intermediate certs to a trust anchor, using either the certificates provided by the peer or in this case a cache of previously seen intermediates. Any cache hits get their
verify()
method called and that’s where the exception is getting thrown.There are arguments for and against the intermediate cache (we recently discussed removing it), but the idea is to make things go better when not all servers for a site are not sending a full certificate chain.
So the sequence looks something like:
Intermediate
) which (a) fails verification (b) without generating a useful error message. It’s possible that both (a) and (b) are fixed in Android 10, I haven’t done all the archaeology. Certainly there have been changes in that area ofTrustManagerImpl
.Leaf
) with issuerIntermediate
but the trust manager isn’t able to build a chain of trust using the certificates provided by the server, which may be becauseIntermediate
wasn’t included or because some other link in the chain isn’t trusted.Intermediate
, finds it and explodes.If you’re able to reproduce this yourself, the list of certificates passed into
RootTrustManager.checkServerTrusted()
would be helpful, or failing that just point me at the server and I ought to be able to reproduce it from the certificate chain.Note that
X509Certificate.verify()
is just doing structural checks on the certificate itself, so somewhere in here there’s an intermediate certificate that either BoringSSL thinks is invalid or that triggers a bug on Android 9 BoringSSL, or that Conscrypt is somehow corrupting. If it’s one of the latter two then a timely fix for Android 9 is going to be difficult.OK, so neither of those changes made it into Android 9.
I’d still like to see the certificate chain so we can figure out if there’s a bug around signature algorithm matching or intermediate caching in Android 9.