blob: df29676916df06c4295bffe6c6cdf3bc733738bb [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> {
213 if !key.key_ops.contains(&KeyOperation::Assigned(iana::KeyOperation::Verify)) {
214 error!("Public key does not support verification");
215 return Err(RequestProcessingError::InvalidDiceChain);
216 }
217 Ok(Self(key))
218 }
219}
220
Alice Wang3397b362023-12-01 13:57:10 +0000221impl PublicKey {
222 /// Verifies the signature of the provided message with the public key.
223 ///
224 /// This function supports the following key/algorithm types as specified in
225 /// hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
226 /// generateCertificateRequestV2.cddl:
227 ///
228 /// PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384
229 pub(crate) fn verify(&self, signature: &[u8], message: &[u8]) -> Result<()> {
230 match &self.0.kty {
231 KeyType::Assigned(iana::KeyType::EC2) => {
232 let public_key = EcKey::from_cose_public_key(&self.0)?;
233 let Some(Algorithm::Assigned(alg)) = self.0.alg else {
234 error!("Invalid algorithm in COSE key {:?}", self.0.alg);
235 return Err(RequestProcessingError::InvalidDiceChain);
236 };
237 let digester = match alg {
238 iana::Algorithm::ES256 => Digester::sha256(),
239 iana::Algorithm::ES384 => Digester::sha384(),
240 _ => {
241 error!("Unsupported algorithm in EC2 key: {:?}", alg);
242 return Err(RequestProcessingError::InvalidDiceChain);
243 }
244 };
245 let digest = digester.digest(message)?;
246 Ok(public_key.ecdsa_verify(signature, &digest)?)
247 }
248 KeyType::Assigned(iana::KeyType::OKP) => {
249 let curve_type =
250 get_label_value(&self.0, Label::Int(iana::OkpKeyParameter::Crv.to_i64()))?;
251 if curve_type != &Value::from(iana::EllipticCurve::Ed25519.to_i64()) {
252 error!("Unsupported curve type in OKP COSE key: {:?}", curve_type);
253 return Err(RequestProcessingError::OperationUnimplemented);
254 }
255 let x = get_label_value_as_bytes(
256 &self.0,
257 Label::Int(iana::OkpKeyParameter::X.to_i64()),
258 )?;
259 let public_key = x.try_into().map_err(|_| {
260 error!("Invalid ED25519 public key size: {}", x.len());
261 RequestProcessingError::InvalidDiceChain
262 })?;
263 let signature = signature.try_into().map_err(|_| {
264 error!("Invalid ED25519 signature size: {}", signature.len());
265 RequestProcessingError::InvalidDiceChain
266 })?;
267 Ok(ed25519_verify(message, signature, public_key)?)
268 }
269 kty => {
270 error!("Unsupported key type in COSE key: {:?}", kty);
271 Err(RequestProcessingError::OperationUnimplemented)
272 }
273 }
274 }
275}
276
Alice Wangd3a96402023-11-24 15:37:39 +0000277/// Represents a partially decoded `DiceChainEntryPayload`. The whole payload is defined in:
278///
279/// hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
280/// generateCertificateRequestV2.cddl
281#[derive(Debug, Clone)]
282pub(crate) struct DiceChainEntryPayload {
Alice Wang3397b362023-12-01 13:57:10 +0000283 pub(crate) subject_public_key: PublicKey,
Alice Wangd3a96402023-11-24 15:37:39 +0000284 mode: DiceMode,
Alice Wang4e093102023-12-13 09:16:29 +0000285 pub(crate) code_hash: [u8; HASH_SIZE],
286 pub(crate) authority_hash: [u8; HASH_SIZE],
Alice Wang1cc13502023-12-05 11:05:34 +0000287 config_descriptor: ConfigDescriptor,
Alice Wangd3a96402023-11-24 15:37:39 +0000288}
289
290impl DiceChainEntryPayload {
291 /// Validates the signature of the provided CBOR value with the provided public key and
292 /// extracts payload from the value.
293 fn validate_cose_signature_and_extract_payload(
294 value: Value,
Alice Wang3397b362023-12-01 13:57:10 +0000295 authority_public_key: &PublicKey,
Alice Wangd3a96402023-11-24 15:37:39 +0000296 ) -> Result<Self> {
297 let cose_sign1 = CoseSign1::from_cbor_value(value)?;
Alice Wang3397b362023-12-01 13:57:10 +0000298 let aad = &[]; // AAD is not used in DICE chain entry.
299 cose_sign1.verify_signature(aad, |signature, message| {
300 authority_public_key.verify(signature, message)
301 })?;
Alice Wangd3a96402023-11-24 15:37:39 +0000302
303 let payload = cose_sign1.payload.ok_or_else(|| {
304 error!("No payload found in the DICE chain entry");
305 RequestProcessingError::InvalidDiceChain
306 })?;
Alice Wang4e093102023-12-13 09:16:29 +0000307 Self::from_slice(&payload)
Alice Wangd3a96402023-11-24 15:37:39 +0000308 }
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000309
Alice Wang4e093102023-12-13 09:16:29 +0000310 pub(crate) fn from_slice(data: &[u8]) -> Result<Self> {
311 let entries = value_to_map(Value::from_slice(data)?, "DiceChainEntryPayload")?;
312 let mut builder = PayloadBuilder::default();
313 for (key, value) in entries.into_iter() {
314 let key: i64 = value_to_num(key, "DiceChainEntryPayload key")?;
315 match key {
316 SUBJECT_PUBLIC_KEY => {
317 let subject_public_key = value_to_bytes(value, "subject_public_key")?;
318 let subject_public_key =
319 CoseKey::from_slice(&subject_public_key)?.try_into()?;
320 builder.subject_public_key(subject_public_key)?;
321 }
322 MODE => builder.mode(to_mode(value)?)?,
323 CODE_HASH => {
324 let code_hash = value_to_byte_array(value, "DiceChainEntryPayload code_hash")?;
325 builder.code_hash(code_hash)?;
326 }
327 AUTHORITY_HASH => {
328 let authority_hash =
329 value_to_byte_array(value, "DiceChainEntryPayload authority_hash")?;
330 builder.authority_hash(authority_hash)?;
331 }
332 CONFIG_DESC => {
333 let config_descriptor = value_to_bytes(value, "config_descriptor")?;
334 let config_descriptor = ConfigDescriptor::from_slice(&config_descriptor)?;
335 builder.config_descriptor(config_descriptor)?;
336 }
337 _ => {}
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000338 }
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000339 }
Alice Wang4e093102023-12-13 09:16:29 +0000340 builder.build()
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000341 }
Ajinkya Chalkebd511762023-12-12 11:57:03 +0000342}
Alice Wang1cc13502023-12-05 11:05:34 +0000343/// Represents a partially decoded `ConfigurationDescriptor`.
344///
345/// The whole `ConfigurationDescriptor` is defined in:
346///
347/// hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
348/// generateCertificateRequestV2.cddl
349#[derive(Debug, Clone)]
350pub(crate) struct ConfigDescriptor {
351 component_name: String,
352 sub_components: Option<Vec<SubComponent>>,
353}
354
355impl ConfigDescriptor {
356 fn from_slice(data: &[u8]) -> Result<Self> {
357 let value = Value::from_slice(data)?;
358 let entries = value_to_map(value, "ConfigDescriptor")?;
359 let mut builder = ConfigDescriptorBuilder::default();
360 for (key, value) in entries.into_iter() {
361 let key: i64 = value_to_num(key, "ConfigDescriptor key")?;
362 match key {
363 CONFIG_DESC_COMPONENT_NAME => {
364 let name = value_to_text(value, "ConfigDescriptor component_name")?;
365 builder.component_name(name)?;
366 }
367 CONFIG_DESC_SUB_COMPONENTS => {
368 let sub_components = value_to_array(value, "ConfigDescriptor sub_components")?;
369 let sub_components = sub_components
370 .into_iter()
371 .map(SubComponent::try_from)
372 .collect::<Result<Vec<_>>>()?;
373 builder.sub_components(sub_components)?
374 }
375 _ => {}
376 }
377 }
378 builder.build()
379 }
380}
381
382#[derive(Debug, Clone, Default)]
383struct ConfigDescriptorBuilder {
384 component_name: OnceCell<String>,
385 sub_components: OnceCell<Vec<SubComponent>>,
386}
387
388impl ConfigDescriptorBuilder {
389 fn component_name(&mut self, component_name: String) -> Result<()> {
390 set_once(&self.component_name, component_name, "ConfigDescriptor component_name")
391 }
392
393 fn sub_components(&mut self, sub_components: Vec<SubComponent>) -> Result<()> {
394 set_once(&self.sub_components, sub_components, "ConfigDescriptor sub_components")
395 }
396
397 fn build(mut self) -> Result<ConfigDescriptor> {
398 let component_name =
399 take_value(&mut self.component_name, "ConfigDescriptor component_name")?;
400 let sub_components = self.sub_components.take();
401 Ok(ConfigDescriptor { component_name, sub_components })
402 }
403}
404
405#[derive(Debug, Clone)]
406pub(crate) struct SubComponent {
407 pub(crate) name: String,
408 pub(crate) version: u64,
409 pub(crate) code_hash: Vec<u8>,
410 pub(crate) authority_hash: Vec<u8>,
411}
412
413impl TryFrom<Value> for SubComponent {
414 type Error = RequestProcessingError;
415
416 fn try_from(value: Value) -> Result<Self> {
417 let entries = value_to_map(value, "SubComponent")?;
418 let mut builder = SubComponentBuilder::default();
419 for (key, value) in entries.into_iter() {
420 let key: i64 = value_to_num(key, "SubComponent key")?;
421 match key {
422 SUB_COMPONENT_NAME => {
423 builder.name(value_to_text(value, "SubComponent component_name")?)?
424 }
425 SUB_COMPONENT_VERSION => {
426 builder.version(value_to_num(value, "SubComponent version")?)?
427 }
428 SUB_COMPONENT_CODE_HASH => {
429 builder.code_hash(value_to_bytes(value, "SubComponent code_hash")?)?
430 }
431 SUB_COMPONENT_AUTHORITY_HASH => {
432 builder.authority_hash(value_to_bytes(value, "SubComponent authority_hash")?)?
433 }
434 k => {
435 error!("Unknown key in SubComponent: {}", k);
436 return Err(RequestProcessingError::InvalidDiceChain);
437 }
438 }
439 }
440 builder.build()
441 }
442}
443
444#[derive(Debug, Clone, Default)]
445struct SubComponentBuilder {
446 name: OnceCell<String>,
447 version: OnceCell<u64>,
448 code_hash: OnceCell<Vec<u8>>,
449 authority_hash: OnceCell<Vec<u8>>,
450}
451
452impl SubComponentBuilder {
453 fn name(&mut self, name: String) -> Result<()> {
454 set_once(&self.name, name, "SubComponent name")
455 }
456
457 fn version(&mut self, version: u64) -> Result<()> {
458 set_once(&self.version, version, "SubComponent version")
459 }
460
461 fn code_hash(&mut self, code_hash: Vec<u8>) -> Result<()> {
462 set_once(&self.code_hash, code_hash, "SubComponent code_hash")
463 }
464
465 fn authority_hash(&mut self, authority_hash: Vec<u8>) -> Result<()> {
466 set_once(&self.authority_hash, authority_hash, "SubComponent authority_hash")
467 }
468
469 fn build(mut self) -> Result<SubComponent> {
470 let name = take_value(&mut self.name, "SubComponent name")?;
471 let version = take_value(&mut self.version, "SubComponent version")?;
472 let code_hash = take_value(&mut self.code_hash, "SubComponent code_hash")?;
473 let authority_hash = take_value(&mut self.authority_hash, "SubComponent authority_hash")?;
474 Ok(SubComponent { name, version, code_hash, authority_hash })
475 }
476}
477
Alice Wangd3a96402023-11-24 15:37:39 +0000478fn to_mode(value: Value) -> Result<DiceMode> {
479 let mode = match value {
480 // Mode is supposed to be encoded as a 1-byte bstr, but some implementations instead
481 // encode it as an integer. Accept either. See b/273552826.
482 // If Mode is omitted, it should be treated as if it was NotConfigured, according to
483 // the Open Profile for DICE spec.
484 Value::Bytes(bytes) => {
485 if bytes.len() != 1 {
486 error!("Bytes array with invalid length for mode: {:?}", bytes.len());
487 return Err(RequestProcessingError::InvalidDiceChain);
488 }
489 bytes[0].into()
490 }
491 Value::Integer(i) => i,
492 v => return Err(CoseError::UnexpectedItem(cbor_value_type(&v), "bstr or int").into()),
493 };
494 let mode = match mode {
495 x if x == (DiceMode::kDiceModeNormal as i64).into() => DiceMode::kDiceModeNormal,
496 x if x == (DiceMode::kDiceModeDebug as i64).into() => DiceMode::kDiceModeDebug,
497 x if x == (DiceMode::kDiceModeMaintenance as i64).into() => DiceMode::kDiceModeMaintenance,
498 // If Mode is invalid, it should be treated as if it was NotConfigured, according to
499 // the Open Profile for DICE spec.
500 _ => DiceMode::kDiceModeNotInitialized,
501 };
502 Ok(mode)
503}
504
505#[derive(Default, Debug, Clone)]
506struct PayloadBuilder {
507 subject_public_key: OnceCell<PublicKey>,
508 mode: OnceCell<DiceMode>,
509 code_hash: OnceCell<[u8; HASH_SIZE]>,
510 authority_hash: OnceCell<[u8; HASH_SIZE]>,
Alice Wang1cc13502023-12-05 11:05:34 +0000511 config_descriptor: OnceCell<ConfigDescriptor>,
Alice Wangd3a96402023-11-24 15:37:39 +0000512}
513
514fn set_once<T>(field: &OnceCell<T>, value: T, field_name: &str) -> Result<()> {
515 field.set(value).map_err(|_| {
516 error!("Field '{field_name}' is duplicated in the Payload");
517 RequestProcessingError::InvalidDiceChain
518 })
519}
520
521fn take_value<T>(field: &mut OnceCell<T>, field_name: &str) -> Result<T> {
522 field.take().ok_or_else(|| {
523 error!("Field '{field_name}' is missing in the Payload");
524 RequestProcessingError::InvalidDiceChain
525 })
526}
527
528impl PayloadBuilder {
529 fn subject_public_key(&mut self, key: PublicKey) -> Result<()> {
530 set_once(&self.subject_public_key, key, "subject_public_key")
531 }
532
533 fn mode(&mut self, mode: DiceMode) -> Result<()> {
534 set_once(&self.mode, mode, "mode")
535 }
536
537 fn code_hash(&mut self, code_hash: [u8; HASH_SIZE]) -> Result<()> {
538 set_once(&self.code_hash, code_hash, "code_hash")
539 }
540
541 fn authority_hash(&mut self, authority_hash: [u8; HASH_SIZE]) -> Result<()> {
542 set_once(&self.authority_hash, authority_hash, "authority_hash")
543 }
544
Alice Wang1cc13502023-12-05 11:05:34 +0000545 fn config_descriptor(&mut self, config_descriptor: ConfigDescriptor) -> Result<()> {
Alice Wangd3a96402023-11-24 15:37:39 +0000546 set_once(&self.config_descriptor, config_descriptor, "config_descriptor")
547 }
548
549 fn build(mut self) -> Result<DiceChainEntryPayload> {
550 let subject_public_key = take_value(&mut self.subject_public_key, "subject_public_key")?;
551 // If Mode is omitted, it should be treated as if it was NotConfigured, according to
552 // the Open Profile for DICE spec.
553 let mode = self.mode.take().unwrap_or(DiceMode::kDiceModeNotInitialized);
554 let code_hash = take_value(&mut self.code_hash, "code_hash")?;
555 let authority_hash = take_value(&mut self.authority_hash, "authority_hash")?;
556 let config_descriptor = take_value(&mut self.config_descriptor, "config_descriptor")?;
557 Ok(DiceChainEntryPayload {
558 subject_public_key,
559 mode,
560 code_hash,
561 authority_hash,
562 config_descriptor,
563 })
564 }
565}