Merge "dump apk signing version" into nyc-dev

This commit is contained in:
Todd Kennedy
2016-03-04 18:33:58 +00:00
committed by Android (Google) Code Review
3 changed files with 92 additions and 28 deletions

View File

@@ -121,6 +121,10 @@ public class PackageParser {
private static final int MAX_PACKAGES_PER_APK = 5;
public static final int APK_SIGNING_UNKNOWN = 0;
public static final int APK_SIGNING_V1 = 1;
public static final int APK_SIGNING_V2 = 2;
// TODO: switch outError users to PackageParserException
// TODO: refactor "codePath" to "apkPath"
@@ -1058,12 +1062,24 @@ public class PackageParser {
return pkg;
}
public static int getApkSigningVersion(Package pkg) {
try {
if (ApkSignatureSchemeV2Verifier.hasSignature(pkg.baseCodePath)) {
return APK_SIGNING_V2;
}
return APK_SIGNING_V1;
} catch (IOException e) {
}
return APK_SIGNING_UNKNOWN;
}
/**
* Collect certificates from all the APKs described in the given package,
* populating {@link Package#mSignatures}. Also asserts that all APK
* contents are signed correctly and consistently.
*/
public static void collectCertificates(Package pkg, int parseFlags) throws PackageParserException {
public static void collectCertificates(Package pkg, int parseFlags)
throws PackageParserException {
collectCertificatesInternal(pkg, parseFlags);
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
@@ -1074,7 +1090,8 @@ public class PackageParser {
}
}
private static void collectCertificatesInternal(Package pkg, int parseFlags) throws PackageParserException {
private static void collectCertificatesInternal(Package pkg, int parseFlags)
throws PackageParserException {
pkg.mCertificates = null;
pkg.mSignatures = null;
pkg.mSigningKeys = null;

View File

@@ -74,6 +74,36 @@ public class ApkSignatureSchemeV2Verifier {
public static final String SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME = "X-Android-APK-Signed";
public static final int SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID = 2;
/**
* Returns {@code true} if the provided APK contains an APK Signature Scheme V2
* signature. The signature will not be verified.
*/
public static boolean hasSignature(String apkFile) throws IOException {
try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) {
long fileSize = apk.length();
if (fileSize > Integer.MAX_VALUE) {
return false;
}
MappedByteBuffer apkContents =
apk.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, fileSize);
// ZipUtils and APK Signature Scheme v2 verifier expect little-endian byte order.
apkContents.order(ByteOrder.LITTLE_ENDIAN);
final int centralDirOffset =
(int) getCentralDirOffset(apkContents, getEocdOffset(apkContents));
// Find the APK Signing Block.
int apkSigningBlockOffset = findApkSigningBlock(apkContents, centralDirOffset);
ByteBuffer apkSigningBlock =
sliceFromTo(apkContents, apkSigningBlockOffset, centralDirOffset);
// Find the APK Signature Scheme v2 Block inside the APK Signing Block.
findApkSignatureSchemeV2Block(apkSigningBlock);
return true;
} catch (SignatureNotFoundException e) {
}
return false;
}
/**
* Verifies APK Signature Scheme v2 signatures of the provided APK and returns the certificates
* associated with each signer.
@@ -130,31 +160,8 @@ public class ApkSignatureSchemeV2Verifier {
// ZipUtils and APK Signature Scheme v2 verifier expect little-endian byte order.
apkContents.order(ByteOrder.LITTLE_ENDIAN);
// Find the offset of ZIP End of Central Directory (EoCD)
int eocdOffset = ZipUtils.findZipEndOfCentralDirectoryRecord(apkContents);
if (eocdOffset == -1) {
throw new SignatureNotFoundException(
"Not an APK file: ZIP End of Central Directory record not found");
}
if (ZipUtils.isZip64EndOfCentralDirectoryLocatorPresent(apkContents, eocdOffset)) {
throw new SignatureNotFoundException("ZIP64 APK not supported");
}
ByteBuffer eocd = sliceFromTo(apkContents, eocdOffset, apkContents.capacity());
// Look up the offset of ZIP Central Directory.
long centralDirOffsetLong = ZipUtils.getZipEocdCentralDirectoryOffset(eocd);
if (centralDirOffsetLong >= eocdOffset) {
throw new SignatureNotFoundException(
"ZIP Central Directory offset out of range: " + centralDirOffsetLong
+ ". ZIP End of Central Directory offset: " + eocdOffset);
}
long centralDirSizeLong = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocd);
if (centralDirOffsetLong + centralDirSizeLong != eocdOffset) {
throw new SignatureNotFoundException(
"ZIP Central Directory is not immediately followed by End of Central"
+ " Directory");
}
int centralDirOffset = (int) centralDirOffsetLong;
final int eocdOffset = getEocdOffset(apkContents);
final int centralDirOffset = (int) getCentralDirOffset(apkContents, eocdOffset);
// Find the APK Signing Block.
int apkSigningBlockOffset = findApkSigningBlock(apkContents, centralDirOffset);
@@ -499,6 +506,43 @@ public class ApkSignatureSchemeV2Verifier {
return result;
}
/**
* Finds the offset of ZIP End of Central Directory (EoCD).
*
* @throws SignatureNotFoundException If the EoCD could not be found
*/
private static int getEocdOffset(ByteBuffer apkContents) throws SignatureNotFoundException {
int eocdOffset = ZipUtils.findZipEndOfCentralDirectoryRecord(apkContents);
if (eocdOffset == -1) {
throw new SignatureNotFoundException(
"Not an APK file: ZIP End of Central Directory record not found");
}
return eocdOffset;
}
private static long getCentralDirOffset(ByteBuffer apkContents, int eocdOffset)
throws SignatureNotFoundException {
if (ZipUtils.isZip64EndOfCentralDirectoryLocatorPresent(apkContents, eocdOffset)) {
throw new SignatureNotFoundException("ZIP64 APK not supported");
}
ByteBuffer eocd = sliceFromTo(apkContents, eocdOffset, apkContents.capacity());
// Look up the offset of ZIP Central Directory.
long centralDirOffsetLong = ZipUtils.getZipEocdCentralDirectoryOffset(eocd);
if (centralDirOffsetLong >= eocdOffset) {
throw new SignatureNotFoundException(
"ZIP Central Directory offset out of range: " + centralDirOffsetLong
+ ". ZIP End of Central Directory offset: " + eocdOffset);
}
long centralDirSizeLong = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocd);
if (centralDirOffsetLong + centralDirSizeLong != eocdOffset) {
throw new SignatureNotFoundException(
"ZIP Central Directory is not immediately followed by End of Central"
+ " Directory");
}
return centralDirOffsetLong;
}
private static final int getChunkCount(int inputSizeBytes) {
return (inputSizeBytes + CHUNK_SIZE_BYTES - 1) / CHUNK_SIZE_BYTES;
}

View File

@@ -2604,7 +2604,6 @@ final class Settings {
if (pkg.volumeUuid != null) {
serializer.attribute(null, "volumeUuid", pkg.volumeUuid);
}
if (pkg.parentPackageName != null) {
serializer.attribute(null, "parentPackageName", pkg.parentPackageName);
}
@@ -4316,6 +4315,10 @@ final class Settings {
}
pw.print(prefix); pw.print(" versionName="); pw.println(ps.pkg.mVersionName);
pw.print(prefix); pw.print(" splits="); dumpSplitNames(pw, ps.pkg); pw.println();
final int apkSigningVersion = PackageParser.getApkSigningVersion(ps.pkg);
if (apkSigningVersion != PackageParser.APK_SIGNING_UNKNOWN) {
pw.print(prefix); pw.print(" apkSigningVersion="); pw.println(apkSigningVersion);
}
pw.print(prefix); pw.print(" applicationInfo=");
pw.println(ps.pkg.applicationInfo.toString());
pw.print(prefix); pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags,