Loading core/java/android/content/pm/PackageParser.java +19 −2 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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++) { Loading @@ -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; Loading core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java +69 −25 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -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; } Loading services/core/java/com/android/server/pm/Settings.java +4 −1 Original line number Diff line number Diff line Loading @@ -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); } Loading Loading @@ -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, Loading Loading
core/java/android/content/pm/PackageParser.java +19 −2 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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++) { Loading @@ -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; Loading
core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java +69 −25 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -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; } Loading
services/core/java/com/android/server/pm/Settings.java +4 −1 Original line number Diff line number Diff line Loading @@ -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); } Loading Loading @@ -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, Loading