blob: 2789a60d2a279eefbda7cebaca9ec96dfca84f0c [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};
Alice Wang4d3059a2023-02-15 10:24:33 +000021use anyhow::{anyhow, Context, Result};
Alice Wang8722d9e2023-02-13 14:56:56 +000022use diced_open_dice as dice;
Alice Wang4d3059a2023-02-15 10:24:33 +000023use diced_open_dice::DiceArtifacts;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070024use 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 Wangf4bd1c62023-02-08 08:38:44 +000041fn to_dice_mode(binder_mode: BinderMode) -> dice::DiceMode {
Alice Wangb68814b2023-02-02 13:15:32 +000042 match binder_mode {
Alice Wangf4bd1c62023-02-08 08:38:44 +000043 BinderMode::NOT_INITIALIZED => dice::DiceMode::kDiceModeNotInitialized,
44 BinderMode::NORMAL => dice::DiceMode::kDiceModeNormal,
45 BinderMode::DEBUG => dice::DiceMode::kDiceModeDebug,
46 BinderMode::RECOVERY => dice::DiceMode::kDiceModeMaintenance,
47 _ => dice::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.
Alice Wang4d3059a2023-02-15 10:24:33 +000065/// TODO(b/268322533): Remove this struct with the unused HAL service dice
Janis Danisevskisc51dff82021-10-20 09:51:16 -070066pub struct ResidentArtifacts {
67 cdi_attest: ZVec,
68 cdi_seal: ZVec,
69 bcc: Vec<u8>,
70}
71
Alice Wangf4bd1c62023-02-08 08:38:44 +000072impl TryFrom<dice::OwnedDiceArtifacts> for ResidentArtifacts {
73 type Error = anyhow::Error;
74
75 fn try_from(dice_artifacts: dice::OwnedDiceArtifacts) -> Result<Self, Self::Error> {
76 Ok(ResidentArtifacts {
Alice Wang4d3059a2023-02-15 10:24:33 +000077 cdi_attest: dice_artifacts.cdi_attest().to_vec().try_into()?,
78 cdi_seal: dice_artifacts.cdi_seal().to_vec().try_into()?,
79 bcc: dice_artifacts.bcc().ok_or_else(|| anyhow!("bcc is none"))?.to_vec(),
Alice Wangf4bd1c62023-02-08 08:38:44 +000080 })
81 }
82}
83
Janis Danisevskisc51dff82021-10-20 09:51:16 -070084impl ResidentArtifacts {
85 /// Create a ResidentArtifacts object. The parameters ensure that the stored secrets
86 /// can only have the appropriate size, so that subsequent casts to array references
87 /// cannot fail.
88 pub fn new(
89 cdi_attest: &[u8; dice::CDI_SIZE],
90 cdi_seal: &[u8; dice::CDI_SIZE],
91 bcc: &[u8],
92 ) -> Result<Self> {
93 Ok(ResidentArtifacts {
94 cdi_attest: cdi_attest[..]
95 .try_into()
96 .context("In ResidentArtifacts::new: Trying to convert cdi_attest to ZVec.")?,
97 cdi_seal: cdi_seal[..]
98 .try_into()
99 .context("In ResidentArtifacts::new: Trying to convert cdi_seal to ZVec.")?,
100 bcc: bcc.to_vec(),
101 })
102 }
103
Janis Danisevskisaaba4af2021-11-18 14:25:07 -0800104 /// Creates a ResidentArtifacts object from another one implementing the DiceArtifacts
105 /// trait. Like `new` this function can only create artifacts of appropriate size
106 /// because DiceArtifacts returns array references of appropriate size.
107 pub fn new_from<T: DiceArtifacts + ?Sized>(artifacts: &T) -> Result<Self> {
108 Ok(ResidentArtifacts {
Alice Wang4d3059a2023-02-15 10:24:33 +0000109 cdi_attest: artifacts.cdi_attest().to_vec().try_into()?,
110 cdi_seal: artifacts.cdi_seal().to_vec().try_into()?,
111 bcc: artifacts.bcc().ok_or_else(|| anyhow!("bcc is none"))?.to_vec(),
Janis Danisevskisaaba4af2021-11-18 14:25:07 -0800112 })
113 }
114
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700115 /// Attempts to clone the artifacts. This operation is fallible due to the fallible
116 /// nature of ZVec.
117 pub fn try_clone(&self) -> Result<Self> {
118 Ok(ResidentArtifacts {
119 cdi_attest: self
120 .cdi_attest
121 .try_clone()
122 .context("In ResidentArtifacts::new: Trying to clone cdi_attest.")?,
123 cdi_seal: self
124 .cdi_seal
125 .try_clone()
126 .context("In ResidentArtifacts::new: Trying to clone cdi_seal.")?,
127 bcc: self.bcc.clone(),
128 })
129 }
130
131 /// Deconstruct the Artifacts into a tuple.
132 /// (CDI_ATTEST, CDI_SEAL, BCC)
133 pub fn into_tuple(self) -> (ZVec, ZVec, Vec<u8>) {
134 let ResidentArtifacts { cdi_attest, cdi_seal, bcc } = self;
135 (cdi_attest, cdi_seal, bcc)
136 }
137
Alice Wangb68814b2023-02-02 13:15:32 +0000138 fn execute_step(self, input_values: &BinderInputValues) -> Result<Self> {
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700139 let ResidentArtifacts { cdi_attest, cdi_seal, bcc } = self;
140
Alice Wangf4bd1c62023-02-08 08:38:44 +0000141 dice::retry_bcc_main_flow(
142 cdi_attest[..].try_into().with_context(|| {
143 format!("Trying to convert cdi_attest. (length: {})", cdi_attest.len())
144 })?,
145 cdi_seal[..].try_into().with_context(|| {
146 format!("Trying to convert cdi_seal. (length: {})", cdi_seal.len())
147 })?,
148 &bcc,
149 &to_dice_input_values(input_values),
150 )
151 .context("In ResidentArtifacts::execute_step:")?
152 .try_into()
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700153 }
154
155 /// Iterate through the iterator of dice input values performing one
156 /// BCC main flow step on each element.
Alice Wangb68814b2023-02-02 13:15:32 +0000157 pub fn execute_steps<'a, I>(self, input_values: I) -> Result<Self>
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700158 where
Alice Wangb68814b2023-02-02 13:15:32 +0000159 I: IntoIterator<Item = &'a BinderInputValues>,
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700160 {
161 input_values
162 .into_iter()
Alice Wangb68814b2023-02-02 13:15:32 +0000163 .try_fold(self, |acc, input| acc.execute_step(input))
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700164 .context("In ResidentArtifacts::execute_step:")
165 }
166}
167
Janis Danisevskisaaba4af2021-11-18 14:25:07 -0800168/// Implement this trait to provide read and write access to a secure artifact
169/// storage that can be used by the ResidentHal implementation.
170pub trait UpdatableDiceArtifacts {
171 /// With artifacts provides access to the stored artifacts for the duration
172 /// of the function call by means of calling the callback.
173 fn with_artifacts<F, T>(&self, f: F) -> Result<T>
174 where
175 F: FnOnce(&dyn DiceArtifacts) -> Result<T>;
176
177 /// Consumes the object and returns a an updated version of itself.
178 fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self>
179 where
180 Self: Sized;
181}
182
183impl DiceArtifacts for ResidentArtifacts {
184 fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
185 self.cdi_attest[..].try_into().unwrap()
186 }
187 fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] {
188 self.cdi_seal[..].try_into().unwrap()
189 }
Alice Wang4d3059a2023-02-15 10:24:33 +0000190 fn bcc(&self) -> Option<&[u8]> {
191 Some(&self.bcc)
Janis Danisevskisaaba4af2021-11-18 14:25:07 -0800192 }
193}
194
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700195/// This submodule implements a limited set of CBOR generation functionality. Essentially,
196/// a cbor header generator and some convenience functions for number and BSTR encoding.
197pub mod cbor {
198 use anyhow::{anyhow, Context, Result};
199 use std::convert::TryInto;
200 use std::io::Write;
201
202 /// CBOR encodes a positive number.
203 pub fn encode_number(n: u64, buffer: &mut dyn Write) -> Result<()> {
204 encode_header(0, n, buffer)
205 }
206
207 /// CBOR encodes a binary string.
208 pub fn encode_bstr(bstr: &[u8], buffer: &mut dyn Write) -> Result<()> {
209 encode_header(
210 2,
211 bstr.len().try_into().context("In encode_bstr: Failed to convert usize to u64.")?,
212 buffer,
213 )
214 .context("In encode_bstr: While writing header.")?;
215 let written = buffer.write(bstr).context("In encode_bstr: While writing payload.")?;
216 if written != bstr.len() {
217 return Err(anyhow!("In encode_bstr: Buffer too small. ({}, {})", written, bstr.len()));
218 }
219 Ok(())
220 }
221
222 /// Formats a CBOR header. `t` is the type, and n is the header argument.
223 pub fn encode_header(t: u8, n: u64, buffer: &mut dyn Write) -> Result<()> {
224 match n {
225 n if n < 24 => {
Charisee03e00842023-01-25 01:41:23 +0000226 let written =
227 buffer.write(&u8::to_be_bytes((t << 5) | (n as u8 & 0x1F))).with_context(
228 || format!("In encode_header: Failed to write header ({}, {})", t, n),
229 )?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700230 if written != 1 {
231 return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
232 }
233 }
234 n if n <= 0xFF => {
235 let written =
Charisee03e00842023-01-25 01:41:23 +0000236 buffer.write(&u8::to_be_bytes((t << 5) | (24u8 & 0x1F))).with_context(
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700237 || format!("In encode_header: Failed to write header ({}, {})", t, n),
238 )?;
239 if written != 1 {
240 return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
241 }
242 let written = buffer.write(&u8::to_be_bytes(n as u8)).with_context(|| {
243 format!("In encode_header: Failed to write size ({}, {})", t, n)
244 })?;
245 if written != 1 {
246 return Err(anyhow!(
247 "In encode_header while writing size: Buffer to small. ({}, {})",
248 t,
249 n
250 ));
251 }
252 }
253 n if n <= 0xFFFF => {
254 let written =
Charisee03e00842023-01-25 01:41:23 +0000255 buffer.write(&u8::to_be_bytes((t << 5) | (25u8 & 0x1F))).with_context(
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700256 || format!("In encode_header: Failed to write header ({}, {})", t, n),
257 )?;
258 if written != 1 {
259 return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
260 }
261 let written = buffer.write(&u16::to_be_bytes(n as u16)).with_context(|| {
262 format!("In encode_header: Failed to write size ({}, {})", t, n)
263 })?;
264 if written != 2 {
265 return Err(anyhow!(
266 "In encode_header while writing size: Buffer to small. ({}, {})",
267 t,
268 n
269 ));
270 }
271 }
272 n if n <= 0xFFFFFFFF => {
273 let written =
Charisee03e00842023-01-25 01:41:23 +0000274 buffer.write(&u8::to_be_bytes((t << 5) | (26u8 & 0x1F))).with_context(
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700275 || format!("In encode_header: Failed to write header ({}, {})", t, n),
276 )?;
277 if written != 1 {
278 return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
279 }
280 let written = buffer.write(&u32::to_be_bytes(n as u32)).with_context(|| {
281 format!("In encode_header: Failed to write size ({}, {})", t, n)
282 })?;
283 if written != 4 {
284 return Err(anyhow!(
285 "In encode_header while writing size: Buffer to small. ({}, {})",
286 t,
287 n
288 ));
289 }
290 }
291 n => {
292 let written =
Charisee03e00842023-01-25 01:41:23 +0000293 buffer.write(&u8::to_be_bytes((t << 5) | (27u8 & 0x1F))).with_context(
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700294 || format!("In encode_header: Failed to write header ({}, {})", t, n),
295 )?;
296 if written != 1 {
297 return Err(anyhow!("In encode_header: Buffer to small. ({}, {})", t, n));
298 }
Charisee03e00842023-01-25 01:41:23 +0000299 let written = buffer.write(&u64::to_be_bytes(n)).with_context(|| {
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700300 format!("In encode_header: Failed to write size ({}, {})", t, n)
301 })?;
302 if written != 8 {
303 return Err(anyhow!(
304 "In encode_header while writing size: Buffer to small. ({}, {})",
305 t,
306 n
307 ));
308 }
309 }
310 }
311 Ok(())
312 }
313
314 #[cfg(test)]
315 mod test {
316 use super::*;
317
318 fn encode_header_helper(t: u8, n: u64) -> Vec<u8> {
319 let mut b: Vec<u8> = vec![];
320 encode_header(t, n, &mut b).unwrap();
321 b
322 }
323
324 #[test]
325 fn encode_header_test() {
326 assert_eq!(&encode_header_helper(0, 0), &[0b000_00000]);
327 assert_eq!(&encode_header_helper(0, 23), &[0b000_10111]);
328 assert_eq!(&encode_header_helper(0, 24), &[0b000_11000, 24]);
329 assert_eq!(&encode_header_helper(0, 0xff), &[0b000_11000, 0xff]);
330 assert_eq!(&encode_header_helper(0, 0x100), &[0b000_11001, 0x01, 0x00]);
331 assert_eq!(&encode_header_helper(0, 0xffff), &[0b000_11001, 0xff, 0xff]);
332 assert_eq!(&encode_header_helper(0, 0x10000), &[0b000_11010, 0x00, 0x01, 0x00, 0x00]);
333 assert_eq!(
334 &encode_header_helper(0, 0xffffffff),
335 &[0b000_11010, 0xff, 0xff, 0xff, 0xff]
336 );
337 assert_eq!(
338 &encode_header_helper(0, 0x100000000),
339 &[0b000_11011, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]
340 );
341 assert_eq!(
342 &encode_header_helper(0, 0xffffffffffffffff),
343 &[0b000_11011, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
344 );
345 }
346 }
347}