blob: a85dbbb1dcf74bd944cf1542ec1084cbd7535a40 [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;
David Pursellb59bcc42023-11-10 16:59:19 -080023use avb::{PartitionData, SlotVerifyError, SlotVerifyNoDataResult, VbmetaData};
Alice Wang28cbcf12022-12-01 07:58:28 +000024
David Pursellb59bcc42023-11-10 16:59:19 -080025// We use this for the rollback_index field if SlotVerifyData has empty rollback_indexes
Shikha Panwara26f16a2023-09-27 09:39:00 +000026const DEFAULT_ROLLBACK_INDEX: u64 = 0;
27
Alice Wang1f0add02023-01-23 16:22:53 +000028/// Verified data returned when the payload verification succeeds.
Pierre-Clément Tosi81ca0802023-02-14 10:41:38 +000029#[derive(Debug, PartialEq, Eq)]
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000030pub struct VerifiedBootData<'a> {
Alice Wang1f0add02023-01-23 16:22:53 +000031 /// DebugLevel of the VM.
32 pub debug_level: DebugLevel,
33 /// Kernel digest.
34 pub kernel_digest: Digest,
35 /// Initrd digest if initrd exists.
36 pub initrd_digest: Option<Digest>,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000037 /// Trusted public key.
38 pub public_key: &'a [u8],
Alice Wangab0d0202023-05-17 08:07:41 +000039 /// VM capabilities.
40 pub capabilities: Vec<Capability>,
Shikha Panwara26f16a2023-09-27 09:39:00 +000041 /// Rollback index of kernel.
42 pub rollback_index: u64,
Alice Wang1f0add02023-01-23 16:22:53 +000043}
44
Shikha Panwar4a0651d2023-09-28 13:06:13 +000045impl VerifiedBootData<'_> {
46 /// Returns whether the kernel have the given capability
47 pub fn has_capability(&self, cap: Capability) -> bool {
48 self.capabilities.contains(&cap)
49 }
50}
51
Alice Wang5c1a7562023-01-13 17:19:57 +000052/// This enum corresponds to the `DebugLevel` in `VirtualMachineConfig`.
Alice Wang1f0add02023-01-23 16:22:53 +000053#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Alice Wang5c1a7562023-01-13 17:19:57 +000054pub enum DebugLevel {
55 /// Not debuggable at all.
56 None,
57 /// Fully debuggable.
58 Full,
59}
60
Alice Wangab0d0202023-05-17 08:07:41 +000061/// VM Capability.
Shikha Panwar4a0651d2023-09-28 13:06:13 +000062#[derive(Copy, Clone, Debug, PartialEq, Eq)]
Alice Wangab0d0202023-05-17 08:07:41 +000063pub enum Capability {
64 /// Remote attestation.
65 RemoteAttest,
Shikha Panwar4a0651d2023-09-28 13:06:13 +000066 /// Secretkeeper protected secrets.
67 SecretkeeperProtection,
Alice Wangab0d0202023-05-17 08:07:41 +000068}
69
70impl Capability {
Chris Wailes98f18232023-12-07 12:04:21 -080071 const KEY: &'static [u8] = b"com.android.virt.cap";
72 const REMOTE_ATTEST: &'static [u8] = b"remote_attest";
73 const SECRETKEEPER_PROTECTION: &'static [u8] = b"secretkeeper_protection";
Alice Wangab0d0202023-05-17 08:07:41 +000074 const SEPARATOR: u8 = b'|';
75
David Pursella7c727b2023-08-14 16:24:40 -070076 fn get_capabilities(property_value: &[u8]) -> Result<Vec<Self>, PvmfwVerifyError> {
Alice Wangab0d0202023-05-17 08:07:41 +000077 let mut res = Vec::new();
78
79 for v in property_value.split(|b| *b == Self::SEPARATOR) {
80 let cap = match v {
81 Self::REMOTE_ATTEST => Self::RemoteAttest,
Shikha Panwar4a0651d2023-09-28 13:06:13 +000082 Self::SECRETKEEPER_PROTECTION => Self::SecretkeeperProtection,
David Pursella7c727b2023-08-14 16:24:40 -070083 _ => return Err(PvmfwVerifyError::UnknownVbmetaProperty),
Alice Wangab0d0202023-05-17 08:07:41 +000084 };
85 if res.contains(&cap) {
David Pursellb59bcc42023-11-10 16:59:19 -080086 return Err(SlotVerifyError::InvalidMetadata.into());
Alice Wangab0d0202023-05-17 08:07:41 +000087 }
88 res.push(cap);
89 }
90 Ok(res)
91 }
92}
93
David Pursellb59bcc42023-11-10 16:59:19 -080094fn verify_only_one_vbmeta_exists(vbmeta_data: &[VbmetaData]) -> SlotVerifyNoDataResult<()> {
95 if vbmeta_data.len() == 1 {
Alice Wangd3f28ae2023-01-25 10:41:40 +000096 Ok(())
97 } else {
David Pursellb59bcc42023-11-10 16:59:19 -080098 Err(SlotVerifyError::InvalidMetadata)
Alice Wangd3f28ae2023-01-25 10:41:40 +000099 }
100}
101
David Pursellb59bcc42023-11-10 16:59:19 -0800102fn verify_vbmeta_is_from_kernel_partition(vbmeta_image: &VbmetaData) -> SlotVerifyNoDataResult<()> {
103 match vbmeta_image.partition_name().try_into() {
Alice Wang9dfb2962023-01-18 10:01:34 +0000104 Ok(PartitionName::Kernel) => Ok(()),
David Pursellb59bcc42023-11-10 16:59:19 -0800105 _ => Err(SlotVerifyError::InvalidMetadata),
Alice Wang9dfb2962023-01-18 10:01:34 +0000106 }
107}
108
Alice Wangf2752862023-01-18 11:51:25 +0000109fn verify_vbmeta_has_only_one_hash_descriptor(
Alice Wang79985512023-05-22 08:15:36 +0000110 descriptors: &Descriptors,
David Pursellb59bcc42023-11-10 16:59:19 -0800111) -> SlotVerifyNoDataResult<()> {
Alice Wang79985512023-05-22 08:15:36 +0000112 if descriptors.num_hash_descriptor() == 1 {
Alice Wangf2752862023-01-18 11:51:25 +0000113 Ok(())
114 } else {
David Pursellb59bcc42023-11-10 16:59:19 -0800115 Err(SlotVerifyError::InvalidMetadata)
Alice Wangf2752862023-01-18 11:51:25 +0000116 }
117}
118
Alice Wang75d05632023-01-25 13:31:18 +0000119fn verify_loaded_partition_has_expected_length(
David Pursellb59bcc42023-11-10 16:59:19 -0800120 loaded_partitions: &[PartitionData],
Alice Wang75d05632023-01-25 13:31:18 +0000121 partition_name: PartitionName,
122 expected_len: usize,
David Pursellb59bcc42023-11-10 16:59:19 -0800123) -> SlotVerifyNoDataResult<()> {
Alice Wang75d05632023-01-25 13:31:18 +0000124 if loaded_partitions.len() != 1 {
125 // Only one partition should be loaded in each verify result.
David Pursellb59bcc42023-11-10 16:59:19 -0800126 return Err(SlotVerifyError::Io);
Alice Wang75d05632023-01-25 13:31:18 +0000127 }
David Pursellb59bcc42023-11-10 16:59:19 -0800128 let loaded_partition = &loaded_partitions[0];
129 if !PartitionName::try_from(loaded_partition.partition_name())
Alice Wang75d05632023-01-25 13:31:18 +0000130 .map_or(false, |p| p == partition_name)
131 {
132 // Only the requested partition should be loaded.
David Pursellb59bcc42023-11-10 16:59:19 -0800133 return Err(SlotVerifyError::Io);
Alice Wang75d05632023-01-25 13:31:18 +0000134 }
David Pursellb59bcc42023-11-10 16:59:19 -0800135 if loaded_partition.data().len() == expected_len {
Alice Wang75d05632023-01-25 13:31:18 +0000136 Ok(())
137 } else {
David Pursellb59bcc42023-11-10 16:59:19 -0800138 Err(SlotVerifyError::Verification(None))
Alice Wang75d05632023-01-25 13:31:18 +0000139 }
140}
141
Alice Wangab0d0202023-05-17 08:07:41 +0000142/// Verifies that the vbmeta contains at most one property descriptor and it indicates the
143/// vm type is service VM.
144fn verify_property_and_get_capabilities(
145 descriptors: &Descriptors,
David Pursella7c727b2023-08-14 16:24:40 -0700146) -> Result<Vec<Capability>, PvmfwVerifyError> {
Alice Wangab0d0202023-05-17 08:07:41 +0000147 if !descriptors.has_property_descriptor() {
148 return Ok(vec![]);
149 }
150 descriptors
151 .find_property_value(Capability::KEY)
David Pursella7c727b2023-08-14 16:24:40 -0700152 .ok_or(PvmfwVerifyError::UnknownVbmetaProperty)
Alice Wangab0d0202023-05-17 08:07:41 +0000153 .and_then(Capability::get_capabilities)
154}
155
David Pursellb59bcc42023-11-10 16:59:19 -0800156/// Verifies the given initrd partition, and checks that the resulting contents looks like expected.
157fn verify_initrd(
158 ops: &mut Ops,
159 partition_name: PartitionName,
160 expected_initrd: &[u8],
161) -> SlotVerifyNoDataResult<()> {
162 let result =
163 ops.verify_partition(partition_name.as_cstr()).map_err(|e| e.without_verify_data())?;
164 verify_loaded_partition_has_expected_length(
165 result.partition_data(),
166 partition_name,
167 expected_initrd.len(),
168 )
169}
170
Alice Wangf3d96b12022-12-15 13:10:47 +0000171/// Verifies the payload (signed kernel + initrd) against the trusted public key.
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000172pub fn verify_payload<'a>(
Alice Wang6b486f12023-01-06 13:12:16 +0000173 kernel: &[u8],
174 initrd: Option<&[u8]>,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000175 trusted_public_key: &'a [u8],
David Pursella7c727b2023-08-14 16:24:40 -0700176) -> Result<VerifiedBootData<'a>, PvmfwVerifyError> {
David Pursellb59bcc42023-11-10 16:59:19 -0800177 let payload = Payload::new(kernel, initrd, trusted_public_key);
178 let mut ops = Ops::new(&payload);
Alice Wang167ab3f2023-01-23 13:39:25 +0000179 let kernel_verify_result = ops.verify_partition(PartitionName::Kernel.as_cstr())?;
Alice Wang75d05632023-01-25 13:31:18 +0000180
David Pursellb59bcc42023-11-10 16:59:19 -0800181 let vbmeta_images = kernel_verify_result.vbmeta_data();
Shikha Panwara26f16a2023-09-27 09:39:00 +0000182 // TODO(b/302093437): Use explicit rollback_index_location instead of default
183 // location (first element).
184 let rollback_index =
185 *kernel_verify_result.rollback_indexes().first().unwrap_or(&DEFAULT_ROLLBACK_INDEX);
Alice Wangd3f28ae2023-01-25 10:41:40 +0000186 verify_only_one_vbmeta_exists(vbmeta_images)?;
David Pursellb59bcc42023-11-10 16:59:19 -0800187 let vbmeta_image = &vbmeta_images[0];
188 verify_vbmeta_is_from_kernel_partition(vbmeta_image)?;
189 let descriptors = Descriptors::from_vbmeta(vbmeta_image)?;
Alice Wangab0d0202023-05-17 08:07:41 +0000190 let capabilities = verify_property_and_get_capabilities(&descriptors)?;
Alice Wang79985512023-05-22 08:15:36 +0000191 let kernel_descriptor = descriptors.find_hash_descriptor(PartitionName::Kernel)?;
Alice Wangd3f28ae2023-01-25 10:41:40 +0000192
Alice Wang167ab3f2023-01-23 13:39:25 +0000193 if initrd.is_none() {
Alice Wang79985512023-05-22 08:15:36 +0000194 verify_vbmeta_has_only_one_hash_descriptor(&descriptors)?;
Alice Wang1f0add02023-01-23 16:22:53 +0000195 return Ok(VerifiedBootData {
196 debug_level: DebugLevel::None,
Alice Wang91509482023-05-22 13:10:32 +0000197 kernel_digest: *kernel_descriptor.digest,
Alice Wang1f0add02023-01-23 16:22:53 +0000198 initrd_digest: None,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000199 public_key: trusted_public_key,
Alice Wangab0d0202023-05-17 08:07:41 +0000200 capabilities,
Shikha Panwara26f16a2023-09-27 09:39:00 +0000201 rollback_index,
Alice Wang1f0add02023-01-23 16:22:53 +0000202 });
Alice Wang86383df2023-01-11 10:03:56 +0000203 }
Alice Wang5c1a7562023-01-13 17:19:57 +0000204
Alice Wang75d05632023-01-25 13:31:18 +0000205 let initrd = initrd.unwrap();
David Pursellb59bcc42023-11-10 16:59:19 -0800206 let mut initrd_ops = Ops::new(&payload);
207 let (debug_level, initrd_partition_name) =
208 if verify_initrd(&mut initrd_ops, PartitionName::InitrdNormal, initrd).is_ok() {
209 (DebugLevel::None, PartitionName::InitrdNormal)
210 } else if verify_initrd(&mut initrd_ops, PartitionName::InitrdDebug, initrd).is_ok() {
211 (DebugLevel::Full, PartitionName::InitrdDebug)
Alice Wang75d05632023-01-25 13:31:18 +0000212 } else {
David Pursellb59bcc42023-11-10 16:59:19 -0800213 return Err(SlotVerifyError::Verification(None).into());
Alice Wang75d05632023-01-25 13:31:18 +0000214 };
Alice Wang79985512023-05-22 08:15:36 +0000215 let initrd_descriptor = descriptors.find_hash_descriptor(initrd_partition_name)?;
Alice Wang1f0add02023-01-23 16:22:53 +0000216 Ok(VerifiedBootData {
217 debug_level,
Alice Wang91509482023-05-22 13:10:32 +0000218 kernel_digest: *kernel_descriptor.digest,
219 initrd_digest: Some(*initrd_descriptor.digest),
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000220 public_key: trusted_public_key,
Alice Wangab0d0202023-05-17 08:07:41 +0000221 capabilities,
Shikha Panwara26f16a2023-09-27 09:39:00 +0000222 rollback_index,
Alice Wang1f0add02023-01-23 16:22:53 +0000223 })
Alice Wang28cbcf12022-12-01 07:58:28 +0000224}