{"record":{"id":"7938d15c05040ac1","repo":"beemdevelopment/Aegis","slug":"signatures-cannot-be-null-or-empty","errorCode":null,"errorMessage":"signatures cannot be null or empty!","messagePattern":"signatures cannot be null or empty!","errorType":"exception","errorClass":"CertificateException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/info/guardianproject/trustedintents/TrustedIntents.java","lineNumber":228,"sourceCode":"        }\n        return false;\n    }\n\n    public void checkTrustedSigner(String packageName)\n            throws NameNotFoundException, CertificateException {\n        PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);\n        checkTrustedSigner(packageInfo.signatures);\n    }\n\n    public void checkTrustedSigner(PackageInfo packageInfo)\n            throws NameNotFoundException, CertificateException {\n        checkTrustedSigner(packageInfo.signatures);\n    }\n\n    public void checkTrustedSigner(Signature[] signatures)\n            throws NameNotFoundException, CertificateException {\n        if (signatures == null || signatures.length == 0)\n            throw new CertificateException(\"signatures cannot be null or empty!\");\n        for (int i = 0; i < signatures.length; i++)\n            if (signatures[i] == null || signatures[i].toByteArray().length == 0)\n                throw new CertificateException(\"Certificates cannot be null or empty!\");\n\n        // check whether the APK signer is trusted for all apps\n        for (ApkSignaturePin pin : pinList)\n            if (areSignaturesEqual(signatures, pin.getSignatures()))\n                return; // found a matching trusted APK signer\n\n        throw new CertificateException(\"APK signatures did not match!\");\n    }\n\n    public boolean areSignaturesEqual(Signature[] sigs0, Signature[] sigs1) {\n        // TODO where is Android's implementation of this that I can just call?\n        if (sigs0 == null || sigs1 == null)\n            return false;\n        if (sigs0.length == 0 || sigs1.length == 0)\n            return false;","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/info/guardianproject/trustedintents/TrustedIntents.java#L210-L246","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Request signatures properly: getPackageInfo(pkg, PackageManager.GET_SIGNATURES) (or GET_SIGNING_CERTIFICATES + signingInfo on API 28+) and check the result before calling","Verify the target package is actually installed and visible (manifest queries/package-visibility on Android 11+)","Guard the call: if signatures == null || signatures.length == 0, fail with a clear message or re-fetch signatures rather than passing them through","Use the newer checkTrustedSigner(SigningInfo) path on API 28+ where GET_SIGNATURES is unreliable"],"exampleFix":"// before\nPackageInfo info = pm.getPackageInfo(pkg, 0);\ntrustedIntents.checkTrustedSigner(info); // CertificateException: signatures cannot be null or empty!\n// after\nPackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);\nif (info == null || info.signatures == null || info.signatures.length == 0) {\n    Log.w(TAG, \"No signatures for \" + pkg + \"; treating as untrusted\");\n    return false;\n}\ntrustedIntents.checkTrustedSigner(info);","handlingStrategy":"type-guard","validationCode":"PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);\nif (info == null || info.signatures == null || info.signatures.length == 0) {\n    throw new IllegalStateException(\"no signatures for \" + pkg);\n}","typeGuard":"boolean hasUsableSignatures(PackageInfo info) {\n    return info != null && info.signatures != null && info.signatures.length > 0;\n}","tryCatchPattern":"try {\n    trustedIntents.checkTrustedSigner(info);\n} catch (CertificateException e) {\n    Log.w(TAG, \"signature data unavailable for \" + pkg, e);\n} catch (NameNotFoundException e) {\n    Log.w(TAG, \"package not installed: \" + pkg, e);\n}","preventionTips":["Always request GET_SIGNATURES (or SigningInfo on API 28+) when fetching PackageInfo","Confirm the package is installed and visible (Android 11+ package visibility)","Never pass through signature arrays without a null/empty check"],"tags":["android","signatures","security","certificate-pinning"],"backgroundTag":"empty-required-field","analyzedSha":"d6f4e5925a97e4e91593f1542085eae03432a759","analyzedAt":"2026-09-08T00:46:31.111Z","contentChangedAt":"2026-09-08T00:46:31.111Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}