diff options
| -rw-r--r-- | core/java/android/util/PackageUtils.java | 2 | ||||
| -rw-r--r-- | services/core/java/com/android/server/BinaryTransparencyService.java | 231 |
2 files changed, 210 insertions, 23 deletions
diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java index 11481209284a..6f8c5dbdb6f8 100644 --- a/core/java/android/util/PackageUtils.java +++ b/core/java/android/util/PackageUtils.java @@ -224,7 +224,7 @@ public final class PackageUtils { byte[] resultBytes = messageDigest.digest(); if (separator == null) { - return HexEncoding.encodeToString(resultBytes, true); + return HexEncoding.encodeToString(resultBytes, false); } int length = resultBytes.length; diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java index fa52ac905a43..8055afce8370 100644 --- a/services/core/java/com/android/server/BinaryTransparencyService.java +++ b/services/core/java/com/android/server/BinaryTransparencyService.java @@ -26,9 +26,15 @@ import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; +import android.content.pm.InstallSourceInfo; import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.content.pm.SigningDetails; +import android.content.pm.SigningInfo; +import android.content.pm.parsing.result.ParseResult; +import android.content.pm.parsing.result.ParseTypeImpl; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; @@ -39,13 +45,19 @@ import android.os.ShellCommand; import android.os.SystemProperties; import android.util.PackageUtils; import android.util.Slog; +import android.util.apk.ApkSignatureVerifier; +import android.util.apk.ApkSigningBlockUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IBinaryTransparencyService; import com.android.internal.util.FrameworkStatsLog; +import libcore.util.HexEncoding; + import java.io.FileDescriptor; import java.io.PrintWriter; +import java.security.PublicKey; +import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -151,6 +163,117 @@ public class BinaryTransparencyService extends SystemService { return 0; } + private void printPackageMeasurements(PackageInfo packageInfo, + final PrintWriter pw) { + pw.print(mBinaryHashes.get(packageInfo.packageName) + ","); + // TODO: To be moved to somewhere more suitable + final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); + ParseResult<ApkSignatureVerifier.SigningDetailsWithDigests> parseResult = + ApkSignatureVerifier.verifySignaturesInternal(input, + packageInfo.applicationInfo.sourceDir, + SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, false); + if (parseResult.isError()) { + pw.println("ERROR: Failed to compute package content digest for " + + packageInfo.applicationInfo.sourceDir + "due to: " + + parseResult.getErrorMessage()); + } else { + ApkSignatureVerifier.SigningDetailsWithDigests signingDetails = + parseResult.getResult(); + Map<Integer, byte[]> contentDigests = signingDetails.contentDigests; + for (Map.Entry<Integer, byte[]> entry : contentDigests.entrySet()) { + Integer algorithmId = entry.getKey(); + byte[] cDigest = entry.getValue(); + //pw.print("Content digest algorithm: "); + switch (algorithmId) { + case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256: + pw.print("CHUNKED_SHA256:"); + break; + case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512: + pw.print("CHUNKED_SHA512:"); + break; + case ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256: + pw.print("VERITY_CHUNKED_SHA256:"); + break; + case ApkSigningBlockUtils.CONTENT_DIGEST_SHA256: + pw.print("SHA256:"); + break; + default: + pw.print("UNKNOWN:"); + } + pw.print(HexEncoding.encodeToString(cDigest, false)); + } + } + } + + private void printPackageInstallationInfo(PackageInfo packageInfo, + final PrintWriter pw) { + pw.println("--- Package Installation Info ---"); + pw.println("Current install location: " + + packageInfo.applicationInfo.sourceDir); + if (packageInfo.applicationInfo.sourceDir.startsWith("/data/apex/")) { + String origPackageFilepath = getOriginalPreinstalledLocation( + packageInfo.packageName, packageInfo.applicationInfo.sourceDir); + pw.println("|--> Package pre-installed location: " + origPackageFilepath); + String digest = mBinaryHashes.get(origPackageFilepath); + if (digest == null) { + pw.println("ERROR finding SHA256-digest from cache..."); + } else { + pw.println("|--> Pre-installed package SHA256-digest: " + digest); + } + } + pw.println("First install time (ms): " + packageInfo.firstInstallTime); + pw.println("Last update time (ms): " + packageInfo.lastUpdateTime); + boolean isPreloaded = (packageInfo.firstInstallTime + == packageInfo.lastUpdateTime); + pw.println("Is preloaded: " + isPreloaded); + + InstallSourceInfo installSourceInfo = getInstallSourceInfo( + packageInfo.packageName); + if (installSourceInfo == null) { + pw.println("ERROR: Unable to obtain installSourceInfo of " + + packageInfo.packageName); + } else { + pw.println("Installation initiated by: " + + installSourceInfo.getInitiatingPackageName()); + pw.println("Installation done by: " + + installSourceInfo.getInstallingPackageName()); + pw.println("Installation originating from: " + + installSourceInfo.getOriginatingPackageName()); + } + + if (packageInfo.isApex) { + pw.println("Is an active APEX: " + packageInfo.isActiveApex); + } + } + + private void printPackageSignerDetails(SigningInfo signerInfo, + final PrintWriter pw) { + if (signerInfo == null) { + pw.println("ERROR: Package's signingInfo is null."); + return; + } + pw.println("--- Package Signer Info ---"); + pw.println("Has multiple signers: " + signerInfo.hasMultipleSigners()); + Signature[] packageSigners = signerInfo.getApkContentsSigners(); + for (Signature packageSigner : packageSigners) { + byte[] packageSignerDigestBytes = + PackageUtils.computeSha256DigestBytes(packageSigner.toByteArray()); + String packageSignerDigestHextring = + HexEncoding.encodeToString(packageSignerDigestBytes, false); + pw.println("Signer cert's SHA256-digest: " + packageSignerDigestHextring); + try { + PublicKey publicKey = packageSigner.getPublicKey(); + pw.println("Signing key algorithm: " + publicKey.getAlgorithm()); + } catch (CertificateException e) { + Slog.e(TAG, + "Failed to obtain public key of signer for cert with hash: " + + packageSignerDigestHextring); + e.printStackTrace(); + } + } + + } + private void printModuleDetails(ModuleInfo moduleInfo, final PrintWriter pw) { pw.println("--- Module Details ---"); pw.println("Module name: " + moduleInfo.getName()); @@ -190,28 +313,35 @@ public class BinaryTransparencyService extends SystemService { return -1; } - pw.println("APEX Info:"); + if (!verbose) { + pw.println("APEX Info [Format: package_name,package_version," + + "package_sha256_digest," + + "content_digest_algorithm:content_digest]:"); + } for (PackageInfo packageInfo : getInstalledApexs()) { + if (verbose) { + pw.println("APEX Info [Format: package_name,package_version," + + "package_sha256_digest," + + "content_digest_algorithm:content_digest]:"); + } String packageName = packageInfo.packageName; - pw.println(packageName + ";" - + packageInfo.getLongVersionCode() + ":" - + mBinaryHashes.get(packageName).toLowerCase()); + pw.print(packageName + "," + + packageInfo.getLongVersionCode() + ","); + printPackageMeasurements(packageInfo, pw); + pw.print("\n"); if (verbose) { - pw.println("Install location: " - + packageInfo.applicationInfo.sourceDir); - pw.println("Last Update Time (ms): " + packageInfo.lastUpdateTime); - ModuleInfo moduleInfo; try { moduleInfo = pm.getModuleInfo(packageInfo.packageName, 0); + pw.println("Is a module: true"); + printModuleDetails(moduleInfo, pw); } catch (PackageManager.NameNotFoundException e) { - pw.println("Is A Module: False"); - pw.println(""); - continue; + pw.println("Is a module: false"); } - pw.println("Is A Module: True"); - printModuleDetails(moduleInfo, pw); + + printPackageInstallationInfo(packageInfo, pw); + printPackageSignerDetails(packageInfo.signingInfo, pw); pw.println(""); } } @@ -250,25 +380,37 @@ public class BinaryTransparencyService extends SystemService { return -1; } - pw.println("Module Info:"); + if (!verbose) { + pw.println("Module Info [Format: package_name,package_version," + + "package_sha256_digest," + + "content_digest_algorithm:content_digest]:"); + } for (ModuleInfo module : pm.getInstalledModules(PackageManager.MATCH_ALL)) { String packageName = module.getPackageName(); + if (verbose) { + pw.println("Module Info [Format: package_name,package_version," + + "package_sha256_digest," + + "content_digest_algorithm:content_digest]:"); + } try { PackageInfo packageInfo = pm.getPackageInfo(packageName, - PackageManager.MATCH_APEX); - pw.println(packageInfo.packageName + ";" - + packageInfo.getLongVersionCode() + ":" - + mBinaryHashes.get(packageName).toLowerCase()); + PackageManager.MATCH_APEX + | PackageManager.GET_SIGNING_CERTIFICATES); + //pw.print("package:"); + pw.print(packageInfo.packageName + ","); + pw.print(packageInfo.getLongVersionCode() + ","); + printPackageMeasurements(packageInfo, pw); + pw.print("\n"); if (verbose) { - pw.println("Install location: " - + packageInfo.applicationInfo.sourceDir); printModuleDetails(module, pw); + printPackageInstallationInfo(packageInfo, pw); + printPackageSignerDetails(packageInfo.signingInfo, pw); pw.println(""); } } catch (PackageManager.NameNotFoundException e) { pw.println(packageName - + ";ERROR:Unable to find PackageInfo for this module."); + + ",ERROR:Unable to find PackageInfo for this module."); if (verbose) { printModuleDetails(module, pw); pw.println(""); @@ -468,7 +610,8 @@ public class BinaryTransparencyService extends SystemService { return results; } List<PackageInfo> allPackages = pm.getInstalledPackages( - PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX)); + PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX + | PackageManager.GET_SIGNING_CERTIFICATES)); if (allPackages == null) { Slog.e(TAG, "Error obtaining installed packages (including APEX)"); return results; @@ -478,6 +621,21 @@ public class BinaryTransparencyService extends SystemService { return results; } + @Nullable + private InstallSourceInfo getInstallSourceInfo(String packageName) { + PackageManager pm = mContext.getPackageManager(); + if (pm == null) { + Slog.e(TAG, "Error obtaining an instance of PackageManager."); + return null; + } + try { + return pm.getInstallSourceInfo(packageName); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return null; + } + } + /** * Updates the internal data structure with the most current APEX measurements. @@ -539,6 +697,14 @@ public class BinaryTransparencyService extends SystemService { return true; } + private String getOriginalPreinstalledLocation(String packageName, + String currentInstalledLocation) { + if (currentInstalledLocation.contains("/decompressed/")) { + return "/system/apex/" + packageName + ".capex"; + } + return "/system/apex" + packageName + "apex"; + } + private void doFreshBinaryMeasurements() { PackageManager pm = mContext.getPackageManager(); Slog.d(TAG, "Obtained package manager"); @@ -567,6 +733,27 @@ public class BinaryTransparencyService extends SystemService { mBinaryLastUpdateTimes.put(packageInfo.packageName, packageInfo.lastUpdateTime); } + for (PackageInfo packageInfo : getInstalledApexs()) { + ApplicationInfo appInfo = packageInfo.applicationInfo; + if (!appInfo.sourceDir.startsWith("/data/")) { + continue; + } + String origInstallPath = getOriginalPreinstalledLocation(packageInfo.packageName, + appInfo.sourceDir); + + // compute SHA256 for the orig /system APEXs + String sha256digest = PackageUtils.computeSha256DigestForLargeFile(origInstallPath, + largeFileBuffer); + if (sha256digest == null) { + Slog.e(TAG, String.format("Failed to compute SHA256 digest for file at %s", + origInstallPath)); + mBinaryHashes.put(origInstallPath, BINARY_HASH_ERROR); + } else { + mBinaryHashes.put(origInstallPath, sha256digest); + } + // there'd be no entry into mBinaryLastUpdateTimes + } + // Next, get all installed modules from PackageManager - skip over those APEXs we've // processed above for (ModuleInfo module : pm.getInstalledModules(PackageManager.MATCH_ALL)) { |