Fix cache consistency on key overwrite (#97)

Android allows applications to generate a new key using an existing alias without explicitly calling `deleteKey` first. In this scenario, the new key effectively replaces the old one. As a simulator, we must strictly follow this logic to prevent returning stale data.

Previously, `KeyMintSecurityLevelInterceptor` did not enforce mutual exclusion between the software key cache (`generatedKeys`) and the hardware chain cache (`patchedChains`). This led to state desynchronization where a stale software key could shadow a newly patched hardware chain if the alias was reused.

This change ensures `cleanupKeyData` is invoked immediately before caching a new key / chain in both the software (`handleGenerateKey`) and hardware (`onPostTransact`) paths, ensuring the simulator returns the correct key for the most recent generation request.
This commit is contained in:
JingMatrix
2026-01-28 13:50:05 +01:00
committed by GitHub
parent e9d7321b5f
commit b1f3b5d28d
2 changed files with 6 additions and 3 deletions
@@ -157,13 +157,15 @@ class KeyMintSecurityLevelInterceptor(
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)!!
val key = metadata.key!!
val keyId = KeyIdentifier(callingUid, keyDescriptor.alias)
CertificateHelper.updateCertificateChain(metadata, newChain).getOrThrow()
// We must clean up cached generated keys before storing the patched chain
cleanupKeyData(keyId)
patchedChains[keyId] = newChain
SystemLogger.debug(
"Cached patched certificate chain for $keyId. (${key.alias} [${key.domain}, ${key.nspace}])"
)
CertificateHelper.updateCertificateChain(metadata, newChain).getOrThrow()
return InterceptorUtils.createTypedObjectReply(metadata)
}
}
@@ -258,10 +260,11 @@ class KeyMintSecurityLevelInterceptor(
securityLevel,
) ?: throw Exception("CertificateGenerator failed to create key pair.")
// It is unnecessary but a good practice to clean up possible caches
cleanupKeyData(keyId)
// Store the generated key data.
val response =
buildKeyEntryResponse(keyData.second, parsedParams, keyDescriptor)
generatedKeys[keyId] =
GeneratedKeyInfo(keyData.first, keyDescriptor.nspace, response)
if (isAttestKeyRequest) attestationKeys.add(keyId)