diff options
| author | 2020-01-24 19:00:01 -0800 | |
|---|---|---|
| committer | 2020-01-28 14:31:29 -0800 | |
| commit | 33df7c415a42ef495771228c8895b0ba7961382c (patch) | |
| tree | 961e75b2c424fbfdc249cc52957cd4f11a42fbb7 | |
| parent | 0f681fb3fb2e85a39ac434e4728d0255e14f1d50 (diff) | |
Require signature scheme V2+ for target SDK R+
With the recent sha-1 news, and since minSdk less than 18 for RSA and
minSdk less than 21 for DSA require sha-1, APK signature verification
will now require a minimum of a V2 signature for apps targeting R+.
Bug: 148313868
Test: atest PkgInstallSignatureVerificationTest
Change-Id: I8f518102a0b7cef190cbca59d140d380ae41c326
6 files changed, 42 insertions, 10 deletions
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index fd4c26569873..45f5ab69ff93 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1582,7 +1582,8 @@ public class PackageParser { throws PackageParserException { final String apkPath = apkFile.getAbsolutePath(); - int minSignatureScheme = SigningDetails.SignatureSchemeVersion.JAR; + int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk( + pkg.applicationInfo.targetSdkVersion); if (pkg.applicationInfo.isStaticSharedLibrary()) { // must use v2 signing scheme minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2; diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 6639b3d5c0b5..90a332ccb430 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -231,9 +231,9 @@ public class ApkLiteParseUtils { final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0; Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); try { - signingDetails = - ApkParseUtils.collectCertificates(apkFile.getAbsolutePath(), skipVerify, - false, PackageParser.SigningDetails.UNKNOWN); + signingDetails = ApkParseUtils.collectCertificates(apkFile.getAbsolutePath(), + skipVerify, false, PackageParser.SigningDetails.UNKNOWN, + DEFAULT_TARGET_SDK_VERSION); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java index 3018230fac27..7506412f72cc 100644 --- a/core/java/android/content/pm/parsing/ApkParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkParseUtils.java @@ -3176,7 +3176,8 @@ public class ApkParseUtils { pkg.getBaseCodePath(), skipVerify, pkg.isStaticSharedLibrary(), - pkg.getSigningDetails() + pkg.getSigningDetails(), + pkg.getTargetSdkVersion() )); String[] splitCodePaths = pkg.getSplitCodePaths(); @@ -3186,7 +3187,8 @@ public class ApkParseUtils { splitCodePaths[i], skipVerify, pkg.isStaticSharedLibrary(), - pkg.getSigningDetails() + pkg.getSigningDetails(), + pkg.getTargetSdkVersion() )); } } @@ -3199,9 +3201,11 @@ public class ApkParseUtils { String baseCodePath, boolean skipVerify, boolean isStaticSharedLibrary, - @NonNull SigningDetails existingSigningDetails + @NonNull SigningDetails existingSigningDetails, + int targetSdk ) throws PackageParserException { - int minSignatureScheme = SigningDetails.SignatureSchemeVersion.JAR; + int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk( + targetSdk); if (isStaticSharedLibrary) { // must use v2 signing scheme minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2; diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java index 71c8e98a0faa..64635098f7f4 100644 --- a/core/java/android/util/apk/ApkSignatureVerifier.java +++ b/core/java/android/util/apk/ApkSignatureVerifier.java @@ -27,6 +27,7 @@ import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.Signature; +import android.os.Build; import android.os.Trace; import android.util.jar.StrictJarFile; @@ -447,6 +448,17 @@ public class ApkSignatureVerifier { } /** + * Returns the minimum signature scheme version required for an app targeting the specified + * {@code targetSdk}. + */ + public static int getMinimumSignatureSchemeVersionForTargetSdk(int targetSdk) { + if (targetSdk >= Build.VERSION_CODES.R) { + return SignatureSchemeVersion.SIGNING_BLOCK_V2; + } + return SignatureSchemeVersion.JAR; + } + + /** * Result of a successful APK verification operation. */ public static class Result { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ca4ae0277aaf..b899fcd53ee5 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -60,6 +60,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIB import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE; import static android.content.pm.PackageManager.INSTALL_INTERNAL; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; @@ -124,8 +125,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; -import android.app.ApplicationPackageManager; import android.app.AppOpsManager; +import android.app.ApplicationPackageManager; import android.app.BroadcastOptions; import android.app.IActivityManager; import android.app.ResourcesManager; @@ -289,6 +290,7 @@ import android.util.SparseIntArray; import android.util.StatsLog; import android.util.TimingsTraceLog; import android.util.Xml; +import android.util.apk.ApkSignatureVerifier; import android.util.jar.StrictJarFile; import android.util.proto.ProtoOutputStream; import android.view.Display; @@ -11561,6 +11563,17 @@ public class PackageManagerService extends IPackageManager.Stub } } } + + // Ensure the package is signed with at least the minimum signature scheme version + // required for its target SDK. + int minSignatureSchemeVersion = + ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk( + pkg.getTargetSdkVersion()); + if (pkg.getSigningDetails().signatureSchemeVersion < minSignatureSchemeVersion) { + throw new PackageManagerException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, + "No signature found in package of version " + minSignatureSchemeVersion + + " or newer for package " + pkg.getPackageName()); + } } } diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 74c98f9ef444..ae28019a5dea 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -141,10 +141,12 @@ public class StagingManager { // Get signing details of the new package final String apexPath = newApexPkg.applicationInfo.sourceDir; final String packageName = newApexPkg.packageName; + int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk( + newApexPkg.applicationInfo.targetSdkVersion); final SigningDetails newSigningDetails; try { - newSigningDetails = ApkSignatureVerifier.verify(apexPath, SignatureSchemeVersion.JAR); + newSigningDetails = ApkSignatureVerifier.verify(apexPath, minSignatureScheme); } catch (PackageParserException e) { throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, "Failed to parse APEX package " + apexPath, e); |