blob: 99bf589c1cb0ed9f001e346b72e67f724d66de83 [file] [log] [blame]
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +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
15//! Support for DICE derivation and BCC generation.
16
Alice Wang1f0add02023-01-23 16:22:53 +000017use core::mem::size_of;
Pierre-Clément Tosi1bf532b2023-11-13 11:06:20 +000018use cstr::cstr;
Alice Wang843d8312023-02-15 09:47:06 +000019use diced_open_dice::{
Alan Stokesc6e92462023-08-22 14:43:17 +010020 bcc_format_config_descriptor, bcc_handover_main_flow, hash, Config, DiceConfigValues, DiceMode,
21 Hash, InputValues, HIDDEN_SIZE,
Alice Wang843d8312023-02-15 09:47:06 +000022};
Alan Stokesa639b582023-11-22 13:14:27 +000023use pvmfw_avb::{Capability, DebugLevel, Digest, VerifiedBootData};
Alice Wang1f0add02023-01-23 16:22:53 +000024
Alice Wang31226132023-01-31 12:44:39 +000025fn to_dice_mode(debug_level: DebugLevel) -> DiceMode {
Alice Wang1f0add02023-01-23 16:22:53 +000026 match debug_level {
Alice Wang31226132023-01-31 12:44:39 +000027 DebugLevel::None => DiceMode::kDiceModeNormal,
28 DebugLevel::Full => DiceMode::kDiceModeDebug,
Alice Wang1f0add02023-01-23 16:22:53 +000029 }
30}
31
Alice Wang843d8312023-02-15 09:47:06 +000032fn to_dice_hash(verified_boot_data: &VerifiedBootData) -> diced_open_dice::Result<Hash> {
Alice Wang1f0add02023-01-23 16:22:53 +000033 let mut digests = [0u8; size_of::<Digest>() * 2];
34 digests[..size_of::<Digest>()].copy_from_slice(&verified_boot_data.kernel_digest);
35 if let Some(initrd_digest) = verified_boot_data.initrd_digest {
36 digests[size_of::<Digest>()..].copy_from_slice(&initrd_digest);
37 }
38 hash(&digests)
39}
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000040
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000041pub struct PartialInputs {
Pierre-Clément Tosi1cc5eb72023-02-02 11:09:18 +000042 pub code_hash: Hash,
43 pub auth_hash: Hash,
44 pub mode: DiceMode,
Shikha Panwara26f16a2023-09-27 09:39:00 +000045 pub security_version: u64,
Alan Stokesa639b582023-11-22 13:14:27 +000046 pub rkp_vm_marker: bool,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000047}
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000048
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000049impl PartialInputs {
Alice Wang843d8312023-02-15 09:47:06 +000050 pub fn new(data: &VerifiedBootData) -> diced_open_dice::Result<Self> {
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000051 let code_hash = to_dice_hash(data)?;
52 let auth_hash = hash(data.public_key)?;
53 let mode = to_dice_mode(data.debug_level);
Shikha Panwara26f16a2023-09-27 09:39:00 +000054 // We use rollback_index from vbmeta as the security_version field in dice certificate.
55 let security_version = data.rollback_index;
Alan Stokesa639b582023-11-22 13:14:27 +000056 let rkp_vm_marker = data.has_capability(Capability::RemoteAttest);
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000057
Alan Stokesa639b582023-11-22 13:14:27 +000058 Ok(Self { code_hash, auth_hash, mode, security_version, rkp_vm_marker })
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000059 }
60
Alan Stokesc4354b82023-05-04 16:06:52 +010061 pub fn write_next_bcc(
Alice Wang843d8312023-02-15 09:47:06 +000062 self,
Alan Stokesc4354b82023-05-04 16:06:52 +010063 current_bcc_handover: &[u8],
Alice Wang843d8312023-02-15 09:47:06 +000064 salt: &[u8; HIDDEN_SIZE],
Alan Stokesc4354b82023-05-04 16:06:52 +010065 next_bcc: &mut [u8],
66 ) -> diced_open_dice::Result<()> {
67 let mut config_descriptor_buffer = [0; 128];
Alan Stokesddb988c2023-11-27 11:13:06 +000068 let config = self.generate_config_descriptor(&mut config_descriptor_buffer)?;
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000069
Alan Stokesc4354b82023-05-04 16:06:52 +010070 let dice_inputs = InputValues::new(
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000071 self.code_hash,
72 Config::Descriptor(config),
73 self.auth_hash,
74 self.mode,
75 *salt,
Alan Stokesc4354b82023-05-04 16:06:52 +010076 );
77 let _ = bcc_handover_main_flow(current_bcc_handover, &dice_inputs, next_bcc)?;
78 Ok(())
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000079 }
Alan Stokesddb988c2023-11-27 11:13:06 +000080
81 fn generate_config_descriptor<'a>(
82 &self,
83 config_descriptor_buffer: &'a mut [u8],
84 ) -> diced_open_dice::Result<&'a [u8]> {
85 let config_values = DiceConfigValues {
86 component_name: Some(cstr!("vm_entry")),
87 security_version: if cfg!(dice_changes) { Some(self.security_version) } else { None },
88 rkp_vm_marker: self.rkp_vm_marker,
89 ..Default::default()
90 };
91 let config_descriptor_size =
92 bcc_format_config_descriptor(&config_values, config_descriptor_buffer)?;
93 let config = &config_descriptor_buffer[..config_descriptor_size];
94 Ok(config)
95 }
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000096}
Pierre-Clément Tosibec84662023-01-04 14:25:33 +000097
98/// Flushes data caches over the provided address range.
99///
100/// # Safety
101///
Alan Stokesddb988c2023-11-27 11:13:06 +0000102/// The provided address and size must be to an address range that is valid for read and write
103/// (typically on the stack, .bss, .data, or provided BCC) from a single allocation
104/// (e.g. stack array).
Pierre-Clément Tosibec84662023-01-04 14:25:33 +0000105#[no_mangle]
Alan Stokesddb988c2023-11-27 11:13:06 +0000106#[cfg(not(test))]
107unsafe extern "C" fn DiceClearMemory(
108 _ctx: *mut core::ffi::c_void,
109 size: usize,
110 addr: *mut core::ffi::c_void,
111) {
112 use core::slice;
113 use vmbase::memory::flushed_zeroize;
114
115 // SAFETY: We require our caller to provide a valid range within a single object. The open-dice
116 // always calls this on individual stack-allocated arrays which ensures that.
Pierre-Clément Tosibec84662023-01-04 14:25:33 +0000117 let region = unsafe { slice::from_raw_parts_mut(addr as *mut u8, size) };
118 flushed_zeroize(region)
119}
Alan Stokesddb988c2023-11-27 11:13:06 +0000120
121#[cfg(test)]
122mod tests {
123 use super::*;
124 use ciborium::Value;
125 use std::collections::HashMap;
126 use std::vec;
127
128 const COMPONENT_NAME_KEY: i64 = -70002;
129 const COMPONENT_VERSION_KEY: i64 = -70003;
130 const RESETTABLE_KEY: i64 = -70004;
131 const SECURITY_VERSION_KEY: i64 = -70005;
132 const RKP_VM_MARKER_KEY: i64 = -70006;
133
134 const BASE_VB_DATA: VerifiedBootData = VerifiedBootData {
135 debug_level: DebugLevel::None,
136 kernel_digest: [1u8; size_of::<Digest>()],
137 initrd_digest: Some([2u8; size_of::<Digest>()]),
138 public_key: b"public key",
139 capabilities: vec![],
140 rollback_index: 42,
141 };
142
143 #[test]
144 fn base_data_conversion() {
145 let vb_data = BASE_VB_DATA;
146 let inputs = PartialInputs::new(&vb_data).unwrap();
147
148 assert_eq!(inputs.mode, DiceMode::kDiceModeNormal);
149 assert_eq!(inputs.security_version, 42);
150 assert!(!inputs.rkp_vm_marker);
151
152 // TODO(b/313608219): Consider checks for code_hash and possibly auth_hash.
153 }
154
155 #[test]
156 fn debuggable_conversion() {
157 let vb_data = VerifiedBootData { debug_level: DebugLevel::Full, ..BASE_VB_DATA };
158 let inputs = PartialInputs::new(&vb_data).unwrap();
159
160 assert_eq!(inputs.mode, DiceMode::kDiceModeDebug);
161 }
162
163 #[test]
164 fn rkp_vm_conversion() {
165 let vb_data =
166 VerifiedBootData { capabilities: vec![Capability::RemoteAttest], ..BASE_VB_DATA };
167 let inputs = PartialInputs::new(&vb_data).unwrap();
168
169 assert!(inputs.rkp_vm_marker);
170 }
171
172 #[test]
173 fn base_config_descriptor() {
174 let vb_data = BASE_VB_DATA;
175 let inputs = PartialInputs::new(&vb_data).unwrap();
176 let config_map = decode_config_descriptor(&inputs);
177
178 assert_eq!(config_map.get(&COMPONENT_NAME_KEY).unwrap().as_text().unwrap(), "vm_entry");
179 assert_eq!(config_map.get(&COMPONENT_VERSION_KEY), None);
180 assert_eq!(config_map.get(&RESETTABLE_KEY), None);
181 if cfg!(dice_changes) {
182 assert_eq!(
183 config_map.get(&SECURITY_VERSION_KEY).unwrap().as_integer().unwrap(),
184 42.into()
185 );
186 } else {
187 assert_eq!(config_map.get(&SECURITY_VERSION_KEY), None);
188 }
189 assert_eq!(config_map.get(&RKP_VM_MARKER_KEY), None);
190 }
191
192 #[test]
193 fn config_descriptor_with_rkp_vm() {
194 let vb_data =
195 VerifiedBootData { capabilities: vec![Capability::RemoteAttest], ..BASE_VB_DATA };
196 let inputs = PartialInputs::new(&vb_data).unwrap();
197 let config_map = decode_config_descriptor(&inputs);
198
199 assert!(config_map.get(&RKP_VM_MARKER_KEY).unwrap().is_null());
200 }
201
202 fn decode_config_descriptor(inputs: &PartialInputs) -> HashMap<i64, Value> {
203 let mut buffer = [0; 128];
204 let config_descriptor = inputs.generate_config_descriptor(&mut buffer).unwrap();
205
206 let cbor_map =
207 cbor_util::deserialize::<Value>(config_descriptor).unwrap().into_map().unwrap();
208
209 cbor_map
210 .into_iter()
211 .map(|(k, v)| ((k.into_integer().unwrap().try_into().unwrap()), v))
212 .collect()
213 }
214}