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