Ignore signature stripping protection for preinstalled APKs.
The current build process may currently strip APK Signature Scheme v2
signatures from prebuilt APKs to be installed on the system or vendor
partitions. However, it leaves intact the signature scheme rollback
protections introduced by APK Signature Scheme v2. Due to a bug, when
the system extracts signer certificates from preinstalled APKs, it
encounters the rollback protection and aborts the extraction process.
This manifests itself as some preinstalled packages not appearing as
installed.
This change makes the system ignore signature scheme rollback
protections when extracting certificates from preinstalled APKs. This
is fine because the process of extracting certificates from
preinstalled APKs does not care about validity/integrity of signatures
and the APKs. It only cares about extracting signer certificates.
Bug: 27829513
Change-Id: I3bed463e776b057e93a0fce915db4014946be1f9
diff --git a/core/java/android/util/jar/StrictJarVerifier.java b/core/java/android/util/jar/StrictJarVerifier.java
index 0546a5f..6da50ba 100644
--- a/core/java/android/util/jar/StrictJarVerifier.java
+++ b/core/java/android/util/jar/StrictJarVerifier.java
@@ -72,6 +72,7 @@
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 @@
*
* @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 @@
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?");
+ }
}
}