beemdevelopment/Aegis · warning · CertificateException

APK signatures did not match!

Error message

APK signatures did not match!

What it means

After the null/empty guards, checkTrustedSigner compares the APK's signatures against every registered ApkSignaturePin in pinList using areSignaturesEqual. If none matches, it throws CertificateException('APK signatures did not match!'), meaning the intent sender's signing key is not one of the trusted/pinned keys — the app's identity cannot be verified as the intended, trusted sender.

Solutions

  1. Verify the sender app's origin (install channel) — install the genuine, properly signed build from the official source
  2. Update the trustedintents pin data (ApkSignaturePin certificate hashes) to match the vendor's current signing certificate if the vendor rotated keys
  3. Check you pinned the right certificate (e.g. 'X509:' prefixed hex of the full cert); regenerate the pin from the trusted app's actual signature
  4. Log and reject the intent — treat the exception as a security signal, do not add the unknown signature to the pin list

Example fix

// before
try {
    trustedIntents.checkTrustedSigner(signatures);
} catch (CertificateException e) {
    Log.e(TAG, "untrusted sender", e); // APK signatures did not match!
}
// after
try {
    trustedIntents.checkTrustedSigner(signatures);
} catch (CertificateException e) {
    Log.w(TAG, "Rejected intent from untrusted signer for pkg " + packageName, e);
    Toast.show(context, "Sender app is not the genuine version; install the official build");
    return; // do not process the intent
}
Defensive patterns

Strategy: try-catch

Validate before calling

byte[] expected = pin.getSignatures()[0].toByteArray();
byte[] actual = signatures[0].toByteArray();
boolean pinned = java.util.Arrays.equals(expected, actual);
if (!pinned) { rejectIntentWithUserGuidance(); }

Type guard

boolean isTrustedPackage(TrustedIntents ti, String pkg) {
    try {
        ti.checkTrustedSigner(pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES));
        return true;
    } catch (Exception e) {
        return false;
    }
}

Try / catch

try {
    trustedIntents.checkTrustedSigner(signatures);
} catch (CertificateException e) {
    if (e.getMessage().contains("did not match")) {
        Log.w(TAG, "untrusted APK signer; possible repackage", e);
        refuseToRespond();
    }
}

Prevention

When it happens

Trigger: An app sends a trusted intent but was signed with a different key: a repackaged/cloned APK, a debug-signed build, a different app impersonating the package name, or the library's pin list not updated after the vendor rotated their signing certificate.

Common situations: Side-loaded or modded APK of the trusted app; switching between Play Store and third-party builds signed differently; upstream app migrates signing keys (new pin format/rotated key) while your pinned ApkSignaturePin is stale; malicious app spoofing package names.

Related errors


AI-assisted analysis of beemdevelopment/Aegis@d6f4e5925a (2026-09-08). Data as JSON: /api/errors/7348c849e202f5d0. Report an issue: GitHub.

Appendix: source

Thrown at app/src/main/java/info/guardianproject/trustedintents/TrustedIntents.java:238

    public void checkTrustedSigner(PackageInfo packageInfo)
            throws NameNotFoundException, CertificateException {
        checkTrustedSigner(packageInfo.signatures);
    }

    public void checkTrustedSigner(Signature[] signatures)
            throws NameNotFoundException, CertificateException {
        if (signatures == null || signatures.length == 0)
            throw new CertificateException("signatures cannot be null or empty!");
        for (int i = 0; i < signatures.length; i++)
            if (signatures[i] == null || signatures[i].toByteArray().length == 0)
                throw new CertificateException("Certificates cannot be null or empty!");

        // check whether the APK signer is trusted for all apps
        for (ApkSignaturePin pin : pinList)
            if (areSignaturesEqual(signatures, pin.getSignatures()))
                return; // found a matching trusted APK signer

        throw new CertificateException("APK signatures did not match!");
    }

    public boolean areSignaturesEqual(Signature[] sigs0, Signature[] sigs1) {
        // TODO where is Android's implementation of this that I can just call?
        if (sigs0 == null || sigs1 == null)
            return false;
        if (sigs0.length == 0 || sigs1.length == 0)
            return false;
        if (sigs0.length != sigs1.length)
            return false;
        for (int i = 0; i < sigs0.length; i++)
            if (!sigs0[i].equals(sigs1[i]))
                return false;
        return true;
    }

    public void startActivity(Context context, Intent intent) throws CertificateException {
        if (!isIntentSane(intent))

View on GitHub (pinned to d6f4e5925a)