Define the 'Dice' trait
Relevant types are moved from the encode module to the new dice module.
Change-Id: I66aca19638997dbef632b3b3b1cd84e145f58f1b
Reviewed-on: https://pigweed-review.googlesource.com/c/open-dice/+/209611
Commit-Queue: Darren Krahn <dkrahn@google.com>
Reviewed-by: Marshall Pierce <marshallpierce@google.com>
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
Reviewed-by: Andrew Scull <ascull@google.com>
diff --git a/dpe-rs/src/constants.rs b/dpe-rs/src/constants.rs
index f42954e..ddc8eba 100644
--- a/dpe-rs/src/constants.rs
+++ b/dpe-rs/src/constants.rs
@@ -73,6 +73,9 @@
/// The maximum number of certificates that can appear in a certificate chain.
pub(crate) const DPE_MAX_CERTIFICATES_PER_CHAIN: usize = 4;
+/// The maximum number of certificate info blocks that can be held per context.
+pub(crate) const DPE_MAX_CERTIFICATE_INFOS_PER_CONTEXT: usize = 6;
+
/// The maximum number of internal inputs that can be included in a message.
pub(crate) const DPE_MAX_INTERNAL_INPUTS: usize = 8;
diff --git a/dpe-rs/src/dice.rs b/dpe-rs/src/dice.rs
new file mode 100644
index 0000000..fd5bf1e
--- /dev/null
+++ b/dpe-rs/src/dice.rs
@@ -0,0 +1,198 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+//! Types and traits related to DICE.
+use crate::byte_array_wrapper;
+use crate::constants::{
+ DICE_CDI_SIZE, DICE_UDS_SIZE, DPE_MAX_CERTIFICATE_INFOS_PER_CONTEXT,
+ DPE_MAX_CERTIFICATE_SIZE,
+};
+use crate::crypto::{
+ EncryptionKey, Hash, MacKey, SealingPrivateKey, SealingPublicKey,
+ SigningPrivateKey, SigningPublicKey,
+};
+use crate::error::DpeResult;
+use heapless::Vec;
+use num_derive::{FromPrimitive, ToPrimitive};
+use zeroize::ZeroizeOnDrop;
+
+byte_array_wrapper!(Uds, DICE_UDS_SIZE, "UDS");
+byte_array_wrapper!(Cdi, DICE_CDI_SIZE, "CDI");
+
+/// A Vec wrapper to represent a single encoded certificate.
+#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, ZeroizeOnDrop)]
+pub(crate) struct Certificate(pub(crate) Vec<u8, DPE_MAX_CERTIFICATE_SIZE>);
+
+/// Contains all the information necessary to construct a certificate except for
+/// the subject and issuer keys.
+#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, ZeroizeOnDrop)]
+pub(crate) struct CertificateInfo(pub(crate) Vec<u8, DPE_MAX_CERTIFICATE_SIZE>);
+
+/// A Vec wrapper to represent a [`CertificateInfo`] list.
+#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
+pub(crate) struct CertificateInfoList(
+ pub(crate) Vec<CertificateInfo, DPE_MAX_CERTIFICATE_INFOS_PER_CONTEXT>,
+);
+
+/// Represents the mode value in DICE input. The discriminants match the
+/// corresponding encoded values for CBOR or X.509. See the Open Profile for
+/// DICE specification for details.
+#[derive(
+ Clone, Copy, Debug, Eq, PartialEq, Hash, FromPrimitive, ToPrimitive,
+)]
+pub(crate) enum DiceInputMode {
+ /// The `Not Configured` mode.
+ NotInitialized = 0,
+ /// The `Normal` mode.
+ Normal = 1,
+ /// The `Debug` mode.
+ Debug = 2,
+ /// The `Recovery` mode (aka maintenance mode).
+ Recovery = 3,
+}
+
+/// Represents a config value as defined by the Open Profile for DICE.
+#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
+pub(crate) enum DiceInputConfig<'a> {
+ /// No config value provided by the client.
+ #[default]
+ EmptyConfig,
+ /// The inline 64-byte value provided by the client.
+ ConfigInlineValue(Hash),
+ /// The free-form configuration descriptor provided by the client.
+ ConfigDescriptor(&'a [u8]),
+}
+
+/// Defines the supported internal input types. The enum discriminants match the
+/// encoded CBOR values. When an internal input is indicated as part of a
+/// context derivation, the corresponding information is included in the CDI
+/// derivation and possibly an associated certificate.
+#[derive(
+ Clone, Copy, Debug, Eq, PartialEq, Hash, FromPrimitive, ToPrimitive,
+)]
+pub(crate) enum InternalInputType {
+ /// Associated with information the DPE has about its own identity. This
+ /// information is included in the context's certificate info.
+ DpeInfo = 1,
+ /// Associated with information the DPE has about its own DICE attestation
+ /// data. This information is included in the context's certificate info.
+ DpeDice = 2,
+ /// Associated with a value that can be rotated in some way. This value
+ /// remains internal to the DPE and is not included in certificate info.
+ RotationValue = 3,
+ /// Associated with a monotonic counter internal do the DPE. This value
+ /// remains internal to the DPE and is not included in certificate info.
+ MonotonicCounter = 4,
+}
+
+/// Represents a complete set of DICE input values as defined by the Open
+/// Profile for DICE.
+#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
+pub(crate) struct DiceInput<'a> {
+ /// The `Code` input value.
+ pub(crate) code_hash: Option<Hash>,
+ /// An optional code descriptor (not included in the CDI derivation).
+ pub(crate) code_descriptor: Option<&'a [u8]>,
+ /// The `Configuration Data` input value.
+ pub(crate) config: DiceInputConfig<'a>,
+ /// The `Authority Data` input value as a hash. One of this field or the
+ /// `authority_descriptor` field is required.
+ pub(crate) authority_hash: Option<Hash>,
+ /// The `Authority Data` input value as a descriptor. One of this field or
+ /// the `authority_hash` field is required.
+ pub(crate) authority_descriptor: Option<&'a [u8]>,
+ /// The `Mode Decision` input value.
+ pub(crate) mode: Option<DiceInputMode>,
+ /// The `Hidden Inputs` input value.
+ pub(crate) hidden: Option<Hash>,
+}
+
+/// A trait to represent DICE-related functionality required by a DPE.
+pub(crate) trait Dice {
+ /// Performs a DICE derivation flow.
+ ///
+ /// On success returns a tuple containing the new CDI for signing followed
+ /// by the new CDI for sealing.
+ fn dice(
+ &self,
+ cdi_sign: &Cdi,
+ cdi_seal: &Cdi,
+ inputs: &DiceInput,
+ internal_inputs: &[InternalInputType],
+ is_export: bool,
+ ) -> DpeResult<(Cdi, Cdi)>;
+
+ /// Derives a key pair from a CDI for signing certificates (embedded CA).
+ fn derive_eca_key_pair(
+ &self,
+ cdi_sign: &Cdi,
+ ) -> DpeResult<(SigningPublicKey, SigningPrivateKey)>;
+
+ /// Derives a key pair from a CDI for general purpose signing.
+ fn derive_signing_key_pair(
+ &self,
+ cdi_sign: &Cdi,
+ label: &[u8],
+ ) -> DpeResult<(SigningPublicKey, SigningPrivateKey)>;
+
+ /// Derives a key pair from a CDI for asymmetric sealing.
+ fn derive_sealing_key_pair(
+ &self,
+ cdi_seal: &Cdi,
+ label: &[u8],
+ unseal_policy: &[u8],
+ ) -> DpeResult<(SealingPublicKey, SealingPrivateKey)>;
+
+ /// Derives a key from a CDI for generating MACs.
+ fn derive_mac_key(&self, cdi_sign: &Cdi, label: &[u8])
+ -> DpeResult<MacKey>;
+
+ /// Derives a key from a CDI for symmetric sealing.
+ fn derive_sealing_key(
+ &self,
+ cdi_seal: &Cdi,
+ label: &[u8],
+ unseal_policy: &[u8],
+ ) -> DpeResult<EncryptionKey>;
+
+ /// Populates [`CertificateInfo`] from the given DICE inputs.
+ fn create_certificate_info(
+ &self,
+ inputs: &DiceInput,
+ internal_inputs: &[InternalInputType],
+ ) -> DpeResult<CertificateInfo>;
+
+ /// Creates an embedded CA certificate.
+ ///
+ /// Derive the `subject_public_key` using [`Dice::derive_eca_key_pair`].
+ fn create_eca_certificate(
+ &self,
+ issuer_key_pair: &(SigningPublicKey, SigningPrivateKey),
+ subject_public_key: &SigningPublicKey,
+ certificate_info: &CertificateInfo,
+ additional_certificate_info: &CertificateInfoList,
+ is_export: bool,
+ ) -> DpeResult<Certificate>;
+
+ /// Creates a leaf certificate.
+ ///
+ /// Derive the `subject_public_key` using [`Dice::derive_signing_key_pair`].
+ fn create_leaf_certificate(
+ &self,
+ issuer_key_pair: &(SigningPublicKey, SigningPrivateKey),
+ subject_public_key: &SigningPublicKey,
+ certificate_info: &CertificateInfoList,
+ additional_input: &[u8],
+ ) -> DpeResult<Certificate>;
+}
diff --git a/dpe-rs/src/encode.rs b/dpe-rs/src/encode.rs
index bbaf508..71fec3d 100644
--- a/dpe-rs/src/encode.rs
+++ b/dpe-rs/src/encode.rs
@@ -22,6 +22,10 @@
};
use crate::constants::*;
use crate::crypto::{HandshakePayload, Hash};
+use crate::dice::{
+ Cdi, Certificate, DiceInput, DiceInputConfig, DiceInputMode,
+ InternalInputType, Uds,
+};
use crate::error::{DpeResult, ErrCode};
use crate::memory::{Message, SizedMessage};
use heapless::Vec;
@@ -49,8 +53,6 @@
// ]
const MESSAGE_ARRAY_SIZE: u64 = 2;
-byte_array_wrapper!(Uds, DICE_UDS_SIZE, "UDS");
-byte_array_wrapper!(Cdi, DICE_CDI_SIZE, "CDI");
byte_array_wrapper!(ContextHandle, DPE_HANDLE_SIZE, "context handle");
impl ContextHandle {
@@ -70,10 +72,6 @@
/// the contents will fit.
pub(crate) type SmallMessage = SizedMessage<DPE_MAX_SMALL_MESSAGE_SIZE>;
-/// A Vec wrapper to represent a single encoded certificate.
-#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, ZeroizeOnDrop)]
-pub(crate) struct Certificate(pub(crate) Vec<u8, DPE_MAX_CERTIFICATE_SIZE>);
-
/// A Vec wrapper to represent a certificate chain.
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
pub(crate) struct CertificateChain(
@@ -133,28 +131,6 @@
InternalCdis,
}
-/// Defines the supported internal input types. The enum discriminants match the
-/// encoded CBOR values. When an internal input is indicated as part of a
-/// context derivation, the corresponding information is included in the CDI
-/// derivation and possibly an associated certificate.
-#[derive(
- Clone, Copy, Debug, Eq, PartialEq, Hash, FromPrimitive, ToPrimitive,
-)]
-pub(crate) enum InternalInputType {
- /// Associated with information the DPE has about its own identity. This
- /// information is included in the context's certificate info.
- DpeInfo = 1,
- /// Associated with information the DPE has about its own DICE attestation
- /// data. This information is included in the context's certificate info.
- DpeDice = 2,
- /// Associated with a value that can be rotated in some way. This value
- /// remains internal to the DPE and is not included in certificate info.
- RotationValue = 3,
- /// Associated with a monotonic counter internal do the DPE. This value
- /// remains internal to the DPE and is not included in certificate info.
- MonotonicCounter = 4,
-}
-
impl TryFrom<u32> for InternalInputType {
type Error = ErrCode;
fn try_from(value: u32) -> DpeResult<Self> {
@@ -255,22 +231,6 @@
}
}
-/// Represents the mode value in DICE input. The discriminants match the CBOR
-/// encoded values. See the Open Profile for DICE specification for details.
-#[derive(
- Clone, Copy, Debug, Eq, PartialEq, Hash, FromPrimitive, ToPrimitive,
-)]
-pub(crate) enum DiceInputMode {
- /// The `Not Configured` mode.
- NotInitialized = 0,
- /// The `Normal` mode.
- Normal = 1,
- /// The `Debug` mode.
- Debug = 2,
- /// The `Recovery` mode (aka maintenance mode).
- Recovery = 3,
-}
-
impl TryFrom<u8> for DiceInputMode {
type Error = ErrCode;
fn try_from(value: u8) -> DpeResult<Self> {
@@ -308,40 +268,6 @@
}
}
-/// Represents a config value as defined by the Open Profile for DICE.
-#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
-pub(crate) enum DiceInputConfig<'a> {
- /// No config value provided by the client.
- #[default]
- EmptyConfig,
- /// The inline 64-byte value provided by the client.
- ConfigInlineValue(Hash),
- /// The free-form configuration descriptor provided by the client.
- ConfigDescriptor(&'a [u8]),
-}
-
-/// Represents a complete set of DICE input values as defined by the Open
-/// Profile for DICE.
-#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
-pub(crate) struct DiceInput<'a> {
- /// The `Code` input value.
- pub(crate) code_hash: Option<Hash>,
- /// An optional code descriptor (not included in the CDI derivation).
- pub(crate) code_descriptor: Option<&'a [u8]>,
- /// The `Configuration Data` input value.
- pub(crate) config: DiceInputConfig<'a>,
- /// The `Authority Data` input value as a hash. One of this field or the
- /// `authority_descriptor` field is required.
- pub(crate) authority_hash: Option<Hash>,
- /// The `Authority Data` input value as a descriptor. One of this field or
- /// the `authority_hash` field is required.
- pub(crate) authority_descriptor: Option<&'a [u8]>,
- /// The `Mode Decision` input value.
- pub(crate) mode: Option<DiceInputMode>,
- /// The `Hidden Inputs` input value.
- pub(crate) hidden: Option<Hash>,
-}
-
/// Decodes a CBOR-encoded set of internal input selectors.
pub(crate) fn decode_internal_inputs(
cbor: &[u8],
@@ -1266,9 +1192,9 @@
#[test]
fn init_seed_decode() {
test_init();
- let uds_value = Uds([0; DICE_UDS_SIZE]);
- let cdi_sign = Cdi([1; DICE_CDI_SIZE]);
- let cdi_seal = Cdi([2; DICE_CDI_SIZE]);
+ let uds_value = Uds::from_array(&[0; DICE_UDS_SIZE]);
+ let cdi_sign = Cdi::from_array(&[1; DICE_CDI_SIZE]);
+ let cdi_seal = Cdi::from_array(&[2; DICE_CDI_SIZE]);
let invalid_seed = encode_init_seed_for_testing(None, None, None, None);
let uds_internal_init = InitType::InternalUds;
let uds_internal_seed = encode_init_seed_for_testing(
diff --git a/dpe-rs/src/lib.rs b/dpe-rs/src/lib.rs
index 02adb2a..a301bf7 100644
--- a/dpe-rs/src/lib.rs
+++ b/dpe-rs/src/lib.rs
@@ -52,6 +52,7 @@
pub mod cbor;
pub mod constants;
pub mod crypto;
+pub mod dice;
pub mod encode;
pub mod error;
pub mod memory;