blob: 6b0775a1e47906c416381b665d75f9621da2365f [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 Stokes9b8b8ec2023-10-13 15:58:11 +010016use crate::instance::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,
29 verified_data: &MicrodroidData,
30 payload_metadata: &PayloadMetadata,
31) -> Result<OwnedDiceArtifacts> {
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010032 let subcomponents = build_subcomponent_list(verified_data);
33
34 let config_descriptor = format_payload_config_descriptor(payload_metadata, &subcomponents)
35 .context("Building config descriptor")?;
36
Alan Stokes1125e012023-10-13 12:31:10 +010037 // Calculate compound digests of code and authorities
38 let mut code_hash_ctx = Sha512::new();
39 let mut authority_hash_ctx = Sha512::new();
40 code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
41 authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
42 for extra_apk in &verified_data.extra_apks_data {
43 code_hash_ctx.update(extra_apk.root_hash.as_ref());
44 authority_hash_ctx.update(extra_apk.pubkey.as_ref());
Alice Wang7e6c9352023-02-15 15:44:13 +000045 }
Alan Stokes1125e012023-10-13 12:31:10 +010046 for apex in &verified_data.apex_data {
47 code_hash_ctx.update(apex.root_digest.as_ref());
48 authority_hash_ctx.update(apex.public_key.as_ref());
Andrew Sculld64ae7d2022-10-05 17:41:43 +000049 }
Alan Stokes1125e012023-10-13 12:31:10 +010050 let code_hash = code_hash_ctx.finish();
51 let authority_hash = authority_hash_ctx.finish();
Andrew Sculld64ae7d2022-10-05 17:41:43 +000052
Alan Stokes1125e012023-10-13 12:31:10 +010053 // Check debuggability, conservatively assuming it is debuggable
54 let debuggable = is_debuggable()?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +000055
Alan Stokes1125e012023-10-13 12:31:10 +010056 // Send the details to diced
57 let hidden = verified_data.salt.clone().try_into().unwrap();
58 dice.derive(code_hash, &config_descriptor, authority_hash, debuggable, hidden)
Andrew Sculld64ae7d2022-10-05 17:41:43 +000059}
Alice Wang285a3d22023-03-01 11:36:29 +000060
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010061struct Subcomponent<'a> {
62 name: String,
63 version: u64,
64 code_hash: &'a [u8],
65 authority_hash: Box<[u8]>,
66}
Alice Wang285a3d22023-03-01 11:36:29 +000067
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010068impl<'a> Subcomponent<'a> {
69 fn to_value(&self) -> Result<Value> {
70 Ok(cbor!({
71 1 => self.name,
72 2 => self.version,
73 3 => self.code_hash,
74 4 => self.authority_hash
75 })?)
Alice Wang285a3d22023-03-01 11:36:29 +000076 }
Ludovic Barman93ee3082023-06-20 12:18:43 +000077
Alan Stokes9b8b8ec2023-10-13 15:58:11 +010078 fn for_apk(apk: &'a ApkData) -> Self {
79 Self {
80 name: format!("apk:{}", apk.package_name),
81 version: apk.version_code,
82 code_hash: &apk.root_hash,
83 authority_hash:
84 // TODO(b/305925597): Hash the certificate not the pubkey
85 Box::new(sha512(&apk.pubkey)),
86 }
87 }
88}
89
90fn build_subcomponent_list(verified_data: &MicrodroidData) -> Vec<Subcomponent> {
91 if !cfg!(dice_changes) {
92 return vec![];
93 }
94
95 once(&verified_data.apk_data)
96 .chain(&verified_data.extra_apks_data)
97 .map(Subcomponent::for_apk)
98 .collect()
99}
100
101// Returns a configuration descriptor of the given payload. See vm_config.cddl for a definition
102// of the format.
103fn format_payload_config_descriptor(
104 payload: &PayloadMetadata,
105 subcomponents: &[Subcomponent],
106) -> Result<Vec<u8>> {
107 let mut map = Vec::new();
108 map.push((cbor!(-70002)?, cbor!("Microdroid payload")?));
109 map.push(match payload {
110 PayloadMetadata::ConfigPath(payload_config_path) => {
111 (cbor!(-71000)?, cbor!(payload_config_path)?)
112 }
113 PayloadMetadata::Config(payload_config) => {
114 (cbor!(-71001)?, cbor!({1 => payload_config.payload_binary_name})?)
115 }
116 _ => bail!("Failed to match the payload against a config type: {:?}", payload),
117 });
118
119 if !subcomponents.is_empty() {
120 let values =
121 subcomponents.iter().map(Subcomponent::to_value).collect::<Result<Vec<_>>>()?;
122 map.push((cbor!(-71002)?, cbor!(values)?));
123 }
124
125 Ok(Value::Map(map).to_vec()?)
Alice Wang285a3d22023-03-01 11:36:29 +0000126}
127
Alice Wang285a3d22023-03-01 11:36:29 +0000128#[cfg(test)]
129mod tests {
130 use super::*;
131 use microdroid_metadata::PayloadConfig;
132
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100133 const NO_SUBCOMPONENTS: [Subcomponent; 0] = [];
134
135 fn assert_eq_bytes(expected: &[u8], actual: &[u8]) {
136 assert_eq!(
137 expected,
138 actual,
139 "Expected {}, got {}",
140 hex::encode(expected),
141 hex::encode(actual)
142 )
143 }
144
Alice Wang285a3d22023-03-01 11:36:29 +0000145 #[test]
146 fn payload_metadata_with_path_formats_correctly() -> Result<()> {
Ludovic Barman93ee3082023-06-20 12:18:43 +0000147 let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100148 let config_descriptor =
149 format_payload_config_descriptor(&payload_metadata, &NO_SUBCOMPONENTS)?;
Alice Wang285a3d22023-03-01 11:36:29 +0000150 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
151 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
152 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
153 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
154 0x68,
155 ];
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100156 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Alice Wang285a3d22023-03-01 11:36:29 +0000157 Ok(())
158 }
159
160 #[test]
161 fn payload_metadata_with_config_formats_correctly() -> Result<()> {
162 let payload_config = PayloadConfig {
163 payload_binary_name: "payload_binary".to_string(),
164 ..Default::default()
165 };
Ludovic Barman93ee3082023-06-20 12:18:43 +0000166 let payload_metadata = PayloadMetadata::Config(payload_config);
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100167 let config_descriptor =
168 format_payload_config_descriptor(&payload_metadata, &NO_SUBCOMPONENTS)?;
Alice Wang285a3d22023-03-01 11:36:29 +0000169 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
170 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
171 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
172 0x15, 0x58, 0xa1, 0x01, 0x6e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62,
173 0x69, 0x6e, 0x61, 0x72, 0x79,
174 ];
Alan Stokes9b8b8ec2023-10-13 15:58:11 +0100175 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
176 Ok(())
177 }
178
179 #[test]
180 fn payload_metadata_with_subcomponents_formats_correctly() -> Result<()> {
181 let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
182 let subcomponents = [
183 Subcomponent {
184 name: "apk1".to_string(),
185 version: 1,
186 code_hash: &[42u8],
187 authority_hash: Box::new([17u8]),
188 },
189 Subcomponent {
190 name: "apk2".to_string(),
191 version: 0x1000_0000_0001,
192 code_hash: &[43u8],
193 authority_hash: Box::new([19u8]),
194 },
195 ];
196 let config_descriptor =
197 format_payload_config_descriptor(&payload_metadata, &subcomponents)?;
198 // Verified using cbor.me.
199 static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
200 0xa3, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
201 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
202 0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
203 0x68, 0x3a, 0x00, 0x01, 0x15, 0x59, 0x82, 0xa4, 0x01, 0x64, 0x61, 0x70, 0x6b, 0x31,
204 0x02, 0x01, 0x03, 0x81, 0x18, 0x2a, 0x04, 0x81, 0x11, 0xa4, 0x01, 0x64, 0x61, 0x70,
205 0x6b, 0x32, 0x02, 0x1b, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x81,
206 0x18, 0x2b, 0x04, 0x81, 0x13,
207 ];
208 assert_eq_bytes(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Alice Wang285a3d22023-03-01 11:36:29 +0000209 Ok(())
210 }
211}