blob: da39f8f8ed761d0aa772d7af07430495f341f1e5 [file] [log] [blame]
Janis Danisevskisc51dff82021-10-20 09:51:16 -07001// 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
17use android_hardware_security_dice::aidl::android::hardware::security::dice::{
18 Bcc::Bcc, BccHandover::BccHandover, InputValues::InputValues as BinderInputValues,
19 Mode::Mode as BinderMode,
20};
Janis Danisevskisd9513f42021-12-16 17:15:13 -080021use anyhow::{Context, Result};
Alice Wang97d47a72023-01-31 12:48:02 +000022use dice::{ContextImpl, DiceMode};
Janis Danisevskisc51dff82021-10-20 09:51:16 -070023use diced_open_dice_cbor as dice;
24use keystore2_crypto::ZVec;
Janis Danisevskisd9513f42021-12-16 17:15:13 -080025use std::convert::TryInto;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070026
27/// This new type wraps a reference to BinderInputValues and implements the open dice
28/// InputValues trait.
29#[derive(Debug)]
30pub struct InputValues<'a>(&'a BinderInputValues);
31
Janis Danisevskisd9513f42021-12-16 17:15:13 -080032impl<'a> From<&'a BinderInputValues> for InputValues<'a> {
33 fn from(input_values: &'a BinderInputValues) -> InputValues<'a> {
34 Self(input_values)
Janis Danisevskisc51dff82021-10-20 09:51:16 -070035 }
36}
37
38impl From<&InputValues<'_>> for BinderInputValues {
39 fn from(input_values: &InputValues) -> BinderInputValues {
40 input_values.0.clone()
41 }
42}
43impl From<InputValues<'_>> for BinderInputValues {
44 fn from(input_values: InputValues) -> BinderInputValues {
45 input_values.0.clone()
46 }
47}
48
49impl dice::InputValues for InputValues<'_> {
50 fn code_hash(&self) -> &[u8; dice::HASH_SIZE] {
Janis Danisevskisd9513f42021-12-16 17:15:13 -080051 &self.0.codeHash
Janis Danisevskisc51dff82021-10-20 09:51:16 -070052 }
53
54 fn config(&self) -> dice::Config {
55 dice::Config::Descriptor(self.0.config.desc.as_slice())
56 }
57
58 fn authority_hash(&self) -> &[u8; dice::HASH_SIZE] {
Janis Danisevskisd9513f42021-12-16 17:15:13 -080059 &self.0.authorityHash
Janis Danisevskisc51dff82021-10-20 09:51:16 -070060 }
61
62 fn authority_descriptor(&self) -> Option<&[u8]> {
63 self.0.authorityDescriptor.as_deref()
64 }
65
Alice Wang97d47a72023-01-31 12:48:02 +000066 fn mode(&self) -> DiceMode {
Janis Danisevskisc51dff82021-10-20 09:51:16 -070067 match self.0.mode {
Alice Wang97d47a72023-01-31 12:48:02 +000068 BinderMode::NOT_INITIALIZED => DiceMode::kDiceModeNotInitialized,
69 BinderMode::NORMAL => DiceMode::kDiceModeNormal,
70 BinderMode::DEBUG => DiceMode::kDiceModeDebug,
71 BinderMode::RECOVERY => DiceMode::kDiceModeMaintenance,
72 _ => DiceMode::kDiceModeNotInitialized,
Janis Danisevskisc51dff82021-10-20 09:51:16 -070073 }
74 }
75
76 fn hidden(&self) -> &[u8; dice::HIDDEN_SIZE] {
77 // If `self` was created using try_from the length was checked and this cannot panic.
Janis Danisevskisd9513f42021-12-16 17:15:13 -080078 &self.0.hidden
Janis Danisevskisc51dff82021-10-20 09:51:16 -070079 }
80}
81
82/// Initializes an aidl defined BccHandover object with the arguments `cdi_attest`, `cdi_seal`,
83/// and `bcc`.
84pub fn make_bcc_handover(
85 cdi_attest: &[u8; dice::CDI_SIZE],
86 cdi_seal: &[u8; dice::CDI_SIZE],
87 bcc: &[u8],
88) -> Result<BccHandover> {
Janis Danisevskisd9513f42021-12-16 17:15:13 -080089 Ok(BccHandover { cdiAttest: *cdi_attest, cdiSeal: *cdi_seal, bcc: Bcc { data: bcc.to_vec() } })
Janis Danisevskisc51dff82021-10-20 09:51:16 -070090}
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.
96pub struct ResidentArtifacts {
97 cdi_attest: ZVec,
98 cdi_seal: ZVec,
99 bcc: Vec<u8>,
100}
101
102impl 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.
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
Janis Danisevskisaaba4af2021-11-18 14:25:07 -0800122 /// 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.
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
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700133 /// Attempts to clone the artifacts. This operation is fallible due to the fallible
134 /// nature of ZVec.
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)
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
Alice Wang93e6e372023-02-02 14:36:17 +0000156 fn execute_step(self, input_values: InputValues) -> Result<Self> {
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700157 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,
Alice Wang93e6e372023-02-02 14:36:17 +0000168 &input_values,
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700169 )
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.
Alice Wang93e6e372023-02-02 14:36:17 +0000176 pub fn execute_steps<'a, T, I>(self, input_values: I) -> Result<Self>
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700177 where
Alice Wang93e6e372023-02-02 14:36:17 +0000178 T: Into<InputValues<'a>>,
179 I: IntoIterator<Item = T>,
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700180 {
181 input_values
182 .into_iter()
Alice Wang93e6e372023-02-02 14:36:17 +0000183 .try_fold(self, |acc, input| acc.execute_step(input.into()))
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700184 .context("In ResidentArtifacts::execute_step:")
185 }
186}
187
Janis Danisevskisaaba4af2021-11-18 14:25:07 -0800188/// An object that implements this trait provides the typical DICE artifacts.
189/// CDI_ATTEST, CDI_SEAL, and a certificate chain up to the public key that
190/// can be derived from CDI_ATTEST. Implementations should check the length of
191/// the stored CDI_* secrets on creation so that any valid instance returns the
192/// correct secrets in an infallible way.
193pub trait DiceArtifacts {
194 /// Returns CDI_ATTEST.
195 fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE];
196 /// Returns CDI_SEAL.
197 fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE];
198 /// Returns the attestation certificate chain in BCC format.
199 fn bcc(&self) -> Vec<u8>;
200}
201
202/// Implement this trait to provide read and write access to a secure artifact
203/// storage that can be used by the ResidentHal implementation.
204pub trait UpdatableDiceArtifacts {
205 /// With artifacts provides access to the stored artifacts for the duration
206 /// of the function call by means of calling the callback.
207 fn with_artifacts<F, T>(&self, f: F) -> Result<T>
208 where
209 F: FnOnce(&dyn DiceArtifacts) -> Result<T>;
210
211 /// Consumes the object and returns a an updated version of itself.
212 fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self>
213 where
214 Self: Sized;
215}
216
217impl DiceArtifacts for ResidentArtifacts {
218 fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
219 self.cdi_attest[..].try_into().unwrap()
220 }
221 fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] {
222 self.cdi_seal[..].try_into().unwrap()
223 }
224 fn bcc(&self) -> Vec<u8> {
225 self.bcc.clone()
226 }
227}
228
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700229/// This submodule implements a limited set of CBOR generation functionality. Essentially,
230/// a cbor header generator and some convenience functions for number and BSTR encoding.
231pub mod cbor {
232 use anyhow::{anyhow, Context, Result};
233 use std::convert::TryInto;
234 use std::io::Write;
235
236 /// CBOR encodes a positive number.
237 pub fn encode_number(n: u64, buffer: &mut dyn Write) -> Result<()> {
238 encode_header(0, n, buffer)
239 }
240
241 /// CBOR encodes a binary string.
242 pub fn encode_bstr(bstr: &[u8], buffer: &mut dyn Write) -> Result<()> {
243 encode_header(
244 2,
245 bstr.len().try_into().context("In encode_bstr: Failed to convert usize to u64.")?,
246 buffer,
247 )
248 .context("In encode_bstr: While writing header.")?;
249 let written = buffer.write(bstr).context("In encode_bstr: While writing payload.")?;
250 if written != bstr.len() {
251 return Err(anyhow!("In encode_bstr: Buffer too small. ({}, {})", written, bstr.len()));
252 }
253 Ok(())
254 }
255
256 /// Formats a CBOR header. `t` is the type, and n is the header argument.
257 pub fn encode_header(t: u8, n: u64, buffer: &mut dyn Write) -> Result<()> {
258 match n {
259 n if n < 24 => {
Charisee03e00842023-01-25 01:41:23 +0000260 let written =
261 buffer.write(&u8::to_be_bytes((t << 5) | (n as u8 & 0x1F))).with_context(
262 || format!("In encode_header: Failed to write header ({}, {})", t, n),
263 )?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700264 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 =
Charisee03e00842023-01-25 01:41:23 +0000270 buffer.write(&u8::to_be_bytes((t << 5) | (24u8 & 0x1F))).with_context(
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700271 || 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 =
Charisee03e00842023-01-25 01:41:23 +0000289 buffer.write(&u8::to_be_bytes((t << 5) | (25u8 & 0x1F))).with_context(
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700290 || 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 =
Charisee03e00842023-01-25 01:41:23 +0000308 buffer.write(&u8::to_be_bytes((t << 5) | (26u8 & 0x1F))).with_context(
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700309 || 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 =
Charisee03e00842023-01-25 01:41:23 +0000327 buffer.write(&u8::to_be_bytes((t << 5) | (27u8 & 0x1F))).with_context(
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700328 || 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 }
Charisee03e00842023-01-25 01:41:23 +0000333 let written = buffer.write(&u64::to_be_bytes(n)).with_context(|| {
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700334 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
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]
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}