Merge "Two phases to set the password for disk encryption" into nyc-dev
This commit is contained in:
@@ -1233,8 +1233,8 @@ public interface IMountService extends IInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeUserKey(int userId, int serialNumber,
|
||||
byte[] token, byte[] oldSecret, byte[] newSecret) throws RemoteException {
|
||||
public void addUserKeyAuth(int userId, int serialNumber,
|
||||
byte[] token, byte[] secret) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
try {
|
||||
@@ -1242,9 +1242,23 @@ public interface IMountService extends IInterface {
|
||||
_data.writeInt(userId);
|
||||
_data.writeInt(serialNumber);
|
||||
_data.writeByteArray(token);
|
||||
_data.writeByteArray(oldSecret);
|
||||
_data.writeByteArray(newSecret);
|
||||
mRemote.transact(Stub.TRANSACTION_changeUserKey, _data, _reply, 0);
|
||||
_data.writeByteArray(secret);
|
||||
mRemote.transact(Stub.TRANSACTION_addUserKeyAuth, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixateNewestUserKeyAuth(int userId) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeInt(userId);
|
||||
mRemote.transact(Stub.TRANSACTION_fixateNewestUserKeyAuth, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
@@ -1489,7 +1503,9 @@ public interface IMountService extends IInterface {
|
||||
|
||||
static final int TRANSACTION_mountAppFuse = IBinder.FIRST_CALL_TRANSACTION + 69;
|
||||
|
||||
static final int TRANSACTION_changeUserKey = IBinder.FIRST_CALL_TRANSACTION + 70;
|
||||
static final int TRANSACTION_addUserKeyAuth = IBinder.FIRST_CALL_TRANSACTION + 70;
|
||||
|
||||
static final int TRANSACTION_fixateNewestUserKeyAuth = IBinder.FIRST_CALL_TRANSACTION + 71;
|
||||
|
||||
/**
|
||||
* Cast an IBinder object into an IMountService interface, generating a
|
||||
@@ -2069,14 +2085,20 @@ public interface IMountService extends IInterface {
|
||||
reply.writeNoException();
|
||||
return true;
|
||||
}
|
||||
case TRANSACTION_changeUserKey: {
|
||||
case TRANSACTION_addUserKeyAuth: {
|
||||
data.enforceInterface(DESCRIPTOR);
|
||||
int userId = data.readInt();
|
||||
int serialNumber = data.readInt();
|
||||
byte[] token = data.createByteArray();
|
||||
byte[] oldSecret = data.createByteArray();
|
||||
byte[] newSecret = data.createByteArray();
|
||||
changeUserKey(userId, serialNumber, token, oldSecret, newSecret);
|
||||
byte[] secret = data.createByteArray();
|
||||
addUserKeyAuth(userId, serialNumber, token, secret);
|
||||
reply.writeNoException();
|
||||
return true;
|
||||
}
|
||||
case TRANSACTION_fixateNewestUserKeyAuth: {
|
||||
data.enforceInterface(DESCRIPTOR);
|
||||
int userId = data.readInt();
|
||||
fixateNewestUserKeyAuth(userId);
|
||||
reply.writeNoException();
|
||||
return true;
|
||||
}
|
||||
@@ -2452,8 +2474,9 @@ public interface IMountService extends IInterface {
|
||||
public void createUserKey(int userId, int serialNumber, boolean ephemeral)
|
||||
throws RemoteException;
|
||||
public void destroyUserKey(int userId) throws RemoteException;
|
||||
public void changeUserKey(int userId, int serialNumber,
|
||||
byte[] token, byte[] oldSecret, byte[] newSecret) throws RemoteException;
|
||||
public void addUserKeyAuth(int userId, int serialNumber,
|
||||
byte[] token, byte[] secret) throws RemoteException;
|
||||
public void fixateNewestUserKeyAuth(int userId) throws RemoteException;
|
||||
|
||||
public void unlockUserKey(int userId, int serialNumber,
|
||||
byte[] token, byte[] secret) throws RemoteException;
|
||||
|
||||
@@ -790,10 +790,11 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
if (isSecure) {
|
||||
tieManagedProfileLockIfNecessary(managedUserId, null);
|
||||
} else {
|
||||
clearUserKeyProtection(managedUserId);
|
||||
getGateKeeperService().clearSecureUserId(managedUserId);
|
||||
mStorage.writePatternHash(null, managedUserId);
|
||||
setKeystorePassword(null, managedUserId);
|
||||
clearUserKeyProtection(managedUserId);
|
||||
fixateNewestUserKeyAuth(managedUserId);
|
||||
mStorage.removeChildProfileLock(managedUserId);
|
||||
removeKeystoreProfileKey(managedUserId);
|
||||
}
|
||||
@@ -828,10 +829,11 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
byte[] currentHandle = getCurrentHandle(userId);
|
||||
|
||||
if (pattern == null) {
|
||||
clearUserKeyProtection(userId);
|
||||
getGateKeeperService().clearSecureUserId(userId);
|
||||
mStorage.writePatternHash(null, userId);
|
||||
setKeystorePassword(null, userId);
|
||||
clearUserKeyProtection(userId);
|
||||
fixateNewestUserKeyAuth(userId);
|
||||
onUserLockChanged(userId);
|
||||
return;
|
||||
}
|
||||
@@ -861,8 +863,12 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
|
||||
byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);
|
||||
if (enrolledHandle != null) {
|
||||
CredentialHash willStore
|
||||
= new CredentialHash(enrolledHandle, CredentialHash.VERSION_GATEKEEPER);
|
||||
setUserKeyProtection(userId, pattern,
|
||||
doVerifyPattern(pattern, willStore, true, 0, userId));
|
||||
mStorage.writePatternHash(enrolledHandle, userId);
|
||||
setUserKeyProtection(userId, pattern, verifyPattern(pattern, 0, userId));
|
||||
fixateNewestUserKeyAuth(userId);
|
||||
onUserLockChanged(userId);
|
||||
} else {
|
||||
throw new RemoteException("Failed to enroll pattern");
|
||||
@@ -885,10 +891,11 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
throws RemoteException {
|
||||
byte[] currentHandle = getCurrentHandle(userId);
|
||||
if (password == null) {
|
||||
clearUserKeyProtection(userId);
|
||||
getGateKeeperService().clearSecureUserId(userId);
|
||||
mStorage.writePasswordHash(null, userId);
|
||||
setKeystorePassword(null, userId);
|
||||
clearUserKeyProtection(userId);
|
||||
fixateNewestUserKeyAuth(userId);
|
||||
onUserLockChanged(userId);
|
||||
return;
|
||||
}
|
||||
@@ -916,8 +923,12 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
|
||||
byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);
|
||||
if (enrolledHandle != null) {
|
||||
CredentialHash willStore
|
||||
= new CredentialHash(enrolledHandle, CredentialHash.VERSION_GATEKEEPER);
|
||||
setUserKeyProtection(userId, password,
|
||||
doVerifyPassword(password, willStore, true, 0, userId));
|
||||
mStorage.writePasswordHash(enrolledHandle, userId);
|
||||
setUserKeyProtection(userId, password, verifyPassword(password, 0, userId));
|
||||
fixateNewestUserKeyAuth(userId);
|
||||
onUserLockChanged(userId);
|
||||
} else {
|
||||
throw new RemoteException("Failed to enroll password");
|
||||
@@ -1022,11 +1033,11 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
if (token == null) {
|
||||
throw new RemoteException("Empty payload verifying a credential we just set");
|
||||
}
|
||||
changeUserKey(userId, token, secretFromCredential(credential));
|
||||
addUserKeyAuth(userId, token, secretFromCredential(credential));
|
||||
}
|
||||
|
||||
private void clearUserKeyProtection(int userId) throws RemoteException {
|
||||
changeUserKey(userId, null, null);
|
||||
addUserKeyAuth(userId, null, null);
|
||||
}
|
||||
|
||||
private static byte[] secretFromCredential(String credential) throws RemoteException {
|
||||
@@ -1045,18 +1056,23 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void changeUserKey(int userId, byte[] token, byte[] secret)
|
||||
private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
|
||||
throws RemoteException {
|
||||
final UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
|
||||
final IMountService mountService = getMountService();
|
||||
final long callingId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mountService.changeUserKey(userId, userInfo.serialNumber, token, null, secret);
|
||||
mountService.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingId);
|
||||
}
|
||||
}
|
||||
|
||||
private void fixateNewestUserKeyAuth(int userId)
|
||||
throws RemoteException {
|
||||
getMountService().fixateNewestUserKeyAuth(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VerifyCredentialResponse checkPattern(String pattern, int userId) throws RemoteException {
|
||||
return doVerifyPattern(pattern, false, 0, userId);
|
||||
@@ -1072,6 +1088,11 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
long challenge, int userId) throws RemoteException {
|
||||
checkPasswordReadPermission(userId);
|
||||
CredentialHash storedHash = mStorage.readPatternHash(userId);
|
||||
return doVerifyPattern(pattern, storedHash, hasChallenge, challenge, userId);
|
||||
}
|
||||
|
||||
private VerifyCredentialResponse doVerifyPattern(String pattern, CredentialHash storedHash,
|
||||
boolean hasChallenge, long challenge, int userId) throws RemoteException {
|
||||
boolean shouldReEnrollBaseZero = storedHash != null && storedHash.isBaseZeroPattern;
|
||||
|
||||
String patternToVerify;
|
||||
@@ -1109,7 +1130,6 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1159,6 +1179,11 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
long challenge, int userId) throws RemoteException {
|
||||
checkPasswordReadPermission(userId);
|
||||
CredentialHash storedHash = mStorage.readPasswordHash(userId);
|
||||
return doVerifyPassword(password, storedHash, hasChallenge, challenge, userId);
|
||||
}
|
||||
|
||||
private VerifyCredentialResponse doVerifyPassword(String password, CredentialHash storedHash,
|
||||
boolean hasChallenge, long challenge, int userId) throws RemoteException {
|
||||
return verifyCredential(userId, storedHash, password, hasChallenge, challenge,
|
||||
new CredentialUtil() {
|
||||
@Override
|
||||
|
||||
@@ -74,7 +74,7 @@ class LockSettingsStorage {
|
||||
|
||||
private SparseArray<Integer> mStoredCredentialType;
|
||||
|
||||
class CredentialHash {
|
||||
static class CredentialHash {
|
||||
static final int TYPE_NONE = -1;
|
||||
static final int TYPE_PATTERN = 1;
|
||||
static final int TYPE_PASSWORD = 2;
|
||||
|
||||
@@ -2816,15 +2816,36 @@ class MountService extends IMountService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add this token/secret pair to the set of ways we can recover a disk encryption key.
|
||||
* Changing the token/secret for a disk encryption key is done in two phases: first, adding
|
||||
* a new token/secret pair with this call, then delting all other pairs with
|
||||
* fixateNewestUserKeyAuth. This allows other places where a credential is used, such as
|
||||
* Gatekeeper, to be updated between the two calls.
|
||||
*/
|
||||
@Override
|
||||
public void changeUserKey(int userId, int serialNumber,
|
||||
byte[] token, byte[] oldSecret, byte[] newSecret) {
|
||||
public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
|
||||
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
|
||||
waitForReady();
|
||||
|
||||
try {
|
||||
mCryptConnector.execute("cryptfs", "change_user_key", userId, serialNumber,
|
||||
encodeBytes(token), encodeBytes(oldSecret), encodeBytes(newSecret));
|
||||
mCryptConnector.execute("cryptfs", "add_user_key_auth", userId, serialNumber,
|
||||
encodeBytes(token), encodeBytes(secret));
|
||||
} catch (NativeDaemonConnectorException e) {
|
||||
throw e.rethrowAsParcelableException();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete all disk encryption token/secret pairs except the most recently added one
|
||||
*/
|
||||
@Override
|
||||
public void fixateNewestUserKeyAuth(int userId) {
|
||||
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
|
||||
waitForReady();
|
||||
|
||||
try {
|
||||
mCryptConnector.execute("cryptfs", "fixate_newest_user_key_auth", userId);
|
||||
} catch (NativeDaemonConnectorException e) {
|
||||
throw e.rethrowAsParcelableException();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user