• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
17 use crate::dice::{Cdi, CdiValues, DiceArtifacts, InputValues, CDI_SIZE};
18 use crate::error::{check_result, DiceError, Result};
19 use open_dice_bcc_bindgen::{
20     BccConfigValues, BccFormatConfigDescriptor, BccHandoverMainFlow, BccHandoverParse, BccMainFlow,
21     BCC_INPUT_COMPONENT_NAME, BCC_INPUT_COMPONENT_VERSION, BCC_INPUT_RESETTABLE,
22 };
23 use 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
bcc_format_config_descriptor( name: Option<&CStr>, version: Option<u64>, resettable: bool, buffer: &mut [u8], ) -> Result<usize>27 pub 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;
51     // SAFETY: The function writes to the buffer, within the given bounds, and only reads the
52     // input values. It writes its result to buffer_size.
53     check_result(unsafe {
54         BccFormatConfigDescriptor(&values, buffer.len(), buffer.as_mut_ptr(), &mut buffer_size)
55     })?;
56     Ok(buffer_size)
57 }
58 
59 /// Executes the main BCC flow.
60 ///
61 /// Given a full set of input values along with the current BCC and CDI values,
62 /// computes the next CDI values and matching updated BCC.
bcc_main_flow( current_cdi_attest: &Cdi, current_cdi_seal: &Cdi, current_bcc: &[u8], input_values: &InputValues, next_cdi_values: &mut CdiValues, next_bcc: &mut [u8], ) -> Result<usize>63 pub fn bcc_main_flow(
64     current_cdi_attest: &Cdi,
65     current_cdi_seal: &Cdi,
66     current_bcc: &[u8],
67     input_values: &InputValues,
68     next_cdi_values: &mut CdiValues,
69     next_bcc: &mut [u8],
70 ) -> Result<usize> {
71     let mut next_bcc_size = 0;
72     // SAFETY: `BccMainFlow` only reads the current `bcc` and CDI values and writes
73     // to `next_bcc` and next CDI values within its bounds. It also reads
74     // `input_values` as a constant input and doesn't store any pointer.
75     // The first argument can be null and is not used in the current implementation.
76     check_result(unsafe {
77         BccMainFlow(
78             ptr::null_mut(), // context
79             current_cdi_attest.as_ptr(),
80             current_cdi_seal.as_ptr(),
81             current_bcc.as_ptr(),
82             current_bcc.len(),
83             input_values.as_ptr(),
84             next_bcc.len(),
85             next_bcc.as_mut_ptr(),
86             &mut next_bcc_size,
87             next_cdi_values.cdi_attest.as_mut_ptr(),
88             next_cdi_values.cdi_seal.as_mut_ptr(),
89         )
90     })?;
91     Ok(next_bcc_size)
92 }
93 
94 /// Executes the main BCC handover flow.
95 ///
96 /// A BCC handover combines the BCC and CDIs in a single CBOR object.
97 /// This function takes the current boot stage's BCC handover bundle and produces a
98 /// bundle for the next stage.
bcc_handover_main_flow( current_bcc_handover: &[u8], input_values: &InputValues, next_bcc_handover: &mut [u8], ) -> Result<usize>99 pub fn bcc_handover_main_flow(
100     current_bcc_handover: &[u8],
101     input_values: &InputValues,
102     next_bcc_handover: &mut [u8],
103 ) -> Result<usize> {
104     let mut next_bcc_handover_size = 0;
105     // SAFETY - The function only reads `current_bcc_handover` and writes to `next_bcc_handover`
106     // within its bounds,
107     // It also reads `input_values` as a constant input and doesn't store any pointer.
108     // The first argument can be null and is not used in the current implementation.
109     check_result(unsafe {
110         BccHandoverMainFlow(
111             ptr::null_mut(), // context
112             current_bcc_handover.as_ptr(),
113             current_bcc_handover.len(),
114             input_values.as_ptr(),
115             next_bcc_handover.len(),
116             next_bcc_handover.as_mut_ptr(),
117             &mut next_bcc_handover_size,
118         )
119     })?;
120 
121     Ok(next_bcc_handover_size)
122 }
123 
124 /// A BCC handover combines the BCC and CDIs in a single CBOR object.
125 /// This struct is used as return of the function `bcc_handover_parse`, its lifetime is tied
126 /// to the lifetime of the raw BCC handover slice.
127 #[derive(Debug)]
128 pub struct BccHandover<'a> {
129     /// Attestation CDI.
130     cdi_attest: &'a [u8; CDI_SIZE],
131     /// Sealing CDI.
132     cdi_seal: &'a [u8; CDI_SIZE],
133     /// Boot Certificate Chain.
134     bcc: Option<&'a [u8]>,
135 }
136 
137 impl<'a> DiceArtifacts for BccHandover<'a> {
cdi_attest(&self) -> &[u8; CDI_SIZE]138     fn cdi_attest(&self) -> &[u8; CDI_SIZE] {
139         self.cdi_attest
140     }
141 
cdi_seal(&self) -> &[u8; CDI_SIZE]142     fn cdi_seal(&self) -> &[u8; CDI_SIZE] {
143         self.cdi_seal
144     }
145 
bcc(&self) -> Option<&[u8]>146     fn bcc(&self) -> Option<&[u8]> {
147         self.bcc
148     }
149 }
150 
151 /// A BCC handover combines the BCC and CDIs in a single CBOR object.
152 /// This function parses the `bcc_handover` to extracts the BCC and CDIs.
153 /// The lifetime of the returned `BccHandover` is tied to the given `bcc_handover` slice.
bcc_handover_parse(bcc_handover: &[u8]) -> Result<BccHandover>154 pub fn bcc_handover_parse(bcc_handover: &[u8]) -> Result<BccHandover> {
155     let mut cdi_attest: *const u8 = ptr::null();
156     let mut cdi_seal: *const u8 = ptr::null();
157     let mut bcc: *const u8 = ptr::null();
158     let mut bcc_size = 0;
159     // SAFETY: The `bcc_handover` is only read and never stored and the returned pointers should all
160     // point within the address range of the `bcc_handover` or be NULL.
161     check_result(unsafe {
162         BccHandoverParse(
163             bcc_handover.as_ptr(),
164             bcc_handover.len(),
165             &mut cdi_attest,
166             &mut cdi_seal,
167             &mut bcc,
168             &mut bcc_size,
169         )
170     })?;
171     let cdi_attest = sub_slice(bcc_handover, cdi_attest, CDI_SIZE)?;
172     let cdi_seal = sub_slice(bcc_handover, cdi_seal, CDI_SIZE)?;
173     let bcc = sub_slice(bcc_handover, bcc, bcc_size).ok();
174     Ok(BccHandover {
175         cdi_attest: cdi_attest.try_into().map_err(|_| DiceError::PlatformError)?,
176         cdi_seal: cdi_seal.try_into().map_err(|_| DiceError::PlatformError)?,
177         bcc,
178     })
179 }
180 
181 /// Gets a slice the `addr` points to and of length `len`.
182 /// The slice should be contained in the buffer.
sub_slice(buffer: &[u8], addr: *const u8, len: usize) -> Result<&[u8]>183 fn sub_slice(buffer: &[u8], addr: *const u8, len: usize) -> Result<&[u8]> {
184     if addr.is_null() || !buffer.as_ptr_range().contains(&addr) {
185         return Err(DiceError::PlatformError);
186     }
187     // SAFETY: This is safe because addr is not null and is within the range of the buffer.
188     let start: usize = unsafe {
189         addr.offset_from(buffer.as_ptr()).try_into().map_err(|_| DiceError::PlatformError)?
190     };
191     start.checked_add(len).and_then(|end| buffer.get(start..end)).ok_or(DiceError::PlatformError)
192 }
193