• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021, 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 //! Implements utility functions and types for diced and the dice HAL.
16 
17 use android_hardware_security_dice::aidl::android::hardware::security::dice::{
18     Bcc::Bcc, BccHandover::BccHandover, InputValues::InputValues as BinderInputValues,
19     Mode::Mode as BinderMode,
20 };
21 use anyhow::{Context, Result};
22 use dice::ContextImpl;
23 use diced_open_dice_cbor as dice;
24 use keystore2_crypto::ZVec;
25 use std::convert::TryInto;
26 
27 /// This new type wraps a reference to BinderInputValues and implements the open dice
28 /// InputValues trait.
29 #[derive(Debug)]
30 pub struct InputValues<'a>(&'a BinderInputValues);
31 
32 impl<'a> From<&'a BinderInputValues> for InputValues<'a> {
from(input_values: &'a BinderInputValues) -> InputValues<'a>33     fn from(input_values: &'a BinderInputValues) -> InputValues<'a> {
34         Self(input_values)
35     }
36 }
37 
38 impl From<&InputValues<'_>> for BinderInputValues {
from(input_values: &InputValues) -> BinderInputValues39     fn from(input_values: &InputValues) -> BinderInputValues {
40         input_values.0.clone()
41     }
42 }
43 impl From<InputValues<'_>> for BinderInputValues {
from(input_values: InputValues) -> BinderInputValues44     fn from(input_values: InputValues) -> BinderInputValues {
45         input_values.0.clone()
46     }
47 }
48 
49 impl dice::InputValues for InputValues<'_> {
code_hash(&self) -> &[u8; dice::HASH_SIZE]50     fn code_hash(&self) -> &[u8; dice::HASH_SIZE] {
51         &self.0.codeHash
52     }
53 
config(&self) -> dice::Config54     fn config(&self) -> dice::Config {
55         dice::Config::Descriptor(self.0.config.desc.as_slice())
56     }
57 
authority_hash(&self) -> &[u8; dice::HASH_SIZE]58     fn authority_hash(&self) -> &[u8; dice::HASH_SIZE] {
59         &self.0.authorityHash
60     }
61 
authority_descriptor(&self) -> Option<&[u8]>62     fn authority_descriptor(&self) -> Option<&[u8]> {
63         self.0.authorityDescriptor.as_deref()
64     }
65 
mode(&self) -> dice::Mode66     fn mode(&self) -> dice::Mode {
67         match self.0.mode {
68             BinderMode::NOT_INITIALIZED => dice::Mode::NotConfigured,
69             BinderMode::NORMAL => dice::Mode::Normal,
70             BinderMode::DEBUG => dice::Mode::Debug,
71             BinderMode::RECOVERY => dice::Mode::Recovery,
72             _ => dice::Mode::NotConfigured,
73         }
74     }
75 
hidden(&self) -> &[u8; dice::HIDDEN_SIZE]76     fn hidden(&self) -> &[u8; dice::HIDDEN_SIZE] {
77         // If `self` was created using try_from the length was checked and this cannot panic.
78         &self.0.hidden
79     }
80 }
81 
82 /// Initializes an aidl defined BccHandover object with the arguments `cdi_attest`, `cdi_seal`,
83 /// and `bcc`.
make_bcc_handover( cdi_attest: &[u8; dice::CDI_SIZE], cdi_seal: &[u8; dice::CDI_SIZE], bcc: &[u8], ) -> Result<BccHandover>84 pub fn make_bcc_handover(
85     cdi_attest: &[u8; dice::CDI_SIZE],
86     cdi_seal: &[u8; dice::CDI_SIZE],
87     bcc: &[u8],
88 ) -> Result<BccHandover> {
89     Ok(BccHandover { cdiAttest: *cdi_attest, cdiSeal: *cdi_seal, bcc: Bcc { data: bcc.to_vec() } })
90 }
91 
92 /// ResidentArtifacts stores a set of dice artifacts comprising CDI_ATTEST, CDI_SEAL,
93 /// and the BCC formatted attestation certificate chain. The sensitive secrets are
94 /// stored in zeroing vectors, and it implements functionality to perform DICE
95 /// derivation steps using libopen-dice-cbor.
96 pub struct ResidentArtifacts {
97     cdi_attest: ZVec,
98     cdi_seal: ZVec,
99     bcc: Vec<u8>,
100 }
101 
102 impl ResidentArtifacts {
103     /// Create a ResidentArtifacts object. The parameters ensure that the stored secrets
104     /// can only have the appropriate size, so that subsequent casts to array references
105     /// cannot fail.
new( cdi_attest: &[u8; dice::CDI_SIZE], cdi_seal: &[u8; dice::CDI_SIZE], bcc: &[u8], ) -> Result<Self>106     pub fn new(
107         cdi_attest: &[u8; dice::CDI_SIZE],
108         cdi_seal: &[u8; dice::CDI_SIZE],
109         bcc: &[u8],
110     ) -> Result<Self> {
111         Ok(ResidentArtifacts {
112             cdi_attest: cdi_attest[..]
113                 .try_into()
114                 .context("In ResidentArtifacts::new: Trying to convert cdi_attest to ZVec.")?,
115             cdi_seal: cdi_seal[..]
116                 .try_into()
117                 .context("In ResidentArtifacts::new: Trying to convert cdi_seal to ZVec.")?,
118             bcc: bcc.to_vec(),
119         })
120     }
121 
122     /// Creates a ResidentArtifacts object from another one implementing the DiceArtifacts
123     /// trait. Like `new` this function can only create artifacts of appropriate size
124     /// because DiceArtifacts returns array references of appropriate size.
new_from<T: DiceArtifacts + ?Sized>(artifacts: &T) -> Result<Self>125     pub fn new_from<T: DiceArtifacts + ?Sized>(artifacts: &T) -> Result<Self> {
126         Ok(ResidentArtifacts {
127             cdi_attest: artifacts.cdi_attest()[..].try_into()?,
128             cdi_seal: artifacts.cdi_seal()[..].try_into()?,
129             bcc: artifacts.bcc(),
130         })
131     }
132 
133     /// Attempts to clone the artifacts. This operation is fallible due to the fallible
134     /// nature of ZVec.
try_clone(&self) -> Result<Self>135     pub fn try_clone(&self) -> Result<Self> {
136         Ok(ResidentArtifacts {
137             cdi_attest: self
138                 .cdi_attest
139                 .try_clone()
140                 .context("In ResidentArtifacts::new: Trying to clone cdi_attest.")?,
141             cdi_seal: self
142                 .cdi_seal
143                 .try_clone()
144                 .context("In ResidentArtifacts::new: Trying to clone cdi_seal.")?,
145             bcc: self.bcc.clone(),
146         })
147     }
148 
149     /// Deconstruct the Artifacts into a tuple.
150     /// (CDI_ATTEST, CDI_SEAL, BCC)
into_tuple(self) -> (ZVec, ZVec, Vec<u8>)151     pub fn into_tuple(self) -> (ZVec, ZVec, Vec<u8>) {
152         let ResidentArtifacts { cdi_attest, cdi_seal, bcc } = self;
153         (cdi_attest, cdi_seal, bcc)
154     }
155 
execute_step(self, input_values: &dyn dice::InputValues) -> Result<Self>156     fn execute_step(self, input_values: &dyn dice::InputValues) -> Result<Self> {
157         let ResidentArtifacts { cdi_attest, cdi_seal, bcc } = self;
158 
159         let (cdi_attest, cdi_seal, bcc) = dice::OpenDiceCborContext::new()
160             .bcc_main_flow(
161                 cdi_attest[..].try_into().with_context(|| {
162                     format!("Trying to convert cdi_attest. (length: {})", cdi_attest.len())
163                 })?,
164                 cdi_seal[..].try_into().with_context(|| {
165                     format!("Trying to convert cdi_seal. (length: {})", cdi_seal.len())
166                 })?,
167                 &bcc,
168                 input_values,
169             )
170             .context("In ResidentArtifacts::execute_step:")?;
171         Ok(ResidentArtifacts { cdi_attest, cdi_seal, bcc })
172     }
173 
174     /// Iterate through the iterator of dice input values performing one
175     /// BCC main flow step on each element.
execute_steps<'a, Iter>(self, input_values: Iter) -> Result<Self> where Iter: IntoIterator<Item = &'a dyn dice::InputValues>,176     pub fn execute_steps<'a, Iter>(self, input_values: Iter) -> Result<Self>
177     where
178         Iter: IntoIterator<Item = &'a dyn dice::InputValues>,
179     {
180         input_values
181             .into_iter()
182             .try_fold(self, |acc, input_values| acc.execute_step(input_values))
183             .context("In ResidentArtifacts::execute_step:")
184     }
185 }
186 
187 /// An object that implements this trait provides the typical DICE artifacts.
188 /// CDI_ATTEST, CDI_SEAL, and a certificate chain up to the public key that
189 /// can be derived from CDI_ATTEST. Implementations should check the length of
190 /// the stored CDI_* secrets on creation so that any valid instance returns the
191 /// correct secrets in an infallible way.
192 pub trait DiceArtifacts {
193     /// Returns CDI_ATTEST.
cdi_attest(&self) -> &[u8; dice::CDI_SIZE]194     fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE];
195     /// Returns CDI_SEAL.
cdi_seal(&self) -> &[u8; dice::CDI_SIZE]196     fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE];
197     /// Returns the attestation certificate chain in BCC format.
bcc(&self) -> Vec<u8>198     fn bcc(&self) -> Vec<u8>;
199 }
200 
201 /// Implement this trait to provide read and write access to a secure artifact
202 /// storage that can be used by the ResidentHal implementation.
203 pub trait UpdatableDiceArtifacts {
204     /// With artifacts provides access to the stored artifacts for the duration
205     /// of the function call by means of calling the callback.
with_artifacts<F, T>(&self, f: F) -> Result<T> where F: FnOnce(&dyn DiceArtifacts) -> Result<T>206     fn with_artifacts<F, T>(&self, f: F) -> Result<T>
207     where
208         F: FnOnce(&dyn DiceArtifacts) -> Result<T>;
209 
210     /// Consumes the object and returns a an updated version of itself.
update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self> where Self: Sized211     fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self>
212     where
213         Self: Sized;
214 }
215 
216 impl DiceArtifacts for ResidentArtifacts {
cdi_attest(&self) -> &[u8; dice::CDI_SIZE]217     fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
218         self.cdi_attest[..].try_into().unwrap()
219     }
cdi_seal(&self) -> &[u8; dice::CDI_SIZE]220     fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] {
221         self.cdi_seal[..].try_into().unwrap()
222     }
bcc(&self) -> Vec<u8>223     fn bcc(&self) -> Vec<u8> {
224         self.bcc.clone()
225     }
226 }
227 
228 /// This submodule implements a limited set of CBOR generation functionality. Essentially,
229 /// a cbor header generator and some convenience functions for number and BSTR encoding.
230 pub mod cbor {
231     use anyhow::{anyhow, Context, Result};
232     use std::convert::TryInto;
233     use std::io::Write;
234 
235     /// CBOR encodes a positive number.
encode_number(n: u64, buffer: &mut dyn Write) -> Result<()>236     pub fn encode_number(n: u64, buffer: &mut dyn Write) -> Result<()> {
237         encode_header(0, n, buffer)
238     }
239 
240     /// CBOR encodes a binary string.
encode_bstr(bstr: &[u8], buffer: &mut dyn Write) -> Result<()>241     pub fn encode_bstr(bstr: &[u8], buffer: &mut dyn Write) -> Result<()> {
242         encode_header(
243             2,
244             bstr.len().try_into().context("In encode_bstr: Failed to convert usize to u64.")?,
245             buffer,
246         )
247         .context("In encode_bstr: While writing header.")?;
248         let written = buffer.write(bstr).context("In encode_bstr: While writing payload.")?;
249         if written != bstr.len() {
250             return Err(anyhow!("In encode_bstr: Buffer too small. ({}, {})", written, bstr.len()));
251         }
252         Ok(())
253     }
254 
255     /// Formats a CBOR header. `t` is the type, and n is the header argument.
encode_header(t: u8, n: u64, buffer: &mut dyn Write) -> Result<()>256     pub fn encode_header(t: u8, n: u64, buffer: &mut dyn Write) -> Result<()> {
257         match n {
258             n if n < 24 => {
259                 let written = buffer
260                     .write(&u8::to_be_bytes(((t as u8) << 5) | (n as u8 & 0x1F)))
261                     .with_context(|| {
262                     format!("In encode_header: Failed to write header ({}, {})", t, n)
263                 })?;
264                 if written != 1 {
265                     return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
266                 }
267             }
268             n if n <= 0xFF => {
269                 let written =
270                     buffer.write(&u8::to_be_bytes(((t as u8) << 5) | (24u8 & 0x1F))).with_context(
271                         || format!("In encode_header: Failed to write header ({}, {})", t, n),
272                     )?;
273                 if written != 1 {
274                     return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
275                 }
276                 let written = buffer.write(&u8::to_be_bytes(n as u8)).with_context(|| {
277                     format!("In encode_header: Failed to write size ({}, {})", t, n)
278                 })?;
279                 if written != 1 {
280                     return Err(anyhow!(
281                         "In encode_header while writing size: Buffer to small. ({}, {})",
282                         t,
283                         n
284                     ));
285                 }
286             }
287             n if n <= 0xFFFF => {
288                 let written =
289                     buffer.write(&u8::to_be_bytes(((t as u8) << 5) | (25u8 & 0x1F))).with_context(
290                         || format!("In encode_header: Failed to write header ({}, {})", t, n),
291                     )?;
292                 if written != 1 {
293                     return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
294                 }
295                 let written = buffer.write(&u16::to_be_bytes(n as u16)).with_context(|| {
296                     format!("In encode_header: Failed to write size ({}, {})", t, n)
297                 })?;
298                 if written != 2 {
299                     return Err(anyhow!(
300                         "In encode_header while writing size: Buffer to small. ({}, {})",
301                         t,
302                         n
303                     ));
304                 }
305             }
306             n if n <= 0xFFFFFFFF => {
307                 let written =
308                     buffer.write(&u8::to_be_bytes(((t as u8) << 5) | (26u8 & 0x1F))).with_context(
309                         || format!("In encode_header: Failed to write header ({}, {})", t, n),
310                     )?;
311                 if written != 1 {
312                     return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
313                 }
314                 let written = buffer.write(&u32::to_be_bytes(n as u32)).with_context(|| {
315                     format!("In encode_header: Failed to write size ({}, {})", t, n)
316                 })?;
317                 if written != 4 {
318                     return Err(anyhow!(
319                         "In encode_header while writing size: Buffer to small. ({}, {})",
320                         t,
321                         n
322                     ));
323                 }
324             }
325             n => {
326                 let written =
327                     buffer.write(&u8::to_be_bytes(((t as u8) << 5) | (27u8 & 0x1F))).with_context(
328                         || format!("In encode_header: Failed to write header ({}, {})", t, n),
329                     )?;
330                 if written != 1 {
331                     return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
332                 }
333                 let written = buffer.write(&u64::to_be_bytes(n as u64)).with_context(|| {
334                     format!("In encode_header: Failed to write size ({}, {})", t, n)
335                 })?;
336                 if written != 8 {
337                     return Err(anyhow!(
338                         "In encode_header while writing size: Buffer to small. ({}, {})",
339                         t,
340                         n
341                     ));
342                 }
343             }
344         }
345         Ok(())
346     }
347 
348     #[cfg(test)]
349     mod test {
350         use super::*;
351 
encode_header_helper(t: u8, n: u64) -> Vec<u8>352         fn encode_header_helper(t: u8, n: u64) -> Vec<u8> {
353             let mut b: Vec<u8> = vec![];
354             encode_header(t, n, &mut b).unwrap();
355             b
356         }
357 
358         #[test]
encode_header_test()359         fn encode_header_test() {
360             assert_eq!(&encode_header_helper(0, 0), &[0b000_00000]);
361             assert_eq!(&encode_header_helper(0, 23), &[0b000_10111]);
362             assert_eq!(&encode_header_helper(0, 24), &[0b000_11000, 24]);
363             assert_eq!(&encode_header_helper(0, 0xff), &[0b000_11000, 0xff]);
364             assert_eq!(&encode_header_helper(0, 0x100), &[0b000_11001, 0x01, 0x00]);
365             assert_eq!(&encode_header_helper(0, 0xffff), &[0b000_11001, 0xff, 0xff]);
366             assert_eq!(&encode_header_helper(0, 0x10000), &[0b000_11010, 0x00, 0x01, 0x00, 0x00]);
367             assert_eq!(
368                 &encode_header_helper(0, 0xffffffff),
369                 &[0b000_11010, 0xff, 0xff, 0xff, 0xff]
370             );
371             assert_eq!(
372                 &encode_header_helper(0, 0x100000000),
373                 &[0b000_11011, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]
374             );
375             assert_eq!(
376                 &encode_header_helper(0, 0xffffffffffffffff),
377                 &[0b000_11011, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
378             );
379         }
380     }
381 }
382