Skip to content

签名变更处理

分析 v3 签名 lineage、capability 撤销、更新回滚与 shared UID 的签名变更判断。

AndroidPMS签名Key Rotation

签名变更处理 ​

签名变更不是把旧证书替换成新证书后继续比较。APK Signature Scheme v3 把旧 signer 组成有序 lineage,并由每个历史证书的 capability 决定它还能否保留安装数据、shared UID、签名权限或回滚能力。Android 17 的安装代码把这些能力分别用于更新、回滚、系统包和 shared UID 判断。

1. 变更的三种关系 ​

关系API典型用途
完全相同signaturesMatchExactly多 signer、无变更
lineage 包含hasAncestorOrSelf判断旧 signer 是否仍在历史链
能力授权checkCapability更新、权限、shared UID、回滚

hasAncestorOrSelf 只回答“是否属于同一信任链”,不回答是否授予某项能力;能力必须再由 checkCapability(flags) 验证。

2. PoR 与 lineage ​

v3 验证器把 Proof-of-Rotation 中的历史证书转换为 SigningDetails.mPastSigningCertificates。数组按旧到新的顺序保存,最后一项通常是当前 signer;每个 Signature 的 flags 保存历史 signer 被授予的能力。

3. lineage 方向 ​

源码文件:frameworks/base/core/java/android/content/pm/SigningDetails.java

java
public boolean hasAncestorOrSelf(
        @NonNull SigningDetails oldDetails) {
    if (this == UNKNOWN || oldDetails == UNKNOWN) {
        return false;
    }
    if (oldDetails.mSignatures.length > 1) {
        return signaturesMatchExactly(oldDetails);
    }
    return hasCertificate(oldDetails.mSignatures[0]);
}

public boolean hasAncestor(
        @NonNull SigningDetails oldDetails) {
    if (this == UNKNOWN || oldDetails == UNKNOWN) {
        return false;
    }
    if (hasPastSigningCertificates()
            && oldDetails.mSignatures.length == 1) {
        for (int i = 0;
                i < mPastSigningCertificates.length - 1; i++) {
            if (mPastSigningCertificates[i].equals(
                    oldDetails.mSignatures[0])) {
                return true;
            }
        }
    }
    return false;
}

当前对象调用 hasAncestor(oldDetails),表示当前 signer 的 lineage 中出现旧 signer,且不是当前 signer 本身。多 signer 包没有 rotation,退化为 exact match。

4. capability 检查 ​

java
public boolean checkCapability(
        @NonNull SigningDetails oldDetails,
        @CertCapabilities int flags) {
    if (this == UNKNOWN || oldDetails == UNKNOWN) {
        return false;
    }
    if (oldDetails.mSignatures.length > 1) {
        return signaturesMatchExactly(oldDetails);
    }
    boolean matchFound = hasCertificate(
            oldDetails.mSignatures[0], flags);
    if (!android.security.Flags.apkPqcHybridSigning()
            || !matchFound) {
        return matchFound;
    }
    if (isV32Hybrid() || oldDetails.isV32Hybrid()) {
        return checkV32HybridCapability(oldDetails, flags);
    }
    return true;
}

单 signer 场景先查旧 signer 是否在当前 lineage,再检查该历史证书的 flags。多 signer 必须完全相同;不会因为某个 signer 恰好出现在 lineage 中就放行。

5. 更新判断 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java

java
SigningDetails parsedPkgSigningDetails =
        parsedPackage.getSigningDetails();
SigningDetails oldPkgSigningDetails =
        oldPackageState.getSigningDetails();
if (!parsedPkgSigningDetails.checkCapability(
        oldPkgSigningDetails,
        SigningDetails.CertCapabilities.INSTALLED_DATA)
        && !oldPkgSigningDetails.checkCapability(
                parsedPkgSigningDetails,
                SigningDetails.CertCapabilities.ROLLBACK)) {
    if (!isRollback || !oldPkgSigningDetails.hasAncestorOrSelf(
            parsedPkgSigningDetails)) {
        throw new PrepareFailure(
                INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                "New package has a different signature: " + pkgName);
    }
}

正常更新看新包是否授予旧 signer INSTALLED_DATA;回滚看旧 signer 是否授予新 signer ROLLBACK。两者都失败时,只有回滚且旧 lineage 包含待回滚 signer 才能继续。

6. 能力撤销 ​

历史证书可以在新版本的 lineage 中保留证书,但清除某个 capability。这样“同一 lineage”不等于“所有旧行为继续有效”。例如旧 signer 仍在链中,但没有 PERMISSION,新包就不能凭该旧 signer 获取签名权限;没有 SHARED_USER_ID 也不能加入 shared UID。

7. shared UID 变更 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java

java
boolean capabilityGranted =
        packageSigningDetails.checkCapability(
                sharedUserSigningDetails,
                SigningDetails.CertCapabilities.SHARED_USER_ID)
        || sharedUserSigningDetails.checkCapability(
                packageSigningDetails,
                SigningDetails.CertCapabilities.SHARED_USER_ID);

if (capabilityGranted
        && joinType != SHARED_USER_ID_JOIN_TYPE_INSTALL) {
    return true;
}
if (!capabilityGranted
        && sharedUserSigningDetails.hasAncestor(packageSigningDetails)) {
    return joinType == SHARED_USER_ID_JOIN_TYPE_SYSTEM;
}
if (!capabilityGranted
        && packageSigningDetails.hasAncestor(sharedUserSigningDetails)) {
    return joinType != SHARED_USER_ID_JOIN_TYPE_INSTALL;
}

shared UID 的 install、update、system join 不是同一权限级别。capability 被撤销时,系统 join 或更新可能仍允许迁移,普通新安装则被拒绝,避免新包借旧 signer 进入已有 shared UID 组。

8. 系统包检查 ​

java
private static boolean matchSignatureInSystem(
        String packageName, SigningDetails signingDetails,
        PackageSetting disabledPkgSetting) {
    return signingDetails.checkCapability(
            disabledPkgSetting.getSigningDetails(),
            SigningDetails.CertCapabilities.INSTALLED_DATA)
            || disabledPkgSetting.getSigningDetails().checkCapability(
                    signingDetails,
                    SigningDetails.CertCapabilities.ROLLBACK);
}

系统应用更新同时要通过 data 包和 disabled system package 的签名能力检查。只与 /data 旧包兼容而与出厂包不兼容,仍会被拒绝。

9. v3.2 hybrid ​

Android 17 的 checkCapability 在 PQC hybrid flag 开启时会额外调用 checkV32HybridCapability。如果一个 hybrid 身份只复用了 primary 或 classical key,而不是成对出现,能力检查失败并记录签名策略指标,防止单钥复用绕过 lineage 信任。

java
if (oldDetails.isV32Hybrid()) {
    if (!hasCertificate(
            oldDetails.getV32ClassicalHybridSigner(), flags)) {
        return false;
    }
}

这条约束只在 hybrid signer 场景触发;普通 v3 rotation 仍按历史证书和 flags 判断。

10. 排查顺序 ​

  1. 先确认新旧 SigningDetails 是否为 UNKNOWN、单 signer 还是多 signer。
  2. 打印 lineage 顺序,确认旧 signer 是当前 signer、ancestor 还是完全不相关。
  3. 按场景选择 capability:更新看 INSTALLED_DATA,回滚看 ROLLBACK,shared UID 看 SHARED_USER_ID,签名权限看 PERMISSION。
  4. 检查 capability 是否被新 lineage 撤销。
  5. 系统应用更新额外检查 disabled system package。
  6. shared UID 失败时区分 install、update、system join type。
  7. hybrid signer 失败时检查 primary/classical 两把 key 是否成对存在。

11. 源码阅读路线 ​

  1. SigningDetails.hasAncestorOrSelf/hasAncestor:确认 lineage 方向。
  2. SigningDetails.checkCapability:确认历史证书 flags 和 hybrid 约束。
  3. InstallPackageHelper 更新/回滚分支:观察 capability 消费。
  4. PackageManagerServiceUtils.verifySignatures:观察 compat/recover 和系统包检查。
  5. canJoinSharedUserId:理解 shared UID 在不同 join type 下的差异。

签名轮换的安全边界是“新 signer 通过旧 signer 的背书获得有限能力”,而不是永久继承旧证书的全部信任。Android 17 将 lineage、capability、更新类型和包来源组合起来,任何一项不满足都可能改变安装结果。