blob: a5764164066de0ccbd59422444acc5c14e5957c1 [file] [log] [blame]
// Copyright 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::dice_driver::DiceDriver;
use crate::{is_debuggable, MicrodroidData};
use anyhow::{bail, Context, Result};
use ciborium::{cbor, ser};
use diced_open_dice::OwnedDiceArtifacts;
use microdroid_metadata::PayloadMetadata;
use openssl::sha::Sha512;
/// Perform an open DICE derivation for the payload.
pub fn dice_derivation(
dice: DiceDriver,
verified_data: &MicrodroidData,
payload_metadata: &PayloadMetadata,
) -> Result<OwnedDiceArtifacts> {
// Calculate compound digests of code and authorities
let mut code_hash_ctx = Sha512::new();
let mut authority_hash_ctx = Sha512::new();
code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
for extra_apk in &verified_data.extra_apks_data {
code_hash_ctx.update(extra_apk.root_hash.as_ref());
authority_hash_ctx.update(extra_apk.pubkey.as_ref());
}
for apex in &verified_data.apex_data {
code_hash_ctx.update(apex.root_digest.as_ref());
authority_hash_ctx.update(apex.public_key.as_ref());
}
let code_hash = code_hash_ctx.finish();
let authority_hash = authority_hash_ctx.finish();
let config_descriptor = format_payload_config_descriptor(payload_metadata)?;
// Check debuggability, conservatively assuming it is debuggable
let debuggable = is_debuggable()?;
// Send the details to diced
let hidden = verified_data.salt.clone().try_into().unwrap();
dice.derive(code_hash, &config_descriptor, authority_hash, debuggable, hidden)
}
/// Returns a configuration descriptor of the given payload following the BCC's specification:
/// https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
/// {
/// -70002: "Microdroid payload",
/// ? -71000: tstr ; payload_config_path
/// ? -71001: PayloadConfig
/// }
/// PayloadConfig = {
/// 1: tstr ; payload_binary_name
/// }
fn format_payload_config_descriptor(payload: &PayloadMetadata) -> Result<Vec<u8>> {
const MICRODROID_PAYLOAD_COMPONENT_NAME: &str = "Microdroid payload";
let config_descriptor_cbor_value = match payload {
PayloadMetadata::ConfigPath(payload_config_path) => cbor!({
-70002 => MICRODROID_PAYLOAD_COMPONENT_NAME,
-71000 => payload_config_path
}),
PayloadMetadata::Config(payload_config) => cbor!({
-70002 => MICRODROID_PAYLOAD_COMPONENT_NAME,
-71001 => {1 => payload_config.payload_binary_name}
}),
_ => bail!("Failed to match the payload against a config type: {:?}", payload),
}
.context("Failed to build a CBOR Value from payload metadata")?;
let mut config_descriptor = Vec::new();
ser::into_writer(&config_descriptor_cbor_value, &mut config_descriptor)?;
Ok(config_descriptor)
}
#[cfg(test)]
mod tests {
use super::*;
use microdroid_metadata::PayloadConfig;
#[test]
fn payload_metadata_with_path_formats_correctly() -> Result<()> {
let payload_metadata = PayloadMetadata::ConfigPath("/config_path".to_string());
let config_descriptor = format_payload_config_descriptor(&payload_metadata)?;
static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
0x15, 0x57, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74,
0x68,
];
assert_eq!(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Ok(())
}
#[test]
fn payload_metadata_with_config_formats_correctly() -> Result<()> {
let payload_config = PayloadConfig {
payload_binary_name: "payload_binary".to_string(),
..Default::default()
};
let payload_metadata = PayloadMetadata::Config(payload_config);
let config_descriptor = format_payload_config_descriptor(&payload_metadata)?;
static EXPECTED_CONFIG_DESCRIPTOR: &[u8] = &[
0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72,
0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x00, 0x01,
0x15, 0x58, 0xa1, 0x01, 0x6e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62,
0x69, 0x6e, 0x61, 0x72, 0x79,
];
assert_eq!(EXPECTED_CONFIG_DESCRIPTOR, &config_descriptor);
Ok(())
}
}