beemdevelopment/Aegis · error · CertificateException

signatures cannot be null or empty!

Error message

signatures cannot be null or empty!

What it means

TrustedIntents.checkTrustedSigner validates that an APK's signature array is usable before comparing it against the pinned signer list. If the Signature[] is null or zero-length it throws CertificateException('signatures cannot be null or empty!') — there is nothing to compare, and treating that as 'untrusted' would hide the real cause.

Solutions

  1. Request signatures properly: getPackageInfo(pkg, PackageManager.GET_SIGNATURES) (or GET_SIGNING_CERTIFICATES + signingInfo on API 28+) and check the result before calling
  2. Verify the target package is actually installed and visible (manifest queries/package-visibility on Android 11+)
  3. Guard the call: if signatures == null || signatures.length == 0, fail with a clear message or re-fetch signatures rather than passing them through
  4. Use the newer checkTrustedSigner(SigningInfo) path on API 28+ where GET_SIGNATURES is unreliable

Example fix

// before
PackageInfo info = pm.getPackageInfo(pkg, 0);
trustedIntents.checkTrustedSigner(info); // CertificateException: signatures cannot be null or empty!
// after
PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
if (info == null || info.signatures == null || info.signatures.length == 0) {
    Log.w(TAG, "No signatures for " + pkg + "; treating as untrusted");
    return false;
}
trustedIntents.checkTrustedSigner(info);
Defensive patterns

Strategy: type-guard

Validate before calling

PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
if (info == null || info.signatures == null || info.signatures.length == 0) {
    throw new IllegalStateException("no signatures for " + pkg);
}

Type guard

boolean hasUsableSignatures(PackageInfo info) {
    return info != null && info.signatures != null && info.signatures.length > 0;
}

Try / catch

try {
    trustedIntents.checkTrustedSigner(info);
} catch (CertificateException e) {
    Log.w(TAG, "signature data unavailable for " + pkg, e);
} catch (NameNotFoundException e) {
    Log.w(TAG, "package not installed: " + pkg, e);
}

Prevention

When it happens

Trigger: Calling checkTrustedSigner with a null or empty Signature[]; commonly from checkTrustedSigner(PackageInfo) where packageInfo.signatures is null — e.g. PackageManager could not retrieve signatures (GET_SIGNATURES not requested, app not installed, or platform returned none).

Common situations: Querying a package that isn't installed; calling getPackageInfo without GET_SIGNATURES on some Android versions; signature info stripped by app-bundle/installer tooling; work-profile/instant-app quirks returning null signatures.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

        }
        return false;
    }

    public void checkTrustedSigner(String packageName)
            throws NameNotFoundException, CertificateException {
        PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
        checkTrustedSigner(packageInfo.signatures);
    }

    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;

View on GitHub (pinned to d6f4e5925a)