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
- Verify the sender app's origin (install channel) — install the genuine, properly signed build from the official source
- Update the trustedintents pin data (ApkSignaturePin certificate hashes) to match the vendor's current signing certificate if the vendor rotated keys
- 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
- 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
- Treat mismatch as a security signal; never auto-add unknown keys to pinList
- Keep ApkSignaturePin data in sync with the trusted vendor's signing certificate rotation
- Verify users install the genuine app from official channels
- Log the sender package name on mismatch for incident triage
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
- signatures cannot be null or empty!
- Certificates cannot be null or empty!
- Unable to decode stream to bitmap
- Unable to find pack.json in the root of the ZIP file
- Attempted to write outside of the parent directory
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)