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