blob: 6dc0cc3f84819ef1babe7c22d604eb9eccaccdca [file] [log] [blame]
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +00001/*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! Wrapper around dice/android/bcc.h.
18
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000019use core::ffi::CStr;
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +000020use core::mem;
21use core::ptr;
22
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000023use open_dice_bcc_bindgen::BccConfigValues;
24use open_dice_bcc_bindgen::BccFormatConfigDescriptor;
25use open_dice_bcc_bindgen::BccHandoverMainFlow;
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +000026use open_dice_bcc_bindgen::BccHandoverParse;
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000027use open_dice_bcc_bindgen::DiceInputValues;
28use open_dice_bcc_bindgen::BCC_INPUT_COMPONENT_NAME;
29use open_dice_bcc_bindgen::BCC_INPUT_COMPONENT_VERSION;
30use open_dice_bcc_bindgen::BCC_INPUT_RESETTABLE;
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +000031
32use crate::check_call;
33use crate::Cdi;
34use crate::Error;
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000035use crate::InputValues;
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +000036use crate::Result;
37
38/// Boot Chain Certificate handover format combining the BCC and CDIs in a single CBOR object.
39#[derive(Clone, Debug)]
40pub struct Handover<'a> {
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000041 buffer: &'a [u8],
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +000042 /// Attestation CDI.
43 pub cdi_attest: &'a Cdi,
44 /// Sealing CDI.
45 pub cdi_seal: &'a Cdi,
46 /// Boot Chain Certificate (optional).
47 pub bcc: Option<&'a [u8]>,
48}
49
50impl<'a> Handover<'a> {
51 /// Validates and extracts the fields of a BCC handover buffer.
52 pub fn new(buffer: &'a [u8]) -> Result<Self> {
53 let mut cdi_attest: *const u8 = ptr::null();
54 let mut cdi_seal: *const u8 = ptr::null();
55 let mut bcc: *const u8 = ptr::null();
56 let mut bcc_size: usize = 0;
57
58 // SAFETY - The buffer is only read and never stored and the returned pointers should all
59 // point within the address range of the buffer or be NULL.
60 check_call(unsafe {
61 BccHandoverParse(
62 buffer.as_ptr(),
63 buffer.len(),
64 &mut cdi_attest as *mut *const u8,
65 &mut cdi_seal as *mut *const u8,
66 &mut bcc as *mut *const u8,
67 &mut bcc_size as *mut usize,
68 )
69 })?;
70
71 let cdi_attest = {
72 let i = index_from_ptr(buffer, cdi_attest).ok_or(Error::PlatformError)?;
73 let s = buffer.get(i..(i + mem::size_of::<Cdi>())).ok_or(Error::PlatformError)?;
74 s.try_into().map_err(|_| Error::PlatformError)?
75 };
76 let cdi_seal = {
77 let i = index_from_ptr(buffer, cdi_seal).ok_or(Error::PlatformError)?;
78 let s = buffer.get(i..(i + mem::size_of::<Cdi>())).ok_or(Error::PlatformError)?;
79 s.try_into().map_err(|_| Error::PlatformError)?
80 };
81 let bcc = if bcc.is_null() {
82 None
83 } else {
84 let i = index_from_ptr(buffer, bcc).ok_or(Error::PlatformError)?;
85 Some(buffer.get(i..(i + bcc_size)).ok_or(Error::PlatformError)?)
86 };
87
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000088 Ok(Self { buffer, cdi_attest, cdi_seal, bcc })
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +000089 }
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000090
91 /// Executes the main BCC handover flow.
92 pub fn main_flow(&self, input_values: &InputValues, buffer: &mut [u8]) -> Result<usize> {
93 let context = ptr::null_mut();
94 let mut size: usize = 0;
95 // SAFETY - The function only reads `self.buffer`, writes to `buffer` within its bounds,
96 // reads `input_values` as a constant input and doesn't store any pointer.
97 check_call(unsafe {
98 BccHandoverMainFlow(
99 context,
100 self.buffer.as_ptr(),
101 self.buffer.len(),
102 input_values as *const _ as *const DiceInputValues,
103 buffer.len(),
104 buffer.as_mut_ptr(),
105 &mut size as *mut usize,
106 )
107 })?;
108
109 Ok(size)
110 }
111}
112
113/// Formats a configuration descriptor following the BCC's specification.
114///
115/// ```
116/// BccConfigDescriptor = {
117/// ? -70002 : tstr, ; Component name
118/// ? -70003 : int, ; Component version
119/// ? -70004 : null, ; Resettable
120/// }
121/// ```
122pub fn format_config_descriptor(
123 buffer: &mut [u8],
124 name: Option<&CStr>,
125 version: Option<u64>,
126 resettable: bool,
127) -> Result<usize> {
128 let mut inputs = 0;
129
130 if name.is_some() {
131 inputs |= BCC_INPUT_COMPONENT_NAME;
132 }
133
134 if version.is_some() {
135 inputs |= BCC_INPUT_COMPONENT_VERSION;
136 }
137
138 if resettable {
139 inputs |= BCC_INPUT_RESETTABLE;
140 }
141
142 let values = BccConfigValues {
143 inputs,
144 component_name: name.map_or(ptr::null(), |p| p.as_ptr()),
145 component_version: version.unwrap_or(0),
146 };
147
148 let mut buffer_size = 0;
149
150 // SAFETY - The function writes to the buffer, within the given bounds, and only reads the
151 // input values. It writes its result to buffer_size.
152 check_call(unsafe {
153 BccFormatConfigDescriptor(
154 &values as *const _,
155 buffer.len(),
156 buffer.as_mut_ptr(),
157 &mut buffer_size as *mut _,
158 )
159 })?;
160
161 Ok(buffer_size)
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +0000162}
163
164fn index_from_ptr(slice: &[u8], pointer: *const u8) -> Option<usize> {
165 if slice.as_ptr_range().contains(&pointer) {
166 (pointer as usize).checked_sub(slice.as_ptr() as usize)
167 } else {
168 None
169 }
170}