Skip to content

Commit 1dd3851

Browse files
committed
fix: the potential bug of finding the wrong key due to nspace not being unique
Signed-off-by: qwq233 <[email protected]>
1 parent be54499 commit 1dd3851

File tree

5 files changed

+54
-20
lines changed

5 files changed

+54
-20
lines changed

service/src/main/java/io/github/a13e300/tricky_store/Cache.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ object Cache {
4343
keys[key] = info
4444
}
4545

46-
fun getInfoByNspace(nspace: Long): Info? = keys.values.firstOrNull { it.response.metadata?.key?.nspace == nspace }
46+
fun getInfoByNspace(callingUid: Int, nspace: Long): List<Info> = keys.values.filter { it.key.uid == callingUid && it.response.metadata?.key?.nspace == nspace }
4747

4848
fun getKeyResponse(uid: Int, alias: String): KeyEntryResponse? = keys[Key(uid, alias)]?.response
4949

service/src/main/java/io/github/a13e300/tricky_store/KeystoreInterceptor.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ import kotlin.system.exitProcess
1717

1818
@SuppressLint("BlockedPrivateApi")
1919
object KeystoreInterceptor : BinderInterceptor() {
20+
private val getSecurityLevelTransaction =
21+
getTransactCode(IKeystoreService.Stub::class.java, "getSecurityLevel") // 1
2022
private val getKeyEntryTransaction =
2123
getTransactCode(IKeystoreService.Stub::class.java, "getKeyEntry") // 2
22-
private val deleteKeyTransaction =
23-
getTransactCode(IKeystoreService.Stub::class.java, "deleteKey")
2424
private val updateSubcomponentTransaction =
25-
getTransactCode(IKeystoreService.Stub::class.java, "updateSubcomponent")
25+
getTransactCode(IKeystoreService.Stub::class.java, "updateSubcomponent") // 3
26+
private val deleteKeyTransaction =
27+
getTransactCode(IKeystoreService.Stub::class.java, "deleteKey") // 5
2628

2729
private lateinit var keystore: IBinder
2830

@@ -94,6 +96,16 @@ object KeystoreInterceptor : BinderInterceptor() {
9496

9597
deleteKeyTransaction -> {
9698
Logger.d("KeystoreInceptor onPreTransact deleteKeyTransaction uid=$callingUid pid=$callingPid")
99+
data.enforceInterface("android.system.keystore2.IKeystoreService")
100+
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)
101+
if (keyDescriptor == null) return Skip
102+
103+
Logger.d("KeystoreInterceptor deleteKey uid=$callingUid alias=${keyDescriptor.alias}")
104+
105+
Cache.deleteKey(Key(callingUid, keyDescriptor.alias))
106+
Cache.deleteImportedKey(callingUid, callingPid)
107+
108+
return Skip
97109
}
98110
}
99111
return Skip

service/src/main/java/io/github/a13e300/tricky_store/Logger.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ public static void d(String msg) {
88
Log.d(TAG, msg);
99
}
1010

11+
public static void d(String tag, String msg) {
12+
Log.d(TAG, tag + ": " + msg);
13+
}
14+
1115
public static void dd(String msg) {
1216
d("wtf: " + msg);
1317
}

service/src/main/java/io/github/a13e300/tricky_store/SecurityLevelInterceptor.kt

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,16 @@ class SecurityLevelInterceptor(
2525
private val original: IKeystoreSecurityLevel, private val level: Int
2626
) : BinderInterceptor() {
2727
companion object {
28-
private val generateKeyTransaction = getTransactCode(IKeystoreSecurityLevel.Stub::class.java, "generateKey")
29-
private val deleteKeyTransaction = getTransactCode(IKeystoreSecurityLevel.Stub::class.java, "deleteKey")
30-
private val createOperationTransaction = getTransactCode(IKeystoreSecurityLevel.Stub::class.java, "createOperation")
31-
private val importWrappedKeyTransaction = getTransactCode(IKeystoreSecurityLevel.Stub::class.java, "importWrappedKey")
32-
private val importKeyTransaction = getTransactCode(IKeystoreSecurityLevel.Stub::class.java, "importKey")
28+
private val createOperationTransaction =
29+
getTransactCode(IKeystoreSecurityLevel.Stub::class.java, "createOperation") //1
30+
private val generateKeyTransaction =
31+
getTransactCode(IKeystoreSecurityLevel.Stub::class.java, "generateKey") // 2
32+
private val importKeyTransaction =
33+
getTransactCode(IKeystoreSecurityLevel.Stub::class.java, "importKey") // 3
34+
private val importWrappedKeyTransaction =
35+
getTransactCode(IKeystoreSecurityLevel.Stub::class.java, "importWrappedKey") // 4
36+
private val deleteKeyTransaction =
37+
getTransactCode(IKeystoreSecurityLevel.Stub::class.java, "deleteKey") // 6
3338

3439
}
3540
override fun onPreTransact(
@@ -114,23 +119,30 @@ class SecurityLevelInterceptor(
114119
val params = data.createTypedArray(KeyParameter.CREATOR) ?: return Skip
115120
val kgp = CertHack.KeyGenParameters(params)
116121

117-
val info = Cache.getInfoByNspace(keyDescriptor.nspace)
118-
if (info == null || (info.key.uid != callingUid)) {
119-
Logger.e("key not found or uid mismatch")
120-
return Skip
121-
}
122122
if (keyDescriptor.domain != 4) throw IllegalArgumentException("unsupported domain ${keyDescriptor.domain}")
123123
kgp.purpose.any { it != 2 /* sign */ && it != 7 /* attest */ } ||
124124
throw IllegalArgumentException("unsupported purpose ${kgp.purpose}")
125-
kgp.digest.any { it != 4 } ||
126-
throw IllegalArgumentException("unsupported digest ${kgp.digest}")
127125
val algorithm = when (kgp.algorithm) {
128-
Algorithm.EC -> "SHA256withECDSA"
129-
Algorithm.RSA -> "SHA256withRSA"
126+
Algorithm.EC -> "ECDSA"
127+
Algorithm.RSA -> "RSA"
130128
else -> throw IllegalArgumentException("unsupported algorithm ${kgp.algorithm}")
131129
}
132130

133-
val op = KeyStoreOperation(info.keyPair.private, algorithm)
131+
val infos = Cache.getInfoByNspace(callingUid, keyDescriptor.nspace)
132+
if (infos.isEmpty()) {
133+
Logger.e("key not found")
134+
return Skip
135+
}
136+
infos.filter { it.response.metadata.key.alias == keyDescriptor.alias }.let {
137+
it.forEach {
138+
Logger.d("found key alias=${it.key.alias} uid=${it.key.uid} actual=${it.response.metadata.key.alias}")
139+
Logger.d("createOperation", it.chain.first().toString())
140+
}
141+
}
142+
Logger.d("found keys number: ${infos.size}")
143+
val info = infos.first { it.response.metadata.key.alias == keyDescriptor.alias && it.keyPair.private.algorithm == algorithm }
144+
Logger.d("createOperation", info.chain.first().toString())
145+
val op = KeyStoreOperation(info.keyPair.private, "SHA256with$algorithm")
134146
val parcel = Parcel.obtain()
135147
parcel.writeNoException()
136148
val createOperationResponse = CreateOperationResponse().apply {
@@ -151,27 +163,32 @@ class SecurityLevelInterceptor(
151163
var isAborted = false
152164

153165
constructor(privateKey: PrivateKey, algorithm: String) {
166+
Logger.d("KeyStoreOperation using algorithm $algorithm, privateKey=${privateKey.algorithm}")
154167
signature = Signature.getInstance(algorithm)
155168
signature.initSign(privateKey)
156169
}
157170

158171
override fun updateAad(aadInput: ByteArray?) {
159172
// do nothing for now
173+
Logger.d("updateAad called, ignored")
160174
}
161175

162176
override fun update(input: ByteArray): ByteArray? {
163177
if (isAborted) throw IllegalStateException("operation aborted")
178+
Logger.d("update called with ${input.size} bytes")
164179
signature.update(input)
165180
return null
166181
}
167182

168183
override fun finish(input: ByteArray?, signature: ByteArray?): ByteArray? {
169184
if (isAborted) throw IllegalStateException("operation aborted")
185+
Logger.d("finish called with ${input?.size ?: 0} bytes")
170186
this.signature.update(input)
171187
return this.signature.sign()
172188
}
173189

174190
override fun abort() {
191+
Logger.d("abort called")
175192
isAborted = true
176193
}
177194
}

service/src/main/java/io/github/a13e300/tricky_store/keystore/CertHack.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,8 @@ public KeyGenParameters(KeyParameter[] params) {
813813
certificateNotAfter = new Date(p.getDateTime());
814814
case Tag.CERTIFICATE_SUBJECT ->
815815
certificateSubject = new X500Name(new X500Principal(p.getBlob()).getName());
816-
case Tag.RSA_PUBLIC_EXPONENT -> rsaPublicExponent = new BigInteger(p.getBlob());
816+
case Tag.RSA_PUBLIC_EXPONENT ->
817+
rsaPublicExponent = new BigInteger(String.valueOf(p.getLongInteger()));
817818
case Tag.EC_CURVE -> {
818819
ecCurve = p.getEcCurve();
819820
ecCurveName = getEcCurveName(ecCurve);

0 commit comments

Comments
 (0)