Loading services/core/java/com/android/server/pm/ApkChecksums.java +45 −8 Original line number Original line Diff line number Diff line Loading @@ -77,6 +77,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStream; import java.io.RandomAccessFile; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.file.Files; import java.nio.file.Files; import java.security.DigestException; import java.security.DigestException; import java.security.InvalidParameterException; import java.security.InvalidParameterException; Loading Loading @@ -584,7 +585,7 @@ public class ApkChecksums { }); }); checksums.put(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, checksums.put(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, generatedRootHash)); verityHashForFile(file, generatedRootHash))); } catch (IOException | NoSuchAlgorithmException | DigestException e) { } catch (IOException | NoSuchAlgorithmException | DigestException e) { Slog.e(TAG, "Error calculating WHOLE_MERKLE_ROOT_4K_SHA256", e); Slog.e(TAG, "Error calculating WHOLE_MERKLE_ROOT_4K_SHA256", e); } } Loading Loading @@ -649,19 +650,20 @@ public class ApkChecksums { // Skip /product folder. // Skip /product folder. // TODO(b/231354111): remove this hack once we are allowed to change SELinux rules. // TODO(b/231354111): remove this hack once we are allowed to change SELinux rules. if (!containsFile(Environment.getProductDirectory(), filePath)) { if (!containsFile(Environment.getProductDirectory(), filePath)) { byte[] hash = VerityUtils.getFsverityRootHash(filePath); byte[] verityHash = VerityUtils.getFsverityRootHash(filePath); if (hash != null) { if (verityHash != null) { return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, hash); return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, verityHash); } } } } // v4 next // v4 next try { try { ApkSignatureSchemeV4Verifier.VerifiedSigner signer = ApkSignatureSchemeV4Verifier.VerifiedSigner signer = ApkSignatureSchemeV4Verifier.extractCertificates(filePath); ApkSignatureSchemeV4Verifier.extractCertificates(filePath); byte[] hash = signer.contentDigests.getOrDefault(CONTENT_DIGEST_VERITY_CHUNKED_SHA256, byte[] rootHash = signer.contentDigests.getOrDefault( null); CONTENT_DIGEST_VERITY_CHUNKED_SHA256, null); if (hash != null) { if (rootHash != null) { return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, hash); return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, verityHashForFile(new File(filePath), rootHash)); } } } catch (SignatureNotFoundException e) { } catch (SignatureNotFoundException e) { // Nothing // Nothing Loading @@ -671,6 +673,41 @@ public class ApkChecksums { return null; return null; } } /** * Returns fs-verity digest as described in * https://www.kernel.org/doc/html/latest/filesystems/fsverity.html#fs-verity-descriptor * @param file the Merkle tree is built over * @param rootHash Merkle tree root hash */ static byte[] verityHashForFile(File file, byte[] rootHash) { try { ByteBuffer buffer = ByteBuffer.allocate(256); // sizeof(fsverity_descriptor) buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.put((byte) 1); // __u8 version, must be 1 buffer.put((byte) 1); // __u8 hash_algorithm, FS_VERITY_HASH_ALG_SHA256 buffer.put((byte) 12); // __u8, FS_VERITY_LOG_BLOCKSIZE buffer.put((byte) 0); // __u8, size of salt in bytes; 0 if none buffer.putInt(0); // __le32 __reserved_0x04, must be 0 buffer.putLong(file.length()); // __le64 data_size buffer.put(rootHash); // root_hash, first 32 bytes final int padding = 32 + 32 + 144; // root_hash, last 32 bytes, we are using sha256. // salt, 32 bytes // reserved, 144 bytes for (int i = 0; i < padding; ++i) { buffer.put((byte) 0); } buffer.flip(); final MessageDigest md = MessageDigest.getInstance(ALGO_SHA256); md.update(buffer); return md.digest(); } catch (NoSuchAlgorithmException e) { Slog.e(TAG, "Device does not support MessageDigest algorithm", e); return null; } } private static Map<Integer, ApkChecksum> extractHashFromV2V3Signature( private static Map<Integer, ApkChecksum> extractHashFromV2V3Signature( String split, String filePath, int types) { String split, String filePath, int types) { Map<Integer, byte[]> contentDigests = null; Map<Integer, byte[]> contentDigests = null; Loading services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -1069,7 +1069,7 @@ public class PackageManagerServiceUtils { if (ArrayUtils.isEmpty(hashInfo.rawRootHash)) { if (ArrayUtils.isEmpty(hashInfo.rawRootHash)) { throw new IOException("Root has not present"); throw new IOException("Root has not present"); } } return hashInfo.rawRootHash; return ApkChecksums.verityHashForFile(new File(filename), hashInfo.rawRootHash); } catch (IOException ignore) { } catch (IOException ignore) { Slog.e(TAG, "ERROR: could not load root hash from incremental install"); Slog.e(TAG, "ERROR: could not load root hash from incremental install"); } } Loading Loading
services/core/java/com/android/server/pm/ApkChecksums.java +45 −8 Original line number Original line Diff line number Diff line Loading @@ -77,6 +77,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStream; import java.io.RandomAccessFile; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.file.Files; import java.nio.file.Files; import java.security.DigestException; import java.security.DigestException; import java.security.InvalidParameterException; import java.security.InvalidParameterException; Loading Loading @@ -584,7 +585,7 @@ public class ApkChecksums { }); }); checksums.put(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, checksums.put(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, generatedRootHash)); verityHashForFile(file, generatedRootHash))); } catch (IOException | NoSuchAlgorithmException | DigestException e) { } catch (IOException | NoSuchAlgorithmException | DigestException e) { Slog.e(TAG, "Error calculating WHOLE_MERKLE_ROOT_4K_SHA256", e); Slog.e(TAG, "Error calculating WHOLE_MERKLE_ROOT_4K_SHA256", e); } } Loading Loading @@ -649,19 +650,20 @@ public class ApkChecksums { // Skip /product folder. // Skip /product folder. // TODO(b/231354111): remove this hack once we are allowed to change SELinux rules. // TODO(b/231354111): remove this hack once we are allowed to change SELinux rules. if (!containsFile(Environment.getProductDirectory(), filePath)) { if (!containsFile(Environment.getProductDirectory(), filePath)) { byte[] hash = VerityUtils.getFsverityRootHash(filePath); byte[] verityHash = VerityUtils.getFsverityRootHash(filePath); if (hash != null) { if (verityHash != null) { return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, hash); return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, verityHash); } } } } // v4 next // v4 next try { try { ApkSignatureSchemeV4Verifier.VerifiedSigner signer = ApkSignatureSchemeV4Verifier.VerifiedSigner signer = ApkSignatureSchemeV4Verifier.extractCertificates(filePath); ApkSignatureSchemeV4Verifier.extractCertificates(filePath); byte[] hash = signer.contentDigests.getOrDefault(CONTENT_DIGEST_VERITY_CHUNKED_SHA256, byte[] rootHash = signer.contentDigests.getOrDefault( null); CONTENT_DIGEST_VERITY_CHUNKED_SHA256, null); if (hash != null) { if (rootHash != null) { return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, hash); return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, verityHashForFile(new File(filePath), rootHash)); } } } catch (SignatureNotFoundException e) { } catch (SignatureNotFoundException e) { // Nothing // Nothing Loading @@ -671,6 +673,41 @@ public class ApkChecksums { return null; return null; } } /** * Returns fs-verity digest as described in * https://www.kernel.org/doc/html/latest/filesystems/fsverity.html#fs-verity-descriptor * @param file the Merkle tree is built over * @param rootHash Merkle tree root hash */ static byte[] verityHashForFile(File file, byte[] rootHash) { try { ByteBuffer buffer = ByteBuffer.allocate(256); // sizeof(fsverity_descriptor) buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.put((byte) 1); // __u8 version, must be 1 buffer.put((byte) 1); // __u8 hash_algorithm, FS_VERITY_HASH_ALG_SHA256 buffer.put((byte) 12); // __u8, FS_VERITY_LOG_BLOCKSIZE buffer.put((byte) 0); // __u8, size of salt in bytes; 0 if none buffer.putInt(0); // __le32 __reserved_0x04, must be 0 buffer.putLong(file.length()); // __le64 data_size buffer.put(rootHash); // root_hash, first 32 bytes final int padding = 32 + 32 + 144; // root_hash, last 32 bytes, we are using sha256. // salt, 32 bytes // reserved, 144 bytes for (int i = 0; i < padding; ++i) { buffer.put((byte) 0); } buffer.flip(); final MessageDigest md = MessageDigest.getInstance(ALGO_SHA256); md.update(buffer); return md.digest(); } catch (NoSuchAlgorithmException e) { Slog.e(TAG, "Device does not support MessageDigest algorithm", e); return null; } } private static Map<Integer, ApkChecksum> extractHashFromV2V3Signature( private static Map<Integer, ApkChecksum> extractHashFromV2V3Signature( String split, String filePath, int types) { String split, String filePath, int types) { Map<Integer, byte[]> contentDigests = null; Map<Integer, byte[]> contentDigests = null; Loading
services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -1069,7 +1069,7 @@ public class PackageManagerServiceUtils { if (ArrayUtils.isEmpty(hashInfo.rawRootHash)) { if (ArrayUtils.isEmpty(hashInfo.rawRootHash)) { throw new IOException("Root has not present"); throw new IOException("Root has not present"); } } return hashInfo.rawRootHash; return ApkChecksums.verityHashForFile(new File(filename), hashInfo.rawRootHash); } catch (IOException ignore) { } catch (IOException ignore) { Slog.e(TAG, "ERROR: could not load root hash from incremental install"); Slog.e(TAG, "ERROR: could not load root hash from incremental install"); } } Loading