Merge "Ignore signature stripping protection for preinstalled APKs." into nyc-dev am: e60d72f

am: c860aec

* commit 'c860aecc2f632ba7a0a1e53755b778b52645bb7e':
  Ignore signature stripping protection for preinstalled APKs.
This commit is contained in:
Alex Klyubin
2016-03-24 19:54:08 +00:00
committed by android-build-merger
3 changed files with 69 additions and 39 deletions

View File

@@ -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

View File

@@ -58,11 +58,22 @@ public final class StrictJarFile {
public StrictJarFile(String fileName)
throws IOException, SecurityException {
this(fileName, true);
this(fileName, true, true);
}
public StrictJarFile(String fileName, boolean verify)
throws IOException, SecurityException {
/**
*
* @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");
@@ -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) {

View File

@@ -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);
@@ -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;
}
/**
@@ -357,40 +364,42 @@ class StrictJarVerifier {
return;
}
// Check whether APK Signature Scheme v2 signature was stripped.
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.
boolean v2SignatureGenerated = false;
StringTokenizer tokenizer = new StringTokenizer(apkSignatureSchemeIdList, ",");
while (tokenizer.hasMoreTokens()) {
String idText = tokenizer.nextToken().trim();
if (idText.isEmpty()) {
continue;
// 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.
boolean v2SignatureGenerated = false;
StringTokenizer tokenizer = new StringTokenizer(apkSignatureSchemeIdList, ",");
while (tokenizer.hasMoreTokens()) {
String idText = tokenizer.nextToken().trim();
if (idText.isEmpty()) {
continue;
}
int id;
try {
id = Integer.parseInt(idText);
} catch (Exception ignored) {
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.
v2SignatureGenerated = true;
break;
}
}
int id;
try {
id = Integer.parseInt(idText);
} catch (Exception ignored) {
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.
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?");
if (v2SignatureGenerated) {
throw new SecurityException(signatureFile + " indicates " + jarName
+ " is signed using APK Signature Scheme v2, but no such signature was"
+ " found. Signature stripped?");
}
}
}