需求:
允许持有特定公钥的应用声明系统权限,保证应用的正常安装、运行
修改文件
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 模数与硬编码值一致时,直接认为签名匹配成功。
补充
当前是使用硬编码特定公钥的,有条件的话可以新增一个系统属性来存储特定公钥,比较规范