Skip to content

Commit 75964ec

Browse files
committed
android: more detail for test config verify exception
Recently CI started failing the real world verification suite on Android. The root cause was the vendored Let's Encrypt end entity certificate expiring. Figuring this out was hard for two main reasons: 1. CI was eating the Android logs we needed to see the error message. This has since been fixed. 2. The Android verifier was surfacing the expiration as an unknown issuer error with a generic "Chain validation failed" message. This branch attempts to fix item 2 by surfacing a more relevant error message. Unfortunately doing so is a little bit annoying. The `checkServerTrusted` call throws an exception with ~3 layers of wrapping before you get at the `CertificateExpiredException` that's the root cause. Since non-test configurations should never have an expired exception thrown at this stage (recall we check this explicitly earlier in processing), we gate the more complicated excepting "digging" based on `BuildConfig.TEST`. This should be a good balance of: * not changing existing behaviour, or introducing complexity for normal validation * surfacing a better error message when test certificates expire and start to break CI.
1 parent d68c2ed commit 75964ec

File tree

1 file changed

+26
-0
lines changed

1 file changed

+26
-0
lines changed

android/rustls-platform-verifier/src/main/java/org/rustls/platformverifier/CertificateVerifier.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,32 @@ internal object CertificateVerifier {
253253
val validChain = try {
254254
trustManager.checkServerTrusted(certificateChain.toTypedArray(), authMethod, serverName)
255255
} catch (e: CertificateException) {
256+
// In test configurations we may see `checkServerTrusted` fail once vendored test
257+
// certificates pass their expiry date. We try to avoid that by using a fixed
258+
// verification time when calling `endEntity.checkValidity` above, however we can't
259+
// fix the time for the `checkServerTrusted` call.
260+
//
261+
// To make diagnosing CI test failures easier we try to find the root cause of
262+
// checkServerTrusted failing, returning a different `StatusCode` as appropriate.
263+
if (BuildConfig.TEST) {
264+
var rootCause: Throwable = e
265+
while (rootCause.cause != rootCause) {
266+
rootCause.cause?.let {
267+
rootCause = it
268+
}
269+
}
270+
return when (rootCause) {
271+
is CertificateExpiredException, is CertificateNotYetValidException -> VerificationResult(
272+
StatusCode.Expired,
273+
rootCause.toString()
274+
)
275+
276+
else -> VerificationResult(StatusCode.UnknownCert, rootCause.toString())
277+
}
278+
}
279+
// In non-test configurations we should have caught expiry errors earlier and
280+
// can simply return an unknown cert error without digging through the exception
281+
// cause chain.
256282
return VerificationResult(StatusCode.UnknownCert, e.toString())
257283
}
258284

0 commit comments

Comments
 (0)