blob: 9ebee285d5ccbdf5402feea0922febe8abb5c1e7 [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::{
Janis Danisevskis99652dc2021-10-20 15:59:33 -070027 IDiceMaintenance::BnDiceMaintenance, IDiceMaintenance::IDiceMaintenance, IDiceNode::BnDiceNode,
28 IDiceNode::IDiceNode, ResponseCode::ResponseCode,
Janis Danisevskisc51dff82021-10-20 09:51:16 -070029};
30use anyhow::{Context, Result};
31use binder::{public_api::Result as BinderResult, BinderFeatures, Strong, ThreadState};
32pub use diced_open_dice_cbor as dice;
33use error::{map_or_log_err, Error};
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -070034use keystore2_selinux as selinux;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070035use libc::uid_t;
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -070036use permission::Permission;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070037use std::sync::Arc;
38
39/// A DiceNode backend implementation.
40/// All functions except demote_self derive effective dice artifacts staring from
41/// this node and iterating through `{ [client | demotion path], input_values }`
42/// in ascending order.
43pub trait DiceNodeImpl {
44 /// Signs the message using the effective dice artifacts and Ed25519Pure.
45 fn sign(
46 &self,
47 client: BinderInputValues,
48 input_values: &[BinderInputValues],
49 message: &[u8],
50 ) -> Result<Signature>;
51 /// Returns the effective attestation chain.
52 fn get_attestation_chain(
53 &self,
54 client: BinderInputValues,
55 input_values: &[BinderInputValues],
56 ) -> Result<Bcc>;
57 /// Returns the effective dice artifacts.
58 fn derive(
59 &self,
60 client: BinderInputValues,
61 input_values: &[BinderInputValues],
62 ) -> Result<BccHandover>;
63 /// Adds [ `client` | `input_values` ] to the demotion path of the given client.
64 /// This changes the effective dice artifacts for all subsequent API calls of the
65 /// given client.
66 fn demote(&self, client: BinderInputValues, input_values: &[BinderInputValues]) -> Result<()>;
67 /// This demotes the implementation itself. I.e. a resident node would replace its resident
68 /// with the effective artifacts derived using `input_values`. A proxy node would
69 /// simply call `demote` on its parent node. This is not reversible and changes
70 /// the effective dice artifacts of all clients.
71 fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()>;
72}
73
74/// Wraps a DiceNodeImpl and implements the actual IDiceNode AIDL API.
75pub struct DiceNode {
76 node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
77}
78
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -070079/// This function uses its namesake in the permission module and in
80/// combination with with_calling_sid from the binder crate to check
81/// if the caller has the given keystore permission.
82pub fn check_caller_permission<T: selinux::ClassPermission>(perm: T) -> Result<()> {
83 ThreadState::with_calling_sid(|calling_sid| {
84 let target_context =
85 selinux::getcon().context("In check_caller_permission: getcon failed.")?;
86
87 selinux::check_permission(
88 calling_sid.ok_or(Error::Rc(ResponseCode::SYSTEM_ERROR)).context(
89 "In check_keystore_permission: Cannot check permission without calling_sid.",
90 )?,
91 &target_context,
92 perm,
93 )
94 })
95}
96
Janis Danisevskisc51dff82021-10-20 09:51:16 -070097fn client_input_values(uid: uid_t) -> Result<BinderInputValues> {
98 Ok(BinderInputValues {
99 codeHash: vec![0; dice::HASH_SIZE],
100 config: BinderConfig {
101 desc: dice::bcc::format_config_descriptor(Some(&format!("{}", uid)), None, true)
102 .context("In client_input_values: failed to format config descriptor")?,
103 },
104 authorityHash: vec![0; dice::HASH_SIZE],
105 authorityDescriptor: None,
106 hidden: vec![0; dice::HIDDEN_SIZE],
107 mode: Mode::NORMAL,
108 })
109}
110
111impl DiceNode {
112 /// Constructs an instance of DiceNode, wraps it with a BnDiceNode object and
113 /// returns a strong pointer to the binder. The result can be used to register
114 /// the service with service manager.
115 pub fn new_as_binder(
116 node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
117 ) -> Result<Strong<dyn IDiceNode>> {
118 let result = BnDiceNode::new_binder(
119 DiceNode { node_impl },
120 BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
121 );
122 Ok(result)
123 }
124
125 fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> Result<Signature> {
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -0700126 check_caller_permission(Permission::UseSign).context("In DiceNode::sign:")?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700127 let client =
128 client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::sign:")?;
129 self.node_impl.sign(client, input_values, message)
130 }
131 fn get_attestation_chain(&self, input_values: &[BinderInputValues]) -> Result<Bcc> {
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -0700132 check_caller_permission(Permission::GetAttestationChain)
133 .context("In DiceNode::get_attestation_chain:")?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700134 let client = client_input_values(ThreadState::get_calling_uid())
135 .context("In DiceNode::get_attestation_chain:")?;
136 self.node_impl.get_attestation_chain(client, input_values)
137 }
138 fn derive(&self, input_values: &[BinderInputValues]) -> Result<BccHandover> {
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -0700139 check_caller_permission(Permission::Derive).context("In DiceNode::derive:")?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700140 let client =
141 client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::extend:")?;
142 self.node_impl.derive(client, input_values)
143 }
144 fn demote(&self, input_values: &[BinderInputValues]) -> Result<()> {
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -0700145 check_caller_permission(Permission::Demote).context("In DiceNode::demote:")?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700146 let client =
147 client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::demote:")?;
148 self.node_impl.demote(client, input_values)
149 }
150}
151
152impl binder::Interface for DiceNode {}
153
154impl IDiceNode for DiceNode {
155 fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> BinderResult<Signature> {
156 map_or_log_err(self.sign(input_values, message), Ok)
157 }
158 fn getAttestationChain(&self, input_values: &[BinderInputValues]) -> BinderResult<Bcc> {
159 map_or_log_err(self.get_attestation_chain(input_values), Ok)
160 }
161 fn derive(&self, input_values: &[BinderInputValues]) -> BinderResult<BccHandover> {
162 map_or_log_err(self.derive(input_values), Ok)
163 }
164 fn demote(&self, input_values: &[BinderInputValues]) -> BinderResult<()> {
165 map_or_log_err(self.demote(input_values), Ok)
166 }
167}
Janis Danisevskis99652dc2021-10-20 15:59:33 -0700168
169/// Wraps a DiceNodeImpl and implements the IDiceMaintenance AIDL API.
170pub struct DiceMaintenance {
171 node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
172}
173
174impl DiceMaintenance {
175 /// Constructs an instance of DiceMaintenance, wraps it with a BnDiceMaintenance object and
176 /// returns a strong pointer to the binder. The result can be used to register the service
177 /// with service manager.
178 pub fn new_as_binder(
179 node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
180 ) -> Result<Strong<dyn IDiceMaintenance>> {
181 let result = BnDiceMaintenance::new_binder(
182 DiceMaintenance { node_impl },
183 BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
184 );
185 Ok(result)
186 }
187
188 fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()> {
189 check_caller_permission(Permission::DemoteSelf)
190 .context("In DiceMaintenance::demote_self:")?;
191 self.node_impl.demote_self(input_values)
192 }
193}
194
195impl binder::Interface for DiceMaintenance {}
196
197impl IDiceMaintenance for DiceMaintenance {
198 fn demoteSelf(&self, input_values: &[BinderInputValues]) -> BinderResult<()> {
199 map_or_log_err(self.demote_self(input_values), Ok)
200 }
201}