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