blob: 795221015f199ea07e6ddc2bd97d6e49bd132906 [file] [log] [blame]
Alan Stokes1125e012023-10-13 12:31:10 +01001// Copyright 2023 The Android Open Source Project
Andrew Sculld64ae7d2022-10-05 17:41:43 +00002//
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//
Alan Stokes1125e012023-10-13 12:31:10 +01007// http://www.apache.org/licenses/LICENSE-2.0
Andrew Sculld64ae7d2022-10-05 17:41:43 +00008//
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
Alan Stokes26a6a5c2023-11-10 16:18:43 +000015use crate::instance::{ApexData, ApkData};
Shikha Panwarf15e0272024-03-12 22:35:09 +000016use crate::{is_debuggable, is_strict_boot, MicrodroidData};
Alan Stokes1125e012023-10-13 12:31:10 +010017use anyhow::{bail, Context, Result};
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010018use ciborium::{cbor, Value};
19use coset::CborSerializable;
Nikita Ioffee18cc132024-02-28 16:13:36 +000020use dice_driver::DiceDriver;
Shikha Panwarf15e0272024-03-12 22:35:09 +000021use diced_open_dice::{Hidden, OwnedDiceArtifacts, HIDDEN_SIZE};
Alice Wang285a3d22023-03-01 11:36:29 +000022use microdroid_metadata::PayloadMetadata;
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010023use openssl::sha::{sha512, Sha512};
24use std::iter::once;
Andrew Sculld64ae7d2022-10-05 17:41:43 +000025
Alan Stokes1125e012023-10-13 12:31:10 +010026/// Perform an open DICE derivation for the payload.
27pub fn dice_derivation(
28 dice: DiceDriver,
Alan Stokes26a6a5c2023-11-10 16:18:43 +000029 instance_data: &MicrodroidData,
Alan Stokes1125e012023-10-13 12:31:10 +010030 payload_metadata: &PayloadMetadata,
31) -> Result<OwnedDiceArtifacts> {
Alan Stokes26a6a5c2023-11-10 16:18:43 +000032 let subcomponents = build_subcomponent_list(instance_data);
Alan Stokes1508df22023-12-04 11:31:21 +000033 let config_descriptor = format_payload_config_descriptor(payload_metadata, subcomponents)
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010034 .context("Building config descriptor")?;
35
Alan Stokes1125e012023-10-13 12:31:10 +010036 // Calculate compound digests of code and authorities
37 let mut code_hash_ctx = Sha512::new();
38 let mut authority_hash_ctx = Sha512::new();
Alan Stokes26a6a5c2023-11-10 16:18:43 +000039 code_hash_ctx.update(instance_data.apk_data.root_hash.as_ref());
Alan Stokes1508df22023-12-04 11:31:21 +000040 authority_hash_ctx.update(instance_data.apk_data.cert_hash.as_ref());
Alan Stokes26a6a5c2023-11-10 16:18:43 +000041 for extra_apk in &instance_data.extra_apks_data {
Alan Stokes1125e012023-10-13 12:31:10 +010042 code_hash_ctx.update(extra_apk.root_hash.as_ref());
Alan Stokes1508df22023-12-04 11:31:21 +000043 authority_hash_ctx.update(extra_apk.cert_hash.as_ref());
Alice Wang7e6c9352023-02-15 15:44:13 +000044 }
Alan Stokes26a6a5c2023-11-10 16:18:43 +000045 for apex in &instance_data.apex_data {
Alan Stokes1125e012023-10-13 12:31:10 +010046 code_hash_ctx.update(apex.root_digest.as_ref());
47 authority_hash_ctx.update(apex.public_key.as_ref());
Andrew Sculld64ae7d2022-10-05 17:41:43 +000048 }
Alan Stokes1125e012023-10-13 12:31:10 +010049 let code_hash = code_hash_ctx.finish();
50 let authority_hash = authority_hash_ctx.finish();
Andrew Sculld64ae7d2022-10-05 17:41:43 +000051
Alan Stokes1125e012023-10-13 12:31:10 +010052 // Check debuggability, conservatively assuming it is debuggable
53 let debuggable = is_debuggable()?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +000054
Alan Stokes1125e012023-10-13 12:31:10 +010055 // Send the details to diced
Shikha Panwarad0e5352024-12-11 17:36:43 +000056 let hidden = hidden_input_from_instance_id()?;
Alan Stokes1125e012023-10-13 12:31:10 +010057 dice.derive(code_hash, &config_descriptor, authority_hash, debuggable, hidden)
Andrew Sculld64ae7d2022-10-05 17:41:43 +000058}
Alice Wang285a3d22023-03-01 11:36:29 +000059
Shikha Panwarf15e0272024-03-12 22:35:09 +000060// Get the "Hidden input" for DICE derivation.
61// This provides differentiation of secrets for different VM instances with same payload.
62fn hidden_input_from_instance_id() -> Result<Hidden> {
63 // For protected VM: this is all 0s, pvmfw ensures differentiation is added early in secrets.
64 // For non-protected VM: this is derived from instance_id of the VM instance.
65 let hidden_input = if !is_strict_boot() {
66 if let Some(id) = super::get_instance_id()? {
67 sha512(&id)
68 } else {
69 // TODO(b/325094712): Absence of instance_id occurs due to missing DT in some
70 // x86_64 test devices (such as Cuttlefish). From security perspective, this is
71 // acceptable for non-protected VM.
72 log::warn!(
73 "Instance Id missing, this may lead to 2 non protected VMs having same secrets"
74 );
75 [0u8; HIDDEN_SIZE]
76 }
77 } else {
78 [0u8; HIDDEN_SIZE]
79 };
80 Ok(hidden_input)
81}
82
Alan Stokes1508df22023-12-04 11:31:21 +000083struct Subcomponent {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010084 name: String,
85 version: u64,
Alan Stokes1508df22023-12-04 11:31:21 +000086 code_hash: Vec<u8>,
87 authority_hash: Vec<u8>,
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010088}
Alice Wang285a3d22023-03-01 11:36:29 +000089
Alan Stokes1508df22023-12-04 11:31:21 +000090impl Subcomponent {
91 fn into_value(self) -> Result<Value> {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010092 Ok(cbor!({
93 1 => self.name,
94 2 => self.version,
Alan Stokes1508df22023-12-04 11:31:21 +000095 3 => Value::Bytes(self.code_hash),
96 4 => Value::Bytes(self.authority_hash),
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010097 })?)
Alice Wang285a3d22023-03-01 11:36:29 +000098 }
Ludovic Barman93ee3082023-06-20 12:18:43 +000099
Alan Stokes1508df22023-12-04 11:31:21 +0000100 fn for_apk(apk: &ApkData) -> Self {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100101 Self {
102 name: format!("apk:{}", apk.package_name),
Nikita Ioffe2cb8e732025-02-04 00:41:51 +0000103 // Ideally we would want to log both rollback_index and apk version code in dice. There
104 // is even a separate field called security_version_code, but it looks like it is not
105 // used in subcomponents, so for now log the rollback index as version code.
106 version: apk.rollback_index.map(u64::from).unwrap_or(apk.version_code),
Alan Stokes1508df22023-12-04 11:31:21 +0000107 code_hash: apk.root_hash.clone(),
108 authority_hash: apk.cert_hash.clone(),
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100109 }
110 }
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000111
Alan Stokes1508df22023-12-04 11:31:21 +0000112 fn for_apex(apex: &ApexData) -> Self {
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000113 // Note that this is only reachable if the dice_changes flag is on, in which case
114 // the manifest data will always be present.
115 Self {
116 name: format!("apex:{}", apex.manifest_name.as_ref().unwrap()),
117 version: apex.manifest_version.unwrap() as u64,
Alan Stokes1508df22023-12-04 11:31:21 +0000118 code_hash: apex.root_digest.clone(),
119 authority_hash: sha512(&apex.public_key).to_vec(),
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000120 }
121 }
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100122}
123
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000124fn build_subcomponent_list(instance_data: &MicrodroidData) -> Vec<Subcomponent> {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100125 if !cfg!(dice_changes) {
126 return vec![];
127 }
128
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000129 let apks = once(&instance_data.apk_data)
130 .chain(&instance_data.extra_apks_data)
131 .map(Subcomponent::for_apk);
132 let apexes = instance_data.apex_data.iter().map(Subcomponent::for_apex);
133 apks.chain(apexes).collect()
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100134}
135
Shikha Panwar47e5b612024-05-20 19:50:02 +0000136// Returns a configuration descriptor of the given payload. See dice_for_avf_guest.cddl for the
137// definition of the format.
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100138fn format_payload_config_descriptor(
139 payload: &PayloadMetadata,
Alan Stokes1508df22023-12-04 11:31:21 +0000140 subcomponents: Vec<Subcomponent>,
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100141) -> Result<Vec<u8>> {
142 let mut map = Vec::new();
143 map.push((cbor!(-70002)?, cbor!("Microdroid payload")?));
144 map.push(match payload {
145 PayloadMetadata::ConfigPath(payload_config_path) => {
146 (cbor!(-71000)?, cbor!(payload_config_path)?)
147 }
148 PayloadMetadata::Config(payload_config) => {
149 (cbor!(-71001)?, cbor!({1 => payload_config.payload_binary_name})?)
150 }
151 _ => bail!("Failed to match the payload against a config type: {:?}", payload),
152 });
153
154 if !subcomponents.is_empty() {
155 let values =
Alan Stokes1508df22023-12-04 11:31:21 +0000156 subcomponents.into_iter().map(Subcomponent::into_value).collect::<Result<Vec<_>>>()?;
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100157 map.push((cbor!(-71002)?, cbor!(values)?));
158 }
Alice Wang0177c1d2025-02-03 14:34:00 +0000159 // Add a placeholder security version as it is required by the open-dice profile "Android.16".
160 // Note: The DICE certificate derived in microdroid_manager primarily describes the APKs/APEXs
161 // loaded by microdroid_manager. Each APK/APEX is described separately with its own security
162 // version as a subcomponent within the certificate's config descriptor.
163 // Therefore, the global security version below (for the entire certificate) is unused.
Alice Wangb6f19882024-12-24 09:55:30 +0000164 map.push((cbor!(-70005)?, cbor!(0)?));
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100165 Ok(Value::Map(map).to_vec()?)
Alice Wang285a3d22023-03-01 11:36:29 +0000166}
167
Alice Wang285a3d22023-03-01 11:36:29 +0000168#[cfg(test)]
169mod tests {
170 use super::*;
171 use microdroid_metadata::PayloadConfig;
172
Alan Stokes1508df22023-12-04 11:31:21 +0000173 const NO_SUBCOMPONENTS: Vec<Subcomponent> = Vec::new();
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100174
175 fn assert_eq_bytes(expected: &[u8], actual: &[u8]) {
176 assert_eq!(
177 expected,
178 actual,
179 "Expected {}, got {}",
180 hex::encode(expected),
181 hex::encode(actual)
182 )
183 }
184
Alice Wang285a3d22023-03-01 11:36:29 +0000185 #[test]
186 fn payload_metadata_with_path_formats_correctly() -> Result<()> {
Ludovic Barman93ee3082023-06-20 12:18:43 +0000187 let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100188 let config_descriptor =
Alan Stokes1508df22023-12-04 11:31:21 +0000189 format_payload_config_descriptor(&payload_metadata, NO_SUBCOMPONENTS)?;
Alice Wang285a3d22023-03-01 11:36:29 +0000190 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
Alice Wangb6f19882024-12-24 09:55:30 +0000191 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
Alice Wang285a3d22023-03-01 11:36:29 +0000192 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
193 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
Alice Wangb6f19882024-12-24 09:55:30 +0000194 0x68, 0x3a, 0x00, 0x01, 0x11, 0x74, 0x00,
Alice Wang285a3d22023-03-01 11:36:29 +0000195 ];
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100196 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Alice Wang285a3d22023-03-01 11:36:29 +0000197 Ok(())
198 }
199
200 #[test]
201 fn payload_metadata_with_config_formats_correctly() -> Result<()> {
202 let payload_config = PayloadConfig {
203 payload_binary_name: "payload_binary".to_string(),
204 ..Default::default()
205 };
Ludovic Barman93ee3082023-06-20 12:18:43 +0000206 let payload_metadata = PayloadMetadata::Config(payload_config);
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100207 let config_descriptor =
Alan Stokes1508df22023-12-04 11:31:21 +0000208 format_payload_config_descriptor(&payload_metadata, NO_SUBCOMPONENTS)?;
Alice Wang285a3d22023-03-01 11:36:29 +0000209 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
Alice Wangb6f19882024-12-24 09:55:30 +0000210 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
Alice Wang285a3d22023-03-01 11:36:29 +0000211 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
212 0x15, 0x58, 0xa1, 0x01, 0x6e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62,
Alice Wangb6f19882024-12-24 09:55:30 +0000213 0x69, 0x6e, 0x61, 0x72, 0x79, 0x3a, 0x00, 0x01, 0x11, 0x74, 0x00,
Alice Wang285a3d22023-03-01 11:36:29 +0000214 ];
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100215 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
216 Ok(())
217 }
218
219 #[test]
220 fn payload_metadata_with_subcomponents_formats_correctly() -> Result<()> {
221 let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
Alan Stokes1508df22023-12-04 11:31:21 +0000222 let subcomponents = vec![
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100223 Subcomponent {
224 name: "apk1".to_string(),
225 version: 1,
Alan Stokes1508df22023-12-04 11:31:21 +0000226 code_hash: vec![42, 43],
227 authority_hash: vec![17],
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100228 },
229 Subcomponent {
230 name: "apk2".to_string(),
231 version: 0x1000_0000_0001,
Alan Stokes1508df22023-12-04 11:31:21 +0000232 code_hash: vec![43],
233 authority_hash: vec![19, 20],
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100234 },
235 ];
Alan Stokes1508df22023-12-04 11:31:21 +0000236 let config_descriptor = format_payload_config_descriptor(&payload_metadata, subcomponents)?;
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100237 // Verified using cbor.me.
238 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
Alice Wangb6f19882024-12-24 09:55:30 +0000239 0xa4, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100240 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
241 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
242 0x68, 0x3a, 0x00, 0x01, 0x15, 0x59, 0x82, 0xa4, 0x01, 0x64, 0x61, 0x70, 0x6b, 0x31,
Alan Stokes1508df22023-12-04 11:31:21 +0000243 0x02, 0x01, 0x03, 0x42, 0x2a, 0x2b, 0x04, 0x41, 0x11, 0xa4, 0x01, 0x64, 0x61, 0x70,
244 0x6b, 0x32, 0x02, 0x1b, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x41,
Alice Wangb6f19882024-12-24 09:55:30 +0000245 0x2b, 0x04, 0x42, 0x13, 0x14, 0x3a, 0x00, 0x01, 0x11, 0x74, 0x00,
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100246 ];
247 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Alice Wang285a3d22023-03-01 11:36:29 +0000248 Ok(())
249 }
250}