• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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