blob: dc7b64e1fc737d53ded3330d10fcba48e5d42a85 [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
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -080015//! Support for DICE derivation and DICE chain generation.
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +000016extern crate alloc;
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000017
Pierre-Clément Tosif5d34852025-03-03 11:44:43 -080018pub(crate) mod chain;
19
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +000020use alloc::format;
Pierre-Clément Tosi677de942025-02-11 18:23:44 +000021use alloc::string::String;
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +000022use alloc::vec::Vec;
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -080023pub use chain::DiceChainInfo;
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +000024use ciborium::cbor;
25use ciborium::Value;
Alice Wang1f0add02023-01-23 16:22:53 +000026use core::mem::size_of;
Alice Wang843d8312023-02-15 09:47:06 +000027use diced_open_dice::{
Alice Wang87fbc4b2024-11-05 13:09:58 +000028 bcc_handover_main_flow, hash, Config, DiceContext, DiceMode, Hash, InputValues, HIDDEN_SIZE,
Alice Wang843d8312023-02-15 09:47:06 +000029};
Alan Stokesa639b582023-11-22 13:14:27 +000030use pvmfw_avb::{Capability, DebugLevel, Digest, VerifiedBootData};
Andrew Walbran47d316e2024-11-28 18:41:09 +000031use zerocopy::Immutable;
32use zerocopy::IntoBytes;
33use zerocopy::KnownLayout;
Alice Wang1f0add02023-01-23 16:22:53 +000034
Shikha Panwar47e5b612024-05-20 19:50:02 +000035// pVM firmware (like other VM components) is expected to populate some fields in DICE
36// Configuration Descriptor. See dice_for_avf_guest.cddl
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +000037const COMPONENT_NAME_KEY: i64 = -70002;
38const SECURITY_VERSION_KEY: i64 = -70005;
39const RKP_VM_MARKER_KEY: i64 = -70006;
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +000040const INSTANCE_HASH_KEY: i64 = -71003;
41
42#[derive(Debug)]
43pub enum Error {
44 /// Error in CBOR operations
Stephen Hinese1b42892024-08-07 11:03:44 -070045 #[allow(dead_code)]
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +000046 CborError(ciborium::value::Error),
47 /// Error in DICE operations
Stephen Hinese1b42892024-08-07 11:03:44 -070048 #[allow(dead_code)]
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +000049 DiceError(diced_open_dice::DiceError),
50}
51
52impl From<ciborium::value::Error> for Error {
53 fn from(e: ciborium::value::Error) -> Self {
54 Self::CborError(e)
55 }
56}
57
58impl From<diced_open_dice::DiceError> for Error {
59 fn from(e: diced_open_dice::DiceError) -> Self {
60 Self::DiceError(e)
61 }
62}
63
64// DICE in pvmfw result type.
65type Result<T> = core::result::Result<T, Error>;
66
Alice Wang31226132023-01-31 12:44:39 +000067fn to_dice_mode(debug_level: DebugLevel) -> DiceMode {
Alice Wang1f0add02023-01-23 16:22:53 +000068 match debug_level {
Alice Wang31226132023-01-31 12:44:39 +000069 DebugLevel::None => DiceMode::kDiceModeNormal,
70 DebugLevel::Full => DiceMode::kDiceModeDebug,
Alice Wang1f0add02023-01-23 16:22:53 +000071 }
72}
73
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +000074fn to_dice_hash(verified_boot_data: &VerifiedBootData) -> Result<Hash> {
Alice Wang1f0add02023-01-23 16:22:53 +000075 let mut digests = [0u8; size_of::<Digest>() * 2];
76 digests[..size_of::<Digest>()].copy_from_slice(&verified_boot_data.kernel_digest);
77 if let Some(initrd_digest) = verified_boot_data.initrd_digest {
78 digests[size_of::<Digest>()..].copy_from_slice(&initrd_digest);
79 }
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +000080 Ok(hash(&digests)?)
Alice Wang1f0add02023-01-23 16:22:53 +000081}
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000082
Shikha Panwarf3acfd12024-05-28 15:48:13 +000083#[derive(Clone)]
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000084pub struct PartialInputs {
Pierre-Clément Tosi1cc5eb72023-02-02 11:09:18 +000085 pub code_hash: Hash,
86 pub auth_hash: Hash,
87 pub mode: DiceMode,
Shikha Panwara26f16a2023-09-27 09:39:00 +000088 pub security_version: u64,
Alan Stokesa639b582023-11-22 13:14:27 +000089 pub rkp_vm_marker: bool,
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +000090 pub instance_hash: Option<Hash>,
Pierre-Clément Tosi677de942025-02-11 18:23:44 +000091 component_name: String,
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000092}
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000093
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000094impl PartialInputs {
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +000095 pub fn new(data: &VerifiedBootData, instance_hash: Option<Hash>) -> Result<Self> {
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +000096 let code_hash = to_dice_hash(data)?;
97 let auth_hash = hash(data.public_key)?;
98 let mode = to_dice_mode(data.debug_level);
Pierre-Clément Tosi677de942025-02-11 18:23:44 +000099 let component_name = data.name.clone().unwrap_or(String::from("vm_entry"));
Shikha Panwara26f16a2023-09-27 09:39:00 +0000100 // We use rollback_index from vbmeta as the security_version field in dice certificate.
101 let security_version = data.rollback_index;
Alice Wang8b5274a2025-01-17 09:31:43 +0000102 let rkp_vm_marker = data.has_capability(Capability::RemoteAttest)
103 || data.has_capability(Capability::TrustySecurityVm);
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +0000104
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000105 Ok(Self {
106 code_hash,
107 auth_hash,
108 mode,
109 security_version,
110 rkp_vm_marker,
111 instance_hash,
112 component_name,
113 })
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000114 }
115
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800116 pub fn write_next_handover(
Alice Wang843d8312023-02-15 09:47:06 +0000117 self,
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800118 current_handover: &[u8],
Alice Wang843d8312023-02-15 09:47:06 +0000119 salt: &[u8; HIDDEN_SIZE],
Shikha Panwarffadd4d2024-05-28 13:47:56 +0000120 deferred_rollback_protection: bool,
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800121 next_handover: &mut [u8],
Alice Wang87fbc4b2024-11-05 13:09:58 +0000122 context: DiceContext,
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +0000123 ) -> Result<()> {
124 let config = self
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000125 .generate_config_descriptor()
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +0000126 .map_err(|_| diced_open_dice::DiceError::InvalidInput)?;
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000127
Alan Stokesc4354b82023-05-04 16:06:52 +0100128 let dice_inputs = InputValues::new(
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000129 self.code_hash,
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +0000130 Config::Descriptor(&config),
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000131 self.auth_hash,
132 self.mode,
Shikha Panwarffadd4d2024-05-28 13:47:56 +0000133 self.make_hidden(salt, deferred_rollback_protection)?,
Alan Stokesc4354b82023-05-04 16:06:52 +0100134 );
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800135 let _ = bcc_handover_main_flow(current_handover, &dice_inputs, next_handover, context)?;
Alan Stokesc4354b82023-05-04 16:06:52 +0100136 Ok(())
Pierre-Clément Tosif58f3a32023-02-02 16:24:23 +0000137 }
Alan Stokesddb988c2023-11-27 11:13:06 +0000138
Shikha Panwarffadd4d2024-05-28 13:47:56 +0000139 fn make_hidden(
140 &self,
141 salt: &[u8; HIDDEN_SIZE],
142 deferred_rollback_protection: bool,
143 ) -> diced_open_dice::Result<[u8; HIDDEN_SIZE]> {
Alan Stokesa17cfba2024-02-14 17:34:51 +0000144 // We want to make sure we get a different sealing CDI for:
145 // - VMs with different salt values
146 // - An RKP VM and any other VM (regardless of salt)
Shikha Panwarffadd4d2024-05-28 13:47:56 +0000147 // - depending on whether rollback protection has been deferred to payload. This ensures the
148 // adversary cannot leak the secrets by using old images & setting
149 // `deferred_rollback_protection` to true.
Alan Stokesa17cfba2024-02-14 17:34:51 +0000150 // The hidden input for DICE affects the sealing CDI (but the values in the config
151 // descriptor do not).
152 // Since the hidden input has to be a fixed size, create it as a hash of the values we
153 // want included.
Andrew Walbran47d316e2024-11-28 18:41:09 +0000154 #[derive(Immutable, IntoBytes, KnownLayout)]
Alan Stokesa17cfba2024-02-14 17:34:51 +0000155 #[repr(C, packed)]
156 struct HiddenInput {
157 rkp_vm_marker: bool,
158 salt: [u8; HIDDEN_SIZE],
Shikha Panwarffadd4d2024-05-28 13:47:56 +0000159 deferred_rollback_protection: bool,
Alan Stokesa17cfba2024-02-14 17:34:51 +0000160 }
Shikha Panwarffadd4d2024-05-28 13:47:56 +0000161 hash(
162 HiddenInput {
163 rkp_vm_marker: self.rkp_vm_marker,
164 salt: *salt,
165 deferred_rollback_protection,
166 }
167 .as_bytes(),
168 )
Alan Stokesa17cfba2024-02-14 17:34:51 +0000169 }
170
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000171 fn generate_config_descriptor(&self) -> Result<Vec<u8>> {
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +0000172 let mut config = Vec::with_capacity(4);
Pierre-Clément Tosi677de942025-02-11 18:23:44 +0000173 config.push((cbor!(COMPONENT_NAME_KEY)?, cbor!(self.component_name.as_str())?));
Alice Wangf13bc4b2025-01-17 10:11:09 +0000174 config.push((cbor!(SECURITY_VERSION_KEY)?, cbor!(self.security_version)?));
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +0000175 if self.rkp_vm_marker {
176 config.push((cbor!(RKP_VM_MARKER_KEY)?, Value::Null))
177 }
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000178 if let Some(instance_hash) = self.instance_hash {
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +0000179 config.push((cbor!(INSTANCE_HASH_KEY)?, Value::from(instance_hash.as_slice())));
180 }
181 let config = Value::Map(config);
182 Ok(cbor_util::serialize(&config).map_err(|e| {
183 ciborium::value::Error::Custom(format!("Error in serialization: {e:?}"))
184 })?)
Alan Stokesddb988c2023-11-27 11:13:06 +0000185 }
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +0000186}
Pierre-Clément Tosibec84662023-01-04 14:25:33 +0000187
Alan Stokesddb988c2023-11-27 11:13:06 +0000188#[cfg(test)]
189mod tests {
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000190 use crate::{
191 Hash, PartialInputs, COMPONENT_NAME_KEY, INSTANCE_HASH_KEY, RKP_VM_MARKER_KEY,
192 SECURITY_VERSION_KEY,
193 };
Alan Stokesddb988c2023-11-27 11:13:06 +0000194 use ciborium::Value;
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800195 use diced_open_dice::bcc_handover_parse;
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000196 use diced_open_dice::DiceArtifacts;
Alice Wang87fbc4b2024-11-05 13:09:58 +0000197 use diced_open_dice::DiceContext;
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000198 use diced_open_dice::DiceMode;
Alice Wang87fbc4b2024-11-05 13:09:58 +0000199 use diced_open_dice::KeyAlgorithm;
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000200 use diced_open_dice::HIDDEN_SIZE;
Alice Wang87fbc4b2024-11-05 13:09:58 +0000201 use diced_sample_inputs::make_sample_bcc_and_cdis;
Alice Wang4dc62912024-12-11 08:27:15 +0000202 use hwtrust::{dice, session::Session};
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000203 use pvmfw_avb::Capability;
204 use pvmfw_avb::DebugLevel;
205 use pvmfw_avb::Digest;
206 use pvmfw_avb::VerifiedBootData;
Alan Stokesddb988c2023-11-27 11:13:06 +0000207 use std::collections::HashMap;
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000208 use std::mem::size_of;
Alan Stokesddb988c2023-11-27 11:13:06 +0000209 use std::vec;
210
Alan Stokesddb988c2023-11-27 11:13:06 +0000211 const COMPONENT_VERSION_KEY: i64 = -70003;
212 const RESETTABLE_KEY: i64 = -70004;
Alan Stokesddb988c2023-11-27 11:13:06 +0000213 const BASE_VB_DATA: VerifiedBootData = VerifiedBootData {
214 debug_level: DebugLevel::None,
215 kernel_digest: [1u8; size_of::<Digest>()],
216 initrd_digest: Some([2u8; size_of::<Digest>()]),
217 public_key: b"public key",
Pierre-Clément Tosif1369352024-12-02 18:55:08 +0000218 name: None,
Alan Stokesddb988c2023-11-27 11:13:06 +0000219 capabilities: vec![],
220 rollback_index: 42,
Pierre-Clément Tosi938b4fb2024-11-26 12:59:47 +0000221 page_size: None,
Alan Stokesddb988c2023-11-27 11:13:06 +0000222 };
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +0000223 const HASH: Hash = *b"sixtyfourbyteslongsentencearerarebutletsgiveitatrycantbethathard";
Alan Stokesddb988c2023-11-27 11:13:06 +0000224
225 #[test]
226 fn base_data_conversion() {
227 let vb_data = BASE_VB_DATA;
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000228 let inputs = PartialInputs::new(&vb_data, None).unwrap();
Alan Stokesddb988c2023-11-27 11:13:06 +0000229
230 assert_eq!(inputs.mode, DiceMode::kDiceModeNormal);
231 assert_eq!(inputs.security_version, 42);
232 assert!(!inputs.rkp_vm_marker);
233
234 // TODO(b/313608219): Consider checks for code_hash and possibly auth_hash.
235 }
236
237 #[test]
238 fn debuggable_conversion() {
239 let vb_data = VerifiedBootData { debug_level: DebugLevel::Full, ..BASE_VB_DATA };
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000240 let inputs = PartialInputs::new(&vb_data, None).unwrap();
Alan Stokesddb988c2023-11-27 11:13:06 +0000241
242 assert_eq!(inputs.mode, DiceMode::kDiceModeDebug);
243 }
244
245 #[test]
246 fn rkp_vm_conversion() {
247 let vb_data =
248 VerifiedBootData { capabilities: vec![Capability::RemoteAttest], ..BASE_VB_DATA };
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000249 let inputs = PartialInputs::new(&vb_data, None).unwrap();
Alan Stokesddb988c2023-11-27 11:13:06 +0000250
251 assert!(inputs.rkp_vm_marker);
252 }
253
254 #[test]
255 fn base_config_descriptor() {
256 let vb_data = BASE_VB_DATA;
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000257 let inputs = PartialInputs::new(&vb_data, None).unwrap();
258 let config_map = decode_config_descriptor(&inputs);
Alan Stokesddb988c2023-11-27 11:13:06 +0000259
260 assert_eq!(config_map.get(&COMPONENT_NAME_KEY).unwrap().as_text().unwrap(), "vm_entry");
261 assert_eq!(config_map.get(&COMPONENT_VERSION_KEY), None);
262 assert_eq!(config_map.get(&RESETTABLE_KEY), None);
Alice Wangf13bc4b2025-01-17 10:11:09 +0000263 assert_eq!(config_map.get(&SECURITY_VERSION_KEY).unwrap().as_integer().unwrap(), 42.into());
Alan Stokesddb988c2023-11-27 11:13:06 +0000264 assert_eq!(config_map.get(&RKP_VM_MARKER_KEY), None);
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000265 assert_eq!(config_map.get(&INSTANCE_HASH_KEY), None);
Alan Stokesddb988c2023-11-27 11:13:06 +0000266 }
267
268 #[test]
Pierre-Clément Tosi677de942025-02-11 18:23:44 +0000269 fn rkp_vm_config_descriptor_has_rkp_vm_marker_and_component_name() {
Alan Stokesddb988c2023-11-27 11:13:06 +0000270 let vb_data =
271 VerifiedBootData { capabilities: vec![Capability::RemoteAttest], ..BASE_VB_DATA };
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000272 let inputs = PartialInputs::new(&vb_data, Some(HASH)).unwrap();
273 let config_map = decode_config_descriptor(&inputs);
Alan Stokesddb988c2023-11-27 11:13:06 +0000274
Pierre-Clément Tosi677de942025-02-11 18:23:44 +0000275 assert_eq!(config_map.get(&COMPONENT_NAME_KEY).unwrap().as_text().unwrap(), "vm_entry");
Alan Stokesddb988c2023-11-27 11:13:06 +0000276 assert!(config_map.get(&RKP_VM_MARKER_KEY).unwrap().is_null());
277 }
278
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +0000279 #[test]
Alice Wang8b5274a2025-01-17 09:31:43 +0000280 fn security_vm_config_descriptor_has_rkp_vm_marker() {
281 let vb_data =
282 VerifiedBootData { capabilities: vec![Capability::TrustySecurityVm], ..BASE_VB_DATA };
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000283 let inputs = PartialInputs::new(&vb_data, Some(HASH)).unwrap();
284 let config_map = decode_config_descriptor(&inputs);
Alice Wang8b5274a2025-01-17 09:31:43 +0000285
286 assert!(config_map.get(&RKP_VM_MARKER_KEY).unwrap().is_null());
287 }
288
289 #[test]
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +0000290 fn config_descriptor_with_instance_hash() {
291 let vb_data =
292 VerifiedBootData { capabilities: vec![Capability::RemoteAttest], ..BASE_VB_DATA };
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000293 let inputs = PartialInputs::new(&vb_data, Some(HASH)).unwrap();
294 let config_map = decode_config_descriptor(&inputs);
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +0000295 assert_eq!(*config_map.get(&INSTANCE_HASH_KEY).unwrap(), Value::from(HASH.as_slice()));
296 }
297
298 #[test]
299 fn config_descriptor_without_instance_hash() {
300 let vb_data =
301 VerifiedBootData { capabilities: vec![Capability::RemoteAttest], ..BASE_VB_DATA };
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000302 let inputs = PartialInputs::new(&vb_data, None).unwrap();
303 let config_map = decode_config_descriptor(&inputs);
Chris Wailese9579642024-05-29 18:25:19 -0700304 assert!(!config_map.contains_key(&INSTANCE_HASH_KEY));
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +0000305 }
306
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000307 fn decode_config_descriptor(inputs: &PartialInputs) -> HashMap<i64, Value> {
308 let config_descriptor = inputs.generate_config_descriptor().unwrap();
Alan Stokesddb988c2023-11-27 11:13:06 +0000309
310 let cbor_map =
Shikha Panwar8f7fc1a2024-04-10 10:41:34 +0000311 cbor_util::deserialize::<Value>(&config_descriptor).unwrap().into_map().unwrap();
Alan Stokesddb988c2023-11-27 11:13:06 +0000312
313 cbor_map
314 .into_iter()
315 .map(|(k, v)| ((k.into_integer().unwrap().try_into().unwrap()), v))
316 .collect()
317 }
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000318
319 #[test]
320 fn changing_deferred_rpb_changes_secrets() {
321 let vb_data = VerifiedBootData { debug_level: DebugLevel::Full, ..BASE_VB_DATA };
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000322 let inputs = PartialInputs::new(&vb_data, Some([0u8; 64])).unwrap();
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000323 let mut buffer_without_defer = [0; 4096];
324 let mut buffer_with_defer = [0; 4096];
325 let mut buffer_without_defer_retry = [0; 4096];
Alice Wang87fbc4b2024-11-05 13:09:58 +0000326 let context = DiceContext {
327 authority_algorithm: KeyAlgorithm::Ed25519,
328 subject_algorithm: KeyAlgorithm::Ed25519,
329 };
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000330
331 let sample_dice_input: &[u8] = &[
332 0xa3, // CDI attest
333 0x01, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // CDI seal
336 0x02, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DICE chain
339 0x03, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x27, 0x04, 0x02, 0x20, 0x01, 0x21, 0x40, 0x22,
340 0x40, 0x84, 0x40, 0xa0, 0x40, 0x40,
341 // 8-bytes of trailing data that aren't part of the DICE chain.
342 0x84, 0x41, 0x55, 0xa0, 0x42, 0x11, 0x22, 0x40,
343 ];
344
345 inputs
346 .clone()
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800347 .write_next_handover(
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000348 sample_dice_input,
349 &[0u8; HIDDEN_SIZE],
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000350 false,
351 &mut buffer_without_defer,
Alice Wang87fbc4b2024-11-05 13:09:58 +0000352 context.clone(),
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000353 )
354 .unwrap();
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800355 let handover1 = from_serialized_handover(&buffer_without_defer);
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000356
357 inputs
358 .clone()
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800359 .write_next_handover(
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000360 sample_dice_input,
361 &[0u8; HIDDEN_SIZE],
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000362 true,
363 &mut buffer_with_defer,
Alice Wang87fbc4b2024-11-05 13:09:58 +0000364 context.clone(),
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000365 )
366 .unwrap();
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800367 let handover2 = from_serialized_handover(&buffer_with_defer);
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000368
369 inputs
370 .clone()
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800371 .write_next_handover(
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000372 sample_dice_input,
373 &[0u8; HIDDEN_SIZE],
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000374 false,
375 &mut buffer_without_defer_retry,
Alice Wang87fbc4b2024-11-05 13:09:58 +0000376 context.clone(),
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000377 )
378 .unwrap();
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800379 let handover3 = from_serialized_handover(&buffer_without_defer_retry);
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000380
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800381 assert_ne!(handover1.cdi_seal(), handover2.cdi_seal());
382 assert_eq!(handover1.cdi_seal(), handover3.cdi_seal());
Shikha Panwarf3acfd12024-05-28 15:48:13 +0000383 }
Alice Wang87fbc4b2024-11-05 13:09:58 +0000384
385 #[test]
386 fn dice_derivation_with_different_algorithms_is_valid() {
387 let dice_artifacts = make_sample_bcc_and_cdis().unwrap();
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800388 let handover0_bytes = to_serialized_handover(&dice_artifacts);
Alice Wang87fbc4b2024-11-05 13:09:58 +0000389 let vb_data = VerifiedBootData { debug_level: DebugLevel::Full, ..BASE_VB_DATA };
Pierre-Clément Tosi2d635322025-03-21 16:01:21 +0000390 let inputs = PartialInputs::new(&vb_data, Some([0u8; 64])).unwrap();
Alice Wang87fbc4b2024-11-05 13:09:58 +0000391 let mut buffer = [0; 4096];
392
393 inputs
394 .clone()
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800395 .write_next_handover(
396 &handover0_bytes,
Alice Wang87fbc4b2024-11-05 13:09:58 +0000397 &[0u8; HIDDEN_SIZE],
Alice Wang87fbc4b2024-11-05 13:09:58 +0000398 true,
399 &mut buffer,
400 DiceContext {
401 authority_algorithm: KeyAlgorithm::Ed25519,
402 subject_algorithm: KeyAlgorithm::EcdsaP256,
403 },
404 )
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800405 .expect("Failed to derive Ed25519 -> EcdsaP256 DICE chain");
406 let handover1 = from_serialized_handover(&buffer);
407 let handover1_bytes = to_serialized_handover(&handover1);
Alice Wang87fbc4b2024-11-05 13:09:58 +0000408 buffer.fill(0);
409
410 inputs
411 .clone()
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800412 .write_next_handover(
413 &handover1_bytes,
Alice Wang87fbc4b2024-11-05 13:09:58 +0000414 &[0u8; HIDDEN_SIZE],
Alice Wang87fbc4b2024-11-05 13:09:58 +0000415 true,
416 &mut buffer,
417 DiceContext {
418 authority_algorithm: KeyAlgorithm::EcdsaP256,
419 subject_algorithm: KeyAlgorithm::EcdsaP384,
420 },
421 )
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800422 .expect("Failed to derive EcdsaP256 -> EcdsaP384 DICE chain");
423 let handover2 = from_serialized_handover(&buffer);
424 let handover2_bytes = to_serialized_handover(&handover2);
Alice Wang87fbc4b2024-11-05 13:09:58 +0000425 buffer.fill(0);
426
427 inputs
428 .clone()
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800429 .write_next_handover(
430 &handover2_bytes,
Alice Wang87fbc4b2024-11-05 13:09:58 +0000431 &[0u8; HIDDEN_SIZE],
Alice Wang87fbc4b2024-11-05 13:09:58 +0000432 true,
433 &mut buffer,
434 DiceContext {
435 authority_algorithm: KeyAlgorithm::EcdsaP384,
436 subject_algorithm: KeyAlgorithm::Ed25519,
437 },
438 )
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800439 .expect("Failed to derive EcdsaP384 -> Ed25519 DICE chain");
440 let handover3 = from_serialized_handover(&buffer);
Alice Wang87fbc4b2024-11-05 13:09:58 +0000441
Alice Wang4dc62912024-12-11 08:27:15 +0000442 let mut session = Session::default();
443 session.set_allow_any_mode(true);
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800444 let _chain = dice::Chain::from_cbor(&session, handover3.bcc().unwrap()).unwrap();
Alice Wang87fbc4b2024-11-05 13:09:58 +0000445 }
446
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800447 fn to_serialized_handover(dice_artifacts: &dyn DiceArtifacts) -> Vec<u8> {
Alice Wang87fbc4b2024-11-05 13:09:58 +0000448 let dice_chain = cbor_util::deserialize::<Value>(dice_artifacts.bcc().unwrap()).unwrap();
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800449 let handover = Value::Map(vec![
Alice Wang87fbc4b2024-11-05 13:09:58 +0000450 (Value::Integer(1.into()), Value::Bytes(dice_artifacts.cdi_attest().to_vec())),
451 (Value::Integer(2.into()), Value::Bytes(dice_artifacts.cdi_seal().to_vec())),
452 (Value::Integer(3.into()), dice_chain),
453 ]);
Pierre-Clément Tosi520664c2025-03-03 11:51:53 -0800454 cbor_util::serialize(&handover).unwrap()
455 }
456
457 fn from_serialized_handover(bytes: &[u8]) -> diced_open_dice::BccHandover {
458 bcc_handover_parse(bytes).unwrap()
Alice Wang87fbc4b2024-11-05 13:09:58 +0000459 }
Alan Stokesddb988c2023-11-27 11:13:06 +0000460}