blob: 27905c9f63b8f8b9a7bebd064892fba43d415920 [file] [log] [blame]
Andrew Sculld64ae7d2022-10-05 17:41:43 +00001// Copyright 2022, 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//! Logic for handling the DICE values and boot operations.
16
Alice Wang6a22be92023-02-15 10:08:36 +000017use anyhow::{anyhow, bail, Context, Error, Result};
Andrew Sculld64ae7d2022-10-05 17:41:43 +000018use byteorder::{NativeEndian, ReadBytesExt};
Alice Wanga04890b2023-03-01 11:45:09 +000019use ciborium::{cbor, ser};
Alice Wangf4b8b002023-02-08 08:53:23 +000020use diced_open_dice::{
Alice Wang7e6c9352023-02-15 15:44:13 +000021 bcc_handover_parse, retry_bcc_main_flow, BccHandover, Config, DiceArtifacts, DiceMode, Hash,
22 Hidden, InputValues, OwnedDiceArtifacts,
Andrew Sculld64ae7d2022-10-05 17:41:43 +000023};
24use keystore2_crypto::ZVec;
25use libc::{c_void, mmap, munmap, MAP_FAILED, MAP_PRIVATE, PROT_READ};
Alice Wang285a3d22023-03-01 11:36:29 +000026use microdroid_metadata::PayloadMetadata;
Andrew Sculld64ae7d2022-10-05 17:41:43 +000027use openssl::hkdf::hkdf;
28use openssl::md::Md;
29use std::fs;
30use std::os::unix::io::AsRawFd;
31use std::path::{Path, PathBuf};
32use std::ptr::null_mut;
33use std::slice;
34
Andrew Sculld64ae7d2022-10-05 17:41:43 +000035/// Artifacts that are mapped into the process address space from the driver.
36pub enum DiceDriver<'a> {
37 Real {
38 driver_path: PathBuf,
39 mmap_addr: *mut c_void,
40 mmap_size: usize,
Alice Wang6a22be92023-02-15 10:08:36 +000041 bcc_handover: BccHandover<'a>,
Andrew Sculld64ae7d2022-10-05 17:41:43 +000042 },
Alice Wang62f7e642023-02-10 09:55:13 +000043 Fake(OwnedDiceArtifacts),
Andrew Sculld64ae7d2022-10-05 17:41:43 +000044}
45
46impl DiceDriver<'_> {
Alice Wang7e6c9352023-02-15 15:44:13 +000047 fn dice_artifacts(&self) -> &dyn DiceArtifacts {
48 match self {
49 Self::Real { bcc_handover, .. } => bcc_handover,
50 Self::Fake(owned_dice_artifacts) => owned_dice_artifacts,
51 }
52 }
53
Andrew Sculld64ae7d2022-10-05 17:41:43 +000054 pub fn new(driver_path: &Path) -> Result<Self> {
55 if driver_path.exists() {
56 log::info!("Using DICE values from driver");
57 } else if super::is_strict_boot() {
58 bail!("Strict boot requires DICE value from driver but none were found");
59 } else {
60 log::warn!("Using sample DICE values");
Alice Wangf4b8b002023-02-08 08:53:23 +000061 let dice_artifacts = diced_sample_inputs::make_sample_bcc_and_cdis()
Andrew Sculld64ae7d2022-10-05 17:41:43 +000062 .expect("Failed to create sample dice artifacts.");
Alice Wang62f7e642023-02-10 09:55:13 +000063 return Ok(Self::Fake(dice_artifacts));
Andrew Sculld64ae7d2022-10-05 17:41:43 +000064 };
65
66 let mut file = fs::File::open(driver_path)
67 .map_err(|error| Error::new(error).context("Opening driver"))?;
68 let mmap_size =
69 file.read_u64::<NativeEndian>()
70 .map_err(|error| Error::new(error).context("Reading driver"))? as usize;
Andrew Walbranae3350d2023-07-21 19:01:18 +010071 // SAFETY: It's safe to map the driver as the service will only create a single
Andrew Sculld64ae7d2022-10-05 17:41:43 +000072 // mapping per process.
73 let mmap_addr = unsafe {
74 let fd = file.as_raw_fd();
75 mmap(null_mut(), mmap_size, PROT_READ, MAP_PRIVATE, fd, 0)
76 };
77 if mmap_addr == MAP_FAILED {
78 bail!("Failed to mmap {:?}", driver_path);
79 }
Andrew Walbranae3350d2023-07-21 19:01:18 +010080 let mmap_buf =
81 // SAFETY: The slice is created for the region of memory that was just
Andrew Sculld64ae7d2022-10-05 17:41:43 +000082 // successfully mapped into the process address space so it will be
83 // accessible and not referenced from anywhere else.
Andrew Sculld64ae7d2022-10-05 17:41:43 +000084 unsafe { slice::from_raw_parts((mmap_addr as *const u8).as_ref().unwrap(), mmap_size) };
Alice Wang6a22be92023-02-15 10:08:36 +000085 let bcc_handover =
86 bcc_handover_parse(mmap_buf).map_err(|_| anyhow!("Failed to parse Bcc Handover"))?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +000087 Ok(Self::Real {
88 driver_path: driver_path.to_path_buf(),
89 mmap_addr,
90 mmap_size,
Alice Wang6a22be92023-02-15 10:08:36 +000091 bcc_handover,
Andrew Sculld64ae7d2022-10-05 17:41:43 +000092 })
93 }
94
Alice Wang7e6c9352023-02-15 15:44:13 +000095 /// Derives a sealing key of `key_length` bytes from the DICE sealing CDI.
96 pub fn get_sealing_key(&self, identifier: &[u8], key_length: usize) -> Result<ZVec> {
Andrew Sculld64ae7d2022-10-05 17:41:43 +000097 // Deterministically derive a key to use for sealing data, rather than using the CDI
98 // directly, so we have the chance to rotate the key if needed. A salt isn't needed as the
99 // input key material is already cryptographically strong.
Alice Wang7e6c9352023-02-15 15:44:13 +0000100 let mut key = ZVec::new(key_length)?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000101 let salt = &[];
Shikha Panwar95084df2023-07-22 11:47:45 +0000102 hkdf(&mut key, Md::sha256(), self.dice_artifacts().cdi_seal(), salt, identifier)?;
Alice Wang7e6c9352023-02-15 15:44:13 +0000103 Ok(key)
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000104 }
105
106 pub fn derive(
107 self,
Alice Wang5aeed332023-02-02 09:42:21 +0000108 code_hash: Hash,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000109 config_desc: &[u8],
Alice Wang5aeed332023-02-02 09:42:21 +0000110 authority_hash: Hash,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000111 debug: bool,
Alice Wang5aeed332023-02-02 09:42:21 +0000112 hidden: Hidden,
Alice Wang62f7e642023-02-10 09:55:13 +0000113 ) -> Result<OwnedDiceArtifacts> {
Alice Wanga7773662023-02-03 09:37:17 +0000114 let input_values = InputValues::new(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000115 code_hash,
116 Config::Descriptor(config_desc),
117 authority_hash,
Alice Wang31226132023-01-31 12:44:39 +0000118 if debug { DiceMode::kDiceModeDebug } else { DiceMode::kDiceModeNormal },
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000119 hidden,
120 );
Alice Wang7e6c9352023-02-15 15:44:13 +0000121 let current_dice_artifacts = self.dice_artifacts();
122 let next_dice_artifacts = retry_bcc_main_flow(
123 current_dice_artifacts.cdi_attest(),
124 current_dice_artifacts.cdi_seal(),
125 current_dice_artifacts.bcc().ok_or_else(|| anyhow!("bcc is none"))?,
126 &input_values,
127 )
128 .context("DICE derive from driver")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000129 if let Self::Real { driver_path, .. } = &self {
130 // Writing to the device wipes the artifacts. The string is ignored by the driver but
131 // included for documentation.
132 fs::write(driver_path, "wipe")
133 .map_err(|err| Error::new(err).context("Wiping driver"))?;
134 }
Alice Wang7e6c9352023-02-15 15:44:13 +0000135 Ok(next_dice_artifacts)
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000136 }
137}
138
139impl Drop for DiceDriver<'_> {
140 fn drop(&mut self) {
141 if let &mut Self::Real { mmap_addr, mmap_size, .. } = self {
Andrew Walbranae3350d2023-07-21 19:01:18 +0100142 // SAFETY: All references to the mapped region have the same lifetime as self. Since
143 // self is being dropped, so are all the references to the mapped region meaning it's
144 // safe to unmap.
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000145 let ret = unsafe { munmap(mmap_addr, mmap_size) };
146 if ret != 0 {
147 log::warn!("Failed to munmap ({})", ret);
148 }
149 }
150 }
151}
Alice Wang285a3d22023-03-01 11:36:29 +0000152
153/// Returns a configuration descriptor of the given payload following the BCC's specification:
154/// https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
155/// {
156/// -70002: "Microdroid payload",
Alan Stokes331a3a12023-08-04 11:31:51 +0100157/// ? -71000: tstr ; payload_config_path
Alice Wang285a3d22023-03-01 11:36:29 +0000158/// ? -71001: PayloadConfig
159/// }
160/// PayloadConfig = {
Alan Stokes331a3a12023-08-04 11:31:51 +0100161/// 1: tstr ; payload_binary_name
Alice Wang285a3d22023-03-01 11:36:29 +0000162/// }
Ludovic Barman93ee3082023-06-20 12:18:43 +0000163pub fn format_payload_config_descriptor(payload: &PayloadMetadata) -> Result<Vec<u8>> {
Alice Wanga04890b2023-03-01 11:45:09 +0000164 const MICRODROID_PAYLOAD_COMPONENT_NAME: &str = "Microdroid payload";
Alice Wang285a3d22023-03-01 11:36:29 +0000165
Ludovic Barman93ee3082023-06-20 12:18:43 +0000166 let config_descriptor_cbor_value = match payload {
167 PayloadMetadata::ConfigPath(payload_config_path) => cbor!({
Alice Wanga04890b2023-03-01 11:45:09 +0000168 -70002 => MICRODROID_PAYLOAD_COMPONENT_NAME,
169 -71000 => payload_config_path
170 }),
Ludovic Barman93ee3082023-06-20 12:18:43 +0000171 PayloadMetadata::Config(payload_config) => cbor!({
Alice Wanga04890b2023-03-01 11:45:09 +0000172 -70002 => MICRODROID_PAYLOAD_COMPONENT_NAME,
173 -71001 => {1 => payload_config.payload_binary_name}
174 }),
Ludovic Barman93ee3082023-06-20 12:18:43 +0000175 _ => bail!("Failed to match the payload against a config type: {:?}", payload),
Alice Wang285a3d22023-03-01 11:36:29 +0000176 }
Alice Wanga04890b2023-03-01 11:45:09 +0000177 .context("Failed to build a CBOR Value from payload metadata")?;
178 let mut config_descriptor = Vec::new();
Ludovic Barman93ee3082023-06-20 12:18:43 +0000179
Alice Wanga04890b2023-03-01 11:45:09 +0000180 ser::into_writer(&config_descriptor_cbor_value, &mut config_descriptor)?;
Alice Wang285a3d22023-03-01 11:36:29 +0000181 Ok(config_descriptor)
182}
183
Alice Wang285a3d22023-03-01 11:36:29 +0000184#[cfg(test)]
185mod tests {
186 use super::*;
187 use microdroid_metadata::PayloadConfig;
188
189 #[test]
190 fn payload_metadata_with_path_formats_correctly() -> Result<()> {
Ludovic Barman93ee3082023-06-20 12:18:43 +0000191 let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
Alice Wang285a3d22023-03-01 11:36:29 +0000192 let config_descriptor = format_payload_config_descriptor(&payload_metadata)?;
193 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
194 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
195 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
196 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
197 0x68,
198 ];
199 assert_eq!(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
200 Ok(())
201 }
202
203 #[test]
204 fn payload_metadata_with_config_formats_correctly() -> Result<()> {
205 let payload_config = PayloadConfig {
206 payload_binary_name: "payload_binary".to_string(),
207 ..Default::default()
208 };
Ludovic Barman93ee3082023-06-20 12:18:43 +0000209 let payload_metadata = PayloadMetadata::Config(payload_config);
Alice Wang285a3d22023-03-01 11:36:29 +0000210 let config_descriptor = format_payload_config_descriptor(&payload_metadata)?;
211 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
212 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
213 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
214 0x15, 0x58, 0xa1, 0x01, 0x6e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62,
215 0x69, 0x6e, 0x61, 0x72, 0x79,
216 ];
217 assert_eq!(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
218 Ok(())
219 }
220}