blob: 4df1d6df3c31f038cacea216aa8d6f8de9b6e50f [file] [log] [blame]
// Copyright 2025 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.
//! Command message handlers.
use crate::args::{ArgId, ArgMap, ArgMapExt, ArgTypeMap, ArgTypeSelector};
use crate::crypto::{
HandshakeMessage, SealingPublicKey, Signature, SigningPublicKey,
};
use crate::dice::{Certificate, DiceInput, InternalInputType};
use crate::encode::{
decode_and_remove_command_header, decode_args, decode_dice_input,
decode_internal_inputs, decode_locality, encode_and_insert_response_header,
encode_args, CommandSelector, ContextHandle, LocalityId, SessionId,
};
use crate::error::DpeResult;
use crate::memory::{Message, SmallMessage};
use log::debug;
/// A struct combining boolean option arguments for the DeriveContext command.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub(crate) struct DeriveContextOptions {
/// Corresponds to the `retain-parent-context` argument. When this is true
/// the derivation will result in a new derived context and the parent
/// context will be retained as is.
pub(crate) retain_parent_context: bool,
/// Corresponds to the `allow-new-context-to-derive` argument. The DPE
/// tracks this permission for every context. It might be false, for
/// example, when it represents a program that should not be spawning
/// other programs. If this option is set to true, the derived context will
/// have this set to true (requires the parent context already has this set
/// to true).
pub(crate) allow_new_context_to_derive: bool,
/// Corresponds to the `create-certificate` argument. If this is true a
/// certificate will be created for the derived context, otherwise
/// information that would have gone into the certificate is stored
/// until a certificate is created.
pub(crate) create_certificate: bool,
/// Corresponds to the `return-certificate` argument. If this is true the
/// new certificate is provided in the command response.
pub(crate) return_certificate: bool,
/// Corresponds to the `allow-new-context-to-export` argument. The DPE
/// tracks this permission for every context. If this is true, the
/// derived context will have this set to true (requires the parent
/// context already has this set to true).
pub(crate) allow_new_context_to_export: bool,
/// Corresponds to the `export-cdi` argument. If this is true an
/// export-specific derivation process is followed and the resulting
/// CDI(s) are provided to the caller.
pub(crate) export_cdi: bool,
/// Corresponds to the `recursive` argument. If this is true the derivation
/// will affect not only the given context but any context previously
/// derived from the given context.
pub(crate) recursive: bool,
}
impl Default for DeriveContextOptions {
fn default() -> Self {
Self {
retain_parent_context: false,
allow_new_context_to_derive: true,
create_certificate: true,
return_certificate: false,
allow_new_context_to_export: false,
export_cdi: false,
recursive: false,
}
}
}
/// A trait representing the core DPE functionality required to handle commands.
///
/// When handling a command message, exactly one of these methods will be
/// called. The method documentation below is very brief. For details on command
/// behavior, arguments, and DPE concepts, refer to the [DPE
/// specification][dpe_spec]. For details specified by a profile, see the [Open
/// Profile][profile_spec]. In general, the method parameters correspond
/// directly to the command parameters described in the spec.
///
/// # Errors
///
/// Methods in this trait might return [ErrCode::InternalError]. This indicates
/// a problem that is no fault of the caller and not actionable by the caller.
///
/// Methods in this trait might return [ErrCode::InvalidArgument] when the
/// session / locality on which the command was sent is not valid. For example,
/// an implementation might enforce that plaintext commands are not allowed on
/// locality 0.
///
/// Anticipated errors are documented per method but implementations can use any
/// error code.
///
/// [dpe_spec]: https://trustedcomputinggroup.org/wp-content/uploads/DICE-Protection-Environment-Version-1.0_pub.pdf
/// [profile_spec]: ../../docs/specification.md
pub(crate) trait DpeCore {
/// Returns the locality associated with the current command. This is the
/// actual locality, not a locality indicated in a command argument. For
/// example, if an implementation uses locality 0 for clients running on
/// a main application processor and locality 1 for a separate special
/// purpose core, this method indicates which of those the current
/// command originated from. This value is used when the specification
/// indicates the "current locality".
fn get_current_locality(&self) -> LocalityId;
/// Implements the GetProfile DPE command.
///
/// # Returns
///
/// On success, returns a CBOR-encoded profile descriptor.
///
/// # Errors
///
/// This method is expected to succeed during normal operation.
fn get_profile(&self) -> DpeResult<Message>;
/// Implements the OpenSession DPE command. On success a new session
/// endpoint is established in the DPE and will consume DPE resources
/// until it is closed.
///
/// # Parameters
///
/// * `initiator_handshake`: A handshake message from the client to start a
/// session negotiation. The format and semantic of the message depend on
/// the handshake protocol.
///
/// # Returns
///
/// On success, a responding handshake message is returned. This message is
/// sufficient for the client to establish its session endpoint.
///
/// # Errors
///
/// * [`ErrCode::InvalidArgument`]: The intiator handshake could not be
/// processed.
/// * [`ErrCode::OutOfMemory`]: The maximum supported sessions already
/// exist.
fn open_session(
&mut self,
initiator_handshake: &HandshakeMessage,
) -> DpeResult<HandshakeMessage>;
/// Implements the CloseSession DPE command. On success the session on which
/// the command was sent is closed and associated DPE resources are
/// released. The response message to this command is the last message
/// encrypted using the session.
///
/// # Errors
///
/// * [`ErrCode::InvalidCommand`]: A plaintext session cannot be closed.
fn close_session(&mut self) -> DpeResult<()>;
/// Implements the SyncSession DPE command. On success the target session
/// state in the DPE is updated. This command is always sent on a
/// plaintext session because presumably the encrypted session needs to
/// be synced. This is intended for sessions which require counters
/// to be maintained at both endpoints to recover from these counters
/// getting out of sync.
///
/// # Parameters
///
/// * `target_session`: Indicates which session to sync.
/// * `initiator_counter`: The client's current counter value (for
/// encrypting commands).
///
/// # Returns
///
/// On success, returns the DPE's current counter value (for encrypting
/// responses).
///
/// # Errors
///
/// * [`ErrCode::InvalidCommand`]: This command must be invoked on a
/// plaintext session.
/// * [`ErrCode::InvalidArgument`]: The provided counter is not in an
/// acceptable range. For
/// example, if the counter is lower than the current value.
fn sync_session(
&mut self,
target_session: SessionId,
initiator_counter: u64,
) -> DpeResult<u64>;
/// Implements the InitializeContext DPE command. On success a new context
/// is established in the DPE and will consume DPE resources until it is
/// destroyed.
///
/// # Parameters
///
/// * `simulation`: Whether the new context should be a simulation context.
/// * `use_default_context`: If true, the default context will be
/// initialized.
/// * `seed`: A seed value to use when deriving the initial CDI value(s).
///
/// # Returns
///
/// On success, returns a context handle that can be used to reference the
/// new context in a subsequent command. If `use_default_context` was
/// set, this will be `None`.
///
/// # Errors
///
/// *[`ErrCode::InvalidArgument`]: A given argument is malformed or is not
/// supported by the implementation, for example if simulation contexts
/// are not supported but `simulation` is true.
/// *[`ErrCode::OutOfMemory`]: The maximum supported contexts already exist.
fn initialize_context(
&mut self,
simulation: bool,
use_default_context: bool,
seed: &[u8],
) -> DpeResult<Option<ContextHandle>>;
/// Implements the DeriveContext DPE command. This command is the main DPE
/// command and essentially runs the DICE process with the given
/// context. It can have a variety of effects on the state of the DPE
/// depending on the arguments.
///
/// # Parameters
///
/// * `options`: Command options. See [`DeriveContextOptions`].
/// * `handle`: The context to derive from, or, the parent context.
/// * `new_session_initiator_handshake`: If not None, contains a handshake
/// message used to negotiate a new session for the derived context.
/// * `version_info`: Specifies version info to associate with the derived
/// context. This is used for evaluating unseal policies.
/// * `dice_input`: Describes the system transition represented by the
/// derivation. This is used as input to the derivation.
/// * `internal_inputs`: Indicates internal input values to be included in
/// the derivation. This is similar to `dice_input` but the values are
/// only known to the DPE.
/// * `target_locality`: Indicates the locality that should be associated
/// with the derived context. Usually this is the current locality.
///
/// # Returns
///
/// * `new_context_handle`: A handle to the new derived context, when
/// available
/// * `new_session_responder_handshake`: A handshake message corresponding
/// to `new_session_initiator_handshake`, when a new session was created.
/// * `new_parent_context_handle`: A new handle to the parent context, when
/// retained.
/// * `new_certificate`: The generated certificate, when requested.
/// * `exported_cdi`: The exported CDI values, when export was requested.
///
/// # Errors
///
/// * [`ErrCode::InvalidArgument`]: Arguments can be invalid in multiple
/// ways:
/// * An argument is malformed.
/// * An argument has an invalid value, for example:
/// * The given context handle is not found.
/// * The target locality is not in the supported range.
/// * A new session is initiated on a locality that does not support
/// encrypted sessions.
/// * Arguments are incompatible per the DPE spec, for example:
/// * A default context is retained but neither a new session nor
/// new locality is given.
/// * Certificate return or CDI export requested for a recursive
/// derivation.
/// * Export is requested for a new target locality.
/// * Arguments would violate a DPE rule or permission, per the spec.
/// For example:
/// * Derivation is not allowed for the given context.
/// * Export or allow export is requested but export is not allowed
/// for the given context.
/// * Cannot target a locality that supports encrypted sessions from
/// one that does not.
/// * Export is requested for a simulation context.
/// * A new default context is targeted but already initialized.
/// * [`ErrCode::OutOfMemory`]: A new context or session were requested but
/// not available.
#[allow(clippy::type_complexity, clippy::too_many_arguments)]
fn derive_context(
&mut self,
options: &DeriveContextOptions,
handle: Option<&ContextHandle>,
new_session_initiator_handshake: Option<&HandshakeMessage>,
version_info: Option<(usize, u64)>,
dice_input: &DiceInput,
internal_inputs: &[InternalInputType],
target_locality: LocalityId,
) -> DpeResult<(
/* new_context_handle: */ Option<ContextHandle>,
/* new_session_responder_handshake: */ Option<HandshakeMessage>,
/* new_parent_context_handle: */ Option<ContextHandle>,
/* new_certificate: */ Option<Certificate>,
/* exported_cdi: */ Option<SmallMessage>,
)>;
/// Implements the GetCertificateChain DPE command.
///
/// # Parameters
///
/// * `handle`: The context to get the certificate chain from.
/// * `retain_context`: Whether the context will be used again, if so a new
/// handle will be provided.
/// * `clear_from_context`: Whether to clear the certificate chain from the
/// DPE on success. This allows the DPE to reclaim resources.
/// * `encoded_certificate_chain`: The certificate chain data.
/// * `new_handle`: The new handle, if provided.
///
/// # Errors
///
/// * [`ErrCode::InvalidArgument`]: The given context contains info not yet
/// added to a certificate.
fn get_certificate_chain(
&mut self,
handle: Option<&ContextHandle>,
retain_context: bool,
clear_from_context: bool,
) -> DpeResult<(
/* encoded_certificate_chain: */ Message,
/* new_handle: */ Option<ContextHandle>,
)>;
/// Implements the CertifyKey DPE command. This command certifies a leaf key
/// using the given context.
///
/// # Parameters
///
/// * `handle`: The context to certify with.
/// * `retain_context`: Whether the context will be used again, if so a new
/// handle will be provided.
/// * `public_key`: If provided, will be the key that is certified. If not
/// provided a key will be derived by the DPE and returned.
/// * `label`: Used in the leaf key derivation.
/// * `additional_input`: Optional data that allows implementations to
/// further customize the certificate.
///
/// # Returns
///
/// * `certificate`: The generated certificate.
/// * `derived_public_key`: The public key of the derived key pair. The same
/// key pair can be derived in other commands like [`sign`] by using the
/// same label.
/// * `new_handle`: The new handle, if provided.
///
/// # Errors
///
/// * [`ErrCode::InvalidArgument`]: Returned if an argument is malformed,
/// the handle cannot be found, or if `public_key` was provided with a
/// simulation context (simulation contexts cannot be used to certify
/// external keys).
#[allow(clippy::too_many_arguments)]
fn certify_key(
&mut self,
handle: Option<&ContextHandle>,
retain_context: bool,
public_key: Option<&SigningPublicKey>,
label: &[u8],
additional_input: &[u8],
) -> DpeResult<(
/* certificate: */ Certificate,
/* derived_public_key: */ Option<SigningPublicKey>,
/* new_handle: */ Option<ContextHandle>,
)>;
/// Implements the Sign DPE command. This command signs with a derived leaf
/// key.
///
/// # Parameters
///
/// * `handle`: The context to sign with.
/// * `retain_context`: Whether the context will be used again, if so a new
/// handle will be provided.
/// * `label`: Used in the key derivation.
/// * `is_symmetric`: If true, a symmetric key is derived (e.g. HMAC)
/// * `to_be_signed`: The data to be signed.
///
/// # Returns
///
/// * `signature`: The generated signature.
/// * `new_handle`: The new handle, if provided.
///
/// # Errors
///
/// * `[ErrCode::InvalidArgument`]: Returned if an argument is malformed,
/// the handle cannot be found, or if the given context is a simulation
/// context (signing with a simulation context is not allowed).
#[allow(clippy::too_many_arguments)]
fn sign(
&mut self,
handle: Option<&ContextHandle>,
retain_context: bool,
label: &[u8],
is_symmetric: bool,
to_be_signed: &[u8],
) -> DpeResult<(
/* signature: */ Signature,
/* new_handle: */ Option<ContextHandle>,
)>;
/// Implements the Seal DPE command. This command seals data with a
/// symmetric key derived from the given context. Note, sealing with an
/// asymmetric key does not need the DPE, see [`derive_sealing_public_key`].
///
/// # Parameters
///
/// * `handle`: The context to seal with.
/// * `retain_context`: Whether the context will be used again, if so a new
/// handle will be provided.
/// * `unseal_policy`: The policy that will be required to unseal.
/// * `label`: Used in the key derivation.
/// * `to_be_sealed`: The data to be sealed.
///
/// # Returns
///
/// * `sealed_data`: The encrypted sealed data.
/// * `new_handle`: The new handle, if provided.
///
/// # Errors
///
/// * `[ErrCode::InvalidArgument`]: Returned if an argument is malformed or
/// the handle cannot be found.
#[allow(clippy::too_many_arguments)]
fn seal(
&mut self,
handle: Option<&ContextHandle>,
retain_context: bool,
unseal_policy: &[u8],
label: &[u8],
data_to_seal: &[u8],
) -> DpeResult<(
/* sealed_data: */ Message,
/* new_handle: */ Option<ContextHandle>,
)>;
/// Implements the Unseal DPE command. This command unseals data that was
/// sealed with either a symmetric or asymmetric key.
///
/// # Parameters
///
/// * `handle`: The context to unseal with.
/// * `retain_context`: Whether the context will be used again, if so a new
/// handle will be provided.
/// * `is_symmetric`: Whether the data was sealed with a symmetric key.
/// * `unseal_policy`: The policy required to unseal.
/// * `label`: Used in the key derivation.
/// * `data_to_unsealed`: The data to be unsealed.
///
/// # Returns
///
/// * `unsealed_data`: The unsealed data.
/// * `new_handle`: The new handle, if provided.
///
/// # Errors
///
/// * `[ErrCode::InvalidArgument`]: Returned if an argument is malformed,
/// the handle cannot be found, if the given context is a simulation
/// context (unsealing with a simulation context is not allowed), or the
/// unseal policy does not match (or its requirements are not met).
#[allow(clippy::too_many_arguments)]
fn unseal(
&mut self,
handle: Option<&ContextHandle>,
retain_context: bool,
is_asymmetric: bool,
unseal_policy: &[u8],
label: &[u8],
data_to_unseal: &[u8],
) -> DpeResult<(
/* unsealed_data: */ Message,
/* new_handle: */ Option<ContextHandle>,
)>;
/// Implements the DeriveSealingPublicKey DPE command. This command derives
/// a public key that can be used for asymmetric sealing.
///
/// # Parameters
///
/// * `handle`: The context to derive from.
/// * `retain_context`: Whether the context will be used again, if so a new
/// handle will be provided.
/// * `unseal_policy`: The policy that will be required to unseal.
/// * `label`: Used in the key derivation.
///
/// # Returns
///
/// * `public_key`: The derived public key.
/// * `new_handle`: The new handle, if provided.
///
/// # Errors
///
/// * `[ErrCode::InvalidArgument`]: Returned if an argument is malformed or
/// the handle cannot be found.
fn derive_sealing_public_key(
&mut self,
handle: Option<&ContextHandle>,
retain_context: bool,
unseal_policy: &[u8],
label: &[u8],
) -> DpeResult<(
/* public_key: */ SealingPublicKey,
/* new_handle: */ Option<ContextHandle>,
)>;
/// Implements the RotateContextHandle DPE command. This command generates
/// a new handle for a context or changes handle properties. This command
/// does not modify the state of the context itself (beyond handle/locality
/// association).
///
/// # Parameters
///
/// * `handle`: The context handle to rotate.
/// * `to_default`: If true, makes this context the default context for the
/// target locality. If false, a new handle is generated for the context
/// even if the context was previously the default context.
/// * `target_locality`: Indicates the target locality.
///
/// # Errors
///
/// * `[ErrCode::InvalidArgument`]: Returned if the handle is not found, the
/// target locality is not valid or allowed (a context cannot be moved to
/// a locality that supports encrypted sessions from one that does not),
/// or a target default context is already initialized.
fn rotate_context_handle(
&mut self,
handle: Option<&ContextHandle>,
to_default: bool,
target_locality: LocalityId,
) -> DpeResult<Option<ContextHandle>>;
/// Implements the DestroyContext DPE command. This command destroys the
/// given context within the DPE and releases all associated resources.
///
/// # Parameters
///
/// * `handle`: The context to destroy.
/// * `recursive`: Whether all previously derived contexts should also be
/// destroyed. If false, previously derived contexts will inherit the
/// parent of the destroyed context.
///
/// # Errors
///
/// * `[ErrCode::InvalidArgument`]: The handle is not found.
fn destroy_context(
&mut self,
handle: Option<&ContextHandle>,
recursive: bool,
) -> DpeResult<()>;
}
/// Handles a plaintext command message and provides a plaintext response.
///
/// Messages received via an encrypted session must be already decrypted and the
/// response provided here must be subsequently encrypted.
///
/// The `message_buffer` holds both command and response. Initially the buffer
/// must contain only the complete command message. On success, the command
/// message is cleared and the buffer is populated with a response message.
///
/// # Errors
///
/// If a command is unsuccessful an error is returned and the content of the
/// `message_buffer` is undefined and should be ignored and cleared before
/// reuse.
pub(crate) fn handle_command_message(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
let command_selector = decode_and_remove_command_header(message_buffer)?;
debug!("Command id: {:?}", command_selector);
let response = handle_command(dpe, command_selector, message_buffer)?;
encode_and_insert_response_header(response)?;
Ok(())
}
// Handles a command given a [`CommandSelector`] and input arguments.
//
// On input the message_buffer contains the encoded input arguments. On success
// the buffer is cleared and populated with encoded output arguments. Each
// handle_<command> function uses the buffer this way.
fn handle_command<'a>(
dpe: &mut impl DpeCore,
command_selector: CommandSelector,
message_buffer: &'a mut Message,
) -> DpeResult<&'a mut Message> {
match command_selector {
CommandSelector::GetProfile => {
handle_get_profile(dpe, message_buffer)?;
}
CommandSelector::OpenSession => {
handle_open_session(dpe, message_buffer)?;
}
CommandSelector::CloseSession => {
handle_close_session(dpe, message_buffer)?;
}
CommandSelector::SyncSession => {
handle_sync_session(dpe, message_buffer)?;
}
CommandSelector::InitializeContext => {
handle_initialize_context(dpe, message_buffer)?;
}
CommandSelector::DeriveContext => {
handle_derive_context(dpe, message_buffer)?;
}
CommandSelector::GetCertificateChain => {
handle_get_certificate_chain(dpe, message_buffer)?;
}
CommandSelector::CertifyKey => {
handle_certify_key(dpe, message_buffer)?;
}
CommandSelector::Sign => {
handle_sign(dpe, message_buffer)?;
}
CommandSelector::Seal => {
handle_seal(dpe, message_buffer)?;
}
CommandSelector::Unseal => {
handle_unseal(dpe, message_buffer)?;
}
CommandSelector::DeriveSealingPublicKey => {
handle_derive_sealing_public_key(dpe, message_buffer)?;
}
CommandSelector::RotateContextHandle => {
handle_rotate_context_handle(dpe, message_buffer)?;
}
CommandSelector::DestroyContext => {
handle_destroy_context(dpe, message_buffer)?;
}
};
Ok(message_buffer)
}
fn handle_get_profile(
dpe: &impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const OUTPUT_ID_DESCRIPTOR: ArgId = 1;
let _ = decode_args(message_buffer.as_slice(), &ArgTypeMap::new())?;
let descriptor = dpe.get_profile()?;
let mut output_args: ArgMap = Default::default();
output_args.insert_or_err(OUTPUT_ID_DESCRIPTOR, &descriptor)?;
encode_args(&output_args, message_buffer)
}
fn handle_open_session(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const INPUT_ID_HANDSHAKE: ArgId = 1;
const OUTPUT_ID_HANDSHAKE: ArgId = 1;
let input_arg_types =
ArgTypeMap::from_iter([(INPUT_ID_HANDSHAKE, ArgTypeSelector::Bytes)]);
let input_arg_map =
decode_args(message_buffer.as_slice(), &input_arg_types)?;
let initiator_handshake = input_arg_map.get_or_err(INPUT_ID_HANDSHAKE)?;
let responder_handshake =
dpe.open_session(&HandshakeMessage::from_slice(initiator_handshake)?)?;
let mut output_args: ArgMap = Default::default();
output_args.insert_or_err(OUTPUT_ID_HANDSHAKE, &responder_handshake)?;
drop(input_arg_map);
encode_args(&output_args, message_buffer)
}
fn handle_close_session(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
let _ = decode_args(message_buffer.as_slice(), &ArgTypeMap::new())?;
dpe.close_session()?;
encode_args(&Default::default(), message_buffer)
}
fn handle_sync_session(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const INPUT_ID_SESSION: ArgId = 1;
const INPUT_ID_COUNTER: ArgId = 2;
const OUTPUT_ID_COUNTER: ArgId = 1;
let input_arg_types = ArgTypeMap::from_iter([
(INPUT_ID_SESSION, ArgTypeSelector::Int),
(INPUT_ID_COUNTER, ArgTypeSelector::Int),
]);
let input_arg_map =
decode_args(message_buffer.as_slice(), &input_arg_types)?;
let target_session = SessionId(input_arg_map.get_or_err(INPUT_ID_SESSION)?);
let in_counter = input_arg_map.get_or_err(INPUT_ID_COUNTER)?;
let out_counter = dpe.sync_session(target_session, in_counter)?;
let mut output_args: ArgMap = Default::default();
output_args.insert_or_err(OUTPUT_ID_COUNTER, out_counter)?;
drop(input_arg_map);
encode_args(&output_args, message_buffer)
}
fn handle_initialize_context(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const INPUT_ID_SIMULATION: ArgId = 1;
const INPUT_ID_USE_DEFAULT: ArgId = 2;
const INPUT_ID_SEED: ArgId = 3;
const OUTPUT_ID_HANDLE: ArgId = 1;
let input_arg_types = ArgTypeMap::from_iter([
(INPUT_ID_SIMULATION, ArgTypeSelector::Bool(false)),
(INPUT_ID_USE_DEFAULT, ArgTypeSelector::Bool(false)),
(INPUT_ID_SEED, ArgTypeSelector::Bytes),
]);
let input_arg_map =
decode_args(message_buffer.as_slice(), &input_arg_types)?;
let simulation = input_arg_map.get_or_err(INPUT_ID_SIMULATION)?;
let use_default = input_arg_map.get_or_err(INPUT_ID_USE_DEFAULT)?;
let seed = input_arg_map.get_or_err(INPUT_ID_SEED)?;
let handle = dpe.initialize_context(simulation, use_default, seed)?;
let mut output_args: ArgMap = Default::default();
if let Some(ref handle) = handle {
output_args.insert_or_err(OUTPUT_ID_HANDLE, handle.as_slice())?;
}
drop(input_arg_map);
encode_args(&output_args, message_buffer)
}
fn handle_derive_context(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const INPUT_ID_CONTEXT_HANDLE: ArgId = 1;
const INPUT_ID_RETAIN_PARENT: ArgId = 2;
const INPUT_ID_ALLOW_DERIVE: ArgId = 3;
const INPUT_ID_CREATE_CERTIFICATE: ArgId = 4;
const INPUT_ID_HANDSHAKE: ArgId = 5;
const INPUT_ID_DICE_INPUT_DATA: ArgId = 6;
const INPUT_ID_INTERNAL_INPUTS: ArgId = 7;
const INPUT_ID_LOCALITY: ArgId = 8;
const INPUT_ID_RETURN_CERTIFICATE: ArgId = 9;
const INPUT_ID_ALLOW_EXPORT: ArgId = 10;
const INPUT_ID_EXPORT: ArgId = 11;
const INPUT_ID_RECURSIVE: ArgId = 12;
const OUTPUT_ID_HANDLE: ArgId = 1;
const OUTPUT_ID_HANDSHAKE: ArgId = 2;
const OUTPUT_ID_PARENT_HANDLE: ArgId = 3;
const OUTPUT_ID_CERTIFICATE: ArgId = 4;
const OUTPUT_ID_EXPORTED_CDI: ArgId = 5;
let input_arg_types = ArgTypeMap::from_iter([
(INPUT_ID_CONTEXT_HANDLE, ArgTypeSelector::Bytes),
(INPUT_ID_RETAIN_PARENT, ArgTypeSelector::Bool(false)),
(INPUT_ID_ALLOW_DERIVE, ArgTypeSelector::Bool(true)),
(INPUT_ID_CREATE_CERTIFICATE, ArgTypeSelector::Bool(true)),
(INPUT_ID_HANDSHAKE, ArgTypeSelector::Bytes),
(INPUT_ID_DICE_INPUT_DATA, ArgTypeSelector::Bytes),
(INPUT_ID_INTERNAL_INPUTS, ArgTypeSelector::Other),
(INPUT_ID_LOCALITY, ArgTypeSelector::Bytes),
(INPUT_ID_RETURN_CERTIFICATE, ArgTypeSelector::Bool(false)),
(INPUT_ID_ALLOW_EXPORT, ArgTypeSelector::Bool(false)),
(INPUT_ID_EXPORT, ArgTypeSelector::Bool(false)),
(INPUT_ID_RECURSIVE, ArgTypeSelector::Bool(false)),
]);
let input_arg_map =
decode_args(message_buffer.as_slice(), &input_arg_types)?;
let context_handle = ContextHandle::from_slice_to_option(
input_arg_map.get_or_err(INPUT_ID_CONTEXT_HANDLE)?,
)?;
let handshake = HandshakeMessage::from_slice(
input_arg_map.get_or_err(INPUT_ID_HANDSHAKE)?,
)?;
let encoded_dice_input =
input_arg_map.get_or_err(INPUT_ID_DICE_INPUT_DATA)?;
let internal_inputs_vec = decode_internal_inputs(
input_arg_map.get_or_err(INPUT_ID_INTERNAL_INPUTS)?,
)?;
let locality = decode_locality(
input_arg_map.get_or_err(INPUT_ID_LOCALITY)?,
dpe.get_current_locality(),
)?;
let options = DeriveContextOptions {
retain_parent_context: input_arg_map
.get_or_err(INPUT_ID_RETAIN_PARENT)?,
allow_new_context_to_derive: input_arg_map
.get_or_err(INPUT_ID_ALLOW_DERIVE)?,
create_certificate: input_arg_map
.get_or_err(INPUT_ID_CREATE_CERTIFICATE)?,
return_certificate: input_arg_map
.get_or_err(INPUT_ID_RETURN_CERTIFICATE)?,
allow_new_context_to_export: input_arg_map
.get_or_err(INPUT_ID_ALLOW_EXPORT)?,
export_cdi: input_arg_map.get_or_err(INPUT_ID_EXPORT)?,
recursive: input_arg_map.get_or_err(INPUT_ID_RECURSIVE)?,
};
let (version_info, dice_input) = decode_dice_input(encoded_dice_input)?;
let (
new_context_handle,
handshake_out,
parent_handle,
new_certificate,
exported_cdi,
) = dpe.derive_context(
&options,
context_handle.as_ref(),
if !handshake.is_empty() { Some(&handshake) } else { None },
version_info,
&dice_input,
internal_inputs_vec.as_slice(),
locality,
)?;
let mut output_args: ArgMap = Default::default();
if let Some(ref new_context_handle) = new_context_handle {
output_args
.insert_or_err(OUTPUT_ID_HANDLE, new_context_handle.as_slice())?;
}
if let Some(ref handshake_out) = handshake_out {
output_args.insert_or_err(OUTPUT_ID_HANDSHAKE, handshake_out)?;
}
if let Some(ref parent_handle) = parent_handle {
output_args
.insert_or_err(OUTPUT_ID_PARENT_HANDLE, parent_handle.as_slice())?;
}
if let Some(ref new_certificate) = new_certificate {
output_args.insert_or_err(
OUTPUT_ID_CERTIFICATE,
new_certificate.0.as_slice(),
)?;
}
if let Some(ref exported_cdi) = exported_cdi {
output_args.insert_or_err(OUTPUT_ID_EXPORTED_CDI, exported_cdi)?;
}
drop(input_arg_map);
encode_args(&output_args, message_buffer)
}
fn handle_get_certificate_chain(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const INPUT_ID_CONTEXT_HANDLE: ArgId = 1;
const INPUT_ID_RETAIN_CONTEXT: ArgId = 2;
const INPUT_ID_CLEAR_FROM_CONTEXT: ArgId = 3;
const OUTPUT_ID_CERTIFICATE_CHAIN: ArgId = 1;
const OUTPUT_ID_HANDLE: ArgId = 2;
let input_arg_types = ArgTypeMap::from_iter([
(INPUT_ID_CONTEXT_HANDLE, ArgTypeSelector::Bytes),
(INPUT_ID_RETAIN_CONTEXT, ArgTypeSelector::Bool(false)),
(INPUT_ID_CLEAR_FROM_CONTEXT, ArgTypeSelector::Bool(false)),
]);
let input_arg_map =
decode_args(message_buffer.as_slice(), &input_arg_types)?;
let context_handle = ContextHandle::from_slice_to_option(
input_arg_map.get_or_err(INPUT_ID_CONTEXT_HANDLE)?,
)?;
let retain_context = input_arg_map.get_or_err(INPUT_ID_RETAIN_CONTEXT)?;
let clear_from_context =
input_arg_map.get_or_err(INPUT_ID_CLEAR_FROM_CONTEXT)?;
let (certificate_chain, new_context_handle) = dpe.get_certificate_chain(
context_handle.as_ref(),
retain_context,
clear_from_context,
)?;
let mut output_args: ArgMap = Default::default();
output_args.insert_or_err(
OUTPUT_ID_CERTIFICATE_CHAIN,
certificate_chain.as_slice(),
)?;
if let Some(ref new_context_handle) = new_context_handle {
output_args
.insert_or_err(OUTPUT_ID_HANDLE, new_context_handle.as_slice())?;
}
drop(input_arg_map);
encode_args(&output_args, message_buffer)
}
fn handle_certify_key(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const INPUT_ID_CONTEXT_HANDLE: ArgId = 1;
const INPUT_ID_RETAIN_CONTEXT: ArgId = 2;
const INPUT_ID_PUBLIC_KEY: ArgId = 3;
const INPUT_ID_LABEL: ArgId = 4;
const INPUT_ID_ADDITIONAL_INPUT: ArgId = 6;
const OUTPUT_ID_CERTIFICATE: ArgId = 1;
const OUTPUT_ID_DERIVED_PUBLIC_KEY: ArgId = 2;
const OUTPUT_ID_HANDLE: ArgId = 3;
let input_arg_types = ArgTypeMap::from_iter([
(INPUT_ID_CONTEXT_HANDLE, ArgTypeSelector::Bytes),
(INPUT_ID_RETAIN_CONTEXT, ArgTypeSelector::Bool(false)),
(INPUT_ID_PUBLIC_KEY, ArgTypeSelector::Bytes),
(INPUT_ID_LABEL, ArgTypeSelector::Bytes),
(INPUT_ID_ADDITIONAL_INPUT, ArgTypeSelector::Bytes),
]);
let input_arg_map =
decode_args(message_buffer.as_slice(), &input_arg_types)?;
let context_handle = ContextHandle::from_slice_to_option(
input_arg_map.get_or_err(INPUT_ID_CONTEXT_HANDLE)?,
)?;
let retain_context = input_arg_map.get_or_err(INPUT_ID_RETAIN_CONTEXT)?;
let public_key_bytes: &[u8] =
input_arg_map.get_or_err(INPUT_ID_PUBLIC_KEY)?;
let public_key;
let public_key_opt = if public_key_bytes.is_empty() {
None
} else {
public_key = SigningPublicKey::from_slice(public_key_bytes)?;
Some(&public_key)
};
let label = input_arg_map.get_or_err(INPUT_ID_LABEL)?;
let additional_input =
input_arg_map.get_or_err(INPUT_ID_ADDITIONAL_INPUT)?;
let (certificate, derived_public_key, new_context_handle) = dpe
.certify_key(
context_handle.as_ref(),
retain_context,
public_key_opt,
label,
additional_input,
)?;
let mut output_args: ArgMap = Default::default();
output_args
.insert_or_err(OUTPUT_ID_CERTIFICATE, certificate.0.as_slice())?;
if let Some(ref derived_public_key) = derived_public_key {
output_args.insert_or_err(
OUTPUT_ID_DERIVED_PUBLIC_KEY,
derived_public_key.as_slice(),
)?;
}
if let Some(ref new_context_handle) = new_context_handle {
output_args
.insert_or_err(OUTPUT_ID_HANDLE, new_context_handle.as_slice())?;
}
drop(input_arg_map);
encode_args(&output_args, message_buffer)
}
fn handle_sign(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const INPUT_ID_CONTEXT_HANDLE: ArgId = 1;
const INPUT_ID_RETAIN_CONTEXT: ArgId = 2;
const INPUT_ID_LABEL: ArgId = 3;
const INPUT_ID_IS_SYMMETRIC: ArgId = 4;
const INPUT_ID_TO_BE_SIGNED: ArgId = 5;
const OUTPUT_ID_SIGNATURE: ArgId = 1;
const OUTPUT_ID_HANDLE: ArgId = 2;
let input_arg_types = ArgTypeMap::from_iter([
(INPUT_ID_CONTEXT_HANDLE, ArgTypeSelector::Bytes),
(INPUT_ID_RETAIN_CONTEXT, ArgTypeSelector::Bool(false)),
(INPUT_ID_LABEL, ArgTypeSelector::Bytes),
(INPUT_ID_IS_SYMMETRIC, ArgTypeSelector::Bool(false)),
(INPUT_ID_TO_BE_SIGNED, ArgTypeSelector::Bytes),
]);
let input_arg_map =
decode_args(message_buffer.as_slice(), &input_arg_types)?;
let context_handle = ContextHandle::from_slice_to_option(
input_arg_map.get_or_err(INPUT_ID_CONTEXT_HANDLE)?,
)?;
let retain_context = input_arg_map.get_or_err(INPUT_ID_RETAIN_CONTEXT)?;
let label = input_arg_map.get_or_err(INPUT_ID_LABEL)?;
let is_symmetric = input_arg_map.get_or_err(INPUT_ID_IS_SYMMETRIC)?;
let to_be_signed = input_arg_map.get_or_err(INPUT_ID_TO_BE_SIGNED)?;
let (signature, new_context_handle) = dpe.sign(
context_handle.as_ref(),
retain_context,
label,
is_symmetric,
to_be_signed,
)?;
let mut output_args: ArgMap = Default::default();
output_args.insert_or_err(OUTPUT_ID_SIGNATURE, signature.as_slice())?;
if let Some(ref new_context_handle) = new_context_handle {
output_args
.insert_or_err(OUTPUT_ID_HANDLE, new_context_handle.as_slice())?;
}
drop(input_arg_map);
encode_args(&output_args, message_buffer)
}
fn handle_seal(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const INPUT_ID_CONTEXT_HANDLE: ArgId = 1;
const INPUT_ID_RETAIN_CONTEXT: ArgId = 2;
const INPUT_ID_POLICY: ArgId = 3;
const INPUT_ID_LABEL: ArgId = 4;
const INPUT_ID_DATA_TO_SEAL: ArgId = 5;
const OUTPUT_ID_SEALED_DATA: ArgId = 1;
const OUTPUT_ID_HANDLE: ArgId = 2;
let input_arg_types = ArgTypeMap::from_iter([
(INPUT_ID_CONTEXT_HANDLE, ArgTypeSelector::Bytes),
(INPUT_ID_RETAIN_CONTEXT, ArgTypeSelector::Bool(false)),
(INPUT_ID_POLICY, ArgTypeSelector::Bytes),
(INPUT_ID_LABEL, ArgTypeSelector::Bytes),
(INPUT_ID_DATA_TO_SEAL, ArgTypeSelector::Bytes),
]);
let input_arg_map =
decode_args(message_buffer.as_slice(), &input_arg_types)?;
let context_handle = ContextHandle::from_slice_to_option(
input_arg_map.get_or_err(INPUT_ID_CONTEXT_HANDLE)?,
)?;
let retain_context = input_arg_map.get_or_err(INPUT_ID_RETAIN_CONTEXT)?;
let policy = input_arg_map.get_or_err(INPUT_ID_POLICY)?;
let label = input_arg_map.get_or_err(INPUT_ID_LABEL)?;
let data_to_seal = input_arg_map.get_or_err(INPUT_ID_DATA_TO_SEAL)?;
let (sealed_data, new_context_handle) = dpe.seal(
context_handle.as_ref(),
retain_context,
policy,
label,
data_to_seal,
)?;
let mut output_args: ArgMap = Default::default();
output_args.insert_or_err(OUTPUT_ID_SEALED_DATA, sealed_data.as_slice())?;
if let Some(ref new_context_handle) = new_context_handle {
output_args
.insert_or_err(OUTPUT_ID_HANDLE, new_context_handle.as_slice())?;
}
drop(input_arg_map);
encode_args(&output_args, message_buffer)
}
fn handle_unseal(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const INPUT_ID_CONTEXT_HANDLE: ArgId = 1;
const INPUT_ID_RETAIN_CONTEXT: ArgId = 2;
const INPUT_ID_IS_ASYMMETRIC: ArgId = 3;
const INPUT_ID_POLICY: ArgId = 4;
const INPUT_ID_LABEL: ArgId = 5;
const INPUT_ID_DATA_TO_UNSEAL: ArgId = 6;
const OUTPUT_ID_UNSEALED_DATA: ArgId = 1;
const OUTPUT_ID_HANDLE: ArgId = 2;
let input_arg_types = ArgTypeMap::from_iter([
(INPUT_ID_CONTEXT_HANDLE, ArgTypeSelector::Bytes),
(INPUT_ID_RETAIN_CONTEXT, ArgTypeSelector::Bool(false)),
(INPUT_ID_IS_ASYMMETRIC, ArgTypeSelector::Bool(false)),
(INPUT_ID_POLICY, ArgTypeSelector::Bytes),
(INPUT_ID_LABEL, ArgTypeSelector::Bytes),
(INPUT_ID_DATA_TO_UNSEAL, ArgTypeSelector::Bytes),
]);
let input_arg_map =
decode_args(message_buffer.as_slice(), &input_arg_types)?;
let context_handle = ContextHandle::from_slice_to_option(
input_arg_map.get_or_err(INPUT_ID_CONTEXT_HANDLE)?,
)?;
let retain_context = input_arg_map.get_or_err(INPUT_ID_RETAIN_CONTEXT)?;
let is_asymmetric = input_arg_map.get_or_err(INPUT_ID_IS_ASYMMETRIC)?;
let policy = input_arg_map.get_or_err(INPUT_ID_POLICY)?;
let label = input_arg_map.get_or_err(INPUT_ID_LABEL)?;
let data_to_unseal = input_arg_map.get_or_err(INPUT_ID_DATA_TO_UNSEAL)?;
let (unsealed_data, new_context_handle) = dpe.unseal(
context_handle.as_ref(),
retain_context,
is_asymmetric,
policy,
label,
data_to_unseal,
)?;
let mut output_args: ArgMap = Default::default();
output_args
.insert_or_err(OUTPUT_ID_UNSEALED_DATA, unsealed_data.as_slice())?;
if let Some(ref new_context_handle) = new_context_handle {
output_args
.insert_or_err(OUTPUT_ID_HANDLE, new_context_handle.as_slice())?;
}
drop(input_arg_map);
encode_args(&output_args, message_buffer)
}
fn handle_derive_sealing_public_key(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const INPUT_ID_CONTEXT_HANDLE: ArgId = 1;
const INPUT_ID_RETAIN_CONTEXT: ArgId = 2;
const INPUT_ID_POLICY: ArgId = 3;
const INPUT_ID_LABEL: ArgId = 4;
const OUTPUT_ID_PUBLIC_KEY: ArgId = 1;
const OUTPUT_ID_HANDLE: ArgId = 2;
let input_arg_types = ArgTypeMap::from_iter([
(INPUT_ID_CONTEXT_HANDLE, ArgTypeSelector::Bytes),
(INPUT_ID_RETAIN_CONTEXT, ArgTypeSelector::Bool(false)),
(INPUT_ID_POLICY, ArgTypeSelector::Bytes),
(INPUT_ID_LABEL, ArgTypeSelector::Bytes),
]);
let input_arg_map =
decode_args(message_buffer.as_slice(), &input_arg_types)?;
let context_handle = ContextHandle::from_slice_to_option(
input_arg_map.get_or_err(INPUT_ID_CONTEXT_HANDLE)?,
)?;
let retain_context = input_arg_map.get_or_err(INPUT_ID_RETAIN_CONTEXT)?;
let policy = input_arg_map.get_or_err(INPUT_ID_POLICY)?;
let label = input_arg_map.get_or_err(INPUT_ID_LABEL)?;
let (public_key, new_context_handle) = dpe.derive_sealing_public_key(
context_handle.as_ref(),
retain_context,
policy,
label,
)?;
let mut output_args: ArgMap = Default::default();
output_args.insert_or_err(OUTPUT_ID_PUBLIC_KEY, public_key.as_slice())?;
if let Some(ref new_context_handle) = new_context_handle {
output_args
.insert_or_err(OUTPUT_ID_HANDLE, new_context_handle.as_slice())?;
}
drop(input_arg_map);
encode_args(&output_args, message_buffer)
}
fn handle_rotate_context_handle(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const INPUT_ID_HANDLE: ArgId = 1;
const INPUT_ID_TO_DEFAULT: ArgId = 2;
const INPUT_ID_TARGET_LOCALITY: ArgId = 3;
const OUTPUT_ID_HANDLE: ArgId = 1;
let input_arg_types = ArgTypeMap::from_iter([
(INPUT_ID_HANDLE, ArgTypeSelector::Bytes),
(INPUT_ID_TO_DEFAULT, ArgTypeSelector::Bool(false)),
(INPUT_ID_TARGET_LOCALITY, ArgTypeSelector::Bytes),
]);
let input_arg_map =
decode_args(message_buffer.as_slice(), &input_arg_types)?;
let handle = ContextHandle::from_slice_to_option(
input_arg_map.get_or_err(INPUT_ID_HANDLE)?,
)?;
let to_default = input_arg_map.get_or_err(INPUT_ID_TO_DEFAULT)?;
let target_locality = decode_locality(
input_arg_map.get_or_err(INPUT_ID_TARGET_LOCALITY)?,
dpe.get_current_locality(),
)?;
let new_handle = dpe.rotate_context_handle(
handle.as_ref(),
to_default,
target_locality,
)?;
let mut output_args: ArgMap = Default::default();
if let Some(ref new_handle) = new_handle {
output_args.insert_or_err(OUTPUT_ID_HANDLE, new_handle.as_slice())?;
}
drop(input_arg_map);
encode_args(&output_args, message_buffer)
}
fn handle_destroy_context(
dpe: &mut impl DpeCore,
message_buffer: &mut Message,
) -> DpeResult<()> {
const INPUT_ID_HANDLE: ArgId = 1;
const INPUT_ID_RECURSIVE: ArgId = 2;
let input_arg_types = ArgTypeMap::from_iter([
(INPUT_ID_HANDLE, ArgTypeSelector::Bytes),
(INPUT_ID_RECURSIVE, ArgTypeSelector::Bool(false)),
]);
let input_arg_map =
decode_args(message_buffer.as_slice(), &input_arg_types)?;
let handle = ContextHandle::from_slice_to_option(
input_arg_map.get_or_err(INPUT_ID_HANDLE)?,
)?;
let recursive = input_arg_map.get_or_err(INPUT_ID_RECURSIVE)?;
dpe.destroy_context(handle.as_ref(), recursive)?;
drop(input_arg_map);
message_buffer.clear();
encode_args(&Default::default(), message_buffer)
}