[apk_digest][test] Check v4 apk_digest is valid

This CL checks that the v4 apk_digest is valid for apks signed
with different v3 signature algorithms.

Bug: 247689066
Bug: 246254355
Test: libapkverify.integration_test
Change-Id: I9fdb3d547755e050bd241b0be1431b827da7ed5f
diff --git a/libs/apkverify/tests/apkverify_test.rs b/libs/apkverify/tests/apkverify_test.rs
index 03cb4bb..5bd901d 100644
--- a/libs/apkverify/tests/apkverify_test.rs
+++ b/libs/apkverify/tests/apkverify_test.rs
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-use apkverify::{get_public_key_der, testing::assert_contains, verify};
+use apkverify::{
+    get_public_key_der, pick_v4_apk_digest, testing::assert_contains, verify, SignatureAlgorithmID,
+};
 use std::{fs, matches, path::Path};
 
 const KEY_NAMES_DSA: &[&str] = &["1024", "2048", "3072"];
@@ -33,8 +35,8 @@
 }
 
 #[test]
-fn test_verify_v3() {
-    validate_apk_public_key("tests/data/test.apex");
+fn apex_signed_with_v3_rsa_pkcs1_sha512_is_valid() {
+    validate_apk("tests/data/test.apex", SignatureAlgorithmID::RsaPkcs1V15WithSha512);
 }
 
 #[test]
@@ -46,37 +48,54 @@
     }
 }
 
+/// TODO(b/197052981): DSA algorithm is not yet supported.
 #[test]
-fn test_verify_v3_ecdsa_sha256() {
+fn apks_signed_with_v3_dsa_sha256_have_valid_apk_digest() {
+    for key_name in KEY_NAMES_DSA.iter() {
+        validate_apk_digest(
+            format!("tests/data/v3-only-with-dsa-sha256-{}.apk", key_name),
+            SignatureAlgorithmID::DsaWithSha256,
+        );
+    }
+}
+
+#[test]
+fn apks_signed_with_v3_ecdsa_sha256_are_valid() {
     for key_name in KEY_NAMES_ECDSA.iter() {
-        validate_apk_public_key(format!("tests/data/v3-only-with-ecdsa-sha256-{}.apk", key_name));
+        validate_apk(
+            format!("tests/data/v3-only-with-ecdsa-sha256-{}.apk", key_name),
+            SignatureAlgorithmID::EcdsaWithSha256,
+        );
     }
 }
 
 #[test]
-fn test_verify_v3_ecdsa_sha512() {
+fn apks_signed_with_v3_ecdsa_sha512_are_valid() {
     for key_name in KEY_NAMES_ECDSA.iter() {
-        validate_apk_public_key(format!("tests/data/v3-only-with-ecdsa-sha512-{}.apk", key_name));
+        validate_apk(
+            format!("tests/data/v3-only-with-ecdsa-sha512-{}.apk", key_name),
+            SignatureAlgorithmID::EcdsaWithSha512,
+        );
     }
 }
 
 #[test]
-fn test_verify_v3_rsa_sha256() {
+fn apks_signed_with_v3_rsa_pkcs1_sha256_are_valid() {
     for key_name in KEY_NAMES_RSA.iter() {
-        validate_apk_public_key(format!(
-            "tests/data/v3-only-with-rsa-pkcs1-sha256-{}.apk",
-            key_name
-        ));
+        validate_apk(
+            format!("tests/data/v3-only-with-rsa-pkcs1-sha256-{}.apk", key_name),
+            SignatureAlgorithmID::RsaPkcs1V15WithSha256,
+        );
     }
 }
 
 #[test]
-fn test_verify_v3_rsa_sha512() {
+fn apks_signed_with_v3_rsa_pkcs1_sha512_are_valid() {
     for key_name in KEY_NAMES_RSA.iter() {
-        validate_apk_public_key(format!(
-            "tests/data/v3-only-with-rsa-pkcs1-sha512-{}.apk",
-            key_name
-        ));
+        validate_apk(
+            format!("tests/data/v3-only-with-rsa-pkcs1-sha512-{}.apk", key_name),
+            SignatureAlgorithmID::RsaPkcs1V15WithSha512,
+        );
     }
 }
 
@@ -168,50 +187,88 @@
 }
 
 #[test]
-fn test_verify_v3_unknown_additional_attr() {
-    validate_apk_public_key("tests/data/v3-only-unknown-additional-attr.apk");
+fn apk_signed_with_v3_unknown_additional_attr_is_valid() {
+    validate_apk(
+        "tests/data/v3-only-unknown-additional-attr.apk",
+        SignatureAlgorithmID::RsaPkcs1V15WithSha256,
+    );
 }
 
 #[test]
-fn test_verify_v3_unknown_pair_in_apk_sig_block() {
-    validate_apk_public_key("tests/data/v3-only-unknown-pair-in-apk-sig-block.apk");
+fn apk_signed_with_v3_unknown_pair_in_apk_sig_block_is_valid() {
+    validate_apk(
+        "tests/data/v3-only-unknown-pair-in-apk-sig-block.apk",
+        SignatureAlgorithmID::RsaPkcs1V15WithSha256,
+    );
 }
 
 #[test]
-fn test_verify_v3_ignorable_unsupported_sig_algs() {
-    validate_apk_public_key("tests/data/v3-only-with-ignorable-unsupported-sig-algs.apk");
+fn apk_signed_with_v3_ignorable_unsupported_sig_algs_is_valid() {
+    validate_apk(
+        "tests/data/v3-only-with-ignorable-unsupported-sig-algs.apk",
+        SignatureAlgorithmID::RsaPkcs1V15WithSha256,
+    );
 }
 
 #[test]
-fn test_verify_v3_stamp() {
-    validate_apk_public_key("tests/data/v3-only-with-stamp.apk");
+fn apk_signed_with_v3_stamp_is_valid() {
+    validate_apk("tests/data/v3-only-with-stamp.apk", SignatureAlgorithmID::EcdsaWithSha256);
 }
 
+fn validate_apk<P: AsRef<Path>>(apk_path: P, expected_algorithm_id: SignatureAlgorithmID) {
+    validate_apk_public_key(&apk_path);
+    validate_apk_digest(&apk_path, expected_algorithm_id);
+}
+
+/// Validates that the following public keys are equal:
+/// * public key from verification
+/// * public key extracted from apk without verification
+/// * expected public key from the corresponding .der file
 fn validate_apk_public_key<P: AsRef<Path>>(apk_path: P) {
-    // Validates public key from verification == expected public key.
-    let public_key_from_verification = verify(apk_path.as_ref());
+    let public_key_from_verification = verify(&apk_path);
     let public_key_from_verification =
         public_key_from_verification.expect("Error in verification result");
 
     let expected_public_key_path = format!("{}.der", apk_path.as_ref().to_str().unwrap());
-    assert!(
-        fs::metadata(&expected_public_key_path).is_ok(),
-        "File does not exist. You can re-create it with:\n$ echo -en {} > {}\n",
-        public_key_from_verification.iter().map(|b| format!("\\\\x{:02x}", b)).collect::<String>(),
-        expected_public_key_path
-    );
-    let expected_public_key = fs::read(&expected_public_key_path).unwrap();
-    assert_eq!(
-        expected_public_key,
-        public_key_from_verification.as_ref(),
-        "{}",
-        expected_public_key_path
-    );
+    assert_bytes_eq_to_data_in_file(&public_key_from_verification, expected_public_key_path);
 
-    // Validates public key extracted directly from apk
-    // (without verification) == expected public key.
-    let public_key_from_apk = get_public_key_der(apk_path.as_ref());
+    let public_key_from_apk = get_public_key_der(&apk_path);
     let public_key_from_apk =
         public_key_from_apk.expect("Error when extracting public key from apk");
-    assert_eq!(expected_public_key, public_key_from_apk.as_ref(), "{}", expected_public_key_path);
+    assert_eq!(
+        public_key_from_verification, public_key_from_apk,
+        "Public key extracted directly from apk does not match the public key from verification."
+    );
+}
+
+/// Validates that the following apk_digest are equal:
+/// * apk_digest directly extracted from apk without computation
+/// * expected apk digest from the corresponding .apk_digest file
+fn validate_apk_digest<P: AsRef<Path>>(apk_path: P, expected_algorithm_id: SignatureAlgorithmID) {
+    let apk = fs::File::open(&apk_path).expect("Unabled to open apk file");
+
+    let (signature_algorithm_id, digest_from_apk) =
+        pick_v4_apk_digest(apk).expect("Error when extracting apk digest.");
+
+    assert_eq!(expected_algorithm_id, signature_algorithm_id);
+    let expected_digest_path = format!("{}.apk_digest", apk_path.as_ref().to_str().unwrap());
+    assert_bytes_eq_to_data_in_file(&digest_from_apk, expected_digest_path);
+}
+
+fn assert_bytes_eq_to_data_in_file<P: AsRef<Path> + std::fmt::Display>(
+    bytes_data: &[u8],
+    expected_data_path: P,
+) {
+    assert!(
+        fs::metadata(&expected_data_path).is_ok(),
+        "File does not exist. You can re-create it with:\n$ echo -en {} > {}\n",
+        bytes_data.iter().map(|b| format!("\\\\x{:02x}", b)).collect::<String>(),
+        expected_data_path
+    );
+    let expected_data = fs::read(&expected_data_path).unwrap();
+    assert_eq!(
+        expected_data, bytes_data,
+        "Actual data does not match the data from: {}",
+        expected_data_path
+    );
 }