blob: b03506cbf4681203a11c35816d75cd5399202e74 [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 Wang1f0add02023-01-23 16:22:53 +000017use crate::descriptor::{Digest, HashDescriptors};
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 Wangf2752862023-01-18 11:51:25 +000021use avb_bindgen::{AvbPartitionData, AvbVBMetaData};
22use core::ffi::c_char;
Alice Wang28cbcf12022-12-01 07:58:28 +000023
Alice Wang1f0add02023-01-23 16:22:53 +000024/// Verified data returned when the payload verification succeeds.
Pierre-Clément Tosi81ca0802023-02-14 10:41:38 +000025#[derive(Debug, PartialEq, Eq)]
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000026pub struct VerifiedBootData<'a> {
Alice Wang1f0add02023-01-23 16:22:53 +000027 /// DebugLevel of the VM.
28 pub debug_level: DebugLevel,
29 /// Kernel digest.
30 pub kernel_digest: Digest,
31 /// Initrd digest if initrd exists.
32 pub initrd_digest: Option<Digest>,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000033 /// Trusted public key.
34 pub public_key: &'a [u8],
Alice Wang1f0add02023-01-23 16:22:53 +000035}
36
Alice Wang5c1a7562023-01-13 17:19:57 +000037/// This enum corresponds to the `DebugLevel` in `VirtualMachineConfig`.
Alice Wang1f0add02023-01-23 16:22:53 +000038#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Alice Wang5c1a7562023-01-13 17:19:57 +000039pub enum DebugLevel {
40 /// Not debuggable at all.
41 None,
42 /// Fully debuggable.
43 Full,
44}
45
Alice Wangd3f28ae2023-01-25 10:41:40 +000046fn verify_only_one_vbmeta_exists(
47 vbmeta_images: &[AvbVBMetaData],
48) -> Result<(), AvbSlotVerifyError> {
49 if vbmeta_images.len() == 1 {
50 Ok(())
51 } else {
52 Err(AvbSlotVerifyError::InvalidMetadata)
53 }
54}
55
Alice Wang9dfb2962023-01-18 10:01:34 +000056fn verify_vbmeta_is_from_kernel_partition(
57 vbmeta_image: &AvbVBMetaData,
58) -> Result<(), AvbSlotVerifyError> {
59 match (vbmeta_image.partition_name as *const c_char).try_into() {
60 Ok(PartitionName::Kernel) => Ok(()),
61 _ => Err(AvbSlotVerifyError::InvalidMetadata),
62 }
63}
64
Alice Wangf2752862023-01-18 11:51:25 +000065fn verify_vbmeta_has_only_one_hash_descriptor(
66 hash_descriptors: &HashDescriptors,
67) -> Result<(), AvbSlotVerifyError> {
68 if hash_descriptors.len() == 1 {
69 Ok(())
70 } else {
71 Err(AvbSlotVerifyError::InvalidMetadata)
72 }
73}
74
Alice Wang75d05632023-01-25 13:31:18 +000075fn verify_loaded_partition_has_expected_length(
76 loaded_partitions: &[AvbPartitionData],
77 partition_name: PartitionName,
78 expected_len: usize,
79) -> Result<(), AvbSlotVerifyError> {
80 if loaded_partitions.len() != 1 {
81 // Only one partition should be loaded in each verify result.
82 return Err(AvbSlotVerifyError::Io);
83 }
84 let loaded_partition = loaded_partitions[0];
85 if !PartitionName::try_from(loaded_partition.partition_name as *const c_char)
86 .map_or(false, |p| p == partition_name)
87 {
88 // Only the requested partition should be loaded.
89 return Err(AvbSlotVerifyError::Io);
90 }
91 if loaded_partition.data_size == expected_len {
92 Ok(())
93 } else {
94 Err(AvbSlotVerifyError::Verification)
95 }
96}
97
Alice Wangf3d96b12022-12-15 13:10:47 +000098/// Verifies the payload (signed kernel + initrd) against the trusted public key.
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000099pub fn verify_payload<'a>(
Alice Wang6b486f12023-01-06 13:12:16 +0000100 kernel: &[u8],
101 initrd: Option<&[u8]>,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000102 trusted_public_key: &'a [u8],
103) -> Result<VerifiedBootData<'a>, AvbSlotVerifyError> {
Alice Wang167ab3f2023-01-23 13:39:25 +0000104 let mut payload = Payload::new(kernel, initrd, trusted_public_key);
105 let mut ops = Ops::from(&mut payload);
106 let kernel_verify_result = ops.verify_partition(PartitionName::Kernel.as_cstr())?;
Alice Wang75d05632023-01-25 13:31:18 +0000107
Alice Wang86383df2023-01-11 10:03:56 +0000108 let vbmeta_images = kernel_verify_result.vbmeta_images()?;
Alice Wangd3f28ae2023-01-25 10:41:40 +0000109 verify_only_one_vbmeta_exists(vbmeta_images)?;
Alice Wang9dfb2962023-01-18 10:01:34 +0000110 let vbmeta_image = vbmeta_images[0];
111 verify_vbmeta_is_from_kernel_partition(&vbmeta_image)?;
Alice Wangf2752862023-01-18 11:51:25 +0000112 // SAFETY: It is safe because the `vbmeta_image` is collected from `AvbSlotVerifyData`,
113 // which is returned by `avb_slot_verify()` when the verification succeeds. It is
114 // guaranteed by libavb to be non-null and to point to a valid VBMeta structure.
115 let hash_descriptors = unsafe { HashDescriptors::from_vbmeta(vbmeta_image)? };
Alice Wang1f0add02023-01-23 16:22:53 +0000116 let kernel_descriptor = hash_descriptors.find(PartitionName::Kernel)?;
Alice Wangd3f28ae2023-01-25 10:41:40 +0000117
Alice Wang167ab3f2023-01-23 13:39:25 +0000118 if initrd.is_none() {
Alice Wangf2752862023-01-18 11:51:25 +0000119 verify_vbmeta_has_only_one_hash_descriptor(&hash_descriptors)?;
Alice Wang1f0add02023-01-23 16:22:53 +0000120 return Ok(VerifiedBootData {
121 debug_level: DebugLevel::None,
122 kernel_digest: kernel_descriptor.digest,
123 initrd_digest: None,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000124 public_key: trusted_public_key,
Alice Wang1f0add02023-01-23 16:22:53 +0000125 });
Alice Wang86383df2023-01-11 10:03:56 +0000126 }
Alice Wang5c1a7562023-01-13 17:19:57 +0000127
Alice Wang75d05632023-01-25 13:31:18 +0000128 let initrd = initrd.unwrap();
129 let (debug_level, initrd_verify_result, initrd_partition_name) =
130 if let Ok(result) = ops.verify_partition(PartitionName::InitrdNormal.as_cstr()) {
131 (DebugLevel::None, result, PartitionName::InitrdNormal)
132 } else if let Ok(result) = ops.verify_partition(PartitionName::InitrdDebug.as_cstr()) {
133 (DebugLevel::Full, result, PartitionName::InitrdDebug)
134 } else {
135 return Err(AvbSlotVerifyError::Verification);
136 };
137 let loaded_partitions = initrd_verify_result.loaded_partitions()?;
138 verify_loaded_partition_has_expected_length(
139 loaded_partitions,
140 initrd_partition_name,
141 initrd.len(),
142 )?;
Alice Wang1f0add02023-01-23 16:22:53 +0000143 let initrd_descriptor = hash_descriptors.find(initrd_partition_name)?;
144 Ok(VerifiedBootData {
145 debug_level,
146 kernel_digest: kernel_descriptor.digest,
147 initrd_digest: Some(initrd_descriptor.digest),
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000148 public_key: trusted_public_key,
Alice Wang1f0add02023-01-23 16:22:53 +0000149 })
Alice Wang28cbcf12022-12-01 07:58:28 +0000150}