1 // 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
17 use anyhow::{anyhow, bail, Context, Error, Result};
18 use byteorder::{NativeEndian, ReadBytesExt};
19 use ciborium::{cbor, ser};
20 use diced_open_dice::{
21 bcc_handover_parse, retry_bcc_main_flow, BccHandover, Config, DiceArtifacts, DiceMode, Hash,
22 Hidden, InputValues, OwnedDiceArtifacts,
23 };
24 use keystore2_crypto::ZVec;
25 use libc::{c_void, mmap, munmap, MAP_FAILED, MAP_PRIVATE, PROT_READ};
26 use microdroid_metadata::PayloadMetadata;
27 use openssl::hkdf::hkdf;
28 use openssl::md::Md;
29 use std::fs;
30 use std::os::unix::io::AsRawFd;
31 use std::path::{Path, PathBuf};
32 use std::ptr::null_mut;
33 use std::slice;
34
35 /// Derives a sealing key from the DICE sealing CDI.
derive_sealing_key( dice_artifacts: &dyn DiceArtifacts, salt: &[u8], info: &[u8], key: &mut [u8], ) -> Result<()>36 pub fn derive_sealing_key(
37 dice_artifacts: &dyn DiceArtifacts,
38 salt: &[u8],
39 info: &[u8],
40 key: &mut [u8],
41 ) -> Result<()> {
42 Ok(hkdf(key, Md::sha256(), dice_artifacts.cdi_seal(), salt, info)?)
43 }
44
45 /// Artifacts that are mapped into the process address space from the driver.
46 pub enum DiceDriver<'a> {
47 Real {
48 driver_path: PathBuf,
49 mmap_addr: *mut c_void,
50 mmap_size: usize,
51 bcc_handover: BccHandover<'a>,
52 },
53 Fake(OwnedDiceArtifacts),
54 }
55
56 impl DiceDriver<'_> {
dice_artifacts(&self) -> &dyn DiceArtifacts57 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
new(driver_path: &Path) -> Result<Self>64 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");
71 let dice_artifacts = diced_sample_inputs::make_sample_bcc_and_cdis()
72 .expect("Failed to create sample dice artifacts.");
73 return Ok(Self::Fake(dice_artifacts));
74 };
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) };
95 let bcc_handover =
96 bcc_handover_parse(mmap_buf).map_err(|_| anyhow!("Failed to parse Bcc Handover"))?;
97 Ok(Self::Real {
98 driver_path: driver_path.to_path_buf(),
99 mmap_addr,
100 mmap_size,
101 bcc_handover,
102 })
103 }
104
105 /// Derives a sealing key of `key_length` bytes from the DICE sealing CDI.
get_sealing_key(&self, identifier: &[u8], key_length: usize) -> Result<ZVec>106 pub fn get_sealing_key(&self, identifier: &[u8], key_length: usize) -> Result<ZVec> {
107 // 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.
110 let mut key = ZVec::new(key_length)?;
111 let salt = &[];
112 derive_sealing_key(self.dice_artifacts(), salt, identifier, &mut key)?;
113 Ok(key)
114 }
115
derive( self, code_hash: Hash, config_desc: &[u8], authority_hash: Hash, debug: bool, hidden: Hidden, ) -> Result<OwnedDiceArtifacts>116 pub fn derive(
117 self,
118 code_hash: Hash,
119 config_desc: &[u8],
120 authority_hash: Hash,
121 debug: bool,
122 hidden: Hidden,
123 ) -> Result<OwnedDiceArtifacts> {
124 let input_values = InputValues::new(
125 code_hash,
126 Config::Descriptor(config_desc),
127 authority_hash,
128 if debug { DiceMode::kDiceModeDebug } else { DiceMode::kDiceModeNormal },
129 hidden,
130 );
131 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")?;
139 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 }
145 Ok(next_dice_artifacts)
146 }
147 }
148
149 impl Drop for DiceDriver<'_> {
drop(&mut self)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 }
162
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 /// }
format_payload_config_descriptor(payload_metadata: &PayloadMetadata) -> Result<Vec<u8>>173 pub fn format_payload_config_descriptor(payload_metadata: &PayloadMetadata) -> Result<Vec<u8>> {
174 const MICRODROID_PAYLOAD_COMPONENT_NAME: &str = "Microdroid payload";
175
176 let config_descriptor_cbor_value = match payload_metadata {
177 PayloadMetadata::config_path(payload_config_path) => cbor!({
178 -70002 => MICRODROID_PAYLOAD_COMPONENT_NAME,
179 -71000 => payload_config_path
180 }),
181 PayloadMetadata::config(payload_config) => cbor!({
182 -70002 => MICRODROID_PAYLOAD_COMPONENT_NAME,
183 -71001 => {1 => payload_config.payload_binary_name}
184 }),
185 }
186 .context("Failed to build a CBOR Value from payload metadata")?;
187 let mut config_descriptor = Vec::new();
188 ser::into_writer(&config_descriptor_cbor_value, &mut config_descriptor)?;
189 Ok(config_descriptor)
190 }
191
192 #[cfg(test)]
193 mod tests {
194 use super::*;
195 use microdroid_metadata::PayloadConfig;
196
197 #[test]
payload_metadata_with_path_formats_correctly() -> Result<()>198 fn payload_metadata_with_path_formats_correctly() -> Result<()> {
199 let payload_metadata = PayloadMetadata::config_path("/config_path".to_string());
200 let config_descriptor = format_payload_config_descriptor(&payload_metadata)?;
201 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
202 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
203 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
204 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
205 0x68,
206 ];
207 assert_eq!(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
208 Ok(())
209 }
210
211 #[test]
payload_metadata_with_config_formats_correctly() -> Result<()>212 fn payload_metadata_with_config_formats_correctly() -> Result<()> {
213 let payload_config = PayloadConfig {
214 payload_binary_name: "payload_binary".to_string(),
215 ..Default::default()
216 };
217 let payload_metadata = PayloadMetadata::config(payload_config);
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, 0x58, 0xa1, 0x01, 0x6e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62,
223 0x69, 0x6e, 0x61, 0x72, 0x79,
224 ];
225 assert_eq!(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
226 Ok(())
227 }
228 }
229