blob: 7416b7f25cb973afd477bde7acccdd0f805d1158 [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
Janis Danisevskisea03cff2021-12-16 08:10:17 -080017use crate::error::anyhow_error_to_cstring;
James Willcoxd215da82023-10-03 21:31:31 +000018use crate::error::Error as KeystoreError;
19use crate::globals::{DB, ENFORCEMENTS, LEGACY_IMPORTER, SUPER_KEY};
20use crate::ks_err;
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +000021use crate::permission::KeystorePerm;
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +000022use crate::utils::{check_keystore_permission, watchdog as wd};
James Willcoxd215da82023-10-03 21:31:31 +000023use aconfig_android_hardware_biometrics_rust;
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +000024use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
James Willcoxd215da82023-10-03 21:31:31 +000025 HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType,
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +000026};
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +000027use android_security_authorization::aidl::android::security::authorization::{
James Willcoxd215da82023-10-03 21:31:31 +000028 AuthorizationTokens::AuthorizationTokens, IKeystoreAuthorization::BnKeystoreAuthorization,
29 IKeystoreAuthorization::IKeystoreAuthorization, LockScreenEvent::LockScreenEvent,
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +000030 ResponseCode::ResponseCode,
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +000031};
James Willcoxd215da82023-10-03 21:31:31 +000032use android_security_authorization::binder::{
33 BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status as BinderStatus,
34 Strong,
35};
36use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode as KsResponseCode;
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +000037use anyhow::{Context, Result};
Paul Crowleyf61fee72021-03-17 14:38:44 -070038use keystore2_crypto::Password;
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +000039use keystore2_selinux as selinux;
James Willcoxd215da82023-10-03 21:31:31 +000040use std::ffi::CString;
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +000041
42/// This is the Authorization error type, it wraps binder exceptions and the
43/// Authorization ResponseCode
Chris Wailes263de9f2022-08-11 15:00:51 -070044#[derive(Debug, thiserror::Error, PartialEq, Eq)]
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +000045pub enum Error {
46 /// Wraps an IKeystoreAuthorization response code as defined by
47 /// android.security.authorization AIDL interface specification.
48 #[error("Error::Rc({0:?})")]
49 Rc(ResponseCode),
50 /// Wraps a Binder exception code other than a service specific exception.
51 #[error("Binder exception code {0:?}, {1:?}")]
52 Binder(ExceptionCode, i32),
53}
54
55/// This function should be used by authorization service calls to translate error conditions
56/// into service specific exceptions.
57///
58/// All error conditions get logged by this function.
59///
60/// `Error::Rc(x)` variants get mapped onto a service specific error code of `x`.
61/// Certain response codes may be returned from keystore/ResponseCode.aidl by the keystore2 modules,
62/// which are then converted to the corresponding response codes of android.security.authorization
63/// AIDL interface specification.
64///
65/// `selinux::Error::perm()` is mapped on `ResponseCode::PERMISSION_DENIED`.
66///
67/// All non `Error` error conditions get mapped onto ResponseCode::SYSTEM_ERROR`.
68///
69/// `handle_ok` will be called if `result` is `Ok(value)` where `value` will be passed
70/// as argument to `handle_ok`. `handle_ok` must generate a `BinderResult<T>`, but it
71/// typically returns Ok(value).
72pub fn map_or_log_err<T, U, F>(result: Result<U>, handle_ok: F) -> BinderResult<T>
73where
74 F: FnOnce(U) -> BinderResult<T>,
75{
76 result.map_or_else(
77 |e| {
78 log::error!("{:#?}", e);
79 let root_cause = e.root_cause();
80 if let Some(KeystoreError::Rc(ks_rcode)) = root_cause.downcast_ref::<KeystoreError>() {
81 let rc = match *ks_rcode {
82 // Although currently keystore2/ResponseCode.aidl and
83 // authorization/ResponseCode.aidl share the same integer values for the
84 // common response codes, this may deviate in the future, hence the
85 // conversion here.
86 KsResponseCode::SYSTEM_ERROR => ResponseCode::SYSTEM_ERROR.0,
87 KsResponseCode::KEY_NOT_FOUND => ResponseCode::KEY_NOT_FOUND.0,
88 KsResponseCode::VALUE_CORRUPTED => ResponseCode::VALUE_CORRUPTED.0,
89 KsResponseCode::INVALID_ARGUMENT => ResponseCode::INVALID_ARGUMENT.0,
90 // If the code paths of IKeystoreAuthorization aidl's methods happen to return
91 // other error codes from KsResponseCode in the future, they should be converted
92 // as well.
93 _ => ResponseCode::SYSTEM_ERROR.0,
94 };
Janis Danisevskisea03cff2021-12-16 08:10:17 -080095 return Err(BinderStatus::new_service_specific_error(
96 rc,
97 anyhow_error_to_cstring(&e).as_deref(),
98 ));
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +000099 }
100 let rc = match root_cause.downcast_ref::<Error>() {
101 Some(Error::Rc(rcode)) => rcode.0,
102 Some(Error::Binder(_, _)) => ResponseCode::SYSTEM_ERROR.0,
103 None => match root_cause.downcast_ref::<selinux::Error>() {
104 Some(selinux::Error::PermissionDenied) => ResponseCode::PERMISSION_DENIED.0,
105 _ => ResponseCode::SYSTEM_ERROR.0,
106 },
107 };
Janis Danisevskisea03cff2021-12-16 08:10:17 -0800108 Err(BinderStatus::new_service_specific_error(
109 rc,
110 anyhow_error_to_cstring(&e).as_deref(),
111 ))
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000112 },
113 handle_ok,
114 )
115}
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000116
117/// This struct is defined to implement the aforementioned AIDL interface.
118/// As of now, it is an empty struct.
119pub struct AuthorizationManager;
120
121impl AuthorizationManager {
122 /// Create a new instance of Keystore Authorization service.
Stephen Crane221bbb52020-12-16 15:52:10 -0800123 pub fn new_native_binder() -> Result<Strong<dyn IKeystoreAuthorization>> {
Andrew Walbrande45c8b2021-04-13 14:42:38 +0000124 Ok(BnKeystoreAuthorization::new_binder(
125 Self,
126 BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
127 ))
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000128 }
129
130 fn add_auth_token(&self, auth_token: &HardwareAuthToken) -> Result<()> {
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700131 // Check keystore permission.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000132 check_keystore_permission(KeystorePerm::AddAuth).context(ks_err!())?;
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000133
David Drysdalebf2d72f2023-06-15 13:38:36 +0100134 log::info!(
135 "add_auth_token(challenge={}, userId={}, authId={}, authType={:#x}, timestamp={}ms)",
136 auth_token.challenge,
137 auth_token.userId,
138 auth_token.authenticatorId,
139 auth_token.authenticatorType.0,
140 auth_token.timestamp.milliSeconds,
141 );
142
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700143 ENFORCEMENTS.add_auth_token(auth_token.clone());
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000144 Ok(())
145 }
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000146
147 fn on_lock_screen_event(
148 &self,
149 lock_screen_event: LockScreenEvent,
150 user_id: i32,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700151 password: Option<Password>,
Paul Crowley618869e2021-04-08 20:30:54 -0700152 unlocking_sids: Option<&[i64]>,
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000153 ) -> Result<()> {
Paul Crowley618869e2021-04-08 20:30:54 -0700154 log::info!(
155 "on_lock_screen_event({:?}, user_id={:?}, password.is_some()={}, unlocking_sids={:?})",
156 lock_screen_event,
157 user_id,
158 password.is_some(),
159 unlocking_sids
160 );
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000161 match (lock_screen_event, password) {
Paul Crowleyf61fee72021-03-17 14:38:44 -0700162 (LockScreenEvent::UNLOCK, Some(password)) => {
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700163 // This corresponds to the unlock() method in legacy keystore API.
164 // check permission
Janis Danisevskisa916d992021-10-19 15:46:09 -0700165 check_keystore_permission(KeystorePerm::Unlock)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000166 .context(ks_err!("Unlock with password."))?;
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000167 ENFORCEMENTS.set_device_locked(user_id, false);
Paul Crowley7a658392021-03-18 17:08:20 -0700168
Janis Danisevskis0fd25a62022-01-04 19:53:37 -0800169 let mut skm = SUPER_KEY.write().unwrap();
170
Paul Crowley7a658392021-03-18 17:08:20 -0700171 DB.with(|db| {
Nathan Huckleberry7dfe8182023-04-04 20:41:01 +0000172 skm.unlock_user(
Paul Crowley7a658392021-03-18 17:08:20 -0700173 &mut db.borrow_mut(),
Nathan Huckleberry7dfe8182023-04-04 20:41:01 +0000174 &LEGACY_IMPORTER,
Paul Crowley7a658392021-03-18 17:08:20 -0700175 user_id as u32,
176 &password,
177 )
178 })
Nathan Huckleberry7dfe8182023-04-04 20:41:01 +0000179 .context(ks_err!("Unlock with password."))?;
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000180 Ok(())
181 }
182 (LockScreenEvent::UNLOCK, None) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000183 check_keystore_permission(KeystorePerm::Unlock).context(ks_err!("Unlock."))?;
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000184 ENFORCEMENTS.set_device_locked(user_id, false);
Janis Danisevskis0fd25a62022-01-04 19:53:37 -0800185 let mut skm = SUPER_KEY.write().unwrap();
Paul Crowley618869e2021-04-08 20:30:54 -0700186 DB.with(|db| {
Janis Danisevskis0fd25a62022-01-04 19:53:37 -0800187 skm.try_unlock_user_with_biometric(&mut db.borrow_mut(), user_id as u32)
Paul Crowley618869e2021-04-08 20:30:54 -0700188 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000189 .context(ks_err!("try_unlock_user_with_biometric failed"))?;
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000190 Ok(())
191 }
192 (LockScreenEvent::LOCK, None) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000193 check_keystore_permission(KeystorePerm::Lock).context(ks_err!("Lock"))?;
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000194 ENFORCEMENTS.set_device_locked(user_id, true);
Janis Danisevskis0fd25a62022-01-04 19:53:37 -0800195 let mut skm = SUPER_KEY.write().unwrap();
Paul Crowley618869e2021-04-08 20:30:54 -0700196 DB.with(|db| {
Eric Biggersb1f641d2023-10-18 01:54:18 +0000197 skm.lock_unlocked_device_required_keys(
Paul Crowley618869e2021-04-08 20:30:54 -0700198 &mut db.borrow_mut(),
199 user_id as u32,
200 unlocking_sids.unwrap_or(&[]),
201 );
202 });
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000203 Ok(())
204 }
205 _ => {
206 // Any other combination is not supported.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000207 Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!("Unknown event."))
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000208 }
209 }
210 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000211
212 fn get_auth_tokens_for_credstore(
213 &self,
214 challenge: i64,
215 secure_user_id: i64,
216 auth_token_max_age_millis: i64,
217 ) -> Result<AuthorizationTokens> {
218 // Check permission. Function should return if this failed. Therefore having '?' at the end
219 // is very important.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000220 check_keystore_permission(KeystorePerm::GetAuthToken).context(ks_err!("GetAuthToken"))?;
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000221
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700222 // If the challenge is zero, return error
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000223 if challenge == 0 {
224 return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000225 .context(ks_err!("Challenge can not be zero."));
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000226 }
227 // Obtain the auth token and the timestamp token from the enforcement module.
228 let (auth_token, ts_token) =
229 ENFORCEMENTS.get_auth_tokens(challenge, secure_user_id, auth_token_max_age_millis)?;
230 Ok(AuthorizationTokens { authToken: auth_token, timestampToken: ts_token })
231 }
James Willcoxd215da82023-10-03 21:31:31 +0000232
233 fn get_last_auth_time(
234 &self,
235 secure_user_id: i64,
236 auth_types: &[HardwareAuthenticatorType],
237 ) -> Result<i64> {
238 // Check keystore permission.
239 check_keystore_permission(KeystorePerm::GetLastAuthTime).context(ks_err!())?;
240
241 let mut max_time: i64 = -1;
242 for auth_type in auth_types.iter() {
243 if let Some(time) = ENFORCEMENTS.get_last_auth_time(secure_user_id, *auth_type) {
244 if time.milliseconds() > max_time {
245 max_time = time.milliseconds();
246 }
247 }
248 }
249
250 if max_time >= 0 {
251 Ok(max_time)
252 } else {
253 Err(Error::Rc(ResponseCode::NO_AUTH_TOKEN_FOUND))
254 .context(ks_err!("No auth token found"))
255 }
256 }
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000257}
258
259impl Interface for AuthorizationManager {}
260
261impl IKeystoreAuthorization for AuthorizationManager {
262 fn addAuthToken(&self, auth_token: &HardwareAuthToken) -> BinderResult<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000263 let _wp = wd::watch_millis("IKeystoreAuthorization::addAuthToken", 500);
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000264 map_or_log_err(self.add_auth_token(auth_token), Ok)
265 }
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000266
267 fn onLockScreenEvent(
268 &self,
269 lock_screen_event: LockScreenEvent,
270 user_id: i32,
271 password: Option<&[u8]>,
Paul Crowley618869e2021-04-08 20:30:54 -0700272 unlocking_sids: Option<&[i64]>,
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000273 ) -> BinderResult<()> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000274 let _wp =
275 wd::watch_millis_with("IKeystoreAuthorization::onLockScreenEvent", 500, move || {
276 format!("lock event: {}", lock_screen_event.0)
277 });
Paul Crowleyf61fee72021-03-17 14:38:44 -0700278 map_or_log_err(
Paul Crowley618869e2021-04-08 20:30:54 -0700279 self.on_lock_screen_event(
280 lock_screen_event,
281 user_id,
282 password.map(|pw| pw.into()),
283 unlocking_sids,
284 ),
Paul Crowleyf61fee72021-03-17 14:38:44 -0700285 Ok,
286 )
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000287 }
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000288
289 fn getAuthTokensForCredStore(
290 &self,
291 challenge: i64,
292 secure_user_id: i64,
293 auth_token_max_age_millis: i64,
Stephen Crane23cf7242022-01-19 17:49:46 +0000294 ) -> binder::Result<AuthorizationTokens> {
Hasini Gunasinghe5a893e82021-05-05 14:32:32 +0000295 let _wp = wd::watch_millis("IKeystoreAuthorization::getAuthTokensForCredStore", 500);
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000296 map_or_log_err(
297 self.get_auth_tokens_for_credstore(
298 challenge,
299 secure_user_id,
300 auth_token_max_age_millis,
301 ),
302 Ok,
303 )
304 }
James Willcoxd215da82023-10-03 21:31:31 +0000305
306 fn getLastAuthTime(
307 &self,
308 secure_user_id: i64,
309 auth_types: &[HardwareAuthenticatorType],
310 ) -> binder::Result<i64> {
311 if aconfig_android_hardware_biometrics_rust::last_authentication_time() {
312 map_or_log_err(self.get_last_auth_time(secure_user_id, auth_types), Ok)
313 } else {
314 Err(BinderStatus::new_service_specific_error(
315 ResponseCode::PERMISSION_DENIED.0,
316 Some(CString::new("Feature is not enabled.").unwrap().as_c_str()),
317 ))
318 }
319 }
Janis Danisevskis9f10a6a2021-01-18 16:45:21 +0000320}