From 994d5313046aa7c64652a3abc8c14ab58abaefe1 Mon Sep 17 00:00:00 2001 From: 5ec1cff Date: Tue, 16 Jul 2024 09:15:08 +0800 Subject: [PATCH] support generate key --- service/proguard-rules.pro | 5 + .../io/github/a13e300/tricky_store/Config.kt | 39 +- .../tricky_store/KeystoreInterceptor.kt | 73 +++- .../tricky_store/SecurityLevelInterceptor.kt | 141 +++++++ .../tricky_store/keystore/CertHack.java | 374 ++++++++++++++++-- .../a13e300/tricky_store/keystore/Utils.java | 9 +- .../io/github/a13e300/tricky_store/util.kt | 40 ++ .../android/content/pm/IPackageManager.java | 2 + .../hardware/security/keymint/Algorithm.java | 9 + .../hardware/security/keymint/EcCurve.java | 10 + .../security/keymint/KeyParameter.java | 32 ++ .../security/keymint/KeyParameterValue.java | 239 +++++++++++ .../hardware/security/keymint/KeyPurpose.java | 11 + .../security/keymint/SecurityLevel.java | 8 + .../hardware/security/keymint/Tag.java | 70 ++++ .../system/keystore2/Authorization.java | 8 + .../keystore2/IKeystoreSecurityLevel.java | 20 + .../system/keystore2/IKeystoreService.java | 8 +- .../system/keystore2/KeyDescriptor.java | 8 +- .../system/keystore2/KeyEntryResponse.java | 6 +- .../android/system/keystore2/KeyMetadata.java | 6 +- 21 files changed, 1047 insertions(+), 71 deletions(-) create mode 100644 service/src/main/java/io/github/a13e300/tricky_store/SecurityLevelInterceptor.kt create mode 100644 service/src/main/java/io/github/a13e300/tricky_store/util.kt create mode 100644 stub/src/main/java/android/hardware/security/keymint/Algorithm.java create mode 100644 stub/src/main/java/android/hardware/security/keymint/EcCurve.java create mode 100644 stub/src/main/java/android/hardware/security/keymint/KeyParameter.java create mode 100644 stub/src/main/java/android/hardware/security/keymint/KeyParameterValue.java create mode 100644 stub/src/main/java/android/hardware/security/keymint/KeyPurpose.java create mode 100644 stub/src/main/java/android/hardware/security/keymint/SecurityLevel.java create mode 100644 stub/src/main/java/android/hardware/security/keymint/Tag.java create mode 100644 stub/src/main/java/android/system/keystore2/Authorization.java create mode 100644 stub/src/main/java/android/system/keystore2/IKeystoreSecurityLevel.java diff --git a/service/proguard-rules.pro b/service/proguard-rules.pro index 082bf02..65b9810 100644 --- a/service/proguard-rules.pro +++ b/service/proguard-rules.pro @@ -26,3 +26,8 @@ -assumenosideeffects class io.github.a13e300.tricky_store.Logger { 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.** diff --git a/service/src/main/java/io/github/a13e300/tricky_store/Config.kt b/service/src/main/java/io/github/a13e300/tricky_store/Config.kt index e85968a..7bb18e6 100644 --- a/service/src/main/java/io/github/a13e300/tricky_store/Config.kt +++ b/service/src/main/java/io/github/a13e300/tricky_store/Config.kt @@ -1,11 +1,14 @@ package io.github.a13e300.tricky_store +import android.content.pm.IPackageManager import android.os.FileObserver +import android.os.ServiceManager import io.github.a13e300.tricky_store.keystore.CertHack import java.io.File object Config { - val targetPackages = mutableSetOf() + private val hackPackages = mutableSetOf() + private val generatePackages = mutableSetOf() private val DEFAULT_TARGET_PACKAGES = listOf( "com.google.android.gms", "icu.nullptr.nativetest", @@ -14,11 +17,16 @@ object Config { ) private fun updateTargetPackages(f: File?) = runCatching { - targetPackages.clear() - f?.readLines()?.mapNotNullTo(targetPackages) { - if (it.isNotBlank() && !it.startsWith("#")) it else null + hackPackages.clear() + generatePackages.clear() + 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 { Logger.e("failed to update target files", it) } @@ -65,4 +73,25 @@ object Config { } 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 } diff --git a/service/src/main/java/io/github/a13e300/tricky_store/KeystoreInterceptor.kt b/service/src/main/java/io/github/a13e300/tricky_store/KeystoreInterceptor.kt index 4fcca61..ce9f8c9 100644 --- a/service/src/main/java/io/github/a13e300/tricky_store/KeystoreInterceptor.kt +++ b/service/src/main/java/io/github/a13e300/tricky_store/KeystoreInterceptor.kt @@ -1,11 +1,12 @@ package io.github.a13e300.tricky_store import android.annotation.SuppressLint -import android.content.pm.IPackageManager +import android.hardware.security.keymint.SecurityLevel import android.os.IBinder import android.os.Parcel import android.os.ServiceManager import android.system.keystore2.IKeystoreService +import android.system.keystore2.KeyDescriptor import android.system.keystore2.KeyEntryResponse import io.github.a13e300.tricky_store.binder.BinderInterceptor import io.github.a13e300.tricky_store.keystore.CertHack @@ -13,17 +14,14 @@ import io.github.a13e300.tricky_store.keystore.Utils import kotlin.system.exitProcess @SuppressLint("BlockedPrivateApi") -object KeystoreInterceptor : BinderInterceptor() { - private val targetTransaction = IKeystoreService.Stub::class.java.getDeclaredField("TRANSACTION_getKeyEntry").apply { isAccessible = true }.getInt(null) // 2 +object KeystoreInterceptor : BinderInterceptor() { + private val getKeyEntryTransaction = + getTransactCode(IKeystoreService.Stub::class.java, "getKeyEntry") // 2 - private var iPm: IPackageManager? = null + private lateinit var keystore: IBinder - private fun getPm(): IPackageManager? { - if (iPm == null) { - iPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")) - } - return iPm - } + private var teeInterceptor: SecurityLevelInterceptor? = null + private var strongBoxInterceptor: SecurityLevelInterceptor? = null override fun onPreTransact( target: IBinder, @@ -33,12 +31,26 @@ object KeystoreInterceptor : BinderInterceptor() { callingPid: Int, data: Parcel ): Result { - if (code == targetTransaction && CertHack.canHack() && Config.targetPackages.isNotEmpty()) { - Logger.d("intercept pre $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()}") - kotlin.runCatching { - val ps = getPm()?.getPackagesForUid(callingUid) - if (ps?.any { it in Config.targetPackages } == true) return Continue - }.onFailure { Logger.e("failed to get packages", it) } + if (code == getKeyEntryTransaction) { + if (CertHack.canHack()) { + Logger.d("intercept pre $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()}") + if (Config.needGenerate(callingUid)) + kotlin.runCatching { + 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 } @@ -53,7 +65,7 @@ object KeystoreInterceptor : BinderInterceptor() { reply: Parcel?, resultCode: Int ): Result { - if (code != targetTransaction || reply == null) return Skip + if (target != keystore || code != getKeyEntryTransaction || reply == null) return Skip val p = Parcel.obtain() Logger.d("intercept post $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()} replySz=${reply.dataSize()}") try { @@ -61,7 +73,7 @@ object KeystoreInterceptor : BinderInterceptor() { val response = reply.readTypedObject(KeyEntryResponse.CREATOR) val chain = Utils.getCertificateChain(response) if (chain != null) { - val newChain = CertHack.engineGetCertificateChain(chain) + val newChain = CertHack.hackCertificateChain(chain) Utils.putCertificateChain(response, newChain) p.writeNoException() p.writeTypedObject(response, 0) @@ -98,8 +110,31 @@ object KeystoreInterceptor : BinderInterceptor() { } 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) - 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 } diff --git a/service/src/main/java/io/github/a13e300/tricky_store/SecurityLevelInterceptor.kt b/service/src/main/java/io/github/a13e300/tricky_store/SecurityLevelInterceptor.kt new file mode 100644 index 0000000..a1af1c9 --- /dev/null +++ b/service/src/main/java/io/github/a13e300/tricky_store/SecurityLevelInterceptor.kt @@ -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() + + 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, + params: KeyGenParameters, + descriptor: KeyDescriptor + ): KeyEntryResponse { + val response = KeyEntryResponse() + val metadata = KeyMetadata() + Utils.putCertificateChain(metadata, chain.toTypedArray()) + val d = KeyDescriptor() + d.domain = descriptor.domain + d.nspace = descriptor.nspace + metadata.key = d + val authorizations = ArrayList() + 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() + response.metadata = metadata + response.iSecurityLevel = original + return response + } +} diff --git a/service/src/main/java/io/github/a13e300/tricky_store/keystore/CertHack.java b/service/src/main/java/io/github/a13e300/tricky_store/keystore/CertHack.java index 10b17a6..e676235 100644 --- a/service/src/main/java/io/github/a13e300/tricky_store/keystore/CertHack.java +++ b/service/src/main/java/io/github/a13e300/tricky_store/keystore/CertHack.java @@ -1,22 +1,38 @@ 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.system.keystore2.KeyDescriptor; +import android.util.Pair; + +import androidx.annotation.Nullable; import org.bouncycastle.asn1.ASN1Boolean; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Enumerated; +import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERSet; import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.KeyUsage; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.X509v3CertificateBuilder; 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.PEMParser; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; @@ -25,25 +41,46 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.util.io.pem.PemReader; import java.io.ByteArrayInputStream; +import java.io.IOException; 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.CertificateFactory; import java.security.cert.CertificateParsingException; 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.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; 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.UtilKt; public final class CertHack { private static final ASN1ObjectIdentifier OID = new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17"); - record KeyBox(PEMKeyPair privateKey, List 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 keyboxes = new HashMap<>(); + private static final int ATTESTATION_PACKAGE_INFO_PACKAGE_NAME_INDEX = 0; private static final CertificateFactory certificateFactory; @@ -55,11 +92,31 @@ public final class CertHack { throw new RuntimeException(t); } } + private static final int ATTESTATION_PACKAGE_INFO_VERSION_INDEX = 1; public static boolean canHack() { 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) { keyboxes.clear(); if (data == null) { @@ -92,7 +149,9 @@ public final class CertHack { } else { 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"); } catch (Throwable t) { @@ -100,26 +159,7 @@ public final class CertHack { } } - 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 Certificate[] engineGetCertificateChain(Certificate[] caList) { + public static Certificate[] hackCertificateChain(Certificate[] caList) { if (caList == null) throw new UnsupportedOperationException("caList is null!"); try { X509Certificate leaf = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(caList[0].getEncoded())); @@ -158,14 +198,10 @@ public final class CertHack { holder.getNotBefore(), holder.getNotAfter(), holder.getSubject(), - k.privateKey.getPublicKeyInfo() + k.pemKeyPair.getPublicKeyInfo() ); signer = new JcaContentSignerBuilder(leaf.getSigAlgName()) - .build( - new JcaPEMKeyConverter() - .getPrivateKey(k.privateKey.getPrivateKeyInfo() - ) - ); + .build(k.keyPair.getPrivate()); byte[] verifiedBootKey = null; byte[] verifiedBootHash = null; @@ -221,4 +257,286 @@ public final class CertHack { } return caList; } + + public static Pair> 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 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 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 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 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 purpose = new ArrayList<>(); + public List 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; + } + } } diff --git a/service/src/main/java/io/github/a13e300/tricky_store/keystore/Utils.java b/service/src/main/java/io/github/a13e300/tricky_store/keystore/Utils.java index a2821f1..6b1659c 100644 --- a/service/src/main/java/io/github/a13e300/tricky_store/keystore/Utils.java +++ b/service/src/main/java/io/github/a13e300/tricky_store/keystore/Utils.java @@ -1,6 +1,7 @@ package io.github.a13e300.tricky_store.keystore; import android.system.keystore2.KeyEntryResponse; +import android.system.keystore2.KeyMetadata; import android.util.Log; import java.io.ByteArrayInputStream; @@ -58,12 +59,16 @@ public class Utils { } 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; - response.metadata.certificate = chain[0].getEncoded(); + metadata.certificate = chain[0].getEncoded(); var output = new ByteArrayOutputStream(); for (int i = 1; i < chain.length; i++) { output.write(chain[i].getEncoded()); } - response.metadata.certificateChain = output.toByteArray(); + metadata.certificateChain = output.toByteArray(); } } diff --git a/service/src/main/java/io/github/a13e300/tricky_store/util.kt b/service/src/main/java/io/github/a13e300/tricky_store/util.kt new file mode 100644 index 0000000..4327020 --- /dev/null +++ b/service/src/main/java/io/github/a13e300/tricky_store/util.kt @@ -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) diff --git a/stub/src/main/java/android/content/pm/IPackageManager.java b/stub/src/main/java/android/content/pm/IPackageManager.java index 1102c27..f495383 100644 --- a/stub/src/main/java/android/content/pm/IPackageManager.java +++ b/stub/src/main/java/android/content/pm/IPackageManager.java @@ -5,6 +5,8 @@ import android.os.IBinder; public interface IPackageManager { String[] getPackagesForUid(int uid); + PackageInfo getPackageInfo(String packageName, long flags, int userId); + class Stub { public static IPackageManager asInterface(IBinder binder) { throw new RuntimeException(""); diff --git a/stub/src/main/java/android/hardware/security/keymint/Algorithm.java b/stub/src/main/java/android/hardware/security/keymint/Algorithm.java new file mode 100644 index 0000000..a9f6907 --- /dev/null +++ b/stub/src/main/java/android/hardware/security/keymint/Algorithm.java @@ -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; +} diff --git a/stub/src/main/java/android/hardware/security/keymint/EcCurve.java b/stub/src/main/java/android/hardware/security/keymint/EcCurve.java new file mode 100644 index 0000000..ef4ee31 --- /dev/null +++ b/stub/src/main/java/android/hardware/security/keymint/EcCurve.java @@ -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; +} diff --git a/stub/src/main/java/android/hardware/security/keymint/KeyParameter.java b/stub/src/main/java/android/hardware/security/keymint/KeyParameter.java new file mode 100644 index 0000000..4267187 --- /dev/null +++ b/stub/src/main/java/android/hardware/security/keymint/KeyParameter.java @@ -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 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(); + } +} diff --git a/stub/src/main/java/android/hardware/security/keymint/KeyParameterValue.java b/stub/src/main/java/android/hardware/security/keymint/KeyParameterValue.java new file mode 100644 index 0000000..749705c --- /dev/null +++ b/stub/src/main/java/android/hardware/security/keymint/KeyParameterValue.java @@ -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 CREATOR = new Creator() { + @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(); + } +} diff --git a/stub/src/main/java/android/hardware/security/keymint/KeyPurpose.java b/stub/src/main/java/android/hardware/security/keymint/KeyPurpose.java new file mode 100644 index 0000000..04be5ca --- /dev/null +++ b/stub/src/main/java/android/hardware/security/keymint/KeyPurpose.java @@ -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; +} diff --git a/stub/src/main/java/android/hardware/security/keymint/SecurityLevel.java b/stub/src/main/java/android/hardware/security/keymint/SecurityLevel.java new file mode 100644 index 0000000..ec5ef35 --- /dev/null +++ b/stub/src/main/java/android/hardware/security/keymint/SecurityLevel.java @@ -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; +} diff --git a/stub/src/main/java/android/hardware/security/keymint/Tag.java b/stub/src/main/java/android/hardware/security/keymint/Tag.java new file mode 100644 index 0000000..f135a76 --- /dev/null +++ b/stub/src/main/java/android/hardware/security/keymint/Tag.java @@ -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; +} diff --git a/stub/src/main/java/android/system/keystore2/Authorization.java b/stub/src/main/java/android/system/keystore2/Authorization.java new file mode 100644 index 0000000..02f0726 --- /dev/null +++ b/stub/src/main/java/android/system/keystore2/Authorization.java @@ -0,0 +1,8 @@ +package android.system.keystore2; + +import android.hardware.security.keymint.KeyParameter; + +public class Authorization { + public KeyParameter keyParameter; + public int securityLevel = 0; +} diff --git a/stub/src/main/java/android/system/keystore2/IKeystoreSecurityLevel.java b/stub/src/main/java/android/system/keystore2/IKeystoreSecurityLevel.java new file mode 100644 index 0000000..7f9a66e --- /dev/null +++ b/stub/src/main/java/android/system/keystore2/IKeystoreSecurityLevel.java @@ -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(); + } + } +} diff --git a/stub/src/main/java/android/system/keystore2/IKeystoreService.java b/stub/src/main/java/android/system/keystore2/IKeystoreService.java index b6ad034..5563cd1 100644 --- a/stub/src/main/java/android/system/keystore2/IKeystoreService.java +++ b/stub/src/main/java/android/system/keystore2/IKeystoreService.java @@ -1,9 +1,15 @@ package android.system.keystore2; +import android.os.IBinder; + public interface IKeystoreService { String DESCRIPTOR = "android.system.keystore2.IKeystoreService"; - class Stub { + IKeystoreSecurityLevel getSecurityLevel(int securityLevel); + class Stub { + public static IKeystoreService asInterface(IBinder b) { + throw new RuntimeException(""); + } } } diff --git a/stub/src/main/java/android/system/keystore2/KeyDescriptor.java b/stub/src/main/java/android/system/keystore2/KeyDescriptor.java index 0432425..81f0fd5 100644 --- a/stub/src/main/java/android/system/keystore2/KeyDescriptor.java +++ b/stub/src/main/java/android/system/keystore2/KeyDescriptor.java @@ -11,19 +11,15 @@ public class KeyDescriptor implements Parcelable { public int domain = 0; public long nspace = 0; - protected KeyDescriptor(Parcel in) { - throw new RuntimeException(""); - } - public static final Creator CREATOR = new Creator() { @Override public KeyDescriptor createFromParcel(Parcel in) { - return new KeyDescriptor(in); + throw new RuntimeException(); } @Override public KeyDescriptor[] newArray(int size) { - return new KeyDescriptor[size]; + throw new RuntimeException(); } }; diff --git a/stub/src/main/java/android/system/keystore2/KeyEntryResponse.java b/stub/src/main/java/android/system/keystore2/KeyEntryResponse.java index 2bfd347..13abc0d 100644 --- a/stub/src/main/java/android/system/keystore2/KeyEntryResponse.java +++ b/stub/src/main/java/android/system/keystore2/KeyEntryResponse.java @@ -6,13 +6,9 @@ import android.os.Parcelable; import androidx.annotation.NonNull; public class KeyEntryResponse implements Parcelable { - // public IKeystoreSecurityLevel iSecurityLevel; + public IKeystoreSecurityLevel iSecurityLevel; public KeyMetadata metadata; - protected KeyEntryResponse(Parcel in) { - throw new RuntimeException(""); - } - public static final Creator CREATOR = new Creator() { @Override public KeyEntryResponse createFromParcel(Parcel in) { diff --git a/stub/src/main/java/android/system/keystore2/KeyMetadata.java b/stub/src/main/java/android/system/keystore2/KeyMetadata.java index 762649d..efeef31 100644 --- a/stub/src/main/java/android/system/keystore2/KeyMetadata.java +++ b/stub/src/main/java/android/system/keystore2/KeyMetadata.java @@ -6,17 +6,13 @@ import android.os.Parcelable; import androidx.annotation.NonNull; public class KeyMetadata implements Parcelable { - // public Authorization[] authorizations; + public Authorization[] authorizations; public byte[] certificate; public byte[] certificateChain; public KeyDescriptor key; public int keySecurityLevel = 0; public long modificationTimeMs = 0; - protected KeyMetadata(Parcel in) { - throw new RuntimeException(""); - } - public static final Creator CREATOR = new Creator() { @Override public KeyMetadata createFromParcel(Parcel in) {