Merge "Verify the content length in the verity digest" into pi-dev

This commit is contained in:
TreeHugger Robot
2018-03-08 00:15:18 +00:00
committed by Android (Google) Code Review
3 changed files with 46 additions and 7 deletions

View File

@@ -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(

View File

@@ -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;

View File

@@ -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;