blob: baf7c4216552c2813a345634f68d818dd4a61bd3 [file] [log] [blame]
Jooyung Han12a0b702021-08-05 23:20:31 +09001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Alice Wang676bb4a2022-09-19 14:21:39 +000017use apkverify::{
Alice Wang0cafa142022-09-23 15:17:02 +000018 get_apk_digest, get_public_key_der, testing::assert_contains, verify, SignatureAlgorithmID,
Alice Wang676bb4a2022-09-19 14:21:39 +000019};
Alice Wang67d3c002022-09-16 10:08:25 +000020use std::{fs, matches, path::Path};
Jooyung Hand8397852021-08-10 16:29:36 +090021
Seungjae Yoo91e250a2022-06-07 02:21:56 +000022const KEY_NAMES_DSA: &[&str] = &["1024", "2048", "3072"];
23const KEY_NAMES_ECDSA: &[&str] = &["p256", "p384", "p521"];
24const KEY_NAMES_RSA: &[&str] = &["1024", "2048", "3072", "4096", "8192", "16384"];
Jooyung Hancee6de62021-08-11 15:52:07 +090025
26#[test]
27fn test_verify_truncated_cd() {
28 use zip::result::ZipError;
29 let res = verify("tests/data/v2-only-truncated-cd.apk");
Alice Wang92889352022-09-16 10:42:52 +000030 // TODO(b/190343842): consider making a helper for err assertion
Jooyung Hancee6de62021-08-11 15:52:07 +090031 assert!(matches!(
Andrew Walbran117cd5e2021-08-13 11:42:13 +000032 res.unwrap_err().root_cause().downcast_ref::<ZipError>().unwrap(),
Jooyung Hancee6de62021-08-11 15:52:07 +090033 ZipError::InvalidArchive(_),
34 ));
35}
Seungjae Yoo91e250a2022-06-07 02:21:56 +000036
37#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +000038fn apex_signed_with_v3_rsa_pkcs1_sha512_is_valid() {
39 validate_apk("tests/data/test.apex", SignatureAlgorithmID::RsaPkcs1V15WithSha512);
Seungjae Yoo91e250a2022-06-07 02:21:56 +000040}
41
Seungjae Yoo91e250a2022-06-07 02:21:56 +000042#[test]
Alice Wang50701022022-09-21 08:51:38 +000043fn apks_signed_with_v3_dsa_sha256_are_not_supported() {
Seungjae Yoo91e250a2022-06-07 02:21:56 +000044 for key_name in KEY_NAMES_DSA.iter() {
45 let res = verify(format!("tests/data/v3-only-with-dsa-sha256-{}.apk", key_name));
Alice Wang50701022022-09-21 08:51:38 +000046 assert!(res.is_err(), "DSA algorithm is not supported for verification. See b/197052981.");
Alan Stokesa6876992023-01-20 12:26:25 +000047 assert_contains(&res.unwrap_err().to_string(), "No supported APK signatures found");
Alice Wang676bb4a2022-09-19 14:21:39 +000048 }
49}
50
51#[test]
52fn apks_signed_with_v3_ecdsa_sha256_are_valid() {
Seungjae Yoo91e250a2022-06-07 02:21:56 +000053 for key_name in KEY_NAMES_ECDSA.iter() {
Alice Wang676bb4a2022-09-19 14:21:39 +000054 validate_apk(
55 format!("tests/data/v3-only-with-ecdsa-sha256-{}.apk", key_name),
56 SignatureAlgorithmID::EcdsaWithSha256,
57 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +000058 }
59}
60
Seungjae Yoo91e250a2022-06-07 02:21:56 +000061#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +000062fn apks_signed_with_v3_ecdsa_sha512_are_valid() {
Seungjae Yoo91e250a2022-06-07 02:21:56 +000063 for key_name in KEY_NAMES_ECDSA.iter() {
Alice Wang676bb4a2022-09-19 14:21:39 +000064 validate_apk(
65 format!("tests/data/v3-only-with-ecdsa-sha512-{}.apk", key_name),
66 SignatureAlgorithmID::EcdsaWithSha512,
67 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +000068 }
69}
70
71#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +000072fn apks_signed_with_v3_rsa_pkcs1_sha256_are_valid() {
Seungjae Yoo91e250a2022-06-07 02:21:56 +000073 for key_name in KEY_NAMES_RSA.iter() {
Alice Wang676bb4a2022-09-19 14:21:39 +000074 validate_apk(
75 format!("tests/data/v3-only-with-rsa-pkcs1-sha256-{}.apk", key_name),
76 SignatureAlgorithmID::RsaPkcs1V15WithSha256,
77 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +000078 }
79}
80
81#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +000082fn apks_signed_with_v3_rsa_pkcs1_sha512_are_valid() {
Seungjae Yoo91e250a2022-06-07 02:21:56 +000083 for key_name in KEY_NAMES_RSA.iter() {
Alice Wang676bb4a2022-09-19 14:21:39 +000084 validate_apk(
85 format!("tests/data/v3-only-with-rsa-pkcs1-sha512-{}.apk", key_name),
86 SignatureAlgorithmID::RsaPkcs1V15WithSha512,
87 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +000088 }
89}
90
Seungjae Yoo91e250a2022-06-07 02:21:56 +000091#[test]
92fn test_verify_v3_sig_does_not_verify() {
93 let path_list = [
Seungjae Yoo91e250a2022-06-07 02:21:56 +000094 "tests/data/v3-only-with-ecdsa-sha512-p521-sig-does-not-verify.apk",
95 "tests/data/v3-only-with-rsa-pkcs1-sha256-3072-sig-does-not-verify.apk",
96 ];
97 for path in path_list.iter() {
98 let res = verify(path);
99 assert!(res.is_err());
Alice Wang50701022022-09-21 08:51:38 +0000100 assert_contains(&res.unwrap_err().to_string(), "Signature is invalid");
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000101 }
102}
103
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000104#[test]
105fn test_verify_v3_digest_mismatch() {
Alice Wang50701022022-09-21 08:51:38 +0000106 let res = verify("tests/data/v3-only-with-rsa-pkcs1-sha512-8192-digest-mismatch.apk");
107 assert!(res.is_err());
108 assert_contains(&res.unwrap_err().to_string(), "Digest mismatch");
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000109}
110
111#[test]
112fn test_verify_v3_wrong_apk_sig_block_magic() {
113 let res = verify("tests/data/v3-only-with-ecdsa-sha512-p384-wrong-apk-sig-block-magic.apk");
114 assert!(res.is_err());
115 assert_contains(&res.unwrap_err().to_string(), "No APK Signing Block");
116}
117
118#[test]
119fn test_verify_v3_apk_sig_block_size_mismatch() {
120 let res =
121 verify("tests/data/v3-only-with-rsa-pkcs1-sha512-4096-apk-sig-block-size-mismatch.apk");
122 assert!(res.is_err());
123 assert_contains(
124 &res.unwrap_err().to_string(),
125 "APK Signing Block sizes in header and footer do not match",
126 );
127}
128
129#[test]
130fn test_verify_v3_cert_and_public_key_mismatch() {
131 let res = verify("tests/data/v3-only-cert-and-public-key-mismatch.apk");
132 assert!(res.is_err());
133 assert_contains(&res.unwrap_err().to_string(), "Public key mismatch");
134}
135
136#[test]
137fn test_verify_v3_empty() {
138 let res = verify("tests/data/v3-only-empty.apk");
139 assert!(res.is_err());
140 assert_contains(&res.unwrap_err().to_string(), "APK too small for APK Signing Block");
141}
142
143#[test]
144fn test_verify_v3_no_certs_in_sig() {
145 let res = verify("tests/data/v3-only-no-certs-in-sig.apk");
146 assert!(res.is_err());
147 assert_contains(&res.unwrap_err().to_string(), "No certificates listed");
148}
149
150#[test]
151fn test_verify_v3_no_supported_sig_algs() {
152 let res = verify("tests/data/v3-only-no-supported-sig-algs.apk");
153 assert!(res.is_err());
Alan Stokesa6876992023-01-20 12:26:25 +0000154 assert_contains(&res.unwrap_err().to_string(), "No supported APK signatures found");
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000155}
156
157#[test]
158fn test_verify_v3_signatures_and_digests_block_mismatch() {
159 let res = verify("tests/data/v3-only-signatures-and-digests-block-mismatch.apk");
160 assert!(res.is_err());
161 assert_contains(
162 &res.unwrap_err().to_string(),
163 "Signature algorithms don't match between digests and signatures records",
164 );
165}
166
167#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +0000168fn apk_signed_with_v3_unknown_additional_attr_is_valid() {
169 validate_apk(
170 "tests/data/v3-only-unknown-additional-attr.apk",
171 SignatureAlgorithmID::RsaPkcs1V15WithSha256,
172 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000173}
174
175#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +0000176fn apk_signed_with_v3_unknown_pair_in_apk_sig_block_is_valid() {
177 validate_apk(
178 "tests/data/v3-only-unknown-pair-in-apk-sig-block.apk",
179 SignatureAlgorithmID::RsaPkcs1V15WithSha256,
180 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000181}
182
183#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +0000184fn apk_signed_with_v3_ignorable_unsupported_sig_algs_is_valid() {
185 validate_apk(
186 "tests/data/v3-only-with-ignorable-unsupported-sig-algs.apk",
187 SignatureAlgorithmID::RsaPkcs1V15WithSha256,
188 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000189}
190
191#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +0000192fn apk_signed_with_v3_stamp_is_valid() {
193 validate_apk("tests/data/v3-only-with-stamp.apk", SignatureAlgorithmID::EcdsaWithSha256);
Alice Wang67d3c002022-09-16 10:08:25 +0000194}
195
Alice Wang676bb4a2022-09-19 14:21:39 +0000196fn validate_apk<P: AsRef<Path>>(apk_path: P, expected_algorithm_id: SignatureAlgorithmID) {
197 validate_apk_public_key(&apk_path);
198 validate_apk_digest(&apk_path, expected_algorithm_id);
199}
200
201/// Validates that the following public keys are equal:
202/// * public key from verification
203/// * public key extracted from apk without verification
204/// * expected public key from the corresponding .der file
Alice Wang67d3c002022-09-16 10:08:25 +0000205fn validate_apk_public_key<P: AsRef<Path>>(apk_path: P) {
Alice Wang676bb4a2022-09-19 14:21:39 +0000206 let public_key_from_verification = verify(&apk_path);
Alice Wang67d3c002022-09-16 10:08:25 +0000207 let public_key_from_verification =
208 public_key_from_verification.expect("Error in verification result");
209
210 let expected_public_key_path = format!("{}.der", apk_path.as_ref().to_str().unwrap());
Alice Wang676bb4a2022-09-19 14:21:39 +0000211 assert_bytes_eq_to_data_in_file(&public_key_from_verification, expected_public_key_path);
Alice Wang67d3c002022-09-16 10:08:25 +0000212
Alice Wang676bb4a2022-09-19 14:21:39 +0000213 let public_key_from_apk = get_public_key_der(&apk_path);
Alice Wang3c016622022-09-19 09:08:27 +0000214 let public_key_from_apk =
215 public_key_from_apk.expect("Error when extracting public key from apk");
Alice Wang676bb4a2022-09-19 14:21:39 +0000216 assert_eq!(
217 public_key_from_verification, public_key_from_apk,
218 "Public key extracted directly from apk does not match the public key from verification."
219 );
220}
221
222/// Validates that the following apk_digest are equal:
223/// * apk_digest directly extracted from apk without computation
Alice Wang0cafa142022-09-23 15:17:02 +0000224/// * computed apk_digest
Alice Wang676bb4a2022-09-19 14:21:39 +0000225/// * expected apk digest from the corresponding .apk_digest file
226fn validate_apk_digest<P: AsRef<Path>>(apk_path: P, expected_algorithm_id: SignatureAlgorithmID) {
227 let apk = fs::File::open(&apk_path).expect("Unabled to open apk file");
228
Alice Wang0cafa142022-09-23 15:17:02 +0000229 let (verified_algorithm_id, verified_digest) = get_apk_digest(&apk, /*verify=*/ true)
230 .expect("Error when extracting apk digest with verification.");
Alice Wang676bb4a2022-09-19 14:21:39 +0000231
Alice Wang0cafa142022-09-23 15:17:02 +0000232 assert_eq!(expected_algorithm_id, verified_algorithm_id);
Alice Wang676bb4a2022-09-19 14:21:39 +0000233 let expected_digest_path = format!("{}.apk_digest", apk_path.as_ref().to_str().unwrap());
Alice Wang0cafa142022-09-23 15:17:02 +0000234 assert_bytes_eq_to_data_in_file(&verified_digest, expected_digest_path);
235
236 let (unverified_algorithm_id, unverified_digest) = get_apk_digest(&apk, /*verify=*/ false)
237 .expect("Error when extracting apk digest without verification.");
238 assert_eq!(expected_algorithm_id, unverified_algorithm_id);
239 assert_eq!(verified_digest, unverified_digest);
Alice Wang676bb4a2022-09-19 14:21:39 +0000240}
241
242fn assert_bytes_eq_to_data_in_file<P: AsRef<Path> + std::fmt::Display>(
243 bytes_data: &[u8],
244 expected_data_path: P,
245) {
246 assert!(
247 fs::metadata(&expected_data_path).is_ok(),
248 "File does not exist. You can re-create it with:\n$ echo -en {} > {}\n",
249 bytes_data.iter().map(|b| format!("\\\\x{:02x}", b)).collect::<String>(),
250 expected_data_path
251 );
252 let expected_data = fs::read(&expected_data_path).unwrap();
253 assert_eq!(
254 expected_data, bytes_data,
255 "Actual data does not match the data from: {}",
256 expected_data_path
257 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000258}