blob: cecf4138ccf0ba53b098f08db84469ba86c206e7 [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 Panwarf15e0272024-03-12 22:35:09 +000056 let hidden = if cfg!(llpvm_changes) {
57 hidden_input_from_instance_id()?
58 } else {
59 instance_data.salt.clone().try_into().unwrap()
60 };
Alan Stokes1125e012023-10-13 12:31:10 +010061 dice.derive(code_hash, &config_descriptor, authority_hash, debuggable, hidden)
Andrew Sculld64ae7d2022-10-05 17:41:43 +000062}
Alice Wang285a3d22023-03-01 11:36:29 +000063
Shikha Panwarf15e0272024-03-12 22:35:09 +000064// Get the "Hidden input" for DICE derivation.
65// This provides differentiation of secrets for different VM instances with same payload.
66fn hidden_input_from_instance_id() -> Result<Hidden> {
67 // For protected VM: this is all 0s, pvmfw ensures differentiation is added early in secrets.
68 // For non-protected VM: this is derived from instance_id of the VM instance.
69 let hidden_input = if !is_strict_boot() {
70 if let Some(id) = super::get_instance_id()? {
71 sha512(&id)
72 } else {
73 // TODO(b/325094712): Absence of instance_id occurs due to missing DT in some
74 // x86_64 test devices (such as Cuttlefish). From security perspective, this is
75 // acceptable for non-protected VM.
76 log::warn!(
77 "Instance Id missing, this may lead to 2 non protected VMs having same secrets"
78 );
79 [0u8; HIDDEN_SIZE]
80 }
81 } else {
82 [0u8; HIDDEN_SIZE]
83 };
84 Ok(hidden_input)
85}
86
Alan Stokes1508df22023-12-04 11:31:21 +000087struct Subcomponent {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010088 name: String,
89 version: u64,
Alan Stokes1508df22023-12-04 11:31:21 +000090 code_hash: Vec<u8>,
91 authority_hash: Vec<u8>,
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010092}
Alice Wang285a3d22023-03-01 11:36:29 +000093
Alan Stokes1508df22023-12-04 11:31:21 +000094impl Subcomponent {
95 fn into_value(self) -> Result<Value> {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010096 Ok(cbor!({
97 1 => self.name,
98 2 => self.version,
Alan Stokes1508df22023-12-04 11:31:21 +000099 3 => Value::Bytes(self.code_hash),
100 4 => Value::Bytes(self.authority_hash),
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100101 })?)
Alice Wang285a3d22023-03-01 11:36:29 +0000102 }
Ludovic Barman93ee3082023-06-20 12:18:43 +0000103
Alan Stokes1508df22023-12-04 11:31:21 +0000104 fn for_apk(apk: &ApkData) -> Self {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100105 Self {
106 name: format!("apk:{}", apk.package_name),
107 version: apk.version_code,
Alan Stokes1508df22023-12-04 11:31:21 +0000108 code_hash: apk.root_hash.clone(),
109 authority_hash: apk.cert_hash.clone(),
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100110 }
111 }
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000112
Alan Stokes1508df22023-12-04 11:31:21 +0000113 fn for_apex(apex: &ApexData) -> Self {
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000114 // Note that this is only reachable if the dice_changes flag is on, in which case
115 // the manifest data will always be present.
116 Self {
117 name: format!("apex:{}", apex.manifest_name.as_ref().unwrap()),
118 version: apex.manifest_version.unwrap() as u64,
Alan Stokes1508df22023-12-04 11:31:21 +0000119 code_hash: apex.root_digest.clone(),
120 authority_hash: sha512(&apex.public_key).to_vec(),
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000121 }
122 }
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100123}
124
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000125fn build_subcomponent_list(instance_data: &MicrodroidData) -> Vec<Subcomponent> {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100126 if !cfg!(dice_changes) {
127 return vec![];
128 }
129
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000130 let apks = once(&instance_data.apk_data)
131 .chain(&instance_data.extra_apks_data)
132 .map(Subcomponent::for_apk);
133 let apexes = instance_data.apex_data.iter().map(Subcomponent::for_apex);
134 apks.chain(apexes).collect()
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100135}
136
Alan Stokes58f2a282023-12-05 09:41:54 +0000137// Returns a configuration descriptor of the given payload. See vm_config.cddl for the definition
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100138// of the format.
139fn format_payload_config_descriptor(
140 payload: &PayloadMetadata,
Alan Stokes1508df22023-12-04 11:31:21 +0000141 subcomponents: Vec<Subcomponent>,
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100142) -> Result<Vec<u8>> {
143 let mut map = Vec::new();
144 map.push((cbor!(-70002)?, cbor!("Microdroid payload")?));
145 map.push(match payload {
146 PayloadMetadata::ConfigPath(payload_config_path) => {
147 (cbor!(-71000)?, cbor!(payload_config_path)?)
148 }
149 PayloadMetadata::Config(payload_config) => {
150 (cbor!(-71001)?, cbor!({1 => payload_config.payload_binary_name})?)
151 }
152 _ => bail!("Failed to match the payload against a config type: {:?}", payload),
153 });
154
155 if !subcomponents.is_empty() {
156 let values =
Alan Stokes1508df22023-12-04 11:31:21 +0000157 subcomponents.into_iter().map(Subcomponent::into_value).collect::<Result<Vec<_>>>()?;
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100158 map.push((cbor!(-71002)?, cbor!(values)?));
159 }
160
161 Ok(Value::Map(map).to_vec()?)
Alice Wang285a3d22023-03-01 11:36:29 +0000162}
163
Alice Wang285a3d22023-03-01 11:36:29 +0000164#[cfg(test)]
165mod tests {
166 use super::*;
167 use microdroid_metadata::PayloadConfig;
168
Alan Stokes1508df22023-12-04 11:31:21 +0000169 const NO_SUBCOMPONENTS: Vec<Subcomponent> = Vec::new();
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100170
171 fn assert_eq_bytes(expected: &[u8], actual: &[u8]) {
172 assert_eq!(
173 expected,
174 actual,
175 "Expected {}, got {}",
176 hex::encode(expected),
177 hex::encode(actual)
178 )
179 }
180
Alice Wang285a3d22023-03-01 11:36:29 +0000181 #[test]
182 fn payload_metadata_with_path_formats_correctly() -> Result<()> {
Ludovic Barman93ee3082023-06-20 12:18:43 +0000183 let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100184 let config_descriptor =
Alan Stokes1508df22023-12-04 11:31:21 +0000185 format_payload_config_descriptor(&payload_metadata, NO_SUBCOMPONENTS)?;
Alice Wang285a3d22023-03-01 11:36:29 +0000186 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
187 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
188 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
189 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
190 0x68,
191 ];
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100192 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Alice Wang285a3d22023-03-01 11:36:29 +0000193 Ok(())
194 }
195
196 #[test]
197 fn payload_metadata_with_config_formats_correctly() -> Result<()> {
198 let payload_config = PayloadConfig {
199 payload_binary_name: "payload_binary".to_string(),
200 ..Default::default()
201 };
Ludovic Barman93ee3082023-06-20 12:18:43 +0000202 let payload_metadata = PayloadMetadata::Config(payload_config);
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100203 let config_descriptor =
Alan Stokes1508df22023-12-04 11:31:21 +0000204 format_payload_config_descriptor(&payload_metadata, NO_SUBCOMPONENTS)?;
Alice Wang285a3d22023-03-01 11:36:29 +0000205 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
206 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
207 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
208 0x15, 0x58, 0xa1, 0x01, 0x6e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62,
209 0x69, 0x6e, 0x61, 0x72, 0x79,
210 ];
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100211 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
212 Ok(())
213 }
214
215 #[test]
216 fn payload_metadata_with_subcomponents_formats_correctly() -> Result<()> {
217 let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
Alan Stokes1508df22023-12-04 11:31:21 +0000218 let subcomponents = vec![
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100219 Subcomponent {
220 name: "apk1".to_string(),
221 version: 1,
Alan Stokes1508df22023-12-04 11:31:21 +0000222 code_hash: vec![42, 43],
223 authority_hash: vec![17],
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100224 },
225 Subcomponent {
226 name: "apk2".to_string(),
227 version: 0x1000_0000_0001,
Alan Stokes1508df22023-12-04 11:31:21 +0000228 code_hash: vec![43],
229 authority_hash: vec![19, 20],
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100230 },
231 ];
Alan Stokes1508df22023-12-04 11:31:21 +0000232 let config_descriptor = format_payload_config_descriptor(&payload_metadata, subcomponents)?;
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100233 // Verified using cbor.me.
234 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
235 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
236 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
237 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
238 0x68, 0x3a, 0x00, 0x01, 0x15, 0x59, 0x82, 0xa4, 0x01, 0x64, 0x61, 0x70, 0x6b, 0x31,
Alan Stokes1508df22023-12-04 11:31:21 +0000239 0x02, 0x01, 0x03, 0x42, 0x2a, 0x2b, 0x04, 0x41, 0x11, 0xa4, 0x01, 0x64, 0x61, 0x70,
240 0x6b, 0x32, 0x02, 0x1b, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x41,
241 0x2b, 0x04, 0x42, 0x13, 0x14,
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100242 ];
243 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Alice Wang285a3d22023-03-01 11:36:29 +0000244 Ok(())
245 }
246}