apkverify: verify content digest

Bug: 190343842
Test: MicrodroidHostTestCases
Change-Id: I370aaf6bf88e7267f5a03b7a2da32c87d49552db
diff --git a/apkverify/src/v3.rs b/apkverify/src/v3.rs
index 91043ab..0ef035c 100644
--- a/apkverify/src/v3.rs
+++ b/apkverify/src/v3.rs
@@ -22,6 +22,7 @@
 use anyhow::{anyhow, bail, Result};
 use bytes::Bytes;
 use std::fs::File;
+use std::io::{Read, Seek};
 use std::ops::Range;
 use std::path::Path;
 
@@ -85,16 +86,18 @@
 /// associated with each signer.
 pub fn verify<P: AsRef<Path>>(path: P) -> Result<()> {
     let f = File::open(path.as_ref())?;
-    let signature = find_signature(f, APK_SIGNATURE_SCHEME_V3_BLOCK_ID)?;
-    verify_signature(&signature.signature_block)?;
+    let mut sections = ApkSections::new(f)?;
+    verify_signature(&mut sections)?;
     Ok(())
 }
 
 /// Verifies the contents of the provided APK file against the provided APK Signature Scheme v3
 /// Block.
-fn verify_signature(block: &Bytes) -> Result<()> {
+fn verify_signature<R: Read + Seek>(sections: &mut ApkSections<R>) -> Result<()> {
+    let mut block = sections.find_signature(APK_SIGNATURE_SCHEME_V3_BLOCK_ID)?;
+
     // parse v3 scheme block
-    let signers = block.slice(..).read::<Signers>()?;
+    let signers = block.read::<Signers>()?;
 
     // find supported by platform
     let mut supported =
@@ -106,13 +109,13 @@
     }
 
     // and it should be verified
-    supported.pop().unwrap().verify()?;
+    supported.pop().unwrap().verify(sections)?;
 
     Ok(())
 }
 
 impl Signer {
-    fn verify(&self) -> Result<()> {
+    fn verify<R: Read + Seek>(&self, sections: &mut ApkSections<R>) -> Result<()> {
         // 1. Choose the strongest supported signature algorithm ID from signatures. The strength
         //    ordering is up to each implementation/platform version.
         let strongest: &Signature = self
@@ -134,9 +137,36 @@
         if self.sdk_range() != signed_data.sdk_range() {
             bail!("SDK versions mismatch between signed and unsigned in v3 signer block.");
         }
-        // TODO(jooyung) 4. Verify that the ordered list of signature algorithm IDs in digests and signatures is identical. (This is to prevent signature stripping/addition.)
-        // TODO(jooyung) 5. Compute the digest of APK contents using the same digest algorithm as the digest algorithm used by the signature algorithm.
-        // TODO(jooyung) 6. Verify that the computed digest is identical to the corresponding digest from digests.
+
+        // 4. Verify that the ordered list of signature algorithm IDs in digests and signatures is
+        //    identical. (This is to prevent signature stripping/addition.)
+        if !self
+            .signatures
+            .iter()
+            .map(|sig| sig.signature_algorithm_id)
+            .eq(signed_data.digests.iter().map(|dig| dig.signature_algorithm_id))
+        {
+            bail!("Signature algorithms don't match between digests and signatures records");
+        }
+
+        // 5. Compute the digest of APK contents using the same digest algorithm as the digest
+        //    algorithm used by the signature algorithm.
+        let digest = signed_data
+            .digests
+            .iter()
+            .find(|&dig| dig.signature_algorithm_id == strongest.signature_algorithm_id)
+            .unwrap(); // ok to unwrap since we check if two lists are the same above
+        let computed = sections.compute_digest(digest.signature_algorithm_id)?;
+
+        // 6. Verify that the computed digest is identical to the corresponding digest from digests.
+        if computed != digest.digest.as_ref() {
+            bail!(
+                "digest mismatch: computed={:?} vs expected={:?}",
+                to_hex_string(&computed),
+                to_hex_string(&digest.digest),
+            );
+        }
+
         // TODO(jooyung) 7. Verify that SubjectPublicKeyInfo of the first certificate of certificates is identical to public key.
         // TODO(jooyung) 8. If the proof-of-rotation attribute exists for the signer verify that the struct is valid and this signer is the last certificate in the list.
         Ok(())
@@ -215,3 +245,8 @@
         Ok(Self { signature_algorithm_id: buf.read()?, digest: buf.read()? })
     }
 }
+
+#[inline]
+fn to_hex_string(buf: &[u8]) -> String {
+    buf.iter().map(|b| format!("{:02X}", b)).collect()
+}