1 // 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 //! Structs and functions about the types used in DICE.
16 //! This module mirrors the content in open-dice/include/dice/dice.h
17 
18 use crate::error::{check_result, DiceError, Result};
19 use coset::iana;
20 pub use open_dice_cbor_bindgen::DiceMode;
21 use open_dice_cbor_bindgen::{
22     DiceConfigType, DiceDeriveCdiCertificateId, DiceDeriveCdiPrivateKeySeed, DiceInputValues,
23     DiceMainFlow, DICE_CDI_SIZE, DICE_HASH_SIZE, DICE_HIDDEN_SIZE, DICE_ID_SIZE,
24     DICE_INLINE_CONFIG_SIZE, DICE_PRIVATE_KEY_BUFFER_SIZE, DICE_PRIVATE_KEY_SEED_SIZE,
25 };
26 #[cfg(feature = "multialg")]
27 use open_dice_cbor_bindgen::{DiceContext_, DiceKeyAlgorithm};
28 #[cfg(feature = "serde_derive")]
29 use serde_derive::{Deserialize, Serialize};
30 use std::{ffi::c_void, marker::PhantomData, ptr};
31 use zeroize::{Zeroize, ZeroizeOnDrop};
32 
33 /// The size of a DICE hash.
34 pub const HASH_SIZE: usize = DICE_HASH_SIZE as usize;
35 /// The size of the DICE hidden value.
36 pub const HIDDEN_SIZE: usize = DICE_HIDDEN_SIZE as usize;
37 /// The size of a DICE inline config.
38 const INLINE_CONFIG_SIZE: usize = DICE_INLINE_CONFIG_SIZE as usize;
39 /// The size of a CDI.
40 pub const CDI_SIZE: usize = DICE_CDI_SIZE as usize;
41 /// The size of a private key seed.
42 pub const PRIVATE_KEY_SEED_SIZE: usize = DICE_PRIVATE_KEY_SEED_SIZE as usize;
43 /// The size of a private key.
44 pub const PRIVATE_KEY_SIZE: usize = DICE_PRIVATE_KEY_BUFFER_SIZE as usize;
45 /// The size of an ID.
46 pub const ID_SIZE: usize = DICE_ID_SIZE as usize;
47 
48 /// Array type of hashes used by DICE.
49 pub type Hash = [u8; HASH_SIZE];
50 /// Array type of additional input.
51 pub type Hidden = [u8; HIDDEN_SIZE];
52 /// Array type of inline configuration values.
53 pub type InlineConfig = [u8; INLINE_CONFIG_SIZE];
54 /// Array type of CDIs.
55 pub type Cdi = [u8; CDI_SIZE];
56 /// Array type of DICE ID.
57 pub type DiceId = [u8; ID_SIZE];
58 
59 /// Key algorithm used for DICE.
60 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
61 pub enum KeyAlgorithm {
62     /// Ed25519.
63     Ed25519,
64     /// ECDSA using P-256 curve.
65     EcdsaP256,
66     /// ECDSA using P-384 curve.
67     EcdsaP384,
68 }
69 
70 impl From<KeyAlgorithm> for iana::Algorithm {
from(alg: KeyAlgorithm) -> Self71     fn from(alg: KeyAlgorithm) -> Self {
72         match alg {
73             KeyAlgorithm::Ed25519 => iana::Algorithm::EdDSA,
74             KeyAlgorithm::EcdsaP256 => iana::Algorithm::ES256,
75             KeyAlgorithm::EcdsaP384 => iana::Algorithm::ES384,
76         }
77     }
78 }
79 
80 /// Key algorithm used within different components in VMs.
81 ///
82 /// This algorithm serves two primary purposes:
83 ///
84 /// * **pvmfw Handover:** In pvmfw, a vendor DICE chain, potentially using various algorithms, is
85 ///   transitioned to this specific algorithm.
86 /// * **Post-Handover Consistency:** In components following pvmfw (e.g., the Microdroid OS), this
87 ///   algorithm is used consistently for both the authority and subject keys in DICE derivation.
88 pub const VM_KEY_ALGORITHM: KeyAlgorithm = KeyAlgorithm::Ed25519;
89 
90 impl KeyAlgorithm {
91     /// Returns the size of the public key.
public_key_size(&self) -> usize92     pub fn public_key_size(&self) -> usize {
93         match self {
94             KeyAlgorithm::Ed25519 => 32,
95             KeyAlgorithm::EcdsaP256 => 64,
96             KeyAlgorithm::EcdsaP384 => 96,
97         }
98     }
99 
100     /// Returns the size of the signature.
signature_size(&self) -> usize101     pub fn signature_size(&self) -> usize {
102         match self {
103             KeyAlgorithm::Ed25519 => 64,
104             KeyAlgorithm::EcdsaP256 => 64,
105             KeyAlgorithm::EcdsaP384 => 96,
106         }
107     }
108 
109     /// Returns the size of the private key.
private_key_size(&self) -> usize110     pub fn private_key_size(&self) -> usize {
111         match self {
112             KeyAlgorithm::Ed25519 => 64,
113             KeyAlgorithm::EcdsaP256 => 32,
114             KeyAlgorithm::EcdsaP384 => 48,
115         }
116     }
117 }
118 
119 impl TryFrom<iana::Algorithm> for KeyAlgorithm {
120     type Error = DiceError;
121 
try_from(alg: iana::Algorithm) -> Result<Self>122     fn try_from(alg: iana::Algorithm) -> Result<Self> {
123         match alg {
124             iana::Algorithm::EdDSA => Ok(KeyAlgorithm::Ed25519),
125             iana::Algorithm::ES256 => Ok(KeyAlgorithm::EcdsaP256),
126             iana::Algorithm::ES384 => Ok(KeyAlgorithm::EcdsaP384),
127             other => Err(DiceError::UnsupportedKeyAlgorithm(other)),
128         }
129     }
130 }
131 
132 #[cfg(feature = "multialg")]
133 impl From<KeyAlgorithm> for DiceKeyAlgorithm {
from(alg: KeyAlgorithm) -> Self134     fn from(alg: KeyAlgorithm) -> Self {
135         match alg {
136             KeyAlgorithm::Ed25519 => DiceKeyAlgorithm::kDiceKeyAlgorithmEd25519,
137             KeyAlgorithm::EcdsaP256 => DiceKeyAlgorithm::kDiceKeyAlgorithmP256,
138             KeyAlgorithm::EcdsaP384 => DiceKeyAlgorithm::kDiceKeyAlgorithmP384,
139         }
140     }
141 }
142 
143 /// Represents the context used for DICE operations.
144 #[cfg(feature = "multialg")]
145 #[derive(Debug, Clone)]
146 pub struct DiceContext {
147     /// The algorithm used for the authority key.
148     pub authority_algorithm: KeyAlgorithm,
149     /// The algorithm used for the subject key.
150     pub subject_algorithm: KeyAlgorithm,
151 }
152 
153 #[cfg(feature = "multialg")]
154 impl From<DiceContext> for DiceContext_ {
from(ctx: DiceContext) -> Self155     fn from(ctx: DiceContext) -> Self {
156         DiceContext_ {
157             authority_algorithm: ctx.authority_algorithm.into(),
158             subject_algorithm: ctx.subject_algorithm.into(),
159         }
160     }
161 }
162 
163 #[cfg(feature = "multialg")]
164 const VM_DICE_CONTEXT: DiceContext_ = DiceContext_ {
165     authority_algorithm: DiceKeyAlgorithm::kDiceKeyAlgorithmEd25519,
166     subject_algorithm: DiceKeyAlgorithm::kDiceKeyAlgorithmEd25519,
167 };
168 
169 /// Returns the pointer points to |DiceContext_| for DICE operations when `multialg`
170 /// feature is enabled.
171 #[cfg(feature = "multialg")]
context() -> *mut c_void172 pub(crate) fn context() -> *mut c_void {
173     &VM_DICE_CONTEXT as *const DiceContext_ as *mut c_void
174 }
175 
176 /// Returns a null pointer when `multialg` feature is disabled.
177 #[cfg(not(feature = "multialg"))]
context() -> *mut c_void178 pub(crate) fn context() -> *mut c_void {
179     ptr::null_mut()
180 }
181 
182 /// A trait for types that represent Dice artifacts, which include:
183 ///
184 /// - Attestation CDI
185 /// - Sealing CDI
186 /// - Boot Certificate Chain
187 ///
188 /// Types that implement this trait provide an access these artifacts.
189 pub trait DiceArtifacts {
190     /// Returns a reference to the attestation CDI.
cdi_attest(&self) -> &[u8; CDI_SIZE]191     fn cdi_attest(&self) -> &[u8; CDI_SIZE];
192 
193     /// Returns a reference to the sealing CDI.
cdi_seal(&self) -> &[u8; CDI_SIZE]194     fn cdi_seal(&self) -> &[u8; CDI_SIZE];
195 
196     /// Returns a reference to the Boot Certificate Chain, if present.
bcc(&self) -> Option<&[u8]>197     fn bcc(&self) -> Option<&[u8]>;
198 }
199 
200 /// TODO(b/268587826): Clean up the memory cache after zeroing out the memory
201 /// for sensitive data like CDI values and private key.
202 /// CDI Values.
203 #[derive(Debug, Zeroize, ZeroizeOnDrop, Default)]
204 #[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
205 pub struct CdiValues {
206     /// Attestation CDI.
207     pub cdi_attest: [u8; CDI_SIZE],
208     /// Sealing CDI.
209     pub cdi_seal: [u8; CDI_SIZE],
210 }
211 
212 /// Private key seed. The data is zeroed out when the struct is dropped.
213 #[derive(Zeroize, ZeroizeOnDrop, Default)]
214 pub struct PrivateKeySeed([u8; PRIVATE_KEY_SEED_SIZE]);
215 
216 impl PrivateKeySeed {
217     /// Returns an array reference of the private key seed.
as_array(&self) -> &[u8; PRIVATE_KEY_SEED_SIZE]218     pub fn as_array(&self) -> &[u8; PRIVATE_KEY_SEED_SIZE] {
219         &self.0
220     }
221 
222     /// Returns a mutable pointer to the slice buffer of the private key seed.
as_mut_ptr(&mut self) -> *mut u8223     pub fn as_mut_ptr(&mut self) -> *mut u8 {
224         self.0.as_mut_ptr()
225     }
226 }
227 
228 /// Private key. The data is zeroed out when the struct is dropped.
229 #[derive(Zeroize, ZeroizeOnDrop)]
230 pub struct PrivateKey([u8; PRIVATE_KEY_SIZE]);
231 
232 impl Default for PrivateKey {
233     /// Creates a new `PrivateKey` instance with all bytes set to 0.
234     ///
235     /// Since the size of the private key array is too large to be initialized
236     /// with a default value, this implementation sets all the bytes in the array
237     /// to 0 using the `[0u8; PRIVATE_KEY_SIZE]` syntax.
default() -> Self238     fn default() -> Self {
239         Self([0u8; PRIVATE_KEY_SIZE])
240     }
241 }
242 
243 impl PrivateKey {
244     /// Returns an array reference of the private key.
as_array(&self) -> &[u8; PRIVATE_KEY_SIZE]245     pub fn as_array(&self) -> &[u8; PRIVATE_KEY_SIZE] {
246         &self.0
247     }
248 
249     /// Returns a mutable pointer to the slice buffer of the private key.
as_mut_ptr(&mut self) -> *mut u8250     pub fn as_mut_ptr(&mut self) -> *mut u8 {
251         self.0.as_mut_ptr()
252     }
253 }
254 
255 /// Configuration descriptor for DICE input values.
256 #[derive(Debug, Clone, PartialEq, Eq)]
257 pub enum Config<'a> {
258     /// Reference to an inline descriptor.
259     Inline(&'a InlineConfig),
260     /// Reference to a free form descriptor that will be hashed by the implementation.
261     Descriptor(&'a [u8]),
262 }
263 
264 impl Config<'_> {
dice_config_type(&self) -> DiceConfigType265     fn dice_config_type(&self) -> DiceConfigType {
266         match self {
267             Self::Inline(_) => DiceConfigType::kDiceConfigTypeInline,
268             Self::Descriptor(_) => DiceConfigType::kDiceConfigTypeDescriptor,
269         }
270     }
271 
inline_config(&self) -> InlineConfig272     fn inline_config(&self) -> InlineConfig {
273         match self {
274             Self::Inline(inline) => **inline,
275             Self::Descriptor(_) => [0u8; INLINE_CONFIG_SIZE],
276         }
277     }
278 
descriptor_ptr(&self) -> *const u8279     fn descriptor_ptr(&self) -> *const u8 {
280         match self {
281             Self::Descriptor(descriptor) => descriptor.as_ptr(),
282             _ => ptr::null(),
283         }
284     }
285 
descriptor_size(&self) -> usize286     fn descriptor_size(&self) -> usize {
287         match self {
288             Self::Descriptor(descriptor) => descriptor.len(),
289             _ => 0,
290         }
291     }
292 }
293 
294 /// Wrap of `DiceInputValues`.
295 #[derive(Clone, Debug)]
296 pub struct InputValues<'a> {
297     dice_inputs: DiceInputValues,
298     // DiceInputValues contains a pointer to the separate config descriptor, which must therefore
299     // outlive it. Make sure the borrow checker can enforce that.
300     config_descriptor: PhantomData<&'a [u8]>,
301 }
302 
303 impl<'a> InputValues<'a> {
304     /// Creates a new `InputValues`.
new( code_hash: Hash, config: Config<'a>, authority_hash: Hash, mode: DiceMode, hidden: Hidden, ) -> Self305     pub fn new(
306         code_hash: Hash,
307         config: Config<'a>,
308         authority_hash: Hash,
309         mode: DiceMode,
310         hidden: Hidden,
311     ) -> Self {
312         Self {
313             dice_inputs: DiceInputValues {
314                 code_hash,
315                 code_descriptor: ptr::null(),
316                 code_descriptor_size: 0,
317                 config_type: config.dice_config_type(),
318                 config_value: config.inline_config(),
319                 config_descriptor: config.descriptor_ptr(),
320                 config_descriptor_size: config.descriptor_size(),
321                 authority_hash,
322                 authority_descriptor: ptr::null(),
323                 authority_descriptor_size: 0,
324                 mode,
325                 hidden,
326             },
327             config_descriptor: PhantomData,
328         }
329     }
330 
331     /// Returns a raw pointer to the wrapped `DiceInputValues`.
as_ptr(&self) -> *const DiceInputValues332     pub fn as_ptr(&self) -> *const DiceInputValues {
333         &self.dice_inputs as *const DiceInputValues
334     }
335 }
336 
337 /// Derives a CDI private key seed from a `cdi_attest` value.
derive_cdi_private_key_seed(cdi_attest: &Cdi) -> Result<PrivateKeySeed>338 pub fn derive_cdi_private_key_seed(cdi_attest: &Cdi) -> Result<PrivateKeySeed> {
339     let mut seed = PrivateKeySeed::default();
340     check_result(
341         // SAFETY: The function writes to the buffer within the given bounds, and only reads the
342         // input values. The first argument context is not used in this function.
343         unsafe {
344             DiceDeriveCdiPrivateKeySeed(
345                 ptr::null_mut(), // context
346                 cdi_attest.as_ptr(),
347                 seed.as_mut_ptr(),
348             )
349         },
350         seed.0.len(),
351     )?;
352     Ok(seed)
353 }
354 
355 /// Derives an ID from the given `cdi_public_key` value.
derive_cdi_certificate_id(cdi_public_key: &[u8]) -> Result<DiceId>356 pub fn derive_cdi_certificate_id(cdi_public_key: &[u8]) -> Result<DiceId> {
357     let mut id = [0u8; ID_SIZE];
358     check_result(
359         // SAFETY: The function writes to the buffer within the given bounds, and only reads the
360         // input values. The first argument context is not used in this function.
361         unsafe {
362             DiceDeriveCdiCertificateId(
363                 ptr::null_mut(), // context
364                 cdi_public_key.as_ptr(),
365                 cdi_public_key.len(),
366                 id.as_mut_ptr(),
367             )
368         },
369         id.len(),
370     )?;
371     Ok(id)
372 }
373 
374 /// Executes the main DICE flow.
375 ///
376 /// Given a full set of input values and the current CDI values, computes the
377 /// next CDI values and a matching certificate.
378 /// Returns the actual size of the next CDI certificate.
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>379 pub fn dice_main_flow(
380     current_cdi_attest: &Cdi,
381     current_cdi_seal: &Cdi,
382     input_values: &InputValues,
383     next_cdi_certificate: &mut [u8],
384     next_cdi_values: &mut CdiValues,
385 ) -> Result<usize> {
386     let mut next_cdi_certificate_actual_size = 0;
387     check_result(
388         // SAFETY: The function only reads the current CDI values and inputs and writes
389         // to `next_cdi_certificate` and next CDI values within its bounds.
390         unsafe {
391             DiceMainFlow(
392                 context(),
393                 current_cdi_attest.as_ptr(),
394                 current_cdi_seal.as_ptr(),
395                 input_values.as_ptr(),
396                 next_cdi_certificate.len(),
397                 next_cdi_certificate.as_mut_ptr(),
398                 &mut next_cdi_certificate_actual_size,
399                 next_cdi_values.cdi_attest.as_mut_ptr(),
400                 next_cdi_values.cdi_seal.as_mut_ptr(),
401             )
402         },
403         next_cdi_certificate_actual_size,
404     )?;
405     Ok(next_cdi_certificate_actual_size)
406 }
407