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