Merge "Split Keystore's onLockScreenEvent into onDevice{Unlocked,Locked}" into main
This commit is contained in:
commit
a2609f539d
4 changed files with 80 additions and 136 deletions
|
@ -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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* ## 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.
|
||||
* `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.
|
||||
*
|
||||
* @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
|
||||
* @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 onLockScreenEvent(in LockScreenEvent lockScreenEvent, in int userId,
|
||||
in @nullable byte[] password, in @nullable long[] unlockingSids);
|
||||
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 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 onDeviceLocked(in int userId, in long[] unlockingSids);
|
||||
|
||||
/**
|
||||
* Allows Credstore to retrieve a HardwareAuthToken and a TimestampToken.
|
||||
|
|
|
@ -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,
|
||||
}
|
|
@ -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);
|
||||
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.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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue