1 // 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
17 use alloc::string::String;
18 use alloc::vec;
19 use alloc::vec::Vec;
20 use bssl_avf::{ed25519_verify, Digester, EcKey};
21 use cbor_util::{
22 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,
24 };
25 use ciborium::value::Value;
26 use core::cell::OnceCell;
27 use core::result;
28 use coset::{
29 self,
30 iana::{self, EnumI64},
31 Algorithm, AsCborValue, CborSerializable, CoseError, CoseKey, CoseSign1, KeyOperation, KeyType,
32 Label,
33 };
34 use diced_open_dice::{DiceMode, HASH_SIZE};
35 use log::{debug, error, info};
36 use service_vm_comm::RequestProcessingError;
37
38 type Result<T> = result::Result<T, RequestProcessingError>;
39
40 const CODE_HASH: i64 = -4670545;
41 const CONFIG_DESC: i64 = -4670548;
42 const AUTHORITY_HASH: i64 = -4670549;
43 const MODE: i64 = -4670551;
44 const SUBJECT_PUBLIC_KEY: i64 = -4670552;
45
46 const CONFIG_DESC_COMPONENT_NAME: i64 = -70002;
47 const CONFIG_DESC_SUB_COMPONENTS: i64 = -71002;
48
49 const SUB_COMPONENT_NAME: i64 = 1;
50 const SUB_COMPONENT_VERSION: i64 = 2;
51 const SUB_COMPONENT_CODE_HASH: i64 = 3;
52 const SUB_COMPONENT_AUTHORITY_HASH: i64 = 4;
53
54 const KERNEL_COMPONENT_NAME: &str = "vm_entry";
55 const VENDOR_PARTITION_COMPONENT_NAME: &str = "Microdroid vendor";
56 const MICRODROID_PAYLOAD_COMPONENT_NAME: &str = "Microdroid payload";
57
58 /// 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)]
66 pub(crate) struct ClientVmDiceChain {
67 payloads: Vec<DiceChainEntryPayload>,
68 /// 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,
72 }
73
74 impl 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.
validate_signatures_and_parse_dice_chain( mut client_vm_dice_chain: Vec<Value>, service_vm_dice_chain_len: usize, ) -> Result<Self>82 pub(crate) fn validate_signatures_and_parse_dice_chain(
83 mut client_vm_dice_chain: Vec<Value>,
84 service_vm_dice_chain_len: usize,
85 ) -> Result<Self> {
86 let has_vendor_partition =
87 vendor_partition_exists(client_vm_dice_chain.len(), service_vm_dice_chain_len)?;
88
89 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 }
106
107 Self::build(payloads, has_vendor_partition)
108 }
109
build( dice_entry_payloads: Vec<DiceChainEntryPayload>, has_vendor_partition: bool, ) -> Result<Self>110 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;
116 if Some(MICRODROID_PAYLOAD_COMPONENT_NAME) != microdroid_payload_name.as_deref() {
117 error!(
118 "The last entry in the client VM DICE chain must describe the Microdroid \
119 payload. Got '{microdroid_payload_name:?}'"
120 );
121 return Err(RequestProcessingError::InvalidDiceChain);
122 }
123
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 Some(VENDOR_PARTITION_COMPONENT_NAME) != vendor_partition_name.as_deref() {
129 error!(
130 "The vendor partition entry in the client VM DICE chain must describe the \
131 vendor partition. Got '{vendor_partition_name:?}'"
132 );
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;
141 if Some(KERNEL_COMPONENT_NAME) != kernel_name.as_deref() {
142 error!(
143 "The microdroid kernel entry in the client VM DICE chain must describe the \
144 Microdroid kernel. Got '{kernel_name:?}'"
145 );
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 })
151 }
152
microdroid_kernel(&self) -> &DiceChainEntryPayload153 pub(crate) fn microdroid_kernel(&self) -> &DiceChainEntryPayload {
154 &self.payloads[self.kernel_index]
155 }
156
vendor_partition(&self) -> Option<&DiceChainEntryPayload>157 pub(crate) fn vendor_partition(&self) -> Option<&DiceChainEntryPayload> {
158 self.vendor_partition_index.map(|i| &self.payloads[i])
159 }
160
microdroid_payload(&self) -> &DiceChainEntryPayload161 pub(crate) fn microdroid_payload(&self) -> &DiceChainEntryPayload {
162 &self.payloads[self.payloads.len() - 1]
163 }
164
microdroid_payload_components(&self) -> Result<Vec<SubComponent>>165 pub(crate) fn microdroid_payload_components(&self) -> Result<Vec<SubComponent>> {
166 self.microdroid_payload().config_descriptor.sub_components()
167 }
168
169 /// Returns true if all payloads in the DICE chain are in normal mode.
all_entries_are_secure(&self) -> bool170 pub(crate) fn all_entries_are_secure(&self) -> bool {
171 self.payloads.iter().all(|p| p.mode == DiceMode::kDiceModeNormal)
172 }
173 }
174
vendor_partition_exists( client_vm_dice_chain_len: usize, service_vm_dice_chain_len: usize, ) -> Result<bool>175 fn 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 }
201 }
202 }
203
204 #[derive(Debug, Clone)]
205 pub(crate) struct PublicKey(CoseKey);
206
207 impl TryFrom<CoseKey> for PublicKey {
208 type Error = RequestProcessingError;
209
try_from(key: CoseKey) -> Result<Self>210 fn try_from(key: CoseKey) -> Result<Self> {
211 // 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 {
217 error!("Public key does not support verification - key_ops: {key_ops:?}");
218 return Err(RequestProcessingError::InvalidDiceChain);
219 }
220 Ok(Self(key))
221 }
222 }
223
224 impl 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
232 ///
233 /// The signature should be in the format defined by COSE in RFC 9053 section 2 for the
234 /// specific algorithm.
verify(&self, signature: &[u8], message: &[u8]) -> Result<()>235 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)?;
252 Ok(public_key.ecdsa_verify_cose(signature, &digest)?)
253 }
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
283 /// 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)]
288 pub(crate) struct DiceChainEntryPayload {
289 pub(crate) subject_public_key: PublicKey,
290 mode: DiceMode,
291 pub(crate) code_hash: [u8; HASH_SIZE],
292 pub(crate) authority_hash: [u8; HASH_SIZE],
293 config_descriptor: ConfigDescriptor,
294 }
295
296 impl DiceChainEntryPayload {
297 /// Validates the signature of the provided CBOR value with the provided public key and
298 /// extracts payload from the value.
validate_cose_signature_and_extract_payload( value: Value, authority_public_key: &PublicKey, ) -> Result<Self>299 fn validate_cose_signature_and_extract_payload(
300 value: Value,
301 authority_public_key: &PublicKey,
302 ) -> Result<Self> {
303 let cose_sign1 = CoseSign1::from_cbor_value(value)?;
304 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 })?;
308
309 let payload = cose_sign1.payload.ok_or_else(|| {
310 error!("No payload found in the DICE chain entry");
311 RequestProcessingError::InvalidDiceChain
312 })?;
313 Self::from_slice(&payload)
314 }
315
from_slice(data: &[u8]) -> Result<Self>316 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 _ => {}
344 }
345 }
346 builder.build()
347 }
348 }
349 /// 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
355 #[derive(Debug, Clone, Default)]
356 pub(crate) struct ConfigDescriptor {
357 component_name: Option<String>,
358 sub_components: Option<Value>,
359 }
360
361 impl ConfigDescriptor {
from_slice(data: &[u8]) -> Result<Self>362 fn from_slice(data: &[u8]) -> Result<Self> {
363 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 };
370 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 => {
380 // 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)?
384 }
385 _ => {}
386 }
387 }
388 builder.build()
389 }
390
391 /// Attempt to decode any Microdroid sub-components that were present in this config descriptor.
sub_components(&self) -> Result<Vec<SubComponent>>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 }
399 }
400
401 #[derive(Debug, Clone, Default)]
402 struct ConfigDescriptorBuilder {
403 component_name: OnceCell<String>,
404 sub_components: OnceCell<Value>,
405 }
406
407 impl ConfigDescriptorBuilder {
component_name(&mut self, component_name: String) -> Result<()>408 fn component_name(&mut self, component_name: String) -> Result<()> {
409 set_once(&self.component_name, component_name, "ConfigDescriptor component_name")
410 }
411
sub_components(&mut self, sub_components: Value) -> Result<()>412 fn sub_components(&mut self, sub_components: Value) -> Result<()> {
413 set_once(&self.sub_components, sub_components, "ConfigDescriptor sub_components")
414 }
415
build(mut self) -> Result<ConfigDescriptor>416 fn build(mut self) -> Result<ConfigDescriptor> {
417 let component_name = self.component_name.take();
418 let sub_components = self.sub_components.take();
419 Ok(ConfigDescriptor { component_name, sub_components })
420 }
421 }
422
423 #[derive(Debug, Clone)]
424 pub(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
431 impl TryFrom<Value> for SubComponent {
432 type Error = RequestProcessingError;
433
try_from(value: Value) -> Result<Self>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)]
463 struct SubComponentBuilder {
464 name: OnceCell<String>,
465 version: OnceCell<u64>,
466 code_hash: OnceCell<Vec<u8>>,
467 authority_hash: OnceCell<Vec<u8>>,
468 }
469
470 impl SubComponentBuilder {
name(&mut self, name: String) -> Result<()>471 fn name(&mut self, name: String) -> Result<()> {
472 set_once(&self.name, name, "SubComponent name")
473 }
474
version(&mut self, version: u64) -> Result<()>475 fn version(&mut self, version: u64) -> Result<()> {
476 set_once(&self.version, version, "SubComponent version")
477 }
478
code_hash(&mut self, code_hash: Vec<u8>) -> Result<()>479 fn code_hash(&mut self, code_hash: Vec<u8>) -> Result<()> {
480 set_once(&self.code_hash, code_hash, "SubComponent code_hash")
481 }
482
authority_hash(&mut self, authority_hash: Vec<u8>) -> Result<()>483 fn authority_hash(&mut self, authority_hash: Vec<u8>) -> Result<()> {
484 set_once(&self.authority_hash, authority_hash, "SubComponent authority_hash")
485 }
486
build(mut self) -> Result<SubComponent>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
to_mode(value: Value) -> Result<DiceMode>496 fn 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)]
524 struct 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]>,
529 config_descriptor: OnceCell<ConfigDescriptor>,
530 }
531
set_once<T>(field: &OnceCell<T>, value: T, field_name: &str) -> Result<()>532 fn 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
take_value<T>(field: &mut OnceCell<T>, field_name: &str) -> Result<T>539 fn 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
546 impl PayloadBuilder {
subject_public_key(&mut self, key: PublicKey) -> Result<()>547 fn subject_public_key(&mut self, key: PublicKey) -> Result<()> {
548 set_once(&self.subject_public_key, key, "subject_public_key")
549 }
550
mode(&mut self, mode: DiceMode) -> Result<()>551 fn mode(&mut self, mode: DiceMode) -> Result<()> {
552 set_once(&self.mode, mode, "mode")
553 }
554
code_hash(&mut self, code_hash: [u8; HASH_SIZE]) -> Result<()>555 fn code_hash(&mut self, code_hash: [u8; HASH_SIZE]) -> Result<()> {
556 set_once(&self.code_hash, code_hash, "code_hash")
557 }
558
authority_hash(&mut self, authority_hash: [u8; HASH_SIZE]) -> Result<()>559 fn authority_hash(&mut self, authority_hash: [u8; HASH_SIZE]) -> Result<()> {
560 set_once(&self.authority_hash, authority_hash, "authority_hash")
561 }
562
config_descriptor(&mut self, config_descriptor: ConfigDescriptor) -> Result<()>563 fn config_descriptor(&mut self, config_descriptor: ConfigDescriptor) -> Result<()> {
564 set_once(&self.config_descriptor, config_descriptor, "config_descriptor")
565 }
566
build(mut self) -> Result<DiceChainEntryPayload>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 }
584