Loading core/java/android/content/pm/PackageParser.java +7 −2 Original line number Diff line number Diff line Loading @@ -1158,10 +1158,15 @@ public class PackageParser { StrictJarFile jarFile = null; try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor"); // Ignore signature stripping protections when verifying APKs from system partition. // For those APKs we only care about extracting signer certificates, and don't care // about verifying integrity. boolean signatureSchemeRollbackProtectionsEnforced = (parseFlags & PARSE_IS_SYSTEM) == 0; jarFile = new StrictJarFile( apkPath, !verified // whether to verify JAR signature ); !verified, // whether to verify JAR signature signatureSchemeRollbackProtectionsEnforced); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); // Always verify manifest, regardless of source Loading core/java/android/util/jar/StrictJarFile.java +20 −4 Original line number Diff line number Diff line Loading @@ -58,10 +58,21 @@ public final class StrictJarFile { public StrictJarFile(String fileName) throws IOException, SecurityException { this(fileName, true); this(fileName, true, true); } public StrictJarFile(String fileName, boolean verify) /** * * @param verify whether to verify the file's JAR signatures and collect the corresponding * signer certificates. * @param signatureSchemeRollbackProtectionsEnforced {@code true} to enforce protections against * stripping newer signature schemes (e.g., APK Signature Scheme v2) from the file, or * {@code false} to ignore any such protections. This parameter is ignored when * {@code verify} is {@code false}. */ public StrictJarFile(String fileName, boolean verify, boolean signatureSchemeRollbackProtectionsEnforced) throws IOException, SecurityException { this.nativeHandle = nativeOpenJarFile(fileName); this.raf = new RandomAccessFile(fileName, "r"); Loading @@ -73,7 +84,12 @@ public final class StrictJarFile { if (verify) { HashMap<String, byte[]> metaEntries = getMetaEntries(); this.manifest = new StrictJarManifest(metaEntries.get(JarFile.MANIFEST_NAME), true); this.verifier = new StrictJarVerifier(fileName, manifest, metaEntries); this.verifier = new StrictJarVerifier( fileName, manifest, metaEntries, signatureSchemeRollbackProtectionsEnforced); Set<String> files = manifest.getEntries().keySet(); for (String file : files) { if (findEntry(file) == null) { Loading core/java/android/util/jar/StrictJarVerifier.java +42 −33 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ class StrictJarVerifier { private final StrictJarManifest manifest; private final HashMap<String, byte[]> metaEntries; private final int mainAttributesEnd; private final boolean signatureSchemeRollbackProtectionsEnforced; private final Hashtable<String, HashMap<String, Attributes>> signatures = new Hashtable<String, HashMap<String, Attributes>>(5); Loading Loading @@ -164,13 +165,19 @@ class StrictJarVerifier { * * @param name * the name of the JAR file being verified. * * @param signatureSchemeRollbackProtectionsEnforced {@code true} to enforce protections against * stripping newer signature schemes (e.g., APK Signature Scheme v2) from the file, or * {@code false} to ignore any such protections. */ StrictJarVerifier(String name, StrictJarManifest manifest, HashMap<String, byte[]> metaEntries) { HashMap<String, byte[]> metaEntries, boolean signatureSchemeRollbackProtectionsEnforced) { jarName = name; this.manifest = manifest; this.metaEntries = metaEntries; this.mainAttributesEnd = manifest.getMainAttributesEnd(); this.signatureSchemeRollbackProtectionsEnforced = signatureSchemeRollbackProtectionsEnforced; } /** Loading Loading @@ -357,15 +364,16 @@ class StrictJarVerifier { return; } // Check whether APK Signature Scheme v2 signature was stripped. // If requested, check whether APK Signature Scheme v2 signature was stripped. if (signatureSchemeRollbackProtectionsEnforced) { String apkSignatureSchemeIdList = attributes.getValue( ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME); if (apkSignatureSchemeIdList != null) { // This field contains a comma-separated list of APK signature scheme IDs which were // used to sign this APK. If an ID is known to us, it means signatures of that scheme // were stripped from the APK because otherwise we wouldn't have fallen back to // verifying the APK using the JAR signature scheme. // This field contains a comma-separated list of APK signature scheme IDs which // were used to sign this APK. If an ID is known to us, it means signatures of that // scheme were stripped from the APK because otherwise we wouldn't have fallen back // to verifying the APK using the JAR signature scheme. boolean v2SignatureGenerated = false; StringTokenizer tokenizer = new StringTokenizer(apkSignatureSchemeIdList, ","); while (tokenizer.hasMoreTokens()) { Loading @@ -380,17 +388,18 @@ class StrictJarVerifier { continue; } if (id == ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID) { // This APK was supposed to be signed with APK Signature Scheme v2 but no such // signature was found. // This APK was supposed to be signed with APK Signature Scheme v2 but no // such signature was found. v2SignatureGenerated = true; break; } } if (v2SignatureGenerated) { throw new SecurityException(signatureFile + " indicates " + jarName + " is signed" + " using APK Signature Scheme v2, but no such signature was found." + " Signature stripped?"); throw new SecurityException(signatureFile + " indicates " + jarName + " is signed using APK Signature Scheme v2, but no such signature was" + " found. Signature stripped?"); } } } Loading Loading
core/java/android/content/pm/PackageParser.java +7 −2 Original line number Diff line number Diff line Loading @@ -1158,10 +1158,15 @@ public class PackageParser { StrictJarFile jarFile = null; try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor"); // Ignore signature stripping protections when verifying APKs from system partition. // For those APKs we only care about extracting signer certificates, and don't care // about verifying integrity. boolean signatureSchemeRollbackProtectionsEnforced = (parseFlags & PARSE_IS_SYSTEM) == 0; jarFile = new StrictJarFile( apkPath, !verified // whether to verify JAR signature ); !verified, // whether to verify JAR signature signatureSchemeRollbackProtectionsEnforced); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); // Always verify manifest, regardless of source Loading
core/java/android/util/jar/StrictJarFile.java +20 −4 Original line number Diff line number Diff line Loading @@ -58,10 +58,21 @@ public final class StrictJarFile { public StrictJarFile(String fileName) throws IOException, SecurityException { this(fileName, true); this(fileName, true, true); } public StrictJarFile(String fileName, boolean verify) /** * * @param verify whether to verify the file's JAR signatures and collect the corresponding * signer certificates. * @param signatureSchemeRollbackProtectionsEnforced {@code true} to enforce protections against * stripping newer signature schemes (e.g., APK Signature Scheme v2) from the file, or * {@code false} to ignore any such protections. This parameter is ignored when * {@code verify} is {@code false}. */ public StrictJarFile(String fileName, boolean verify, boolean signatureSchemeRollbackProtectionsEnforced) throws IOException, SecurityException { this.nativeHandle = nativeOpenJarFile(fileName); this.raf = new RandomAccessFile(fileName, "r"); Loading @@ -73,7 +84,12 @@ public final class StrictJarFile { if (verify) { HashMap<String, byte[]> metaEntries = getMetaEntries(); this.manifest = new StrictJarManifest(metaEntries.get(JarFile.MANIFEST_NAME), true); this.verifier = new StrictJarVerifier(fileName, manifest, metaEntries); this.verifier = new StrictJarVerifier( fileName, manifest, metaEntries, signatureSchemeRollbackProtectionsEnforced); Set<String> files = manifest.getEntries().keySet(); for (String file : files) { if (findEntry(file) == null) { Loading
core/java/android/util/jar/StrictJarVerifier.java +42 −33 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ class StrictJarVerifier { private final StrictJarManifest manifest; private final HashMap<String, byte[]> metaEntries; private final int mainAttributesEnd; private final boolean signatureSchemeRollbackProtectionsEnforced; private final Hashtable<String, HashMap<String, Attributes>> signatures = new Hashtable<String, HashMap<String, Attributes>>(5); Loading Loading @@ -164,13 +165,19 @@ class StrictJarVerifier { * * @param name * the name of the JAR file being verified. * * @param signatureSchemeRollbackProtectionsEnforced {@code true} to enforce protections against * stripping newer signature schemes (e.g., APK Signature Scheme v2) from the file, or * {@code false} to ignore any such protections. */ StrictJarVerifier(String name, StrictJarManifest manifest, HashMap<String, byte[]> metaEntries) { HashMap<String, byte[]> metaEntries, boolean signatureSchemeRollbackProtectionsEnforced) { jarName = name; this.manifest = manifest; this.metaEntries = metaEntries; this.mainAttributesEnd = manifest.getMainAttributesEnd(); this.signatureSchemeRollbackProtectionsEnforced = signatureSchemeRollbackProtectionsEnforced; } /** Loading Loading @@ -357,15 +364,16 @@ class StrictJarVerifier { return; } // Check whether APK Signature Scheme v2 signature was stripped. // If requested, check whether APK Signature Scheme v2 signature was stripped. if (signatureSchemeRollbackProtectionsEnforced) { String apkSignatureSchemeIdList = attributes.getValue( ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME); if (apkSignatureSchemeIdList != null) { // This field contains a comma-separated list of APK signature scheme IDs which were // used to sign this APK. If an ID is known to us, it means signatures of that scheme // were stripped from the APK because otherwise we wouldn't have fallen back to // verifying the APK using the JAR signature scheme. // This field contains a comma-separated list of APK signature scheme IDs which // were used to sign this APK. If an ID is known to us, it means signatures of that // scheme were stripped from the APK because otherwise we wouldn't have fallen back // to verifying the APK using the JAR signature scheme. boolean v2SignatureGenerated = false; StringTokenizer tokenizer = new StringTokenizer(apkSignatureSchemeIdList, ","); while (tokenizer.hasMoreTokens()) { Loading @@ -380,17 +388,18 @@ class StrictJarVerifier { continue; } if (id == ApkSignatureSchemeV2Verifier.SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID) { // This APK was supposed to be signed with APK Signature Scheme v2 but no such // signature was found. // This APK was supposed to be signed with APK Signature Scheme v2 but no // such signature was found. v2SignatureGenerated = true; break; } } if (v2SignatureGenerated) { throw new SecurityException(signatureFile + " indicates " + jarName + " is signed" + " using APK Signature Scheme v2, but no such signature was found." + " Signature stripped?"); throw new SecurityException(signatureFile + " indicates " + jarName + " is signed using APK Signature Scheme v2, but no such signature was" + " found. Signature stripped?"); } } } Loading