diff --git a/app/src/main/java/io/github/vvb2060/keyattestation/attestation/RootPublicKey.java b/app/src/main/java/io/github/vvb2060/keyattestation/attestation/RootPublicKey.java index 3620dd31..512e5655 100644 --- a/app/src/main/java/io/github/vvb2060/keyattestation/attestation/RootPublicKey.java +++ b/app/src/main/java/io/github/vvb2060/keyattestation/attestation/RootPublicKey.java @@ -14,6 +14,12 @@ import io.github.vvb2060.keyattestation.AppApplication; public class RootPublicKey { + public enum TestKey { + NONE, + RSA2048, + RSA4096, + RSA8192, + } public enum Status { NULL, FAILED, @@ -106,6 +112,38 @@ private static Set getOemPublicKey() { return set; } + private static byte[] hexToBytes(String hex) { + int len = hex.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + + Character.digit(hex.charAt(i + 1), 16)); + } + return data; + } + + /** + * Detect if verifiedBootKey matches known AVB test public keys by SHA-256 digest. + */ + public static TestKey checkVbmetaTestKeyBySha256(byte[] verifiedBootKey) { + if (verifiedBootKey == null) return TestKey.NONE; + + // Known SHA-256 fingerprints for AVB test keys + final String SHA256_RSA2048 = "22de3994532196f61c039e90260d78a93a4c57362c7e789be928036e80b77c8c"; + final String SHA256_RSA4096 = "7728e30f50bfa5cea165f473175a08803f6a8346642b5aa10913e9d9e6defef6"; + final String SHA256_RSA8192 = "e15e2365469ce672a91d02cc8d9c2f29b787481e574d3b56ac774153d7ced614"; + + var sha256_2048 = hexToBytes(SHA256_RSA2048); + var sha256_4096 = hexToBytes(SHA256_RSA4096); + var sha256_8192 = hexToBytes(SHA256_RSA8192); + + if (Arrays.equals(verifiedBootKey, sha256_2048)) return TestKey.RSA2048; + if (Arrays.equals(verifiedBootKey, sha256_4096)) return TestKey.RSA4096; + if (Arrays.equals(verifiedBootKey, sha256_8192)) return TestKey.RSA8192; + + return TestKey.NONE; + } + public static Status check(byte[] publicKey) { if (Arrays.equals(publicKey, googleKey)) { return Status.GOOGLE; diff --git a/app/src/main/java/io/github/vvb2060/keyattestation/home/HomeAdapter.kt b/app/src/main/java/io/github/vvb2060/keyattestation/home/HomeAdapter.kt index e3aea98f..97206e13 100644 --- a/app/src/main/java/io/github/vvb2060/keyattestation/home/HomeAdapter.kt +++ b/app/src/main/java/io/github/vvb2060/keyattestation/home/HomeAdapter.kt @@ -105,6 +105,41 @@ class HomeAdapter(listener: Listener) : IdBasedRecyclerViewAdapter() { private fun updateData(attestationData: AttestationData) { addItemAt(1, BootStateViewHolder.CREATOR, attestationData, ID_BOOT_STATUS) + // If verifiedBootKey matches known AVB test keys (by SHA-1), show a warning header + var testKeyShown = false + attestationData.rootOfTrust?.verifiedBootKey?.let { vbk -> + when (RootPublicKey.checkVbmetaTestKeyBySha256(vbk)) { + RootPublicKey.TestKey.RSA2048 -> { + addItemAt(2, HeaderViewHolder.CREATOR, HeaderData( + R.string.vbmeta_testkey, + R.string.vbmeta_testkey_rsa2048_summary, + R.drawable.ic_error_outline_24, + rikka.material.R.attr.colorAlert + ), ID_VB_TESTKEY_WARNING) + testKeyShown = true + } + RootPublicKey.TestKey.RSA4096 -> { + addItemAt(2, HeaderViewHolder.CREATOR, HeaderData( + R.string.vbmeta_testkey, + R.string.vbmeta_testkey_rsa4096_summary, + R.drawable.ic_error_outline_24, + rikka.material.R.attr.colorAlert + ), ID_VB_TESTKEY_WARNING) + testKeyShown = true + } + RootPublicKey.TestKey.RSA8192 -> { + addItemAt(2, HeaderViewHolder.CREATOR, HeaderData( + R.string.vbmeta_testkey, + R.string.vbmeta_testkey_rsa8192_summary, + R.drawable.ic_error_outline_24, + rikka.material.R.attr.colorAlert + ), ID_VB_TESTKEY_WARNING) + testKeyShown = true + } + else -> {} + } + } + var id = ID_DESCRIPTION_START val attestation = attestationData.showAttestation ?: return addItem(CommonItemViewHolder.SECURITY_LEVEL_CREATOR, SecurityLevelData( @@ -270,6 +305,7 @@ class HomeAdapter(listener: Listener) : IdBasedRecyclerViewAdapter() { private const val ID_ERROR = 0L private const val ID_CERT_STATUS = 1L private const val ID_BOOT_STATUS = 2L + private const val ID_VB_TESTKEY_WARNING = 3L private const val ID_CERT_INFO_START = 1000L private const val ID_RKP_HOSTNAME = 2000L private const val ID_DESCRIPTION_START = 3000L diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 914a6dcb..14540265 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -40,6 +40,11 @@ 设备制造商的根证书 此设备信任该根证书,但它可能不被其它人信任。 + vbmeta 被测试密钥签名 + verifiedBootKey 是 testkey_rsa2048 + verifiedBootKey 是 testkey_rsa4096 + verifiedBootKey 是 testkey_rsa8192 + 证书链 证书链是用于验证密钥的证书列表。从该密钥的证书开始,每个证书均由链中下一个证书签名,到根证书为止。认证的可信度取决于证书链的根证书。 证书信息 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5620044a..4545c9dd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -40,6 +40,11 @@ OEM root certificate This device trusts this root certificate, but it may not be trusted by others. + VBMeta signed with test key + verifiedBootKey is testkey_rsa2048 + verifiedBootKey is testkey_rsa4096 + verifiedBootKey is testkey_rsa8192 + Certificate chain Certificate chain is a list of certificates used to authenticate a key. The chain starts with the certificate associated with that key, and each certificate is signed by the next in the chain. The chain ends with a root certificate, and the trustworthiness of the attestation depends on the root certificate of the chain.. Certificate info