diff options
| author | 2018-03-08 00:15:18 +0000 | |
|---|---|---|
| committer | 2018-03-08 00:15:18 +0000 | |
| commit | 429a58d18b32a9dcc82a3aa5edc99a519cf80df9 (patch) | |
| tree | 1caf14ac49382ab9eb8f2729e5ebc15d5f921280 | |
| parent | a1aa6abe36251827620130477b1b6faec4be33c0 (diff) | |
| parent | 4ba1eeaa0e0468131da08a5c5f461361cac79ff1 (diff) | |
Merge "Verify the content length in the verity digest" into pi-dev
3 files changed, 46 insertions, 7 deletions
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java index 62222b5764e7..533d72590f0a 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java @@ -213,7 +213,9 @@ public class ApkSignatureSchemeV2Verifier { byte[] verityRootHash = null; if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) { - verityRootHash = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256); + byte[] verityDigest = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256); + verityRootHash = ApkSigningBlockUtils.parseVerityDigestAndVerifySourceLength( + verityDigest, apk.length(), signatureInfo); } return new VerifiedSigner( diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java index 9436b296e9e2..4431bcef1ff4 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java @@ -165,7 +165,7 @@ public class ApkSignatureSchemeV3Verifier { private static VerifiedSigner verify( RandomAccessFile apk, SignatureInfo signatureInfo, - boolean doVerifyIntegrity) throws SecurityException { + boolean doVerifyIntegrity) throws SecurityException, IOException { int signerCount = 0; Map<Integer, byte[]> contentDigests = new ArrayMap<>(); VerifiedSigner result = null; @@ -214,7 +214,9 @@ public class ApkSignatureSchemeV3Verifier { } if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) { - result.verityRootHash = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256); + byte[] verityDigest = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256); + result.verityRootHash = ApkSigningBlockUtils.parseVerityDigestAndVerifySourceLength( + verityDigest, apk.length(), signatureInfo); } return result; diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java index 40db758e1d4b..1c67434b2609 100644 --- a/core/java/android/util/apk/ApkSigningBlockUtils.java +++ b/core/java/android/util/apk/ApkSigningBlockUtils.java @@ -285,11 +285,46 @@ final class ApkSigningBlockUtils { return result; } + /** + * Return the verity digest only if the length of digest content looks correct. + * When verity digest is generated, the last incomplete 4k chunk is padded with 0s before + * hashing. This means two almost identical APKs with different number of 0 at the end will have + * the same verity digest. To avoid this problem, the length of the source content (excluding + * Signing Block) is appended to the verity digest, and the digest is returned only if the + * length is consistent to the current APK. + */ + static byte[] parseVerityDigestAndVerifySourceLength( + byte[] data, long fileSize, SignatureInfo signatureInfo) throws SecurityException { + // FORMAT: + // OFFSET DATA TYPE DESCRIPTION + // * @+0 bytes uint8[32] Merkle tree root hash of SHA-256 + // * @+32 bytes int64 Length of source data + int kRootHashSize = 32; + int kSourceLengthSize = 8; + + if (data.length != kRootHashSize + kSourceLengthSize) { + throw new SecurityException("Verity digest size is wrong: " + data.length); + } + ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN); + buffer.position(kRootHashSize); + long expectedSourceLength = buffer.getLong(); + + long signingBlockSize = signatureInfo.centralDirOffset + - signatureInfo.apkSigningBlockOffset; + if (expectedSourceLength != fileSize - signingBlockSize) { + throw new SecurityException("APK content size did not verify"); + } + + return Arrays.copyOfRange(data, 0, kRootHashSize); + } + private static void verifyIntegrityForVerityBasedAlgorithm( - byte[] expectedRootHash, + byte[] expectedDigest, RandomAccessFile apk, SignatureInfo signatureInfo) throws SecurityException { try { + byte[] expectedRootHash = parseVerityDigestAndVerifySourceLength(expectedDigest, + apk.length(), signatureInfo); ApkVerityBuilder.ApkVerityResult verity = ApkVerityBuilder.generateApkVerity(apk, signatureInfo, new ByteBufferFactory() { @Override @@ -373,9 +408,9 @@ final class ApkSigningBlockUtils { static final int SIGNATURE_ECDSA_WITH_SHA256 = 0x0201; static final int SIGNATURE_ECDSA_WITH_SHA512 = 0x0202; static final int SIGNATURE_DSA_WITH_SHA256 = 0x0301; - static final int SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0411; - static final int SIGNATURE_VERITY_ECDSA_WITH_SHA256 = 0x0413; - static final int SIGNATURE_VERITY_DSA_WITH_SHA256 = 0x0415; + static final int SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0421; + static final int SIGNATURE_VERITY_ECDSA_WITH_SHA256 = 0x0423; + static final int SIGNATURE_VERITY_DSA_WITH_SHA256 = 0x0425; static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1; static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2; |