Diced: Add service diced an implementation of android.security.dice
Bug: 198197213
Test: diced_test
Change-Id: I7075c2e7ac8e48a13f4eb177f2e989ff1e6695a2
diff --git a/diced/src/lib.rs b/diced/src/lib.rs
new file mode 100644
index 0000000..ac9484a
--- /dev/null
+++ b/diced/src/lib.rs
@@ -0,0 +1,140 @@
+// 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.
+
+//! Implement the android.security.dice.IDiceNode service.
+
+mod error;
+mod resident_node;
+
+pub use crate::resident_node::ResidentNode;
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+ Bcc::Bcc, BccHandover::BccHandover, Config::Config as BinderConfig,
+ InputValues::InputValues as BinderInputValues, Mode::Mode, Signature::Signature,
+};
+use android_security_dice::aidl::android::security::dice::{
+ IDiceNode::BnDiceNode, IDiceNode::IDiceNode, ResponseCode::ResponseCode,
+};
+use anyhow::{Context, Result};
+use binder::{public_api::Result as BinderResult, BinderFeatures, Strong, ThreadState};
+pub use diced_open_dice_cbor as dice;
+use error::{map_or_log_err, Error};
+use libc::uid_t;
+use std::sync::Arc;
+
+/// A DiceNode backend implementation.
+/// All functions except demote_self derive effective dice artifacts staring from
+/// this node and iterating through `{ [client | demotion path], input_values }`
+/// in ascending order.
+pub trait DiceNodeImpl {
+ /// Signs the message using the effective dice artifacts and Ed25519Pure.
+ fn sign(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ message: &[u8],
+ ) -> Result<Signature>;
+ /// Returns the effective attestation chain.
+ fn get_attestation_chain(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<Bcc>;
+ /// Returns the effective dice artifacts.
+ fn derive(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<BccHandover>;
+ /// Adds [ `client` | `input_values` ] to the demotion path of the given client.
+ /// This changes the effective dice artifacts for all subsequent API calls of the
+ /// given client.
+ fn demote(&self, client: BinderInputValues, input_values: &[BinderInputValues]) -> Result<()>;
+ /// This demotes the implementation itself. I.e. a resident node would replace its resident
+ /// with the effective artifacts derived using `input_values`. A proxy node would
+ /// simply call `demote` on its parent node. This is not reversible and changes
+ /// the effective dice artifacts of all clients.
+ fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()>;
+}
+
+/// Wraps a DiceNodeImpl and implements the actual IDiceNode AIDL API.
+pub struct DiceNode {
+ node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
+}
+
+fn client_input_values(uid: uid_t) -> Result<BinderInputValues> {
+ Ok(BinderInputValues {
+ codeHash: vec![0; dice::HASH_SIZE],
+ config: BinderConfig {
+ desc: dice::bcc::format_config_descriptor(Some(&format!("{}", uid)), None, true)
+ .context("In client_input_values: failed to format config descriptor")?,
+ },
+ authorityHash: vec![0; dice::HASH_SIZE],
+ authorityDescriptor: None,
+ hidden: vec![0; dice::HIDDEN_SIZE],
+ mode: Mode::NORMAL,
+ })
+}
+
+impl DiceNode {
+ /// Constructs an instance of DiceNode, wraps it with a BnDiceNode object and
+ /// returns a strong pointer to the binder. The result can be used to register
+ /// the service with service manager.
+ pub fn new_as_binder(
+ node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
+ ) -> Result<Strong<dyn IDiceNode>> {
+ let result = BnDiceNode::new_binder(
+ DiceNode { node_impl },
+ BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+ );
+ Ok(result)
+ }
+
+ fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> Result<Signature> {
+ let client =
+ client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::sign:")?;
+ self.node_impl.sign(client, input_values, message)
+ }
+ fn get_attestation_chain(&self, input_values: &[BinderInputValues]) -> Result<Bcc> {
+ let client = client_input_values(ThreadState::get_calling_uid())
+ .context("In DiceNode::get_attestation_chain:")?;
+ self.node_impl.get_attestation_chain(client, input_values)
+ }
+ fn derive(&self, input_values: &[BinderInputValues]) -> Result<BccHandover> {
+ let client =
+ client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::extend:")?;
+ self.node_impl.derive(client, input_values)
+ }
+ fn demote(&self, input_values: &[BinderInputValues]) -> Result<()> {
+ let client =
+ client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::demote:")?;
+ self.node_impl.demote(client, input_values)
+ }
+}
+
+impl binder::Interface for DiceNode {}
+
+impl IDiceNode for DiceNode {
+ fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> BinderResult<Signature> {
+ map_or_log_err(self.sign(input_values, message), Ok)
+ }
+ fn getAttestationChain(&self, input_values: &[BinderInputValues]) -> BinderResult<Bcc> {
+ map_or_log_err(self.get_attestation_chain(input_values), Ok)
+ }
+ fn derive(&self, input_values: &[BinderInputValues]) -> BinderResult<BccHandover> {
+ map_or_log_err(self.derive(input_values), Ok)
+ }
+ fn demote(&self, input_values: &[BinderInputValues]) -> BinderResult<()> {
+ map_or_log_err(self.demote(input_values), Ok)
+ }
+}