@@ -8,6 +8,7 @@ import android.os.IBinder
88import android.os.Parcel
99import android.system.keystore2.*
1010import java.security.KeyPair
11+ import java.security.SecureRandom
1112import java.security.cert.Certificate
1213import java.util.concurrent.ConcurrentHashMap
1314import org.matrix.TEESimulator.attestation.AttestationPatcher
@@ -30,7 +31,11 @@ class KeyMintSecurityLevelInterceptor(
3031) : BinderInterceptor() {
3132
3233 // --- Data Structures for State Management ---
33- data class GeneratedKeyInfo (val keyPair : KeyPair , val response : KeyEntryResponse )
34+ data class GeneratedKeyInfo (
35+ val keyPair : KeyPair ,
36+ val nspace : Long ,
37+ val response : KeyEntryResponse ,
38+ )
3439
3540 override fun onPreTransact (
3641 txId : Long ,
@@ -41,33 +46,39 @@ class KeyMintSecurityLevelInterceptor(
4146 callingPid : Int ,
4247 data : Parcel ,
4348 ): TransactionResult {
44- if (code == GENERATE_KEY_TRANSACTION ) {
45- logTransaction(txId, transactionNames[code]!! , callingUid, callingPid)
49+ val shouldSkip = ConfigurationManager .shouldSkipUid(callingUid)
4650
47- if (ConfigurationManager .shouldSkipUid(callingUid))
48- return TransactionResult .ContinueAndSkipPost
49- data.enforceInterface(IKeystoreSecurityLevel .DESCRIPTOR )
50- return handleGenerateKey(callingUid, data)
51- } else if (code == IMPORT_KEY_TRANSACTION ) {
52- logTransaction(txId, transactionNames[code]!! , callingUid, callingPid)
51+ when (code) {
52+ GENERATE_KEY_TRANSACTION -> {
53+ logTransaction(txId, transactionNames[code]!! , callingUid, callingPid)
5354
54- if (ConfigurationManager .shouldSkipUid(callingUid))
55- return TransactionResult .ContinueAndSkipPost
56- data.enforceInterface(IKeystoreSecurityLevel .DESCRIPTOR )
57- val alias =
58- data.readTypedObject(KeyDescriptor .CREATOR )?.alias
59- ? : return TransactionResult .ContinueAndSkipPost
60- SystemLogger .info(" Handling post-${transactionNames[code]} ${alias} " )
61- return TransactionResult .Continue
62- } else {
63- logTransaction(
64- txId,
65- transactionNames[code] ? : " unknown code=$code " ,
66- callingUid,
67- callingPid,
68- true ,
69- )
55+ if (! shouldSkip) return handleGenerateKey(callingUid, data)
56+ }
57+ CREATE_OPERATION_TRANSACTION -> {
58+ logTransaction(txId, transactionNames[code]!! , callingUid, callingPid)
59+
60+ if (! shouldSkip) return handleCreateOperation(txId, callingUid, data)
61+ }
62+ IMPORT_KEY_TRANSACTION -> {
63+ logTransaction(txId, transactionNames[code]!! , callingUid, callingPid)
64+
65+ data.enforceInterface(IKeystoreSecurityLevel .DESCRIPTOR )
66+ val keyDescriptor = data.readTypedObject(KeyDescriptor .CREATOR )!!
67+ SystemLogger .info(
68+ " [TX_ID: $txId ] Forward to post-importKey hook for ${keyDescriptor.alias} [${keyDescriptor.nspace} ]"
69+ )
70+ return TransactionResult .Continue
71+ }
7072 }
73+
74+ logTransaction(
75+ txId,
76+ transactionNames[code] ? : " unknown code=$code " ,
77+ callingUid,
78+ callingPid,
79+ true ,
80+ )
81+
7182 return TransactionResult .ContinueAndSkipPost
7283 }
7384
@@ -94,6 +105,41 @@ class KeyMintSecurityLevelInterceptor(
94105 data.readTypedObject(KeyDescriptor .CREATOR )
95106 ? : return TransactionResult .SkipTransaction
96107 cleanupKeyData(KeyIdentifier (callingUid, keyDescriptor.alias))
108+ } else if (code == CREATE_OPERATION_TRANSACTION ) {
109+ logTransaction(txId, " post-${transactionNames[code]!! } " , callingUid, callingPid)
110+
111+ data.enforceInterface(IKeystoreSecurityLevel .DESCRIPTOR )
112+ val keyDescriptor = data.readTypedObject(KeyDescriptor .CREATOR )!!
113+ val params = data.createTypedArray(KeyParameter .CREATOR )!!
114+ val parsedParams = KeyMintAttestation (params)
115+ val forced = data.readBoolean()
116+ if (forced)
117+ SystemLogger .verbose(
118+ " [TX_ID: $txId ] Current operation has a very high pruning power."
119+ )
120+ val response: CreateOperationResponse =
121+ reply.readTypedObject(CreateOperationResponse .CREATOR )!!
122+ SystemLogger .verbose(
123+ " [TX_ID: $txId ] CreateOperationResponse: ${response.iOperation} ${response.operationChallenge} "
124+ )
125+
126+ // Intercept the IKeystoreOperation binder
127+ response.iOperation?.let { operation ->
128+ val operationBinder = operation.asBinder()
129+ if (! interceptedOperations.containsKey(operationBinder)) {
130+ SystemLogger .info(" Found new IKeystoreOperation. Registering interceptor..." )
131+ val backdoor = getBackdoor(target)
132+ if (backdoor != null ) {
133+ val interceptor = OperationInterceptor (operation, backdoor)
134+ register(backdoor, operationBinder, interceptor)
135+ interceptedOperations[operationBinder] = interceptor
136+ } else {
137+ SystemLogger .error(
138+ " Failed to get backdoor to register OperationInterceptor."
139+ )
140+ }
141+ }
142+ }
97143 } else if (code == GENERATE_KEY_TRANSACTION ) {
98144 logTransaction(txId, " post-${transactionNames[code]!! } " , callingUid, callingPid)
99145
@@ -109,9 +155,12 @@ class KeyMintSecurityLevelInterceptor(
109155 // Cache the newly patched chain to ensure consistency across subsequent API calls.
110156 data.enforceInterface(IKeystoreSecurityLevel .DESCRIPTOR )
111157 val keyDescriptor = data.readTypedObject(KeyDescriptor .CREATOR )!!
158+ val key = metadata.key!!
112159 val keyId = KeyIdentifier (callingUid, keyDescriptor.alias)
113160 patchedChains[keyId] = newChain
114- SystemLogger .debug(" Cached patched certificate chain for $keyId ." )
161+ SystemLogger .debug(
162+ " Cached patched certificate chain for $keyId . (${key.alias} [${key.domain} , ${key.nspace} ])"
163+ )
115164
116165 CertificateHelper .updateCertificateChain(metadata, newChain).getOrThrow()
117166
@@ -121,12 +170,58 @@ class KeyMintSecurityLevelInterceptor(
121170 return TransactionResult .SkipTransaction
122171 }
123172
173+ /* *
174+ * Handles the `createOperation` transaction. It checks if the operation is for a key that was
175+ * generated in software. If so, it creates a software-based operation handler. Otherwise, it
176+ * lets the call proceed to the real hardware service.
177+ */
178+ private fun handleCreateOperation (
179+ txId : Long ,
180+ callingUid : Int ,
181+ data : Parcel ,
182+ ): TransactionResult {
183+ data.enforceInterface(IKeystoreSecurityLevel .DESCRIPTOR )
184+ val keyDescriptor = data.readTypedObject(KeyDescriptor .CREATOR )!!
185+
186+ // An operation must use the KEY_ID domain.
187+ if (keyDescriptor.domain != Domain .KEY_ID ) {
188+ return TransactionResult .ContinueAndSkipPost
189+ }
190+
191+ val nspace = keyDescriptor.nspace
192+ val generatedKeyInfo = findGeneratedKeyByKeyId(callingUid, nspace)
193+
194+ if (generatedKeyInfo == null ) {
195+ SystemLogger .debug(
196+ " [TX_ID: $txId ] Operation for unknown/hardware KeyId ($nspace ). Forwarding."
197+ )
198+ return TransactionResult .Continue
199+ }
200+
201+ SystemLogger .info(" [TX_ID: $txId ] Creating SOFTWARE operation for KeyId $nspace ." )
202+
203+ val params = data.createTypedArray(KeyParameter .CREATOR )!!
204+ val parsedParams = KeyMintAttestation (params)
205+
206+ val softwareOperation = SoftwareOperation (txId, generatedKeyInfo.keyPair, parsedParams)
207+ val operationBinder = SoftwareOperationBinder (softwareOperation)
208+
209+ val response =
210+ CreateOperationResponse ().apply {
211+ iOperation = operationBinder
212+ operationChallenge = null
213+ }
214+
215+ return InterceptorUtils .createTypedObjectReply(response)
216+ }
217+
124218 /* *
125219 * Handles the `generateKey` transaction. Based on the configuration for the calling UID, it
126220 * either generates a key in software or lets the call pass through to the hardware.
127221 */
128222 private fun handleGenerateKey (callingUid : Int , data : Parcel ): TransactionResult {
129223 return runCatching {
224+ data.enforceInterface(IKeystoreSecurityLevel .DESCRIPTOR )
130225 val keyDescriptor = data.readTypedObject(KeyDescriptor .CREATOR )!!
131226 val attestationKey = data.readTypedObject(KeyDescriptor .CREATOR )
132227 SystemLogger .debug(
@@ -148,7 +243,10 @@ class KeyMintSecurityLevelInterceptor(
148243 isAttestationKey(KeyIdentifier (callingUid, attestationKey.alias)))
149244
150245 if (needsSoftwareGeneration) {
151- SystemLogger .info(" Generating software key for ${keyId} ." )
246+ keyDescriptor.nspace = secureRandom.nextLong()
247+ SystemLogger .info(
248+ " Generating software key for ${keyDescriptor.alias} [${keyDescriptor.nspace} ]."
249+ )
152250
153251 // Generate the key pair and certificate chain.
154252 val keyData =
@@ -164,7 +262,8 @@ class KeyMintSecurityLevelInterceptor(
164262 val response =
165263 buildKeyEntryResponse(keyData.second, parsedParams, keyDescriptor)
166264
167- generatedKeys[keyId] = GeneratedKeyInfo (keyData.first, response)
265+ generatedKeys[keyId] =
266+ GeneratedKeyInfo (keyData.first, keyDescriptor.nspace, response)
168267 if (isAttestKeyRequest) attestationKeys.add(keyId)
169268
170269 // Return the metadata of our generated key, skipping the real hardware call.
@@ -205,11 +304,18 @@ class KeyMintSecurityLevelInterceptor(
205304 }
206305
207306 companion object {
307+ private val secureRandom = SecureRandom ()
308+
208309 // Transaction codes for IKeystoreSecurityLevel interface.
209310 private val GENERATE_KEY_TRANSACTION =
210311 InterceptorUtils .getTransactCode(IKeystoreSecurityLevel .Stub ::class .java, " generateKey" )
211312 private val IMPORT_KEY_TRANSACTION =
212313 InterceptorUtils .getTransactCode(IKeystoreSecurityLevel .Stub ::class .java, " importKey" )
314+ private val CREATE_OPERATION_TRANSACTION =
315+ InterceptorUtils .getTransactCode(
316+ IKeystoreSecurityLevel .Stub ::class .java,
317+ " createOperation" ,
318+ )
213319
214320 private val transactionNames: Map <Int , String > by lazy {
215321 IKeystoreSecurityLevel .Stub ::class
@@ -228,11 +334,30 @@ class KeyMintSecurityLevelInterceptor(
228334 private val patchedChains = ConcurrentHashMap <KeyIdentifier , Array <Certificate >>()
229335 // A set to quickly identify keys that were generated for attestation purposes.
230336 private val attestationKeys = ConcurrentHashMap .newKeySet<KeyIdentifier >()
337+ // Stores interceptors for active cryptographic operations.
338+ private val interceptedOperations = ConcurrentHashMap <IBinder , OperationInterceptor >()
231339
232340 // --- Public Accessors for Other Interceptors ---
233341 fun getGeneratedKeyResponse (keyId : KeyIdentifier ): KeyEntryResponse ? =
234342 generatedKeys[keyId]?.response
235343
344+ /* *
345+ * Finds a software-generated key by first filtering all known keys by the caller's UID, and
346+ * then matching the specific nspace.
347+ *
348+ * @param callingUid The UID of the process that initiated the createOperation call.
349+ * @param nspace The unique key identifier from the operation's KeyDescriptor.
350+ * @return The matching GeneratedKeyInfo if found, otherwise null.
351+ */
352+ private fun findGeneratedKeyByKeyId (callingUid : Int , nspace : Long ): GeneratedKeyInfo ? {
353+ // Iterate through all entries in the map to check both the key (for UID) and value (for
354+ // nspace).
355+ return generatedKeys.entries
356+ .filter { (keyIdentifier, _) -> keyIdentifier.uid == callingUid }
357+ .find { (_, info) -> info.nspace == nspace }
358+ ?.value
359+ }
360+
236361 fun getPatchedChain (keyId : KeyIdentifier ): Array <Certificate >? = patchedChains[keyId]
237362
238363 fun isAttestationKey (keyId : KeyIdentifier ): Boolean = attestationKeys.contains(keyId)
@@ -249,6 +374,15 @@ class KeyMintSecurityLevelInterceptor(
249374 }
250375 }
251376
377+ fun removeOperationInterceptor (operationBinder : IBinder , backdoor : IBinder ) {
378+ // Unregister from the native hook layer first.
379+ unregister(backdoor, operationBinder)
380+
381+ if (interceptedOperations.remove(operationBinder) != null ) {
382+ SystemLogger .debug(" Removed operation interceptor for binder: $operationBinder " )
383+ }
384+ }
385+
252386 // Clears all cached keys.
253387 fun clearAllGeneratedKeys (reason : String? = null) {
254388 val count = generatedKeys.size
0 commit comments