blob: ec1edff875d5f6c74078977f7494083674742583 [file] [log] [blame]
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +00001// Copyright 2020, 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
Hasini Gunasinghe0e161452021-01-27 19:34:37 +000015//! This module implements IKeystoreAuthorization AIDL interface.
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +000016
Hasini Gunasinghea020b532021-01-07 21:42:35 +000017use crate::error::Error as KeystoreError;
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +000018use crate::globals::{ENFORCEMENTS, SUPER_KEY, DB, LEGACY_MIGRATOR};
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +000019use crate::permission::KeystorePerm;
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +000020use crate::super_key::UserState;
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +000021use crate::utils::check_keystore_permission;
22use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Hasini Gunasingheda895552021-01-27 19:34:37 +000023 HardwareAuthToken::HardwareAuthToken,
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +000024};
Andrew Walbrande45c8b2021-04-13 14:42:38 +000025use android_security_authorization::binder::{BinderFeatures,ExceptionCode, Interface, Result as BinderResult,
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +000026 Strong, Status as BinderStatus};
27use android_security_authorization::aidl::android::security::authorization::{
28 IKeystoreAuthorization::BnKeystoreAuthorization, IKeystoreAuthorization::IKeystoreAuthorization,
29 LockScreenEvent::LockScreenEvent, AuthorizationTokens::AuthorizationTokens,
30 ResponseCode::ResponseCode,
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +000031};
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +000032use android_system_keystore2::aidl::android::system::keystore2::{
33 ResponseCode::ResponseCode as KsResponseCode };
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +000034use anyhow::{Context, Result};
Paul Crowleyf61fee72021-03-17 14:38:44 -070035use keystore2_crypto::Password;
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +000036use keystore2_selinux as selinux;
37
38/// This is the Authorization error type, it wraps binder exceptions and the
39/// Authorization ResponseCode
40#[derive(Debug, thiserror::Error, PartialEq)]
41pub enum Error {
42 /// Wraps an IKeystoreAuthorization response code as defined by
43 /// android.security.authorization AIDL interface specification.
44 #[error("Error::Rc({0:?})")]
45 Rc(ResponseCode),
46 /// Wraps a Binder exception code other than a service specific exception.
47 #[error("Binder exception code {0:?}, {1:?}")]
48 Binder(ExceptionCode, i32),
49}
50
51/// This function should be used by authorization service calls to translate error conditions
52/// into service specific exceptions.
53///
54/// All error conditions get logged by this function.
55///
56/// `Error::Rc(x)` variants get mapped onto a service specific error code of `x`.
57/// Certain response codes may be returned from keystore/ResponseCode.aidl by the keystore2 modules,
58/// which are then converted to the corresponding response codes of android.security.authorization
59/// AIDL interface specification.
60///
61/// `selinux::Error::perm()` is mapped on `ResponseCode::PERMISSION_DENIED`.
62///
63/// All non `Error` error conditions get mapped onto ResponseCode::SYSTEM_ERROR`.
64///
65/// `handle_ok` will be called if `result` is `Ok(value)` where `value` will be passed
66/// as argument to `handle_ok`. `handle_ok` must generate a `BinderResult<T>`, but it
67/// typically returns Ok(value).
68pub fn map_or_log_err<T, U, F>(result: Result<U>, handle_ok: F) -> BinderResult<T>
69where
70 F: FnOnce(U) -> BinderResult<T>,
71{
72 result.map_or_else(
73 |e| {
74 log::error!("{:#?}", e);
75 let root_cause = e.root_cause();
76 if let Some(KeystoreError::Rc(ks_rcode)) = root_cause.downcast_ref::<KeystoreError>() {
77 let rc = match *ks_rcode {
78 // Although currently keystore2/ResponseCode.aidl and
79 // authorization/ResponseCode.aidl share the same integer values for the
80 // common response codes, this may deviate in the future, hence the
81 // conversion here.
82 KsResponseCode::SYSTEM_ERROR => ResponseCode::SYSTEM_ERROR.0,
83 KsResponseCode::KEY_NOT_FOUND => ResponseCode::KEY_NOT_FOUND.0,
84 KsResponseCode::VALUE_CORRUPTED => ResponseCode::VALUE_CORRUPTED.0,
85 KsResponseCode::INVALID_ARGUMENT => ResponseCode::INVALID_ARGUMENT.0,
86 // If the code paths of IKeystoreAuthorization aidl's methods happen to return
87 // other error codes from KsResponseCode in the future, they should be converted
88 // as well.
89 _ => ResponseCode::SYSTEM_ERROR.0,
90 };
91 return Err(BinderStatus::new_service_specific_error(rc, None));
92 }
93 let rc = match root_cause.downcast_ref::<Error>() {
94 Some(Error::Rc(rcode)) => rcode.0,
95 Some(Error::Binder(_, _)) => ResponseCode::SYSTEM_ERROR.0,
96 None => match root_cause.downcast_ref::<selinux::Error>() {
97 Some(selinux::Error::PermissionDenied) => ResponseCode::PERMISSION_DENIED.0,
98 _ => ResponseCode::SYSTEM_ERROR.0,
99 },
100 };
101 Err(BinderStatus::new_service_specific_error(rc, None))
102 },
103 handle_ok,
104 )
105}
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000106
107/// This struct is defined to implement the aforementioned AIDL interface.
108/// As of now, it is an empty struct.
109pub struct AuthorizationManager;
110
111impl AuthorizationManager {
112 /// Create a new instance of Keystore Authorization service.
Stephen Crane221bbb52020-12-16 15:52:10 -0800113 pub fn new_native_binder() -> Result<Strong<dyn IKeystoreAuthorization>> {
Andrew Walbrande45c8b2021-04-13 14:42:38 +0000114 Ok(BnKeystoreAuthorization::new_binder(
115 Self,
116 BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
117 ))
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000118 }
119
120 fn add_auth_token(&self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700121 // Check keystore permission.
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000122 check_keystore_permission(KeystorePerm::add_auth()).context("In add_auth_token.")?;
123
Hasini Gunasingheda895552021-01-27 19:34:37 +0000124 ENFORCEMENTS.add_auth_token(auth_token.clone())?;
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000125 Ok(())
126 }
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000127
128 fn on_lock_screen_event(
129 &self,
130 lock_screen_event: LockScreenEvent,
131 user_id: i32,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700132 password: Option<Password>,
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000133 ) -> Result<()> {
134 match (lock_screen_event, password) {
Paul Crowleyf61fee72021-03-17 14:38:44 -0700135 (LockScreenEvent::UNLOCK, Some(password)) => {
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700136 // This corresponds to the unlock() method in legacy keystore API.
137 // check permission
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000138 check_keystore_permission(KeystorePerm::unlock())
139 .context("In on_lock_screen_event: Unlock with password.")?;
140 ENFORCEMENTS.set_device_locked(user_id, false);
Paul Crowley7a658392021-03-18 17:08:20 -0700141
142 DB.with(|db| {
143 SUPER_KEY.unlock_screen_lock_bound_key(
144 &mut db.borrow_mut(),
145 user_id as u32,
146 &password,
147 )
148 })
149 .context("In on_lock_screen_event: unlock_screen_lock_bound_key failed")?;
150
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000151 // Unlock super key.
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000152 if let UserState::Uninitialized = DB
153 .with(|db| {
154 UserState::get_with_password_unlock(
155 &mut db.borrow_mut(),
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000156 &LEGACY_MIGRATOR,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000157 &SUPER_KEY,
158 user_id as u32,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700159 &password,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000160 )
161 })
162 .context("In on_lock_screen_event: Unlock with password.")?
163 {
164 log::info!(
165 "In on_lock_screen_event. Trying to unlock when LSKF is uninitialized."
166 );
167 }
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000168
169 Ok(())
170 }
171 (LockScreenEvent::UNLOCK, None) => {
172 check_keystore_permission(KeystorePerm::unlock())
173 .context("In on_lock_screen_event: Unlock.")?;
174 ENFORCEMENTS.set_device_locked(user_id, false);
175 Ok(())
176 }
177 (LockScreenEvent::LOCK, None) => {
178 check_keystore_permission(KeystorePerm::lock())
179 .context("In on_lock_screen_event: Lock")?;
180 ENFORCEMENTS.set_device_locked(user_id, true);
Paul Crowley7a658392021-03-18 17:08:20 -0700181 SUPER_KEY.lock_screen_lock_bound_key(user_id as u32);
182
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000183 Ok(())
184 }
185 _ => {
186 // Any other combination is not supported.
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000187 Err(Error::Rc(ResponseCode::INVALID_ARGUMENT))
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000188 .context("In on_lock_screen_event: Unknown event.")
189 }
190 }
191 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000192
193 fn get_auth_tokens_for_credstore(
194 &self,
195 challenge: i64,
196 secure_user_id: i64,
197 auth_token_max_age_millis: i64,
198 ) -> Result<AuthorizationTokens> {
199 // Check permission. Function should return if this failed. Therefore having '?' at the end
200 // is very important.
201 check_keystore_permission(KeystorePerm::get_auth_token())
202 .context("In get_auth_tokens_for_credstore.")?;
203
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700204 // If the challenge is zero, return error
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000205 if challenge == 0 {
206 return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT))
207 .context("In get_auth_tokens_for_credstore. Challenge can not be zero.");
208 }
209 // Obtain the auth token and the timestamp token from the enforcement module.
210 let (auth_token, ts_token) =
211 ENFORCEMENTS.get_auth_tokens(challenge, secure_user_id, auth_token_max_age_millis)?;
212 Ok(AuthorizationTokens { authToken: auth_token, timestampToken: ts_token })
213 }
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000214}
215
216impl Interface for AuthorizationManager {}
217
218impl IKeystoreAuthorization for AuthorizationManager {
219 fn addAuthToken(&self, auth_token: &HardwareAuthToken) -> BinderResult<()> {
220 map_or_log_err(self.add_auth_token(auth_token), Ok)
221 }
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000222
223 fn onLockScreenEvent(
224 &self,
225 lock_screen_event: LockScreenEvent,
226 user_id: i32,
227 password: Option<&[u8]>,
228 ) -> BinderResult<()> {
Paul Crowleyf61fee72021-03-17 14:38:44 -0700229 map_or_log_err(
230 self.on_lock_screen_event(lock_screen_event, user_id, password.map(|pw| pw.into())),
231 Ok,
232 )
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000233 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000234
235 fn getAuthTokensForCredStore(
236 &self,
237 challenge: i64,
238 secure_user_id: i64,
239 auth_token_max_age_millis: i64,
240 ) -> binder::public_api::Result<AuthorizationTokens> {
241 map_or_log_err(
242 self.get_auth_tokens_for_credstore(
243 challenge,
244 secure_user_id,
245 auth_token_max_age_millis,
246 ),
247 Ok,
248 )
249 }
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000250}