blob: 88373d194c0ce913aec9f08d8969e52eee0205ce [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 Wangf4b8b002023-02-08 08:53:23 +000019use diced_open_dice::{
Alice Wang7e6c9352023-02-15 15:44:13 +000020 bcc_handover_parse, retry_bcc_main_flow, BccHandover, Config, DiceArtifacts, DiceMode, Hash,
21 Hidden, InputValues, OwnedDiceArtifacts,
Andrew Sculld64ae7d2022-10-05 17:41:43 +000022};
Alice Wang285a3d22023-03-01 11:36:29 +000023use diced_utils::cbor::{encode_header, encode_number};
Andrew Sculld64ae7d2022-10-05 17:41:43 +000024use 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;
Alice Wang285a3d22023-03-01 11:36:29 +000030use std::io::Write;
Andrew Sculld64ae7d2022-10-05 17:41:43 +000031use std::os::unix::io::AsRawFd;
32use std::path::{Path, PathBuf};
33use std::ptr::null_mut;
34use std::slice;
35
Alice Wang62f7e642023-02-10 09:55:13 +000036/// Derives a sealing key from the DICE sealing CDI.
37pub fn derive_sealing_key(
Alice Wang7e6c9352023-02-15 15:44:13 +000038 dice_artifacts: &dyn DiceArtifacts,
Alice Wang62f7e642023-02-10 09:55:13 +000039 salt: &[u8],
40 info: &[u8],
Alice Wang7e6c9352023-02-15 15:44:13 +000041 key: &mut [u8],
42) -> Result<()> {
43 Ok(hkdf(key, Md::sha256(), dice_artifacts.cdi_seal(), salt, info)?)
Shikha Panwar566c9672022-11-15 14:39:58 +000044}
45
Andrew Sculld64ae7d2022-10-05 17:41:43 +000046/// Artifacts that are mapped into the process address space from the driver.
47pub enum DiceDriver<'a> {
48 Real {
49 driver_path: PathBuf,
50 mmap_addr: *mut c_void,
51 mmap_size: usize,
Alice Wang6a22be92023-02-15 10:08:36 +000052 bcc_handover: BccHandover<'a>,
Andrew Sculld64ae7d2022-10-05 17:41:43 +000053 },
Alice Wang62f7e642023-02-10 09:55:13 +000054 Fake(OwnedDiceArtifacts),
Andrew Sculld64ae7d2022-10-05 17:41:43 +000055}
56
57impl DiceDriver<'_> {
Alice Wang7e6c9352023-02-15 15:44:13 +000058 fn dice_artifacts(&self) -> &dyn DiceArtifacts {
59 match self {
60 Self::Real { bcc_handover, .. } => bcc_handover,
61 Self::Fake(owned_dice_artifacts) => owned_dice_artifacts,
62 }
63 }
64
Andrew Sculld64ae7d2022-10-05 17:41:43 +000065 pub fn new(driver_path: &Path) -> Result<Self> {
66 if driver_path.exists() {
67 log::info!("Using DICE values from driver");
68 } else if super::is_strict_boot() {
69 bail!("Strict boot requires DICE value from driver but none were found");
70 } else {
71 log::warn!("Using sample DICE values");
Alice Wangf4b8b002023-02-08 08:53:23 +000072 let dice_artifacts = diced_sample_inputs::make_sample_bcc_and_cdis()
Andrew Sculld64ae7d2022-10-05 17:41:43 +000073 .expect("Failed to create sample dice artifacts.");
Alice Wang62f7e642023-02-10 09:55:13 +000074 return Ok(Self::Fake(dice_artifacts));
Andrew Sculld64ae7d2022-10-05 17:41:43 +000075 };
76
77 let mut file = fs::File::open(driver_path)
78 .map_err(|error| Error::new(error).context("Opening driver"))?;
79 let mmap_size =
80 file.read_u64::<NativeEndian>()
81 .map_err(|error| Error::new(error).context("Reading driver"))? as usize;
82 // It's safe to map the driver as the service will only create a single
83 // mapping per process.
84 let mmap_addr = unsafe {
85 let fd = file.as_raw_fd();
86 mmap(null_mut(), mmap_size, PROT_READ, MAP_PRIVATE, fd, 0)
87 };
88 if mmap_addr == MAP_FAILED {
89 bail!("Failed to mmap {:?}", driver_path);
90 }
91 // The slice is created for the region of memory that was just
92 // successfully mapped into the process address space so it will be
93 // accessible and not referenced from anywhere else.
94 let mmap_buf =
95 unsafe { slice::from_raw_parts((mmap_addr as *const u8).as_ref().unwrap(), mmap_size) };
Alice Wang6a22be92023-02-15 10:08:36 +000096 let bcc_handover =
97 bcc_handover_parse(mmap_buf).map_err(|_| anyhow!("Failed to parse Bcc Handover"))?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +000098 Ok(Self::Real {
99 driver_path: driver_path.to_path_buf(),
100 mmap_addr,
101 mmap_size,
Alice Wang6a22be92023-02-15 10:08:36 +0000102 bcc_handover,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000103 })
104 }
105
Alice Wang7e6c9352023-02-15 15:44:13 +0000106 /// Derives a sealing key of `key_length` bytes from the DICE sealing CDI.
107 pub fn get_sealing_key(&self, identifier: &[u8], key_length: usize) -> Result<ZVec> {
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000108 // Deterministically derive a key to use for sealing data, rather than using the CDI
109 // directly, so we have the chance to rotate the key if needed. A salt isn't needed as the
110 // input key material is already cryptographically strong.
Alice Wang7e6c9352023-02-15 15:44:13 +0000111 let mut key = ZVec::new(key_length)?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000112 let salt = &[];
Alice Wang7e6c9352023-02-15 15:44:13 +0000113 derive_sealing_key(self.dice_artifacts(), salt, identifier, &mut key)?;
114 Ok(key)
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000115 }
116
117 pub fn derive(
118 self,
Alice Wang5aeed332023-02-02 09:42:21 +0000119 code_hash: Hash,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000120 config_desc: &[u8],
Alice Wang5aeed332023-02-02 09:42:21 +0000121 authority_hash: Hash,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000122 debug: bool,
Alice Wang5aeed332023-02-02 09:42:21 +0000123 hidden: Hidden,
Alice Wang62f7e642023-02-10 09:55:13 +0000124 ) -> Result<OwnedDiceArtifacts> {
Alice Wanga7773662023-02-03 09:37:17 +0000125 let input_values = InputValues::new(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000126 code_hash,
127 Config::Descriptor(config_desc),
128 authority_hash,
Alice Wang31226132023-01-31 12:44:39 +0000129 if debug { DiceMode::kDiceModeDebug } else { DiceMode::kDiceModeNormal },
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000130 hidden,
131 );
Alice Wang7e6c9352023-02-15 15:44:13 +0000132 let current_dice_artifacts = self.dice_artifacts();
133 let next_dice_artifacts = retry_bcc_main_flow(
134 current_dice_artifacts.cdi_attest(),
135 current_dice_artifacts.cdi_seal(),
136 current_dice_artifacts.bcc().ok_or_else(|| anyhow!("bcc is none"))?,
137 &input_values,
138 )
139 .context("DICE derive from driver")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000140 if let Self::Real { driver_path, .. } = &self {
141 // Writing to the device wipes the artifacts. The string is ignored by the driver but
142 // included for documentation.
143 fs::write(driver_path, "wipe")
144 .map_err(|err| Error::new(err).context("Wiping driver"))?;
145 }
Alice Wang7e6c9352023-02-15 15:44:13 +0000146 Ok(next_dice_artifacts)
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000147 }
148}
149
150impl Drop for DiceDriver<'_> {
151 fn drop(&mut self) {
152 if let &mut Self::Real { mmap_addr, mmap_size, .. } = self {
153 // All references to the mapped region have the same lifetime as self. Since self is
154 // being dropped, so are all the references to the mapped region meaning its safe to
155 // unmap.
156 let ret = unsafe { munmap(mmap_addr, mmap_size) };
157 if ret != 0 {
158 log::warn!("Failed to munmap ({})", ret);
159 }
160 }
161 }
162}
Alice Wang285a3d22023-03-01 11:36:29 +0000163
164/// Returns a configuration descriptor of the given payload following the BCC's specification:
165/// https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
166/// {
167/// -70002: "Microdroid payload",
168/// ? -71000: tstr // payload_config_path
169/// ? -71001: PayloadConfig
170/// }
171/// PayloadConfig = {
172/// 1: tstr // payload_binary_name
173/// }
174pub fn format_payload_config_descriptor(payload_metadata: &PayloadMetadata) -> Result<Vec<u8>> {
175 let mut config_descriptor = vec![
176 0xa2, // map(2)
177 0x3a, 0x00, 0x01, 0x11, 0x71, // -70002
178 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79,
179 0x6c, 0x6f, 0x61, 0x64, // "Microdroid payload"
180 ];
181
182 match payload_metadata {
183 PayloadMetadata::config_path(payload_config_path) => {
184 encode_negative_number(-71000, &mut config_descriptor)?;
185 encode_tstr(payload_config_path, &mut config_descriptor)?;
186 }
187 PayloadMetadata::config(payload_config) => {
188 encode_negative_number(-71001, &mut config_descriptor)?;
189 encode_header(5, 1, &mut config_descriptor)?; // map(1)
190 encode_number(1, &mut config_descriptor)?;
191 encode_tstr(&payload_config.payload_binary_name, &mut config_descriptor)?;
192 }
193 }
194 Ok(config_descriptor)
195}
196
197fn encode_tstr(tstr: &str, buffer: &mut Vec<u8>) -> Result<()> {
198 let bytes = tstr.as_bytes();
199 encode_header(3, bytes.len().try_into().unwrap(), buffer)?;
200 buffer.extend_from_slice(bytes);
201 Ok(())
202}
203
204fn encode_negative_number(n: i64, buffer: &mut dyn Write) -> Result<()> {
205 anyhow::ensure!(n < 0);
206 let n = -1 - n;
207 encode_header(1, n.try_into().unwrap(), buffer)
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213 use microdroid_metadata::PayloadConfig;
214
215 #[test]
216 fn payload_metadata_with_path_formats_correctly() -> Result<()> {
217 let payload_metadata = PayloadMetadata::config_path("/config_path".to_string());
218 let config_descriptor = format_payload_config_descriptor(&payload_metadata)?;
219 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
220 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
221 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
222 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
223 0x68,
224 ];
225 assert_eq!(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
226 Ok(())
227 }
228
229 #[test]
230 fn payload_metadata_with_config_formats_correctly() -> Result<()> {
231 let payload_config = PayloadConfig {
232 payload_binary_name: "payload_binary".to_string(),
233 ..Default::default()
234 };
235 let payload_metadata = PayloadMetadata::config(payload_config);
236 let config_descriptor = format_payload_config_descriptor(&payload_metadata)?;
237 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
238 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
239 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
240 0x15, 0x58, 0xa1, 0x01, 0x6e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62,
241 0x69, 0x6e, 0x61, 0x72, 0x79,
242 ];
243 assert_eq!(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
244 Ok(())
245 }
246}