blob: 462d2aaa47f4c695b510cc863fe8375ac8e71e82 [file] [log] [blame]
Janis Danisevskisc51dff82021-10-20 09:51:16 -07001// Copyright 2021, The Android Open Source Project
2//
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//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
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
15//! Implement the android.security.dice.IDiceNode service.
16
17mod error;
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -070018mod permission;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070019mod resident_node;
20
21pub use crate::resident_node::ResidentNode;
22use android_hardware_security_dice::aidl::android::hardware::security::dice::{
23 Bcc::Bcc, BccHandover::BccHandover, Config::Config as BinderConfig,
24 InputValues::InputValues as BinderInputValues, Mode::Mode, Signature::Signature,
25};
26use android_security_dice::aidl::android::security::dice::{
27 IDiceNode::BnDiceNode, IDiceNode::IDiceNode, ResponseCode::ResponseCode,
28};
29use anyhow::{Context, Result};
30use binder::{public_api::Result as BinderResult, BinderFeatures, Strong, ThreadState};
31pub use diced_open_dice_cbor as dice;
32use error::{map_or_log_err, Error};
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -070033use keystore2_selinux as selinux;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070034use libc::uid_t;
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -070035use permission::Permission;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070036use std::sync::Arc;
37
38/// A DiceNode backend implementation.
39/// All functions except demote_self derive effective dice artifacts staring from
40/// this node and iterating through `{ [client | demotion path], input_values }`
41/// in ascending order.
42pub trait DiceNodeImpl {
43 /// Signs the message using the effective dice artifacts and Ed25519Pure.
44 fn sign(
45 &self,
46 client: BinderInputValues,
47 input_values: &[BinderInputValues],
48 message: &[u8],
49 ) -> Result<Signature>;
50 /// Returns the effective attestation chain.
51 fn get_attestation_chain(
52 &self,
53 client: BinderInputValues,
54 input_values: &[BinderInputValues],
55 ) -> Result<Bcc>;
56 /// Returns the effective dice artifacts.
57 fn derive(
58 &self,
59 client: BinderInputValues,
60 input_values: &[BinderInputValues],
61 ) -> Result<BccHandover>;
62 /// Adds [ `client` | `input_values` ] to the demotion path of the given client.
63 /// This changes the effective dice artifacts for all subsequent API calls of the
64 /// given client.
65 fn demote(&self, client: BinderInputValues, input_values: &[BinderInputValues]) -> Result<()>;
66 /// This demotes the implementation itself. I.e. a resident node would replace its resident
67 /// with the effective artifacts derived using `input_values`. A proxy node would
68 /// simply call `demote` on its parent node. This is not reversible and changes
69 /// the effective dice artifacts of all clients.
70 fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()>;
71}
72
73/// Wraps a DiceNodeImpl and implements the actual IDiceNode AIDL API.
74pub struct DiceNode {
75 node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
76}
77
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -070078/// This function uses its namesake in the permission module and in
79/// combination with with_calling_sid from the binder crate to check
80/// if the caller has the given keystore permission.
81pub fn check_caller_permission<T: selinux::ClassPermission>(perm: T) -> Result<()> {
82 ThreadState::with_calling_sid(|calling_sid| {
83 let target_context =
84 selinux::getcon().context("In check_caller_permission: getcon failed.")?;
85
86 selinux::check_permission(
87 calling_sid.ok_or(Error::Rc(ResponseCode::SYSTEM_ERROR)).context(
88 "In check_keystore_permission: Cannot check permission without calling_sid.",
89 )?,
90 &target_context,
91 perm,
92 )
93 })
94}
95
Janis Danisevskisc51dff82021-10-20 09:51:16 -070096fn client_input_values(uid: uid_t) -> Result<BinderInputValues> {
97 Ok(BinderInputValues {
98 codeHash: vec![0; dice::HASH_SIZE],
99 config: BinderConfig {
100 desc: dice::bcc::format_config_descriptor(Some(&format!("{}", uid)), None, true)
101 .context("In client_input_values: failed to format config descriptor")?,
102 },
103 authorityHash: vec![0; dice::HASH_SIZE],
104 authorityDescriptor: None,
105 hidden: vec![0; dice::HIDDEN_SIZE],
106 mode: Mode::NORMAL,
107 })
108}
109
110impl DiceNode {
111 /// Constructs an instance of DiceNode, wraps it with a BnDiceNode object and
112 /// returns a strong pointer to the binder. The result can be used to register
113 /// the service with service manager.
114 pub fn new_as_binder(
115 node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
116 ) -> Result<Strong<dyn IDiceNode>> {
117 let result = BnDiceNode::new_binder(
118 DiceNode { node_impl },
119 BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
120 );
121 Ok(result)
122 }
123
124 fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> Result<Signature> {
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -0700125 check_caller_permission(Permission::UseSign).context("In DiceNode::sign:")?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700126 let client =
127 client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::sign:")?;
128 self.node_impl.sign(client, input_values, message)
129 }
130 fn get_attestation_chain(&self, input_values: &[BinderInputValues]) -> Result<Bcc> {
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -0700131 check_caller_permission(Permission::GetAttestationChain)
132 .context("In DiceNode::get_attestation_chain:")?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700133 let client = client_input_values(ThreadState::get_calling_uid())
134 .context("In DiceNode::get_attestation_chain:")?;
135 self.node_impl.get_attestation_chain(client, input_values)
136 }
137 fn derive(&self, input_values: &[BinderInputValues]) -> Result<BccHandover> {
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -0700138 check_caller_permission(Permission::Derive).context("In DiceNode::derive:")?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700139 let client =
140 client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::extend:")?;
141 self.node_impl.derive(client, input_values)
142 }
143 fn demote(&self, input_values: &[BinderInputValues]) -> Result<()> {
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -0700144 check_caller_permission(Permission::Demote).context("In DiceNode::demote:")?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700145 let client =
146 client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::demote:")?;
147 self.node_impl.demote(client, input_values)
148 }
149}
150
151impl binder::Interface for DiceNode {}
152
153impl IDiceNode for DiceNode {
154 fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> BinderResult<Signature> {
155 map_or_log_err(self.sign(input_values, message), Ok)
156 }
157 fn getAttestationChain(&self, input_values: &[BinderInputValues]) -> BinderResult<Bcc> {
158 map_or_log_err(self.get_attestation_chain(input_values), Ok)
159 }
160 fn derive(&self, input_values: &[BinderInputValues]) -> BinderResult<BccHandover> {
161 map_or_log_err(self.derive(input_values), Ok)
162 }
163 fn demote(&self, input_values: &[BinderInputValues]) -> BinderResult<()> {
164 map_or_log_err(self.demote(input_values), Ok)
165 }
166}