blob: 945c838fc860af5f56a074c9285ebf340355634c [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";
32const UNSIGNED_TEST_IMG_PATH: &str = "unsigned_test.img";
33
34const PUBLIC_KEY_RSA2048_PATH: &str = "data/testkey_rsa2048_pub.bin";
35const PUBLIC_KEY_RSA4096_PATH: &str = "data/testkey_rsa4096_pub.bin";
36const RANDOM_FOOTER_POS: usize = 30;
37
38/// This test uses the Microdroid payload compiled on the fly to check that
39/// the latest payload can be verified successfully.
40#[test]
Alice Wang4e55dd92023-01-11 10:17:01 +000041fn latest_normal_payload_passes_verification() -> Result<()> {
42 assert_payload_verification_succeeds(
43 &load_latest_signed_kernel()?,
44 &load_latest_initrd_normal()?,
45 &load_trusted_public_key()?,
46 )
47}
Alice Wangbf7fadd2023-01-13 12:18:24 +000048
Alice Wang4e55dd92023-01-11 10:17:01 +000049#[test]
50fn latest_debug_payload_passes_verification() -> Result<()> {
51 assert_payload_verification_succeeds(
52 &load_latest_signed_kernel()?,
53 &load_latest_initrd_debug()?,
54 &load_trusted_public_key()?,
55 )
Alice Wangbf7fadd2023-01-13 12:18:24 +000056}
57
58#[test]
59fn payload_expecting_no_initrd_passes_verification_with_no_initrd() -> Result<()> {
60 let kernel = fs::read(TEST_IMG_WITH_ONE_HASHDESC_PATH)?;
Alice Wang4e55dd92023-01-11 10:17:01 +000061 let public_key = load_trusted_public_key()?;
Alice Wangbf7fadd2023-01-13 12:18:24 +000062
63 assert_eq!(Ok(()), verify_payload(&kernel, None, &public_key));
64 Ok(())
65}
66
67// TODO(b/256148034): Test that kernel with two hashdesc and no initrd fails verification.
68// e.g. payload_expecting_initrd_fails_verification_with_no_initrd
69
70#[test]
71fn payload_with_empty_public_key_fails_verification() -> Result<()> {
72 assert_payload_verification_fails(
73 &load_latest_signed_kernel()?,
74 &load_latest_initrd_normal()?,
75 /*trusted_public_key=*/ &[0u8; 0],
76 AvbSlotVerifyError::PublicKeyRejected,
77 )
78}
79
80#[test]
81fn payload_with_an_invalid_public_key_fails_verification() -> Result<()> {
82 assert_payload_verification_fails(
83 &load_latest_signed_kernel()?,
84 &load_latest_initrd_normal()?,
85 /*trusted_public_key=*/ &[0u8; 512],
86 AvbSlotVerifyError::PublicKeyRejected,
87 )
88}
89
90#[test]
91fn payload_with_a_different_valid_public_key_fails_verification() -> Result<()> {
92 assert_payload_verification_fails(
93 &load_latest_signed_kernel()?,
94 &load_latest_initrd_normal()?,
95 &fs::read(PUBLIC_KEY_RSA2048_PATH)?,
96 AvbSlotVerifyError::PublicKeyRejected,
97 )
98}
99
100#[test]
101fn unsigned_kernel_fails_verification() -> Result<()> {
102 assert_payload_verification_fails(
103 &fs::read(UNSIGNED_TEST_IMG_PATH)?,
104 &load_latest_initrd_normal()?,
Alice Wang4e55dd92023-01-11 10:17:01 +0000105 &load_trusted_public_key()?,
Alice Wangbf7fadd2023-01-13 12:18:24 +0000106 AvbSlotVerifyError::Io,
107 )
108}
109
110#[test]
111fn tampered_kernel_fails_verification() -> Result<()> {
112 let mut kernel = load_latest_signed_kernel()?;
113 kernel[1] = !kernel[1]; // Flip the bits
114
115 assert_payload_verification_fails(
116 &kernel,
117 &load_latest_initrd_normal()?,
Alice Wang4e55dd92023-01-11 10:17:01 +0000118 &load_trusted_public_key()?,
Alice Wangbf7fadd2023-01-13 12:18:24 +0000119 AvbSlotVerifyError::Verification,
120 )
121}
122
123#[test]
124fn tampered_kernel_footer_fails_verification() -> Result<()> {
125 let mut kernel = load_latest_signed_kernel()?;
126 let avb_footer_index = kernel.len() - size_of::<AvbFooter>() + RANDOM_FOOTER_POS;
127 kernel[avb_footer_index] = !kernel[avb_footer_index];
128
129 assert_payload_verification_fails(
130 &kernel,
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::InvalidMetadata,
134 )
135}
136
Alice Wang58dac082023-01-13 13:03:59 +0000137#[test]
138fn tampered_vbmeta_fails_verification() -> Result<()> {
139 let mut kernel = load_latest_signed_kernel()?;
140 let footer = extract_avb_footer(&kernel)?;
141 let vbmeta_index: usize = (footer.vbmeta_offset + 1).try_into()?;
142
143 kernel[vbmeta_index] = !kernel[vbmeta_index]; // Flip the bits
144
145 assert_payload_verification_fails(
146 &kernel,
147 &load_latest_initrd_normal()?,
148 &load_trusted_public_key()?,
149 AvbSlotVerifyError::InvalidMetadata,
150 )
151}
152
153#[test]
154fn vbmeta_with_public_key_overwritten_fails_verification() -> Result<()> {
155 let mut kernel = load_latest_signed_kernel()?;
156 let footer = extract_avb_footer(&kernel)?;
157 let vbmeta_header = extract_vbmeta_header(&kernel, &footer)?;
158 let public_key_offset = footer.vbmeta_offset as usize
159 + size_of::<AvbVBMetaImageHeader>()
160 + vbmeta_header.authentication_data_block_size as usize
161 + vbmeta_header.public_key_offset as usize;
162 let public_key_size: usize = vbmeta_header.public_key_size.try_into()?;
163 let empty_public_key = vec![0u8; public_key_size];
164
165 kernel[public_key_offset..(public_key_offset + public_key_size)]
166 .copy_from_slice(&empty_public_key);
167
168 assert_payload_verification_fails(
169 &kernel,
170 &load_latest_initrd_normal()?,
171 &empty_public_key,
172 AvbSlotVerifyError::Verification,
173 )?;
174 assert_payload_verification_fails(
175 &kernel,
176 &load_latest_initrd_normal()?,
177 &load_trusted_public_key()?,
178 AvbSlotVerifyError::Verification,
179 )
180}
181
182// TODO(b/256148034): Test that vbmeta with its verification flag overwritten fails verification.
183
184fn extract_avb_footer(kernel: &[u8]) -> Result<AvbFooter> {
185 let footer_start = kernel.len() - size_of::<AvbFooter>();
186 // SAFETY: The slice is the same size as the struct which only contains simple data types.
187 let mut footer = unsafe {
188 transmute::<[u8; size_of::<AvbFooter>()], AvbFooter>(kernel[footer_start..].try_into()?)
189 };
190 // SAFETY: The function updates the struct in-place.
191 unsafe {
192 avb_footer_validate_and_byteswap(&footer, &mut footer);
193 }
194 Ok(footer)
195}
196
197fn extract_vbmeta_header(kernel: &[u8], footer: &AvbFooter) -> Result<AvbVBMetaImageHeader> {
198 let vbmeta_offset: usize = footer.vbmeta_offset.try_into()?;
199 let vbmeta_size: usize = footer.vbmeta_size.try_into()?;
200 let vbmeta_src = &kernel[vbmeta_offset..(vbmeta_offset + vbmeta_size)];
201 // SAFETY: The latest kernel has a valid VBMeta header at the position specified in footer.
202 let vbmeta_header = unsafe {
203 let mut header = MaybeUninit::uninit();
204 let src = vbmeta_src.as_ptr() as *const _ as *const AvbVBMetaImageHeader;
205 avb_vbmeta_image_header_to_host_byte_order(src, header.as_mut_ptr());
206 header.assume_init()
207 };
208 Ok(vbmeta_header)
209}
210
Alice Wangbf7fadd2023-01-13 12:18:24 +0000211fn assert_payload_verification_fails(
212 kernel: &[u8],
213 initrd: &[u8],
214 trusted_public_key: &[u8],
215 expected_error: AvbSlotVerifyError,
216) -> Result<()> {
217 assert_eq!(Err(expected_error), verify_payload(kernel, Some(initrd), trusted_public_key));
218 Ok(())
219}
220
Alice Wang4e55dd92023-01-11 10:17:01 +0000221fn assert_payload_verification_succeeds(
222 kernel: &[u8],
223 initrd: &[u8],
224 trusted_public_key: &[u8],
225) -> Result<()> {
226 assert_eq!(Ok(()), verify_payload(kernel, Some(initrd), trusted_public_key));
227 Ok(())
228}
229
Alice Wangbf7fadd2023-01-13 12:18:24 +0000230fn load_latest_signed_kernel() -> Result<Vec<u8>> {
231 Ok(fs::read(MICRODROID_KERNEL_IMG_PATH)?)
232}
233
234fn load_latest_initrd_normal() -> Result<Vec<u8>> {
235 Ok(fs::read(INITRD_NORMAL_IMG_PATH)?)
236}
Alice Wang4e55dd92023-01-11 10:17:01 +0000237
238fn load_latest_initrd_debug() -> Result<Vec<u8>> {
239 Ok(fs::read(INITRD_DEBUG_IMG_PATH)?)
240}
241
242fn load_trusted_public_key() -> Result<Vec<u8>> {
243 Ok(fs::read(PUBLIC_KEY_RSA4096_PATH)?)
244}