blob: fc6bb1c850b4604d9fc9db9c3bdd2e75b852758f [file] [log] [blame]
Alice Wangbf7fadd2023-01-13 12:18:24 +00001/*
2 * Copyright (C) 2022 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
17use anyhow::Result;
Alice Wang58dac082023-01-13 13:03:59 +000018use avb_bindgen::{
19 avb_footer_validate_and_byteswap, avb_vbmeta_image_header_to_host_byte_order, AvbFooter,
20 AvbVBMetaImageHeader,
21};
Alice Wangbf7fadd2023-01-13 12:18:24 +000022use pvmfw_avb::{verify_payload, AvbSlotVerifyError};
Alice Wang58dac082023-01-13 13:03:59 +000023use std::{
24 fs,
25 mem::{size_of, transmute, MaybeUninit},
26};
Alice Wangbf7fadd2023-01-13 12:18:24 +000027
28const MICRODROID_KERNEL_IMG_PATH: &str = "microdroid_kernel";
29const INITRD_NORMAL_IMG_PATH: &str = "microdroid_initrd_normal.img";
Alice Wang4e55dd92023-01-11 10:17:01 +000030const INITRD_DEBUG_IMG_PATH: &str = "microdroid_initrd_debuggable.img";
Alice Wangbf7fadd2023-01-13 12:18:24 +000031const TEST_IMG_WITH_ONE_HASHDESC_PATH: &str = "test_image_with_one_hashdesc.img";
Alice Wang86383df2023-01-11 10:03:56 +000032const TEST_IMG_WITH_PROP_DESC_PATH: &str = "test_image_with_prop_desc.img";
33const TEST_IMG_WITH_NON_INITRD_HASHDESC_PATH: &str = "test_image_with_non_initrd_hashdesc.img";
Alice Wangbf7fadd2023-01-13 12:18:24 +000034const UNSIGNED_TEST_IMG_PATH: &str = "unsigned_test.img";
35
36const PUBLIC_KEY_RSA2048_PATH: &str = "data/testkey_rsa2048_pub.bin";
37const PUBLIC_KEY_RSA4096_PATH: &str = "data/testkey_rsa4096_pub.bin";
38const RANDOM_FOOTER_POS: usize = 30;
39
40/// This test uses the Microdroid payload compiled on the fly to check that
41/// the latest payload can be verified successfully.
42#[test]
Alice Wang4e55dd92023-01-11 10:17:01 +000043fn latest_normal_payload_passes_verification() -> Result<()> {
44 assert_payload_verification_succeeds(
45 &load_latest_signed_kernel()?,
46 &load_latest_initrd_normal()?,
47 &load_trusted_public_key()?,
48 )
49}
Alice Wangbf7fadd2023-01-13 12:18:24 +000050
Alice Wang4e55dd92023-01-11 10:17:01 +000051#[test]
52fn latest_debug_payload_passes_verification() -> Result<()> {
53 assert_payload_verification_succeeds(
54 &load_latest_signed_kernel()?,
55 &load_latest_initrd_debug()?,
56 &load_trusted_public_key()?,
57 )
Alice Wangbf7fadd2023-01-13 12:18:24 +000058}
59
60#[test]
61fn payload_expecting_no_initrd_passes_verification_with_no_initrd() -> Result<()> {
Alice Wang86383df2023-01-11 10:03:56 +000062 assert_payload_verification_with_no_initrd_eq(
63 &fs::read(TEST_IMG_WITH_ONE_HASHDESC_PATH)?,
64 &load_trusted_public_key()?,
65 Ok(()),
66 )
Alice Wangbf7fadd2023-01-13 12:18:24 +000067}
68
Alice Wang86383df2023-01-11 10:03:56 +000069#[test]
70fn payload_with_non_initrd_descriptor_passes_verification_with_no_initrd() -> Result<()> {
71 assert_payload_verification_with_no_initrd_eq(
72 &fs::read(TEST_IMG_WITH_NON_INITRD_HASHDESC_PATH)?,
73 &load_trusted_public_key()?,
74 Ok(()),
75 )
76}
77
78#[test]
79fn payload_with_prop_descriptor_fails_verification_with_no_initrd() -> Result<()> {
80 assert_payload_verification_with_no_initrd_eq(
81 &fs::read(TEST_IMG_WITH_PROP_DESC_PATH)?,
82 &load_trusted_public_key()?,
83 Err(AvbSlotVerifyError::InvalidMetadata),
84 )
85}
86
87#[test]
88fn payload_expecting_initrd_fails_verification_with_no_initrd() -> Result<()> {
89 assert_payload_verification_with_no_initrd_eq(
90 &load_latest_signed_kernel()?,
91 &load_trusted_public_key()?,
92 Err(AvbSlotVerifyError::InvalidMetadata),
93 )
94}
Alice Wangbf7fadd2023-01-13 12:18:24 +000095
96#[test]
97fn payload_with_empty_public_key_fails_verification() -> Result<()> {
98 assert_payload_verification_fails(
99 &load_latest_signed_kernel()?,
100 &load_latest_initrd_normal()?,
101 /*trusted_public_key=*/ &[0u8; 0],
102 AvbSlotVerifyError::PublicKeyRejected,
103 )
104}
105
106#[test]
107fn payload_with_an_invalid_public_key_fails_verification() -> Result<()> {
108 assert_payload_verification_fails(
109 &load_latest_signed_kernel()?,
110 &load_latest_initrd_normal()?,
111 /*trusted_public_key=*/ &[0u8; 512],
112 AvbSlotVerifyError::PublicKeyRejected,
113 )
114}
115
116#[test]
117fn payload_with_a_different_valid_public_key_fails_verification() -> Result<()> {
118 assert_payload_verification_fails(
119 &load_latest_signed_kernel()?,
120 &load_latest_initrd_normal()?,
121 &fs::read(PUBLIC_KEY_RSA2048_PATH)?,
122 AvbSlotVerifyError::PublicKeyRejected,
123 )
124}
125
126#[test]
127fn unsigned_kernel_fails_verification() -> Result<()> {
128 assert_payload_verification_fails(
129 &fs::read(UNSIGNED_TEST_IMG_PATH)?,
130 &load_latest_initrd_normal()?,
Alice Wang4e55dd92023-01-11 10:17:01 +0000131 &load_trusted_public_key()?,
Alice Wangbf7fadd2023-01-13 12:18:24 +0000132 AvbSlotVerifyError::Io,
133 )
134}
135
136#[test]
137fn tampered_kernel_fails_verification() -> Result<()> {
138 let mut kernel = load_latest_signed_kernel()?;
139 kernel[1] = !kernel[1]; // Flip the bits
140
141 assert_payload_verification_fails(
142 &kernel,
143 &load_latest_initrd_normal()?,
Alice Wang4e55dd92023-01-11 10:17:01 +0000144 &load_trusted_public_key()?,
Alice Wangbf7fadd2023-01-13 12:18:24 +0000145 AvbSlotVerifyError::Verification,
146 )
147}
148
149#[test]
150fn tampered_kernel_footer_fails_verification() -> Result<()> {
151 let mut kernel = load_latest_signed_kernel()?;
152 let avb_footer_index = kernel.len() - size_of::<AvbFooter>() + RANDOM_FOOTER_POS;
153 kernel[avb_footer_index] = !kernel[avb_footer_index];
154
155 assert_payload_verification_fails(
156 &kernel,
157 &load_latest_initrd_normal()?,
Alice Wang4e55dd92023-01-11 10:17:01 +0000158 &load_trusted_public_key()?,
Alice Wangbf7fadd2023-01-13 12:18:24 +0000159 AvbSlotVerifyError::InvalidMetadata,
160 )
161}
162
Alice Wang58dac082023-01-13 13:03:59 +0000163#[test]
164fn tampered_vbmeta_fails_verification() -> Result<()> {
165 let mut kernel = load_latest_signed_kernel()?;
166 let footer = extract_avb_footer(&kernel)?;
167 let vbmeta_index: usize = (footer.vbmeta_offset + 1).try_into()?;
168
169 kernel[vbmeta_index] = !kernel[vbmeta_index]; // Flip the bits
170
171 assert_payload_verification_fails(
172 &kernel,
173 &load_latest_initrd_normal()?,
174 &load_trusted_public_key()?,
175 AvbSlotVerifyError::InvalidMetadata,
176 )
177}
178
179#[test]
180fn vbmeta_with_public_key_overwritten_fails_verification() -> Result<()> {
181 let mut kernel = load_latest_signed_kernel()?;
182 let footer = extract_avb_footer(&kernel)?;
183 let vbmeta_header = extract_vbmeta_header(&kernel, &footer)?;
184 let public_key_offset = footer.vbmeta_offset as usize
185 + size_of::<AvbVBMetaImageHeader>()
186 + vbmeta_header.authentication_data_block_size as usize
187 + vbmeta_header.public_key_offset as usize;
188 let public_key_size: usize = vbmeta_header.public_key_size.try_into()?;
189 let empty_public_key = vec![0u8; public_key_size];
190
191 kernel[public_key_offset..(public_key_offset + public_key_size)]
192 .copy_from_slice(&empty_public_key);
193
194 assert_payload_verification_fails(
195 &kernel,
196 &load_latest_initrd_normal()?,
197 &empty_public_key,
198 AvbSlotVerifyError::Verification,
199 )?;
200 assert_payload_verification_fails(
201 &kernel,
202 &load_latest_initrd_normal()?,
203 &load_trusted_public_key()?,
204 AvbSlotVerifyError::Verification,
205 )
206}
207
208// TODO(b/256148034): Test that vbmeta with its verification flag overwritten fails verification.
209
210fn extract_avb_footer(kernel: &[u8]) -> Result<AvbFooter> {
211 let footer_start = kernel.len() - size_of::<AvbFooter>();
212 // SAFETY: The slice is the same size as the struct which only contains simple data types.
213 let mut footer = unsafe {
214 transmute::<[u8; size_of::<AvbFooter>()], AvbFooter>(kernel[footer_start..].try_into()?)
215 };
216 // SAFETY: The function updates the struct in-place.
217 unsafe {
218 avb_footer_validate_and_byteswap(&footer, &mut footer);
219 }
220 Ok(footer)
221}
222
223fn extract_vbmeta_header(kernel: &[u8], footer: &AvbFooter) -> Result<AvbVBMetaImageHeader> {
224 let vbmeta_offset: usize = footer.vbmeta_offset.try_into()?;
225 let vbmeta_size: usize = footer.vbmeta_size.try_into()?;
226 let vbmeta_src = &kernel[vbmeta_offset..(vbmeta_offset + vbmeta_size)];
227 // SAFETY: The latest kernel has a valid VBMeta header at the position specified in footer.
228 let vbmeta_header = unsafe {
229 let mut header = MaybeUninit::uninit();
230 let src = vbmeta_src.as_ptr() as *const _ as *const AvbVBMetaImageHeader;
231 avb_vbmeta_image_header_to_host_byte_order(src, header.as_mut_ptr());
232 header.assume_init()
233 };
234 Ok(vbmeta_header)
235}
236
Alice Wang86383df2023-01-11 10:03:56 +0000237fn assert_payload_verification_with_no_initrd_eq(
238 kernel: &[u8],
239 trusted_public_key: &[u8],
240 expected_result: Result<(), AvbSlotVerifyError>,
241) -> Result<()> {
242 assert_eq!(expected_result, verify_payload(kernel, /*initrd=*/ None, trusted_public_key));
243 Ok(())
244}
245
Alice Wangbf7fadd2023-01-13 12:18:24 +0000246fn assert_payload_verification_fails(
247 kernel: &[u8],
248 initrd: &[u8],
249 trusted_public_key: &[u8],
250 expected_error: AvbSlotVerifyError,
251) -> Result<()> {
252 assert_eq!(Err(expected_error), verify_payload(kernel, Some(initrd), trusted_public_key));
253 Ok(())
254}
255
Alice Wang4e55dd92023-01-11 10:17:01 +0000256fn assert_payload_verification_succeeds(
257 kernel: &[u8],
258 initrd: &[u8],
259 trusted_public_key: &[u8],
260) -> Result<()> {
261 assert_eq!(Ok(()), verify_payload(kernel, Some(initrd), trusted_public_key));
262 Ok(())
263}
264
Alice Wangbf7fadd2023-01-13 12:18:24 +0000265fn load_latest_signed_kernel() -> Result<Vec<u8>> {
266 Ok(fs::read(MICRODROID_KERNEL_IMG_PATH)?)
267}
268
269fn load_latest_initrd_normal() -> Result<Vec<u8>> {
270 Ok(fs::read(INITRD_NORMAL_IMG_PATH)?)
271}
Alice Wang4e55dd92023-01-11 10:17:01 +0000272
273fn load_latest_initrd_debug() -> Result<Vec<u8>> {
274 Ok(fs::read(INITRD_DEBUG_IMG_PATH)?)
275}
276
277fn load_trusted_public_key() -> Result<Vec<u8>> {
278 Ok(fs::read(PUBLIC_KEY_RSA4096_PATH)?)
279}