blob: 2b47dacf1aa2c55ea9acd3fa4e447404b49dae39 [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 Wang8722d9e2023-02-13 14:56:56 +000022use diced_open_dice as dice;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070023use keystore2_crypto::ZVec;
Janis Danisevskisd9513f42021-12-16 17:15:13 -080024use std::convert::TryInto;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070025
Alice Wangb68814b2023-02-02 13:15:32 +000026/// Converts the `InputValues` from the binder to the `InputValues` type in `diced_open_dice` crate.
27pub fn to_dice_input_values(input: &BinderInputValues) -> dice::InputValues {
28 if input.authorityDescriptor.is_some() {
29 unimplemented!("Authority descriptor is not yet implemented in the current library.");
Janis Danisevskisc51dff82021-10-20 09:51:16 -070030 }
Alice Wangb68814b2023-02-02 13:15:32 +000031 dice::InputValues::new(
32 input.codeHash,
33 dice::Config::Descriptor(input.config.desc.as_slice()),
34 input.authorityHash,
35 to_dice_mode(input.mode),
36 input.hidden,
37 )
Janis Danisevskisc51dff82021-10-20 09:51:16 -070038}
39
Alice Wangf4bd1c62023-02-08 08:38:44 +000040fn to_dice_mode(binder_mode: BinderMode) -> dice::DiceMode {
Alice Wangb68814b2023-02-02 13:15:32 +000041 match binder_mode {
Alice Wangf4bd1c62023-02-08 08:38:44 +000042 BinderMode::NOT_INITIALIZED => dice::DiceMode::kDiceModeNotInitialized,
43 BinderMode::NORMAL => dice::DiceMode::kDiceModeNormal,
44 BinderMode::DEBUG => dice::DiceMode::kDiceModeDebug,
45 BinderMode::RECOVERY => dice::DiceMode::kDiceModeMaintenance,
46 _ => dice::DiceMode::kDiceModeNotInitialized,
Janis Danisevskisc51dff82021-10-20 09:51:16 -070047 }
48}
49
50/// Initializes an aidl defined BccHandover object with the arguments `cdi_attest`, `cdi_seal`,
51/// and `bcc`.
52pub fn make_bcc_handover(
53 cdi_attest: &[u8; dice::CDI_SIZE],
54 cdi_seal: &[u8; dice::CDI_SIZE],
55 bcc: &[u8],
56) -> Result<BccHandover> {
Janis Danisevskisd9513f42021-12-16 17:15:13 -080057 Ok(BccHandover { cdiAttest: *cdi_attest, cdiSeal: *cdi_seal, bcc: Bcc { data: bcc.to_vec() } })
Janis Danisevskisc51dff82021-10-20 09:51:16 -070058}
59
60/// ResidentArtifacts stores a set of dice artifacts comprising CDI_ATTEST, CDI_SEAL,
61/// and the BCC formatted attestation certificate chain. The sensitive secrets are
62/// stored in zeroing vectors, and it implements functionality to perform DICE
63/// derivation steps using libopen-dice-cbor.
64pub struct ResidentArtifacts {
65 cdi_attest: ZVec,
66 cdi_seal: ZVec,
67 bcc: Vec<u8>,
68}
69
Alice Wangf4bd1c62023-02-08 08:38:44 +000070impl TryFrom<dice::OwnedDiceArtifacts> for ResidentArtifacts {
71 type Error = anyhow::Error;
72
73 fn try_from(dice_artifacts: dice::OwnedDiceArtifacts) -> Result<Self, Self::Error> {
74 Ok(ResidentArtifacts {
75 cdi_attest: dice_artifacts.cdi_values.cdi_attest[..].try_into()?,
76 cdi_seal: dice_artifacts.cdi_values.cdi_seal[..].try_into()?,
77 bcc: dice_artifacts.bcc[..].to_vec(),
78 })
79 }
80}
81
Janis Danisevskisc51dff82021-10-20 09:51:16 -070082impl ResidentArtifacts {
83 /// Create a ResidentArtifacts object. The parameters ensure that the stored secrets
84 /// can only have the appropriate size, so that subsequent casts to array references
85 /// cannot fail.
86 pub fn new(
87 cdi_attest: &[u8; dice::CDI_SIZE],
88 cdi_seal: &[u8; dice::CDI_SIZE],
89 bcc: &[u8],
90 ) -> Result<Self> {
91 Ok(ResidentArtifacts {
92 cdi_attest: cdi_attest[..]
93 .try_into()
94 .context("In ResidentArtifacts::new: Trying to convert cdi_attest to ZVec.")?,
95 cdi_seal: cdi_seal[..]
96 .try_into()
97 .context("In ResidentArtifacts::new: Trying to convert cdi_seal to ZVec.")?,
98 bcc: bcc.to_vec(),
99 })
100 }
101
Janis Danisevskisaaba4af2021-11-18 14:25:07 -0800102 /// Creates a ResidentArtifacts object from another one implementing the DiceArtifacts
103 /// trait. Like `new` this function can only create artifacts of appropriate size
104 /// because DiceArtifacts returns array references of appropriate size.
105 pub fn new_from<T: DiceArtifacts + ?Sized>(artifacts: &T) -> Result<Self> {
106 Ok(ResidentArtifacts {
107 cdi_attest: artifacts.cdi_attest()[..].try_into()?,
108 cdi_seal: artifacts.cdi_seal()[..].try_into()?,
109 bcc: artifacts.bcc(),
110 })
111 }
112
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700113 /// Attempts to clone the artifacts. This operation is fallible due to the fallible
114 /// nature of ZVec.
115 pub fn try_clone(&self) -> Result<Self> {
116 Ok(ResidentArtifacts {
117 cdi_attest: self
118 .cdi_attest
119 .try_clone()
120 .context("In ResidentArtifacts::new: Trying to clone cdi_attest.")?,
121 cdi_seal: self
122 .cdi_seal
123 .try_clone()
124 .context("In ResidentArtifacts::new: Trying to clone cdi_seal.")?,
125 bcc: self.bcc.clone(),
126 })
127 }
128
129 /// Deconstruct the Artifacts into a tuple.
130 /// (CDI_ATTEST, CDI_SEAL, BCC)
131 pub fn into_tuple(self) -> (ZVec, ZVec, Vec<u8>) {
132 let ResidentArtifacts { cdi_attest, cdi_seal, bcc } = self;
133 (cdi_attest, cdi_seal, bcc)
134 }
135
Alice Wangb68814b2023-02-02 13:15:32 +0000136 fn execute_step(self, input_values: &BinderInputValues) -> Result<Self> {
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700137 let ResidentArtifacts { cdi_attest, cdi_seal, bcc } = self;
138
Alice Wangf4bd1c62023-02-08 08:38:44 +0000139 dice::retry_bcc_main_flow(
140 cdi_attest[..].try_into().with_context(|| {
141 format!("Trying to convert cdi_attest. (length: {})", cdi_attest.len())
142 })?,
143 cdi_seal[..].try_into().with_context(|| {
144 format!("Trying to convert cdi_seal. (length: {})", cdi_seal.len())
145 })?,
146 &bcc,
147 &to_dice_input_values(input_values),
148 )
149 .context("In ResidentArtifacts::execute_step:")?
150 .try_into()
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700151 }
152
153 /// Iterate through the iterator of dice input values performing one
154 /// BCC main flow step on each element.
Alice Wangb68814b2023-02-02 13:15:32 +0000155 pub fn execute_steps<'a, I>(self, input_values: I) -> Result<Self>
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700156 where
Alice Wangb68814b2023-02-02 13:15:32 +0000157 I: IntoIterator<Item = &'a BinderInputValues>,
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700158 {
159 input_values
160 .into_iter()
Alice Wangb68814b2023-02-02 13:15:32 +0000161 .try_fold(self, |acc, input| acc.execute_step(input))
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700162 .context("In ResidentArtifacts::execute_step:")
163 }
164}
165
Janis Danisevskisaaba4af2021-11-18 14:25:07 -0800166/// An object that implements this trait provides the typical DICE artifacts.
167/// CDI_ATTEST, CDI_SEAL, and a certificate chain up to the public key that
168/// can be derived from CDI_ATTEST. Implementations should check the length of
169/// the stored CDI_* secrets on creation so that any valid instance returns the
170/// correct secrets in an infallible way.
171pub trait DiceArtifacts {
172 /// Returns CDI_ATTEST.
173 fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE];
174 /// Returns CDI_SEAL.
175 fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE];
176 /// Returns the attestation certificate chain in BCC format.
177 fn bcc(&self) -> Vec<u8>;
178}
179
180/// Implement this trait to provide read and write access to a secure artifact
181/// storage that can be used by the ResidentHal implementation.
182pub trait UpdatableDiceArtifacts {
183 /// With artifacts provides access to the stored artifacts for the duration
184 /// of the function call by means of calling the callback.
185 fn with_artifacts<F, T>(&self, f: F) -> Result<T>
186 where
187 F: FnOnce(&dyn DiceArtifacts) -> Result<T>;
188
189 /// Consumes the object and returns a an updated version of itself.
190 fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self>
191 where
192 Self: Sized;
193}
194
195impl DiceArtifacts for ResidentArtifacts {
196 fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
197 self.cdi_attest[..].try_into().unwrap()
198 }
199 fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] {
200 self.cdi_seal[..].try_into().unwrap()
201 }
202 fn bcc(&self) -> Vec<u8> {
203 self.bcc.clone()
204 }
205}
206
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700207/// This submodule implements a limited set of CBOR generation functionality. Essentially,
208/// a cbor header generator and some convenience functions for number and BSTR encoding.
209pub mod cbor {
210 use anyhow::{anyhow, Context, Result};
211 use std::convert::TryInto;
212 use std::io::Write;
213
214 /// CBOR encodes a positive number.
215 pub fn encode_number(n: u64, buffer: &mut dyn Write) -> Result<()> {
216 encode_header(0, n, buffer)
217 }
218
219 /// CBOR encodes a binary string.
220 pub fn encode_bstr(bstr: &[u8], buffer: &mut dyn Write) -> Result<()> {
221 encode_header(
222 2,
223 bstr.len().try_into().context("In encode_bstr: Failed to convert usize to u64.")?,
224 buffer,
225 )
226 .context("In encode_bstr: While writing header.")?;
227 let written = buffer.write(bstr).context("In encode_bstr: While writing payload.")?;
228 if written != bstr.len() {
229 return Err(anyhow!("In encode_bstr: Buffer too small. ({}, {})", written, bstr.len()));
230 }
231 Ok(())
232 }
233
234 /// Formats a CBOR header. `t` is the type, and n is the header argument.
235 pub fn encode_header(t: u8, n: u64, buffer: &mut dyn Write) -> Result<()> {
236 match n {
237 n if n < 24 => {
Charisee03e00842023-01-25 01:41:23 +0000238 let written =
239 buffer.write(&u8::to_be_bytes((t << 5) | (n as u8 & 0x1F))).with_context(
240 || format!("In encode_header: Failed to write header ({}, {})", t, n),
241 )?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700242 if written != 1 {
243 return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
244 }
245 }
246 n if n <= 0xFF => {
247 let written =
Charisee03e00842023-01-25 01:41:23 +0000248 buffer.write(&u8::to_be_bytes((t << 5) | (24u8 & 0x1F))).with_context(
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700249 || format!("In encode_header: Failed to write header ({}, {})", t, n),
250 )?;
251 if written != 1 {
252 return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
253 }
254 let written = buffer.write(&u8::to_be_bytes(n as u8)).with_context(|| {
255 format!("In encode_header: Failed to write size ({}, {})", t, n)
256 })?;
257 if written != 1 {
258 return Err(anyhow!(
259 "In encode_header while writing size: Buffer to small. ({}, {})",
260 t,
261 n
262 ));
263 }
264 }
265 n if n <= 0xFFFF => {
266 let written =
Charisee03e00842023-01-25 01:41:23 +0000267 buffer.write(&u8::to_be_bytes((t << 5) | (25u8 & 0x1F))).with_context(
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700268 || format!("In encode_header: Failed to write header ({}, {})", t, n),
269 )?;
270 if written != 1 {
271 return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
272 }
273 let written = buffer.write(&u16::to_be_bytes(n as u16)).with_context(|| {
274 format!("In encode_header: Failed to write size ({}, {})", t, n)
275 })?;
276 if written != 2 {
277 return Err(anyhow!(
278 "In encode_header while writing size: Buffer to small. ({}, {})",
279 t,
280 n
281 ));
282 }
283 }
284 n if n <= 0xFFFFFFFF => {
285 let written =
Charisee03e00842023-01-25 01:41:23 +0000286 buffer.write(&u8::to_be_bytes((t << 5) | (26u8 & 0x1F))).with_context(
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700287 || format!("In encode_header: Failed to write header ({}, {})", t, n),
288 )?;
289 if written != 1 {
290 return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
291 }
292 let written = buffer.write(&u32::to_be_bytes(n as u32)).with_context(|| {
293 format!("In encode_header: Failed to write size ({}, {})", t, n)
294 })?;
295 if written != 4 {
296 return Err(anyhow!(
297 "In encode_header while writing size: Buffer to small. ({}, {})",
298 t,
299 n
300 ));
301 }
302 }
303 n => {
304 let written =
Charisee03e00842023-01-25 01:41:23 +0000305 buffer.write(&u8::to_be_bytes((t << 5) | (27u8 & 0x1F))).with_context(
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700306 || format!("In encode_header: Failed to write header ({}, {})", t, n),
307 )?;
308 if written != 1 {
309 return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
310 }
Charisee03e00842023-01-25 01:41:23 +0000311 let written = buffer.write(&u64::to_be_bytes(n)).with_context(|| {
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700312 format!("In encode_header: Failed to write size ({}, {})", t, n)
313 })?;
314 if written != 8 {
315 return Err(anyhow!(
316 "In encode_header while writing size: Buffer to small. ({}, {})",
317 t,
318 n
319 ));
320 }
321 }
322 }
323 Ok(())
324 }
325
326 #[cfg(test)]
327 mod test {
328 use super::*;
329
330 fn encode_header_helper(t: u8, n: u64) -> Vec<u8> {
331 let mut b: Vec<u8> = vec![];
332 encode_header(t, n, &mut b).unwrap();
333 b
334 }
335
336 #[test]
337 fn encode_header_test() {
338 assert_eq!(&encode_header_helper(0, 0), &[0b000_00000]);
339 assert_eq!(&encode_header_helper(0, 23), &[0b000_10111]);
340 assert_eq!(&encode_header_helper(0, 24), &[0b000_11000, 24]);
341 assert_eq!(&encode_header_helper(0, 0xff), &[0b000_11000, 0xff]);
342 assert_eq!(&encode_header_helper(0, 0x100), &[0b000_11001, 0x01, 0x00]);
343 assert_eq!(&encode_header_helper(0, 0xffff), &[0b000_11001, 0xff, 0xff]);
344 assert_eq!(&encode_header_helper(0, 0x10000), &[0b000_11010, 0x00, 0x01, 0x00, 0x00]);
345 assert_eq!(
346 &encode_header_helper(0, 0xffffffff),
347 &[0b000_11010, 0xff, 0xff, 0xff, 0xff]
348 );
349 assert_eq!(
350 &encode_header_helper(0, 0x100000000),
351 &[0b000_11011, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]
352 );
353 assert_eq!(
354 &encode_header_helper(0, 0xffffffffffffffff),
355 &[0b000_11011, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
356 );
357 }
358 }
359}