Intercept updateSubcomponent to fix software key state inconsistency (#82)
Apps attempting to update the certificate chain of a simulated software-based key (e.g., via KeyStore.setKeyEntry) currently trigger a KEY_NOT_FOUND error. This happens because the request is passed to the hardware Keystore daemon, which has no knowledge of keys existing only in the simulator's memory. To fix detecting points exploiting this inconsistency, we intercept the UPDATE_SUBCOMPONENT_TRANSACTION. If the target is a recognized virtual key, the simulator now: 1. Updates the in-memory certificate/chain metadata. 2. Returns NO_ERROR immediately to the caller. 3. Prevents the transaction from reaching the real hardware service. Co-authored-by: JingMatrix <jingmatrix@gmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
JingMatrix
parent
ce740542f7
commit
ab4fe643a3
+35
-5
@@ -31,6 +31,8 @@ object Keystore2Interceptor : AbstractKeystoreInterceptor() {
|
||||
InterceptorUtils.getTransactCode(IKeystoreService.Stub::class.java, "getKeyEntry")
|
||||
private val DELETE_KEY_TRANSACTION =
|
||||
InterceptorUtils.getTransactCode(IKeystoreService.Stub::class.java, "deleteKey")
|
||||
private val UPDATE_SUBCOMPONENT_TRANSACTION =
|
||||
InterceptorUtils.getTransactCode(IKeystoreService.Stub::class.java, "updateSubcomponent")
|
||||
|
||||
private val transactionNames: Map<Int, String> by lazy {
|
||||
IKeystoreService.Stub::class
|
||||
@@ -89,16 +91,23 @@ object Keystore2Interceptor : AbstractKeystoreInterceptor() {
|
||||
callingPid: Int,
|
||||
data: Parcel,
|
||||
): TransactionResult {
|
||||
if (code == GET_KEY_ENTRY_TRANSACTION || code == DELETE_KEY_TRANSACTION) {
|
||||
if (
|
||||
code == GET_KEY_ENTRY_TRANSACTION ||
|
||||
code == DELETE_KEY_TRANSACTION ||
|
||||
code == UPDATE_SUBCOMPONENT_TRANSACTION
|
||||
) {
|
||||
logTransaction(txId, transactionNames[code]!!, callingUid, callingPid)
|
||||
|
||||
if (ConfigurationManager.shouldSkipUid(callingUid))
|
||||
return TransactionResult.ContinueAndSkipPost
|
||||
|
||||
if (code == UPDATE_SUBCOMPONENT_TRANSACTION)
|
||||
return handleUpdateSubcomponent(callingUid, data)
|
||||
|
||||
data.enforceInterface(IKeystoreService.DESCRIPTOR)
|
||||
val descriptor =
|
||||
data.readTypedObject(KeyDescriptor.CREATOR)
|
||||
?: return TransactionResult.SkipTransaction
|
||||
|
||||
if (ConfigurationManager.shouldSkipUid(callingUid))
|
||||
return TransactionResult.ContinueAndSkipPost
|
||||
?: return TransactionResult.ContinueAndSkipPost
|
||||
|
||||
SystemLogger.info("Handling ${transactionNames[code]!!} ${descriptor.alias}")
|
||||
val keyId = KeyIdentifier(callingUid, descriptor.alias)
|
||||
@@ -223,4 +232,25 @@ object Keystore2Interceptor : AbstractKeystoreInterceptor() {
|
||||
}
|
||||
return TransactionResult.SkipTransaction
|
||||
}
|
||||
|
||||
private fun handleUpdateSubcomponent(callingUid: Int, data: Parcel): TransactionResult {
|
||||
data.enforceInterface(IKeystoreService.DESCRIPTOR)
|
||||
val descriptor = data.readTypedObject(KeyDescriptor.CREATOR)
|
||||
val generatedKeyInfo =
|
||||
KeyMintSecurityLevelInterceptor.findGeneratedKeyByKeyId(callingUid, descriptor?.nspace)
|
||||
?: return TransactionResult.ContinueAndSkipPost
|
||||
|
||||
SystemLogger.info("Updating sub-component with key[${generatedKeyInfo.nspace}]")
|
||||
val metadata = generatedKeyInfo.response.metadata
|
||||
val publicCert = data.createByteArray()
|
||||
val certificateChain = data.createByteArray()
|
||||
|
||||
metadata.certificate = publicCert
|
||||
metadata.certificateChain = certificateChain
|
||||
SystemLogger.verbose(
|
||||
"Key updated with sizes: [publicCert, certificateChain] = [${publicCert?.size}, ${certificateChain?.size}]"
|
||||
)
|
||||
|
||||
return InterceptorUtils.createSuccessReply(writeResultCode = false)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -349,9 +349,10 @@ class KeyMintSecurityLevelInterceptor(
|
||||
* @param nspace The unique key identifier from the operation's KeyDescriptor.
|
||||
* @return The matching GeneratedKeyInfo if found, otherwise null.
|
||||
*/
|
||||
private fun findGeneratedKeyByKeyId(callingUid: Int, nspace: Long): GeneratedKeyInfo? {
|
||||
fun findGeneratedKeyByKeyId(callingUid: Int, nspace: Long?): GeneratedKeyInfo? {
|
||||
// Iterate through all entries in the map to check both the key (for UID) and value (for
|
||||
// nspace).
|
||||
if (nspace == null || nspace == 0L) return null
|
||||
return generatedKeys.entries
|
||||
.filter { (keyIdentifier, _) -> keyIdentifier.uid == callingUid }
|
||||
.find { (_, info) -> info.nspace == nspace }
|
||||
|
||||
Reference in New Issue
Block a user