Skip to content

Commit

Permalink
android: more detail for test config verify exception
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
cpu committed Mar 15, 2024
1 parent d68c2ed commit 75964ec
Showing 1 changed file with 26 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,32 @@ internal object CertificateVerifier {
val validChain = try {
trustManager.checkServerTrusted(certificateChain.toTypedArray(), authMethod, serverName)
} catch (e: CertificateException) {
// In test configurations we may see `checkServerTrusted` fail once vendored test
// certificates pass their expiry date. We try to avoid that by using a fixed
// verification time when calling `endEntity.checkValidity` above, however we can't
// fix the time for the `checkServerTrusted` call.
//
// To make diagnosing CI test failures easier we try to find the root cause of
// checkServerTrusted failing, returning a different `StatusCode` as appropriate.
if (BuildConfig.TEST) {
var rootCause: Throwable = e
while (rootCause.cause != rootCause) {
rootCause.cause?.let {
rootCause = it
}
}
return when (rootCause) {
is CertificateExpiredException, is CertificateNotYetValidException -> VerificationResult(
StatusCode.Expired,
rootCause.toString()
)

else -> VerificationResult(StatusCode.UnknownCert, rootCause.toString())
}
}
// In non-test configurations we should have caught expiry errors earlier and
// can simply return an unknown cert error without digging through the exception
// cause chain.
return VerificationResult(StatusCode.UnknownCert, e.toString())
}

Expand Down

0 comments on commit 75964ec

Please sign in to comment.