Compare commits
15
Commits
v6.0.0-222
...
v6.0.0-235
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
134d5111ad | ||
|
|
4c801f2089 | ||
|
|
afc5caeb1b | ||
|
|
0e9ea10b50 | ||
|
|
6ae5ea391c | ||
|
|
f554b36416 | ||
|
|
684542f4b1 | ||
|
|
240728f98d | ||
|
|
95b8c27a9f | ||
|
|
66a8c7fbf8 | ||
|
|
36c93decc6 | ||
|
|
55e39c7f01 | ||
|
|
44816c1a8d | ||
|
|
60b6ec64c2 | ||
|
|
2f21cd57a0 |
@@ -116,12 +116,21 @@ object InterceptorUtils {
|
|||||||
fun <T : Parcelable?> createTypedObjectReply(
|
fun <T : Parcelable?> createTypedObjectReply(
|
||||||
obj: T,
|
obj: T,
|
||||||
flags: Int = 0,
|
flags: Int = 0,
|
||||||
|
diagnosticTag: String? = null,
|
||||||
): BinderInterceptor.TransactionResult.OverrideReply {
|
): BinderInterceptor.TransactionResult.OverrideReply {
|
||||||
val parcel =
|
val parcel =
|
||||||
Parcel.obtain().apply {
|
Parcel.obtain().apply {
|
||||||
writeNoException()
|
writeNoException()
|
||||||
writeTypedObject(obj, flags)
|
writeTypedObject(obj, flags)
|
||||||
}
|
}
|
||||||
|
if (diagnosticTag != null && SystemLogger.isDebugBuild) {
|
||||||
|
val savedPos = parcel.dataPosition()
|
||||||
|
val wire = parcel.marshall()
|
||||||
|
parcel.setDataPosition(savedPos)
|
||||||
|
val path = "/data/local/tmp/teesim-$diagnosticTag-${System.nanoTime()}.bin"
|
||||||
|
runCatching { java.io.File(path).writeBytes(wire) }
|
||||||
|
SystemLogger.debug("[$diagnosticTag] reply len=${wire.size} path=$path")
|
||||||
|
}
|
||||||
return BinderInterceptor.TransactionResult.OverrideReply(parcel)
|
return BinderInterceptor.TransactionResult.OverrideReply(parcel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+38
-114
@@ -21,12 +21,10 @@ import java.security.cert.Certificate
|
|||||||
import java.security.cert.CertificateFactory
|
import java.security.cert.CertificateFactory
|
||||||
import java.security.spec.PKCS8EncodedKeySpec
|
import java.security.spec.PKCS8EncodedKeySpec
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.concurrent.CompletableFuture
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.concurrent.ConcurrentLinkedDeque
|
import java.util.concurrent.ConcurrentLinkedDeque
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
|
||||||
import java.util.concurrent.locks.LockSupport
|
import java.util.concurrent.locks.LockSupport
|
||||||
import org.matrix.TEESimulator.attestation.AttestationBuilder
|
import org.matrix.TEESimulator.attestation.AttestationBuilder
|
||||||
import org.matrix.TEESimulator.attestation.AttestationConstants
|
import org.matrix.TEESimulator.attestation.AttestationConstants
|
||||||
@@ -60,10 +58,6 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
val keyParams: KeyMintAttestation? = null,
|
val keyParams: KeyMintAttestation? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
// null = undecided, true = TEE works (use PATCH), false = TEE broken (use GENERATE)
|
|
||||||
// Instance field so TRUSTED_ENVIRONMENT and STRONGBOX decide independently
|
|
||||||
val teePathDecision = AtomicReference<Boolean?>(null)
|
|
||||||
|
|
||||||
private val activeOps = ConcurrentHashMap<Int, ConcurrentLinkedDeque<SoftwareOperation>>()
|
private val activeOps = ConcurrentHashMap<Int, ConcurrentLinkedDeque<SoftwareOperation>>()
|
||||||
private val recentOps = ConcurrentHashMap<Int, ConcurrentLinkedDeque<Long>>()
|
private val recentOps = ConcurrentHashMap<Int, ConcurrentLinkedDeque<Long>>()
|
||||||
|
|
||||||
@@ -76,18 +70,16 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
callingPid: Int,
|
callingPid: Int,
|
||||||
data: Parcel,
|
data: Parcel,
|
||||||
): TransactionResult {
|
): TransactionResult {
|
||||||
val shouldSkip = ConfigurationManager.shouldSkipUid(callingUid)
|
|
||||||
|
|
||||||
when (code) {
|
when (code) {
|
||||||
GENERATE_KEY_TRANSACTION -> {
|
GENERATE_KEY_TRANSACTION -> {
|
||||||
logTransaction(txId, transactionNames[code]!!, callingUid, callingPid)
|
logTransaction(txId, transactionNames[code]!!, callingUid, callingPid)
|
||||||
|
|
||||||
if (!shouldSkip) return handleGenerateKey(txId, callingUid, callingPid, data)
|
return handleGenerateKey(txId, callingUid, callingPid, data)
|
||||||
}
|
}
|
||||||
CREATE_OPERATION_TRANSACTION -> {
|
CREATE_OPERATION_TRANSACTION -> {
|
||||||
logTransaction(txId, transactionNames[code]!!, callingUid, callingPid)
|
logTransaction(txId, transactionNames[code]!!, callingUid, callingPid)
|
||||||
|
|
||||||
if (!shouldSkip) return handleCreateOperation(txId, callingUid, data)
|
return handleCreateOperation(txId, callingUid, data)
|
||||||
}
|
}
|
||||||
IMPORT_KEY_TRANSACTION -> {
|
IMPORT_KEY_TRANSACTION -> {
|
||||||
logTransaction(txId, transactionNames[code]!!, callingUid, callingPid)
|
logTransaction(txId, transactionNames[code]!!, callingUid, callingPid)
|
||||||
@@ -424,6 +416,14 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleGenerateKey(txId: Long, callingUid: Int, callingPid: Int, data: Parcel): TransactionResult {
|
private fun handleGenerateKey(txId: Long, callingUid: Int, callingPid: Int, data: Parcel): TransactionResult {
|
||||||
|
if (SystemLogger.isDebugBuild) {
|
||||||
|
val savedPos = data.dataPosition()
|
||||||
|
val req = data.marshall()
|
||||||
|
data.setDataPosition(savedPos)
|
||||||
|
val path = "/data/local/tmp/teesim-gen-mode-req-uid${callingUid}-tx${txId}-${System.nanoTime()}.bin"
|
||||||
|
runCatching { java.io.File(path).writeBytes(req) }
|
||||||
|
SystemLogger.debug("[gen-mode-req] uid=$callingUid txId=$txId len=${req.size} path=$path")
|
||||||
|
}
|
||||||
val oversized = data.dataSize() > MAX_ALIAS_LENGTH
|
val oversized = data.dataSize() > MAX_ALIAS_LENGTH
|
||||||
|
|
||||||
return runCatching {
|
return runCatching {
|
||||||
@@ -436,6 +436,12 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
)
|
)
|
||||||
val params = data.createTypedArray(KeyParameter.CREATOR)!!
|
val params = data.createTypedArray(KeyParameter.CREATOR)!!
|
||||||
val parsedParams = KeyMintAttestation(params)
|
val parsedParams = KeyMintAttestation(params)
|
||||||
|
val isAttestKeyRequest = parsedParams.isAttestKey()
|
||||||
|
|
||||||
|
if (ConfigurationManager.shouldSkipUid(callingUid)
|
||||||
|
&& attestationKey == null && !isAttestKeyRequest) {
|
||||||
|
return TransactionResult.ContinueAndSkipPost
|
||||||
|
}
|
||||||
|
|
||||||
SystemLogger.trace { "[TRACE-$txId] generateKey alias=${keyDescriptor.alias} algo=${parsedParams.algorithm} challenge=${parsedParams.attestationChallenge?.size ?: "null"} serial=${parsedParams.serial != null} imei=${parsedParams.imei != null} noAuth=${parsedParams.noAuthRequired} purposes=${parsedParams.purpose}" }
|
SystemLogger.trace { "[TRACE-$txId] generateKey alias=${keyDescriptor.alias} algo=${parsedParams.algorithm} challenge=${parsedParams.attestationChallenge?.size ?: "null"} serial=${parsedParams.serial != null} imei=${parsedParams.imei != null} noAuth=${parsedParams.noAuthRequired} purposes=${parsedParams.purpose}" }
|
||||||
if (SystemLogger.isDebugBuild) params.forEach { p ->
|
if (SystemLogger.isDebugBuild) params.forEach { p ->
|
||||||
@@ -496,26 +502,17 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val keyId = KeyIdentifier(callingUid, keyDescriptor.alias)
|
val keyId = KeyIdentifier(callingUid, keyDescriptor.alias)
|
||||||
val isAttestKeyRequest = parsedParams.isAttestKey()
|
|
||||||
|
|
||||||
val forceGenerate =
|
val forceGenerate =
|
||||||
oversized ||
|
oversized ||
|
||||||
ConfigurationManager.shouldGenerate(callingUid) ||
|
ConfigurationManager.shouldGenerate(callingUid) ||
|
||||||
(ConfigurationManager.shouldPatch(callingUid) && isAttestKeyRequest) ||
|
isAttestKeyRequest ||
|
||||||
(attestationKey != null &&
|
attestationKey != null
|
||||||
(attestationKey.alias?.let { isAttestationKey(KeyIdentifier(callingUid, it)) }
|
|
||||||
?: attestationKeys.any { kid -> kid.uid == callingUid && generatedKeys[kid]?.nspace == attestationKey.nspace }))
|
|
||||||
|
|
||||||
val isAuto = ConfigurationManager.isAutoMode(callingUid)
|
SystemLogger.trace { "[TRACE-$txId] dispatch: forceGen=$forceGenerate hasChallenge=${challenge != null} isSymmetric=$isSymmetric isAttestKey=$isAttestKeyRequest" }
|
||||||
|
|
||||||
if (isAuto) SystemLogger.debug("AUTO dispatch: teePathDecision=${teePathDecision.get()} for ${keyDescriptor.alias}")
|
|
||||||
|
|
||||||
SystemLogger.trace { "[TRACE-$txId] dispatch: forceGen=$forceGenerate isAuto=$isAuto teePath=${teePathDecision.get()} hasChallenge=${challenge != null} isSymmetric=$isSymmetric isAttestKey=$isAttestKeyRequest" }
|
|
||||||
|
|
||||||
when {
|
when {
|
||||||
forceGenerate -> doSoftwareKeyGen(callingUid, keyDescriptor, attestationKey, parsedParams, keyId, isAttestKeyRequest)
|
forceGenerate -> doSoftwareKeyGen(callingUid, keyDescriptor, attestationKey, parsedParams, keyId, isAttestKeyRequest)
|
||||||
isAuto && teePathDecision.get() == null -> raceTeePatch(callingUid, keyDescriptor, attestationKey, params, parsedParams, keyId, isAttestKeyRequest)
|
|
||||||
isAuto && teePathDecision.get() == false -> doSoftwareKeyGen(callingUid, keyDescriptor, attestationKey, parsedParams, keyId, isAttestKeyRequest)
|
|
||||||
parsedParams.attestationChallenge != null -> TransactionResult.Continue
|
parsedParams.attestationChallenge != null -> TransactionResult.Continue
|
||||||
else -> {
|
else -> {
|
||||||
cleanupKeyData(keyId)
|
cleanupKeyData(keyId)
|
||||||
@@ -547,11 +544,17 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
parsedParams.algorithm != Algorithm.RSA
|
parsedParams.algorithm != Algorithm.RSA
|
||||||
|
|
||||||
if (isSymmetric) {
|
if (isSymmetric) {
|
||||||
|
if (attestationKey != null) {
|
||||||
|
throw android.os.ServiceSpecificException(
|
||||||
|
KEYMINT_INVALID_ARGUMENT,
|
||||||
|
"ATTEST_KEY tag is not supported for symmetric algorithms (algo=${parsedParams.algorithm})",
|
||||||
|
)
|
||||||
|
}
|
||||||
val algoName = when (parsedParams.algorithm) {
|
val algoName = when (parsedParams.algorithm) {
|
||||||
Algorithm.AES -> "AES"
|
Algorithm.AES -> "AES"
|
||||||
Algorithm.HMAC -> "HmacSHA256"
|
Algorithm.HMAC -> "HmacSHA256"
|
||||||
else -> throw android.os.ServiceSpecificException(
|
else -> throw android.os.ServiceSpecificException(
|
||||||
SECURE_HW_COMMUNICATION_FAILED,
|
KEYMINT_INVALID_ARGUMENT,
|
||||||
"Unsupported symmetric algorithm: ${parsedParams.algorithm}",
|
"Unsupported symmetric algorithm: ${parsedParams.algorithm}",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -620,7 +623,7 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
TeeLatencySimulator.simulateGenerateKeyDelay(parsedParams.algorithm, System.nanoTime() - genStartNanos)
|
TeeLatencySimulator.simulateGenerateKeyDelay(parsedParams.algorithm, System.nanoTime() - genStartNanos)
|
||||||
}
|
}
|
||||||
|
|
||||||
return InterceptorUtils.createTypedObjectReply(metadata)
|
return InterceptorUtils.createTypedObjectReply(metadata, diagnosticTag = "gen-mode-sym")
|
||||||
}
|
}
|
||||||
|
|
||||||
val keyData = if (NativeCertGen.isAvailable && attestationKey == null) {
|
val keyData = if (NativeCertGen.isAvailable && attestationKey == null) {
|
||||||
@@ -693,94 +696,7 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
TeeLatencySimulator.simulateGenerateKeyDelay(parsedParams.algorithm, System.nanoTime() - genStartNanos)
|
TeeLatencySimulator.simulateGenerateKeyDelay(parsedParams.algorithm, System.nanoTime() - genStartNanos)
|
||||||
}
|
}
|
||||||
|
|
||||||
return InterceptorUtils.createTypedObjectReply(response.metadata)
|
return InterceptorUtils.createTypedObjectReply(response.metadata, diagnosticTag = "gen-mode-asym")
|
||||||
}
|
|
||||||
|
|
||||||
private fun raceTeePatch(
|
|
||||||
callingUid: Int,
|
|
||||||
keyDescriptor: KeyDescriptor,
|
|
||||||
attestationKey: KeyDescriptor?,
|
|
||||||
rawParams: Array<KeyParameter>,
|
|
||||||
parsedParams: KeyMintAttestation,
|
|
||||||
keyId: KeyIdentifier,
|
|
||||||
isAttestKeyRequest: Boolean,
|
|
||||||
): TransactionResult {
|
|
||||||
SystemLogger.info("AUTO: racing TEE vs software for ${keyDescriptor.alias}")
|
|
||||||
|
|
||||||
val teeDescriptor = KeyDescriptor().apply {
|
|
||||||
domain = keyDescriptor.domain
|
|
||||||
nspace = keyDescriptor.nspace
|
|
||||||
alias = keyDescriptor.alias
|
|
||||||
blob = keyDescriptor.blob
|
|
||||||
}
|
|
||||||
val teeAttestKey = attestationKey?.let {
|
|
||||||
KeyDescriptor().apply {
|
|
||||||
domain = it.domain
|
|
||||||
nspace = it.nspace
|
|
||||||
alias = it.alias
|
|
||||||
blob = it.blob
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val threadA = CompletableFuture.supplyAsync {
|
|
||||||
original.generateKey(teeDescriptor, teeAttestKey, rawParams, 0, byteArrayOf())
|
|
||||||
}
|
|
||||||
|
|
||||||
val swDescriptor = KeyDescriptor().apply {
|
|
||||||
domain = keyDescriptor.domain
|
|
||||||
nspace = secureRandom.nextLong()
|
|
||||||
alias = keyDescriptor.alias
|
|
||||||
blob = keyDescriptor.blob
|
|
||||||
}
|
|
||||||
val swKeyId = KeyIdentifier(callingUid, keyDescriptor.alias)
|
|
||||||
|
|
||||||
val threadB = CompletableFuture.supplyAsync {
|
|
||||||
doSoftwareKeyGen(callingUid, swDescriptor, attestationKey, parsedParams, swKeyId, isAttestKeyRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
return try {
|
|
||||||
val teeMetadata = threadA.join()
|
|
||||||
threadB.cancel(true)
|
|
||||||
teePathDecision.compareAndSet(null, true)
|
|
||||||
SystemLogger.info("AUTO: TEE succeeded, path locked to PATCH for ${keyDescriptor.alias}")
|
|
||||||
|
|
||||||
val originalChain = CertificateHelper.getCertificateChain(teeMetadata)
|
|
||||||
if (originalChain != null && originalChain.size > 1) {
|
|
||||||
val newChain = AttestationPatcher.patchCertificateChain(
|
|
||||||
originalChain, callingUid, parsedParams.certificateNotBefore, parsedParams.certificateNotAfter
|
|
||||||
)
|
|
||||||
CertificateHelper.updateCertificateChain(teeMetadata, newChain).getOrThrow()
|
|
||||||
teeMetadata.authorizations =
|
|
||||||
InterceptorUtils.patchAuthorizations(teeMetadata.authorizations, callingUid)
|
|
||||||
cleanupKeyData(keyId)
|
|
||||||
patchedChains[keyId] = newChain
|
|
||||||
}
|
|
||||||
|
|
||||||
teeResponses[keyId] = KeyEntryResponse().apply {
|
|
||||||
this.metadata = teeMetadata
|
|
||||||
iSecurityLevel = original
|
|
||||||
}
|
|
||||||
|
|
||||||
InterceptorUtils.createTypedObjectReply(teeMetadata)
|
|
||||||
} catch (_: Exception) {
|
|
||||||
if (teePathDecision.get() == true) {
|
|
||||||
threadB.cancel(true)
|
|
||||||
SystemLogger.info("AUTO: TEE failed locally but globally functional, forwarding for ${keyDescriptor.alias}")
|
|
||||||
return TransactionResult.Continue
|
|
||||||
}
|
|
||||||
teePathDecision.compareAndSet(null, false)
|
|
||||||
SystemLogger.info("AUTO: TEE failed, path locked to GENERATE for ${keyDescriptor.alias}")
|
|
||||||
try {
|
|
||||||
threadB.join()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
SystemLogger.error("AUTO: both paths failed for ${keyDescriptor.alias}.", e)
|
|
||||||
val code =
|
|
||||||
if (e.cause is android.os.ServiceSpecificException)
|
|
||||||
(e.cause as android.os.ServiceSpecificException).errorCode
|
|
||||||
else SECURE_HW_COMMUNICATION_FAILED
|
|
||||||
InterceptorUtils.createServiceSpecificErrorReply(code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateAttestedKeyPairNative(
|
private fun generateAttestedKeyPairNative(
|
||||||
@@ -1329,15 +1245,23 @@ private fun KeyMintAttestation.toAuthorizations(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HAL-enforced authorization ordering mirrors AOSP keymint reference
|
||||||
|
// HAL output: PURPOSE → ALGORITHM → KEY_SIZE → curve → mode params →
|
||||||
|
// exponent. Duck-Detector's generate-mode fingerprint walks the reply
|
||||||
|
// parcel at 12-byte parser strides and matches when slot[count-1] reads
|
||||||
|
// (secLevel=256, tag=1, unionTag=32) — which emerges in the original
|
||||||
|
// order because EC P-256's KEY_SIZE.value=256 lands at byte 224 (auth#4
|
||||||
|
// value field). Reordering moves KEY_SIZE to auth#2, so byte 224 reads
|
||||||
|
// a different field entirely.
|
||||||
|
this.purpose.forEach { authList.add(createAuth(Tag.PURPOSE, KeyParameterValue.keyPurpose(it))) }
|
||||||
authList.add(createAuth(Tag.ALGORITHM, KeyParameterValue.algorithm(this.algorithm)))
|
authList.add(createAuth(Tag.ALGORITHM, KeyParameterValue.algorithm(this.algorithm)))
|
||||||
|
authList.add(createAuth(Tag.KEY_SIZE, KeyParameterValue.integer(this.keySize)))
|
||||||
if (this.ecCurve != null) {
|
if (this.ecCurve != null) {
|
||||||
authList.add(createAuth(Tag.EC_CURVE, KeyParameterValue.ecCurve(this.ecCurve)))
|
authList.add(createAuth(Tag.EC_CURVE, KeyParameterValue.ecCurve(this.ecCurve)))
|
||||||
}
|
}
|
||||||
this.purpose.forEach { authList.add(createAuth(Tag.PURPOSE, KeyParameterValue.keyPurpose(it))) }
|
|
||||||
this.blockMode.forEach { authList.add(createAuth(Tag.BLOCK_MODE, KeyParameterValue.blockMode(it))) }
|
this.blockMode.forEach { authList.add(createAuth(Tag.BLOCK_MODE, KeyParameterValue.blockMode(it))) }
|
||||||
this.digest.forEach { authList.add(createAuth(Tag.DIGEST, KeyParameterValue.digest(it))) }
|
this.digest.forEach { authList.add(createAuth(Tag.DIGEST, KeyParameterValue.digest(it))) }
|
||||||
this.padding.forEach { authList.add(createAuth(Tag.PADDING, KeyParameterValue.paddingMode(it))) }
|
this.padding.forEach { authList.add(createAuth(Tag.PADDING, KeyParameterValue.paddingMode(it))) }
|
||||||
authList.add(createAuth(Tag.KEY_SIZE, KeyParameterValue.integer(this.keySize)))
|
|
||||||
if (this.rsaPublicExponent != null) {
|
if (this.rsaPublicExponent != null) {
|
||||||
authList.add(createAuth(Tag.RSA_PUBLIC_EXPONENT, KeyParameterValue.longInteger(this.rsaPublicExponent.toLong())))
|
authList.add(createAuth(Tag.RSA_PUBLIC_EXPONENT, KeyParameterValue.longInteger(this.rsaPublicExponent.toLong())))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,18 +101,19 @@ object CertificateGenerator {
|
|||||||
|
|
||||||
val keybox = getKeyboxForAlgorithm(uid, params.algorithm)
|
val keybox = getKeyboxForAlgorithm(uid, params.algorithm)
|
||||||
|
|
||||||
val (signingKey, issuer) =
|
val attestKeyInfo =
|
||||||
if (attestKeyAlias != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if (attestKeyAlias != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
getAttestationKeyInfo(uid, attestKeyAlias)?.let { it.first to it.second }
|
getAttestationKeyInfo(uid, attestKeyAlias)
|
||||||
?: (keybox.keyPair to getIssuerFromKeybox(keybox))
|
} else null
|
||||||
} else {
|
|
||||||
keybox.keyPair to getIssuerFromKeybox(keybox)
|
val (signingKey, issuer) = attestKeyInfo
|
||||||
}
|
?.let { it.first to it.second }
|
||||||
|
?: (keybox.keyPair to getIssuerFromKeybox(keybox))
|
||||||
|
|
||||||
val leafCert =
|
val leafCert =
|
||||||
buildCertificate(subjectKeyPair, signingKey, issuer, params, uid, securityLevel)
|
buildCertificate(subjectKeyPair, signingKey, issuer, params, uid, securityLevel)
|
||||||
|
|
||||||
if (attestKeyAlias != null) {
|
if (attestKeyInfo != null) {
|
||||||
listOf(leafCert)
|
listOf(leafCert)
|
||||||
} else {
|
} else {
|
||||||
listOf(leafCert) + keybox.certificates
|
listOf(leafCert) + keybox.certificates
|
||||||
|
|||||||
+44
-2
@@ -2,10 +2,52 @@
|
|||||||
MODDIR=${0%/*}
|
MODDIR=${0%/*}
|
||||||
CONFIG_DIR=/data/adb/tricky_store
|
CONFIG_DIR=/data/adb/tricky_store
|
||||||
|
|
||||||
|
. "$MODDIR/action_i18n.sh"
|
||||||
|
|
||||||
|
echo " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo " ⚠️ $(_msg confirm_header)"
|
||||||
|
echo " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo " "
|
||||||
|
echo " $(_msg confirm_warning_1)"
|
||||||
|
echo " $(_msg confirm_warning_2)"
|
||||||
|
echo " "
|
||||||
|
echo " 🔊 $(_msg confirm_vol_up)"
|
||||||
|
echo " 🔉 $(_msg confirm_vol_down)"
|
||||||
|
echo " "
|
||||||
|
|
||||||
|
confirm() {
|
||||||
|
vol_tmp="${TMPDIR:-/data/local/tmp}/teesim_vol_key"
|
||||||
|
: > "$vol_tmp"
|
||||||
|
|
||||||
|
# Stream getevent and match VOLUME DOWN inline. Single-event sampling
|
||||||
|
# (`getevent -c 1`) races with EV_SYN/EV_MSC noise on Magisk's BusyBox ash.
|
||||||
|
/system/bin/timeout 10 /system/bin/sh -c '
|
||||||
|
/system/bin/getevent -lq 2>/dev/null | while IFS= read -r line; do
|
||||||
|
case "$line" in
|
||||||
|
*KEY_VOLUMEUP*DOWN*) echo UP > "$1"; exit 0 ;;
|
||||||
|
*KEY_VOLUMEDOWN*DOWN*) echo DOWN > "$1"; exit 0 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
' _ "$vol_tmp"
|
||||||
|
|
||||||
|
key=$(cat "$vol_tmp" 2>/dev/null)
|
||||||
|
rm -f "$vol_tmp"
|
||||||
|
[ "$key" = "UP" ] && return 0
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! confirm; then
|
||||||
|
echo " "
|
||||||
|
echo " ❌ $(_msg confirm_cancelled)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -d "$CONFIG_DIR/persistent_keys" ]; then
|
if [ -d "$CONFIG_DIR/persistent_keys" ]; then
|
||||||
rm -rf "$CONFIG_DIR/persistent_keys"
|
rm -rf "$CONFIG_DIR/persistent_keys"
|
||||||
mkdir -p "$CONFIG_DIR/persistent_keys"
|
mkdir -p "$CONFIG_DIR/persistent_keys"
|
||||||
echo "Persistent key storage cleared"
|
echo " "
|
||||||
|
echo " ✅ $(_msg confirm_cleared)"
|
||||||
else
|
else
|
||||||
echo "No persistent key storage found"
|
echo " "
|
||||||
|
echo " ℹ️ $(_msg confirm_not_found)"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -0,0 +1,255 @@
|
|||||||
|
ACTION_LANG="en"
|
||||||
|
_detect_lang() {
|
||||||
|
local raw
|
||||||
|
raw=$(getprop persist.sys.locale 2>/dev/null)
|
||||||
|
[ -z "$raw" ] && raw=$(getprop ro.product.locale 2>/dev/null)
|
||||||
|
[ -z "$raw" ] && raw=$(getprop ro.system.locale 2>/dev/null)
|
||||||
|
local code=$(printf '%s' "$raw" | sed 's/_/-/g')
|
||||||
|
case "$code" in
|
||||||
|
zh-Hans*|zh-CN*) code="zh-CN" ;;
|
||||||
|
zh-Hant*|zh-TW*|zh-HK*) code="zh-TW" ;;
|
||||||
|
pt-BR*) code="pt-BR" ;;
|
||||||
|
pt*) code="pt-BR" ;;
|
||||||
|
es-ES*|es*) code="es-ES" ;;
|
||||||
|
*-*) code="${code%%-*}" ;;
|
||||||
|
esac
|
||||||
|
case "$code" in
|
||||||
|
ar|az|bn|de|el|es-ES|fa|fr|id|it|ja|ko|pl|pt-BR|ru|th|tl|tr|uk|vi|zh-CN|zh-TW) ACTION_LANG="$code" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
_detect_lang
|
||||||
|
|
||||||
|
_msg() {
|
||||||
|
case "$ACTION_LANG" in
|
||||||
|
zh-CN) case "$1" in
|
||||||
|
confirm_header) echo "清除持久化密钥存储" ;;
|
||||||
|
confirm_warning_1) echo "这将删除所有缓存的证明密钥。" ;;
|
||||||
|
confirm_warning_2) echo "使用证明的应用将在下次使用时重新注册。" ;;
|
||||||
|
confirm_vol_up) echo "音量+ = 确认清除" ;;
|
||||||
|
confirm_vol_down) echo "音量- = 取消(10秒后默认)" ;;
|
||||||
|
confirm_cancelled) echo "已取消 - 密钥已保留" ;;
|
||||||
|
confirm_cleared) echo "持久化密钥存储已清除" ;;
|
||||||
|
confirm_not_found) echo "未找到持久化密钥存储" ;;
|
||||||
|
esac ;;
|
||||||
|
zh-TW) case "$1" in
|
||||||
|
confirm_header) echo "清除持久化金鑰儲存" ;;
|
||||||
|
confirm_warning_1) echo "這將刪除所有快取的證明金鑰。" ;;
|
||||||
|
confirm_warning_2) echo "使用證明的應用程式將在下次使用時重新註冊。" ;;
|
||||||
|
confirm_vol_up) echo "音量+ = 確認清除" ;;
|
||||||
|
confirm_vol_down) echo "音量- = 取消(10秒後預設)" ;;
|
||||||
|
confirm_cancelled) echo "已取消 - 金鑰已保留" ;;
|
||||||
|
confirm_cleared) echo "持久化金鑰儲存已清除" ;;
|
||||||
|
confirm_not_found) echo "未找到持久化金鑰儲存" ;;
|
||||||
|
esac ;;
|
||||||
|
ja) case "$1" in
|
||||||
|
confirm_header) echo "永続キーストレージを消去" ;;
|
||||||
|
confirm_warning_1) echo "キャッシュされた証明キーをすべて削除します。" ;;
|
||||||
|
confirm_warning_2) echo "証明を使用するアプリは次回使用時に再登録されます。" ;;
|
||||||
|
confirm_vol_up) echo "音量+ = 消去を確認" ;;
|
||||||
|
confirm_vol_down) echo "音量- = キャンセル(10秒後デフォルト)" ;;
|
||||||
|
confirm_cancelled) echo "キャンセルされました - キーは保持されます" ;;
|
||||||
|
confirm_cleared) echo "永続キーストレージを消去しました" ;;
|
||||||
|
confirm_not_found) echo "永続キーストレージが見つかりません" ;;
|
||||||
|
esac ;;
|
||||||
|
ko) case "$1" in
|
||||||
|
confirm_header) echo "영구 키 저장소 지우기" ;;
|
||||||
|
confirm_warning_1) echo "캐시된 모든 증명 키를 삭제합니다." ;;
|
||||||
|
confirm_warning_2) echo "증명을 사용하는 앱은 다음 사용 시 재등록됩니다." ;;
|
||||||
|
confirm_vol_up) echo "볼륨+ = 지우기 확인" ;;
|
||||||
|
confirm_vol_down) echo "볼륨- = 취소 (10초 후 기본값)" ;;
|
||||||
|
confirm_cancelled) echo "취소됨 - 키 유지됨" ;;
|
||||||
|
confirm_cleared) echo "영구 키 저장소가 지워졌습니다" ;;
|
||||||
|
confirm_not_found) echo "영구 키 저장소를 찾을 수 없습니다" ;;
|
||||||
|
esac ;;
|
||||||
|
ru) case "$1" in
|
||||||
|
confirm_header) echo "Очистить постоянное хранилище ключей" ;;
|
||||||
|
confirm_warning_1) echo "Это удалит все кэшированные ключи аттестации." ;;
|
||||||
|
confirm_warning_2) echo "Приложения, использующие аттестацию, перерегистрируются при следующем использовании." ;;
|
||||||
|
confirm_vol_up) echo "Громкость+ = Подтвердить очистку" ;;
|
||||||
|
confirm_vol_down) echo "Громкость- = Отмена (по умолчанию через 10с)" ;;
|
||||||
|
confirm_cancelled) echo "Отменено - ключи сохранены" ;;
|
||||||
|
confirm_cleared) echo "Постоянное хранилище ключей очищено" ;;
|
||||||
|
confirm_not_found) echo "Постоянное хранилище ключей не найдено" ;;
|
||||||
|
esac ;;
|
||||||
|
de) case "$1" in
|
||||||
|
confirm_header) echo "Persistenten Schlüsselspeicher löschen" ;;
|
||||||
|
confirm_warning_1) echo "Dies löscht alle zwischengespeicherten Attestierungsschlüssel." ;;
|
||||||
|
confirm_warning_2) echo "Apps mit Attestierung registrieren sich bei der nächsten Nutzung neu." ;;
|
||||||
|
confirm_vol_up) echo "Laut+ = Löschen bestätigen" ;;
|
||||||
|
confirm_vol_down) echo "Leise- = Abbrechen (Standard nach 10s)" ;;
|
||||||
|
confirm_cancelled) echo "Abgebrochen - Schlüssel beibehalten" ;;
|
||||||
|
confirm_cleared) echo "Persistenter Schlüsselspeicher gelöscht" ;;
|
||||||
|
confirm_not_found) echo "Kein persistenter Schlüsselspeicher gefunden" ;;
|
||||||
|
esac ;;
|
||||||
|
fr) case "$1" in
|
||||||
|
confirm_header) echo "Effacer le stockage de clés persistant" ;;
|
||||||
|
confirm_warning_1) echo "Ceci supprime toutes les clés d'attestation en cache." ;;
|
||||||
|
confirm_warning_2) echo "Les apps utilisant l'attestation se réinscriront à la prochaine utilisation." ;;
|
||||||
|
confirm_vol_up) echo "Vol+ = Confirmer l'effacement" ;;
|
||||||
|
confirm_vol_down) echo "Vol- = Annuler (par défaut après 10s)" ;;
|
||||||
|
confirm_cancelled) echo "Annulé - clés conservées" ;;
|
||||||
|
confirm_cleared) echo "Stockage de clés persistant effacé" ;;
|
||||||
|
confirm_not_found) echo "Aucun stockage de clés persistant trouvé" ;;
|
||||||
|
esac ;;
|
||||||
|
es-ES) case "$1" in
|
||||||
|
confirm_header) echo "Borrar almacenamiento persistente de claves" ;;
|
||||||
|
confirm_warning_1) echo "Esto elimina todas las claves de atestación en caché." ;;
|
||||||
|
confirm_warning_2) echo "Las apps que usan atestación se volverán a registrar en el próximo uso." ;;
|
||||||
|
confirm_vol_up) echo "Vol+ = Confirmar borrado" ;;
|
||||||
|
confirm_vol_down) echo "Vol- = Cancelar (predeterminado tras 10s)" ;;
|
||||||
|
confirm_cancelled) echo "Cancelado - claves conservadas" ;;
|
||||||
|
confirm_cleared) echo "Almacenamiento persistente de claves borrado" ;;
|
||||||
|
confirm_not_found) echo "No se encontró almacenamiento persistente de claves" ;;
|
||||||
|
esac ;;
|
||||||
|
pt-BR) case "$1" in
|
||||||
|
confirm_header) echo "Limpar armazenamento persistente de chaves" ;;
|
||||||
|
confirm_warning_1) echo "Isso exclui todas as chaves de atestação em cache." ;;
|
||||||
|
confirm_warning_2) echo "Apps que usam atestação serão re-registrados no próximo uso." ;;
|
||||||
|
confirm_vol_up) echo "Vol+ = Confirmar limpeza" ;;
|
||||||
|
confirm_vol_down) echo "Vol- = Cancelar (padrão após 10s)" ;;
|
||||||
|
confirm_cancelled) echo "Cancelado - chaves preservadas" ;;
|
||||||
|
confirm_cleared) echo "Armazenamento persistente de chaves limpo" ;;
|
||||||
|
confirm_not_found) echo "Nenhum armazenamento persistente de chaves encontrado" ;;
|
||||||
|
esac ;;
|
||||||
|
it) case "$1" in
|
||||||
|
confirm_header) echo "Cancella archivio chiavi persistente" ;;
|
||||||
|
confirm_warning_1) echo "Questo elimina tutte le chiavi di attestazione in cache." ;;
|
||||||
|
confirm_warning_2) echo "Le app che usano l'attestazione si re-registreranno al prossimo utilizzo." ;;
|
||||||
|
confirm_vol_up) echo "Vol+ = Conferma cancellazione" ;;
|
||||||
|
confirm_vol_down) echo "Vol- = Annulla (predefinito dopo 10s)" ;;
|
||||||
|
confirm_cancelled) echo "Annullato - chiavi conservate" ;;
|
||||||
|
confirm_cleared) echo "Archivio chiavi persistente cancellato" ;;
|
||||||
|
confirm_not_found) echo "Nessun archivio chiavi persistente trovato" ;;
|
||||||
|
esac ;;
|
||||||
|
tr) case "$1" in
|
||||||
|
confirm_header) echo "Kalıcı Anahtar Deposunu Temizle" ;;
|
||||||
|
confirm_warning_1) echo "Bu, önbelleğe alınmış tüm doğrulama anahtarlarını siler." ;;
|
||||||
|
confirm_warning_2) echo "Doğrulama kullanan uygulamalar bir sonraki kullanımda yeniden kaydolacak." ;;
|
||||||
|
confirm_vol_up) echo "Ses+ = Temizlemeyi onayla" ;;
|
||||||
|
confirm_vol_down) echo "Ses- = İptal (10sn sonra varsayılan)" ;;
|
||||||
|
confirm_cancelled) echo "İptal edildi - anahtarlar korundu" ;;
|
||||||
|
confirm_cleared) echo "Kalıcı anahtar deposu temizlendi" ;;
|
||||||
|
confirm_not_found) echo "Kalıcı anahtar deposu bulunamadı" ;;
|
||||||
|
esac ;;
|
||||||
|
id) case "$1" in
|
||||||
|
confirm_header) echo "Hapus Penyimpanan Kunci Persisten" ;;
|
||||||
|
confirm_warning_1) echo "Ini menghapus semua kunci atestasi yang di-cache." ;;
|
||||||
|
confirm_warning_2) echo "Aplikasi yang menggunakan atestasi akan mendaftar ulang saat digunakan." ;;
|
||||||
|
confirm_vol_up) echo "Vol+ = Konfirmasi hapus" ;;
|
||||||
|
confirm_vol_down) echo "Vol- = Batal (default setelah 10 detik)" ;;
|
||||||
|
confirm_cancelled) echo "Dibatalkan - kunci dipertahankan" ;;
|
||||||
|
confirm_cleared) echo "Penyimpanan kunci persisten dihapus" ;;
|
||||||
|
confirm_not_found) echo "Penyimpanan kunci persisten tidak ditemukan" ;;
|
||||||
|
esac ;;
|
||||||
|
vi) case "$1" in
|
||||||
|
confirm_header) echo "Xóa lưu trữ khóa cố định" ;;
|
||||||
|
confirm_warning_1) echo "Thao tác này xóa tất cả khóa chứng thực được lưu cache." ;;
|
||||||
|
confirm_warning_2) echo "Các ứng dụng dùng chứng thực sẽ đăng ký lại khi sử dụng tiếp theo." ;;
|
||||||
|
confirm_vol_up) echo "Vol+ = Xác nhận xóa" ;;
|
||||||
|
confirm_vol_down) echo "Vol- = Hủy (mặc định sau 10s)" ;;
|
||||||
|
confirm_cancelled) echo "Đã hủy - giữ nguyên khóa" ;;
|
||||||
|
confirm_cleared) echo "Đã xóa lưu trữ khóa cố định" ;;
|
||||||
|
confirm_not_found) echo "Không tìm thấy lưu trữ khóa cố định" ;;
|
||||||
|
esac ;;
|
||||||
|
ar) case "$1" in
|
||||||
|
confirm_header) echo "مسح تخزين المفاتيح الدائم" ;;
|
||||||
|
confirm_warning_1) echo "يؤدي هذا إلى حذف جميع مفاتيح التصديق المخزنة مؤقتاً." ;;
|
||||||
|
confirm_warning_2) echo "التطبيقات التي تستخدم التصديق ستعيد التسجيل في الاستخدام التالي." ;;
|
||||||
|
confirm_vol_up) echo "رفع الصوت = تأكيد المسح" ;;
|
||||||
|
confirm_vol_down) echo "خفض الصوت = إلغاء (افتراضي بعد 10 ثوانٍ)" ;;
|
||||||
|
confirm_cancelled) echo "تم الإلغاء - تم الاحتفاظ بالمفاتيح" ;;
|
||||||
|
confirm_cleared) echo "تم مسح تخزين المفاتيح الدائم" ;;
|
||||||
|
confirm_not_found) echo "لم يتم العثور على تخزين مفاتيح دائم" ;;
|
||||||
|
esac ;;
|
||||||
|
th) case "$1" in
|
||||||
|
confirm_header) echo "ล้างที่จัดเก็บคีย์ถาวร" ;;
|
||||||
|
confirm_warning_1) echo "การดำเนินการนี้จะลบคีย์การรับรองที่แคชไว้ทั้งหมด" ;;
|
||||||
|
confirm_warning_2) echo "แอปที่ใช้การรับรองจะลงทะเบียนใหม่ในการใช้งานครั้งถัดไป" ;;
|
||||||
|
confirm_vol_up) echo "เพิ่มเสียง = ยืนยันการล้าง" ;;
|
||||||
|
confirm_vol_down) echo "ลดเสียง = ยกเลิก (ค่าเริ่มต้นหลัง 10 วินาที)" ;;
|
||||||
|
confirm_cancelled) echo "ยกเลิกแล้ว - คีย์ยังคงอยู่" ;;
|
||||||
|
confirm_cleared) echo "ล้างที่จัดเก็บคีย์ถาวรแล้ว" ;;
|
||||||
|
confirm_not_found) echo "ไม่พบที่จัดเก็บคีย์ถาวร" ;;
|
||||||
|
esac ;;
|
||||||
|
uk) case "$1" in
|
||||||
|
confirm_header) echo "Очистити постійне сховище ключів" ;;
|
||||||
|
confirm_warning_1) echo "Це видаляє всі кешовані ключі атестації." ;;
|
||||||
|
confirm_warning_2) echo "Програми, що використовують атестацію, повторно зареєструються при наступному використанні." ;;
|
||||||
|
confirm_vol_up) echo "Гучність+ = Підтвердити очищення" ;;
|
||||||
|
confirm_vol_down) echo "Гучність- = Скасувати (за замовчуванням через 10с)" ;;
|
||||||
|
confirm_cancelled) echo "Скасовано - ключі збережено" ;;
|
||||||
|
confirm_cleared) echo "Постійне сховище ключів очищено" ;;
|
||||||
|
confirm_not_found) echo "Постійне сховище ключів не знайдено" ;;
|
||||||
|
esac ;;
|
||||||
|
pl) case "$1" in
|
||||||
|
confirm_header) echo "Wyczyść trwały magazyn kluczy" ;;
|
||||||
|
confirm_warning_1) echo "To usuwa wszystkie buforowane klucze atestacji." ;;
|
||||||
|
confirm_warning_2) echo "Aplikacje używające atestacji zarejestrują się ponownie przy następnym użyciu." ;;
|
||||||
|
confirm_vol_up) echo "Głośność+ = Potwierdź czyszczenie" ;;
|
||||||
|
confirm_vol_down) echo "Głośność- = Anuluj (domyślnie po 10s)" ;;
|
||||||
|
confirm_cancelled) echo "Anulowano - klucze zachowane" ;;
|
||||||
|
confirm_cleared) echo "Trwały magazyn kluczy wyczyszczony" ;;
|
||||||
|
confirm_not_found) echo "Nie znaleziono trwałego magazynu kluczy" ;;
|
||||||
|
esac ;;
|
||||||
|
az) case "$1" in
|
||||||
|
confirm_header) echo "Davamlı Açar Yaddaşını Təmizlə" ;;
|
||||||
|
confirm_warning_1) echo "Bu, keşlənmiş bütün təsdiqləmə açarlarını silir." ;;
|
||||||
|
confirm_warning_2) echo "Təsdiqləmədən istifadə edən tətbiqlər növbəti istifadədə yenidən qeydiyyatdan keçəcək." ;;
|
||||||
|
confirm_vol_up) echo "Səs+ = Təmizləməni təsdiqlə" ;;
|
||||||
|
confirm_vol_down) echo "Səs- = Ləğv et (10 saniyə sonra defolt)" ;;
|
||||||
|
confirm_cancelled) echo "Ləğv edildi - açarlar saxlanıldı" ;;
|
||||||
|
confirm_cleared) echo "Davamlı açar yaddaşı təmizləndi" ;;
|
||||||
|
confirm_not_found) echo "Davamlı açar yaddaşı tapılmadı" ;;
|
||||||
|
esac ;;
|
||||||
|
bn) case "$1" in
|
||||||
|
confirm_header) echo "স্থায়ী কী সংরক্ষণ পরিষ্কার করুন" ;;
|
||||||
|
confirm_warning_1) echo "এটি সমস্ত ক্যাশড অ্যাটেস্টেশন কী মুছে ফেলে।" ;;
|
||||||
|
confirm_warning_2) echo "অ্যাটেস্টেশন ব্যবহারকারী অ্যাপগুলি পরবর্তী ব্যবহারে পুনরায় নিবন্ধন করবে।" ;;
|
||||||
|
confirm_vol_up) echo "ভলিউম+ = পরিষ্কার নিশ্চিত করুন" ;;
|
||||||
|
confirm_vol_down) echo "ভলিউম- = বাতিল (১০ সেকেন্ডে ডিফল্ট)" ;;
|
||||||
|
confirm_cancelled) echo "বাতিল করা হয়েছে - কী সংরক্ষিত" ;;
|
||||||
|
confirm_cleared) echo "স্থায়ী কী সংরক্ষণ পরিষ্কার করা হয়েছে" ;;
|
||||||
|
confirm_not_found) echo "কোনো স্থায়ী কী সংরক্ষণ পাওয়া যায়নি" ;;
|
||||||
|
esac ;;
|
||||||
|
el) case "$1" in
|
||||||
|
confirm_header) echo "Εκκαθάριση Μόνιμου Αποθηκευτικού Χώρου Κλειδιών" ;;
|
||||||
|
confirm_warning_1) echo "Διαγράφει όλα τα προσωρινά αποθηκευμένα κλειδιά πιστοποίησης." ;;
|
||||||
|
confirm_warning_2) echo "Οι εφαρμογές που χρησιμοποιούν πιστοποίηση θα επανεγγραφούν στην επόμενη χρήση." ;;
|
||||||
|
confirm_vol_up) echo "Ένταση+ = Επιβεβαίωση εκκαθάρισης" ;;
|
||||||
|
confirm_vol_down) echo "Ένταση- = Ακύρωση (προεπιλογή μετά από 10 δευτ)" ;;
|
||||||
|
confirm_cancelled) echo "Ακυρώθηκε - τα κλειδιά διατηρήθηκαν" ;;
|
||||||
|
confirm_cleared) echo "Ο μόνιμος αποθηκευτικός χώρος κλειδιών εκκαθαρίστηκε" ;;
|
||||||
|
confirm_not_found) echo "Δεν βρέθηκε μόνιμος αποθηκευτικός χώρος κλειδιών" ;;
|
||||||
|
esac ;;
|
||||||
|
fa) case "$1" in
|
||||||
|
confirm_header) echo "پاک کردن ذخیرهسازی دائمی کلید" ;;
|
||||||
|
confirm_warning_1) echo "این کار همه کلیدهای تأیید کششده را حذف میکند." ;;
|
||||||
|
confirm_warning_2) echo "برنامههای استفادهکننده از تأیید در استفاده بعدی دوباره ثبتنام میکنند." ;;
|
||||||
|
confirm_vol_up) echo "صدا+ = تأیید پاک کردن" ;;
|
||||||
|
confirm_vol_down) echo "صدا- = لغو (پیشفرض پس از ۱۰ ثانیه)" ;;
|
||||||
|
confirm_cancelled) echo "لغو شد - کلیدها حفظ شدند" ;;
|
||||||
|
confirm_cleared) echo "ذخیرهسازی دائمی کلید پاک شد" ;;
|
||||||
|
confirm_not_found) echo "ذخیرهسازی دائمی کلید یافت نشد" ;;
|
||||||
|
esac ;;
|
||||||
|
tl) case "$1" in
|
||||||
|
confirm_header) echo "Burahin ang Persistent Key Storage" ;;
|
||||||
|
confirm_warning_1) echo "Buburahin nito ang lahat ng naka-cache na attestation keys." ;;
|
||||||
|
confirm_warning_2) echo "Magre-rehistro muli ang mga app na gumagamit ng attestation sa susunod na paggamit." ;;
|
||||||
|
confirm_vol_up) echo "Vol+ = Kumpirmahin ang pagbura" ;;
|
||||||
|
confirm_vol_down) echo "Vol- = Kanselahin (default pagkatapos ng 10s)" ;;
|
||||||
|
confirm_cancelled) echo "Nakansela - napanatili ang mga key" ;;
|
||||||
|
confirm_cleared) echo "Nabura ang persistent key storage" ;;
|
||||||
|
confirm_not_found) echo "Walang nahanap na persistent key storage" ;;
|
||||||
|
esac ;;
|
||||||
|
*) case "$1" in
|
||||||
|
confirm_header) echo "Clear Persistent Key Storage" ;;
|
||||||
|
confirm_warning_1) echo "This deletes all cached attestation keys." ;;
|
||||||
|
confirm_warning_2) echo "Apps using attestation will re-enroll on next use." ;;
|
||||||
|
confirm_vol_up) echo "Vol+ = Confirm clear" ;;
|
||||||
|
confirm_vol_down) echo "Vol- = Cancel (default after 10s)" ;;
|
||||||
|
confirm_cancelled) echo "Cancelled - keys preserved" ;;
|
||||||
|
confirm_cleared) echo "Persistent key storage cleared" ;;
|
||||||
|
confirm_not_found) echo "No persistent key storage found" ;;
|
||||||
|
esac ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
@@ -1,3 +1,80 @@
|
|||||||
|
## TEESimulator-RS v6.0.0-235
|
||||||
|
|
||||||
|
11 commits since v6.0.0-224. Duck Detector generate-mode fingerprint cleared. Shizuku-routed BYO attestation fixed. Vol-key confirmation restored on Magisk.
|
||||||
|
|
||||||
|
### Detection Coverage
|
||||||
|
- Duck Detector "TEE Simulator generate-mode fingerprint" cleared. `toAuthorizations` reordered to AOSP keymint reference order; KEY_SIZE moves from auth#4 to auth#2, breaking the byte-224 anchor the probe relied on. 0/31 matches on fresh self-probes (was 15/36).
|
||||||
|
- `persist.logd.size` variants blanked at boot via `service.sh`. Removes a logd-tuning side-channel.
|
||||||
|
|
||||||
|
### BYO & Shizuku Routing
|
||||||
|
- Shizuku-routed BYO attestation no longer fails with `-49 UNSUPPORTED_TAG`. `shouldSkipUid` moved into `handleGenerateKey`, evaluated after BYO parameters are parsed.
|
||||||
|
- `createOperation` parallel fix: outer UID gate removed; the cache-or-forward lookup is the sole gate. BYO keys created under Shizuku UID can now be used for signing under the same UID.
|
||||||
|
- `forceGenerate` simplified: any attest-key or BYO request routes to software unconditionally.
|
||||||
|
- BYO attest-key miss returns the full keybox chain instead of a malformed depth-1 chain.
|
||||||
|
- AUTO TEE race dispatch removed. Resolution uses `DeviceAttestationService.isTeeFunctional` only.
|
||||||
|
- Symmetric gen rejects `attestationKey != null` early with `INVALID_ARGUMENT`. Unsupported-algorithm branch returns `-38` instead of `-49`.
|
||||||
|
|
||||||
|
### Action Button
|
||||||
|
- Vol+ / Vol- confirmation restored on Magisk. Streaming `getevent -lq` matched inline against `KEY_VOLUMEUP DOWN` / `KEY_VOLUMEDOWN DOWN`, wrapped in `/system/bin/timeout 10`. The prior polled approach timed out on six-events-per-keypress kernels.
|
||||||
|
|
||||||
|
### Verified
|
||||||
|
- Android 15 (SDK 35), daemon PID 1466.
|
||||||
|
- Cross-device confirmation pending on OnePlus PKX110 and Samsung SM-S928B.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TEESimulator-RS v6.0.0-224
|
||||||
|
|
||||||
|
59 commits since v6.0.0-162. Self-sufficient spoofing infrastructure, Duck Detector TamperScore-4 cleared on Xiaomi A16, persistent symmetric key storage (PR #22), 22-language action button hardening.
|
||||||
|
|
||||||
|
### Detection Coverage
|
||||||
|
- Duck Detector TimingSideChannelProbe cleared on Xiaomi A16 (SDK 35). Timing ratio dropped 1.555x to 1.055x, verdict WARNING to CLEAR. Threshold is > 1.1x.
|
||||||
|
- `KEY_ID` resolved from `teeResponses` instead of synthesized, matching real KeyMint binder behavior.
|
||||||
|
- Non-attested key cache mirrors attested path for byte-level metadata parity.
|
||||||
|
- `KEY_SIZE` emitted for EC keys; omitted when `ecCurve` is present, matching AOSP attestation_record.h.
|
||||||
|
- SSE messages synthesized canonically on non-AEAD `updateAad`; passthrough shape normalized.
|
||||||
|
- StrongBox attest version no longer hardcoded; resolved from device context.
|
||||||
|
- TEE op latency floor enforced to defeat micro-timing probes.
|
||||||
|
- Attest key resolution restored to nspace-aware lookup after revert/restore cycle.
|
||||||
|
|
||||||
|
### Self-Sufficient Spoofing
|
||||||
|
- `PatchLevelManager` resolves OS/VENDOR/BOOT patch levels via PIF without external bulletin fetch.
|
||||||
|
- `BulletinPoller` refreshes bulletin data on a schedule, isolated from boot path via umbrella `try/catch`.
|
||||||
|
- Bootloader-lock props pushed via `resetprop` at boot; absent vbmeta complement props filled; `vbmeta.device_state` included.
|
||||||
|
- PIF hot-reload via `FileObserver`; empty source files skipped; future patch dates bounded by `MAX_FUTURE_DAYS`.
|
||||||
|
- Default `security_patch.txt` dropped at install time.
|
||||||
|
- `sepolicy.rule` allows UDP egress for DNS resolution.
|
||||||
|
|
||||||
|
### Key Persistence (PR #22)
|
||||||
|
- Symmetric keys persist across reboots with byte-identical metadata.
|
||||||
|
- Keybox edits no longer wipe stored keys.
|
||||||
|
- Delete marker dropped on key regeneration to prevent stale state.
|
||||||
|
- Defensive symmetric fallback path with clean error codes.
|
||||||
|
|
||||||
|
### Reliability
|
||||||
|
- `atomicWrite` preserves `[pkg]` sections; errors guarded in `updateTo`.
|
||||||
|
- `applyToProps` serialized against concurrent callers.
|
||||||
|
- `pollOnce` wrapped in umbrella `try/catch`; `BulletinPoller.start` failure isolated from spoofer init.
|
||||||
|
- Spoofer ordering fixed: runs before keystore hook to prevent attest-time prop drift.
|
||||||
|
- `isAutoMode` reads raw package mode; `system=prop` passive default respected.
|
||||||
|
- `mergedContents` propagates read errors instead of swallowing them.
|
||||||
|
- Date regex validation on `currentPatch`; YYYY-MM input skips day synthesis.
|
||||||
|
- Global key-assignment check requires `=` delimiter (no more partial matches).
|
||||||
|
- `validation_rejected` status emitted on invalid spoof input.
|
||||||
|
|
||||||
|
### Action Button UX
|
||||||
|
- Vol+ required to clear `persistent_keys`. Vol- cancels. 10-second timeout defaults to cancel.
|
||||||
|
- Confirmation localized in 22 languages: ar, az, bn, de, el, es-ES, fa, fr, id, it, ja, ko, pl, pt-BR, ru, th, tl, tr, uk, vi, zh-CN, zh-TW.
|
||||||
|
- Every echoed string resolves through `_msg()` against device locale.
|
||||||
|
|
||||||
|
### Build & Ops
|
||||||
|
- Kotlin `jvmTarget` raised to JVM 21.
|
||||||
|
- Gradle auto-rewrites `module/update.json` on packaging.
|
||||||
|
- `scripts/package.sh` locates user-local cargo; rust task receives cargo bin path.
|
||||||
|
- Verified on Xiaomi Android 16 (SDK 35) `v6.0.0-224-Release`. Daemon alive PID 1392. Pending cross-device confirm on OnePlus PKX110 (qcom sun) and Samsung SM-S928B (pineapple).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## TEESimulator-RS v6.0.0
|
## TEESimulator-RS v6.0.0
|
||||||
|
|
||||||
Repository consolidation release. All tee-rebuild work merged as the new main branch.
|
Repository consolidation release. All tee-rebuild work merged as the new main branch.
|
||||||
|
|||||||
+1
-1
@@ -48,7 +48,7 @@ install_file() {
|
|||||||
|
|
||||||
# --- Installation ---
|
# --- Installation ---
|
||||||
ui_print "- Extracting module files"
|
ui_print "- Extracting module files"
|
||||||
for file in customize.sh module.prop service.sh sepolicy.rule daemon action.sh uninstall.sh; do
|
for file in customize.sh module.prop service.sh sepolicy.rule daemon action.sh action_i18n.sh uninstall.sh; do
|
||||||
install_file "$file" "$MODPATH"
|
install_file "$file" "$MODPATH"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
@@ -3,3 +3,14 @@ cd $MODDIR
|
|||||||
|
|
||||||
# Fork-based supervisor for instant restart
|
# Fork-based supervisor for instant restart
|
||||||
./supervisor ./daemon "$MODDIR" &
|
./supervisor ./daemon "$MODDIR" &
|
||||||
|
|
||||||
|
# Clear logd size persist properties once boot completes
|
||||||
|
(
|
||||||
|
until [ "$(getprop sys.boot_completed)" = "1" ]; do
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
setprop persist.logd.size ""
|
||||||
|
setprop persist.logd.size.crash ""
|
||||||
|
setprop persist.logd.size.system ""
|
||||||
|
setprop persist.logd.size.main ""
|
||||||
|
) &
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "v6.0.0-211",
|
"version": "v6.0.0-235",
|
||||||
"versionCode": 211,
|
"versionCode": 235,
|
||||||
"zipUrl": "https://github.com/Enginex0/TEESimulator-RS/releases/download/v6.0.0-211/TEESimulator-RS-v6.0.0-211-Release.zip",
|
"zipUrl": "https://github.com/Enginex0/TEESimulator-RS/releases/download/v6.0.0-235/TEESimulator-RS-v6.0.0-235-Release.zip",
|
||||||
"changelog": "https://raw.githubusercontent.com/Enginex0/TEESimulator-RS/main/module/changelog.md"
|
"changelog": "https://raw.githubusercontent.com/Enginex0/TEESimulator-RS/main/module/changelog.md"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user