blob: ec05f662819705f32d2be4ab6a07cee951aa0932 [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;
Alice Wangd3a96402023-11-24 15:37:39 +000018use alloc::vec::Vec;
Alice Wang3397b362023-12-01 13:57:10 +000019use bssl_avf::{ed25519_verify, Digester, EcKey};
Alice Wangdd29c5d2023-12-07 09:56:23 +000020use cbor_util::{
Alice Wang3397b362023-12-01 13:57:10 +000021 cbor_value_type, get_label_value, get_label_value_as_bytes, value_to_array,
22 value_to_byte_array, value_to_bytes, value_to_map, value_to_num, value_to_text,
Alice Wangdd29c5d2023-12-07 09:56:23 +000023};
24use ciborium::value::Value;
Alice Wangd3a96402023-11-24 15:37:39 +000025use core::cell::OnceCell;
26use core::result;
27use coset::{
Alice Wang3397b362023-12-01 13:57:10 +000028 self,
29 iana::{self, EnumI64},
30 Algorithm, AsCborValue, CborSerializable, CoseError, CoseKey, CoseSign1, KeyOperation, KeyType,
31 Label,
Alice Wangd3a96402023-11-24 15:37:39 +000032};
33use diced_open_dice::{DiceMode, HASH_SIZE};
Alice Wang9eebbab2024-04-10 14:57:27 +000034use log::{debug, error, info};
Alice Wangdd29c5d2023-12-07 09:56:23 +000035use service_vm_comm::RequestProcessingError;
Alice Wangd3a96402023-11-24 15:37:39 +000036
37type Result<T> = result::Result<T, RequestProcessingError>;
38
39const CODE_HASH: i64 = -4670545;
40const CONFIG_DESC: i64 = -4670548;
41const AUTHORITY_HASH: i64 = -4670549;
42const MODE: i64 = -4670551;
43const SUBJECT_PUBLIC_KEY: i64 = -4670552;
44
Alice Wang1cc13502023-12-05 11:05:34 +000045const CONFIG_DESC_COMPONENT_NAME: i64 = -70002;
46const CONFIG_DESC_SUB_COMPONENTS: i64 = -71002;
47
48const SUB_COMPONENT_NAME: i64 = 1;
49const SUB_COMPONENT_VERSION: i64 = 2;
50const SUB_COMPONENT_CODE_HASH: i64 = 3;
51const SUB_COMPONENT_AUTHORITY_HASH: i64 = 4;
52
Alice Wang9eebbab2024-04-10 14:57:27 +000053const KERNEL_COMPONENT_NAME: &str = "vm_entry";
54const VENDOR_PARTITION_COMPONENT_NAME: &str = "Microdroid vendor";
Alice Wang1cc13502023-12-05 11:05:34 +000055const MICRODROID_PAYLOAD_COMPONENT_NAME: &str = "Microdroid payload";
56
Alice Wangd3a96402023-11-24 15:37:39 +000057/// Represents a partially decoded `DiceCertChain` from the client VM.
58/// The whole chain is defined as following:
59///
60/// DiceCertChain = [
61/// PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384, ; UDS_Pub
62/// + DiceChainEntry, ; First CDI_Certificate -> Last CDI_Certificate
63/// ]
64#[derive(Debug, Clone)]
65pub(crate) struct ClientVmDiceChain {
Alice Wang3397b362023-12-01 13:57:10 +000066 payloads: Vec<DiceChainEntryPayload>,
Alice Wang9eebbab2024-04-10 14:57:27 +000067 /// The index of the vendor partition entry in the DICE chain if it exists.
68 vendor_partition_index: Option<usize>,
69 /// The index of the kernel entry in the DICE chain.
70 kernel_index: usize,
Alice Wangd3a96402023-11-24 15:37:39 +000071}
72
73impl ClientVmDiceChain {
74 /// Validates the signatures of the entries in the `client_vm_dice_chain` as following:
75 ///
76 /// - The first entry of the `client_vm_dice_chain` must be signed with the root public key.
77 /// - After the first entry, each entry of the `client_vm_dice_chain` must be signed with the
78 /// subject public key of the previous entry.
79 ///
80 /// Returns a partially decoded client VM's DICE chain if the verification succeeds.
81 pub(crate) fn validate_signatures_and_parse_dice_chain(
82 mut client_vm_dice_chain: Vec<Value>,
Alice Wang9eebbab2024-04-10 14:57:27 +000083 service_vm_dice_chain_len: usize,
Alice Wangd3a96402023-11-24 15:37:39 +000084 ) -> Result<Self> {
Alice Wang9eebbab2024-04-10 14:57:27 +000085 let has_vendor_partition =
86 vendor_partition_exists(client_vm_dice_chain.len(), service_vm_dice_chain_len)?;
87
Alice Wangd3a96402023-11-24 15:37:39 +000088 let root_public_key =
89 CoseKey::from_cbor_value(client_vm_dice_chain.remove(0))?.try_into()?;
90
91 let mut payloads = Vec::with_capacity(client_vm_dice_chain.len());
92 let mut previous_public_key = &root_public_key;
93 for (i, value) in client_vm_dice_chain.into_iter().enumerate() {
94 let payload = DiceChainEntryPayload::validate_cose_signature_and_extract_payload(
95 value,
96 previous_public_key,
97 )
98 .map_err(|e| {
99 error!("Failed to verify the DICE chain entry {}: {:?}", i, e);
100 e
101 })?;
102 payloads.push(payload);
103 previous_public_key = &payloads.last().unwrap().subject_public_key;
104 }
Alice Wang9eebbab2024-04-10 14:57:27 +0000105
106 Self::build(payloads, has_vendor_partition)
Alice Wang1cc13502023-12-05 11:05:34 +0000107 }
108
Alice Wang9eebbab2024-04-10 14:57:27 +0000109 fn build(
110 dice_entry_payloads: Vec<DiceChainEntryPayload>,
111 has_vendor_partition: bool,
112 ) -> Result<Self> {
113 let microdroid_payload_name =
114 &dice_entry_payloads[dice_entry_payloads.len() - 1].config_descriptor.component_name;
Alice Wang1cc13502023-12-05 11:05:34 +0000115 if MICRODROID_PAYLOAD_COMPONENT_NAME != microdroid_payload_name {
116 error!(
117 "The last entry in the client VM DICE chain must describe the Microdroid \
Alice Wang9eebbab2024-04-10 14:57:27 +0000118 payload. Got '{}'",
Alice Wang1cc13502023-12-05 11:05:34 +0000119 microdroid_payload_name
120 );
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;
128 if VENDOR_PARTITION_COMPONENT_NAME != vendor_partition_name {
129 error!(
130 "The vendor partition entry in the client VM DICE chain must describe the \
131 vendor partition. Got '{}'",
132 vendor_partition_name,
133 );
134 return Err(RequestProcessingError::InvalidDiceChain);
135 }
136 (Some(index), index - 1)
137 } else {
138 (None, dice_entry_payloads.len() - 2)
139 };
140
141 let kernel_name = &dice_entry_payloads[kernel_index].config_descriptor.component_name;
142 if KERNEL_COMPONENT_NAME != kernel_name {
143 error!(
144 "The microdroid kernel entry in the client VM DICE chain must describe the \
145 Microdroid kernel. Got '{}'",
146 kernel_name,
147 );
148 return Err(RequestProcessingError::InvalidDiceChain);
149 }
150
151 debug!("All entries in the client VM DICE chain have correct component names");
152 Ok(Self { payloads: dice_entry_payloads, vendor_partition_index, kernel_index })
Alice Wang1cc13502023-12-05 11:05:34 +0000153 }
154
Alice Wang4e093102023-12-13 09:16:29 +0000155 pub(crate) fn microdroid_kernel(&self) -> &DiceChainEntryPayload {
Alice Wang9eebbab2024-04-10 14:57:27 +0000156 &self.payloads[self.kernel_index]
157 }
158
159 pub(crate) fn vendor_partition(&self) -> Option<&DiceChainEntryPayload> {
160 self.vendor_partition_index.map(|i| &self.payloads[i])
Alice Wang1cc13502023-12-05 11:05:34 +0000161 }
162
Alice Wang3397b362023-12-01 13:57:10 +0000163 pub(crate) fn microdroid_payload(&self) -> &DiceChainEntryPayload {
Alice Wang1cc13502023-12-05 11:05:34 +0000164 &self.payloads[self.payloads.len() - 1]
165 }
166
167 pub(crate) fn microdroid_payload_components(&self) -> Option<&Vec<SubComponent>> {
168 self.microdroid_payload().config_descriptor.sub_components.as_ref()
Alice Wangd3a96402023-11-24 15:37:39 +0000169 }
170
171 /// Returns true if all payloads in the DICE chain are in normal mode.
172 pub(crate) fn all_entries_are_secure(&self) -> bool {
173 self.payloads.iter().all(|p| p.mode == DiceMode::kDiceModeNormal)
174 }
175}
176
Alice Wang9eebbab2024-04-10 14:57:27 +0000177fn vendor_partition_exists(
178 client_vm_dice_chain_len: usize,
179 service_vm_dice_chain_len: usize,
180) -> Result<bool> {
181 let entries_up_to_pvmfw_len = service_vm_dice_chain_len - 1;
182 // Client VM DICE chain = entries_up_to_pvmfw
183 // + Vendor module entry (exists only when the vendor partition is present)
184 // + Microdroid kernel entry (added in pvmfw)
185 // + Apk/Apexes entry (added in microdroid)
186 match client_vm_dice_chain_len.checked_sub(entries_up_to_pvmfw_len) {
187 Some(2) => {
188 debug!("The vendor partition entry is not present in the client VM's DICE chain");
189 Ok(false)
190 }
191 Some(3) => {
192 info!("The vendor partition entry is present in the client VM's DICE chain");
193 Ok(true)
194 }
195 _ => {
196 error!(
197 "The client VM's DICE chain must contain two or three extra entries. \
198 Service VM DICE chain: {} entries, client VM DICE chain: {} entries",
199 service_vm_dice_chain_len, client_vm_dice_chain_len
200 );
201 Err(RequestProcessingError::InvalidDiceChain)
202 }
Alice Wangd3a96402023-11-24 15:37:39 +0000203 }
Alice Wangd3a96402023-11-24 15:37:39 +0000204}
205
206#[derive(Debug, Clone)]
207pub(crate) struct PublicKey(CoseKey);
208
209impl TryFrom<CoseKey> for PublicKey {
210 type Error = RequestProcessingError;
211
212 fn try_from(key: CoseKey) -> Result<Self> {
Alan Stokes33761202024-05-08 10:54:52 +0100213 // The public key must allow use for verification.
214 // Note that an empty key_ops set implicitly allows everything.
215 let key_ops = &key.key_ops;
216 if !key_ops.is_empty()
217 && !key_ops.contains(&KeyOperation::Assigned(iana::KeyOperation::Verify))
218 {
Alice Wangd3a96402023-11-24 15:37:39 +0000219 error!("Public key does not support verification");
220 return Err(RequestProcessingError::InvalidDiceChain);
221 }
222 Ok(Self(key))
223 }
224}
225
Alice Wang3397b362023-12-01 13:57:10 +0000226impl PublicKey {
227 /// Verifies the signature of the provided message with the public key.
228 ///
229 /// This function supports the following key/algorithm types as specified in
230 /// hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
231 /// generateCertificateRequestV2.cddl:
232 ///
233 /// PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384
Alan Stokesb2f52fb2024-05-09 10:12:55 +0100234 ///
235 /// The signature should be in the format defined by COSE in RFC 9053 section 2 for the
236 /// specifric algorithm.
Alice Wang3397b362023-12-01 13:57:10 +0000237 pub(crate) fn verify(&self, signature: &[u8], message: &[u8]) -> Result<()> {
238 match &self.0.kty {
239 KeyType::Assigned(iana::KeyType::EC2) => {
240 let public_key = EcKey::from_cose_public_key(&self.0)?;
241 let Some(Algorithm::Assigned(alg)) = self.0.alg else {
242 error!("Invalid algorithm in COSE key {:?}", self.0.alg);
243 return Err(RequestProcessingError::InvalidDiceChain);
244 };
245 let digester = match alg {
246 iana::Algorithm::ES256 => Digester::sha256(),
247 iana::Algorithm::ES384 => Digester::sha384(),
248 _ => {
249 error!("Unsupported algorithm in EC2 key: {:?}", alg);
250 return Err(RequestProcessingError::InvalidDiceChain);
251 }
252 };
253 let digest = digester.digest(message)?;
Alan Stokesb2f52fb2024-05-09 10:12:55 +0100254 Ok(public_key.ecdsa_verify_nist(signature, &digest)?)
Alice Wang3397b362023-12-01 13:57:10 +0000255 }
256 KeyType::Assigned(iana::KeyType::OKP) => {
257 let curve_type =
258 get_label_value(&self.0, Label::Int(iana::OkpKeyParameter::Crv.to_i64()))?;
259 if curve_type != &Value::from(iana::EllipticCurve::Ed25519.to_i64()) {
260 error!("Unsupported curve type in OKP COSE key: {:?}", curve_type);
261 return Err(RequestProcessingError::OperationUnimplemented);
262 }
263 let x = get_label_value_as_bytes(
264 &self.0,
265 Label::Int(iana::OkpKeyParameter::X.to_i64()),
266 )?;
267 let public_key = x.try_into().map_err(|_| {
268 error!("Invalid ED25519 public key size: {}", x.len());
269 RequestProcessingError::InvalidDiceChain
270 })?;
271 let signature = signature.try_into().map_err(|_| {
272 error!("Invalid ED25519 signature size: {}", signature.len());
273 RequestProcessingError::InvalidDiceChain
274 })?;
275 Ok(ed25519_verify(message, signature, public_key)?)
276 }
277 kty => {
278 error!("Unsupported key type in COSE key: {:?}", kty);
279 Err(RequestProcessingError::OperationUnimplemented)
280 }
281 }
282 }
283}
284
Alice Wangd3a96402023-11-24 15:37:39 +0000285/// Represents a partially decoded `DiceChainEntryPayload`. The whole payload is defined in:
286///
287/// hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
288/// generateCertificateRequestV2.cddl
289#[derive(Debug, Clone)]
290pub(crate) struct DiceChainEntryPayload {
Alice Wang3397b362023-12-01 13:57:10 +0000291 pub(crate) subject_public_key: PublicKey,
Alice Wangd3a96402023-11-24 15:37:39 +0000292 mode: DiceMode,
Alice Wang4e093102023-12-13 09:16:29 +0000293 pub(crate) code_hash: [u8; HASH_SIZE],
294 pub(crate) authority_hash: [u8; HASH_SIZE],
Alice Wang1cc13502023-12-05 11:05:34 +0000295 config_descriptor: ConfigDescriptor,
Alice Wangd3a96402023-11-24 15:37:39 +0000296}
297
298impl DiceChainEntryPayload {
299 /// Validates the signature of the provided CBOR value with the provided public key and
300 /// extracts payload from the value.
301 fn validate_cose_signature_and_extract_payload(
302 value: Value,
Alice Wang3397b362023-12-01 13:57:10 +0000303 authority_public_key: &PublicKey,
Alice Wangd3a96402023-11-24 15:37:39 +0000304 ) -> Result<Self> {
305 let cose_sign1 = CoseSign1::from_cbor_value(value)?;
Alice Wang3397b362023-12-01 13:57:10 +0000306 let aad = &[]; // AAD is not used in DICE chain entry.
307 cose_sign1.verify_signature(aad, |signature, message| {
308 authority_public_key.verify(signature, message)
309 })?;
Alice Wangd3a96402023-11-24 15:37:39 +0000310
311 let payload = cose_sign1.payload.ok_or_else(|| {
312 error!("No payload found in the DICE chain entry");
313 RequestProcessingError::InvalidDiceChain
314 })?;
Alice Wang4e093102023-12-13 09:16:29 +0000315 Self::from_slice(&payload)
Alice Wangd3a96402023-11-24 15:37:39 +0000316 }
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000317
Alice Wang4e093102023-12-13 09:16:29 +0000318 pub(crate) fn from_slice(data: &[u8]) -> Result<Self> {
319 let entries = value_to_map(Value::from_slice(data)?, "DiceChainEntryPayload")?;
320 let mut builder = PayloadBuilder::default();
321 for (key, value) in entries.into_iter() {
322 let key: i64 = value_to_num(key, "DiceChainEntryPayload key")?;
323 match key {
324 SUBJECT_PUBLIC_KEY => {
325 let subject_public_key = value_to_bytes(value, "subject_public_key")?;
326 let subject_public_key =
327 CoseKey::from_slice(&subject_public_key)?.try_into()?;
328 builder.subject_public_key(subject_public_key)?;
329 }
330 MODE => builder.mode(to_mode(value)?)?,
331 CODE_HASH => {
332 let code_hash = value_to_byte_array(value, "DiceChainEntryPayload code_hash")?;
333 builder.code_hash(code_hash)?;
334 }
335 AUTHORITY_HASH => {
336 let authority_hash =
337 value_to_byte_array(value, "DiceChainEntryPayload authority_hash")?;
338 builder.authority_hash(authority_hash)?;
339 }
340 CONFIG_DESC => {
341 let config_descriptor = value_to_bytes(value, "config_descriptor")?;
342 let config_descriptor = ConfigDescriptor::from_slice(&config_descriptor)?;
343 builder.config_descriptor(config_descriptor)?;
344 }
345 _ => {}
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000346 }
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000347 }
Alice Wang4e093102023-12-13 09:16:29 +0000348 builder.build()
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000349 }
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000350}
Alice Wang1cc13502023-12-05 11:05:34 +0000351/// Represents a partially decoded `ConfigurationDescriptor`.
352///
353/// The whole `ConfigurationDescriptor` is defined in:
354///
355/// hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
356/// generateCertificateRequestV2.cddl
357#[derive(Debug, Clone)]
358pub(crate) struct ConfigDescriptor {
359 component_name: String,
360 sub_components: Option<Vec<SubComponent>>,
361}
362
363impl ConfigDescriptor {
364 fn from_slice(data: &[u8]) -> Result<Self> {
365 let value = Value::from_slice(data)?;
366 let entries = value_to_map(value, "ConfigDescriptor")?;
367 let mut builder = ConfigDescriptorBuilder::default();
368 for (key, value) in entries.into_iter() {
369 let key: i64 = value_to_num(key, "ConfigDescriptor key")?;
370 match key {
371 CONFIG_DESC_COMPONENT_NAME => {
372 let name = value_to_text(value, "ConfigDescriptor component_name")?;
373 builder.component_name(name)?;
374 }
375 CONFIG_DESC_SUB_COMPONENTS => {
376 let sub_components = value_to_array(value, "ConfigDescriptor sub_components")?;
377 let sub_components = sub_components
378 .into_iter()
379 .map(SubComponent::try_from)
380 .collect::<Result<Vec<_>>>()?;
381 builder.sub_components(sub_components)?
382 }
383 _ => {}
384 }
385 }
386 builder.build()
387 }
388}
389
390#[derive(Debug, Clone, Default)]
391struct ConfigDescriptorBuilder {
392 component_name: OnceCell<String>,
393 sub_components: OnceCell<Vec<SubComponent>>,
394}
395
396impl ConfigDescriptorBuilder {
397 fn component_name(&mut self, component_name: String) -> Result<()> {
398 set_once(&self.component_name, component_name, "ConfigDescriptor component_name")
399 }
400
401 fn sub_components(&mut self, sub_components: Vec<SubComponent>) -> Result<()> {
402 set_once(&self.sub_components, sub_components, "ConfigDescriptor sub_components")
403 }
404
405 fn build(mut self) -> Result<ConfigDescriptor> {
406 let component_name =
407 take_value(&mut self.component_name, "ConfigDescriptor component_name")?;
408 let sub_components = self.sub_components.take();
409 Ok(ConfigDescriptor { component_name, sub_components })
410 }
411}
412
413#[derive(Debug, Clone)]
414pub(crate) struct SubComponent {
415 pub(crate) name: String,
416 pub(crate) version: u64,
417 pub(crate) code_hash: Vec<u8>,
418 pub(crate) authority_hash: Vec<u8>,
419}
420
421impl TryFrom<Value> for SubComponent {
422 type Error = RequestProcessingError;
423
424 fn try_from(value: Value) -> Result<Self> {
425 let entries = value_to_map(value, "SubComponent")?;
426 let mut builder = SubComponentBuilder::default();
427 for (key, value) in entries.into_iter() {
428 let key: i64 = value_to_num(key, "SubComponent key")?;
429 match key {
430 SUB_COMPONENT_NAME => {
431 builder.name(value_to_text(value, "SubComponent component_name")?)?
432 }
433 SUB_COMPONENT_VERSION => {
434 builder.version(value_to_num(value, "SubComponent version")?)?
435 }
436 SUB_COMPONENT_CODE_HASH => {
437 builder.code_hash(value_to_bytes(value, "SubComponent code_hash")?)?
438 }
439 SUB_COMPONENT_AUTHORITY_HASH => {
440 builder.authority_hash(value_to_bytes(value, "SubComponent authority_hash")?)?
441 }
442 k => {
443 error!("Unknown key in SubComponent: {}", k);
444 return Err(RequestProcessingError::InvalidDiceChain);
445 }
446 }
447 }
448 builder.build()
449 }
450}
451
452#[derive(Debug, Clone, Default)]
453struct SubComponentBuilder {
454 name: OnceCell<String>,
455 version: OnceCell<u64>,
456 code_hash: OnceCell<Vec<u8>>,
457 authority_hash: OnceCell<Vec<u8>>,
458}
459
460impl SubComponentBuilder {
461 fn name(&mut self, name: String) -> Result<()> {
462 set_once(&self.name, name, "SubComponent name")
463 }
464
465 fn version(&mut self, version: u64) -> Result<()> {
466 set_once(&self.version, version, "SubComponent version")
467 }
468
469 fn code_hash(&mut self, code_hash: Vec<u8>) -> Result<()> {
470 set_once(&self.code_hash, code_hash, "SubComponent code_hash")
471 }
472
473 fn authority_hash(&mut self, authority_hash: Vec<u8>) -> Result<()> {
474 set_once(&self.authority_hash, authority_hash, "SubComponent authority_hash")
475 }
476
477 fn build(mut self) -> Result<SubComponent> {
478 let name = take_value(&mut self.name, "SubComponent name")?;
479 let version = take_value(&mut self.version, "SubComponent version")?;
480 let code_hash = take_value(&mut self.code_hash, "SubComponent code_hash")?;
481 let authority_hash = take_value(&mut self.authority_hash, "SubComponent authority_hash")?;
482 Ok(SubComponent { name, version, code_hash, authority_hash })
483 }
484}
485
Alice Wangd3a96402023-11-24 15:37:39 +0000486fn to_mode(value: Value) -> Result<DiceMode> {
487 let mode = match value {
488 // Mode is supposed to be encoded as a 1-byte bstr, but some implementations instead
489 // encode it as an integer. Accept either. See b/273552826.
490 // If Mode is omitted, it should be treated as if it was NotConfigured, according to
491 // the Open Profile for DICE spec.
492 Value::Bytes(bytes) => {
493 if bytes.len() != 1 {
494 error!("Bytes array with invalid length for mode: {:?}", bytes.len());
495 return Err(RequestProcessingError::InvalidDiceChain);
496 }
497 bytes[0].into()
498 }
499 Value::Integer(i) => i,
500 v => return Err(CoseError::UnexpectedItem(cbor_value_type(&v), "bstr or int").into()),
501 };
502 let mode = match mode {
503 x if x == (DiceMode::kDiceModeNormal as i64).into() => DiceMode::kDiceModeNormal,
504 x if x == (DiceMode::kDiceModeDebug as i64).into() => DiceMode::kDiceModeDebug,
505 x if x == (DiceMode::kDiceModeMaintenance as i64).into() => DiceMode::kDiceModeMaintenance,
506 // If Mode is invalid, it should be treated as if it was NotConfigured, according to
507 // the Open Profile for DICE spec.
508 _ => DiceMode::kDiceModeNotInitialized,
509 };
510 Ok(mode)
511}
512
513#[derive(Default, Debug, Clone)]
514struct PayloadBuilder {
515 subject_public_key: OnceCell<PublicKey>,
516 mode: OnceCell<DiceMode>,
517 code_hash: OnceCell<[u8; HASH_SIZE]>,
518 authority_hash: OnceCell<[u8; HASH_SIZE]>,
Alice Wang1cc13502023-12-05 11:05:34 +0000519 config_descriptor: OnceCell<ConfigDescriptor>,
Alice Wangd3a96402023-11-24 15:37:39 +0000520}
521
522fn set_once<T>(field: &OnceCell<T>, value: T, field_name: &str) -> Result<()> {
523 field.set(value).map_err(|_| {
524 error!("Field '{field_name}' is duplicated in the Payload");
525 RequestProcessingError::InvalidDiceChain
526 })
527}
528
529fn take_value<T>(field: &mut OnceCell<T>, field_name: &str) -> Result<T> {
530 field.take().ok_or_else(|| {
531 error!("Field '{field_name}' is missing in the Payload");
532 RequestProcessingError::InvalidDiceChain
533 })
534}
535
536impl PayloadBuilder {
537 fn subject_public_key(&mut self, key: PublicKey) -> Result<()> {
538 set_once(&self.subject_public_key, key, "subject_public_key")
539 }
540
541 fn mode(&mut self, mode: DiceMode) -> Result<()> {
542 set_once(&self.mode, mode, "mode")
543 }
544
545 fn code_hash(&mut self, code_hash: [u8; HASH_SIZE]) -> Result<()> {
546 set_once(&self.code_hash, code_hash, "code_hash")
547 }
548
549 fn authority_hash(&mut self, authority_hash: [u8; HASH_SIZE]) -> Result<()> {
550 set_once(&self.authority_hash, authority_hash, "authority_hash")
551 }
552
Alice Wang1cc13502023-12-05 11:05:34 +0000553 fn config_descriptor(&mut self, config_descriptor: ConfigDescriptor) -> Result<()> {
Alice Wangd3a96402023-11-24 15:37:39 +0000554 set_once(&self.config_descriptor, config_descriptor, "config_descriptor")
555 }
556
557 fn build(mut self) -> Result<DiceChainEntryPayload> {
558 let subject_public_key = take_value(&mut self.subject_public_key, "subject_public_key")?;
559 // If Mode is omitted, it should be treated as if it was NotConfigured, according to
560 // the Open Profile for DICE spec.
561 let mode = self.mode.take().unwrap_or(DiceMode::kDiceModeNotInitialized);
562 let code_hash = take_value(&mut self.code_hash, "code_hash")?;
563 let authority_hash = take_value(&mut self.authority_hash, "authority_hash")?;
564 let config_descriptor = take_value(&mut self.config_descriptor, "config_descriptor")?;
565 Ok(DiceChainEntryPayload {
566 subject_public_key,
567 mode,
568 code_hash,
569 authority_hash,
570 config_descriptor,
571 })
572 }
573}