diff options
Diffstat (limited to 'keystore2')
4 files changed, 79 insertions, 135 deletions
diff --git a/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl b/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl index b31a51e2..54894ff5 100644 --- a/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl +++ b/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl @@ -16,7 +16,6 @@ package android.security.authorization; import android.hardware.security.keymint.HardwareAuthToken; import android.hardware.security.keymint.HardwareAuthenticatorType; -import android.security.authorization.LockScreenEvent; import android.security.authorization.AuthorizationTokens; // TODO: mark the interface with @SensitiveData when the annotation is ready (b/176110256). @@ -41,41 +40,51 @@ interface IKeystoreAuthorization { void addAuthToken(in HardwareAuthToken authToken); /** - * Unlocks the keystore for the given user id. + * Tells Keystore that the device is now unlocked for a user. Requires the 'Unlock' permission. * - * Callers require 'Unlock' permission. + * This method makes Keystore start allowing the use of the given user's keys that require an + * unlocked device, following the device boot or an earlier call to onDeviceLocked() which + * disabled the use of such keys. In addition, once per boot, this method must be called with a + * password before keys that require user authentication can be used. * - * Super-Encryption Key: - * When the device is unlocked (and password is non-null), Keystore stores in memory - * a super-encryption key derived from the password that protects UNLOCKED_DEVICE_REQUIRED - * keys; this key is wiped from memory when the device is locked. + * To enable access to these keys, this method attempts to decrypt and cache the user's super + * keys. If the password is given, i.e. if the unlock occurred using an LSKF-equivalent + * mechanism, then both the AfterFirstUnlock and UnlockedDeviceRequired super keys are decrypted + * (if not already done). Otherwise, only the UnlockedDeviceRequired super keys are decrypted, + * and this only works if a valid HardwareAuthToken has been added to Keystore for one of the + * 'unlockingSids' that was passed to the last call to onDeviceLocked() for the user. * - * If unlockingSids is non-empty on lock, then before the super-encryption key is wiped from - * memory, a copy of it is stored in memory encrypted with a fresh AES key. This key is then - * imported into KM, tagged such that it can be used given a valid, recent auth token for any - * of the unlockingSids. + * ## Error conditions: + * `ResponseCode::PERMISSION_DENIED` - if the caller does not have the 'Unlock' permission. + * `ResponseCode::VALUE_CORRUPTED` - if a super key can not be decrypted. + * `ResponseCode::KEY_NOT_FOUND` - if a super key is not found. + * `ResponseCode::SYSTEM_ERROR` - if another error occurred. * - * Options for unlock: - * - If the password is non-null, the super-encryption key is re-derived as above. - * - If the password is null, then if a suitable auth token to access the encrypted - * Super-encryption key stored in KM has been sent to keystore (via addAuthToken), the - * encrypted super-encryption key is recovered so that UNLOCKED_DEVICE_REQUIRED keys can - * be used once again. - * - If neither of these are met, then the operation fails. + * @param userId The Android user ID of the user for which the device is now unlocked + * @param password If available, a secret derived from the user's synthetic password + */ + void onDeviceUnlocked(in int userId, in @nullable byte[] password); + + /** + * Tells Keystore that the device is now locked for a user. Requires the 'Lock' permission. + * + * This method makes Keystore stop allowing the use of the given user's keys that require an + * unlocked device. This is done through logical enforcement, and also through cryptographic + * enforcement by wiping the UnlockedDeviceRequired super keys from memory. + * + * unlockingSids is the list of SIDs of the user's biometrics with which the device may be + * unlocked later. If this list is non-empty, then instead of completely wiping the + * UnlockedDeviceRequired super keys from memory, this method re-encrypts these super keys with + * a new AES key that is imported into KeyMint and bound to the given SIDs. This allows the + * UnlockedDeviceRequired super keys to be recovered if the device is unlocked with a biometric. * * ## Error conditions: - * `ResponseCode::PERMISSION_DENIED` - if the callers do not have the 'Unlock' permission. - * `ResponseCode::SYSTEM_ERROR` - if failed to perform lock/unlock operations due to various - * `ResponseCode::VALUE_CORRUPTED` - if the super key can not be decrypted. - * `ResponseCode::KEY_NOT_FOUND` - if the super key is not found. - * - * @param lockScreenEvent whether the lock screen locked or unlocked - * @param userId android user id - * @param password synthetic password derived from the user's LSKF, must be null on lock - * @param unlockingSids list of biometric SIDs for this user, ignored on unlock + * `ResponseCode::PERMISSION_DENIED` - if the caller does not have the 'Lock' permission. + * + * @param userId The Android user ID of the user for which the device is now locked + * @param unlockingSids The user's list of biometric SIDs */ - void onLockScreenEvent(in LockScreenEvent lockScreenEvent, in int userId, - in @nullable byte[] password, in @nullable long[] unlockingSids); + void onDeviceLocked(in int userId, in long[] unlockingSids); /** * Allows Credstore to retrieve a HardwareAuthToken and a TimestampToken. diff --git a/keystore2/aidl/android/security/authorization/LockScreenEvent.aidl b/keystore2/aidl/android/security/authorization/LockScreenEvent.aidl deleted file mode 100644 index c7553a27..00000000 --- a/keystore2/aidl/android/security/authorization/LockScreenEvent.aidl +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2020, The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package android.security.authorization; - -/** @hide */ -@Backing(type="int") -enum LockScreenEvent { - UNLOCK = 0, - LOCK = 1, -} diff --git a/keystore2/src/authorization.rs b/keystore2/src/authorization.rs index 7416b7f2..36f94e99 100644 --- a/keystore2/src/authorization.rs +++ b/keystore2/src/authorization.rs @@ -26,8 +26,7 @@ use android_hardware_security_keymint::aidl::android::hardware::security::keymin }; use android_security_authorization::aidl::android::security::authorization::{ AuthorizationTokens::AuthorizationTokens, IKeystoreAuthorization::BnKeystoreAuthorization, - IKeystoreAuthorization::IKeystoreAuthorization, LockScreenEvent::LockScreenEvent, - ResponseCode::ResponseCode, + IKeystoreAuthorization::IKeystoreAuthorization, ResponseCode::ResponseCode, }; use android_security_authorization::binder::{ BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status as BinderStatus, @@ -144,71 +143,43 @@ impl AuthorizationManager { Ok(()) } - fn on_lock_screen_event( - &self, - lock_screen_event: LockScreenEvent, - user_id: i32, - password: Option<Password>, - unlocking_sids: Option<&[i64]>, - ) -> Result<()> { + fn on_device_unlocked(&self, user_id: i32, password: Option<Password>) -> Result<()> { log::info!( - "on_lock_screen_event({:?}, user_id={:?}, password.is_some()={}, unlocking_sids={:?})", - lock_screen_event, + "on_device_unlocked(user_id={}, password.is_some()={})", user_id, password.is_some(), - unlocking_sids ); - match (lock_screen_event, password) { - (LockScreenEvent::UNLOCK, Some(password)) => { - // This corresponds to the unlock() method in legacy keystore API. - // check permission - check_keystore_permission(KeystorePerm::Unlock) - .context(ks_err!("Unlock with password."))?; - ENFORCEMENTS.set_device_locked(user_id, false); - - let mut skm = SUPER_KEY.write().unwrap(); + check_keystore_permission(KeystorePerm::Unlock).context(ks_err!("Unlock."))?; + ENFORCEMENTS.set_device_locked(user_id, false); - DB.with(|db| { - skm.unlock_user( - &mut db.borrow_mut(), - &LEGACY_IMPORTER, - user_id as u32, - &password, - ) - }) - .context(ks_err!("Unlock with password."))?; - Ok(()) - } - (LockScreenEvent::UNLOCK, None) => { - check_keystore_permission(KeystorePerm::Unlock).context(ks_err!("Unlock."))?; - ENFORCEMENTS.set_device_locked(user_id, false); - let mut skm = SUPER_KEY.write().unwrap(); - DB.with(|db| { - skm.try_unlock_user_with_biometric(&mut db.borrow_mut(), user_id as u32) - }) - .context(ks_err!("try_unlock_user_with_biometric failed"))?; - Ok(()) - } - (LockScreenEvent::LOCK, None) => { - check_keystore_permission(KeystorePerm::Lock).context(ks_err!("Lock"))?; - ENFORCEMENTS.set_device_locked(user_id, true); - let mut skm = SUPER_KEY.write().unwrap(); - DB.with(|db| { - skm.lock_unlocked_device_required_keys( - &mut db.borrow_mut(), - user_id as u32, - unlocking_sids.unwrap_or(&[]), - ); - }); - Ok(()) - } - _ => { - // Any other combination is not supported. - Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!("Unknown event.")) - } + let mut skm = SUPER_KEY.write().unwrap(); + if let Some(password) = password { + DB.with(|db| { + skm.unlock_user(&mut db.borrow_mut(), &LEGACY_IMPORTER, user_id as u32, &password) + }) + .context(ks_err!("Unlock with password.")) + } else { + DB.with(|db| skm.try_unlock_user_with_biometric(&mut db.borrow_mut(), user_id as u32)) + .context(ks_err!("try_unlock_user_with_biometric failed")) } } + fn on_device_locked(&self, user_id: i32, unlocking_sids: &[i64]) -> Result<()> { + log::info!("on_device_locked(user_id={}, unlocking_sids={:?})", user_id, unlocking_sids); + + check_keystore_permission(KeystorePerm::Lock).context(ks_err!("Lock"))?; + ENFORCEMENTS.set_device_locked(user_id, true); + let mut skm = SUPER_KEY.write().unwrap(); + DB.with(|db| { + skm.lock_unlocked_device_required_keys( + &mut db.borrow_mut(), + user_id as u32, + unlocking_sids, + ); + }); + Ok(()) + } + fn get_auth_tokens_for_credstore( &self, challenge: i64, @@ -264,26 +235,14 @@ impl IKeystoreAuthorization for AuthorizationManager { map_or_log_err(self.add_auth_token(auth_token), Ok) } - fn onLockScreenEvent( - &self, - lock_screen_event: LockScreenEvent, - user_id: i32, - password: Option<&[u8]>, - unlocking_sids: Option<&[i64]>, - ) -> BinderResult<()> { - let _wp = - wd::watch_millis_with("IKeystoreAuthorization::onLockScreenEvent", 500, move || { - format!("lock event: {}", lock_screen_event.0) - }); - map_or_log_err( - self.on_lock_screen_event( - lock_screen_event, - user_id, - password.map(|pw| pw.into()), - unlocking_sids, - ), - Ok, - ) + fn onDeviceUnlocked(&self, user_id: i32, password: Option<&[u8]>) -> BinderResult<()> { + let _wp = wd::watch_millis("IKeystoreAuthorization::onDeviceUnlocked", 500); + map_or_log_err(self.on_device_unlocked(user_id, password.map(|pw| pw.into())), Ok) + } + + fn onDeviceLocked(&self, user_id: i32, unlocking_sids: &[i64]) -> BinderResult<()> { + let _wp = wd::watch_millis("IKeystoreAuthorization::onDeviceLocked", 500); + map_or_log_err(self.on_device_locked(user_id, unlocking_sids), Ok) } fn getAuthTokensForCredStore( diff --git a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs index faf954a2..c2cd3adf 100644 --- a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs +++ b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs @@ -28,7 +28,7 @@ use android_system_keystore2::aidl::android::system::keystore2::{ use android_security_maintenance::aidl::android::security::maintenance::IKeystoreMaintenance::IKeystoreMaintenance; use android_security_authorization::aidl::android::security::authorization::{ - IKeystoreAuthorization::IKeystoreAuthorization, LockScreenEvent::LockScreenEvent, + IKeystoreAuthorization::IKeystoreAuthorization, }; use keystore2::key_parameter::KeyParameter as KsKeyparameter; @@ -229,8 +229,7 @@ fn keystore2_encrypted_characteristics() -> anyhow::Result<()> { keystore2_restart_service(); let auth_service = get_authorization(); - match auth_service.onLockScreenEvent(LockScreenEvent::UNLOCK, 99, Some(PASSWORD), None) - { + match auth_service.onDeviceUnlocked(99, Some(PASSWORD)) { Ok(result) => { println!("Unlock Result: {:?}", result); } @@ -487,8 +486,7 @@ fn keystore2_encrypted_certificates() -> anyhow::Result<()> { keystore2_restart_service(); let auth_service = get_authorization(); - match auth_service.onLockScreenEvent(LockScreenEvent::UNLOCK, 98, Some(PASSWORD), None) - { + match auth_service.onDeviceUnlocked(98, Some(PASSWORD)) { Ok(result) => { println!("Unlock Result: {:?}", result); } |