From 8b7cc7fbed9499100557144410d8ab76da5d78e3 Mon Sep 17 00:00:00 2001 From: Victor Hsieh Date: Fri, 10 Feb 2023 10:29:05 -0800 Subject: [PATCH] Fallback to sha256 when preferred checksum failed Bug: 265467404 Test: Manually remove the signing block of an updated preload, run the job. Saw a local debugging log of sha256 measurement. Change-Id: I8a4de6ce01a5bfc0c021ece6dbb6efffce9eba25 --- core/java/android/util/PackageUtils.java | 41 ++++++++++++------- .../server/BinaryTransparencyService.java | 36 ++++++++-------- 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java index 6f8c5dbdb6f85..ea7efc79de870 100644 --- a/core/java/android/util/PackageUtils.java +++ b/core/java/android/util/PackageUtils.java @@ -184,24 +184,15 @@ public final class PackageUtils { } /** - * @see #computeSha256DigestForLargeFile(String, byte[], String) - */ - public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath, - @NonNull byte[] fileBuffer) { - return computeSha256DigestForLargeFile(filePath, fileBuffer, null); - } - - /** - * Computes the SHA256 digest of large files. This is typically useful for large APEXs. + * Computes the SHA256 digest of a large file. * @param filePath The path to which the file's content is to be hashed. * @param fileBuffer A buffer to read file's content into memory. It is strongly recommended to * make use of the {@link #createLargeFileBuffer()} method to create this * buffer. - * @param separator Separator between each pair of characters, such as colon, or null to omit. - * @return The SHA256 digest or null if an error occurs. + * @return The byte array of SHA256 digest or null if an error occurs. */ - public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath, - @NonNull byte[] fileBuffer, @Nullable String separator) { + public static @Nullable byte[] computeSha256DigestForLargeFileAsBytes(@NonNull String filePath, + @NonNull byte[] fileBuffer) { MessageDigest messageDigest; try { messageDigest = MessageDigest.getInstance("SHA256"); @@ -221,8 +212,30 @@ public final class PackageUtils { return null; } - byte[] resultBytes = messageDigest.digest(); + return messageDigest.digest(); + } + /** + * @see #computeSha256DigestForLargeFile(String, byte[], String) + */ + public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath, + @NonNull byte[] fileBuffer) { + return computeSha256DigestForLargeFile(filePath, fileBuffer, null); + } + + /** + * Computes the SHA256 digest of a large file. + * @param filePath The path to which the file's content is to be hashed. + * @param fileBuffer A buffer to read file's content into memory. It is strongly recommended to + * make use of the {@link #createLargeFileBuffer()} method to create this + * buffer. + * @param separator Separator between each pair of characters, such as colon, or null to omit. + * @see #computeSha256DigestForLargeFile(String, byte[]) + * @return The encoded string of SHA256 digest or null if an error occurs. + */ + public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath, + @NonNull byte[] fileBuffer, @Nullable String separator) { + byte[] resultBytes = computeSha256DigestForLargeFileAsBytes(filePath, fileBuffer); if (separator == null) { return HexEncoding.encodeToString(resultBytes, false); } diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java index eafd3e0ab3e7f..f49dfeb1f9591 100644 --- a/services/core/java/com/android/server/BinaryTransparencyService.java +++ b/services/core/java/com/android/server/BinaryTransparencyService.java @@ -263,26 +263,26 @@ public class BinaryTransparencyService extends SystemService { Map contentDigests = computeApkContentDigest(apkPath); if (contentDigests == null) { Slog.d(TAG, "Failed to compute content digest for " + apkPath); - return new Checksum(0, new byte[] { -1 }); - } - - // in this iteration, we'll be supporting only 2 types of digests: - // CHUNKED_SHA256 and CHUNKED_SHA512. - // And only one of them will be available per package. - if (contentDigests.containsKey(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256)) { - return new Checksum( - Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, - contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256)); - } else if (contentDigests.containsKey( - ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512)) { - return new Checksum( - Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512, - contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512)); } else { - // TODO(b/259423111): considering putting the raw values for the algorithm & digest - // into the bundle to track potential other digest algorithms that may be in use - return new Checksum(0, new byte[] { -1 }); + // in this iteration, we'll be supporting only 2 types of digests: + // CHUNKED_SHA256 and CHUNKED_SHA512. + // And only one of them will be available per package. + if (contentDigests.containsKey( + ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256)) { + return new Checksum( + Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256, + contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256)); + } else if (contentDigests.containsKey( + ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512)) { + return new Checksum( + Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512, + contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512)); + } } + // When something went wrong, fall back to simple sha256. + byte[] digest = PackageUtils.computeSha256DigestForLargeFileAsBytes(apkPath, + PackageUtils.createLargeFileBuffer()); + return new Checksum(Checksum.TYPE_WHOLE_SHA256, digest); }