}
@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 {
_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();
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
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;
}
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;
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);
}
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;
}
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");
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;
}
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");
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 {
}
}
- 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);
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;
}
return response;
-
}
@Override
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
}
}
+ /*
+ * 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 addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+ waitForReady();
+
+ try {
+ 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 changeUserKey(int userId, int serialNumber,
- byte[] token, byte[] oldSecret, byte[] newSecret) {
+ public void fixateNewestUserKeyAuth(int userId) {
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", "fixate_newest_user_key_auth", userId);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}