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:
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user