blob: 872ad631cfb0075739250ab117fdb16ed56d7cb3 [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},
Alice Wangf06bfd72023-01-19 09:24:21 +000026 ptr,
Alice Wang58dac082023-01-13 13:03:59 +000027};
Alice Wangbf7fadd2023-01-13 12:18:24 +000028
29const MICRODROID_KERNEL_IMG_PATH: &str = "microdroid_kernel";
30const INITRD_NORMAL_IMG_PATH: &str = "microdroid_initrd_normal.img";
Alice Wang4e55dd92023-01-11 10:17:01 +000031const INITRD_DEBUG_IMG_PATH: &str = "microdroid_initrd_debuggable.img";
Alice Wangbf7fadd2023-01-13 12:18:24 +000032const TEST_IMG_WITH_ONE_HASHDESC_PATH: &str = "test_image_with_one_hashdesc.img";
Alice Wang86383df2023-01-11 10:03:56 +000033const TEST_IMG_WITH_PROP_DESC_PATH: &str = "test_image_with_prop_desc.img";
34const TEST_IMG_WITH_NON_INITRD_HASHDESC_PATH: &str = "test_image_with_non_initrd_hashdesc.img";
Alice Wangbf7fadd2023-01-13 12:18:24 +000035const UNSIGNED_TEST_IMG_PATH: &str = "unsigned_test.img";
36
37const PUBLIC_KEY_RSA2048_PATH: &str = "data/testkey_rsa2048_pub.bin";
38const PUBLIC_KEY_RSA4096_PATH: &str = "data/testkey_rsa4096_pub.bin";
39const RANDOM_FOOTER_POS: usize = 30;
40
41/// This test uses the Microdroid payload compiled on the fly to check that
42/// the latest payload can be verified successfully.
43#[test]
Alice Wang4e55dd92023-01-11 10:17:01 +000044fn latest_normal_payload_passes_verification() -> Result<()> {
45 assert_payload_verification_succeeds(
46 &load_latest_signed_kernel()?,
47 &load_latest_initrd_normal()?,
48 &load_trusted_public_key()?,
49 )
50}
Alice Wangbf7fadd2023-01-13 12:18:24 +000051
Alice Wang4e55dd92023-01-11 10:17:01 +000052#[test]
53fn latest_debug_payload_passes_verification() -> Result<()> {
54 assert_payload_verification_succeeds(
55 &load_latest_signed_kernel()?,
56 &load_latest_initrd_debug()?,
57 &load_trusted_public_key()?,
58 )
Alice Wangbf7fadd2023-01-13 12:18:24 +000059}
60
61#[test]
62fn payload_expecting_no_initrd_passes_verification_with_no_initrd() -> Result<()> {
Alice Wang86383df2023-01-11 10:03:56 +000063 assert_payload_verification_with_no_initrd_eq(
64 &fs::read(TEST_IMG_WITH_ONE_HASHDESC_PATH)?,
65 &load_trusted_public_key()?,
66 Ok(()),
67 )
Alice Wangbf7fadd2023-01-13 12:18:24 +000068}
69
Alice Wang86383df2023-01-11 10:03:56 +000070#[test]
71fn payload_with_non_initrd_descriptor_passes_verification_with_no_initrd() -> Result<()> {
72 assert_payload_verification_with_no_initrd_eq(
73 &fs::read(TEST_IMG_WITH_NON_INITRD_HASHDESC_PATH)?,
74 &load_trusted_public_key()?,
75 Ok(()),
76 )
77}
78
79#[test]
80fn payload_with_prop_descriptor_fails_verification_with_no_initrd() -> Result<()> {
81 assert_payload_verification_with_no_initrd_eq(
82 &fs::read(TEST_IMG_WITH_PROP_DESC_PATH)?,
83 &load_trusted_public_key()?,
84 Err(AvbSlotVerifyError::InvalidMetadata),
85 )
86}
87
88#[test]
89fn payload_expecting_initrd_fails_verification_with_no_initrd() -> Result<()> {
90 assert_payload_verification_with_no_initrd_eq(
91 &load_latest_signed_kernel()?,
92 &load_trusted_public_key()?,
93 Err(AvbSlotVerifyError::InvalidMetadata),
94 )
95}
Alice Wangbf7fadd2023-01-13 12:18:24 +000096
97#[test]
98fn payload_with_empty_public_key_fails_verification() -> Result<()> {
99 assert_payload_verification_fails(
100 &load_latest_signed_kernel()?,
101 &load_latest_initrd_normal()?,
102 /*trusted_public_key=*/ &[0u8; 0],
103 AvbSlotVerifyError::PublicKeyRejected,
104 )
105}
106
107#[test]
108fn payload_with_an_invalid_public_key_fails_verification() -> Result<()> {
109 assert_payload_verification_fails(
110 &load_latest_signed_kernel()?,
111 &load_latest_initrd_normal()?,
112 /*trusted_public_key=*/ &[0u8; 512],
113 AvbSlotVerifyError::PublicKeyRejected,
114 )
115}
116
117#[test]
118fn payload_with_a_different_valid_public_key_fails_verification() -> Result<()> {
119 assert_payload_verification_fails(
120 &load_latest_signed_kernel()?,
121 &load_latest_initrd_normal()?,
122 &fs::read(PUBLIC_KEY_RSA2048_PATH)?,
123 AvbSlotVerifyError::PublicKeyRejected,
124 )
125}
126
127#[test]
128fn unsigned_kernel_fails_verification() -> Result<()> {
129 assert_payload_verification_fails(
130 &fs::read(UNSIGNED_TEST_IMG_PATH)?,
131 &load_latest_initrd_normal()?,
Alice Wang4e55dd92023-01-11 10:17:01 +0000132 &load_trusted_public_key()?,
Alice Wangbf7fadd2023-01-13 12:18:24 +0000133 AvbSlotVerifyError::Io,
134 )
135}
136
137#[test]
138fn tampered_kernel_fails_verification() -> Result<()> {
139 let mut kernel = load_latest_signed_kernel()?;
140 kernel[1] = !kernel[1]; // Flip the bits
141
142 assert_payload_verification_fails(
143 &kernel,
144 &load_latest_initrd_normal()?,
Alice Wang4e55dd92023-01-11 10:17:01 +0000145 &load_trusted_public_key()?,
Alice Wangbf7fadd2023-01-13 12:18:24 +0000146 AvbSlotVerifyError::Verification,
147 )
148}
149
150#[test]
151fn tampered_kernel_footer_fails_verification() -> Result<()> {
152 let mut kernel = load_latest_signed_kernel()?;
153 let avb_footer_index = kernel.len() - size_of::<AvbFooter>() + RANDOM_FOOTER_POS;
154 kernel[avb_footer_index] = !kernel[avb_footer_index];
155
156 assert_payload_verification_fails(
157 &kernel,
158 &load_latest_initrd_normal()?,
Alice Wang4e55dd92023-01-11 10:17:01 +0000159 &load_trusted_public_key()?,
Alice Wangbf7fadd2023-01-13 12:18:24 +0000160 AvbSlotVerifyError::InvalidMetadata,
161 )
162}
163
Alice Wang58dac082023-01-13 13:03:59 +0000164#[test]
165fn tampered_vbmeta_fails_verification() -> Result<()> {
166 let mut kernel = load_latest_signed_kernel()?;
167 let footer = extract_avb_footer(&kernel)?;
168 let vbmeta_index: usize = (footer.vbmeta_offset + 1).try_into()?;
169
170 kernel[vbmeta_index] = !kernel[vbmeta_index]; // Flip the bits
171
172 assert_payload_verification_fails(
173 &kernel,
174 &load_latest_initrd_normal()?,
175 &load_trusted_public_key()?,
176 AvbSlotVerifyError::InvalidMetadata,
177 )
178}
179
180#[test]
181fn vbmeta_with_public_key_overwritten_fails_verification() -> Result<()> {
182 let mut kernel = load_latest_signed_kernel()?;
183 let footer = extract_avb_footer(&kernel)?;
184 let vbmeta_header = extract_vbmeta_header(&kernel, &footer)?;
185 let public_key_offset = footer.vbmeta_offset as usize
186 + size_of::<AvbVBMetaImageHeader>()
187 + vbmeta_header.authentication_data_block_size as usize
188 + vbmeta_header.public_key_offset as usize;
189 let public_key_size: usize = vbmeta_header.public_key_size.try_into()?;
190 let empty_public_key = vec![0u8; public_key_size];
191
192 kernel[public_key_offset..(public_key_offset + public_key_size)]
193 .copy_from_slice(&empty_public_key);
194
195 assert_payload_verification_fails(
196 &kernel,
197 &load_latest_initrd_normal()?,
198 &empty_public_key,
199 AvbSlotVerifyError::Verification,
200 )?;
201 assert_payload_verification_fails(
202 &kernel,
203 &load_latest_initrd_normal()?,
204 &load_trusted_public_key()?,
205 AvbSlotVerifyError::Verification,
206 )
207}
208
Alice Wangf06bfd72023-01-19 09:24:21 +0000209#[test]
210fn vbmeta_with_verification_flag_disabled_fails_verification() -> Result<()> {
211 // From external/avb/libavb/avb_vbmeta_image.h
212 const AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED: u32 = 2;
213
214 // Arrange.
215 let mut kernel = load_latest_signed_kernel()?;
216 let footer = extract_avb_footer(&kernel)?;
217 let vbmeta_header = extract_vbmeta_header(&kernel, &footer)?;
218 assert_eq!(
219 0, vbmeta_header.flags as u32,
220 "The disable flag should not be set in the latest kernel."
221 );
222 let flags_addr = ptr::addr_of!(vbmeta_header.flags) as *const u8;
223 // SAFETY: It is safe as both raw pointers `flags_addr` and `vbmeta_header` are not null.
224 let flags_offset = unsafe { flags_addr.offset_from(ptr::addr_of!(vbmeta_header) as *const u8) };
225 let flags_offset = usize::try_from(footer.vbmeta_offset)? + usize::try_from(flags_offset)?;
226
227 // Act.
228 kernel[flags_offset..(flags_offset + size_of::<u32>())]
229 .copy_from_slice(&AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED.to_be_bytes());
230
231 // Assert.
232 let vbmeta_header = extract_vbmeta_header(&kernel, &footer)?;
233 assert_eq!(
234 AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED, vbmeta_header.flags as u32,
235 "VBMeta verification flag should be disabled now."
236 );
237 assert_payload_verification_fails(
238 &kernel,
239 &load_latest_initrd_normal()?,
240 &load_trusted_public_key()?,
241 AvbSlotVerifyError::Verification,
242 )
243}
Alice Wang58dac082023-01-13 13:03:59 +0000244
245fn extract_avb_footer(kernel: &[u8]) -> Result<AvbFooter> {
246 let footer_start = kernel.len() - size_of::<AvbFooter>();
247 // SAFETY: The slice is the same size as the struct which only contains simple data types.
248 let mut footer = unsafe {
249 transmute::<[u8; size_of::<AvbFooter>()], AvbFooter>(kernel[footer_start..].try_into()?)
250 };
251 // SAFETY: The function updates the struct in-place.
252 unsafe {
253 avb_footer_validate_and_byteswap(&footer, &mut footer);
254 }
255 Ok(footer)
256}
257
258fn extract_vbmeta_header(kernel: &[u8], footer: &AvbFooter) -> Result<AvbVBMetaImageHeader> {
259 let vbmeta_offset: usize = footer.vbmeta_offset.try_into()?;
260 let vbmeta_size: usize = footer.vbmeta_size.try_into()?;
261 let vbmeta_src = &kernel[vbmeta_offset..(vbmeta_offset + vbmeta_size)];
262 // SAFETY: The latest kernel has a valid VBMeta header at the position specified in footer.
263 let vbmeta_header = unsafe {
264 let mut header = MaybeUninit::uninit();
265 let src = vbmeta_src.as_ptr() as *const _ as *const AvbVBMetaImageHeader;
266 avb_vbmeta_image_header_to_host_byte_order(src, header.as_mut_ptr());
267 header.assume_init()
268 };
269 Ok(vbmeta_header)
270}
271
Alice Wang86383df2023-01-11 10:03:56 +0000272fn assert_payload_verification_with_no_initrd_eq(
273 kernel: &[u8],
274 trusted_public_key: &[u8],
275 expected_result: Result<(), AvbSlotVerifyError>,
276) -> Result<()> {
277 assert_eq!(expected_result, verify_payload(kernel, /*initrd=*/ None, trusted_public_key));
278 Ok(())
279}
280
Alice Wangbf7fadd2023-01-13 12:18:24 +0000281fn assert_payload_verification_fails(
282 kernel: &[u8],
283 initrd: &[u8],
284 trusted_public_key: &[u8],
285 expected_error: AvbSlotVerifyError,
286) -> Result<()> {
287 assert_eq!(Err(expected_error), verify_payload(kernel, Some(initrd), trusted_public_key));
288 Ok(())
289}
290
Alice Wang4e55dd92023-01-11 10:17:01 +0000291fn assert_payload_verification_succeeds(
292 kernel: &[u8],
293 initrd: &[u8],
294 trusted_public_key: &[u8],
295) -> Result<()> {
296 assert_eq!(Ok(()), verify_payload(kernel, Some(initrd), trusted_public_key));
297 Ok(())
298}
299
Alice Wangbf7fadd2023-01-13 12:18:24 +0000300fn load_latest_signed_kernel() -> Result<Vec<u8>> {
301 Ok(fs::read(MICRODROID_KERNEL_IMG_PATH)?)
302}
303
304fn load_latest_initrd_normal() -> Result<Vec<u8>> {
305 Ok(fs::read(INITRD_NORMAL_IMG_PATH)?)
306}
Alice Wang4e55dd92023-01-11 10:17:01 +0000307
308fn load_latest_initrd_debug() -> Result<Vec<u8>> {
309 Ok(fs::read(INITRD_DEBUG_IMG_PATH)?)
310}
311
312fn load_trusted_public_key() -> Result<Vec<u8>> {
313 Ok(fs::read(PUBLIC_KEY_RSA4096_PATH)?)
314}