blob: ca2136f5bc9291d25268a98ef28a1837139b8a27 [file] [log] [blame]
Alice Wang9c40eca2023-02-03 13:10:24 +00001// Copyright 2023, 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//! This module mirrors the content in open-dice/include/dice/android/bcc.h
16
Alice Wang4d3059a2023-02-15 10:24:33 +000017use crate::dice::{Cdi, CdiValues, DiceArtifacts, InputValues, CDI_SIZE};
Alice Wang1a933a82023-02-14 11:02:51 +000018use crate::error::{check_result, DiceError, Result};
Alice Wang9c40eca2023-02-03 13:10:24 +000019use open_dice_bcc_bindgen::{
Alice Wang1a933a82023-02-14 11:02:51 +000020 BccConfigValues, BccFormatConfigDescriptor, BccHandoverMainFlow, BccHandoverParse, BccMainFlow,
Alice Wang9b2c38e2023-02-14 08:53:31 +000021 BCC_INPUT_COMPONENT_NAME, BCC_INPUT_COMPONENT_VERSION, BCC_INPUT_RESETTABLE,
Alice Wang9c40eca2023-02-03 13:10:24 +000022};
23use std::{ffi::CStr, ptr};
24
25/// Formats a configuration descriptor following the BCC's specification.
26/// See https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
27pub fn bcc_format_config_descriptor(
28 name: Option<&CStr>,
29 version: Option<u64>,
30 resettable: bool,
31 buffer: &mut [u8],
32) -> Result<usize> {
33 let mut inputs = 0;
34 if name.is_some() {
35 inputs |= BCC_INPUT_COMPONENT_NAME;
36 }
37 if version.is_some() {
38 inputs |= BCC_INPUT_COMPONENT_VERSION;
39 }
40 if resettable {
41 inputs |= BCC_INPUT_RESETTABLE;
42 }
43
44 let values = BccConfigValues {
45 inputs,
46 component_name: name.map_or(ptr::null(), |p| p.as_ptr()),
47 component_version: version.unwrap_or(0),
48 };
49
50 let mut buffer_size = 0;
Alice Wangef999242023-05-22 11:14:59 +000051 check_result(
Andrew Walbran7f30e542023-07-07 13:42:25 +010052 // SAFETY: The function writes to the buffer, within the given bounds, and only reads the
53 // input values. It writes its result to buffer_size.
Alice Wangef999242023-05-22 11:14:59 +000054 unsafe {
55 BccFormatConfigDescriptor(&values, buffer.len(), buffer.as_mut_ptr(), &mut buffer_size)
56 },
57 buffer_size,
58 )?;
Alice Wang9c40eca2023-02-03 13:10:24 +000059 Ok(buffer_size)
60}
Alice Wangf4bd1c62023-02-08 08:38:44 +000061
62/// Executes the main BCC flow.
63///
64/// Given a full set of input values along with the current BCC and CDI values,
65/// computes the next CDI values and matching updated BCC.
66pub fn bcc_main_flow(
67 current_cdi_attest: &Cdi,
68 current_cdi_seal: &Cdi,
69 current_bcc: &[u8],
70 input_values: &InputValues,
71 next_cdi_values: &mut CdiValues,
72 next_bcc: &mut [u8],
73) -> Result<usize> {
74 let mut next_bcc_size = 0;
Alice Wangef999242023-05-22 11:14:59 +000075 check_result(
Andrew Walbran7f30e542023-07-07 13:42:25 +010076 // SAFETY: `BccMainFlow` only reads the current `bcc` and CDI values and writes
77 // to `next_bcc` and next CDI values within its bounds. It also reads
78 // `input_values` as a constant input and doesn't store any pointer.
79 // The first argument can be null and is not used in the current implementation.
Alice Wangef999242023-05-22 11:14:59 +000080 unsafe {
81 BccMainFlow(
82 ptr::null_mut(), // context
83 current_cdi_attest.as_ptr(),
84 current_cdi_seal.as_ptr(),
85 current_bcc.as_ptr(),
86 current_bcc.len(),
87 input_values.as_ptr(),
88 next_bcc.len(),
89 next_bcc.as_mut_ptr(),
90 &mut next_bcc_size,
91 next_cdi_values.cdi_attest.as_mut_ptr(),
92 next_cdi_values.cdi_seal.as_mut_ptr(),
93 )
94 },
95 next_bcc_size,
96 )?;
Alice Wangf4bd1c62023-02-08 08:38:44 +000097 Ok(next_bcc_size)
98}
Alice Wang9b2c38e2023-02-14 08:53:31 +000099
100/// Executes the main BCC handover flow.
101///
102/// A BCC handover combines the BCC and CDIs in a single CBOR object.
103/// This function takes the current boot stage's BCC handover bundle and produces a
104/// bundle for the next stage.
105pub fn bcc_handover_main_flow(
106 current_bcc_handover: &[u8],
107 input_values: &InputValues,
108 next_bcc_handover: &mut [u8],
109) -> Result<usize> {
110 let mut next_bcc_handover_size = 0;
Alice Wangef999242023-05-22 11:14:59 +0000111 check_result(
Andrew Walbran7f30e542023-07-07 13:42:25 +0100112 // SAFETY: The function only reads `current_bcc_handover` and writes to `next_bcc_handover`
113 // within its bounds,
114 // It also reads `input_values` as a constant input and doesn't store any pointer.
115 // The first argument can be null and is not used in the current implementation.
Alice Wangef999242023-05-22 11:14:59 +0000116 unsafe {
117 BccHandoverMainFlow(
118 ptr::null_mut(), // context
119 current_bcc_handover.as_ptr(),
120 current_bcc_handover.len(),
121 input_values.as_ptr(),
122 next_bcc_handover.len(),
123 next_bcc_handover.as_mut_ptr(),
124 &mut next_bcc_handover_size,
125 )
126 },
127 next_bcc_handover_size,
128 )?;
Alice Wang9b2c38e2023-02-14 08:53:31 +0000129
130 Ok(next_bcc_handover_size)
131}
Alice Wang1a933a82023-02-14 11:02:51 +0000132
133/// A BCC handover combines the BCC and CDIs in a single CBOR object.
134/// This struct is used as return of the function `bcc_handover_parse`, its lifetime is tied
135/// to the lifetime of the raw BCC handover slice.
Alice Wangacee4fb2023-02-15 09:42:07 +0000136#[derive(Debug)]
Alice Wang1a933a82023-02-14 11:02:51 +0000137pub struct BccHandover<'a> {
138 /// Attestation CDI.
Alice Wang4d3059a2023-02-15 10:24:33 +0000139 cdi_attest: &'a [u8; CDI_SIZE],
Alice Wang1a933a82023-02-14 11:02:51 +0000140 /// Sealing CDI.
Alice Wang4d3059a2023-02-15 10:24:33 +0000141 cdi_seal: &'a [u8; CDI_SIZE],
Alice Wang1a933a82023-02-14 11:02:51 +0000142 /// Boot Certificate Chain.
Alice Wang4d3059a2023-02-15 10:24:33 +0000143 bcc: Option<&'a [u8]>,
144}
145
146impl<'a> DiceArtifacts for BccHandover<'a> {
147 fn cdi_attest(&self) -> &[u8; CDI_SIZE] {
148 self.cdi_attest
149 }
150
151 fn cdi_seal(&self) -> &[u8; CDI_SIZE] {
152 self.cdi_seal
153 }
154
155 fn bcc(&self) -> Option<&[u8]> {
156 self.bcc
157 }
Alice Wang1a933a82023-02-14 11:02:51 +0000158}
159
160/// A BCC handover combines the BCC and CDIs in a single CBOR object.
161/// This function parses the `bcc_handover` to extracts the BCC and CDIs.
162/// The lifetime of the returned `BccHandover` is tied to the given `bcc_handover` slice.
163pub fn bcc_handover_parse(bcc_handover: &[u8]) -> Result<BccHandover> {
164 let mut cdi_attest: *const u8 = ptr::null();
165 let mut cdi_seal: *const u8 = ptr::null();
166 let mut bcc: *const u8 = ptr::null();
167 let mut bcc_size = 0;
Alice Wangef999242023-05-22 11:14:59 +0000168 check_result(
Andrew Walbran7f30e542023-07-07 13:42:25 +0100169 // SAFETY: The `bcc_handover` is only read and never stored and the returned pointers should
170 // all point within the address range of the `bcc_handover` or be NULL.
Alice Wangef999242023-05-22 11:14:59 +0000171 unsafe {
172 BccHandoverParse(
173 bcc_handover.as_ptr(),
174 bcc_handover.len(),
175 &mut cdi_attest,
176 &mut cdi_seal,
177 &mut bcc,
178 &mut bcc_size,
179 )
180 },
181 bcc_size,
182 )?;
Alice Wang1a933a82023-02-14 11:02:51 +0000183 let cdi_attest = sub_slice(bcc_handover, cdi_attest, CDI_SIZE)?;
184 let cdi_seal = sub_slice(bcc_handover, cdi_seal, CDI_SIZE)?;
185 let bcc = sub_slice(bcc_handover, bcc, bcc_size).ok();
186 Ok(BccHandover {
187 cdi_attest: cdi_attest.try_into().map_err(|_| DiceError::PlatformError)?,
188 cdi_seal: cdi_seal.try_into().map_err(|_| DiceError::PlatformError)?,
189 bcc,
190 })
191}
192
193/// Gets a slice the `addr` points to and of length `len`.
194/// The slice should be contained in the buffer.
195fn sub_slice(buffer: &[u8], addr: *const u8, len: usize) -> Result<&[u8]> {
196 if addr.is_null() || !buffer.as_ptr_range().contains(&addr) {
197 return Err(DiceError::PlatformError);
198 }
199 // SAFETY: This is safe because addr is not null and is within the range of the buffer.
200 let start: usize = unsafe {
201 addr.offset_from(buffer.as_ptr()).try_into().map_err(|_| DiceError::PlatformError)?
202 };
Alice Wangacee4fb2023-02-15 09:42:07 +0000203 start.checked_add(len).and_then(|end| buffer.get(start..end)).ok_or(DiceError::PlatformError)
Alice Wang1a933a82023-02-14 11:02:51 +0000204}