• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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