blob: ec87ae2dc7412501f01968678978584f80ef4547 [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> {
Nikita Ioffee18cc132024-02-28 16:13:36 +000035 /// Real implementation
Alan Stokes1125e012023-10-13 12:31:10 +010036 Real {
Nikita Ioffee18cc132024-02-28 16:13:36 +000037 /// Path to the driver character device (e.g. /dev/open-dice0).
Alan Stokes1125e012023-10-13 12:31:10 +010038 driver_path: PathBuf,
Nikita Ioffee18cc132024-02-28 16:13:36 +000039 /// Address of the memory to mmap driver to.
Alan Stokes1125e012023-10-13 12:31:10 +010040 mmap_addr: *mut c_void,
Nikita Ioffee18cc132024-02-28 16:13:36 +000041 /// Size of the mmap.
Alan Stokes1125e012023-10-13 12:31:10 +010042 mmap_size: usize,
Nikita Ioffee18cc132024-02-28 16:13:36 +000043 /// BCC handover.
Alan Stokes1125e012023-10-13 12:31:10 +010044 bcc_handover: BccHandover<'a>,
45 },
Nikita Ioffee18cc132024-02-28 16:13:36 +000046 /// Fake implementation used in tests and non-protected VMs.
Alan Stokes1125e012023-10-13 12:31:10 +010047 Fake(OwnedDiceArtifacts),
48}
49
50impl DiceDriver<'_> {
51 fn dice_artifacts(&self) -> &dyn DiceArtifacts {
52 match self {
53 Self::Real { bcc_handover, .. } => bcc_handover,
54 Self::Fake(owned_dice_artifacts) => owned_dice_artifacts,
55 }
56 }
57
Nikita Ioffee18cc132024-02-28 16:13:36 +000058 /// Creates a new dice driver from the given driver_path.
59 pub fn new(driver_path: &Path, is_strict_boot: bool) -> Result<Self> {
Alan Stokes1125e012023-10-13 12:31:10 +010060 if driver_path.exists() {
61 log::info!("Using DICE values from driver");
Nikita Ioffee18cc132024-02-28 16:13:36 +000062 } else if is_strict_boot {
Alan Stokes1125e012023-10-13 12:31:10 +010063 bail!("Strict boot requires DICE value from driver but none were found");
64 } else {
65 log::warn!("Using sample DICE values");
66 let dice_artifacts = diced_sample_inputs::make_sample_bcc_and_cdis()
67 .expect("Failed to create sample dice artifacts.");
68 return Ok(Self::Fake(dice_artifacts));
69 };
70
71 let mut file = fs::File::open(driver_path)
72 .map_err(|error| Error::new(error).context("Opening driver"))?;
73 let mmap_size =
74 file.read_u64::<NativeEndian>()
75 .map_err(|error| Error::new(error).context("Reading driver"))? as usize;
76 // SAFETY: It's safe to map the driver as the service will only create a single
77 // mapping per process.
78 let mmap_addr = unsafe {
79 let fd = file.as_raw_fd();
80 mmap(null_mut(), mmap_size, PROT_READ, MAP_PRIVATE, fd, 0)
81 };
82 if mmap_addr == MAP_FAILED {
83 bail!("Failed to mmap {:?}", driver_path);
84 }
85 let mmap_buf =
86 // SAFETY: The slice is created for the region of memory that was just
87 // successfully mapped into the process address space so it will be
88 // accessible and not referenced from anywhere else.
89 unsafe { slice::from_raw_parts((mmap_addr as *const u8).as_ref().unwrap(), mmap_size) };
90 let bcc_handover =
91 bcc_handover_parse(mmap_buf).map_err(|_| anyhow!("Failed to parse Bcc Handover"))?;
92 Ok(Self::Real {
93 driver_path: driver_path.to_path_buf(),
94 mmap_addr,
95 mmap_size,
96 bcc_handover,
97 })
98 }
99
100 /// Derives a sealing key of `key_length` bytes from the DICE sealing CDI.
101 pub fn get_sealing_key(&self, identifier: &[u8], key_length: usize) -> Result<ZVec> {
102 // Deterministically derive a key to use for sealing data, rather than using the CDI
103 // directly, so we have the chance to rotate the key if needed. A salt isn't needed as the
104 // input key material is already cryptographically strong.
105 let mut key = ZVec::new(key_length)?;
106 let salt = &[];
107 hkdf(&mut key, Md::sha256(), self.dice_artifacts().cdi_seal(), salt, identifier)?;
108 Ok(key)
109 }
110
Nikita Ioffee18cc132024-02-28 16:13:36 +0000111 /// Derives a new dice chain.
Alan Stokes1125e012023-10-13 12:31:10 +0100112 pub fn derive(
113 self,
114 code_hash: Hash,
115 config_desc: &[u8],
116 authority_hash: Hash,
117 debug: bool,
118 hidden: Hidden,
119 ) -> Result<OwnedDiceArtifacts> {
120 let input_values = InputValues::new(
121 code_hash,
122 Config::Descriptor(config_desc),
123 authority_hash,
124 if debug { DiceMode::kDiceModeDebug } else { DiceMode::kDiceModeNormal },
125 hidden,
126 );
127 let current_dice_artifacts = self.dice_artifacts();
128 let next_dice_artifacts = retry_bcc_main_flow(
129 current_dice_artifacts.cdi_attest(),
130 current_dice_artifacts.cdi_seal(),
131 current_dice_artifacts.bcc().ok_or_else(|| anyhow!("bcc is none"))?,
132 &input_values,
133 )
134 .context("DICE derive from driver")?;
135 if let Self::Real { driver_path, .. } = &self {
136 // Writing to the device wipes the artifacts. The string is ignored by the driver but
137 // included for documentation.
138 fs::write(driver_path, "wipe")
139 .map_err(|err| Error::new(err).context("Wiping driver"))?;
140 }
141 Ok(next_dice_artifacts)
142 }
143}
144
145impl Drop for DiceDriver<'_> {
146 fn drop(&mut self) {
147 if let &mut Self::Real { mmap_addr, mmap_size, .. } = self {
148 // SAFETY: All references to the mapped region have the same lifetime as self. Since
149 // self is being dropped, so are all the references to the mapped region meaning it's
150 // safe to unmap.
151 let ret = unsafe { munmap(mmap_addr, mmap_size) };
152 if ret != 0 {
153 log::warn!("Failed to munmap ({})", ret);
154 }
155 }
156 }
157}