xref: /aosp_15_r20/system/security/keystore2/src/authorization.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
1 // 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 
15 //! This module implements IKeystoreAuthorization AIDL interface.
16 
17 use crate::error::anyhow_error_to_cstring;
18 use crate::error::Error as KeystoreError;
19 use crate::globals::{DB, ENFORCEMENTS, LEGACY_IMPORTER, SUPER_KEY};
20 use crate::ks_err;
21 use crate::permission::KeystorePerm;
22 use crate::utils::{check_keystore_permission, watchdog as wd};
23 use aconfig_android_hardware_biometrics_rust;
24 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
25     HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType,
26 };
27 use android_security_authorization::aidl::android::security::authorization::{
28     AuthorizationTokens::AuthorizationTokens, IKeystoreAuthorization::BnKeystoreAuthorization,
29     IKeystoreAuthorization::IKeystoreAuthorization, ResponseCode::ResponseCode,
30 };
31 use android_security_authorization::binder::{
32     BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status as BinderStatus,
33     Strong,
34 };
35 use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode as KsResponseCode;
36 use anyhow::{Context, Result};
37 use keystore2_crypto::Password;
38 use keystore2_selinux as selinux;
39 use std::ffi::CString;
40 
41 /// This is the Authorization error type, it wraps binder exceptions and the
42 /// Authorization ResponseCode
43 #[derive(Debug, thiserror::Error, PartialEq, Eq)]
44 pub enum Error {
45     /// Wraps an IKeystoreAuthorization response code as defined by
46     /// android.security.authorization AIDL interface specification.
47     #[error("Error::Rc({0:?})")]
48     Rc(ResponseCode),
49     /// Wraps a Binder exception code other than a service specific exception.
50     #[error("Binder exception code {0:?}, {1:?}")]
51     Binder(ExceptionCode, i32),
52 }
53 
54 /// Translate an error into a service specific exception, logging along the way.
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`.
into_logged_binder(e: anyhow::Error) -> BinderStatus64 pub fn into_logged_binder(e: anyhow::Error) -> BinderStatus {
65     log::error!("{:#?}", e);
66     let root_cause = e.root_cause();
67     if let Some(KeystoreError::Rc(ks_rcode)) = root_cause.downcast_ref::<KeystoreError>() {
68         let rc = match *ks_rcode {
69             // Although currently keystore2/ResponseCode.aidl and
70             // authorization/ResponseCode.aidl share the same integer values for the
71             // common response codes, this may deviate in the future, hence the
72             // conversion here.
73             KsResponseCode::SYSTEM_ERROR => ResponseCode::SYSTEM_ERROR.0,
74             KsResponseCode::KEY_NOT_FOUND => ResponseCode::KEY_NOT_FOUND.0,
75             KsResponseCode::VALUE_CORRUPTED => ResponseCode::VALUE_CORRUPTED.0,
76             KsResponseCode::INVALID_ARGUMENT => ResponseCode::INVALID_ARGUMENT.0,
77             // If the code paths of IKeystoreAuthorization aidl's methods happen to return
78             // other error codes from KsResponseCode in the future, they should be converted
79             // as well.
80             _ => ResponseCode::SYSTEM_ERROR.0,
81         };
82         BinderStatus::new_service_specific_error(rc, anyhow_error_to_cstring(&e).as_deref())
83     } else {
84         let rc = match root_cause.downcast_ref::<Error>() {
85             Some(Error::Rc(rcode)) => rcode.0,
86             Some(Error::Binder(_, _)) => ResponseCode::SYSTEM_ERROR.0,
87             None => match root_cause.downcast_ref::<selinux::Error>() {
88                 Some(selinux::Error::PermissionDenied) => ResponseCode::PERMISSION_DENIED.0,
89                 _ => ResponseCode::SYSTEM_ERROR.0,
90             },
91         };
92         BinderStatus::new_service_specific_error(rc, anyhow_error_to_cstring(&e).as_deref())
93     }
94 }
95 
96 /// This struct is defined to implement the aforementioned AIDL interface.
97 /// As of now, it is an empty struct.
98 pub struct AuthorizationManager;
99 
100 impl AuthorizationManager {
101     /// Create a new instance of Keystore Authorization service.
new_native_binder() -> Result<Strong<dyn IKeystoreAuthorization>>102     pub fn new_native_binder() -> Result<Strong<dyn IKeystoreAuthorization>> {
103         Ok(BnKeystoreAuthorization::new_binder(
104             Self,
105             BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
106         ))
107     }
108 
add_auth_token(&self, auth_token: &HardwareAuthToken) -> Result<()>109     fn add_auth_token(&self, auth_token: &HardwareAuthToken) -> Result<()> {
110         // Check keystore permission.
111         check_keystore_permission(KeystorePerm::AddAuth)
112             .context(ks_err!("caller missing AddAuth permissions"))?;
113 
114         log::info!(
115             "add_auth_token(challenge={}, userId={}, authId={}, authType={:#x}, timestamp={}ms)",
116             auth_token.challenge,
117             auth_token.userId,
118             auth_token.authenticatorId,
119             auth_token.authenticatorType.0,
120             auth_token.timestamp.milliSeconds,
121         );
122 
123         ENFORCEMENTS.add_auth_token(auth_token.clone());
124         Ok(())
125     }
126 
on_device_unlocked(&self, user_id: i32, password: Option<Password>) -> Result<()>127     fn on_device_unlocked(&self, user_id: i32, password: Option<Password>) -> Result<()> {
128         log::info!(
129             "on_device_unlocked(user_id={}, password.is_some()={})",
130             user_id,
131             password.is_some(),
132         );
133         check_keystore_permission(KeystorePerm::Unlock)
134             .context(ks_err!("caller missing Unlock permissions"))?;
135         ENFORCEMENTS.set_device_locked(user_id, false);
136 
137         let mut skm = SUPER_KEY.write().unwrap();
138         if let Some(password) = password {
139             DB.with(|db| {
140                 skm.unlock_user(&mut db.borrow_mut(), &LEGACY_IMPORTER, user_id as u32, &password)
141             })
142             .context(ks_err!("Unlock with password."))
143         } else {
144             DB.with(|db| skm.try_unlock_user_with_biometric(&mut db.borrow_mut(), user_id as u32))
145                 .context(ks_err!("try_unlock_user_with_biometric failed user_id={user_id}"))
146         }
147     }
148 
on_device_locked( &self, user_id: i32, unlocking_sids: &[i64], weak_unlock_enabled: bool, ) -> Result<()>149     fn on_device_locked(
150         &self,
151         user_id: i32,
152         unlocking_sids: &[i64],
153         weak_unlock_enabled: bool,
154     ) -> Result<()> {
155         log::info!(
156             "on_device_locked(user_id={}, unlocking_sids={:?}, weak_unlock_enabled={})",
157             user_id,
158             unlocking_sids,
159             weak_unlock_enabled
160         );
161         check_keystore_permission(KeystorePerm::Lock)
162             .context(ks_err!("caller missing Lock permission"))?;
163         ENFORCEMENTS.set_device_locked(user_id, true);
164         let mut skm = SUPER_KEY.write().unwrap();
165         DB.with(|db| {
166             skm.lock_unlocked_device_required_keys(
167                 &mut db.borrow_mut(),
168                 user_id as u32,
169                 unlocking_sids,
170                 weak_unlock_enabled,
171             );
172         });
173         Ok(())
174     }
175 
on_weak_unlock_methods_expired(&self, user_id: i32) -> Result<()>176     fn on_weak_unlock_methods_expired(&self, user_id: i32) -> Result<()> {
177         log::info!("on_weak_unlock_methods_expired(user_id={})", user_id);
178         check_keystore_permission(KeystorePerm::Lock)
179             .context(ks_err!("caller missing Lock permission"))?;
180         SUPER_KEY.write().unwrap().wipe_plaintext_unlocked_device_required_keys(user_id as u32);
181         Ok(())
182     }
183 
on_non_lskf_unlock_methods_expired(&self, user_id: i32) -> Result<()>184     fn on_non_lskf_unlock_methods_expired(&self, user_id: i32) -> Result<()> {
185         log::info!("on_non_lskf_unlock_methods_expired(user_id={})", user_id);
186         check_keystore_permission(KeystorePerm::Lock)
187             .context(ks_err!("caller missing Lock permission"))?;
188         SUPER_KEY.write().unwrap().wipe_all_unlocked_device_required_keys(user_id as u32);
189         Ok(())
190     }
191 
get_auth_tokens_for_credstore( &self, challenge: i64, secure_user_id: i64, auth_token_max_age_millis: i64, ) -> Result<AuthorizationTokens>192     fn get_auth_tokens_for_credstore(
193         &self,
194         challenge: i64,
195         secure_user_id: i64,
196         auth_token_max_age_millis: i64,
197     ) -> Result<AuthorizationTokens> {
198         // Check permission. Function should return if this failed. Therefore having '?' at the end
199         // is very important.
200         check_keystore_permission(KeystorePerm::GetAuthToken)
201             .context(ks_err!("caller missing GetAuthToken permission"))?;
202 
203         // If the challenge is zero, return error
204         if challenge == 0 {
205             return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT))
206                 .context(ks_err!("Challenge can not be zero."));
207         }
208         // Obtain the auth token and the timestamp token from the enforcement module.
209         let (auth_token, ts_token) =
210             ENFORCEMENTS.get_auth_tokens(challenge, secure_user_id, auth_token_max_age_millis)?;
211         Ok(AuthorizationTokens { authToken: auth_token, timestampToken: ts_token })
212     }
213 
get_last_auth_time( &self, secure_user_id: i64, auth_types: &[HardwareAuthenticatorType], ) -> Result<i64>214     fn get_last_auth_time(
215         &self,
216         secure_user_id: i64,
217         auth_types: &[HardwareAuthenticatorType],
218     ) -> Result<i64> {
219         // Check keystore permission.
220         check_keystore_permission(KeystorePerm::GetLastAuthTime)
221             .context(ks_err!("caller missing GetLastAuthTime permission"))?;
222 
223         let mut max_time: i64 = -1;
224         for auth_type in auth_types.iter() {
225             if let Some(time) = ENFORCEMENTS.get_last_auth_time(secure_user_id, *auth_type) {
226                 if time.milliseconds() > max_time {
227                     max_time = time.milliseconds();
228                 }
229             }
230         }
231 
232         if max_time >= 0 {
233             Ok(max_time)
234         } else {
235             Err(Error::Rc(ResponseCode::NO_AUTH_TOKEN_FOUND))
236                 .context(ks_err!("No auth token found"))
237         }
238     }
239 }
240 
241 impl Interface for AuthorizationManager {}
242 
243 impl IKeystoreAuthorization for AuthorizationManager {
addAuthToken(&self, auth_token: &HardwareAuthToken) -> BinderResult<()>244     fn addAuthToken(&self, auth_token: &HardwareAuthToken) -> BinderResult<()> {
245         let _wp = wd::watch("IKeystoreAuthorization::addAuthToken");
246         self.add_auth_token(auth_token).map_err(into_logged_binder)
247     }
248 
onDeviceUnlocked(&self, user_id: i32, password: Option<&[u8]>) -> BinderResult<()>249     fn onDeviceUnlocked(&self, user_id: i32, password: Option<&[u8]>) -> BinderResult<()> {
250         let _wp = wd::watch("IKeystoreAuthorization::onDeviceUnlocked");
251         self.on_device_unlocked(user_id, password.map(|pw| pw.into())).map_err(into_logged_binder)
252     }
253 
onDeviceLocked( &self, user_id: i32, unlocking_sids: &[i64], weak_unlock_enabled: bool, ) -> BinderResult<()>254     fn onDeviceLocked(
255         &self,
256         user_id: i32,
257         unlocking_sids: &[i64],
258         weak_unlock_enabled: bool,
259     ) -> BinderResult<()> {
260         let _wp = wd::watch("IKeystoreAuthorization::onDeviceLocked");
261         self.on_device_locked(user_id, unlocking_sids, weak_unlock_enabled)
262             .map_err(into_logged_binder)
263     }
264 
onWeakUnlockMethodsExpired(&self, user_id: i32) -> BinderResult<()>265     fn onWeakUnlockMethodsExpired(&self, user_id: i32) -> BinderResult<()> {
266         let _wp = wd::watch("IKeystoreAuthorization::onWeakUnlockMethodsExpired");
267         self.on_weak_unlock_methods_expired(user_id).map_err(into_logged_binder)
268     }
269 
onNonLskfUnlockMethodsExpired(&self, user_id: i32) -> BinderResult<()>270     fn onNonLskfUnlockMethodsExpired(&self, user_id: i32) -> BinderResult<()> {
271         let _wp = wd::watch("IKeystoreAuthorization::onNonLskfUnlockMethodsExpired");
272         self.on_non_lskf_unlock_methods_expired(user_id).map_err(into_logged_binder)
273     }
274 
getAuthTokensForCredStore( &self, challenge: i64, secure_user_id: i64, auth_token_max_age_millis: i64, ) -> binder::Result<AuthorizationTokens>275     fn getAuthTokensForCredStore(
276         &self,
277         challenge: i64,
278         secure_user_id: i64,
279         auth_token_max_age_millis: i64,
280     ) -> binder::Result<AuthorizationTokens> {
281         let _wp = wd::watch("IKeystoreAuthorization::getAuthTokensForCredStore");
282         self.get_auth_tokens_for_credstore(challenge, secure_user_id, auth_token_max_age_millis)
283             .map_err(into_logged_binder)
284     }
285 
getLastAuthTime( &self, secure_user_id: i64, auth_types: &[HardwareAuthenticatorType], ) -> binder::Result<i64>286     fn getLastAuthTime(
287         &self,
288         secure_user_id: i64,
289         auth_types: &[HardwareAuthenticatorType],
290     ) -> binder::Result<i64> {
291         if aconfig_android_hardware_biometrics_rust::last_authentication_time() {
292             self.get_last_auth_time(secure_user_id, auth_types).map_err(into_logged_binder)
293         } else {
294             Err(BinderStatus::new_service_specific_error(
295                 ResponseCode::PERMISSION_DENIED.0,
296                 Some(CString::new("Feature is not enabled.").unwrap().as_c_str()),
297             ))
298         }
299     }
300 }
301