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