blob: c5ed8cc6fa8d194019abe6fe23687e9e78a7e1fe [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 Wangf2752862023-01-18 11:51:25 +000018use crate::error::AvbSlotVerifyError;
Alice Wang167ab3f2023-01-23 13:39:25 +000019use crate::ops::{Ops, Payload};
Alice Wang8077a862023-01-18 16:06:37 +000020use crate::partition::PartitionName;
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
Alice Wang1f0add02023-01-23 16:22:53 +000026/// Verified data returned when the payload verification succeeds.
Pierre-Clément Tosi81ca0802023-02-14 10:41:38 +000027#[derive(Debug, PartialEq, Eq)]
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000028pub struct VerifiedBootData<'a> {
Alice Wang1f0add02023-01-23 16:22:53 +000029 /// DebugLevel of the VM.
30 pub debug_level: DebugLevel,
31 /// Kernel digest.
32 pub kernel_digest: Digest,
33 /// Initrd digest if initrd exists.
34 pub initrd_digest: Option<Digest>,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000035 /// Trusted public key.
36 pub public_key: &'a [u8],
Alice Wangab0d0202023-05-17 08:07:41 +000037 /// VM capabilities.
38 pub capabilities: Vec<Capability>,
Alice Wang1f0add02023-01-23 16:22:53 +000039}
40
Alice Wang5c1a7562023-01-13 17:19:57 +000041/// This enum corresponds to the `DebugLevel` in `VirtualMachineConfig`.
Alice Wang1f0add02023-01-23 16:22:53 +000042#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Alice Wang5c1a7562023-01-13 17:19:57 +000043pub enum DebugLevel {
44 /// Not debuggable at all.
45 None,
46 /// Fully debuggable.
47 Full,
48}
49
Alice Wangab0d0202023-05-17 08:07:41 +000050/// VM Capability.
51#[derive(Debug, PartialEq, Eq)]
52pub enum Capability {
53 /// Remote attestation.
54 RemoteAttest,
55}
56
57impl Capability {
58 const KEY: &[u8] = b"com.android.virt.cap";
59 const REMOTE_ATTEST: &[u8] = b"remote_attest";
60 const SEPARATOR: u8 = b'|';
61
62 fn get_capabilities(property_value: &[u8]) -> Result<Vec<Self>, AvbSlotVerifyError> {
63 let mut res = Vec::new();
64
65 for v in property_value.split(|b| *b == Self::SEPARATOR) {
66 let cap = match v {
67 Self::REMOTE_ATTEST => Self::RemoteAttest,
68 _ => return Err(AvbSlotVerifyError::UnknownVbmetaProperty),
69 };
70 if res.contains(&cap) {
71 return Err(AvbSlotVerifyError::InvalidMetadata);
72 }
73 res.push(cap);
74 }
75 Ok(res)
76 }
77}
78
Alice Wangd3f28ae2023-01-25 10:41:40 +000079fn verify_only_one_vbmeta_exists(
80 vbmeta_images: &[AvbVBMetaData],
81) -> Result<(), AvbSlotVerifyError> {
82 if vbmeta_images.len() == 1 {
83 Ok(())
84 } else {
85 Err(AvbSlotVerifyError::InvalidMetadata)
86 }
87}
88
Alice Wang9dfb2962023-01-18 10:01:34 +000089fn verify_vbmeta_is_from_kernel_partition(
90 vbmeta_image: &AvbVBMetaData,
91) -> Result<(), AvbSlotVerifyError> {
92 match (vbmeta_image.partition_name as *const c_char).try_into() {
93 Ok(PartitionName::Kernel) => Ok(()),
94 _ => Err(AvbSlotVerifyError::InvalidMetadata),
95 }
96}
97
Alice Wangf2752862023-01-18 11:51:25 +000098fn verify_vbmeta_has_only_one_hash_descriptor(
Alice Wang79985512023-05-22 08:15:36 +000099 descriptors: &Descriptors,
Alice Wangf2752862023-01-18 11:51:25 +0000100) -> Result<(), AvbSlotVerifyError> {
Alice Wang79985512023-05-22 08:15:36 +0000101 if descriptors.num_hash_descriptor() == 1 {
Alice Wangf2752862023-01-18 11:51:25 +0000102 Ok(())
103 } else {
104 Err(AvbSlotVerifyError::InvalidMetadata)
105 }
106}
107
Alice Wang75d05632023-01-25 13:31:18 +0000108fn verify_loaded_partition_has_expected_length(
109 loaded_partitions: &[AvbPartitionData],
110 partition_name: PartitionName,
111 expected_len: usize,
112) -> Result<(), AvbSlotVerifyError> {
113 if loaded_partitions.len() != 1 {
114 // Only one partition should be loaded in each verify result.
115 return Err(AvbSlotVerifyError::Io);
116 }
117 let loaded_partition = loaded_partitions[0];
118 if !PartitionName::try_from(loaded_partition.partition_name as *const c_char)
119 .map_or(false, |p| p == partition_name)
120 {
121 // Only the requested partition should be loaded.
122 return Err(AvbSlotVerifyError::Io);
123 }
124 if loaded_partition.data_size == expected_len {
125 Ok(())
126 } else {
127 Err(AvbSlotVerifyError::Verification)
128 }
129}
130
Alice Wangab0d0202023-05-17 08:07:41 +0000131/// Verifies that the vbmeta contains at most one property descriptor and it indicates the
132/// vm type is service VM.
133fn verify_property_and_get_capabilities(
134 descriptors: &Descriptors,
135) -> Result<Vec<Capability>, AvbSlotVerifyError> {
136 if !descriptors.has_property_descriptor() {
137 return Ok(vec![]);
138 }
139 descriptors
140 .find_property_value(Capability::KEY)
141 .ok_or(AvbSlotVerifyError::UnknownVbmetaProperty)
142 .and_then(Capability::get_capabilities)
143}
144
Alice Wangf3d96b12022-12-15 13:10:47 +0000145/// Verifies the payload (signed kernel + initrd) against the trusted public key.
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000146pub fn verify_payload<'a>(
Alice Wang6b486f12023-01-06 13:12:16 +0000147 kernel: &[u8],
148 initrd: Option<&[u8]>,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000149 trusted_public_key: &'a [u8],
150) -> Result<VerifiedBootData<'a>, AvbSlotVerifyError> {
Alice Wang167ab3f2023-01-23 13:39:25 +0000151 let mut payload = Payload::new(kernel, initrd, trusted_public_key);
152 let mut ops = Ops::from(&mut payload);
153 let kernel_verify_result = ops.verify_partition(PartitionName::Kernel.as_cstr())?;
Alice Wang75d05632023-01-25 13:31:18 +0000154
Alice Wang86383df2023-01-11 10:03:56 +0000155 let vbmeta_images = kernel_verify_result.vbmeta_images()?;
Alice Wangd3f28ae2023-01-25 10:41:40 +0000156 verify_only_one_vbmeta_exists(vbmeta_images)?;
Alice Wang9dfb2962023-01-18 10:01:34 +0000157 let vbmeta_image = vbmeta_images[0];
158 verify_vbmeta_is_from_kernel_partition(&vbmeta_image)?;
Alice Wangf2752862023-01-18 11:51:25 +0000159 // SAFETY: It is safe because the `vbmeta_image` is collected from `AvbSlotVerifyData`,
160 // which is returned by `avb_slot_verify()` when the verification succeeds. It is
161 // guaranteed by libavb to be non-null and to point to a valid VBMeta structure.
Alice Wang79985512023-05-22 08:15:36 +0000162 let descriptors = unsafe { Descriptors::from_vbmeta(vbmeta_image)? };
Alice Wangab0d0202023-05-17 08:07:41 +0000163 let capabilities = verify_property_and_get_capabilities(&descriptors)?;
Alice Wang79985512023-05-22 08:15:36 +0000164 let kernel_descriptor = descriptors.find_hash_descriptor(PartitionName::Kernel)?;
Alice Wangd3f28ae2023-01-25 10:41:40 +0000165
Alice Wang167ab3f2023-01-23 13:39:25 +0000166 if initrd.is_none() {
Alice Wang79985512023-05-22 08:15:36 +0000167 verify_vbmeta_has_only_one_hash_descriptor(&descriptors)?;
Alice Wang1f0add02023-01-23 16:22:53 +0000168 return Ok(VerifiedBootData {
169 debug_level: DebugLevel::None,
Alice Wang91509482023-05-22 13:10:32 +0000170 kernel_digest: *kernel_descriptor.digest,
Alice Wang1f0add02023-01-23 16:22:53 +0000171 initrd_digest: None,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000172 public_key: trusted_public_key,
Alice Wangab0d0202023-05-17 08:07:41 +0000173 capabilities,
Alice Wang1f0add02023-01-23 16:22:53 +0000174 });
Alice Wang86383df2023-01-11 10:03:56 +0000175 }
Alice Wang5c1a7562023-01-13 17:19:57 +0000176
Alice Wang75d05632023-01-25 13:31:18 +0000177 let initrd = initrd.unwrap();
178 let (debug_level, initrd_verify_result, initrd_partition_name) =
179 if let Ok(result) = ops.verify_partition(PartitionName::InitrdNormal.as_cstr()) {
180 (DebugLevel::None, result, PartitionName::InitrdNormal)
181 } else if let Ok(result) = ops.verify_partition(PartitionName::InitrdDebug.as_cstr()) {
182 (DebugLevel::Full, result, PartitionName::InitrdDebug)
183 } else {
184 return Err(AvbSlotVerifyError::Verification);
185 };
186 let loaded_partitions = initrd_verify_result.loaded_partitions()?;
187 verify_loaded_partition_has_expected_length(
188 loaded_partitions,
189 initrd_partition_name,
190 initrd.len(),
191 )?;
Alice Wang79985512023-05-22 08:15:36 +0000192 let initrd_descriptor = descriptors.find_hash_descriptor(initrd_partition_name)?;
Alice Wang1f0add02023-01-23 16:22:53 +0000193 Ok(VerifiedBootData {
194 debug_level,
Alice Wang91509482023-05-22 13:10:32 +0000195 kernel_digest: *kernel_descriptor.digest,
196 initrd_digest: Some(*initrd_descriptor.digest),
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000197 public_key: trusted_public_key,
Alice Wangab0d0202023-05-17 08:07:41 +0000198 capabilities,
Alice Wang1f0add02023-01-23 16:22:53 +0000199 })
Alice Wang28cbcf12022-12-01 07:58:28 +0000200}