blob: 8d883d2703ea6c0f4c74d2321fa617739f31559b [file] [log] [blame]
// Copyright 2021, 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.
//! A proxy dice node delegates all accesses to CDI_attest and CDI_seal to a parent
//! node, here an implementation of android.hardware.security.dice.IDiceDevice.
#![allow(dead_code)]
use crate::DiceNodeImpl;
use android_hardware_security_dice::aidl::android::hardware::security::dice::{
Bcc::Bcc, BccHandover::BccHandover, IDiceDevice::IDiceDevice,
InputValues::InputValues as BinderInputValues, Signature::Signature,
};
use anyhow::{Context, Result};
use binder::Strong;
use std::collections::HashMap;
use std::sync::RwLock;
/// The ProxyNodeHal implements a IDiceNode backend delegating crypto operations
/// to the corresponding HAL.
pub struct ProxyNodeHal {
parent: Strong<dyn IDiceDevice>,
demotion_db: RwLock<HashMap<BinderInputValues, Vec<BinderInputValues>>>,
}
impl ProxyNodeHal {
/// Creates a new proxy node with a reference to the parent service.
pub fn new(parent: Strong<dyn IDiceDevice>) -> Result<Self> {
Ok(ProxyNodeHal { parent, demotion_db: Default::default() })
}
fn get_effective_input_values(
&self,
client: BinderInputValues,
input_values: &[BinderInputValues],
) -> Vec<BinderInputValues> {
let demotion_db = self.demotion_db.read().unwrap();
let client_arr = [client];
demotion_db
.get(&client_arr[0])
.map(|v| v.iter())
.unwrap_or_else(|| client_arr.iter())
.chain(input_values.iter())
.cloned()
.collect()
}
}
impl DiceNodeImpl for ProxyNodeHal {
fn sign(
&self,
client: BinderInputValues,
input_values: &[BinderInputValues],
message: &[u8],
) -> Result<Signature> {
self.parent
.sign(&self.get_effective_input_values(client, input_values), message)
.context("In ProxyNodeHal::sign:")
}
fn get_attestation_chain(
&self,
client: BinderInputValues,
input_values: &[BinderInputValues],
) -> Result<Bcc> {
self.parent
.getAttestationChain(&self.get_effective_input_values(client, input_values))
.context("In ProxyNodeHal::get_attestation_chain:")
}
fn derive(
&self,
client: BinderInputValues,
input_values: &[BinderInputValues],
) -> Result<BccHandover> {
self.parent
.derive(&self.get_effective_input_values(client, input_values))
.context("In ProxyNodeHal::derive:")
}
fn demote(&self, client: BinderInputValues, input_values: &[BinderInputValues]) -> Result<()> {
let mut demotion_db = self.demotion_db.write().unwrap();
let client_arr = [client];
// The following statement consults demotion database which yields an optional demotion
// path. It then constructs an iterator over the following elements, then clones and
// collects them into a new vector:
// [ demotion path | client ], input_values
let new_path: Vec<BinderInputValues> = demotion_db
.get(&client_arr[0])
.map(|v| v.iter())
.unwrap_or_else(|| client_arr.iter())
.chain(input_values)
.cloned()
.collect();
let [client] = client_arr;
demotion_db.insert(client, new_path);
Ok(())
}
fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()> {
self.parent.demote(input_values).context("In ProxyNodeHal::demote_self:")
}
}