blob: 9594977e31a39dd08fffbfc4f82d5c1868a75fed [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 Danisevskis41e67192021-11-05 09:00:19 -070019mod proxy_node_hal;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070020mod resident_node;
21
Janis Danisevskis41e67192021-11-05 09:00:19 -070022pub use crate::proxy_node_hal::ProxyNodeHal;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070023pub use crate::resident_node::ResidentNode;
24use 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};
28use android_security_dice::aidl::android::security::dice::{
Janis Danisevskis99652dc2021-10-20 15:59:33 -070029 IDiceMaintenance::BnDiceMaintenance, IDiceMaintenance::IDiceMaintenance, IDiceNode::BnDiceNode,
30 IDiceNode::IDiceNode, ResponseCode::ResponseCode,
Janis Danisevskisc51dff82021-10-20 09:51:16 -070031};
32use anyhow::{Context, Result};
Stephen Crane23cf7242022-01-19 17:49:46 +000033use binder::{BinderFeatures, Result as BinderResult, Strong, ThreadState};
Janis Danisevskisc51dff82021-10-20 09:51:16 -070034pub use diced_open_dice_cbor as dice;
35use error::{map_or_log_err, Error};
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -070036use keystore2_selinux as selinux;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070037use libc::uid_t;
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -070038use permission::Permission;
Janis Danisevskisc51dff82021-10-20 09:51:16 -070039use 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.
45pub trait DiceNodeImpl {
46 /// Signs the message using the effective dice artifacts and Ed25519Pure.
47 fn sign(
48 &self,
49 client: BinderInputValues,
50 input_values: &[BinderInputValues],
51 message: &[u8],
52 ) -> Result<Signature>;
53 /// Returns the effective attestation chain.
54 fn get_attestation_chain(
55 &self,
56 client: BinderInputValues,
57 input_values: &[BinderInputValues],
58 ) -> Result<Bcc>;
59 /// Returns the effective dice artifacts.
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.
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.
73 fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()>;
74}
75
76/// Wraps a DiceNodeImpl and implements the actual IDiceNode AIDL API.
77pub struct DiceNode {
78 node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
79}
80
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -070081/// 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.
84pub 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
Janis Danisevskisc51dff82021-10-20 09:51:16 -070099fn client_input_values(uid: uid_t) -> Result<BinderInputValues> {
100 Ok(BinderInputValues {
Janis Danisevskisd9513f42021-12-16 17:15:13 -0800101 codeHash: [0; dice::HASH_SIZE],
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700102 config: BinderConfig {
103 desc: dice::bcc::format_config_descriptor(Some(&format!("{}", uid)), None, true)
104 .context("In client_input_values: failed to format config descriptor")?,
105 },
Janis Danisevskisd9513f42021-12-16 17:15:13 -0800106 authorityHash: [0; dice::HASH_SIZE],
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700107 authorityDescriptor: None,
Janis Danisevskisd9513f42021-12-16 17:15:13 -0800108 hidden: [0; dice::HIDDEN_SIZE],
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700109 mode: Mode::NORMAL,
110 })
111}
112
113impl 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.
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
127 fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> Result<Signature> {
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -0700128 check_caller_permission(Permission::UseSign).context("In DiceNode::sign:")?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700129 let client =
130 client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::sign:")?;
131 self.node_impl.sign(client, input_values, message)
132 }
133 fn get_attestation_chain(&self, input_values: &[BinderInputValues]) -> Result<Bcc> {
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -0700134 check_caller_permission(Permission::GetAttestationChain)
135 .context("In DiceNode::get_attestation_chain:")?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700136 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 }
140 fn derive(&self, input_values: &[BinderInputValues]) -> Result<BccHandover> {
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -0700141 check_caller_permission(Permission::Derive).context("In DiceNode::derive:")?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700142 let client =
143 client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::extend:")?;
144 self.node_impl.derive(client, input_values)
145 }
146 fn demote(&self, input_values: &[BinderInputValues]) -> Result<()> {
Janis Danisevskis2ded9cb2021-10-20 08:39:30 -0700147 check_caller_permission(Permission::Demote).context("In DiceNode::demote:")?;
Janis Danisevskisc51dff82021-10-20 09:51:16 -0700148 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
154impl binder::Interface for DiceNode {}
155
156impl IDiceNode for DiceNode {
157 fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> BinderResult<Signature> {
158 map_or_log_err(self.sign(input_values, message), Ok)
159 }
160 fn getAttestationChain(&self, input_values: &[BinderInputValues]) -> BinderResult<Bcc> {
161 map_or_log_err(self.get_attestation_chain(input_values), Ok)
162 }
163 fn derive(&self, input_values: &[BinderInputValues]) -> BinderResult<BccHandover> {
164 map_or_log_err(self.derive(input_values), Ok)
165 }
166 fn demote(&self, input_values: &[BinderInputValues]) -> BinderResult<()> {
167 map_or_log_err(self.demote(input_values), Ok)
168 }
169}
Janis Danisevskis99652dc2021-10-20 15:59:33 -0700170
171/// Wraps a DiceNodeImpl and implements the IDiceMaintenance AIDL API.
172pub struct DiceMaintenance {
173 node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
174}
175
176impl 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.
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
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
197impl binder::Interface for DiceMaintenance {}
198
199impl IDiceMaintenance for DiceMaintenance {
200 fn demoteSelf(&self, input_values: &[BinderInputValues]) -> BinderResult<()> {
201 map_or_log_err(self.demote_self(input_values), Ok)
202 }
203}