blob: 247c34ec6bd6f2a639d1e0875162dc6b0a175335 [file] [log] [blame]
Alice Wangd3a96402023-11-24 15:37:39 +00001// Copyright 2023, 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//! This module contains functions related to DICE.
16
Alice Wang1cc13502023-12-05 11:05:34 +000017use alloc::string::String;
Alan Stokes8f7db052024-05-09 10:13:28 +010018use alloc::vec;
Alice Wangd3a96402023-11-24 15:37:39 +000019use alloc::vec::Vec;
Alice Wang3397b362023-12-01 13:57:10 +000020use bssl_avf::{ed25519_verify, Digester, EcKey};
Alice Wangdd29c5d2023-12-07 09:56:23 +000021use cbor_util::{
Alice Wang3397b362023-12-01 13:57:10 +000022 cbor_value_type, get_label_value, get_label_value_as_bytes, value_to_array,
23 value_to_byte_array, value_to_bytes, value_to_map, value_to_num, value_to_text,
Alice Wangdd29c5d2023-12-07 09:56:23 +000024};
25use ciborium::value::Value;
Alice Wangd3a96402023-11-24 15:37:39 +000026use core::cell::OnceCell;
27use core::result;
28use coset::{
Alice Wang3397b362023-12-01 13:57:10 +000029 self,
30 iana::{self, EnumI64},
31 Algorithm, AsCborValue, CborSerializable, CoseError, CoseKey, CoseSign1, KeyOperation, KeyType,
32 Label,
Alice Wangd3a96402023-11-24 15:37:39 +000033};
34use diced_open_dice::{DiceMode, HASH_SIZE};
Alice Wang9eebbab2024-04-10 14:57:27 +000035use log::{debug, error, info};
Alice Wangdd29c5d2023-12-07 09:56:23 +000036use service_vm_comm::RequestProcessingError;
Alice Wangd3a96402023-11-24 15:37:39 +000037
38type Result<T> = result::Result<T, RequestProcessingError>;
39
40const CODE_HASH: i64 = -4670545;
41const CONFIG_DESC: i64 = -4670548;
42const AUTHORITY_HASH: i64 = -4670549;
43const MODE: i64 = -4670551;
44const SUBJECT_PUBLIC_KEY: i64 = -4670552;
45
Alice Wang1cc13502023-12-05 11:05:34 +000046const CONFIG_DESC_COMPONENT_NAME: i64 = -70002;
47const CONFIG_DESC_SUB_COMPONENTS: i64 = -71002;
48
49const SUB_COMPONENT_NAME: i64 = 1;
50const SUB_COMPONENT_VERSION: i64 = 2;
51const SUB_COMPONENT_CODE_HASH: i64 = 3;
52const SUB_COMPONENT_AUTHORITY_HASH: i64 = 4;
53
Alice Wang9eebbab2024-04-10 14:57:27 +000054const KERNEL_COMPONENT_NAME: &str = "vm_entry";
55const VENDOR_PARTITION_COMPONENT_NAME: &str = "Microdroid vendor";
Alice Wang1cc13502023-12-05 11:05:34 +000056const MICRODROID_PAYLOAD_COMPONENT_NAME: &str = "Microdroid payload";
57
Alice Wangd3a96402023-11-24 15:37:39 +000058/// Represents a partially decoded `DiceCertChain` from the client VM.
59/// The whole chain is defined as following:
60///
61/// DiceCertChain = [
62/// PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384, ; UDS_Pub
63/// + DiceChainEntry, ; First CDI_Certificate -> Last CDI_Certificate
64/// ]
65#[derive(Debug, Clone)]
66pub(crate) struct ClientVmDiceChain {
Alice Wang3397b362023-12-01 13:57:10 +000067 payloads: Vec<DiceChainEntryPayload>,
Alice Wang9eebbab2024-04-10 14:57:27 +000068 /// The index of the vendor partition entry in the DICE chain if it exists.
69 vendor_partition_index: Option<usize>,
70 /// The index of the kernel entry in the DICE chain.
71 kernel_index: usize,
Alice Wangd3a96402023-11-24 15:37:39 +000072}
73
74impl ClientVmDiceChain {
75 /// Validates the signatures of the entries in the `client_vm_dice_chain` as following:
76 ///
77 /// - The first entry of the `client_vm_dice_chain` must be signed with the root public key.
78 /// - After the first entry, each entry of the `client_vm_dice_chain` must be signed with the
79 /// subject public key of the previous entry.
80 ///
81 /// Returns a partially decoded client VM's DICE chain if the verification succeeds.
82 pub(crate) fn validate_signatures_and_parse_dice_chain(
83 mut client_vm_dice_chain: Vec<Value>,
Alice Wang9eebbab2024-04-10 14:57:27 +000084 service_vm_dice_chain_len: usize,
Alice Wangd3a96402023-11-24 15:37:39 +000085 ) -> Result<Self> {
Alice Wang9eebbab2024-04-10 14:57:27 +000086 let has_vendor_partition =
87 vendor_partition_exists(client_vm_dice_chain.len(), service_vm_dice_chain_len)?;
88
Alice Wangd3a96402023-11-24 15:37:39 +000089 let root_public_key =
90 CoseKey::from_cbor_value(client_vm_dice_chain.remove(0))?.try_into()?;
91
92 let mut payloads = Vec::with_capacity(client_vm_dice_chain.len());
93 let mut previous_public_key = &root_public_key;
94 for (i, value) in client_vm_dice_chain.into_iter().enumerate() {
95 let payload = DiceChainEntryPayload::validate_cose_signature_and_extract_payload(
96 value,
97 previous_public_key,
98 )
99 .map_err(|e| {
100 error!("Failed to verify the DICE chain entry {}: {:?}", i, e);
101 e
102 })?;
103 payloads.push(payload);
104 previous_public_key = &payloads.last().unwrap().subject_public_key;
105 }
Alice Wang9eebbab2024-04-10 14:57:27 +0000106
107 Self::build(payloads, has_vendor_partition)
Alice Wang1cc13502023-12-05 11:05:34 +0000108 }
109
Alice Wang9eebbab2024-04-10 14:57:27 +0000110 fn build(
111 dice_entry_payloads: Vec<DiceChainEntryPayload>,
112 has_vendor_partition: bool,
113 ) -> Result<Self> {
114 let microdroid_payload_name =
115 &dice_entry_payloads[dice_entry_payloads.len() - 1].config_descriptor.component_name;
Alan Stokes8f7db052024-05-09 10:13:28 +0100116 if Some(MICRODROID_PAYLOAD_COMPONENT_NAME) != microdroid_payload_name.as_deref() {
Alice Wang1cc13502023-12-05 11:05:34 +0000117 error!(
118 "The last entry in the client VM DICE chain must describe the Microdroid \
Alan Stokes8f7db052024-05-09 10:13:28 +0100119 payload. Got '{microdroid_payload_name:?}'"
Alice Wang1cc13502023-12-05 11:05:34 +0000120 );
121 return Err(RequestProcessingError::InvalidDiceChain);
122 }
Alice Wang9eebbab2024-04-10 14:57:27 +0000123
124 let (vendor_partition_index, kernel_index) = if has_vendor_partition {
125 let index = dice_entry_payloads.len() - 2;
126 let vendor_partition_name =
127 &dice_entry_payloads[index].config_descriptor.component_name;
Alan Stokes8f7db052024-05-09 10:13:28 +0100128 if Some(VENDOR_PARTITION_COMPONENT_NAME) != vendor_partition_name.as_deref() {
Alice Wang9eebbab2024-04-10 14:57:27 +0000129 error!(
130 "The vendor partition entry in the client VM DICE chain must describe the \
Alan Stokes8f7db052024-05-09 10:13:28 +0100131 vendor partition. Got '{vendor_partition_name:?}'"
Alice Wang9eebbab2024-04-10 14:57:27 +0000132 );
133 return Err(RequestProcessingError::InvalidDiceChain);
134 }
135 (Some(index), index - 1)
136 } else {
137 (None, dice_entry_payloads.len() - 2)
138 };
139
140 let kernel_name = &dice_entry_payloads[kernel_index].config_descriptor.component_name;
Alan Stokes8f7db052024-05-09 10:13:28 +0100141 if Some(KERNEL_COMPONENT_NAME) != kernel_name.as_deref() {
Alice Wang9eebbab2024-04-10 14:57:27 +0000142 error!(
143 "The microdroid kernel entry in the client VM DICE chain must describe the \
Alan Stokes8f7db052024-05-09 10:13:28 +0100144 Microdroid kernel. Got '{kernel_name:?}'"
Alice Wang9eebbab2024-04-10 14:57:27 +0000145 );
146 return Err(RequestProcessingError::InvalidDiceChain);
147 }
148
149 debug!("All entries in the client VM DICE chain have correct component names");
150 Ok(Self { payloads: dice_entry_payloads, vendor_partition_index, kernel_index })
Alice Wang1cc13502023-12-05 11:05:34 +0000151 }
152
Alice Wang4e093102023-12-13 09:16:29 +0000153 pub(crate) fn microdroid_kernel(&self) -> &DiceChainEntryPayload {
Alice Wang9eebbab2024-04-10 14:57:27 +0000154 &self.payloads[self.kernel_index]
155 }
156
157 pub(crate) fn vendor_partition(&self) -> Option<&DiceChainEntryPayload> {
158 self.vendor_partition_index.map(|i| &self.payloads[i])
Alice Wang1cc13502023-12-05 11:05:34 +0000159 }
160
Alice Wang3397b362023-12-01 13:57:10 +0000161 pub(crate) fn microdroid_payload(&self) -> &DiceChainEntryPayload {
Alice Wang1cc13502023-12-05 11:05:34 +0000162 &self.payloads[self.payloads.len() - 1]
163 }
164
Alan Stokes8f7db052024-05-09 10:13:28 +0100165 pub(crate) fn microdroid_payload_components(&self) -> Result<Vec<SubComponent>> {
166 self.microdroid_payload().config_descriptor.sub_components()
Alice Wangd3a96402023-11-24 15:37:39 +0000167 }
168
169 /// Returns true if all payloads in the DICE chain are in normal mode.
170 pub(crate) fn all_entries_are_secure(&self) -> bool {
171 self.payloads.iter().all(|p| p.mode == DiceMode::kDiceModeNormal)
172 }
173}
174
Alice Wang9eebbab2024-04-10 14:57:27 +0000175fn vendor_partition_exists(
176 client_vm_dice_chain_len: usize,
177 service_vm_dice_chain_len: usize,
178) -> Result<bool> {
179 let entries_up_to_pvmfw_len = service_vm_dice_chain_len - 1;
180 // Client VM DICE chain = entries_up_to_pvmfw
181 // + Vendor module entry (exists only when the vendor partition is present)
182 // + Microdroid kernel entry (added in pvmfw)
183 // + Apk/Apexes entry (added in microdroid)
184 match client_vm_dice_chain_len.checked_sub(entries_up_to_pvmfw_len) {
185 Some(2) => {
186 debug!("The vendor partition entry is not present in the client VM's DICE chain");
187 Ok(false)
188 }
189 Some(3) => {
190 info!("The vendor partition entry is present in the client VM's DICE chain");
191 Ok(true)
192 }
193 _ => {
194 error!(
195 "The client VM's DICE chain must contain two or three extra entries. \
196 Service VM DICE chain: {} entries, client VM DICE chain: {} entries",
197 service_vm_dice_chain_len, client_vm_dice_chain_len
198 );
199 Err(RequestProcessingError::InvalidDiceChain)
200 }
Alice Wangd3a96402023-11-24 15:37:39 +0000201 }
Alice Wangd3a96402023-11-24 15:37:39 +0000202}
203
204#[derive(Debug, Clone)]
205pub(crate) struct PublicKey(CoseKey);
206
207impl TryFrom<CoseKey> for PublicKey {
208 type Error = RequestProcessingError;
209
210 fn try_from(key: CoseKey) -> Result<Self> {
Alan Stokes33761202024-05-08 10:54:52 +0100211 // The public key must allow use for verification.
212 // Note that an empty key_ops set implicitly allows everything.
213 let key_ops = &key.key_ops;
214 if !key_ops.is_empty()
215 && !key_ops.contains(&KeyOperation::Assigned(iana::KeyOperation::Verify))
216 {
Alan Stokes0262dec2024-05-09 15:30:23 +0100217 error!("Public key does not support verification - key_ops: {key_ops:?}");
Alice Wangd3a96402023-11-24 15:37:39 +0000218 return Err(RequestProcessingError::InvalidDiceChain);
219 }
220 Ok(Self(key))
221 }
222}
223
Alice Wang3397b362023-12-01 13:57:10 +0000224impl PublicKey {
225 /// Verifies the signature of the provided message with the public key.
226 ///
227 /// This function supports the following key/algorithm types as specified in
228 /// hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
229 /// generateCertificateRequestV2.cddl:
230 ///
231 /// PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384
Alan Stokesb2f52fb2024-05-09 10:12:55 +0100232 ///
233 /// The signature should be in the format defined by COSE in RFC 9053 section 2 for the
Alan Stokes0262dec2024-05-09 15:30:23 +0100234 /// specific algorithm.
Alice Wang3397b362023-12-01 13:57:10 +0000235 pub(crate) fn verify(&self, signature: &[u8], message: &[u8]) -> Result<()> {
236 match &self.0.kty {
237 KeyType::Assigned(iana::KeyType::EC2) => {
238 let public_key = EcKey::from_cose_public_key(&self.0)?;
239 let Some(Algorithm::Assigned(alg)) = self.0.alg else {
240 error!("Invalid algorithm in COSE key {:?}", self.0.alg);
241 return Err(RequestProcessingError::InvalidDiceChain);
242 };
243 let digester = match alg {
244 iana::Algorithm::ES256 => Digester::sha256(),
245 iana::Algorithm::ES384 => Digester::sha384(),
246 _ => {
247 error!("Unsupported algorithm in EC2 key: {:?}", alg);
248 return Err(RequestProcessingError::InvalidDiceChain);
249 }
250 };
251 let digest = digester.digest(message)?;
Alan Stokes20b5ab22024-05-10 15:40:43 +0100252 Ok(public_key.ecdsa_verify_cose(signature, &digest)?)
Alice Wang3397b362023-12-01 13:57:10 +0000253 }
254 KeyType::Assigned(iana::KeyType::OKP) => {
255 let curve_type =
256 get_label_value(&self.0, Label::Int(iana::OkpKeyParameter::Crv.to_i64()))?;
257 if curve_type != &Value::from(iana::EllipticCurve::Ed25519.to_i64()) {
258 error!("Unsupported curve type in OKP COSE key: {:?}", curve_type);
259 return Err(RequestProcessingError::OperationUnimplemented);
260 }
261 let x = get_label_value_as_bytes(
262 &self.0,
263 Label::Int(iana::OkpKeyParameter::X.to_i64()),
264 )?;
265 let public_key = x.try_into().map_err(|_| {
266 error!("Invalid ED25519 public key size: {}", x.len());
267 RequestProcessingError::InvalidDiceChain
268 })?;
269 let signature = signature.try_into().map_err(|_| {
270 error!("Invalid ED25519 signature size: {}", signature.len());
271 RequestProcessingError::InvalidDiceChain
272 })?;
273 Ok(ed25519_verify(message, signature, public_key)?)
274 }
275 kty => {
276 error!("Unsupported key type in COSE key: {:?}", kty);
277 Err(RequestProcessingError::OperationUnimplemented)
278 }
279 }
280 }
281}
282
Alice Wangd3a96402023-11-24 15:37:39 +0000283/// Represents a partially decoded `DiceChainEntryPayload`. The whole payload is defined in:
284///
285/// hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
286/// generateCertificateRequestV2.cddl
287#[derive(Debug, Clone)]
288pub(crate) struct DiceChainEntryPayload {
Alice Wang3397b362023-12-01 13:57:10 +0000289 pub(crate) subject_public_key: PublicKey,
Alice Wangd3a96402023-11-24 15:37:39 +0000290 mode: DiceMode,
Alice Wang4e093102023-12-13 09:16:29 +0000291 pub(crate) code_hash: [u8; HASH_SIZE],
292 pub(crate) authority_hash: [u8; HASH_SIZE],
Alice Wang1cc13502023-12-05 11:05:34 +0000293 config_descriptor: ConfigDescriptor,
Alice Wangd3a96402023-11-24 15:37:39 +0000294}
295
296impl DiceChainEntryPayload {
297 /// Validates the signature of the provided CBOR value with the provided public key and
298 /// extracts payload from the value.
299 fn validate_cose_signature_and_extract_payload(
300 value: Value,
Alice Wang3397b362023-12-01 13:57:10 +0000301 authority_public_key: &PublicKey,
Alice Wangd3a96402023-11-24 15:37:39 +0000302 ) -> Result<Self> {
303 let cose_sign1 = CoseSign1::from_cbor_value(value)?;
Alice Wang3397b362023-12-01 13:57:10 +0000304 let aad = &[]; // AAD is not used in DICE chain entry.
305 cose_sign1.verify_signature(aad, |signature, message| {
306 authority_public_key.verify(signature, message)
307 })?;
Alice Wangd3a96402023-11-24 15:37:39 +0000308
309 let payload = cose_sign1.payload.ok_or_else(|| {
310 error!("No payload found in the DICE chain entry");
311 RequestProcessingError::InvalidDiceChain
312 })?;
Alice Wang4e093102023-12-13 09:16:29 +0000313 Self::from_slice(&payload)
Alice Wangd3a96402023-11-24 15:37:39 +0000314 }
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000315
Alice Wang4e093102023-12-13 09:16:29 +0000316 pub(crate) fn from_slice(data: &[u8]) -> Result<Self> {
317 let entries = value_to_map(Value::from_slice(data)?, "DiceChainEntryPayload")?;
318 let mut builder = PayloadBuilder::default();
319 for (key, value) in entries.into_iter() {
320 let key: i64 = value_to_num(key, "DiceChainEntryPayload key")?;
321 match key {
322 SUBJECT_PUBLIC_KEY => {
323 let subject_public_key = value_to_bytes(value, "subject_public_key")?;
324 let subject_public_key =
325 CoseKey::from_slice(&subject_public_key)?.try_into()?;
326 builder.subject_public_key(subject_public_key)?;
327 }
328 MODE => builder.mode(to_mode(value)?)?,
329 CODE_HASH => {
330 let code_hash = value_to_byte_array(value, "DiceChainEntryPayload code_hash")?;
331 builder.code_hash(code_hash)?;
332 }
333 AUTHORITY_HASH => {
334 let authority_hash =
335 value_to_byte_array(value, "DiceChainEntryPayload authority_hash")?;
336 builder.authority_hash(authority_hash)?;
337 }
338 CONFIG_DESC => {
339 let config_descriptor = value_to_bytes(value, "config_descriptor")?;
340 let config_descriptor = ConfigDescriptor::from_slice(&config_descriptor)?;
341 builder.config_descriptor(config_descriptor)?;
342 }
343 _ => {}
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000344 }
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000345 }
Alice Wang4e093102023-12-13 09:16:29 +0000346 builder.build()
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000347 }
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000348}
Alice Wang1cc13502023-12-05 11:05:34 +0000349/// Represents a partially decoded `ConfigurationDescriptor`.
350///
351/// The whole `ConfigurationDescriptor` is defined in:
352///
353/// hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
354/// generateCertificateRequestV2.cddl
Alan Stokes8f7db052024-05-09 10:13:28 +0100355#[derive(Debug, Clone, Default)]
Alice Wang1cc13502023-12-05 11:05:34 +0000356pub(crate) struct ConfigDescriptor {
Alan Stokes8f7db052024-05-09 10:13:28 +0100357 component_name: Option<String>,
358 sub_components: Option<Value>,
Alice Wang1cc13502023-12-05 11:05:34 +0000359}
360
361impl ConfigDescriptor {
362 fn from_slice(data: &[u8]) -> Result<Self> {
Alan Stokes8f7db052024-05-09 10:13:28 +0100363 let value = Value::from_slice(data);
364 let Ok(value) = value else {
365 // Some DICE implementations store a hash in the config descriptor. So we just
366 // skip anything that doesn't parse correctly.
367 info!("Ignoring malformed config descriptor");
368 return Ok(Default::default());
369 };
Alice Wang1cc13502023-12-05 11:05:34 +0000370 let entries = value_to_map(value, "ConfigDescriptor")?;
371 let mut builder = ConfigDescriptorBuilder::default();
372 for (key, value) in entries.into_iter() {
373 let key: i64 = value_to_num(key, "ConfigDescriptor key")?;
374 match key {
375 CONFIG_DESC_COMPONENT_NAME => {
376 let name = value_to_text(value, "ConfigDescriptor component_name")?;
377 builder.component_name(name)?;
378 }
379 CONFIG_DESC_SUB_COMPONENTS => {
Alan Stokes8f7db052024-05-09 10:13:28 +0100380 // If this is the Microdroid payload node then these are the subcomponents. But
381 // for any other node it could be anything - this isn't a reserved key. So defer
382 // decoding until we know which node is which.
383 builder.sub_components(value)?
Alice Wang1cc13502023-12-05 11:05:34 +0000384 }
385 _ => {}
386 }
387 }
388 builder.build()
389 }
Alan Stokes8f7db052024-05-09 10:13:28 +0100390
391 /// Attempt to decode any Microdroid sub-components that were present in this config descriptor.
392 fn sub_components(&self) -> Result<Vec<SubComponent>> {
393 let Some(value) = &self.sub_components else {
394 return Ok(vec![]);
395 };
396 let sub_components = value_to_array(value.clone(), "ConfigDescriptor sub_components")?;
397 sub_components.into_iter().map(SubComponent::try_from).collect()
398 }
Alice Wang1cc13502023-12-05 11:05:34 +0000399}
400
401#[derive(Debug, Clone, Default)]
402struct ConfigDescriptorBuilder {
403 component_name: OnceCell<String>,
Alan Stokes8f7db052024-05-09 10:13:28 +0100404 sub_components: OnceCell<Value>,
Alice Wang1cc13502023-12-05 11:05:34 +0000405}
406
407impl ConfigDescriptorBuilder {
408 fn component_name(&mut self, component_name: String) -> Result<()> {
409 set_once(&self.component_name, component_name, "ConfigDescriptor component_name")
410 }
411
Alan Stokes8f7db052024-05-09 10:13:28 +0100412 fn sub_components(&mut self, sub_components: Value) -> Result<()> {
Alice Wang1cc13502023-12-05 11:05:34 +0000413 set_once(&self.sub_components, sub_components, "ConfigDescriptor sub_components")
414 }
415
416 fn build(mut self) -> Result<ConfigDescriptor> {
Alan Stokes8f7db052024-05-09 10:13:28 +0100417 let component_name = self.component_name.take();
Alice Wang1cc13502023-12-05 11:05:34 +0000418 let sub_components = self.sub_components.take();
419 Ok(ConfigDescriptor { component_name, sub_components })
420 }
421}
422
423#[derive(Debug, Clone)]
424pub(crate) struct SubComponent {
425 pub(crate) name: String,
426 pub(crate) version: u64,
427 pub(crate) code_hash: Vec<u8>,
428 pub(crate) authority_hash: Vec<u8>,
429}
430
431impl TryFrom<Value> for SubComponent {
432 type Error = RequestProcessingError;
433
434 fn try_from(value: Value) -> Result<Self> {
435 let entries = value_to_map(value, "SubComponent")?;
436 let mut builder = SubComponentBuilder::default();
437 for (key, value) in entries.into_iter() {
438 let key: i64 = value_to_num(key, "SubComponent key")?;
439 match key {
440 SUB_COMPONENT_NAME => {
441 builder.name(value_to_text(value, "SubComponent component_name")?)?
442 }
443 SUB_COMPONENT_VERSION => {
444 builder.version(value_to_num(value, "SubComponent version")?)?
445 }
446 SUB_COMPONENT_CODE_HASH => {
447 builder.code_hash(value_to_bytes(value, "SubComponent code_hash")?)?
448 }
449 SUB_COMPONENT_AUTHORITY_HASH => {
450 builder.authority_hash(value_to_bytes(value, "SubComponent authority_hash")?)?
451 }
452 k => {
453 error!("Unknown key in SubComponent: {}", k);
454 return Err(RequestProcessingError::InvalidDiceChain);
455 }
456 }
457 }
458 builder.build()
459 }
460}
461
462#[derive(Debug, Clone, Default)]
463struct SubComponentBuilder {
464 name: OnceCell<String>,
465 version: OnceCell<u64>,
466 code_hash: OnceCell<Vec<u8>>,
467 authority_hash: OnceCell<Vec<u8>>,
468}
469
470impl SubComponentBuilder {
471 fn name(&mut self, name: String) -> Result<()> {
472 set_once(&self.name, name, "SubComponent name")
473 }
474
475 fn version(&mut self, version: u64) -> Result<()> {
476 set_once(&self.version, version, "SubComponent version")
477 }
478
479 fn code_hash(&mut self, code_hash: Vec<u8>) -> Result<()> {
480 set_once(&self.code_hash, code_hash, "SubComponent code_hash")
481 }
482
483 fn authority_hash(&mut self, authority_hash: Vec<u8>) -> Result<()> {
484 set_once(&self.authority_hash, authority_hash, "SubComponent authority_hash")
485 }
486
487 fn build(mut self) -> Result<SubComponent> {
488 let name = take_value(&mut self.name, "SubComponent name")?;
489 let version = take_value(&mut self.version, "SubComponent version")?;
490 let code_hash = take_value(&mut self.code_hash, "SubComponent code_hash")?;
491 let authority_hash = take_value(&mut self.authority_hash, "SubComponent authority_hash")?;
492 Ok(SubComponent { name, version, code_hash, authority_hash })
493 }
494}
495
Alice Wangd3a96402023-11-24 15:37:39 +0000496fn to_mode(value: Value) -> Result<DiceMode> {
497 let mode = match value {
498 // Mode is supposed to be encoded as a 1-byte bstr, but some implementations instead
499 // encode it as an integer. Accept either. See b/273552826.
500 // If Mode is omitted, it should be treated as if it was NotConfigured, according to
501 // the Open Profile for DICE spec.
502 Value::Bytes(bytes) => {
503 if bytes.len() != 1 {
504 error!("Bytes array with invalid length for mode: {:?}", bytes.len());
505 return Err(RequestProcessingError::InvalidDiceChain);
506 }
507 bytes[0].into()
508 }
509 Value::Integer(i) => i,
510 v => return Err(CoseError::UnexpectedItem(cbor_value_type(&v), "bstr or int").into()),
511 };
512 let mode = match mode {
513 x if x == (DiceMode::kDiceModeNormal as i64).into() => DiceMode::kDiceModeNormal,
514 x if x == (DiceMode::kDiceModeDebug as i64).into() => DiceMode::kDiceModeDebug,
515 x if x == (DiceMode::kDiceModeMaintenance as i64).into() => DiceMode::kDiceModeMaintenance,
516 // If Mode is invalid, it should be treated as if it was NotConfigured, according to
517 // the Open Profile for DICE spec.
518 _ => DiceMode::kDiceModeNotInitialized,
519 };
520 Ok(mode)
521}
522
523#[derive(Default, Debug, Clone)]
524struct PayloadBuilder {
525 subject_public_key: OnceCell<PublicKey>,
526 mode: OnceCell<DiceMode>,
527 code_hash: OnceCell<[u8; HASH_SIZE]>,
528 authority_hash: OnceCell<[u8; HASH_SIZE]>,
Alice Wang1cc13502023-12-05 11:05:34 +0000529 config_descriptor: OnceCell<ConfigDescriptor>,
Alice Wangd3a96402023-11-24 15:37:39 +0000530}
531
532fn set_once<T>(field: &OnceCell<T>, value: T, field_name: &str) -> Result<()> {
533 field.set(value).map_err(|_| {
534 error!("Field '{field_name}' is duplicated in the Payload");
535 RequestProcessingError::InvalidDiceChain
536 })
537}
538
539fn take_value<T>(field: &mut OnceCell<T>, field_name: &str) -> Result<T> {
540 field.take().ok_or_else(|| {
541 error!("Field '{field_name}' is missing in the Payload");
542 RequestProcessingError::InvalidDiceChain
543 })
544}
545
546impl PayloadBuilder {
547 fn subject_public_key(&mut self, key: PublicKey) -> Result<()> {
548 set_once(&self.subject_public_key, key, "subject_public_key")
549 }
550
551 fn mode(&mut self, mode: DiceMode) -> Result<()> {
552 set_once(&self.mode, mode, "mode")
553 }
554
555 fn code_hash(&mut self, code_hash: [u8; HASH_SIZE]) -> Result<()> {
556 set_once(&self.code_hash, code_hash, "code_hash")
557 }
558
559 fn authority_hash(&mut self, authority_hash: [u8; HASH_SIZE]) -> Result<()> {
560 set_once(&self.authority_hash, authority_hash, "authority_hash")
561 }
562
Alice Wang1cc13502023-12-05 11:05:34 +0000563 fn config_descriptor(&mut self, config_descriptor: ConfigDescriptor) -> Result<()> {
Alice Wangd3a96402023-11-24 15:37:39 +0000564 set_once(&self.config_descriptor, config_descriptor, "config_descriptor")
565 }
566
567 fn build(mut self) -> Result<DiceChainEntryPayload> {
568 let subject_public_key = take_value(&mut self.subject_public_key, "subject_public_key")?;
569 // If Mode is omitted, it should be treated as if it was NotConfigured, according to
570 // the Open Profile for DICE spec.
571 let mode = self.mode.take().unwrap_or(DiceMode::kDiceModeNotInitialized);
572 let code_hash = take_value(&mut self.code_hash, "code_hash")?;
573 let authority_hash = take_value(&mut self.authority_hash, "authority_hash")?;
574 let config_descriptor = take_value(&mut self.config_descriptor, "config_descriptor")?;
575 Ok(DiceChainEntryPayload {
576 subject_public_key,
577 mode,
578 code_hash,
579 authority_hash,
580 config_descriptor,
581 })
582 }
583}