blob: e6ddfb930e40f04b7705b9e7e3cebfdec796bd69 [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 Stokes9b8b8ec2023-10-13 15:58:11 +010033 let config_descriptor = format_payload_config_descriptor(payload_metadata, &subcomponents)
34 .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());
40 authority_hash_ctx.update(instance_data.apk_data.pubkey.as_ref());
41 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());
43 authority_hash_ctx.update(extra_apk.pubkey.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 Stokes9b8b8ec2023-10-13 15:58:11 +010060struct Subcomponent<'a> {
61 name: String,
62 version: u64,
63 code_hash: &'a [u8],
64 authority_hash: Box<[u8]>,
65}
Alice Wang285a3d22023-03-01 11:36:29 +000066
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010067impl<'a> Subcomponent<'a> {
68 fn to_value(&self) -> Result<Value> {
69 Ok(cbor!({
70 1 => self.name,
71 2 => self.version,
72 3 => self.code_hash,
73 4 => self.authority_hash
74 })?)
Alice Wang285a3d22023-03-01 11:36:29 +000075 }
Ludovic Barman93ee3082023-06-20 12:18:43 +000076
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010077 fn for_apk(apk: &'a ApkData) -> Self {
78 Self {
79 name: format!("apk:{}", apk.package_name),
80 version: apk.version_code,
81 code_hash: &apk.root_hash,
82 authority_hash:
83 // TODO(b/305925597): Hash the certificate not the pubkey
84 Box::new(sha512(&apk.pubkey)),
85 }
86 }
Alan Stokes26a6a5c2023-11-10 16:18:43 +000087
88 fn for_apex(apex: &'a ApexData) -> Self {
89 // Note that this is only reachable if the dice_changes flag is on, in which case
90 // the manifest data will always be present.
91 Self {
92 name: format!("apex:{}", apex.manifest_name.as_ref().unwrap()),
93 version: apex.manifest_version.unwrap() as u64,
94 code_hash: &apex.root_digest,
95 authority_hash: Box::new(sha512(&apex.public_key)),
96 }
97 }
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010098}
99
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000100fn build_subcomponent_list(instance_data: &MicrodroidData) -> Vec<Subcomponent> {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100101 if !cfg!(dice_changes) {
102 return vec![];
103 }
104
Alan Stokes26a6a5c2023-11-10 16:18:43 +0000105 let apks = once(&instance_data.apk_data)
106 .chain(&instance_data.extra_apks_data)
107 .map(Subcomponent::for_apk);
108 let apexes = instance_data.apex_data.iter().map(Subcomponent::for_apex);
109 apks.chain(apexes).collect()
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100110}
111
112// Returns a configuration descriptor of the given payload. See vm_config.cddl for a definition
113// of the format.
114fn format_payload_config_descriptor(
115 payload: &PayloadMetadata,
116 subcomponents: &[Subcomponent],
117) -> Result<Vec<u8>> {
118 let mut map = Vec::new();
119 map.push((cbor!(-70002)?, cbor!("Microdroid payload")?));
120 map.push(match payload {
121 PayloadMetadata::ConfigPath(payload_config_path) => {
122 (cbor!(-71000)?, cbor!(payload_config_path)?)
123 }
124 PayloadMetadata::Config(payload_config) => {
125 (cbor!(-71001)?, cbor!({1 => payload_config.payload_binary_name})?)
126 }
127 _ => bail!("Failed to match the payload against a config type: {:?}", payload),
128 });
129
130 if !subcomponents.is_empty() {
131 let values =
132 subcomponents.iter().map(Subcomponent::to_value).collect::<Result<Vec<_>>>()?;
133 map.push((cbor!(-71002)?, cbor!(values)?));
134 }
135
136 Ok(Value::Map(map).to_vec()?)
Alice Wang285a3d22023-03-01 11:36:29 +0000137}
138
Alice Wang285a3d22023-03-01 11:36:29 +0000139#[cfg(test)]
140mod tests {
141 use super::*;
142 use microdroid_metadata::PayloadConfig;
143
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100144 const NO_SUBCOMPONENTS: [Subcomponent; 0] = [];
145
146 fn assert_eq_bytes(expected: &[u8], actual: &[u8]) {
147 assert_eq!(
148 expected,
149 actual,
150 "Expected {}, got {}",
151 hex::encode(expected),
152 hex::encode(actual)
153 )
154 }
155
Alice Wang285a3d22023-03-01 11:36:29 +0000156 #[test]
157 fn payload_metadata_with_path_formats_correctly() -> Result<()> {
Ludovic Barman93ee3082023-06-20 12:18:43 +0000158 let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100159 let config_descriptor =
160 format_payload_config_descriptor(&payload_metadata, &NO_SUBCOMPONENTS)?;
Alice Wang285a3d22023-03-01 11:36:29 +0000161 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
162 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
163 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
164 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
165 0x68,
166 ];
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100167 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Alice Wang285a3d22023-03-01 11:36:29 +0000168 Ok(())
169 }
170
171 #[test]
172 fn payload_metadata_with_config_formats_correctly() -> Result<()> {
173 let payload_config = PayloadConfig {
174 payload_binary_name: "payload_binary".to_string(),
175 ..Default::default()
176 };
Ludovic Barman93ee3082023-06-20 12:18:43 +0000177 let payload_metadata = PayloadMetadata::Config(payload_config);
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100178 let config_descriptor =
179 format_payload_config_descriptor(&payload_metadata, &NO_SUBCOMPONENTS)?;
Alice Wang285a3d22023-03-01 11:36:29 +0000180 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
181 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
182 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
183 0x15, 0x58, 0xa1, 0x01, 0x6e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62,
184 0x69, 0x6e, 0x61, 0x72, 0x79,
185 ];
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100186 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
187 Ok(())
188 }
189
190 #[test]
191 fn payload_metadata_with_subcomponents_formats_correctly() -> Result<()> {
192 let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
193 let subcomponents = [
194 Subcomponent {
195 name: "apk1".to_string(),
196 version: 1,
197 code_hash: &[42u8],
198 authority_hash: Box::new([17u8]),
199 },
200 Subcomponent {
201 name: "apk2".to_string(),
202 version: 0x1000_0000_0001,
203 code_hash: &[43u8],
204 authority_hash: Box::new([19u8]),
205 },
206 ];
207 let config_descriptor =
208 format_payload_config_descriptor(&payload_metadata, &subcomponents)?;
209 // Verified using cbor.me.
210 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
211 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
212 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
213 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
214 0x68, 0x3a, 0x00, 0x01, 0x15, 0x59, 0x82, 0xa4, 0x01, 0x64, 0x61, 0x70, 0x6b, 0x31,
215 0x02, 0x01, 0x03, 0x81, 0x18, 0x2a, 0x04, 0x81, 0x11, 0xa4, 0x01, 0x64, 0x61, 0x70,
216 0x6b, 0x32, 0x02, 0x1b, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x81,
217 0x18, 0x2b, 0x04, 0x81, 0x13,
218 ];
219 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Alice Wang285a3d22023-03-01 11:36:29 +0000220 Ok(())
221 }
222}