fix: return full keybox chain when BYO attest key misses

CertificateGenerator.generateCertificateChain selected
keybox.keyPair as fallback signer when getAttestationKeyInfo returned
null, but the chain assembly at line 115 still keyed on
"attestKeyAlias != null" and returned only listOf(leafCert). The
caller received a depth-1 chain signed by the keybox root with no
parent attached, structurally invalid.

Track whether the BYO lookup actually returned a key. On hit return
the depth-1 chain (caller holds the rest). On miss include
keybox.certificates so the chain is rooted.

Surfaced by adversarial audit of f384871, which broadened the
software-dispatch gate to all attestationKey != null requests.
Without this companion fix the miss path produces a malformed chain
where the previous code would have forwarded to HAL.
This commit is contained in:
Enginex0
2026-05-20 03:58:20 +01:00
parent 76e033700c
commit 937058a7ff
@@ -101,18 +101,19 @@ object CertificateGenerator {
val keybox = getKeyboxForAlgorithm(uid, params.algorithm) val keybox = getKeyboxForAlgorithm(uid, params.algorithm)
val (signingKey, issuer) = val attestKeyInfo =
if (attestKeyAlias != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (attestKeyAlias != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
getAttestationKeyInfo(uid, attestKeyAlias)?.let { it.first to it.second } getAttestationKeyInfo(uid, attestKeyAlias)
} else null
val (signingKey, issuer) = attestKeyInfo
?.let { it.first to it.second }
?: (keybox.keyPair to getIssuerFromKeybox(keybox)) ?: (keybox.keyPair to getIssuerFromKeybox(keybox))
} else {
keybox.keyPair to getIssuerFromKeybox(keybox)
}
val leafCert = val leafCert =
buildCertificate(subjectKeyPair, signingKey, issuer, params, uid, securityLevel) buildCertificate(subjectKeyPair, signingKey, issuer, params, uid, securityLevel)
if (attestKeyAlias != null) { if (attestKeyInfo != null) {
listOf(leafCert) listOf(leafCert)
} else { } else {
listOf(leafCert) + keybox.certificates listOf(leafCert) + keybox.certificates