Pierre-Clément Tosi | 8edf72e | 2022-12-06 16:02:57 +0000 | [diff] [blame] | 1 | /* |
| 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 Tosi | 4f4f5eb | 2022-12-08 14:31:42 +0000 | [diff] [blame^] | 19 | use core::ffi::CStr; |
Pierre-Clément Tosi | 8edf72e | 2022-12-06 16:02:57 +0000 | [diff] [blame] | 20 | use core::mem; |
| 21 | use core::ptr; |
| 22 | |
Pierre-Clément Tosi | 4f4f5eb | 2022-12-08 14:31:42 +0000 | [diff] [blame^] | 23 | use open_dice_bcc_bindgen::BccConfigValues; |
| 24 | use open_dice_bcc_bindgen::BccFormatConfigDescriptor; |
| 25 | use open_dice_bcc_bindgen::BccHandoverMainFlow; |
Pierre-Clément Tosi | 8edf72e | 2022-12-06 16:02:57 +0000 | [diff] [blame] | 26 | use open_dice_bcc_bindgen::BccHandoverParse; |
Pierre-Clément Tosi | 4f4f5eb | 2022-12-08 14:31:42 +0000 | [diff] [blame^] | 27 | use open_dice_bcc_bindgen::DiceInputValues; |
| 28 | use open_dice_bcc_bindgen::BCC_INPUT_COMPONENT_NAME; |
| 29 | use open_dice_bcc_bindgen::BCC_INPUT_COMPONENT_VERSION; |
| 30 | use open_dice_bcc_bindgen::BCC_INPUT_RESETTABLE; |
Pierre-Clément Tosi | 8edf72e | 2022-12-06 16:02:57 +0000 | [diff] [blame] | 31 | |
| 32 | use crate::check_call; |
| 33 | use crate::Cdi; |
| 34 | use crate::Error; |
Pierre-Clément Tosi | 4f4f5eb | 2022-12-08 14:31:42 +0000 | [diff] [blame^] | 35 | use crate::InputValues; |
Pierre-Clément Tosi | 8edf72e | 2022-12-06 16:02:57 +0000 | [diff] [blame] | 36 | use crate::Result; |
| 37 | |
| 38 | /// Boot Chain Certificate handover format combining the BCC and CDIs in a single CBOR object. |
| 39 | #[derive(Clone, Debug)] |
| 40 | pub struct Handover<'a> { |
Pierre-Clément Tosi | 4f4f5eb | 2022-12-08 14:31:42 +0000 | [diff] [blame^] | 41 | buffer: &'a [u8], |
Pierre-Clément Tosi | 8edf72e | 2022-12-06 16:02:57 +0000 | [diff] [blame] | 42 | /// 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 | |
| 50 | impl<'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 Tosi | 4f4f5eb | 2022-12-08 14:31:42 +0000 | [diff] [blame^] | 88 | Ok(Self { buffer, cdi_attest, cdi_seal, bcc }) |
Pierre-Clément Tosi | 8edf72e | 2022-12-06 16:02:57 +0000 | [diff] [blame] | 89 | } |
Pierre-Clément Tosi | 4f4f5eb | 2022-12-08 14:31:42 +0000 | [diff] [blame^] | 90 | |
| 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 | /// ``` |
| 122 | pub 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 Tosi | 8edf72e | 2022-12-06 16:02:57 +0000 | [diff] [blame] | 162 | } |
| 163 | |
| 164 | fn 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 | } |