blob: 5bd901d31e708000b14b6d4a582bec1ff2f4a1e4 [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::{
18 get_public_key_der, pick_v4_apk_digest, testing::assert_contains, verify, SignatureAlgorithmID,
19};
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]
Andrew Scull3bae36c2022-09-21 21:55:42 +000043fn test_verify_v3_dsa_sha256() {
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));
Andrew Scull3bae36c2022-09-21 21:55:42 +000046 assert!(res.is_err());
47 assert_contains(&res.unwrap_err().to_string(), "not implemented");
48 }
49}
50
51/// TODO(b/197052981): DSA algorithm is not yet supported.
52#[test]
53fn apks_signed_with_v3_dsa_sha256_have_valid_apk_digest() {
54 for key_name in KEY_NAMES_DSA.iter() {
55 validate_apk_digest(
56 format!("tests/data/v3-only-with-dsa-sha256-{}.apk", key_name),
57 SignatureAlgorithmID::DsaWithSha256,
58 );
Alice Wang676bb4a2022-09-19 14:21:39 +000059 }
60}
61
62#[test]
63fn apks_signed_with_v3_ecdsa_sha256_are_valid() {
Seungjae Yoo91e250a2022-06-07 02:21:56 +000064 for key_name in KEY_NAMES_ECDSA.iter() {
Alice Wang676bb4a2022-09-19 14:21:39 +000065 validate_apk(
66 format!("tests/data/v3-only-with-ecdsa-sha256-{}.apk", key_name),
67 SignatureAlgorithmID::EcdsaWithSha256,
68 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +000069 }
70}
71
Seungjae Yoo91e250a2022-06-07 02:21:56 +000072#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +000073fn apks_signed_with_v3_ecdsa_sha512_are_valid() {
Seungjae Yoo91e250a2022-06-07 02:21:56 +000074 for key_name in KEY_NAMES_ECDSA.iter() {
Alice Wang676bb4a2022-09-19 14:21:39 +000075 validate_apk(
76 format!("tests/data/v3-only-with-ecdsa-sha512-{}.apk", key_name),
77 SignatureAlgorithmID::EcdsaWithSha512,
78 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +000079 }
80}
81
82#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +000083fn apks_signed_with_v3_rsa_pkcs1_sha256_are_valid() {
Seungjae Yoo91e250a2022-06-07 02:21:56 +000084 for key_name in KEY_NAMES_RSA.iter() {
Alice Wang676bb4a2022-09-19 14:21:39 +000085 validate_apk(
86 format!("tests/data/v3-only-with-rsa-pkcs1-sha256-{}.apk", key_name),
87 SignatureAlgorithmID::RsaPkcs1V15WithSha256,
88 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +000089 }
90}
91
92#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +000093fn apks_signed_with_v3_rsa_pkcs1_sha512_are_valid() {
Seungjae Yoo91e250a2022-06-07 02:21:56 +000094 for key_name in KEY_NAMES_RSA.iter() {
Alice Wang676bb4a2022-09-19 14:21:39 +000095 validate_apk(
96 format!("tests/data/v3-only-with-rsa-pkcs1-sha512-{}.apk", key_name),
97 SignatureAlgorithmID::RsaPkcs1V15WithSha512,
98 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +000099 }
100}
101
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000102#[test]
103fn test_verify_v3_sig_does_not_verify() {
104 let path_list = [
Andrew Scull3bae36c2022-09-21 21:55:42 +0000105 "tests/data/v3-only-with-dsa-sha256-2048-sig-does-not-verify.apk",
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000106 "tests/data/v3-only-with-ecdsa-sha512-p521-sig-does-not-verify.apk",
107 "tests/data/v3-only-with-rsa-pkcs1-sha256-3072-sig-does-not-verify.apk",
108 ];
109 for path in path_list.iter() {
110 let res = verify(path);
111 assert!(res.is_err());
112 let error_msg = &res.unwrap_err().to_string();
113 assert!(
Alice Wanga66b5c02022-09-16 07:25:17 +0000114 error_msg.contains("Signature is invalid") || error_msg.contains("not implemented")
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000115 );
116 }
117}
118
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000119#[test]
120fn test_verify_v3_digest_mismatch() {
Andrew Scull3bae36c2022-09-21 21:55:42 +0000121 let path_list = [
122 "tests/data/v3-only-with-dsa-sha256-3072-digest-mismatch.apk",
123 "tests/data/v3-only-with-rsa-pkcs1-sha512-8192-digest-mismatch.apk",
124 ];
125 for path in path_list.iter() {
126 let res = verify(path);
127 assert!(res.is_err());
128 let error_msg = &res.unwrap_err().to_string();
129 assert!(error_msg.contains("Digest mismatch") || error_msg.contains("not implemented"));
130 }
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000131}
132
133#[test]
134fn test_verify_v3_wrong_apk_sig_block_magic() {
135 let res = verify("tests/data/v3-only-with-ecdsa-sha512-p384-wrong-apk-sig-block-magic.apk");
136 assert!(res.is_err());
137 assert_contains(&res.unwrap_err().to_string(), "No APK Signing Block");
138}
139
140#[test]
141fn test_verify_v3_apk_sig_block_size_mismatch() {
142 let res =
143 verify("tests/data/v3-only-with-rsa-pkcs1-sha512-4096-apk-sig-block-size-mismatch.apk");
144 assert!(res.is_err());
145 assert_contains(
146 &res.unwrap_err().to_string(),
147 "APK Signing Block sizes in header and footer do not match",
148 );
149}
150
151#[test]
152fn test_verify_v3_cert_and_public_key_mismatch() {
153 let res = verify("tests/data/v3-only-cert-and-public-key-mismatch.apk");
154 assert!(res.is_err());
155 assert_contains(&res.unwrap_err().to_string(), "Public key mismatch");
156}
157
158#[test]
159fn test_verify_v3_empty() {
160 let res = verify("tests/data/v3-only-empty.apk");
161 assert!(res.is_err());
162 assert_contains(&res.unwrap_err().to_string(), "APK too small for APK Signing Block");
163}
164
165#[test]
166fn test_verify_v3_no_certs_in_sig() {
167 let res = verify("tests/data/v3-only-no-certs-in-sig.apk");
168 assert!(res.is_err());
169 assert_contains(&res.unwrap_err().to_string(), "No certificates listed");
170}
171
172#[test]
173fn test_verify_v3_no_supported_sig_algs() {
174 let res = verify("tests/data/v3-only-no-supported-sig-algs.apk");
175 assert!(res.is_err());
176 assert_contains(&res.unwrap_err().to_string(), "No supported signatures found");
177}
178
179#[test]
180fn test_verify_v3_signatures_and_digests_block_mismatch() {
181 let res = verify("tests/data/v3-only-signatures-and-digests-block-mismatch.apk");
182 assert!(res.is_err());
183 assert_contains(
184 &res.unwrap_err().to_string(),
185 "Signature algorithms don't match between digests and signatures records",
186 );
187}
188
189#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +0000190fn apk_signed_with_v3_unknown_additional_attr_is_valid() {
191 validate_apk(
192 "tests/data/v3-only-unknown-additional-attr.apk",
193 SignatureAlgorithmID::RsaPkcs1V15WithSha256,
194 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000195}
196
197#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +0000198fn apk_signed_with_v3_unknown_pair_in_apk_sig_block_is_valid() {
199 validate_apk(
200 "tests/data/v3-only-unknown-pair-in-apk-sig-block.apk",
201 SignatureAlgorithmID::RsaPkcs1V15WithSha256,
202 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000203}
204
205#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +0000206fn apk_signed_with_v3_ignorable_unsupported_sig_algs_is_valid() {
207 validate_apk(
208 "tests/data/v3-only-with-ignorable-unsupported-sig-algs.apk",
209 SignatureAlgorithmID::RsaPkcs1V15WithSha256,
210 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000211}
212
213#[test]
Alice Wang676bb4a2022-09-19 14:21:39 +0000214fn apk_signed_with_v3_stamp_is_valid() {
215 validate_apk("tests/data/v3-only-with-stamp.apk", SignatureAlgorithmID::EcdsaWithSha256);
Alice Wang67d3c002022-09-16 10:08:25 +0000216}
217
Alice Wang676bb4a2022-09-19 14:21:39 +0000218fn validate_apk<P: AsRef<Path>>(apk_path: P, expected_algorithm_id: SignatureAlgorithmID) {
219 validate_apk_public_key(&apk_path);
220 validate_apk_digest(&apk_path, expected_algorithm_id);
221}
222
223/// Validates that the following public keys are equal:
224/// * public key from verification
225/// * public key extracted from apk without verification
226/// * expected public key from the corresponding .der file
Alice Wang67d3c002022-09-16 10:08:25 +0000227fn validate_apk_public_key<P: AsRef<Path>>(apk_path: P) {
Alice Wang676bb4a2022-09-19 14:21:39 +0000228 let public_key_from_verification = verify(&apk_path);
Alice Wang67d3c002022-09-16 10:08:25 +0000229 let public_key_from_verification =
230 public_key_from_verification.expect("Error in verification result");
231
232 let expected_public_key_path = format!("{}.der", apk_path.as_ref().to_str().unwrap());
Alice Wang676bb4a2022-09-19 14:21:39 +0000233 assert_bytes_eq_to_data_in_file(&public_key_from_verification, expected_public_key_path);
Alice Wang67d3c002022-09-16 10:08:25 +0000234
Alice Wang676bb4a2022-09-19 14:21:39 +0000235 let public_key_from_apk = get_public_key_der(&apk_path);
Alice Wang3c016622022-09-19 09:08:27 +0000236 let public_key_from_apk =
237 public_key_from_apk.expect("Error when extracting public key from apk");
Alice Wang676bb4a2022-09-19 14:21:39 +0000238 assert_eq!(
239 public_key_from_verification, public_key_from_apk,
240 "Public key extracted directly from apk does not match the public key from verification."
241 );
242}
243
244/// Validates that the following apk_digest are equal:
245/// * apk_digest directly extracted from apk without computation
246/// * expected apk digest from the corresponding .apk_digest file
247fn validate_apk_digest<P: AsRef<Path>>(apk_path: P, expected_algorithm_id: SignatureAlgorithmID) {
248 let apk = fs::File::open(&apk_path).expect("Unabled to open apk file");
249
250 let (signature_algorithm_id, digest_from_apk) =
251 pick_v4_apk_digest(apk).expect("Error when extracting apk digest.");
252
253 assert_eq!(expected_algorithm_id, signature_algorithm_id);
254 let expected_digest_path = format!("{}.apk_digest", apk_path.as_ref().to_str().unwrap());
255 assert_bytes_eq_to_data_in_file(&digest_from_apk, expected_digest_path);
256}
257
258fn assert_bytes_eq_to_data_in_file<P: AsRef<Path> + std::fmt::Display>(
259 bytes_data: &[u8],
260 expected_data_path: P,
261) {
262 assert!(
263 fs::metadata(&expected_data_path).is_ok(),
264 "File does not exist. You can re-create it with:\n$ echo -en {} > {}\n",
265 bytes_data.iter().map(|b| format!("\\\\x{:02x}", b)).collect::<String>(),
266 expected_data_path
267 );
268 let expected_data = fs::read(&expected_data_path).unwrap();
269 assert_eq!(
270 expected_data, bytes_data,
271 "Actual data does not match the data from: {}",
272 expected_data_path
273 );
Seungjae Yoo91e250a2022-06-07 02:21:56 +0000274}