diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java index 9754b6d4db020..0450647b94032 100644 --- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java @@ -39,13 +39,20 @@ import android.content.integrity.Rule; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import android.content.pm.PackageParser; +import android.content.pm.PackageUserState; import android.content.pm.ParceledListSlice; import android.content.pm.Signature; +import android.content.pm.SigningInfo; +import android.content.pm.parsing.ApkParseUtils; +import android.content.pm.parsing.PackageInfoUtils; +import android.content.pm.parsing.ParsedPackage; import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; +import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; @@ -67,6 +74,7 @@ import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -121,11 +129,11 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { IntegrityFileManager.getInstance(), handlerThread.getThreadHandler(), Settings.Global.getInt( - context.getContentResolver(), - Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER, - 0) - == 1 - ); + context.getContentResolver(), + Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER, + 0) + == 1 + ); } @VisibleForTesting @@ -260,16 +268,25 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { return; } - String appCert = getCertificateFingerprint(packageInfo); + List appCertificates = getCertificateFingerprint(packageInfo); + List installerCertificates = + getInstallerCertificateFingerprint(installerPackageName); + + // TODO (b/148373316): Figure out what field contains which fields are populated for + // rotated and the multiple signers. Until then, return the first certificate. + String appCert = appCertificates.isEmpty() ? "" : appCertificates.get(0); + String installerCert = + installerCertificates.isEmpty() ? "" : installerCertificates.get(0); + + Slog.w(TAG, appCertificates.toString()); AppInstallMetadata.Builder builder = new AppInstallMetadata.Builder(); builder.setPackageName(getPackageNameNormalized(packageName)); - builder.setAppCertificate(appCert == null ? "" : appCert); + builder.setAppCertificate(appCert); builder.setVersionCode(intent.getLongExtra(EXTRA_LONG_VERSION_CODE, -1)); builder.setInstallerName(getPackageNameNormalized(installerPackageName)); - builder.setInstallerCertificate( - getInstallerCertificateFingerprint(installerPackageName)); + builder.setInstallerCertificate(installerCert); builder.setIsPreInstalled(isSystemApp(packageName)); AppInstallMetadata appInstallMetadata = builder.build(); @@ -320,7 +337,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { * Verify the UID and return the installer package name. * * @return the package name of the installer, or null if it cannot be determined or it is - * installed via adb. + * installed via adb. */ @Nullable private String getInstallerPackageName(Intent intent) { @@ -399,25 +416,29 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { } } - private String getCertificateFingerprint(@NonNull PackageInfo packageInfo) { - return getFingerprint(getSignature(packageInfo)); - } - - private String getInstallerCertificateFingerprint(String installer) { + private List getInstallerCertificateFingerprint(String installer) { if (installer.equals(ADB_INSTALLER) || installer.equals(UNKNOWN_INSTALLER)) { - return INSTALLER_CERT_NOT_APPLICABLE; + return Collections.emptyList(); } try { PackageInfo installerInfo = mContext.getPackageManager() - .getPackageInfo(installer, PackageManager.GET_SIGNATURES); + .getPackageInfo(installer, PackageManager.GET_SIGNING_CERTIFICATES); return getCertificateFingerprint(installerInfo); } catch (PackageManager.NameNotFoundException e) { Slog.i(TAG, "Installer package " + installer + " not found."); - return ""; + return Collections.emptyList(); } } + private List getCertificateFingerprint(@NonNull PackageInfo packageInfo) { + ArrayList certificateFingerprints = new ArrayList(); + for (Signature signature : getSignatures(packageInfo)) { + certificateFingerprints.add(getFingerprint(signature)); + } + return certificateFingerprints; + } + /** Get the allowed installers and their associated certificate hashes from tag. */ private Map getAllowedInstallers(@NonNull PackageInfo packageInfo) { Map packageCertMap = new HashMap<>(); @@ -445,12 +466,15 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { return packageCertMap; } - private static Signature getSignature(@NonNull PackageInfo packageInfo) { - if (packageInfo.signatures == null || packageInfo.signatures.length < 1) { + private static Signature[] getSignatures(@NonNull PackageInfo packageInfo) { + SigningInfo signingInfo = packageInfo.signingInfo; + + if (signingInfo == null || signingInfo.getApkContentsSigners().length < 1) { throw new IllegalArgumentException("Package signature not found in " + packageInfo); } - // Only the first element is guaranteed to be present. - return packageInfo.signatures[0]; + + // We are only interested in evaluating the active signatures. + return signingInfo.getApkContentsSigners(); } private static String getFingerprint(Signature cert) { @@ -489,20 +513,14 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { if (installationPath == null) { throw new IllegalArgumentException("Installation path is null, package not found"); } - PackageInfo packageInfo; + + PackageParser parser = new PackageParser(); try { - // The installation path will be a directory for a multi-apk install on L+ - if (installationPath.isDirectory()) { - packageInfo = getMultiApkInfo(installationPath); - } else { - packageInfo = - mContext.getPackageManager() - .getPackageArchiveInfo( - installationPath.getPath(), - PackageManager.GET_SIGNATURES - | PackageManager.GET_META_DATA); - } - return packageInfo; + ParsedPackage pkg = parser.parseParsedPackage(installationPath, 0, false); + int flags = PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_META_DATA; + ApkParseUtils.collectCertificates(pkg, false); + return PackageInfoUtils.generate(pkg, null, flags, 0, 0, null, new PackageUserState(), + UserHandle.getCallingUserId()); } catch (Exception e) { throw new IllegalArgumentException("Exception reading " + dataUri, e); } @@ -515,7 +533,8 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { mContext.getPackageManager() .getPackageArchiveInfo( baseFile.getAbsolutePath(), - PackageManager.GET_SIGNATURES | PackageManager.GET_META_DATA); + PackageManager.GET_SIGNING_CERTIFICATES + | PackageManager.GET_META_DATA); if (basePackageInfo == null) { for (File apkFile : multiApkDirectory.listFiles()) { diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java index 4a7636a179b1a..c9ec874277225 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java @@ -423,7 +423,8 @@ public class AppIntegrityManagerServiceImplTest { PackageInfo packageInfo = mRealContext .getPackageManager() - .getPackageInfo(TEST_FRAMEWORK_PACKAGE, PackageManager.GET_SIGNATURES); + .getPackageInfo(TEST_FRAMEWORK_PACKAGE, + PackageManager.GET_SIGNING_CERTIFICATES); doReturn(packageInfo).when(mSpyPackageManager).getPackageInfo(eq(INSTALLER), anyInt()); doReturn(1).when(mSpyPackageManager).getPackageUid(eq(INSTALLER), anyInt()); return makeVerificationIntent(INSTALLER);