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 | |
| 19 | use core::mem; |
| 20 | use core::ptr; |
| 21 | |
| 22 | use open_dice_bcc_bindgen::BccHandoverParse; |
| 23 | |
| 24 | use crate::check_call; |
| 25 | use crate::Cdi; |
| 26 | use crate::Error; |
| 27 | use crate::Result; |
| 28 | |
| 29 | /// Boot Chain Certificate handover format combining the BCC and CDIs in a single CBOR object. |
| 30 | #[derive(Clone, Debug)] |
| 31 | pub struct Handover<'a> { |
| 32 | /// Attestation CDI. |
| 33 | pub cdi_attest: &'a Cdi, |
| 34 | /// Sealing CDI. |
| 35 | pub cdi_seal: &'a Cdi, |
| 36 | /// Boot Chain Certificate (optional). |
| 37 | pub bcc: Option<&'a [u8]>, |
| 38 | } |
| 39 | |
| 40 | impl<'a> Handover<'a> { |
| 41 | /// Validates and extracts the fields of a BCC handover buffer. |
| 42 | pub fn new(buffer: &'a [u8]) -> Result<Self> { |
| 43 | let mut cdi_attest: *const u8 = ptr::null(); |
| 44 | let mut cdi_seal: *const u8 = ptr::null(); |
| 45 | let mut bcc: *const u8 = ptr::null(); |
| 46 | let mut bcc_size: usize = 0; |
| 47 | |
| 48 | // SAFETY - The buffer is only read and never stored and the returned pointers should all |
| 49 | // point within the address range of the buffer or be NULL. |
| 50 | check_call(unsafe { |
| 51 | BccHandoverParse( |
| 52 | buffer.as_ptr(), |
| 53 | buffer.len(), |
| 54 | &mut cdi_attest as *mut *const u8, |
| 55 | &mut cdi_seal as *mut *const u8, |
| 56 | &mut bcc as *mut *const u8, |
| 57 | &mut bcc_size as *mut usize, |
| 58 | ) |
| 59 | })?; |
| 60 | |
| 61 | let cdi_attest = { |
| 62 | let i = index_from_ptr(buffer, cdi_attest).ok_or(Error::PlatformError)?; |
| 63 | let s = buffer.get(i..(i + mem::size_of::<Cdi>())).ok_or(Error::PlatformError)?; |
| 64 | s.try_into().map_err(|_| Error::PlatformError)? |
| 65 | }; |
| 66 | let cdi_seal = { |
| 67 | let i = index_from_ptr(buffer, cdi_seal).ok_or(Error::PlatformError)?; |
| 68 | let s = buffer.get(i..(i + mem::size_of::<Cdi>())).ok_or(Error::PlatformError)?; |
| 69 | s.try_into().map_err(|_| Error::PlatformError)? |
| 70 | }; |
| 71 | let bcc = if bcc.is_null() { |
| 72 | None |
| 73 | } else { |
| 74 | let i = index_from_ptr(buffer, bcc).ok_or(Error::PlatformError)?; |
| 75 | Some(buffer.get(i..(i + bcc_size)).ok_or(Error::PlatformError)?) |
| 76 | }; |
| 77 | |
| 78 | Ok(Self { cdi_attest, cdi_seal, bcc }) |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | fn index_from_ptr(slice: &[u8], pointer: *const u8) -> Option<usize> { |
| 83 | if slice.as_ptr_range().contains(&pointer) { |
| 84 | (pointer as usize).checked_sub(slice.as_ptr() as usize) |
| 85 | } else { |
| 86 | None |
| 87 | } |
| 88 | } |