blob: 6e2df81e95bb466bc14620a9eab60701e2553df0 [file] [log] [blame]
// Copyright 2023, The Android Open Source Project
//
// 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
//
// http://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.
//! Structs and functions about the types used in DICE.
//! This module mirrors the content in open-dice/include/dice/dice.h
use crate::error::{check_result, Result};
pub use open_dice_cbor_bindgen::DiceMode;
use open_dice_cbor_bindgen::{
DiceConfigType, DiceDeriveCdiCertificateId, DiceDeriveCdiPrivateKeySeed, DiceInputValues,
DiceMainFlow, DICE_CDI_SIZE, DICE_HASH_SIZE, DICE_HIDDEN_SIZE, DICE_ID_SIZE,
DICE_INLINE_CONFIG_SIZE, DICE_PRIVATE_KEY_SEED_SIZE, DICE_PRIVATE_KEY_SIZE,
DICE_PUBLIC_KEY_SIZE, DICE_SIGNATURE_SIZE,
};
use std::{marker::PhantomData, ptr};
use zeroize::{Zeroize, ZeroizeOnDrop};
/// The size of a DICE hash.
pub const HASH_SIZE: usize = DICE_HASH_SIZE as usize;
/// The size of the DICE hidden value.
pub const HIDDEN_SIZE: usize = DICE_HIDDEN_SIZE as usize;
/// The size of a DICE inline config.
const INLINE_CONFIG_SIZE: usize = DICE_INLINE_CONFIG_SIZE as usize;
/// The size of a CDI.
pub const CDI_SIZE: usize = DICE_CDI_SIZE as usize;
/// The size of a private key seed.
pub const PRIVATE_KEY_SEED_SIZE: usize = DICE_PRIVATE_KEY_SEED_SIZE as usize;
/// The size of a private key.
pub const PRIVATE_KEY_SIZE: usize = DICE_PRIVATE_KEY_SIZE as usize;
/// The size of a public key.
pub const PUBLIC_KEY_SIZE: usize = DICE_PUBLIC_KEY_SIZE as usize;
/// The size of a signature.
pub const SIGNATURE_SIZE: usize = DICE_SIGNATURE_SIZE as usize;
/// The size of an ID.
pub const ID_SIZE: usize = DICE_ID_SIZE as usize;
/// Array type of hashes used by DICE.
pub type Hash = [u8; HASH_SIZE];
/// Array type of additional input.
pub type Hidden = [u8; HIDDEN_SIZE];
/// Array type of inline configuration values.
pub type InlineConfig = [u8; INLINE_CONFIG_SIZE];
/// Array type of CDIs.
pub type Cdi = [u8; CDI_SIZE];
/// Array type of the public key.
pub type PublicKey = [u8; PUBLIC_KEY_SIZE];
/// Array type of the signature.
pub type Signature = [u8; SIGNATURE_SIZE];
/// Array type of DICE ID.
pub type DiceId = [u8; ID_SIZE];
/// A trait for types that represent Dice artifacts, which include:
///
/// - Attestation CDI
/// - Sealing CDI
/// - Boot Certificate Chain
///
/// Types that implement this trait provide an access these artifacts.
pub trait DiceArtifacts {
/// Returns a reference to the attestation CDI.
fn cdi_attest(&self) -> &[u8; CDI_SIZE];
/// Returns a reference to the sealing CDI.
fn cdi_seal(&self) -> &[u8; CDI_SIZE];
/// Returns a reference to the Boot Certificate Chain, if present.
fn bcc(&self) -> Option<&[u8]>;
}
/// TODO(b/268587826): Clean up the memory cache after zeroing out the memory
/// for sensitive data like CDI values and private key.
/// CDI Values.
#[derive(Debug, Zeroize, ZeroizeOnDrop, Default)]
pub struct CdiValues {
/// Attestation CDI.
pub cdi_attest: [u8; CDI_SIZE],
/// Sealing CDI.
pub cdi_seal: [u8; CDI_SIZE],
}
/// Private key seed. The data is zeroed out when the struct is dropped.
#[derive(Zeroize, ZeroizeOnDrop, Default)]
pub struct PrivateKeySeed([u8; PRIVATE_KEY_SEED_SIZE]);
impl PrivateKeySeed {
/// Returns an array reference of the private key seed.
pub fn as_array(&self) -> &[u8; PRIVATE_KEY_SEED_SIZE] {
&self.0
}
/// Returns a mutable pointer to the slice buffer of the private key seed.
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.0.as_mut_ptr()
}
}
/// Private key. The data is zeroed out when the struct is dropped.
#[derive(Zeroize, ZeroizeOnDrop)]
pub struct PrivateKey([u8; PRIVATE_KEY_SIZE]);
impl Default for PrivateKey {
/// Creates a new `PrivateKey` instance with all bytes set to 0.
///
/// Since the size of the private key array is too large to be initialized
/// with a default value, this implementation sets all the bytes in the array
/// to 0 using the `[0u8; PRIVATE_KEY_SIZE]` syntax.
fn default() -> Self {
Self([0u8; PRIVATE_KEY_SIZE])
}
}
impl PrivateKey {
/// Returns an array reference of the private key.
pub fn as_array(&self) -> &[u8; PRIVATE_KEY_SIZE] {
&self.0
}
/// Returns a mutable pointer to the slice buffer of the private key.
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.0.as_mut_ptr()
}
}
/// Configuration descriptor for DICE input values.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Config<'a> {
/// Reference to an inline descriptor.
Inline(&'a InlineConfig),
/// Reference to a free form descriptor that will be hashed by the implementation.
Descriptor(&'a [u8]),
}
impl Config<'_> {
fn dice_config_type(&self) -> DiceConfigType {
match self {
Self::Inline(_) => DiceConfigType::kDiceConfigTypeInline,
Self::Descriptor(_) => DiceConfigType::kDiceConfigTypeDescriptor,
}
}
fn inline_config(&self) -> InlineConfig {
match self {
Self::Inline(inline) => **inline,
Self::Descriptor(_) => [0u8; INLINE_CONFIG_SIZE],
}
}
fn descriptor_ptr(&self) -> *const u8 {
match self {
Self::Descriptor(descriptor) => descriptor.as_ptr(),
_ => ptr::null(),
}
}
fn descriptor_size(&self) -> usize {
match self {
Self::Descriptor(descriptor) => descriptor.len(),
_ => 0,
}
}
}
/// Wrap of `DiceInputValues`.
#[derive(Clone, Debug)]
pub struct InputValues<'a> {
dice_inputs: DiceInputValues,
// DiceInputValues contains a pointer to the separate config descriptor, which must therefore
// outlive it. Make sure the borrow checker can enforce that.
config_descriptor: PhantomData<&'a [u8]>,
}
impl<'a> InputValues<'a> {
/// Creates a new `InputValues`.
pub fn new(
code_hash: Hash,
config: Config<'a>,
authority_hash: Hash,
mode: DiceMode,
hidden: Hidden,
) -> Self {
Self {
dice_inputs: DiceInputValues {
code_hash,
code_descriptor: ptr::null(),
code_descriptor_size: 0,
config_type: config.dice_config_type(),
config_value: config.inline_config(),
config_descriptor: config.descriptor_ptr(),
config_descriptor_size: config.descriptor_size(),
authority_hash,
authority_descriptor: ptr::null(),
authority_descriptor_size: 0,
mode,
hidden,
},
config_descriptor: PhantomData,
}
}
/// Returns a raw pointer to the wrapped `DiceInputValues`.
pub fn as_ptr(&self) -> *const DiceInputValues {
&self.dice_inputs as *const DiceInputValues
}
}
/// Derives a CDI private key seed from a `cdi_attest` value.
pub fn derive_cdi_private_key_seed(cdi_attest: &Cdi) -> Result<PrivateKeySeed> {
let mut seed = PrivateKeySeed::default();
// SAFETY: The function writes to the buffer within the given bounds, and only reads the
// input values. The first argument context is not used in this function.
check_result(unsafe {
DiceDeriveCdiPrivateKeySeed(
ptr::null_mut(), // context
cdi_attest.as_ptr(),
seed.as_mut_ptr(),
)
})?;
Ok(seed)
}
/// Derives an ID from the given `cdi_public_key` value.
pub fn derive_cdi_certificate_id(cdi_public_key: &[u8]) -> Result<DiceId> {
let mut id = [0u8; ID_SIZE];
// SAFETY: The function writes to the buffer within the given bounds, and only reads the
// input values. The first argument context is not used in this function.
check_result(unsafe {
DiceDeriveCdiCertificateId(
ptr::null_mut(), // context
cdi_public_key.as_ptr(),
cdi_public_key.len(),
id.as_mut_ptr(),
)
})?;
Ok(id)
}
/// Executes the main DICE flow.
///
/// Given a full set of input values and the current CDI values, computes the
/// next CDI values and a matching certificate.
/// Returns the actual size of the next CDI certificate.
pub fn dice_main_flow(
current_cdi_attest: &Cdi,
current_cdi_seal: &Cdi,
input_values: &InputValues,
next_cdi_certificate: &mut [u8],
next_cdi_values: &mut CdiValues,
) -> Result<usize> {
let mut next_cdi_certificate_actual_size = 0;
// SAFETY: The function only reads the current CDI values and inputs and writes
// to `next_cdi_certificate` and next CDI values within its bounds.
// The first argument can be null and is not used in the current implementation.
check_result(unsafe {
DiceMainFlow(
ptr::null_mut(), // context
current_cdi_attest.as_ptr(),
current_cdi_seal.as_ptr(),
input_values.as_ptr(),
next_cdi_certificate.len(),
next_cdi_certificate.as_mut_ptr(),
&mut next_cdi_certificate_actual_size,
next_cdi_values.cdi_attest.as_mut_ptr(),
next_cdi_values.cdi_seal.as_mut_ptr(),
)
})?;
Ok(next_cdi_certificate_actual_size)
}