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, Result};
19 pub use open_dice_cbor_bindgen::DiceMode;
20 use open_dice_cbor_bindgen::{
21     DiceConfigType, DiceDeriveCdiCertificateId, DiceDeriveCdiPrivateKeySeed, DiceInputValues,
22     DiceMainFlow, DICE_CDI_SIZE, DICE_HASH_SIZE, DICE_HIDDEN_SIZE, DICE_ID_SIZE,
23     DICE_INLINE_CONFIG_SIZE, DICE_PRIVATE_KEY_SEED_SIZE, DICE_PRIVATE_KEY_SIZE,
24     DICE_PUBLIC_KEY_SIZE, DICE_SIGNATURE_SIZE,
25 };
26 #[cfg(feature = "serde_derive")]
27 use serde_derive::{Deserialize, Serialize};
28 use std::{marker::PhantomData, ptr};
29 use zeroize::{Zeroize, ZeroizeOnDrop};
30 
31 /// The size of a DICE hash.
32 pub const HASH_SIZE: usize = DICE_HASH_SIZE as usize;
33 /// The size of the DICE hidden value.
34 pub const HIDDEN_SIZE: usize = DICE_HIDDEN_SIZE as usize;
35 /// The size of a DICE inline config.
36 const INLINE_CONFIG_SIZE: usize = DICE_INLINE_CONFIG_SIZE as usize;
37 /// The size of a CDI.
38 pub const CDI_SIZE: usize = DICE_CDI_SIZE as usize;
39 /// The size of a private key seed.
40 pub const PRIVATE_KEY_SEED_SIZE: usize = DICE_PRIVATE_KEY_SEED_SIZE as usize;
41 /// The size of a private key.
42 pub const PRIVATE_KEY_SIZE: usize = DICE_PRIVATE_KEY_SIZE as usize;
43 /// The size of a public key.
44 pub const PUBLIC_KEY_SIZE: usize = DICE_PUBLIC_KEY_SIZE as usize;
45 /// The size of a signature.
46 pub const SIGNATURE_SIZE: usize = DICE_SIGNATURE_SIZE as usize;
47 /// The size of an ID.
48 pub const ID_SIZE: usize = DICE_ID_SIZE as usize;
49 
50 /// Array type of hashes used by DICE.
51 pub type Hash = [u8; HASH_SIZE];
52 /// Array type of additional input.
53 pub type Hidden = [u8; HIDDEN_SIZE];
54 /// Array type of inline configuration values.
55 pub type InlineConfig = [u8; INLINE_CONFIG_SIZE];
56 /// Array type of CDIs.
57 pub type Cdi = [u8; CDI_SIZE];
58 /// Array type of the public key.
59 pub type PublicKey = [u8; PUBLIC_KEY_SIZE];
60 /// Array type of the signature.
61 pub type Signature = [u8; SIGNATURE_SIZE];
62 /// Array type of DICE ID.
63 pub type DiceId = [u8; ID_SIZE];
64 
65 /// A trait for types that represent Dice artifacts, which include:
66 ///
67 /// - Attestation CDI
68 /// - Sealing CDI
69 /// - Boot Certificate Chain
70 ///
71 /// Types that implement this trait provide an access these artifacts.
72 pub trait DiceArtifacts {
73     /// Returns a reference to the attestation CDI.
cdi_attest(&self) -> &[u8; CDI_SIZE]74     fn cdi_attest(&self) -> &[u8; CDI_SIZE];
75 
76     /// Returns a reference to the sealing CDI.
cdi_seal(&self) -> &[u8; CDI_SIZE]77     fn cdi_seal(&self) -> &[u8; CDI_SIZE];
78 
79     /// Returns a reference to the Boot Certificate Chain, if present.
bcc(&self) -> Option<&[u8]>80     fn bcc(&self) -> Option<&[u8]>;
81 }
82 
83 /// TODO(b/268587826): Clean up the memory cache after zeroing out the memory
84 /// for sensitive data like CDI values and private key.
85 /// CDI Values.
86 #[derive(Debug, Zeroize, ZeroizeOnDrop, Default)]
87 #[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
88 pub struct CdiValues {
89     /// Attestation CDI.
90     pub cdi_attest: [u8; CDI_SIZE],
91     /// Sealing CDI.
92     pub cdi_seal: [u8; CDI_SIZE],
93 }
94 
95 /// Private key seed. The data is zeroed out when the struct is dropped.
96 #[derive(Zeroize, ZeroizeOnDrop, Default)]
97 pub struct PrivateKeySeed([u8; PRIVATE_KEY_SEED_SIZE]);
98 
99 impl PrivateKeySeed {
100     /// Returns an array reference of the private key seed.
as_array(&self) -> &[u8; PRIVATE_KEY_SEED_SIZE]101     pub fn as_array(&self) -> &[u8; PRIVATE_KEY_SEED_SIZE] {
102         &self.0
103     }
104 
105     /// Returns a mutable pointer to the slice buffer of the private key seed.
as_mut_ptr(&mut self) -> *mut u8106     pub fn as_mut_ptr(&mut self) -> *mut u8 {
107         self.0.as_mut_ptr()
108     }
109 }
110 
111 /// Private key. The data is zeroed out when the struct is dropped.
112 #[derive(Zeroize, ZeroizeOnDrop)]
113 pub struct PrivateKey([u8; PRIVATE_KEY_SIZE]);
114 
115 impl Default for PrivateKey {
116     /// Creates a new `PrivateKey` instance with all bytes set to 0.
117     ///
118     /// Since the size of the private key array is too large to be initialized
119     /// with a default value, this implementation sets all the bytes in the array
120     /// to 0 using the `[0u8; PRIVATE_KEY_SIZE]` syntax.
default() -> Self121     fn default() -> Self {
122         Self([0u8; PRIVATE_KEY_SIZE])
123     }
124 }
125 
126 impl PrivateKey {
127     /// Returns an array reference of the private key.
as_array(&self) -> &[u8; PRIVATE_KEY_SIZE]128     pub fn as_array(&self) -> &[u8; PRIVATE_KEY_SIZE] {
129         &self.0
130     }
131 
132     /// Returns a mutable pointer to the slice buffer of the private key.
as_mut_ptr(&mut self) -> *mut u8133     pub fn as_mut_ptr(&mut self) -> *mut u8 {
134         self.0.as_mut_ptr()
135     }
136 }
137 
138 /// Configuration descriptor for DICE input values.
139 #[derive(Debug, Clone, PartialEq, Eq)]
140 pub enum Config<'a> {
141     /// Reference to an inline descriptor.
142     Inline(&'a InlineConfig),
143     /// Reference to a free form descriptor that will be hashed by the implementation.
144     Descriptor(&'a [u8]),
145 }
146 
147 impl Config<'_> {
dice_config_type(&self) -> DiceConfigType148     fn dice_config_type(&self) -> DiceConfigType {
149         match self {
150             Self::Inline(_) => DiceConfigType::kDiceConfigTypeInline,
151             Self::Descriptor(_) => DiceConfigType::kDiceConfigTypeDescriptor,
152         }
153     }
154 
inline_config(&self) -> InlineConfig155     fn inline_config(&self) -> InlineConfig {
156         match self {
157             Self::Inline(inline) => **inline,
158             Self::Descriptor(_) => [0u8; INLINE_CONFIG_SIZE],
159         }
160     }
161 
descriptor_ptr(&self) -> *const u8162     fn descriptor_ptr(&self) -> *const u8 {
163         match self {
164             Self::Descriptor(descriptor) => descriptor.as_ptr(),
165             _ => ptr::null(),
166         }
167     }
168 
descriptor_size(&self) -> usize169     fn descriptor_size(&self) -> usize {
170         match self {
171             Self::Descriptor(descriptor) => descriptor.len(),
172             _ => 0,
173         }
174     }
175 }
176 
177 /// Wrap of `DiceInputValues`.
178 #[derive(Clone, Debug)]
179 pub struct InputValues<'a> {
180     dice_inputs: DiceInputValues,
181     // DiceInputValues contains a pointer to the separate config descriptor, which must therefore
182     // outlive it. Make sure the borrow checker can enforce that.
183     config_descriptor: PhantomData<&'a [u8]>,
184 }
185 
186 impl<'a> InputValues<'a> {
187     /// Creates a new `InputValues`.
new( code_hash: Hash, config: Config<'a>, authority_hash: Hash, mode: DiceMode, hidden: Hidden, ) -> Self188     pub fn new(
189         code_hash: Hash,
190         config: Config<'a>,
191         authority_hash: Hash,
192         mode: DiceMode,
193         hidden: Hidden,
194     ) -> Self {
195         Self {
196             dice_inputs: DiceInputValues {
197                 code_hash,
198                 code_descriptor: ptr::null(),
199                 code_descriptor_size: 0,
200                 config_type: config.dice_config_type(),
201                 config_value: config.inline_config(),
202                 config_descriptor: config.descriptor_ptr(),
203                 config_descriptor_size: config.descriptor_size(),
204                 authority_hash,
205                 authority_descriptor: ptr::null(),
206                 authority_descriptor_size: 0,
207                 mode,
208                 hidden,
209             },
210             config_descriptor: PhantomData,
211         }
212     }
213 
214     /// Returns a raw pointer to the wrapped `DiceInputValues`.
as_ptr(&self) -> *const DiceInputValues215     pub fn as_ptr(&self) -> *const DiceInputValues {
216         &self.dice_inputs as *const DiceInputValues
217     }
218 }
219 
220 /// Derives a CDI private key seed from a `cdi_attest` value.
derive_cdi_private_key_seed(cdi_attest: &Cdi) -> Result<PrivateKeySeed>221 pub fn derive_cdi_private_key_seed(cdi_attest: &Cdi) -> Result<PrivateKeySeed> {
222     let mut seed = PrivateKeySeed::default();
223     check_result(
224         // SAFETY: The function writes to the buffer within the given bounds, and only reads the
225         // input values. The first argument context is not used in this function.
226         unsafe {
227             DiceDeriveCdiPrivateKeySeed(
228                 ptr::null_mut(), // context
229                 cdi_attest.as_ptr(),
230                 seed.as_mut_ptr(),
231             )
232         },
233         seed.0.len(),
234     )?;
235     Ok(seed)
236 }
237 
238 /// Derives an ID from the given `cdi_public_key` value.
derive_cdi_certificate_id(cdi_public_key: &[u8]) -> Result<DiceId>239 pub fn derive_cdi_certificate_id(cdi_public_key: &[u8]) -> Result<DiceId> {
240     let mut id = [0u8; ID_SIZE];
241     check_result(
242         // SAFETY: The function writes to the buffer within the given bounds, and only reads the
243         // input values. The first argument context is not used in this function.
244         unsafe {
245             DiceDeriveCdiCertificateId(
246                 ptr::null_mut(), // context
247                 cdi_public_key.as_ptr(),
248                 cdi_public_key.len(),
249                 id.as_mut_ptr(),
250             )
251         },
252         id.len(),
253     )?;
254     Ok(id)
255 }
256 
257 /// Executes the main DICE flow.
258 ///
259 /// Given a full set of input values and the current CDI values, computes the
260 /// next CDI values and a matching certificate.
261 /// 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>262 pub fn dice_main_flow(
263     current_cdi_attest: &Cdi,
264     current_cdi_seal: &Cdi,
265     input_values: &InputValues,
266     next_cdi_certificate: &mut [u8],
267     next_cdi_values: &mut CdiValues,
268 ) -> Result<usize> {
269     let mut next_cdi_certificate_actual_size = 0;
270     check_result(
271         // SAFETY: The function only reads the current CDI values and inputs and writes
272         // to `next_cdi_certificate` and next CDI values within its bounds.
273         // The first argument can be null and is not used in the current implementation.
274         unsafe {
275             DiceMainFlow(
276                 ptr::null_mut(), // context
277                 current_cdi_attest.as_ptr(),
278                 current_cdi_seal.as_ptr(),
279                 input_values.as_ptr(),
280                 next_cdi_certificate.len(),
281                 next_cdi_certificate.as_mut_ptr(),
282                 &mut next_cdi_certificate_actual_size,
283                 next_cdi_values.cdi_attest.as_mut_ptr(),
284                 next_cdi_values.cdi_seal.as_mut_ptr(),
285             )
286         },
287         next_cdi_certificate_actual_size,
288     )?;
289     Ok(next_cdi_certificate_actual_size)
290 }
291