[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
+ );
}