blob: 229f3e02ca78d6206374ec9d1203c16729e86003 [file] [log] [blame]
Alan Stokes1125e012023-10-13 12:31:10 +01001// 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
17use anyhow::{anyhow, bail, Context, Error, Result};
18use byteorder::{NativeEndian, ReadBytesExt};
19use diced_open_dice::{
20 bcc_handover_parse, retry_bcc_main_flow, BccHandover, Config, DiceArtifacts, DiceMode, Hash,
21 Hidden, InputValues, OwnedDiceArtifacts,
22};
23use keystore2_crypto::ZVec;
24use libc::{c_void, mmap, munmap, MAP_FAILED, MAP_PRIVATE, PROT_READ};
25use openssl::hkdf::hkdf;
26use openssl::md::Md;
27use std::fs;
28use std::os::unix::io::AsRawFd;
29use std::path::{Path, PathBuf};
30use std::ptr::null_mut;
31use std::slice;
32
33/// Artifacts that are mapped into the process address space from the driver.
34pub enum DiceDriver<'a> {
35 Real {
36 driver_path: PathBuf,
37 mmap_addr: *mut c_void,
38 mmap_size: usize,
39 bcc_handover: BccHandover<'a>,
40 },
41 Fake(OwnedDiceArtifacts),
42}
43
44impl DiceDriver<'_> {
45 fn dice_artifacts(&self) -> &dyn DiceArtifacts {
46 match self {
47 Self::Real { bcc_handover, .. } => bcc_handover,
48 Self::Fake(owned_dice_artifacts) => owned_dice_artifacts,
49 }
50 }
51
52 pub fn new(driver_path: &Path) -> Result<Self> {
53 if driver_path.exists() {
54 log::info!("Using DICE values from driver");
55 } else if super::is_strict_boot() {
56 bail!("Strict boot requires DICE value from driver but none were found");
57 } else {
58 log::warn!("Using sample DICE values");
59 let dice_artifacts = diced_sample_inputs::make_sample_bcc_and_cdis()
60 .expect("Failed to create sample dice artifacts.");
61 return Ok(Self::Fake(dice_artifacts));
62 };
63
64 let mut file = fs::File::open(driver_path)
65 .map_err(|error| Error::new(error).context("Opening driver"))?;
66 let mmap_size =
67 file.read_u64::<NativeEndian>()
68 .map_err(|error| Error::new(error).context("Reading driver"))? as usize;
69 // SAFETY: It's safe to map the driver as the service will only create a single
70 // mapping per process.
71 let mmap_addr = unsafe {
72 let fd = file.as_raw_fd();
73 mmap(null_mut(), mmap_size, PROT_READ, MAP_PRIVATE, fd, 0)
74 };
75 if mmap_addr == MAP_FAILED {
76 bail!("Failed to mmap {:?}", driver_path);
77 }
78 let mmap_buf =
79 // SAFETY: The slice is created for the region of memory that was just
80 // successfully mapped into the process address space so it will be
81 // accessible and not referenced from anywhere else.
82 unsafe { slice::from_raw_parts((mmap_addr as *const u8).as_ref().unwrap(), mmap_size) };
83 let bcc_handover =
84 bcc_handover_parse(mmap_buf).map_err(|_| anyhow!("Failed to parse Bcc Handover"))?;
85 Ok(Self::Real {
86 driver_path: driver_path.to_path_buf(),
87 mmap_addr,
88 mmap_size,
89 bcc_handover,
90 })
91 }
92
93 /// Derives a sealing key of `key_length` bytes from the DICE sealing CDI.
94 pub fn get_sealing_key(&self, identifier: &[u8], key_length: usize) -> Result<ZVec> {
95 // Deterministically derive a key to use for sealing data, rather than using the CDI
96 // directly, so we have the chance to rotate the key if needed. A salt isn't needed as the
97 // input key material is already cryptographically strong.
98 let mut key = ZVec::new(key_length)?;
99 let salt = &[];
100 hkdf(&mut key, Md::sha256(), self.dice_artifacts().cdi_seal(), salt, identifier)?;
101 Ok(key)
102 }
103
104 pub fn derive(
105 self,
106 code_hash: Hash,
107 config_desc: &[u8],
108 authority_hash: Hash,
109 debug: bool,
110 hidden: Hidden,
111 ) -> Result<OwnedDiceArtifacts> {
112 let input_values = InputValues::new(
113 code_hash,
114 Config::Descriptor(config_desc),
115 authority_hash,
116 if debug { DiceMode::kDiceModeDebug } else { DiceMode::kDiceModeNormal },
117 hidden,
118 );
119 let current_dice_artifacts = self.dice_artifacts();
120 let next_dice_artifacts = retry_bcc_main_flow(
121 current_dice_artifacts.cdi_attest(),
122 current_dice_artifacts.cdi_seal(),
123 current_dice_artifacts.bcc().ok_or_else(|| anyhow!("bcc is none"))?,
124 &input_values,
125 )
126 .context("DICE derive from driver")?;
127 if let Self::Real { driver_path, .. } = &self {
128 // Writing to the device wipes the artifacts. The string is ignored by the driver but
129 // included for documentation.
130 fs::write(driver_path, "wipe")
131 .map_err(|err| Error::new(err).context("Wiping driver"))?;
132 }
133 Ok(next_dice_artifacts)
134 }
135}
136
137impl Drop for DiceDriver<'_> {
138 fn drop(&mut self) {
139 if let &mut Self::Real { mmap_addr, mmap_size, .. } = self {
140 // SAFETY: All references to the mapped region have the same lifetime as self. Since
141 // self is being dropped, so are all the references to the mapped region meaning it's
142 // safe to unmap.
143 let ret = unsafe { munmap(mmap_addr, mmap_size) };
144 if ret != 0 {
145 log::warn!("Failed to munmap ({})", ret);
146 }
147 }
148 }
149}