blob: 9a2648fd5317439aae01e1f25b0aab83374b4619 [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
17use anyhow::{bail, Context, Error, Result};
18use byteorder::{NativeEndian, ReadBytesExt};
Alice Wangf4b8b002023-02-08 08:53:23 +000019use diced_open_dice::{
Alice Wang62f7e642023-02-10 09:55:13 +000020 retry_bcc_main_flow, Cdi, Config, DiceMode, Hash, Hidden, InputValues, OwnedDiceArtifacts,
Andrew Sculld64ae7d2022-10-05 17:41:43 +000021};
22use keystore2_crypto::ZVec;
23use libc::{c_void, mmap, munmap, MAP_FAILED, MAP_PRIVATE, PROT_READ};
24use openssl::hkdf::hkdf;
25use openssl::md::Md;
26use std::fs;
27use std::os::unix::io::AsRawFd;
28use std::path::{Path, PathBuf};
29use std::ptr::null_mut;
30use std::slice;
31
Alice Wang62f7e642023-02-10 09:55:13 +000032/// Derives a sealing key from the DICE sealing CDI.
33pub fn derive_sealing_key(
34 cdi_seal: &Cdi,
35 salt: &[u8],
36 info: &[u8],
37 keysize: usize,
38) -> Result<ZVec> {
39 let mut key = ZVec::new(keysize)?;
40 hkdf(&mut key, Md::sha256(), cdi_seal, salt, info)?;
41 Ok(key)
Shikha Panwar566c9672022-11-15 14:39:58 +000042}
43
Andrew Sculld64ae7d2022-10-05 17:41:43 +000044/// Artifacts that are mapped into the process address space from the driver.
45pub enum DiceDriver<'a> {
46 Real {
47 driver_path: PathBuf,
48 mmap_addr: *mut c_void,
49 mmap_size: usize,
Alice Wang62f7e642023-02-10 09:55:13 +000050 cdi_attest: &'a Cdi,
51 cdi_seal: &'a Cdi,
Andrew Sculld64ae7d2022-10-05 17:41:43 +000052 bcc: &'a [u8],
53 },
Alice Wang62f7e642023-02-10 09:55:13 +000054 Fake(OwnedDiceArtifacts),
Andrew Sculld64ae7d2022-10-05 17:41:43 +000055}
56
57impl DiceDriver<'_> {
58 pub fn new(driver_path: &Path) -> Result<Self> {
59 if driver_path.exists() {
60 log::info!("Using DICE values from driver");
61 } else if super::is_strict_boot() {
62 bail!("Strict boot requires DICE value from driver but none were found");
63 } else {
64 log::warn!("Using sample DICE values");
Alice Wangf4b8b002023-02-08 08:53:23 +000065 let dice_artifacts = diced_sample_inputs::make_sample_bcc_and_cdis()
Andrew Sculld64ae7d2022-10-05 17:41:43 +000066 .expect("Failed to create sample dice artifacts.");
Alice Wang62f7e642023-02-10 09:55:13 +000067 return Ok(Self::Fake(dice_artifacts));
Andrew Sculld64ae7d2022-10-05 17:41:43 +000068 };
69
70 let mut file = fs::File::open(driver_path)
71 .map_err(|error| Error::new(error).context("Opening driver"))?;
72 let mmap_size =
73 file.read_u64::<NativeEndian>()
74 .map_err(|error| Error::new(error).context("Reading driver"))? as usize;
75 // It's safe to map the driver as the service will only create a single
76 // mapping per process.
77 let mmap_addr = unsafe {
78 let fd = file.as_raw_fd();
79 mmap(null_mut(), mmap_size, PROT_READ, MAP_PRIVATE, fd, 0)
80 };
81 if mmap_addr == MAP_FAILED {
82 bail!("Failed to mmap {:?}", driver_path);
83 }
84 // The slice is created for the region of memory that was just
85 // successfully mapped into the process address space so it will be
86 // accessible and not referenced from anywhere else.
87 let mmap_buf =
88 unsafe { slice::from_raw_parts((mmap_addr as *const u8).as_ref().unwrap(), mmap_size) };
89 // Very inflexible parsing / validation of the BccHandover data. Assumes deterministically
90 // encoded CBOR.
91 //
92 // BccHandover = {
93 // 1 : bstr .size 32, ; CDI_Attest
94 // 2 : bstr .size 32, ; CDI_Seal
95 // 3 : Bcc, ; Certificate chain
96 // }
97 if mmap_buf[0..4] != [0xa3, 0x01, 0x58, 0x20]
98 || mmap_buf[36..39] != [0x02, 0x58, 0x20]
99 || mmap_buf[71] != 0x03
100 {
101 bail!("BccHandover format mismatch");
102 }
103 Ok(Self::Real {
104 driver_path: driver_path.to_path_buf(),
105 mmap_addr,
106 mmap_size,
107 cdi_attest: mmap_buf[4..36].try_into().unwrap(),
108 cdi_seal: mmap_buf[39..71].try_into().unwrap(),
109 bcc: &mmap_buf[72..],
110 })
111 }
112
113 pub fn get_sealing_key(&self, identifier: &[u8]) -> Result<ZVec> {
114 // Deterministically derive a key to use for sealing data, rather than using the CDI
115 // directly, so we have the chance to rotate the key if needed. A salt isn't needed as the
116 // input key material is already cryptographically strong.
117 let cdi_seal = match self {
118 Self::Real { cdi_seal, .. } => cdi_seal,
Alice Wang62f7e642023-02-10 09:55:13 +0000119 Self::Fake(fake) => &fake.cdi_values.cdi_seal,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000120 };
121 let salt = &[];
Alice Wang62f7e642023-02-10 09:55:13 +0000122 derive_sealing_key(cdi_seal, salt, identifier, 32)
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000123 }
124
125 pub fn derive(
126 self,
Alice Wang5aeed332023-02-02 09:42:21 +0000127 code_hash: Hash,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000128 config_desc: &[u8],
Alice Wang5aeed332023-02-02 09:42:21 +0000129 authority_hash: Hash,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000130 debug: bool,
Alice Wang5aeed332023-02-02 09:42:21 +0000131 hidden: Hidden,
Alice Wang62f7e642023-02-10 09:55:13 +0000132 ) -> Result<OwnedDiceArtifacts> {
Alice Wanga7773662023-02-03 09:37:17 +0000133 let input_values = InputValues::new(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000134 code_hash,
135 Config::Descriptor(config_desc),
136 authority_hash,
Alice Wang31226132023-01-31 12:44:39 +0000137 if debug { DiceMode::kDiceModeDebug } else { DiceMode::kDiceModeNormal },
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000138 hidden,
139 );
140 let (cdi_attest, cdi_seal, bcc) = match &self {
141 Self::Real { cdi_attest, cdi_seal, bcc, .. } => (*cdi_attest, *cdi_seal, *bcc),
Alice Wang62f7e642023-02-10 09:55:13 +0000142 Self::Fake(fake) => {
143 (&fake.cdi_values.cdi_attest, &fake.cdi_values.cdi_seal, fake.bcc.as_slice())
144 }
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000145 };
Alice Wangf4b8b002023-02-08 08:53:23 +0000146 let dice_artifacts = retry_bcc_main_flow(cdi_attest, cdi_seal, bcc, &input_values)
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000147 .context("DICE derive from driver")?;
148 if let Self::Real { driver_path, .. } = &self {
149 // Writing to the device wipes the artifacts. The string is ignored by the driver but
150 // included for documentation.
151 fs::write(driver_path, "wipe")
152 .map_err(|err| Error::new(err).context("Wiping driver"))?;
153 }
Alice Wang62f7e642023-02-10 09:55:13 +0000154 Ok(dice_artifacts)
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000155 }
156}
157
158impl Drop for DiceDriver<'_> {
159 fn drop(&mut self) {
160 if let &mut Self::Real { mmap_addr, mmap_size, .. } = self {
161 // All references to the mapped region have the same lifetime as self. Since self is
162 // being dropped, so are all the references to the mapped region meaning its safe to
163 // unmap.
164 let ret = unsafe { munmap(mmap_addr, mmap_size) };
165 if ret != 0 {
166 log::warn!("Failed to munmap ({})", ret);
167 }
168 }
169 }
170}