blob: bacefcd52423a5aa73fc95c9259ed4ea1f7127d3 [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
Alice Wang62f7e642023-02-10 09:55:13 +000035/// Derives a sealing key from the DICE sealing CDI.
36pub fn derive_sealing_key(
Alice Wang7e6c9352023-02-15 15:44:13 +000037 dice_artifacts: &dyn DiceArtifacts,
Alice Wang62f7e642023-02-10 09:55:13 +000038 salt: &[u8],
39 info: &[u8],
Alice Wang7e6c9352023-02-15 15:44:13 +000040 key: &mut [u8],
41) -> Result<()> {
42 Ok(hkdf(key, Md::sha256(), dice_artifacts.cdi_seal(), salt, info)?)
Shikha Panwar566c9672022-11-15 14:39:58 +000043}
44
Andrew Sculld64ae7d2022-10-05 17:41:43 +000045/// Artifacts that are mapped into the process address space from the driver.
46pub enum DiceDriver<'a> {
47 Real {
48 driver_path: PathBuf,
49 mmap_addr: *mut c_void,
50 mmap_size: usize,
Alice Wang6a22be92023-02-15 10:08:36 +000051 bcc_handover: BccHandover<'a>,
Andrew Sculld64ae7d2022-10-05 17:41:43 +000052 },
Alice Wang62f7e642023-02-10 09:55:13 +000053 Fake(OwnedDiceArtifacts),
Andrew Sculld64ae7d2022-10-05 17:41:43 +000054}
55
56impl DiceDriver<'_> {
Alice Wang7e6c9352023-02-15 15:44:13 +000057 fn dice_artifacts(&self) -> &dyn DiceArtifacts {
58 match self {
59 Self::Real { bcc_handover, .. } => bcc_handover,
60 Self::Fake(owned_dice_artifacts) => owned_dice_artifacts,
61 }
62 }
63
Andrew Sculld64ae7d2022-10-05 17:41:43 +000064 pub fn new(driver_path: &Path) -> Result<Self> {
65 if driver_path.exists() {
66 log::info!("Using DICE values from driver");
67 } else if super::is_strict_boot() {
68 bail!("Strict boot requires DICE value from driver but none were found");
69 } else {
70 log::warn!("Using sample DICE values");
Alice Wangf4b8b002023-02-08 08:53:23 +000071 let dice_artifacts = diced_sample_inputs::make_sample_bcc_and_cdis()
Andrew Sculld64ae7d2022-10-05 17:41:43 +000072 .expect("Failed to create sample dice artifacts.");
Alice Wang62f7e642023-02-10 09:55:13 +000073 return Ok(Self::Fake(dice_artifacts));
Andrew Sculld64ae7d2022-10-05 17:41:43 +000074 };
75
76 let mut file = fs::File::open(driver_path)
77 .map_err(|error| Error::new(error).context("Opening driver"))?;
78 let mmap_size =
79 file.read_u64::<NativeEndian>()
80 .map_err(|error| Error::new(error).context("Reading driver"))? as usize;
81 // It's safe to map the driver as the service will only create a single
82 // mapping per process.
83 let mmap_addr = unsafe {
84 let fd = file.as_raw_fd();
85 mmap(null_mut(), mmap_size, PROT_READ, MAP_PRIVATE, fd, 0)
86 };
87 if mmap_addr == MAP_FAILED {
88 bail!("Failed to mmap {:?}", driver_path);
89 }
90 // The slice is created for the region of memory that was just
91 // successfully mapped into the process address space so it will be
92 // accessible and not referenced from anywhere else.
93 let mmap_buf =
94 unsafe { slice::from_raw_parts((mmap_addr as *const u8).as_ref().unwrap(), mmap_size) };
Alice Wang6a22be92023-02-15 10:08:36 +000095 let bcc_handover =
96 bcc_handover_parse(mmap_buf).map_err(|_| anyhow!("Failed to parse Bcc Handover"))?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +000097 Ok(Self::Real {
98 driver_path: driver_path.to_path_buf(),
99 mmap_addr,
100 mmap_size,
Alice Wang6a22be92023-02-15 10:08:36 +0000101 bcc_handover,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000102 })
103 }
104
Alice Wang7e6c9352023-02-15 15:44:13 +0000105 /// Derives a sealing key of `key_length` bytes from the DICE sealing CDI.
106 pub fn get_sealing_key(&self, identifier: &[u8], key_length: usize) -> Result<ZVec> {
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000107 // Deterministically derive a key to use for sealing data, rather than using the CDI
108 // directly, so we have the chance to rotate the key if needed. A salt isn't needed as the
109 // input key material is already cryptographically strong.
Alice Wang7e6c9352023-02-15 15:44:13 +0000110 let mut key = ZVec::new(key_length)?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000111 let salt = &[];
Alice Wang7e6c9352023-02-15 15:44:13 +0000112 derive_sealing_key(self.dice_artifacts(), salt, identifier, &mut key)?;
113 Ok(key)
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000114 }
115
116 pub fn derive(
117 self,
Alice Wang5aeed332023-02-02 09:42:21 +0000118 code_hash: Hash,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000119 config_desc: &[u8],
Alice Wang5aeed332023-02-02 09:42:21 +0000120 authority_hash: Hash,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000121 debug: bool,
Alice Wang5aeed332023-02-02 09:42:21 +0000122 hidden: Hidden,
Alice Wang62f7e642023-02-10 09:55:13 +0000123 ) -> Result<OwnedDiceArtifacts> {
Alice Wanga7773662023-02-03 09:37:17 +0000124 let input_values = InputValues::new(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000125 code_hash,
126 Config::Descriptor(config_desc),
127 authority_hash,
Alice Wang31226132023-01-31 12:44:39 +0000128 if debug { DiceMode::kDiceModeDebug } else { DiceMode::kDiceModeNormal },
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000129 hidden,
130 );
Alice Wang7e6c9352023-02-15 15:44:13 +0000131 let current_dice_artifacts = self.dice_artifacts();
132 let next_dice_artifacts = retry_bcc_main_flow(
133 current_dice_artifacts.cdi_attest(),
134 current_dice_artifacts.cdi_seal(),
135 current_dice_artifacts.bcc().ok_or_else(|| anyhow!("bcc is none"))?,
136 &input_values,
137 )
138 .context("DICE derive from driver")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000139 if let Self::Real { driver_path, .. } = &self {
140 // Writing to the device wipes the artifacts. The string is ignored by the driver but
141 // included for documentation.
142 fs::write(driver_path, "wipe")
143 .map_err(|err| Error::new(err).context("Wiping driver"))?;
144 }
Alice Wang7e6c9352023-02-15 15:44:13 +0000145 Ok(next_dice_artifacts)
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000146 }
147}
148
149impl Drop for DiceDriver<'_> {
150 fn drop(&mut self) {
151 if let &mut Self::Real { mmap_addr, mmap_size, .. } = self {
152 // All references to the mapped region have the same lifetime as self. Since self is
153 // being dropped, so are all the references to the mapped region meaning its safe to
154 // unmap.
155 let ret = unsafe { munmap(mmap_addr, mmap_size) };
156 if ret != 0 {
157 log::warn!("Failed to munmap ({})", ret);
158 }
159 }
160 }
161}
Alice Wang285a3d22023-03-01 11:36:29 +0000162
163/// Returns a configuration descriptor of the given payload following the BCC's specification:
164/// https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
165/// {
166/// -70002: "Microdroid payload",
167/// ? -71000: tstr // payload_config_path
168/// ? -71001: PayloadConfig
169/// }
170/// PayloadConfig = {
171/// 1: tstr // payload_binary_name
172/// }
Ludovic Barman93ee3082023-06-20 12:18:43 +0000173pub fn format_payload_config_descriptor(payload: &PayloadMetadata) -> Result<Vec<u8>> {
Alice Wanga04890b2023-03-01 11:45:09 +0000174 const MICRODROID_PAYLOAD_COMPONENT_NAME: &str = "Microdroid payload";
Alice Wang285a3d22023-03-01 11:36:29 +0000175
Ludovic Barman93ee3082023-06-20 12:18:43 +0000176 let config_descriptor_cbor_value = match payload {
177 PayloadMetadata::ConfigPath(payload_config_path) => cbor!({
Alice Wanga04890b2023-03-01 11:45:09 +0000178 -70002 => MICRODROID_PAYLOAD_COMPONENT_NAME,
179 -71000 => payload_config_path
180 }),
Ludovic Barman93ee3082023-06-20 12:18:43 +0000181 PayloadMetadata::Config(payload_config) => cbor!({
Alice Wanga04890b2023-03-01 11:45:09 +0000182 -70002 => MICRODROID_PAYLOAD_COMPONENT_NAME,
183 -71001 => {1 => payload_config.payload_binary_name}
184 }),
Ludovic Barman93ee3082023-06-20 12:18:43 +0000185 _ => bail!("Failed to match the payload against a config type: {:?}", payload),
Alice Wang285a3d22023-03-01 11:36:29 +0000186 }
Alice Wanga04890b2023-03-01 11:45:09 +0000187 .context("Failed to build a CBOR Value from payload metadata")?;
188 let mut config_descriptor = Vec::new();
Ludovic Barman93ee3082023-06-20 12:18:43 +0000189
Alice Wanga04890b2023-03-01 11:45:09 +0000190 ser::into_writer(&config_descriptor_cbor_value, &mut config_descriptor)?;
Alice Wang285a3d22023-03-01 11:36:29 +0000191 Ok(config_descriptor)
192}
193
Alice Wang285a3d22023-03-01 11:36:29 +0000194#[cfg(test)]
195mod tests {
196 use super::*;
197 use microdroid_metadata::PayloadConfig;
198
199 #[test]
200 fn payload_metadata_with_path_formats_correctly() -> Result<()> {
Ludovic Barman93ee3082023-06-20 12:18:43 +0000201 let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
Alice Wang285a3d22023-03-01 11:36:29 +0000202 let config_descriptor = format_payload_config_descriptor(&payload_metadata)?;
203 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
204 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
205 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
206 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
207 0x68,
208 ];
209 assert_eq!(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
210 Ok(())
211 }
212
213 #[test]
214 fn payload_metadata_with_config_formats_correctly() -> Result<()> {
215 let payload_config = PayloadConfig {
216 payload_binary_name: "payload_binary".to_string(),
217 ..Default::default()
218 };
Ludovic Barman93ee3082023-06-20 12:18:43 +0000219 let payload_metadata = PayloadMetadata::Config(payload_config);
Alice Wang285a3d22023-03-01 11:36:29 +0000220 let config_descriptor = format_payload_config_descriptor(&payload_metadata)?;
221 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
222 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
223 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
224 0x15, 0x58, 0xa1, 0x01, 0x6e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62,
225 0x69, 0x6e, 0x61, 0x72, 0x79,
226 ];
227 assert_eq!(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
228 Ok(())
229 }
230}