为系统级应用“开绿灯”——Android14 系统签名白名单扩展

需求:

允许持有特定公钥的应用声明系统权限,保证应用的正常安装、运行

修改文件

frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java

修改点一:新增 import

添加了:

java 复制代码
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;

修改点二:新增硬编码公钥模数常量

java 复制代码
private static final String CUSTOM_PUBLIC_KEY_MODULUS_HEX =
    "<完整的十六进制模数字符串,此处省略>";
实际为 RSA 2048 位公钥的模数(小写十六进制,无前导零)。

修改点三:新增两个私有方法

java 复制代码
private static String getRSAPublicKeyModulusHex(Signature signature) {
    // 从 Signature 对象解析 X509Certificate,提取 RSAPublicKey 的 modulus,转为 hex 返回
     try {
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            X509Certificate cert = (X509Certificate) cf.generateCertificate(
+                    new ByteArrayInputStream(signature.toByteArray())
+            );
+            PublicKey pubKey = cert.getPublicKey();
+            if (pubKey instanceof RSAPublicKey) {
+                BigInteger modulus = ((RSAPublicKey) pubKey).getModulus();
+                // 转为无前导零的十六进制(小写)
+                return modulus.toString(16).toLowerCase();
+            }
+        } catch (Exception e) {
+            Slog.w(TAG, "Failed to extract RSA modulus", e);
+        }
+        return null;

}
private static boolean isCustomSignature(SigningDetails signingDetails, String packageName) {
    // 调用 getRSAPublicKeyModulusHex 并与常量比较,匹配返回 true
    if (signingDetails == null) {
+            return false;
+        }
+        Signature[] signatures = signingDetails.getSignatures();
+        if (signatures == null || signatures.length == 0) {
+            return false;
+        }
+        String modulusHex = getRSAPublicKeyModulusHex(signatures[0]);
+        if (modulusHex != null && modulusHex.equals(CUSTOM_PUBLIC_KEY_MODULUS_HEX)) {
+            Slog.i(TAG, "Package " + packageName + " matches public key.");
+            return true;
+        }
+        return false;

}

修改点四:修改 checkSignatures 方法

在原有签名比对逻辑(if (!match) 之前)插入:

java 复制代码
if (isCustomSignature(parsedSignatures, packageName)) {
    match = true;
    testSignatures = true;  // 复用已有标记
}

该块使得当应用签名的 RSA 模数与硬编码值一致时,直接认为签名匹配成功。

补充

当前是使用硬编码特定公钥的,有条件的话可以新增一个系统属性来存储特定公钥,比较规范