You've already forked TrickyStore
mirror of
https://github.com/5ec1cff/TrickyStore.git
synced 2025-09-06 06:37:07 +00:00
support generate key
This commit is contained in:
5
service/proguard-rules.pro
vendored
5
service/proguard-rules.pro
vendored
@@ -26,3 +26,8 @@
|
|||||||
-assumenosideeffects class io.github.a13e300.tricky_store.Logger {
|
-assumenosideeffects class io.github.a13e300.tricky_store.Logger {
|
||||||
public static void d(java.lang.String);
|
public static void d(java.lang.String);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# keep these or bouncycastle will not work
|
||||||
|
-keep class org.bouncycastle.jcajce.provider.** { *; }
|
||||||
|
-keep class org.bouncycastle.jce.provider.** { *; }
|
||||||
|
-dontwarn javax.naming.**
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package io.github.a13e300.tricky_store
|
package io.github.a13e300.tricky_store
|
||||||
|
|
||||||
|
import android.content.pm.IPackageManager
|
||||||
import android.os.FileObserver
|
import android.os.FileObserver
|
||||||
|
import android.os.ServiceManager
|
||||||
import io.github.a13e300.tricky_store.keystore.CertHack
|
import io.github.a13e300.tricky_store.keystore.CertHack
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
object Config {
|
object Config {
|
||||||
val targetPackages = mutableSetOf<String>()
|
private val hackPackages = mutableSetOf<String>()
|
||||||
|
private val generatePackages = mutableSetOf<String>()
|
||||||
private val DEFAULT_TARGET_PACKAGES = listOf(
|
private val DEFAULT_TARGET_PACKAGES = listOf(
|
||||||
"com.google.android.gms",
|
"com.google.android.gms",
|
||||||
"icu.nullptr.nativetest",
|
"icu.nullptr.nativetest",
|
||||||
@@ -14,11 +17,16 @@ object Config {
|
|||||||
)
|
)
|
||||||
|
|
||||||
private fun updateTargetPackages(f: File?) = runCatching {
|
private fun updateTargetPackages(f: File?) = runCatching {
|
||||||
targetPackages.clear()
|
hackPackages.clear()
|
||||||
f?.readLines()?.mapNotNullTo(targetPackages) {
|
generatePackages.clear()
|
||||||
if (it.isNotBlank() && !it.startsWith("#")) it else null
|
f?.readLines()?.forEach {
|
||||||
|
if (it.isNotBlank() && !it.startsWith("#")) {
|
||||||
|
val n = it.trim()
|
||||||
|
if (n.endsWith("!")) generatePackages.add(n.removeSuffix("!").trim())
|
||||||
|
else hackPackages.add(n)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Logger.i("update target packages: $targetPackages")
|
Logger.i("update hack packages: $hackPackages, generate packages=$generatePackages")
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
Logger.e("failed to update target files", it)
|
Logger.e("failed to update target files", it)
|
||||||
}
|
}
|
||||||
@@ -65,4 +73,25 @@ object Config {
|
|||||||
}
|
}
|
||||||
ConfigObserver.startWatching()
|
ConfigObserver.startWatching()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var iPm: IPackageManager? = null
|
||||||
|
|
||||||
|
fun getPm(): IPackageManager? {
|
||||||
|
if (iPm == null) {
|
||||||
|
iPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"))
|
||||||
|
}
|
||||||
|
return iPm
|
||||||
|
}
|
||||||
|
|
||||||
|
fun needHack(callingUid: Int) = kotlin.runCatching {
|
||||||
|
if (hackPackages.isEmpty()) return false
|
||||||
|
val ps = getPm()?.getPackagesForUid(callingUid)
|
||||||
|
ps?.any { it in hackPackages }
|
||||||
|
}.onFailure { Logger.e("failed to get packages", it) }.getOrNull() ?: false
|
||||||
|
|
||||||
|
fun needGenerate(callingUid: Int) = kotlin.runCatching {
|
||||||
|
if (generatePackages.isEmpty()) return false
|
||||||
|
val ps = getPm()?.getPackagesForUid(callingUid)
|
||||||
|
ps?.any { it in generatePackages }
|
||||||
|
}.onFailure { Logger.e("failed to get packages", it) }.getOrNull() ?: false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package io.github.a13e300.tricky_store
|
package io.github.a13e300.tricky_store
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.pm.IPackageManager
|
import android.hardware.security.keymint.SecurityLevel
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.ServiceManager
|
import android.os.ServiceManager
|
||||||
import android.system.keystore2.IKeystoreService
|
import android.system.keystore2.IKeystoreService
|
||||||
|
import android.system.keystore2.KeyDescriptor
|
||||||
import android.system.keystore2.KeyEntryResponse
|
import android.system.keystore2.KeyEntryResponse
|
||||||
import io.github.a13e300.tricky_store.binder.BinderInterceptor
|
import io.github.a13e300.tricky_store.binder.BinderInterceptor
|
||||||
import io.github.a13e300.tricky_store.keystore.CertHack
|
import io.github.a13e300.tricky_store.keystore.CertHack
|
||||||
@@ -13,17 +14,14 @@ import io.github.a13e300.tricky_store.keystore.Utils
|
|||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
@SuppressLint("BlockedPrivateApi")
|
@SuppressLint("BlockedPrivateApi")
|
||||||
object KeystoreInterceptor : BinderInterceptor() {
|
object KeystoreInterceptor : BinderInterceptor() {
|
||||||
private val targetTransaction = IKeystoreService.Stub::class.java.getDeclaredField("TRANSACTION_getKeyEntry").apply { isAccessible = true }.getInt(null) // 2
|
private val getKeyEntryTransaction =
|
||||||
|
getTransactCode(IKeystoreService.Stub::class.java, "getKeyEntry") // 2
|
||||||
|
|
||||||
private var iPm: IPackageManager? = null
|
private lateinit var keystore: IBinder
|
||||||
|
|
||||||
private fun getPm(): IPackageManager? {
|
private var teeInterceptor: SecurityLevelInterceptor? = null
|
||||||
if (iPm == null) {
|
private var strongBoxInterceptor: SecurityLevelInterceptor? = null
|
||||||
iPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"))
|
|
||||||
}
|
|
||||||
return iPm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPreTransact(
|
override fun onPreTransact(
|
||||||
target: IBinder,
|
target: IBinder,
|
||||||
@@ -33,12 +31,26 @@ object KeystoreInterceptor : BinderInterceptor() {
|
|||||||
callingPid: Int,
|
callingPid: Int,
|
||||||
data: Parcel
|
data: Parcel
|
||||||
): Result {
|
): Result {
|
||||||
if (code == targetTransaction && CertHack.canHack() && Config.targetPackages.isNotEmpty()) {
|
if (code == getKeyEntryTransaction) {
|
||||||
Logger.d("intercept pre $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()}")
|
if (CertHack.canHack()) {
|
||||||
kotlin.runCatching {
|
Logger.d("intercept pre $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()}")
|
||||||
val ps = getPm()?.getPackagesForUid(callingUid)
|
if (Config.needGenerate(callingUid))
|
||||||
if (ps?.any { it in Config.targetPackages } == true) return Continue
|
kotlin.runCatching {
|
||||||
}.onFailure { Logger.e("failed to get packages", it) }
|
data.enforceInterface(IKeystoreService.DESCRIPTOR)
|
||||||
|
val descriptor =
|
||||||
|
data.readTypedObject(KeyDescriptor.CREATOR) ?: return@runCatching
|
||||||
|
val response =
|
||||||
|
SecurityLevelInterceptor.getKeyResponse(callingUid, descriptor.alias)
|
||||||
|
?: return@runCatching
|
||||||
|
Logger.i("use generated key $callingUid ${descriptor.alias}")
|
||||||
|
val p = Parcel.obtain()
|
||||||
|
p.writeNoException()
|
||||||
|
p.writeTypedObject(response, 0)
|
||||||
|
return OverrideReply(0, p)
|
||||||
|
}
|
||||||
|
else if (Config.needHack(callingUid)) return Continue
|
||||||
|
return Skip
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Skip
|
return Skip
|
||||||
}
|
}
|
||||||
@@ -53,7 +65,7 @@ object KeystoreInterceptor : BinderInterceptor() {
|
|||||||
reply: Parcel?,
|
reply: Parcel?,
|
||||||
resultCode: Int
|
resultCode: Int
|
||||||
): Result {
|
): Result {
|
||||||
if (code != targetTransaction || reply == null) return Skip
|
if (target != keystore || code != getKeyEntryTransaction || reply == null) return Skip
|
||||||
val p = Parcel.obtain()
|
val p = Parcel.obtain()
|
||||||
Logger.d("intercept post $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()} replySz=${reply.dataSize()}")
|
Logger.d("intercept post $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()} replySz=${reply.dataSize()}")
|
||||||
try {
|
try {
|
||||||
@@ -61,7 +73,7 @@ object KeystoreInterceptor : BinderInterceptor() {
|
|||||||
val response = reply.readTypedObject(KeyEntryResponse.CREATOR)
|
val response = reply.readTypedObject(KeyEntryResponse.CREATOR)
|
||||||
val chain = Utils.getCertificateChain(response)
|
val chain = Utils.getCertificateChain(response)
|
||||||
if (chain != null) {
|
if (chain != null) {
|
||||||
val newChain = CertHack.engineGetCertificateChain(chain)
|
val newChain = CertHack.hackCertificateChain(chain)
|
||||||
Utils.putCertificateChain(response, newChain)
|
Utils.putCertificateChain(response, newChain)
|
||||||
p.writeNoException()
|
p.writeNoException()
|
||||||
p.writeTypedObject(response, 0)
|
p.writeTypedObject(response, 0)
|
||||||
@@ -98,8 +110,31 @@ object KeystoreInterceptor : BinderInterceptor() {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
val ks = IKeystoreService.Stub.asInterface(b)
|
||||||
|
val tee = kotlin.runCatching { ks.getSecurityLevel(SecurityLevel.TRUSTED_ENVIRONMENT) }
|
||||||
|
.getOrNull()
|
||||||
|
val strongBox =
|
||||||
|
kotlin.runCatching { ks.getSecurityLevel(SecurityLevel.STRONGBOX) }.getOrNull()
|
||||||
|
keystore = b
|
||||||
|
Logger.i("register for Keystore $keystore!")
|
||||||
registerBinderInterceptor(bd, b, this)
|
registerBinderInterceptor(bd, b, this)
|
||||||
b.linkToDeath(Killer, 0)
|
keystore.linkToDeath(Killer, 0)
|
||||||
|
if (tee != null) {
|
||||||
|
Logger.i("register for TEE SecurityLevel $tee!")
|
||||||
|
val interceptor = SecurityLevelInterceptor(tee)
|
||||||
|
registerBinderInterceptor(bd, tee.asBinder(), interceptor)
|
||||||
|
teeInterceptor = interceptor
|
||||||
|
} else {
|
||||||
|
Logger.i("no TEE SecurityLevel found!")
|
||||||
|
}
|
||||||
|
if (strongBox != null) {
|
||||||
|
Logger.i("register for StrongBox SecurityLevel $tee!")
|
||||||
|
val interceptor = SecurityLevelInterceptor(strongBox)
|
||||||
|
registerBinderInterceptor(bd, strongBox.asBinder(), interceptor)
|
||||||
|
strongBoxInterceptor = interceptor
|
||||||
|
} else {
|
||||||
|
Logger.i("no StrongBox SecurityLevel found!")
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package io.github.a13e300.tricky_store
|
||||||
|
|
||||||
|
import android.hardware.security.keymint.KeyParameter
|
||||||
|
import android.hardware.security.keymint.KeyParameterValue
|
||||||
|
import android.hardware.security.keymint.SecurityLevel
|
||||||
|
import android.hardware.security.keymint.Tag
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.system.keystore2.Authorization
|
||||||
|
import android.system.keystore2.IKeystoreSecurityLevel
|
||||||
|
import android.system.keystore2.KeyDescriptor
|
||||||
|
import android.system.keystore2.KeyEntryResponse
|
||||||
|
import android.system.keystore2.KeyMetadata
|
||||||
|
import io.github.a13e300.tricky_store.binder.BinderInterceptor
|
||||||
|
import io.github.a13e300.tricky_store.keystore.CertHack
|
||||||
|
import io.github.a13e300.tricky_store.keystore.CertHack.KeyGenParameters
|
||||||
|
import io.github.a13e300.tricky_store.keystore.Utils
|
||||||
|
import java.security.KeyPair
|
||||||
|
import java.security.cert.Certificate
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
class SecurityLevelInterceptor(private val original: IKeystoreSecurityLevel) : BinderInterceptor() {
|
||||||
|
companion object {
|
||||||
|
private val generateKeyTransaction =
|
||||||
|
getTransactCode(IKeystoreSecurityLevel.Stub::class.java, "generateKey")
|
||||||
|
private val keys = ConcurrentHashMap<Key, Info>()
|
||||||
|
|
||||||
|
fun getKeyResponse(uid: Int, alias: String): KeyEntryResponse? =
|
||||||
|
keys[Key(uid, alias)]?.response
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Key(val uid: Int, val alias: String)
|
||||||
|
data class Info(val keyPair: KeyPair, val response: KeyEntryResponse)
|
||||||
|
|
||||||
|
override fun onPreTransact(
|
||||||
|
target: IBinder,
|
||||||
|
code: Int,
|
||||||
|
flags: Int,
|
||||||
|
callingUid: Int,
|
||||||
|
callingPid: Int,
|
||||||
|
data: Parcel
|
||||||
|
): Result {
|
||||||
|
if (code == generateKeyTransaction && Config.needGenerate(callingUid)) {
|
||||||
|
Logger.i("intercept key gen uid=$callingUid pid=$callingPid")
|
||||||
|
kotlin.runCatching {
|
||||||
|
data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR)
|
||||||
|
val keyDescriptor =
|
||||||
|
data.readTypedObject(KeyDescriptor.CREATOR) ?: return@runCatching
|
||||||
|
val attestationKeyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)
|
||||||
|
val params = data.createTypedArray(KeyParameter.CREATOR)!!
|
||||||
|
// val aFlags = data.readInt()
|
||||||
|
// val entropy = data.createByteArray()
|
||||||
|
val kgp = KeyGenParameters(params)
|
||||||
|
if (kgp.attestationChallenge != null) {
|
||||||
|
if (attestationKeyDescriptor != null) {
|
||||||
|
Logger.e("warn: attestation key not supported now")
|
||||||
|
} else {
|
||||||
|
val pair = CertHack.generateKeyPair(callingUid, keyDescriptor, kgp)
|
||||||
|
?: return@runCatching
|
||||||
|
val response = buildResponse(pair.second, kgp, keyDescriptor)
|
||||||
|
keys[Key(callingUid, keyDescriptor.alias)] = Info(pair.first, response)
|
||||||
|
val p = Parcel.obtain()
|
||||||
|
p.writeNoException()
|
||||||
|
p.writeTypedObject(response.metadata, 0)
|
||||||
|
return OverrideReply(0, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.onFailure {
|
||||||
|
Logger.e("parse key gen request", it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Skip
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildResponse(
|
||||||
|
chain: List<Certificate>,
|
||||||
|
params: KeyGenParameters,
|
||||||
|
descriptor: KeyDescriptor
|
||||||
|
): KeyEntryResponse {
|
||||||
|
val response = KeyEntryResponse()
|
||||||
|
val metadata = KeyMetadata()
|
||||||
|
Utils.putCertificateChain(metadata, chain.toTypedArray<Certificate>())
|
||||||
|
val d = KeyDescriptor()
|
||||||
|
d.domain = descriptor.domain
|
||||||
|
d.nspace = descriptor.nspace
|
||||||
|
metadata.key = d
|
||||||
|
val authorizations = ArrayList<Authorization>()
|
||||||
|
var a: Authorization
|
||||||
|
for (i in params.purpose) {
|
||||||
|
a = Authorization()
|
||||||
|
a.keyParameter = KeyParameter()
|
||||||
|
a.keyParameter.tag = Tag.PURPOSE
|
||||||
|
a.keyParameter.value = KeyParameterValue.keyPurpose(i)
|
||||||
|
a.securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT
|
||||||
|
authorizations.add(a)
|
||||||
|
}
|
||||||
|
for (i in params.digest) {
|
||||||
|
a = Authorization()
|
||||||
|
a.keyParameter = KeyParameter()
|
||||||
|
a.keyParameter.tag = Tag.DIGEST
|
||||||
|
a.keyParameter.value = KeyParameterValue.digest(i)
|
||||||
|
a.securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT
|
||||||
|
authorizations.add(a)
|
||||||
|
}
|
||||||
|
a = Authorization()
|
||||||
|
a.keyParameter = KeyParameter()
|
||||||
|
a.keyParameter.tag = Tag.ALGORITHM
|
||||||
|
a.keyParameter.value = KeyParameterValue.algorithm(params.algorithm)
|
||||||
|
a.securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT
|
||||||
|
authorizations.add(a)
|
||||||
|
a = Authorization()
|
||||||
|
a.keyParameter = KeyParameter()
|
||||||
|
a.keyParameter.tag = Tag.KEY_SIZE
|
||||||
|
a.keyParameter.value = KeyParameterValue.integer(params.keySize)
|
||||||
|
a.securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT
|
||||||
|
authorizations.add(a)
|
||||||
|
a = Authorization()
|
||||||
|
a.keyParameter = KeyParameter()
|
||||||
|
a.keyParameter.tag = Tag.EC_CURVE
|
||||||
|
a.keyParameter.value = KeyParameterValue.ecCurve(params.ecCurve)
|
||||||
|
a.securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT
|
||||||
|
authorizations.add(a)
|
||||||
|
a = Authorization()
|
||||||
|
a.keyParameter = KeyParameter()
|
||||||
|
a.keyParameter.tag = Tag.NO_AUTH_REQUIRED
|
||||||
|
a.keyParameter.value = KeyParameterValue.boolValue(true) // TODO: copy
|
||||||
|
a.securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT
|
||||||
|
authorizations.add(a)
|
||||||
|
// TODO: ORIGIN
|
||||||
|
//OS_VERSION
|
||||||
|
//OS_PATCHLEVEL
|
||||||
|
//VENDOR_PATCHLEVEL
|
||||||
|
//BOOT_PATCHLEVEL
|
||||||
|
//CREATION_DATETIME
|
||||||
|
//USER_ID
|
||||||
|
metadata.authorizations = authorizations.toTypedArray<Authorization>()
|
||||||
|
response.metadata = metadata
|
||||||
|
response.iSecurityLevel = original
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,22 +1,38 @@
|
|||||||
package io.github.a13e300.tricky_store.keystore;
|
package io.github.a13e300.tricky_store.keystore;
|
||||||
|
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.hardware.security.keymint.Algorithm;
|
||||||
|
import android.hardware.security.keymint.EcCurve;
|
||||||
|
import android.hardware.security.keymint.KeyParameter;
|
||||||
|
import android.hardware.security.keymint.Tag;
|
||||||
import android.security.keystore.KeyProperties;
|
import android.security.keystore.KeyProperties;
|
||||||
|
import android.system.keystore2.KeyDescriptor;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.bouncycastle.asn1.ASN1Boolean;
|
import org.bouncycastle.asn1.ASN1Boolean;
|
||||||
import org.bouncycastle.asn1.ASN1Encodable;
|
import org.bouncycastle.asn1.ASN1Encodable;
|
||||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||||
import org.bouncycastle.asn1.ASN1Enumerated;
|
import org.bouncycastle.asn1.ASN1Enumerated;
|
||||||
|
import org.bouncycastle.asn1.ASN1Integer;
|
||||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||||
import org.bouncycastle.asn1.ASN1OctetString;
|
import org.bouncycastle.asn1.ASN1OctetString;
|
||||||
import org.bouncycastle.asn1.ASN1Sequence;
|
import org.bouncycastle.asn1.ASN1Sequence;
|
||||||
import org.bouncycastle.asn1.ASN1TaggedObject;
|
import org.bouncycastle.asn1.ASN1TaggedObject;
|
||||||
|
import org.bouncycastle.asn1.DERNull;
|
||||||
import org.bouncycastle.asn1.DEROctetString;
|
import org.bouncycastle.asn1.DEROctetString;
|
||||||
import org.bouncycastle.asn1.DERSequence;
|
import org.bouncycastle.asn1.DERSequence;
|
||||||
|
import org.bouncycastle.asn1.DERSet;
|
||||||
import org.bouncycastle.asn1.DERTaggedObject;
|
import org.bouncycastle.asn1.DERTaggedObject;
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name;
|
||||||
import org.bouncycastle.asn1.x509.Extension;
|
import org.bouncycastle.asn1.x509.Extension;
|
||||||
|
import org.bouncycastle.asn1.x509.KeyUsage;
|
||||||
import org.bouncycastle.cert.X509CertificateHolder;
|
import org.bouncycastle.cert.X509CertificateHolder;
|
||||||
import org.bouncycastle.cert.X509v3CertificateBuilder;
|
import org.bouncycastle.cert.X509v3CertificateBuilder;
|
||||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.bouncycastle.openssl.PEMKeyPair;
|
import org.bouncycastle.openssl.PEMKeyPair;
|
||||||
import org.bouncycastle.openssl.PEMParser;
|
import org.bouncycastle.openssl.PEMParser;
|
||||||
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||||
@@ -25,25 +41,46 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
|||||||
import org.bouncycastle.util.io.pem.PemReader;
|
import org.bouncycastle.util.io.pem.PemReader;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.Security;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.CertificateParsingException;
|
import java.security.cert.CertificateParsingException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.security.spec.ECGenParameterSpec;
|
||||||
|
import java.security.spec.RSAKeyGenParameterSpec;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
import javax.security.auth.x500.X500Principal;
|
||||||
|
|
||||||
|
import io.github.a13e300.tricky_store.Config;
|
||||||
import io.github.a13e300.tricky_store.Logger;
|
import io.github.a13e300.tricky_store.Logger;
|
||||||
|
import io.github.a13e300.tricky_store.UtilKt;
|
||||||
|
|
||||||
public final class CertHack {
|
public final class CertHack {
|
||||||
private static final ASN1ObjectIdentifier OID = new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17");
|
private static final ASN1ObjectIdentifier OID = new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17");
|
||||||
|
|
||||||
record KeyBox(PEMKeyPair privateKey, List<Certificate> certificates) {}
|
private static final int ATTESTATION_APPLICATION_ID_PACKAGE_INFOS_INDEX = 0;
|
||||||
|
private static final int ATTESTATION_APPLICATION_ID_SIGNATURE_DIGESTS_INDEX = 1;
|
||||||
private static final Map<String, KeyBox> keyboxes = new HashMap<>();
|
private static final Map<String, KeyBox> keyboxes = new HashMap<>();
|
||||||
|
private static final int ATTESTATION_PACKAGE_INFO_PACKAGE_NAME_INDEX = 0;
|
||||||
|
|
||||||
private static final CertificateFactory certificateFactory;
|
private static final CertificateFactory certificateFactory;
|
||||||
|
|
||||||
@@ -55,11 +92,31 @@ public final class CertHack {
|
|||||||
throw new RuntimeException(t);
|
throw new RuntimeException(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static final int ATTESTATION_PACKAGE_INFO_VERSION_INDEX = 1;
|
||||||
|
|
||||||
public static boolean canHack() {
|
public static boolean canHack() {
|
||||||
return !keyboxes.isEmpty();
|
return !keyboxes.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static PEMKeyPair parseKeyPair(String key) throws Throwable {
|
||||||
|
try (PEMParser parser = new PEMParser(new StringReader(key))) {
|
||||||
|
return (PEMKeyPair) parser.readObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Certificate parseCert(String cert) throws Throwable {
|
||||||
|
try (PemReader reader = new PemReader(new StringReader(cert))) {
|
||||||
|
return certificateFactory.generateCertificate(new ByteArrayInputStream(reader.readPemObject().getContent()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] getByteArrayFromAsn1(ASN1Encodable asn1Encodable) throws CertificateParsingException {
|
||||||
|
if (!(asn1Encodable instanceof DEROctetString derOctectString)) {
|
||||||
|
throw new CertificateParsingException("Expected DEROctetString");
|
||||||
|
}
|
||||||
|
return derOctectString.getOctets();
|
||||||
|
}
|
||||||
|
|
||||||
public static void readFromXml(String data) {
|
public static void readFromXml(String data) {
|
||||||
keyboxes.clear();
|
keyboxes.clear();
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
@@ -92,7 +149,9 @@ public final class CertHack {
|
|||||||
} else {
|
} else {
|
||||||
algo = KeyProperties.KEY_ALGORITHM_RSA;
|
algo = KeyProperties.KEY_ALGORITHM_RSA;
|
||||||
}
|
}
|
||||||
keyboxes.put(algo, new KeyBox(parseKeyPair(privateKey), certificateChain));
|
var pemKp = parseKeyPair(privateKey);
|
||||||
|
var kp = new JcaPEMKeyConverter().getKeyPair(pemKp);
|
||||||
|
keyboxes.put(algo, new KeyBox(pemKp, kp, certificateChain));
|
||||||
}
|
}
|
||||||
Logger.i("update " + numberOfKeyboxes + " keyboxes");
|
Logger.i("update " + numberOfKeyboxes + " keyboxes");
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
@@ -100,26 +159,7 @@ public final class CertHack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PEMKeyPair parseKeyPair(String key) throws Throwable {
|
public static Certificate[] hackCertificateChain(Certificate[] caList) {
|
||||||
try (PEMParser parser = new PEMParser(new StringReader(key))) {
|
|
||||||
return (PEMKeyPair) parser.readObject();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Certificate parseCert(String cert) throws Throwable {
|
|
||||||
try (PemReader reader = new PemReader(new StringReader(cert))) {
|
|
||||||
return certificateFactory.generateCertificate(new ByteArrayInputStream(reader.readPemObject().getContent()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] getByteArrayFromAsn1(ASN1Encodable asn1Encodable) throws CertificateParsingException {
|
|
||||||
if (!(asn1Encodable instanceof DEROctetString derOctectString)) {
|
|
||||||
throw new CertificateParsingException("Expected DEROctetString");
|
|
||||||
}
|
|
||||||
return derOctectString.getOctets();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Certificate[] engineGetCertificateChain(Certificate[] caList) {
|
|
||||||
if (caList == null) throw new UnsupportedOperationException("caList is null!");
|
if (caList == null) throw new UnsupportedOperationException("caList is null!");
|
||||||
try {
|
try {
|
||||||
X509Certificate leaf = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(caList[0].getEncoded()));
|
X509Certificate leaf = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(caList[0].getEncoded()));
|
||||||
@@ -158,14 +198,10 @@ public final class CertHack {
|
|||||||
holder.getNotBefore(),
|
holder.getNotBefore(),
|
||||||
holder.getNotAfter(),
|
holder.getNotAfter(),
|
||||||
holder.getSubject(),
|
holder.getSubject(),
|
||||||
k.privateKey.getPublicKeyInfo()
|
k.pemKeyPair.getPublicKeyInfo()
|
||||||
);
|
);
|
||||||
signer = new JcaContentSignerBuilder(leaf.getSigAlgName())
|
signer = new JcaContentSignerBuilder(leaf.getSigAlgName())
|
||||||
.build(
|
.build(k.keyPair.getPrivate());
|
||||||
new JcaPEMKeyConverter()
|
|
||||||
.getPrivateKey(k.privateKey.getPrivateKeyInfo()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
byte[] verifiedBootKey = null;
|
byte[] verifiedBootKey = null;
|
||||||
byte[] verifiedBootHash = null;
|
byte[] verifiedBootHash = null;
|
||||||
@@ -221,4 +257,286 @@ public final class CertHack {
|
|||||||
}
|
}
|
||||||
return caList;
|
return caList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Pair<KeyPair, List<Certificate>> generateKeyPair(int uid, KeyDescriptor descriptor, KeyGenParameters params) {
|
||||||
|
Logger.i("Requested KeyPair with alias: " + descriptor.alias);
|
||||||
|
KeyPair rootKP;
|
||||||
|
X500Name issuer;
|
||||||
|
int size = params.keySize;
|
||||||
|
KeyPair kp = null;
|
||||||
|
KeyBox keyBox = null;
|
||||||
|
try {
|
||||||
|
var algo = params.algorithm;
|
||||||
|
if (algo == Algorithm.EC) {
|
||||||
|
Logger.d("GENERATING EC KEYPAIR OF SIZE " + size);
|
||||||
|
kp = buildECKeyPair(params);
|
||||||
|
keyBox = keyboxes.get(KeyProperties.KEY_ALGORITHM_EC);
|
||||||
|
} else if (algo == Algorithm.RSA) {
|
||||||
|
Logger.d("GENERATING RSA KEYPAIR OF SIZE " + size);
|
||||||
|
kp = buildRSAKeyPair(params);
|
||||||
|
keyBox = keyboxes.get(KeyProperties.KEY_ALGORITHM_RSA);
|
||||||
|
}
|
||||||
|
if (keyBox == null) {
|
||||||
|
Logger.e("UNSUPPORTED ALGORITHM: " + algo);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
rootKP = keyBox.keyPair;
|
||||||
|
issuer = new X509CertificateHolder(
|
||||||
|
keyBox.certificates.get(0).getEncoded()
|
||||||
|
).getSubject();
|
||||||
|
|
||||||
|
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(issuer,
|
||||||
|
params.certificateSerial,
|
||||||
|
params.certificateNotBefore,
|
||||||
|
params.certificateNotAfter,
|
||||||
|
params.certificateSubject,
|
||||||
|
kp.getPublic()
|
||||||
|
);
|
||||||
|
|
||||||
|
KeyUsage keyUsage = new KeyUsage(KeyUsage.keyCertSign);
|
||||||
|
certBuilder.addExtension(Extension.keyUsage, true, keyUsage);
|
||||||
|
certBuilder.addExtension(createExtension(params, uid));
|
||||||
|
|
||||||
|
ContentSigner contentSigner;
|
||||||
|
if (algo == Algorithm.EC) {
|
||||||
|
contentSigner = new JcaContentSignerBuilder("SHA256withECDSA").build(rootKP.getPrivate());
|
||||||
|
} else {
|
||||||
|
contentSigner = new JcaContentSignerBuilder("SHA256withRSA").build(rootKP.getPrivate());
|
||||||
|
}
|
||||||
|
X509CertificateHolder certHolder = certBuilder.build(contentSigner);
|
||||||
|
var leaf = new JcaX509CertificateConverter().getCertificate(certHolder);
|
||||||
|
List<Certificate> chain = new ArrayList<>(keyBox.certificates);
|
||||||
|
chain.add(0, leaf);
|
||||||
|
Logger.d("Successfully generated X500 Cert for alias: " + descriptor.alias);
|
||||||
|
return new Pair<>(kp, chain);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Logger.e("", t);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static KeyPair buildECKeyPair(KeyGenParameters params) throws Exception {
|
||||||
|
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
ECGenParameterSpec spec = new ECGenParameterSpec(params.ecCurveName);
|
||||||
|
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDSA", BouncyCastleProvider.PROVIDER_NAME);
|
||||||
|
kpg.initialize(spec);
|
||||||
|
return kpg.generateKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static KeyPair buildRSAKeyPair(KeyGenParameters params) throws Exception {
|
||||||
|
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(
|
||||||
|
params.keySize, params.rsaPublicExponent);
|
||||||
|
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME);
|
||||||
|
kpg.initialize(spec);
|
||||||
|
return kpg.generateKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ASN1Encodable[] fromIntList(List<Integer> list) {
|
||||||
|
ASN1Encodable[] result = new ASN1Encodable[list.size()];
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
result[i] = new ASN1Integer(list.get(i));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Extension createExtension(KeyGenParameters params, int uid) {
|
||||||
|
try {
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
|
||||||
|
byte[] key = new byte[32];
|
||||||
|
byte[] hash = UtilKt.getBootHashFromProp();
|
||||||
|
|
||||||
|
random.nextBytes(key);
|
||||||
|
if (hash == null || hash.length != 32) {
|
||||||
|
hash = new byte[32];
|
||||||
|
random.nextBytes(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASN1Encodable[] rootOfTrustEncodables = {new DEROctetString(key), ASN1Boolean.TRUE,
|
||||||
|
new ASN1Enumerated(0), new DEROctetString(hash)};
|
||||||
|
|
||||||
|
ASN1Sequence rootOfTrustSeq = new DERSequence(rootOfTrustEncodables);
|
||||||
|
|
||||||
|
var Apurpose = new DERSet(fromIntList(params.purpose));
|
||||||
|
var Aalgorithm = new ASN1Integer(params.algorithm);
|
||||||
|
var AkeySize = new ASN1Integer(params.keySize);
|
||||||
|
var Adigest = new DERSet(fromIntList(params.digest));
|
||||||
|
var AecCurve = new ASN1Integer(params.ecCurve);
|
||||||
|
var AnoAuthRequired = DERNull.INSTANCE;
|
||||||
|
|
||||||
|
// To be loaded
|
||||||
|
var AosVersion = new ASN1Integer(UtilKt.getOsVersion());
|
||||||
|
var AosPatchLevel = new ASN1Integer(UtilKt.getPatchLevel());
|
||||||
|
|
||||||
|
// TODO hex3l: add applicationID to attestation
|
||||||
|
var AapplicationID = createApplicationId(uid);
|
||||||
|
var AbootPatchlevel = new ASN1Integer(UtilKt.getPatchLevelLong());
|
||||||
|
var AvendorPatchLevel = new ASN1Integer(UtilKt.getPatchLevelLong());
|
||||||
|
|
||||||
|
var AcreationDateTime = new ASN1Integer(System.currentTimeMillis());
|
||||||
|
var Aorigin = new ASN1Integer(0);
|
||||||
|
|
||||||
|
var purpose = new DERTaggedObject(true, 1, Apurpose);
|
||||||
|
var algorithm = new DERTaggedObject(true, 2, Aalgorithm);
|
||||||
|
var keySize = new DERTaggedObject(true, 3, AkeySize);
|
||||||
|
var digest = new DERTaggedObject(true, 5, Adigest);
|
||||||
|
var ecCurve = new DERTaggedObject(true, 10, AecCurve);
|
||||||
|
var noAuthRequired = new DERTaggedObject(true, 503, AnoAuthRequired);
|
||||||
|
var creationDateTime = new DERTaggedObject(true, 701, AcreationDateTime);
|
||||||
|
var origin = new DERTaggedObject(true, 702, Aorigin);
|
||||||
|
var rootOfTrust = new DERTaggedObject(true, 704, rootOfTrustSeq);
|
||||||
|
var osVersion = new DERTaggedObject(true, 705, AosVersion);
|
||||||
|
var osPatchLevel = new DERTaggedObject(true, 706, AosPatchLevel);
|
||||||
|
var applicationID = new DERTaggedObject(true, 709, AapplicationID);
|
||||||
|
var vendorPatchLevel = new DERTaggedObject(true, 718, AvendorPatchLevel);
|
||||||
|
var bootPatchLevel = new DERTaggedObject(true, 719, AbootPatchlevel);
|
||||||
|
|
||||||
|
ASN1Encodable[] teeEnforcedEncodables = {purpose, algorithm, keySize, digest, ecCurve,
|
||||||
|
noAuthRequired, creationDateTime, origin, rootOfTrust, osVersion, osPatchLevel, applicationID, vendorPatchLevel, bootPatchLevel};
|
||||||
|
|
||||||
|
ASN1OctetString keyDescriptionOctetStr = getAsn1OctetString(teeEnforcedEncodables, params);
|
||||||
|
|
||||||
|
return new Extension(new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17"), false, keyDescriptionOctetStr);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Logger.e("", t);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ASN1OctetString getAsn1OctetString(ASN1Encodable[] teeEnforcedEncodables, KeyGenParameters params) throws IOException {
|
||||||
|
ASN1Integer attestationVersion = new ASN1Integer(100);
|
||||||
|
ASN1Enumerated attestationSecurityLevel = new ASN1Enumerated(1);
|
||||||
|
ASN1Integer keymasterVersion = new ASN1Integer(100);
|
||||||
|
ASN1Enumerated keymasterSecurityLevel = new ASN1Enumerated(1);
|
||||||
|
ASN1OctetString attestationChallenge = new DEROctetString(params.attestationChallenge);
|
||||||
|
ASN1OctetString uniqueId = new DEROctetString("".getBytes());
|
||||||
|
ASN1Sequence softwareEnforced = new DERSequence();
|
||||||
|
ASN1Sequence teeEnforced = new DERSequence(teeEnforcedEncodables);
|
||||||
|
|
||||||
|
ASN1Encodable[] keyDescriptionEncodables = {attestationVersion, attestationSecurityLevel, keymasterVersion,
|
||||||
|
keymasterSecurityLevel, attestationChallenge, uniqueId, softwareEnforced, teeEnforced};
|
||||||
|
|
||||||
|
ASN1Sequence keyDescriptionHackSeq = new DERSequence(keyDescriptionEncodables);
|
||||||
|
|
||||||
|
return new DEROctetString(keyDescriptionHackSeq);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DEROctetString createApplicationId(int uid) throws Throwable {
|
||||||
|
var pm = Config.INSTANCE.getPm();
|
||||||
|
if (pm == null) {
|
||||||
|
throw new IllegalStateException("createApplicationId: pm not found!");
|
||||||
|
}
|
||||||
|
var packages = pm.getPackagesForUid(uid);
|
||||||
|
var size = packages.length;
|
||||||
|
ASN1Encodable[] packageInfoAA = new ASN1Encodable[size];
|
||||||
|
Set<Digest> signatures = new HashSet<>();
|
||||||
|
var dg = MessageDigest.getInstance("SHA-256");
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
var name = packages[i];
|
||||||
|
var info = pm.getPackageInfo(name, PackageManager.GET_SIGNATURES, uid / 100000);
|
||||||
|
ASN1Encodable[] arr = new ASN1Encodable[2];
|
||||||
|
arr[ATTESTATION_PACKAGE_INFO_PACKAGE_NAME_INDEX] =
|
||||||
|
new DEROctetString(packages[i].getBytes(StandardCharsets.UTF_8));
|
||||||
|
arr[ATTESTATION_PACKAGE_INFO_VERSION_INDEX] = new ASN1Integer(info.getLongVersionCode());
|
||||||
|
packageInfoAA[i] = new DERSequence(arr);
|
||||||
|
for (var s : info.signatures) {
|
||||||
|
signatures.add(new Digest(dg.digest(s.toByteArray())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASN1Encodable[] signaturesAA = new ASN1Encodable[signatures.size()];
|
||||||
|
var i = 0;
|
||||||
|
for (var d : signatures) {
|
||||||
|
signaturesAA[i] = new DEROctetString(d.digest);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASN1Encodable[] applicationIdAA = new ASN1Encodable[2];
|
||||||
|
applicationIdAA[ATTESTATION_APPLICATION_ID_PACKAGE_INFOS_INDEX] =
|
||||||
|
new DERSet(packageInfoAA);
|
||||||
|
applicationIdAA[ATTESTATION_APPLICATION_ID_SIGNATURE_DIGESTS_INDEX] =
|
||||||
|
new DERSet(signaturesAA);
|
||||||
|
|
||||||
|
return new DEROctetString(new DERSequence(applicationIdAA).getEncoded());
|
||||||
|
}
|
||||||
|
|
||||||
|
record Digest(byte[] digest) {
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable Object o) {
|
||||||
|
if (o instanceof Digest d)
|
||||||
|
return Arrays.equals(digest, d.digest);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Arrays.hashCode(digest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record KeyBox(PEMKeyPair pemKeyPair, KeyPair keyPair, List<Certificate> certificates) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class KeyGenParameters {
|
||||||
|
public int keySize;
|
||||||
|
public int algorithm;
|
||||||
|
public BigInteger certificateSerial;
|
||||||
|
public Date certificateNotBefore;
|
||||||
|
public Date certificateNotAfter;
|
||||||
|
public X500Name certificateSubject;
|
||||||
|
|
||||||
|
public BigInteger rsaPublicExponent;
|
||||||
|
public int ecCurve;
|
||||||
|
public String ecCurveName;
|
||||||
|
|
||||||
|
public List<Integer> purpose = new ArrayList<>();
|
||||||
|
public List<Integer> digest = new ArrayList<>();
|
||||||
|
|
||||||
|
public byte[] attestationChallenge;
|
||||||
|
|
||||||
|
public KeyGenParameters(KeyParameter[] params) {
|
||||||
|
for (var kp : params) {
|
||||||
|
var p = kp.value;
|
||||||
|
switch (kp.tag) {
|
||||||
|
case Tag.KEY_SIZE -> keySize = p.getInteger();
|
||||||
|
case Tag.ALGORITHM -> algorithm = p.getAlgorithm();
|
||||||
|
case Tag.CERTIFICATE_SERIAL -> certificateSerial = new BigInteger(p.getBlob());
|
||||||
|
case Tag.CERTIFICATE_NOT_BEFORE ->
|
||||||
|
certificateNotBefore = new Date(p.getDateTime());
|
||||||
|
case Tag.CERTIFICATE_NOT_AFTER ->
|
||||||
|
certificateNotAfter = new Date(p.getDateTime());
|
||||||
|
case Tag.CERTIFICATE_SUBJECT ->
|
||||||
|
certificateSubject = new X500Name(new X500Principal(p.getBlob()).getName());
|
||||||
|
case Tag.RSA_PUBLIC_EXPONENT -> rsaPublicExponent = new BigInteger(p.getBlob());
|
||||||
|
case Tag.EC_CURVE -> {
|
||||||
|
ecCurve = p.getEcCurve();
|
||||||
|
ecCurveName = getEcCurveName(ecCurve);
|
||||||
|
}
|
||||||
|
case Tag.PURPOSE -> {
|
||||||
|
purpose.add(p.getKeyPurpose());
|
||||||
|
}
|
||||||
|
case Tag.DIGEST -> {
|
||||||
|
digest.add(p.getDigest());
|
||||||
|
}
|
||||||
|
case Tag.ATTESTATION_CHALLENGE -> attestationChallenge = p.getBlob();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getEcCurveName(int curve) {
|
||||||
|
String res;
|
||||||
|
switch (curve) {
|
||||||
|
case EcCurve.CURVE_25519 -> res = "CURVE_25519";
|
||||||
|
case EcCurve.P_224 -> res = "secp224r1";
|
||||||
|
case EcCurve.P_256 -> res = "secp256r1";
|
||||||
|
case EcCurve.P_384 -> res = "secp384r1";
|
||||||
|
case EcCurve.P_521 -> res = "secp521r1";
|
||||||
|
default -> throw new IllegalArgumentException("unknown curve");
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package io.github.a13e300.tricky_store.keystore;
|
package io.github.a13e300.tricky_store.keystore;
|
||||||
|
|
||||||
import android.system.keystore2.KeyEntryResponse;
|
import android.system.keystore2.KeyEntryResponse;
|
||||||
|
import android.system.keystore2.KeyMetadata;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@@ -58,12 +59,16 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void putCertificateChain(KeyEntryResponse response, Certificate[] chain) throws Throwable {
|
public static void putCertificateChain(KeyEntryResponse response, Certificate[] chain) throws Throwable {
|
||||||
|
putCertificateChain(response.metadata, chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void putCertificateChain(KeyMetadata metadata, Certificate[] chain) throws Throwable {
|
||||||
if (chain == null || chain.length == 0) return;
|
if (chain == null || chain.length == 0) return;
|
||||||
response.metadata.certificate = chain[0].getEncoded();
|
metadata.certificate = chain[0].getEncoded();
|
||||||
var output = new ByteArrayOutputStream();
|
var output = new ByteArrayOutputStream();
|
||||||
for (int i = 1; i < chain.length; i++) {
|
for (int i = 1; i < chain.length; i++) {
|
||||||
output.write(chain[i].getEncoded());
|
output.write(chain[i].getEncoded());
|
||||||
}
|
}
|
||||||
response.metadata.certificateChain = output.toByteArray();
|
metadata.certificateChain = output.toByteArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
40
service/src/main/java/io/github/a13e300/tricky_store/util.kt
Normal file
40
service/src/main/java/io/github/a13e300/tricky_store/util.kt
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package io.github.a13e300.tricky_store
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.SystemProperties
|
||||||
|
|
||||||
|
fun getTransactCode(clazz: Class<*>, method: String) =
|
||||||
|
clazz.getDeclaredField("TRANSACTION_$method").apply { isAccessible = true }
|
||||||
|
.getInt(null) // 2
|
||||||
|
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
val bootHashFromProp by lazy {
|
||||||
|
val b = SystemProperties.get("ro.boot.vbmeta.digest", null) ?: return@lazy null
|
||||||
|
if (b.length != 64) return@lazy null
|
||||||
|
b.hexToByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
val patchLevel by lazy {
|
||||||
|
Build.VERSION.SECURITY_PATCH.convertPatchLevel(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val patchLevelLong by lazy {
|
||||||
|
Build.VERSION.SECURITY_PATCH.convertPatchLevel(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
val osVersion by lazy {
|
||||||
|
when (Build.VERSION.SDK_INT) {
|
||||||
|
Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> 140000
|
||||||
|
Build.VERSION_CODES.TIRAMISU -> 130000
|
||||||
|
Build.VERSION_CODES.S_V2 -> 120100
|
||||||
|
Build.VERSION_CODES.S -> 120000
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.convertPatchLevel(long: Boolean) = kotlin.runCatching {
|
||||||
|
val l = split("-")
|
||||||
|
if (long) l[0].toInt() * 10000 + l[1].toInt() * 100 + l[2].toInt()
|
||||||
|
else l[0].toInt() * 100 + l[1].toInt()
|
||||||
|
}.onFailure { Logger.e("invalid patch level $this !", it) }.getOrDefault(202404)
|
||||||
@@ -5,6 +5,8 @@ import android.os.IBinder;
|
|||||||
public interface IPackageManager {
|
public interface IPackageManager {
|
||||||
String[] getPackagesForUid(int uid);
|
String[] getPackagesForUid(int uid);
|
||||||
|
|
||||||
|
PackageInfo getPackageInfo(String packageName, long flags, int userId);
|
||||||
|
|
||||||
class Stub {
|
class Stub {
|
||||||
public static IPackageManager asInterface(IBinder binder) {
|
public static IPackageManager asInterface(IBinder binder) {
|
||||||
throw new RuntimeException("");
|
throw new RuntimeException("");
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package android.hardware.security.keymint;
|
||||||
|
|
||||||
|
public @interface Algorithm {
|
||||||
|
int AES = 32;
|
||||||
|
int EC = 3;
|
||||||
|
int HMAC = 128;
|
||||||
|
int RSA = 1;
|
||||||
|
int TRIPLE_DES = 33;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package android.hardware.security.keymint;
|
||||||
|
|
||||||
|
/* loaded from: classes2.dex */
|
||||||
|
public @interface EcCurve {
|
||||||
|
public static final int CURVE_25519 = 4;
|
||||||
|
public static final int P_224 = 0;
|
||||||
|
public static final int P_256 = 1;
|
||||||
|
public static final int P_384 = 2;
|
||||||
|
public static final int P_521 = 3;
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package android.hardware.security.keymint;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
public class KeyParameter implements Parcelable {
|
||||||
|
public static final Creator<KeyParameter> CREATOR = new Creator<>() {
|
||||||
|
@Override
|
||||||
|
public KeyParameter createFromParcel(Parcel in) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyParameter[] newArray(int size) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public int tag = 0;
|
||||||
|
public KeyParameterValue value;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(@NonNull Parcel parcel, int i) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
package android.hardware.security.keymint;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
/* loaded from: classes2.dex */
|
||||||
|
public final class KeyParameterValue implements Parcelable {
|
||||||
|
public static final int algorithm = 1;
|
||||||
|
public static final int blob = 14;
|
||||||
|
public static final int blockMode = 2;
|
||||||
|
public static final int boolValue = 10;
|
||||||
|
public static final int dateTime = 13;
|
||||||
|
public static final int digest = 4;
|
||||||
|
public static final int ecCurve = 5;
|
||||||
|
public static final int hardwareAuthenticatorType = 8;
|
||||||
|
public static final int integer = 11;
|
||||||
|
public static final int invalid = 0;
|
||||||
|
public static final int keyPurpose = 7;
|
||||||
|
public static final int longInteger = 12;
|
||||||
|
public static final int origin = 6;
|
||||||
|
public static final int paddingMode = 3;
|
||||||
|
public static final int securityLevel = 9;
|
||||||
|
public static final Creator<KeyParameterValue> CREATOR = new Creator<KeyParameterValue>() {
|
||||||
|
@Override
|
||||||
|
public KeyParameterValue createFromParcel(Parcel in) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyParameterValue[] newArray(int size) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public KeyParameterValue() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected KeyParameterValue(Parcel in) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue invalid(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue algorithm(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue blockMode(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue paddingMode(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue digest(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue ecCurve(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue origin(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue keyPurpose(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue hardwareAuthenticatorType(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue securityLevel(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue boolValue(boolean _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue integer(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue longInteger(long _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue dateTime(long _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyParameterValue blob(byte[] _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTag() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInvalid() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInvalid(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAlgorithm() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlgorithm(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBlockMode() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlockMode(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPaddingMode() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPaddingMode(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDigest() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDigest(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEcCurve() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEcCurve(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOrigin() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrigin(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKeyPurpose() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyPurpose(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHardwareAuthenticatorType() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHardwareAuthenticatorType(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSecurityLevel() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecurityLevel(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getBoolValue() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoolValue(boolean _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInteger() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInteger(int _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLongInteger() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLongInteger(long _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDateTime() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateTime(long _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBlob() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlob(byte[] _value) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(@NonNull Parcel parcel, int i) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package android.hardware.security.keymint;
|
||||||
|
|
||||||
|
public @interface KeyPurpose {
|
||||||
|
int AGREE_KEY = 6;
|
||||||
|
int ATTEST_KEY = 7;
|
||||||
|
int DECRYPT = 1;
|
||||||
|
int ENCRYPT = 0;
|
||||||
|
int SIGN = 2;
|
||||||
|
int VERIFY = 3;
|
||||||
|
int WRAP_KEY = 5;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package android.hardware.security.keymint;
|
||||||
|
|
||||||
|
public @interface SecurityLevel {
|
||||||
|
int KEYSTORE = 100;
|
||||||
|
int SOFTWARE = 0;
|
||||||
|
int STRONGBOX = 2;
|
||||||
|
int TRUSTED_ENVIRONMENT = 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package android.hardware.security.keymint;
|
||||||
|
|
||||||
|
public @interface Tag {
|
||||||
|
int ACTIVE_DATETIME = 1610613136;
|
||||||
|
int ALGORITHM = 268435458;
|
||||||
|
int ALLOW_WHILE_ON_BODY = 1879048698;
|
||||||
|
int APPLICATION_DATA = -1879047492;
|
||||||
|
int APPLICATION_ID = -1879047591;
|
||||||
|
int ASSOCIATED_DATA = -1879047192;
|
||||||
|
int ATTESTATION_APPLICATION_ID = -1879047483;
|
||||||
|
int ATTESTATION_CHALLENGE = -1879047484;
|
||||||
|
int ATTESTATION_ID_BRAND = -1879047482;
|
||||||
|
int ATTESTATION_ID_DEVICE = -1879047481;
|
||||||
|
int ATTESTATION_ID_IMEI = -1879047478;
|
||||||
|
int ATTESTATION_ID_MANUFACTURER = -1879047476;
|
||||||
|
int ATTESTATION_ID_MEID = -1879047477;
|
||||||
|
int ATTESTATION_ID_MODEL = -1879047475;
|
||||||
|
int ATTESTATION_ID_PRODUCT = -1879047480;
|
||||||
|
int ATTESTATION_ID_SECOND_IMEI = -1879047469;
|
||||||
|
int ATTESTATION_ID_SERIAL = -1879047479;
|
||||||
|
int AUTH_TIMEOUT = 805306873;
|
||||||
|
int BLOCK_MODE = 536870916;
|
||||||
|
int BOOTLOADER_ONLY = 1879048494;
|
||||||
|
int BOOT_PATCHLEVEL = 805307087;
|
||||||
|
int CALLER_NONCE = 1879048199;
|
||||||
|
int CERTIFICATE_NOT_AFTER = 1610613745;
|
||||||
|
int CERTIFICATE_NOT_BEFORE = 1610613744;
|
||||||
|
int CERTIFICATE_SERIAL = -2147482642;
|
||||||
|
int CERTIFICATE_SUBJECT = -1879047185;
|
||||||
|
int CONFIRMATION_TOKEN = -1879047187;
|
||||||
|
int CREATION_DATETIME = 1610613437;
|
||||||
|
int DEVICE_UNIQUE_ATTESTATION = 1879048912;
|
||||||
|
int DIGEST = 536870917;
|
||||||
|
int EARLY_BOOT_ONLY = 1879048497;
|
||||||
|
int EC_CURVE = 268435466;
|
||||||
|
int HARDWARE_TYPE = 268435760;
|
||||||
|
int IDENTITY_CREDENTIAL_KEY = 1879048913;
|
||||||
|
int INCLUDE_UNIQUE_ID = 1879048394;
|
||||||
|
int INVALID = 0;
|
||||||
|
int KEY_SIZE = 805306371;
|
||||||
|
int MAC_LENGTH = 805307371;
|
||||||
|
int MAX_BOOT_LEVEL = 805307378;
|
||||||
|
int MAX_USES_PER_BOOT = 805306772;
|
||||||
|
int MIN_MAC_LENGTH = 805306376;
|
||||||
|
int MIN_SECONDS_BETWEEN_OPS = 805306771;
|
||||||
|
int NONCE = -1879047191;
|
||||||
|
int NO_AUTH_REQUIRED = 1879048695;
|
||||||
|
int ORIGIN = 268436158;
|
||||||
|
int ORIGINATION_EXPIRE_DATETIME = 1610613137;
|
||||||
|
int OS_PATCHLEVEL = 805307074;
|
||||||
|
int OS_VERSION = 805307073;
|
||||||
|
int PADDING = 536870918;
|
||||||
|
int PURPOSE = 536870913;
|
||||||
|
int RESET_SINCE_ID_ROTATION = 1879049196;
|
||||||
|
int ROLLBACK_RESISTANCE = 1879048495;
|
||||||
|
int ROOT_OF_TRUST = -1879047488;
|
||||||
|
int RSA_OAEP_MGF_DIGEST = 536871115;
|
||||||
|
int RSA_PUBLIC_EXPONENT = 1342177480;
|
||||||
|
int STORAGE_KEY = 1879048914;
|
||||||
|
int TRUSTED_CONFIRMATION_REQUIRED = 1879048700;
|
||||||
|
int TRUSTED_USER_PRESENCE_REQUIRED = 1879048699;
|
||||||
|
int UNIQUE_ID = -1879047485;
|
||||||
|
int UNLOCKED_DEVICE_REQUIRED = 1879048701;
|
||||||
|
int USAGE_COUNT_LIMIT = 805306773;
|
||||||
|
int USAGE_EXPIRE_DATETIME = 1610613138;
|
||||||
|
int USER_AUTH_TYPE = 268435960;
|
||||||
|
int USER_ID = 805306869;
|
||||||
|
int USER_SECURE_ID = -1610612234;
|
||||||
|
int VENDOR_PATCHLEVEL = 805307086;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package android.system.keystore2;
|
||||||
|
|
||||||
|
import android.hardware.security.keymint.KeyParameter;
|
||||||
|
|
||||||
|
public class Authorization {
|
||||||
|
public KeyParameter keyParameter;
|
||||||
|
public int securityLevel = 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package android.system.keystore2;
|
||||||
|
|
||||||
|
import android.hardware.security.keymint.KeyParameter;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.IInterface;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
public interface IKeystoreSecurityLevel extends IInterface {
|
||||||
|
String DESCRIPTOR = "android.system.keystore2.IKeystoreSecurityLevel";
|
||||||
|
|
||||||
|
KeyMetadata generateKey(KeyDescriptor key, @Nullable KeyDescriptor attestationKey,
|
||||||
|
KeyParameter[] params, int flags, byte[] entropy);
|
||||||
|
|
||||||
|
class Stub {
|
||||||
|
public static IKeystoreSecurityLevel asInterface(IBinder b) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,15 @@
|
|||||||
package android.system.keystore2;
|
package android.system.keystore2;
|
||||||
|
|
||||||
|
import android.os.IBinder;
|
||||||
|
|
||||||
public interface IKeystoreService {
|
public interface IKeystoreService {
|
||||||
String DESCRIPTOR = "android.system.keystore2.IKeystoreService";
|
String DESCRIPTOR = "android.system.keystore2.IKeystoreService";
|
||||||
|
|
||||||
class Stub {
|
IKeystoreSecurityLevel getSecurityLevel(int securityLevel);
|
||||||
|
|
||||||
|
class Stub {
|
||||||
|
public static IKeystoreService asInterface(IBinder b) {
|
||||||
|
throw new RuntimeException("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,19 +11,15 @@ public class KeyDescriptor implements Parcelable {
|
|||||||
public int domain = 0;
|
public int domain = 0;
|
||||||
public long nspace = 0;
|
public long nspace = 0;
|
||||||
|
|
||||||
protected KeyDescriptor(Parcel in) {
|
|
||||||
throw new RuntimeException("");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final Creator<KeyDescriptor> CREATOR = new Creator<KeyDescriptor>() {
|
public static final Creator<KeyDescriptor> CREATOR = new Creator<KeyDescriptor>() {
|
||||||
@Override
|
@Override
|
||||||
public KeyDescriptor createFromParcel(Parcel in) {
|
public KeyDescriptor createFromParcel(Parcel in) {
|
||||||
return new KeyDescriptor(in);
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyDescriptor[] newArray(int size) {
|
public KeyDescriptor[] newArray(int size) {
|
||||||
return new KeyDescriptor[size];
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,9 @@ import android.os.Parcelable;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
public class KeyEntryResponse implements Parcelable {
|
public class KeyEntryResponse implements Parcelable {
|
||||||
// public IKeystoreSecurityLevel iSecurityLevel;
|
public IKeystoreSecurityLevel iSecurityLevel;
|
||||||
public KeyMetadata metadata;
|
public KeyMetadata metadata;
|
||||||
|
|
||||||
protected KeyEntryResponse(Parcel in) {
|
|
||||||
throw new RuntimeException("");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final Creator<KeyEntryResponse> CREATOR = new Creator<KeyEntryResponse>() {
|
public static final Creator<KeyEntryResponse> CREATOR = new Creator<KeyEntryResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public KeyEntryResponse createFromParcel(Parcel in) {
|
public KeyEntryResponse createFromParcel(Parcel in) {
|
||||||
|
|||||||
@@ -6,17 +6,13 @@ import android.os.Parcelable;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
public class KeyMetadata implements Parcelable {
|
public class KeyMetadata implements Parcelable {
|
||||||
// public Authorization[] authorizations;
|
public Authorization[] authorizations;
|
||||||
public byte[] certificate;
|
public byte[] certificate;
|
||||||
public byte[] certificateChain;
|
public byte[] certificateChain;
|
||||||
public KeyDescriptor key;
|
public KeyDescriptor key;
|
||||||
public int keySecurityLevel = 0;
|
public int keySecurityLevel = 0;
|
||||||
public long modificationTimeMs = 0;
|
public long modificationTimeMs = 0;
|
||||||
|
|
||||||
protected KeyMetadata(Parcel in) {
|
|
||||||
throw new RuntimeException("");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final Creator<KeyMetadata> CREATOR = new Creator<KeyMetadata>() {
|
public static final Creator<KeyMetadata> CREATOR = new Creator<KeyMetadata>() {
|
||||||
@Override
|
@Override
|
||||||
public KeyMetadata createFromParcel(Parcel in) {
|
public KeyMetadata createFromParcel(Parcel in) {
|
||||||
|
|||||||
Reference in New Issue
Block a user