blob: 492d387d1066bd63d85143a018e7a24f0eb840a9 [file] [log] [blame]
Alice Wang28cbcf12022-12-01 07:58:28 +00001// Copyright 2022, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Alice Wangf3d96b12022-12-15 13:10:47 +000015//! This module handles the pvmfw payload verification.
Alice Wang28cbcf12022-12-01 07:58:28 +000016
Alice Wang79985512023-05-22 08:15:36 +000017use crate::descriptor::{Descriptors, Digest};
Alice Wang167ab3f2023-01-23 13:39:25 +000018use crate::ops::{Ops, Payload};
Alice Wang8077a862023-01-18 16:06:37 +000019use crate::partition::PartitionName;
David Pursella7c727b2023-08-14 16:24:40 -070020use crate::PvmfwVerifyError;
Alice Wangab0d0202023-05-17 08:07:41 +000021use alloc::vec;
22use alloc::vec::Vec;
Alice Wangf2752862023-01-18 11:51:25 +000023use avb_bindgen::{AvbPartitionData, AvbVBMetaData};
24use core::ffi::c_char;
Alice Wang28cbcf12022-12-01 07:58:28 +000025
Shikha Panwara26f16a2023-09-27 09:39:00 +000026// We use this for the rollback_index field if AvbSlotVerifyDataWrap has empty rollback_indexes
27const DEFAULT_ROLLBACK_INDEX: u64 = 0;
28
Alice Wang1f0add02023-01-23 16:22:53 +000029/// Verified data returned when the payload verification succeeds.
Pierre-Clément Tosi81ca0802023-02-14 10:41:38 +000030#[derive(Debug, PartialEq, Eq)]
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000031pub struct VerifiedBootData<'a> {
Alice Wang1f0add02023-01-23 16:22:53 +000032 /// DebugLevel of the VM.
33 pub debug_level: DebugLevel,
34 /// Kernel digest.
35 pub kernel_digest: Digest,
36 /// Initrd digest if initrd exists.
37 pub initrd_digest: Option<Digest>,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000038 /// Trusted public key.
39 pub public_key: &'a [u8],
Alice Wangab0d0202023-05-17 08:07:41 +000040 /// VM capabilities.
41 pub capabilities: Vec<Capability>,
Shikha Panwara26f16a2023-09-27 09:39:00 +000042 /// Rollback index of kernel.
43 pub rollback_index: u64,
Alice Wang1f0add02023-01-23 16:22:53 +000044}
45
Shikha Panwar4a0651d2023-09-28 13:06:13 +000046impl VerifiedBootData<'_> {
47 /// Returns whether the kernel have the given capability
48 pub fn has_capability(&self, cap: Capability) -> bool {
49 self.capabilities.contains(&cap)
50 }
51}
52
Alice Wang5c1a7562023-01-13 17:19:57 +000053/// This enum corresponds to the `DebugLevel` in `VirtualMachineConfig`.
Alice Wang1f0add02023-01-23 16:22:53 +000054#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Alice Wang5c1a7562023-01-13 17:19:57 +000055pub enum DebugLevel {
56 /// Not debuggable at all.
57 None,
58 /// Fully debuggable.
59 Full,
60}
61
Alice Wangab0d0202023-05-17 08:07:41 +000062/// VM Capability.
Shikha Panwar4a0651d2023-09-28 13:06:13 +000063#[derive(Copy, Clone, Debug, PartialEq, Eq)]
Alice Wangab0d0202023-05-17 08:07:41 +000064pub enum Capability {
65 /// Remote attestation.
66 RemoteAttest,
Shikha Panwar4a0651d2023-09-28 13:06:13 +000067 /// Secretkeeper protected secrets.
68 SecretkeeperProtection,
Alice Wangab0d0202023-05-17 08:07:41 +000069}
70
71impl Capability {
72 const KEY: &[u8] = b"com.android.virt.cap";
73 const REMOTE_ATTEST: &[u8] = b"remote_attest";
Shikha Panwar4a0651d2023-09-28 13:06:13 +000074 const SECRETKEEPER_PROTECTION: &[u8] = b"secretkeeper_protection";
Alice Wangab0d0202023-05-17 08:07:41 +000075 const SEPARATOR: u8 = b'|';
76
David Pursella7c727b2023-08-14 16:24:40 -070077 fn get_capabilities(property_value: &[u8]) -> Result<Vec<Self>, PvmfwVerifyError> {
Alice Wangab0d0202023-05-17 08:07:41 +000078 let mut res = Vec::new();
79
80 for v in property_value.split(|b| *b == Self::SEPARATOR) {
81 let cap = match v {
82 Self::REMOTE_ATTEST => Self::RemoteAttest,
Shikha Panwar4a0651d2023-09-28 13:06:13 +000083 Self::SECRETKEEPER_PROTECTION => Self::SecretkeeperProtection,
David Pursella7c727b2023-08-14 16:24:40 -070084 _ => return Err(PvmfwVerifyError::UnknownVbmetaProperty),
Alice Wangab0d0202023-05-17 08:07:41 +000085 };
86 if res.contains(&cap) {
David Pursella7c727b2023-08-14 16:24:40 -070087 return Err(avb::SlotVerifyError::InvalidMetadata.into());
Alice Wangab0d0202023-05-17 08:07:41 +000088 }
89 res.push(cap);
90 }
91 Ok(res)
92 }
93}
94
Alice Wangd3f28ae2023-01-25 10:41:40 +000095fn verify_only_one_vbmeta_exists(
96 vbmeta_images: &[AvbVBMetaData],
David Pursella7c727b2023-08-14 16:24:40 -070097) -> Result<(), avb::SlotVerifyError> {
Alice Wangd3f28ae2023-01-25 10:41:40 +000098 if vbmeta_images.len() == 1 {
99 Ok(())
100 } else {
David Pursella7c727b2023-08-14 16:24:40 -0700101 Err(avb::SlotVerifyError::InvalidMetadata)
Alice Wangd3f28ae2023-01-25 10:41:40 +0000102 }
103}
104
Alice Wang9dfb2962023-01-18 10:01:34 +0000105fn verify_vbmeta_is_from_kernel_partition(
106 vbmeta_image: &AvbVBMetaData,
David Pursella7c727b2023-08-14 16:24:40 -0700107) -> Result<(), avb::SlotVerifyError> {
Alice Wang9dfb2962023-01-18 10:01:34 +0000108 match (vbmeta_image.partition_name as *const c_char).try_into() {
109 Ok(PartitionName::Kernel) => Ok(()),
David Pursella7c727b2023-08-14 16:24:40 -0700110 _ => Err(avb::SlotVerifyError::InvalidMetadata),
Alice Wang9dfb2962023-01-18 10:01:34 +0000111 }
112}
113
Alice Wangf2752862023-01-18 11:51:25 +0000114fn verify_vbmeta_has_only_one_hash_descriptor(
Alice Wang79985512023-05-22 08:15:36 +0000115 descriptors: &Descriptors,
David Pursella7c727b2023-08-14 16:24:40 -0700116) -> Result<(), avb::SlotVerifyError> {
Alice Wang79985512023-05-22 08:15:36 +0000117 if descriptors.num_hash_descriptor() == 1 {
Alice Wangf2752862023-01-18 11:51:25 +0000118 Ok(())
119 } else {
David Pursella7c727b2023-08-14 16:24:40 -0700120 Err(avb::SlotVerifyError::InvalidMetadata)
Alice Wangf2752862023-01-18 11:51:25 +0000121 }
122}
123
Alice Wang75d05632023-01-25 13:31:18 +0000124fn verify_loaded_partition_has_expected_length(
125 loaded_partitions: &[AvbPartitionData],
126 partition_name: PartitionName,
127 expected_len: usize,
David Pursella7c727b2023-08-14 16:24:40 -0700128) -> Result<(), avb::SlotVerifyError> {
Alice Wang75d05632023-01-25 13:31:18 +0000129 if loaded_partitions.len() != 1 {
130 // Only one partition should be loaded in each verify result.
David Pursella7c727b2023-08-14 16:24:40 -0700131 return Err(avb::SlotVerifyError::Io);
Alice Wang75d05632023-01-25 13:31:18 +0000132 }
133 let loaded_partition = loaded_partitions[0];
134 if !PartitionName::try_from(loaded_partition.partition_name as *const c_char)
135 .map_or(false, |p| p == partition_name)
136 {
137 // Only the requested partition should be loaded.
David Pursella7c727b2023-08-14 16:24:40 -0700138 return Err(avb::SlotVerifyError::Io);
Alice Wang75d05632023-01-25 13:31:18 +0000139 }
140 if loaded_partition.data_size == expected_len {
141 Ok(())
142 } else {
David Pursella7c727b2023-08-14 16:24:40 -0700143 Err(avb::SlotVerifyError::Verification)
Alice Wang75d05632023-01-25 13:31:18 +0000144 }
145}
146
Alice Wangab0d0202023-05-17 08:07:41 +0000147/// Verifies that the vbmeta contains at most one property descriptor and it indicates the
148/// vm type is service VM.
149fn verify_property_and_get_capabilities(
150 descriptors: &Descriptors,
David Pursella7c727b2023-08-14 16:24:40 -0700151) -> Result<Vec<Capability>, PvmfwVerifyError> {
Alice Wangab0d0202023-05-17 08:07:41 +0000152 if !descriptors.has_property_descriptor() {
153 return Ok(vec![]);
154 }
155 descriptors
156 .find_property_value(Capability::KEY)
David Pursella7c727b2023-08-14 16:24:40 -0700157 .ok_or(PvmfwVerifyError::UnknownVbmetaProperty)
Alice Wangab0d0202023-05-17 08:07:41 +0000158 .and_then(Capability::get_capabilities)
159}
160
Alice Wangf3d96b12022-12-15 13:10:47 +0000161/// Verifies the payload (signed kernel + initrd) against the trusted public key.
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000162pub fn verify_payload<'a>(
Alice Wang6b486f12023-01-06 13:12:16 +0000163 kernel: &[u8],
164 initrd: Option<&[u8]>,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000165 trusted_public_key: &'a [u8],
David Pursella7c727b2023-08-14 16:24:40 -0700166) -> Result<VerifiedBootData<'a>, PvmfwVerifyError> {
Alice Wang167ab3f2023-01-23 13:39:25 +0000167 let mut payload = Payload::new(kernel, initrd, trusted_public_key);
168 let mut ops = Ops::from(&mut payload);
169 let kernel_verify_result = ops.verify_partition(PartitionName::Kernel.as_cstr())?;
Alice Wang75d05632023-01-25 13:31:18 +0000170
Alice Wang86383df2023-01-11 10:03:56 +0000171 let vbmeta_images = kernel_verify_result.vbmeta_images()?;
Shikha Panwara26f16a2023-09-27 09:39:00 +0000172 // TODO(b/302093437): Use explicit rollback_index_location instead of default
173 // location (first element).
174 let rollback_index =
175 *kernel_verify_result.rollback_indexes().first().unwrap_or(&DEFAULT_ROLLBACK_INDEX);
Alice Wangd3f28ae2023-01-25 10:41:40 +0000176 verify_only_one_vbmeta_exists(vbmeta_images)?;
Alice Wang9dfb2962023-01-18 10:01:34 +0000177 let vbmeta_image = vbmeta_images[0];
178 verify_vbmeta_is_from_kernel_partition(&vbmeta_image)?;
Alice Wangf2752862023-01-18 11:51:25 +0000179 // SAFETY: It is safe because the `vbmeta_image` is collected from `AvbSlotVerifyData`,
180 // which is returned by `avb_slot_verify()` when the verification succeeds. It is
181 // guaranteed by libavb to be non-null and to point to a valid VBMeta structure.
Alice Wang79985512023-05-22 08:15:36 +0000182 let descriptors = unsafe { Descriptors::from_vbmeta(vbmeta_image)? };
Alice Wangab0d0202023-05-17 08:07:41 +0000183 let capabilities = verify_property_and_get_capabilities(&descriptors)?;
Alice Wang79985512023-05-22 08:15:36 +0000184 let kernel_descriptor = descriptors.find_hash_descriptor(PartitionName::Kernel)?;
Alice Wangd3f28ae2023-01-25 10:41:40 +0000185
Alice Wang167ab3f2023-01-23 13:39:25 +0000186 if initrd.is_none() {
Alice Wang79985512023-05-22 08:15:36 +0000187 verify_vbmeta_has_only_one_hash_descriptor(&descriptors)?;
Alice Wang1f0add02023-01-23 16:22:53 +0000188 return Ok(VerifiedBootData {
189 debug_level: DebugLevel::None,
Alice Wang91509482023-05-22 13:10:32 +0000190 kernel_digest: *kernel_descriptor.digest,
Alice Wang1f0add02023-01-23 16:22:53 +0000191 initrd_digest: None,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000192 public_key: trusted_public_key,
Alice Wangab0d0202023-05-17 08:07:41 +0000193 capabilities,
Shikha Panwara26f16a2023-09-27 09:39:00 +0000194 rollback_index,
Alice Wang1f0add02023-01-23 16:22:53 +0000195 });
Alice Wang86383df2023-01-11 10:03:56 +0000196 }
Alice Wang5c1a7562023-01-13 17:19:57 +0000197
Alice Wang75d05632023-01-25 13:31:18 +0000198 let initrd = initrd.unwrap();
199 let (debug_level, initrd_verify_result, initrd_partition_name) =
200 if let Ok(result) = ops.verify_partition(PartitionName::InitrdNormal.as_cstr()) {
201 (DebugLevel::None, result, PartitionName::InitrdNormal)
202 } else if let Ok(result) = ops.verify_partition(PartitionName::InitrdDebug.as_cstr()) {
203 (DebugLevel::Full, result, PartitionName::InitrdDebug)
204 } else {
David Pursella7c727b2023-08-14 16:24:40 -0700205 return Err(avb::SlotVerifyError::Verification.into());
Alice Wang75d05632023-01-25 13:31:18 +0000206 };
207 let loaded_partitions = initrd_verify_result.loaded_partitions()?;
208 verify_loaded_partition_has_expected_length(
209 loaded_partitions,
210 initrd_partition_name,
211 initrd.len(),
212 )?;
Alice Wang79985512023-05-22 08:15:36 +0000213 let initrd_descriptor = descriptors.find_hash_descriptor(initrd_partition_name)?;
Alice Wang1f0add02023-01-23 16:22:53 +0000214 Ok(VerifiedBootData {
215 debug_level,
Alice Wang91509482023-05-22 13:10:32 +0000216 kernel_digest: *kernel_descriptor.digest,
217 initrd_digest: Some(*initrd_descriptor.digest),
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000218 public_key: trusted_public_key,
Alice Wangab0d0202023-05-17 08:07:41 +0000219 capabilities,
Shikha Panwara26f16a2023-09-27 09:39:00 +0000220 rollback_index,
Alice Wang1f0add02023-01-23 16:22:53 +0000221 })
Alice Wang28cbcf12022-12-01 07:58:28 +0000222}