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;