blob: a8b88aaea8ee361c6d96d13a51d6286310f6174b [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 Stokes1125e012023-10-13 12:31:10 +010015use crate::dice_driver::DiceDriver;
Alan Stokes26a6a5c2023-11-10 16:18:43 +000016use crate::instance::{ApexData, ApkData};
Alan Stokes1125e012023-10-13 12:31:10 +010017use crate::{is_debuggable, MicrodroidData};
18use anyhow::{bail, Context, Result};
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010019use ciborium::{cbor, Value};
20use coset::CborSerializable;
Alan Stokes1125e012023-10-13 12:31:10 +010021use diced_open_dice::OwnedDiceArtifacts;
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
Alan Stokes26a6a5c2023-11-10 16:18:43 +000056 let hidden = instance_data.salt.clone().try_into().unwrap();
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
Alan Stokes1508df22023-12-04 11:31:21 +000060struct Subcomponent {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010061 name: String,
62 version: u64,
Alan Stokes1508df22023-12-04 11:31:21 +000063 code_hash: Vec<u8>,
64 authority_hash: Vec<u8>,
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010065}
Alice Wang285a3d22023-03-01 11:36:29 +000066
Alan Stokes1508df22023-12-04 11:31:21 +000067impl Subcomponent {
68 fn into_value(self) -> Result<Value> {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010069 Ok(cbor!({
70 1 => self.name,
71 2 => self.version,
Alan Stokes1508df22023-12-04 11:31:21 +000072 3 => Value::Bytes(self.code_hash),
73 4 => Value::Bytes(self.authority_hash),
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010074 })?)
Alice Wang285a3d22023-03-01 11:36:29 +000075 }
Ludovic Barman93ee3082023-06-20 12:18:43 +000076
Alan Stokes1508df22023-12-04 11:31:21 +000077 fn for_apk(apk: &ApkData) -> Self {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010078 Self {
79 name: format!("apk:{}", apk.package_name),
80 version: apk.version_code,
Alan Stokes1508df22023-12-04 11:31:21 +000081 code_hash: apk.root_hash.clone(),
82 authority_hash: apk.cert_hash.clone(),
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010083 }
84 }
Alan Stokes26a6a5c2023-11-10 16:18:43 +000085
Alan Stokes1508df22023-12-04 11:31:21 +000086 fn for_apex(apex: &ApexData) -> Self {
Alan Stokes26a6a5c2023-11-10 16:18:43 +000087 // Note that this is only reachable if the dice_changes flag is on, in which case
88 // the manifest data will always be present.
89 Self {
90 name: format!("apex:{}", apex.manifest_name.as_ref().unwrap()),
91 version: apex.manifest_version.unwrap() as u64,
Alan Stokes1508df22023-12-04 11:31:21 +000092 code_hash: apex.root_digest.clone(),
93 authority_hash: sha512(&apex.public_key).to_vec(),
Alan Stokes26a6a5c2023-11-10 16:18:43 +000094 }
95 }
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010096}
97
Alan Stokes26a6a5c2023-11-10 16:18:43 +000098fn build_subcomponent_list(instance_data: &MicrodroidData) -> Vec<Subcomponent> {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010099 if !cfg!(dice_changes) {
100 return vec![];
101 }
102
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000103 let apks = once(&instance_data.apk_data)
104 .chain(&instance_data.extra_apks_data)
105 .map(Subcomponent::for_apk);
106 let apexes = instance_data.apex_data.iter().map(Subcomponent::for_apex);
107 apks.chain(apexes).collect()
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100108}
109
Alan Stokes58f2a282023-12-05 09:41:54 +0000110// Returns a configuration descriptor of the given payload. See vm_config.cddl for the definition
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100111// of the format.
112fn format_payload_config_descriptor(
113 payload: &PayloadMetadata,
Alan Stokes1508df22023-12-04 11:31:21 +0000114 subcomponents: Vec<Subcomponent>,
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100115) -> Result<Vec<u8>> {
116 let mut map = Vec::new();
117 map.push((cbor!(-70002)?, cbor!("Microdroid payload")?));
118 map.push(match payload {
119 PayloadMetadata::ConfigPath(payload_config_path) => {
120 (cbor!(-71000)?, cbor!(payload_config_path)?)
121 }
122 PayloadMetadata::Config(payload_config) => {
123 (cbor!(-71001)?, cbor!({1 => payload_config.payload_binary_name})?)
124 }
125 _ => bail!("Failed to match the payload against a config type: {:?}", payload),
126 });
127
128 if !subcomponents.is_empty() {
129 let values =
Alan Stokes1508df22023-12-04 11:31:21 +0000130 subcomponents.into_iter().map(Subcomponent::into_value).collect::<Result<Vec<_>>>()?;
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100131 map.push((cbor!(-71002)?, cbor!(values)?));
132 }
133
134 Ok(Value::Map(map).to_vec()?)
Alice Wang285a3d22023-03-01 11:36:29 +0000135}
136
Alice Wang285a3d22023-03-01 11:36:29 +0000137#[cfg(test)]
138mod tests {
139 use super::*;
140 use microdroid_metadata::PayloadConfig;
141
Alan Stokes1508df22023-12-04 11:31:21 +0000142 const NO_SUBCOMPONENTS: Vec<Subcomponent> = Vec::new();
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100143
144 fn assert_eq_bytes(expected: &[u8], actual: &[u8]) {
145 assert_eq!(
146 expected,
147 actual,
148 "Expected {}, got {}",
149 hex::encode(expected),
150 hex::encode(actual)
151 )
152 }
153
Alice Wang285a3d22023-03-01 11:36:29 +0000154 #[test]
155 fn payload_metadata_with_path_formats_correctly() -> Result<()> {
Ludovic Barman93ee3082023-06-20 12:18:43 +0000156 let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100157 let config_descriptor =
Alan Stokes1508df22023-12-04 11:31:21 +0000158 format_payload_config_descriptor(&payload_metadata, NO_SUBCOMPONENTS)?;
Alice Wang285a3d22023-03-01 11:36:29 +0000159 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
160 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
161 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
162 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
163 0x68,
164 ];
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100165 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Alice Wang285a3d22023-03-01 11:36:29 +0000166 Ok(())
167 }
168
169 #[test]
170 fn payload_metadata_with_config_formats_correctly() -> Result<()> {
171 let payload_config = PayloadConfig {
172 payload_binary_name: "payload_binary".to_string(),
173 ..Default::default()
174 };
Ludovic Barman93ee3082023-06-20 12:18:43 +0000175 let payload_metadata = PayloadMetadata::Config(payload_config);
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100176 let config_descriptor =
Alan Stokes1508df22023-12-04 11:31:21 +0000177 format_payload_config_descriptor(&payload_metadata, NO_SUBCOMPONENTS)?;
Alice Wang285a3d22023-03-01 11:36:29 +0000178 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
179 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
180 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
181 0x15, 0x58, 0xa1, 0x01, 0x6e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62,
182 0x69, 0x6e, 0x61, 0x72, 0x79,
183 ];
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100184 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
185 Ok(())
186 }
187
188 #[test]
189 fn payload_metadata_with_subcomponents_formats_correctly() -> Result<()> {
190 let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
Alan Stokes1508df22023-12-04 11:31:21 +0000191 let subcomponents = vec![
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100192 Subcomponent {
193 name: "apk1".to_string(),
194 version: 1,
Alan Stokes1508df22023-12-04 11:31:21 +0000195 code_hash: vec![42, 43],
196 authority_hash: vec![17],
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100197 },
198 Subcomponent {
199 name: "apk2".to_string(),
200 version: 0x1000_0000_0001,
Alan Stokes1508df22023-12-04 11:31:21 +0000201 code_hash: vec![43],
202 authority_hash: vec![19, 20],
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100203 },
204 ];
Alan Stokes1508df22023-12-04 11:31:21 +0000205 let config_descriptor = format_payload_config_descriptor(&payload_metadata, subcomponents)?;
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100206 // Verified using cbor.me.
207 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
208 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
209 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
210 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
211 0x68, 0x3a, 0x00, 0x01, 0x15, 0x59, 0x82, 0xa4, 0x01, 0x64, 0x61, 0x70, 0x6b, 0x31,
Alan Stokes1508df22023-12-04 11:31:21 +0000212 0x02, 0x01, 0x03, 0x42, 0x2a, 0x2b, 0x04, 0x41, 0x11, 0xa4, 0x01, 0x64, 0x61, 0x70,
213 0x6b, 0x32, 0x02, 0x1b, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x41,
214 0x2b, 0x04, 0x42, 0x13, 0x14,
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100215 ];
216 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Alice Wang285a3d22023-03-01 11:36:29 +0000217 Ok(())
218 }
219}