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:
+6
-3
@@ -157,13 +157,15 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)!!
|
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)!!
|
||||||
val key = metadata.key!!
|
val key = metadata.key!!
|
||||||
val keyId = KeyIdentifier(callingUid, keyDescriptor.alias)
|
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
|
patchedChains[keyId] = newChain
|
||||||
SystemLogger.debug(
|
SystemLogger.debug(
|
||||||
"Cached patched certificate chain for $keyId. (${key.alias} [${key.domain}, ${key.nspace}])"
|
"Cached patched certificate chain for $keyId. (${key.alias} [${key.domain}, ${key.nspace}])"
|
||||||
)
|
)
|
||||||
|
|
||||||
CertificateHelper.updateCertificateChain(metadata, newChain).getOrThrow()
|
|
||||||
|
|
||||||
return InterceptorUtils.createTypedObjectReply(metadata)
|
return InterceptorUtils.createTypedObjectReply(metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,10 +260,11 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
securityLevel,
|
securityLevel,
|
||||||
) ?: throw Exception("CertificateGenerator failed to create key pair.")
|
) ?: 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.
|
// Store the generated key data.
|
||||||
val response =
|
val response =
|
||||||
buildKeyEntryResponse(keyData.second, parsedParams, keyDescriptor)
|
buildKeyEntryResponse(keyData.second, parsedParams, keyDescriptor)
|
||||||
|
|
||||||
generatedKeys[keyId] =
|
generatedKeys[keyId] =
|
||||||
GeneratedKeyInfo(keyData.first, keyDescriptor.nspace, response)
|
GeneratedKeyInfo(keyData.first, keyDescriptor.nspace, response)
|
||||||
if (isAttestKeyRequest) attestationKeys.add(keyId)
|
if (isAttestKeyRequest) attestationKeys.add(keyId)
|
||||||
|
|||||||
Reference in New Issue
Block a user