use of com.android.apksig.apk.ApkFormatException in project apksig by venshine.
the class V1SchemeVerifier method verifyJarEntriesAgainstManifestAndSigners.
private static Set<Signer> verifyJarEntriesAgainstManifestAndSigners(DataSource apk, long cdOffsetInApk, Collection<CentralDirectoryRecord> cdRecords, Map<String, ManifestParser.Section> entryNameToManifestSection, List<Signer> signers, int minSdkVersion, int maxSdkVersion, Result result) throws ApkFormatException, IOException, NoSuchAlgorithmException {
// Iterate over APK contents as sequentially as possible to improve performance.
List<CentralDirectoryRecord> cdRecordsSortedByLocalFileHeaderOffset = new ArrayList<>(cdRecords);
Collections.sort(cdRecordsSortedByLocalFileHeaderOffset, CentralDirectoryRecord.BY_LOCAL_FILE_HEADER_OFFSET_COMPARATOR);
List<Signer> firstSignedEntrySigners = null;
String firstSignedEntryName = null;
for (CentralDirectoryRecord cdRecord : cdRecordsSortedByLocalFileHeaderOffset) {
String entryName = cdRecord.getName();
if (!isJarEntryDigestNeededInManifest(entryName)) {
continue;
}
ManifestParser.Section manifestSection = entryNameToManifestSection.get(entryName);
if (manifestSection == null) {
result.addError(Issue.JAR_SIG_NO_ZIP_ENTRY_DIGEST_IN_MANIFEST, entryName);
continue;
}
List<Signer> entrySigners = new ArrayList<>(signers.size());
for (Signer signer : signers) {
if (signer.getSigFileEntryNames().contains(entryName)) {
entrySigners.add(signer);
}
}
if (entrySigners.isEmpty()) {
result.addError(Issue.JAR_SIG_ZIP_ENTRY_NOT_SIGNED, entryName);
continue;
}
if (firstSignedEntrySigners == null) {
firstSignedEntrySigners = entrySigners;
firstSignedEntryName = entryName;
} else if (!entrySigners.equals(firstSignedEntrySigners)) {
result.addError(Issue.JAR_SIG_ZIP_ENTRY_SIGNERS_MISMATCH, firstSignedEntryName, getSignerNames(firstSignedEntrySigners), entryName, getSignerNames(entrySigners));
continue;
}
List<NamedDigest> expectedDigests = new ArrayList<>(getDigestsToVerify(manifestSection, "-Digest", minSdkVersion, maxSdkVersion));
if (expectedDigests.isEmpty()) {
result.addError(Issue.JAR_SIG_NO_ZIP_ENTRY_DIGEST_IN_MANIFEST, entryName);
continue;
}
MessageDigest[] mds = new MessageDigest[expectedDigests.size()];
for (int i = 0; i < expectedDigests.size(); i++) {
mds[i] = getMessageDigest(expectedDigests.get(i).jcaDigestAlgorithm);
}
try {
LocalFileRecord.outputUncompressedData(apk, cdRecord, cdOffsetInApk, DataSinks.asDataSink(mds));
} catch (ZipFormatException e) {
throw new ApkFormatException("Malformed ZIP entry: " + entryName, e);
} catch (IOException e) {
throw new IOException("Failed to read entry: " + entryName, e);
}
for (int i = 0; i < expectedDigests.size(); i++) {
NamedDigest expectedDigest = expectedDigests.get(i);
byte[] actualDigest = mds[i].digest();
if (!Arrays.equals(expectedDigest.digest, actualDigest)) {
result.addError(Issue.JAR_SIG_ZIP_ENTRY_DIGEST_DID_NOT_VERIFY, entryName, expectedDigest.jcaDigestAlgorithm, V1SchemeConstants.MANIFEST_ENTRY_NAME, Base64.getEncoder().encodeToString(actualDigest), Base64.getEncoder().encodeToString(expectedDigest.digest));
}
}
}
if (firstSignedEntrySigners == null) {
result.addError(Issue.JAR_SIG_NO_SIGNED_ZIP_ENTRIES);
return Collections.emptySet();
} else {
return new HashSet<>(firstSignedEntrySigners);
}
}
Aggregations