summaryrefslogtreecommitdiff
path: root/keystore2
diff options
context:
space:
mode:
Diffstat (limited to 'keystore2')
-rw-r--r--keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl67
-rw-r--r--keystore2/aidl/android/security/authorization/LockScreenEvent.aidl22
-rw-r--r--keystore2/src/authorization.rs117
-rw-r--r--keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs8
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);
}