@@ -20,6 +20,7 @@ import java.security.SecureRandom
2020import java.security.cert.Certificate
2121import java.security.cert.CertificateFactory
2222import java.security.spec.PKCS8EncodedKeySpec
23+ import java.util.concurrent.CompletableFuture
2324import java.util.concurrent.ConcurrentHashMap
2425import java.util.concurrent.ConcurrentLinkedDeque
2526import java.util.concurrent.Executors
@@ -116,12 +117,6 @@ class KeyMintSecurityLevelInterceptor(
116117 reply : Parcel ? ,
117118 resultCode : Int ,
118119 ): TransactionResult {
119- if (code == GENERATE_KEY_TRANSACTION && hardwareKeygenTxIds.remove(txId)) {
120- val remaining = hardwareKeygenCount(callingUid).decrementAndGet()
121- SystemLogger .info(" [TX_ID: $txId ] PERMIT_RELEASED uid=$callingUid concurrent_remaining=$remaining result=${if (resultCode == 0 ) " OK" else " ERROR($resultCode )" } " )
122- }
123-
124- // We only care about successful transactions.
125120 if (resultCode != 0 || reply == null || InterceptorUtils .hasException(reply))
126121 return TransactionResult .SkipTransaction
127122
@@ -468,38 +463,23 @@ class KeyMintSecurityLevelInterceptor(
468463 val keyId = KeyIdentifier (callingUid, keyDescriptor.alias)
469464 val isAttestKeyRequest = parsedParams.isAttestKey()
470465
471- val needsSoftwareGeneration =
466+ val forceGenerate =
472467 ConfigurationManager .shouldGenerate(callingUid) ||
473468 (ConfigurationManager .shouldPatch(callingUid) && isAttestKeyRequest) ||
474469 (attestationKey != null &&
475470 isAttestationKey(KeyIdentifier (callingUid, attestationKey.alias)))
476471
477- if (needsSoftwareGeneration) {
478- return doSoftwareKeyGen(callingUid, keyDescriptor, attestationKey, parsedParams, keyId, isAttestKeyRequest)
479- } else if (parsedParams.attestationChallenge != null ) {
480- val windowUsed = hardwareKeygenWindowCount(callingUid)
481- val concurrentUsed = hardwareKeygenCount(callingUid).get()
472+ val isAuto = ConfigurationManager .isAutoMode(callingUid)
482473
483- // Sliding window rate limit
484- if (windowUsed >= MAX_HW_KEYGEN_PER_WINDOW ) {
485- SystemLogger .info(" [TX_ID: $txId ] RATE_LIMITED uid=$callingUid window=$windowUsed /$MAX_HW_KEYGEN_PER_WINDOW concurrent=$concurrentUsed → software fallback" )
486- return doSoftwareKeyGen(callingUid, keyDescriptor, attestationKey, parsedParams, keyId, isAttestKeyRequest)
487- }
488- // Concurrent cap
489- if (hardwareKeygenCount(callingUid).incrementAndGet() > MAX_CONCURRENT_HW_KEYGEN_PER_UID ) {
490- hardwareKeygenCount(callingUid).decrementAndGet()
491- SystemLogger .info(" [TX_ID: $txId ] CONCURRENT_LIMITED uid=$callingUid window=$windowUsed /$MAX_HW_KEYGEN_PER_WINDOW concurrent=${concurrentUsed + 1 } /$MAX_CONCURRENT_HW_KEYGEN_PER_UID → software fallback" )
492- return doSoftwareKeyGen(callingUid, keyDescriptor, attestationKey, parsedParams, keyId, isAttestKeyRequest)
474+ when {
475+ forceGenerate -> doSoftwareKeyGen(callingUid, keyDescriptor, attestationKey, parsedParams, keyId, isAttestKeyRequest)
476+ isAuto && ! teeFunctional -> raceTeePatch(callingUid, keyDescriptor, attestationKey, params, parsedParams, keyId, isAttestKeyRequest)
477+ parsedParams.attestationChallenge != null -> TransactionResult .Continue
478+ else -> {
479+ cleanupKeyData(keyId)
480+ TransactionResult .ContinueAndSkipPost
493481 }
494- // Both checks passed — commit the window permit and forward to hardware TEE
495- recordHardwareKeygen(callingUid)
496- hardwareKeygenTxIds.add(txId)
497- SystemLogger .info(" [TX_ID: $txId ] HARDWARE_KEYGEN uid=$callingUid window=${windowUsed + 1 } /$MAX_HW_KEYGEN_PER_WINDOW concurrent=${concurrentUsed + 1 } /$MAX_CONCURRENT_HW_KEYGEN_PER_UID → forwarding to TEE" )
498- return TransactionResult .Continue
499482 }
500-
501- cleanupKeyData(keyId)
502- TransactionResult .ContinueAndSkipPost
503483 }
504484 .getOrElse {
505485 SystemLogger .error(" Error during generateKey handling for UID $callingUid ." , it)
@@ -608,6 +588,85 @@ class KeyMintSecurityLevelInterceptor(
608588 return InterceptorUtils .createTypedObjectReply(response.metadata)
609589 }
610590
591+ private fun raceTeePatch (
592+ callingUid : Int ,
593+ keyDescriptor : KeyDescriptor ,
594+ attestationKey : KeyDescriptor ? ,
595+ rawParams : Array <KeyParameter >,
596+ parsedParams : KeyMintAttestation ,
597+ keyId : KeyIdentifier ,
598+ isAttestKeyRequest : Boolean ,
599+ ): TransactionResult {
600+ SystemLogger .info(" AUTO: racing TEE vs software for ${keyDescriptor.alias} " )
601+
602+ val teeDescriptor = KeyDescriptor ().apply {
603+ domain = keyDescriptor.domain
604+ nspace = keyDescriptor.nspace
605+ alias = keyDescriptor.alias
606+ blob = keyDescriptor.blob
607+ }
608+ val teeAttestKey = attestationKey?.let {
609+ KeyDescriptor ().apply {
610+ domain = it.domain
611+ nspace = it.nspace
612+ alias = it.alias
613+ blob = it.blob
614+ }
615+ }
616+
617+ val threadA = CompletableFuture .supplyAsync {
618+ original.generateKey(teeDescriptor, teeAttestKey, rawParams, 0 , byteArrayOf())
619+ }
620+
621+ val swDescriptor = KeyDescriptor ().apply {
622+ domain = keyDescriptor.domain
623+ nspace = secureRandom.nextLong()
624+ alias = keyDescriptor.alias
625+ blob = keyDescriptor.blob
626+ }
627+ val swKeyId = KeyIdentifier (callingUid, keyDescriptor.alias)
628+
629+ val threadB = CompletableFuture .supplyAsync {
630+ doSoftwareKeyGen(callingUid, swDescriptor, attestationKey, parsedParams, swKeyId, isAttestKeyRequest)
631+ }
632+
633+ return try {
634+ val teeMetadata = threadA.join()
635+ threadB.cancel(true )
636+ teeFunctional = true
637+ SystemLogger .info(" AUTO: TEE succeeded for ${keyDescriptor.alias} , marked functional." )
638+
639+ val originalChain = CertificateHelper .getCertificateChain(teeMetadata)
640+ if (originalChain != null && originalChain.size > 1 ) {
641+ val newChain = AttestationPatcher .patchCertificateChain(originalChain, callingUid)
642+ CertificateHelper .updateCertificateChain(teeMetadata, newChain).getOrThrow()
643+ teeMetadata.authorizations =
644+ InterceptorUtils .patchAuthorizations(teeMetadata.authorizations, callingUid)
645+ cleanupKeyData(keyId)
646+ patchedChains[keyId] = newChain
647+ }
648+
649+ teeResponses[keyId] = KeyEntryResponse ().apply {
650+ this .metadata = teeMetadata
651+ iSecurityLevel = original
652+ }
653+
654+ InterceptorUtils .createTypedObjectReply(teeMetadata)
655+ } catch (_: Exception ) {
656+ SystemLogger .info(" AUTO: TEE failed for ${keyDescriptor.alias} , using software result." )
657+ try {
658+ threadB.join()
659+ } catch (e: Exception ) {
660+ SystemLogger .error(" AUTO: both paths failed for ${keyDescriptor.alias} ." , e)
661+ val code =
662+ if (e.cause is android.os.ServiceSpecificException )
663+ (e.cause as android.os.ServiceSpecificException ).errorCode
664+ else SECURE_HW_COMMUNICATION_FAILED
665+ InterceptorUtils .createServiceSpecificErrorReply(code)
666+ }
667+ }
668+ }
669+
611670 private fun generateAttestedKeyPairNative (
612671 callingUid : Int ,
613672 params : KeyMintAttestation ,
@@ -811,6 +870,7 @@ class KeyMintSecurityLevelInterceptor(
811870
812871 companion object {
813872 private val secureRandom = SecureRandom ()
873+ @Volatile var teeFunctional = false
814874
815875 // Maximum alias length to prevent binder buffer exhaustion (Issue #109)
816876 // Binder buffer is ~1MB; 256KB provides 4x safety margin for transaction overhead
@@ -830,43 +890,12 @@ class KeyMintSecurityLevelInterceptor(
830890 private const val MAX_CONCURRENT_OPS_PER_UID = 15
831891 private const val STRONGBOX_MAX_CONCURRENT_OPS = 4
832892 private const val STRONGBOX_OP_WINDOW_NS = 10_000_000_000L // 10s
833- private const val MAX_CONCURRENT_HW_KEYGEN_PER_UID = 2
834- // Sliding window: max hardware keygen permits per UID within the burst window
835- private const val MAX_HW_KEYGEN_PER_WINDOW = 2
836- private const val BURST_WINDOW_MS = 30_000L
837- private val uidHardwareKeygenCount = ConcurrentHashMap <Int , AtomicInteger >()
838- private val hardwareKeygenTxIds = ConcurrentHashMap .newKeySet<Long >()
839- private val uidKeygenTimestamps = ConcurrentHashMap <Int , MutableList <Long >>()
840-
841893 private fun isStrongBoxCapable (params : KeyMintAttestation ): Boolean = when (params.algorithm) {
842894 Algorithm .RSA -> params.keySize <= 2048
843895 Algorithm .EC -> params.ecCurve == null || params.ecCurve == EcCurve .P_256
844896 else -> true
845897 }
846898
847- private fun hardwareKeygenCount (uid : Int ): AtomicInteger =
848- uidHardwareKeygenCount.computeIfAbsent(uid) { AtomicInteger (0 ) }
849-
850- private fun hardwareKeygenWindowCount (uid : Int ): Int {
851- val now = System .currentTimeMillis()
852- val timestamps = uidKeygenTimestamps.computeIfAbsent(uid) { mutableListOf () }
853- synchronized(timestamps) {
854- timestamps.removeAll { now - it > BURST_WINDOW_MS }
855- if (timestamps.isEmpty()) {
856- uidKeygenTimestamps.remove(uid, timestamps)
857- uidHardwareKeygenCount.remove(uid)
858- }
859- return timestamps.size
860- }
861- }
862-
863- private fun recordHardwareKeygen (uid : Int ) {
864- val timestamps = uidKeygenTimestamps.computeIfAbsent(uid) { mutableListOf () }
865- synchronized(timestamps) {
866- timestamps.add(System .currentTimeMillis())
867- }
868- }
869-
870899 private val GENERATE_KEY_TRANSACTION =
871900 InterceptorUtils .getTransactCode(IKeystoreSecurityLevel .Stub ::class .java, " generateKey" )
872901 private val IMPORT_KEY_TRANSACTION =
0 commit comments