Merge "Fix keyguard/Keystore storage issue" into klp-dev

This commit is contained in:
Jim Miller
2013-09-19 00:00:22 +00:00
committed by Android (Google) Code Review
3 changed files with 61 additions and 56 deletions

View File

@@ -24,10 +24,10 @@ interface ILockSettings {
boolean getBoolean(in String key, in boolean defaultValue, in int userId); boolean getBoolean(in String key, in boolean defaultValue, in int userId);
long getLong(in String key, in long defaultValue, in int userId); long getLong(in String key, in long defaultValue, in int userId);
String getString(in String key, in String defaultValue, in int userId); String getString(in String key, in String defaultValue, in int userId);
void setLockPattern(in byte[] hash, int userId); void setLockPattern(in String pattern, int userId);
boolean checkPattern(in byte[] hash, int userId); boolean checkPattern(in String pattern, int userId);
void setLockPassword(in byte[] hash, int userId); void setLockPassword(in String password, int userId);
boolean checkPassword(in byte[] hash, int userId); boolean checkPassword(in String password, int userId);
boolean havePattern(int userId); boolean havePattern(int userId);
boolean havePassword(int userId); boolean havePassword(int userId);
void removeUser(int userId); void removeUser(int userId);

View File

@@ -32,7 +32,6 @@ import android.os.SystemClock;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.storage.IMountService; import android.os.storage.IMountService;
import android.provider.Settings; import android.provider.Settings;
import android.security.KeyStore;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
@@ -292,11 +291,7 @@ public class LockPatternUtils {
public boolean checkPattern(List<LockPatternView.Cell> pattern) { public boolean checkPattern(List<LockPatternView.Cell> pattern) {
final int userId = getCurrentOrCallingUserId(); final int userId = getCurrentOrCallingUserId();
try { try {
final boolean matched = getLockSettings().checkPattern(patternToHash(pattern), userId); return getLockSettings().checkPattern(patternToString(pattern), userId);
if (matched && (userId == UserHandle.USER_OWNER)) {
KeyStore.getInstance().password(patternToString(pattern));
}
return matched;
} catch (RemoteException re) { } catch (RemoteException re) {
return true; return true;
} }
@@ -311,12 +306,7 @@ public class LockPatternUtils {
public boolean checkPassword(String password) { public boolean checkPassword(String password) {
final int userId = getCurrentOrCallingUserId(); final int userId = getCurrentOrCallingUserId();
try { try {
final boolean matched = getLockSettings().checkPassword(passwordToHash(password), return getLockSettings().checkPassword(password, userId);
userId);
if (matched && (userId == UserHandle.USER_OWNER)) {
KeyStore.getInstance().password(password);
}
return matched;
} catch (RemoteException re) { } catch (RemoteException re) {
return true; return true;
} }
@@ -505,14 +495,10 @@ public class LockPatternUtils {
* @param isFallback Specifies if this is a fallback to biometric weak * @param isFallback Specifies if this is a fallback to biometric weak
*/ */
public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) { public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
// Compute the hash
final byte[] hash = LockPatternUtils.patternToHash(pattern);
try { try {
getLockSettings().setLockPattern(hash, getCurrentOrCallingUserId()); getLockSettings().setLockPattern(patternToString(pattern), getCurrentOrCallingUserId());
DevicePolicyManager dpm = getDevicePolicyManager(); DevicePolicyManager dpm = getDevicePolicyManager();
KeyStore keyStore = KeyStore.getInstance();
if (pattern != null) { if (pattern != null) {
keyStore.password(patternToString(pattern));
setBoolean(PATTERN_EVER_CHOSEN_KEY, true); setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
if (!isFallback) { if (!isFallback) {
deleteGallery(); deleteGallery();
@@ -528,9 +514,6 @@ public class LockPatternUtils {
0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId()); 0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
} }
} else { } else {
if (keyStore.isEmpty()) {
keyStore.reset();
}
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
0, 0, 0, 0, 0, getCurrentOrCallingUserId()); 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
} }
@@ -637,19 +620,13 @@ public class LockPatternUtils {
* @param userHandle The userId of the user to change the password for * @param userHandle The userId of the user to change the password for
*/ */
public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) { public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) {
// Compute the hash
final byte[] hash = passwordToHash(password);
try { try {
getLockSettings().setLockPassword(hash, userHandle); getLockSettings().setLockPassword(password, userHandle);
DevicePolicyManager dpm = getDevicePolicyManager(); DevicePolicyManager dpm = getDevicePolicyManager();
KeyStore keyStore = KeyStore.getInstance();
if (password != null) { if (password != null) {
if (userHandle == UserHandle.USER_OWNER) { if (userHandle == UserHandle.USER_OWNER) {
// Update the encryption password. // Update the encryption password.
updateEncryptionPassword(password); updateEncryptionPassword(password);
// Update the keystore password
keyStore.password(password);
} }
int computedQuality = computePasswordQuality(password); int computedQuality = computePasswordQuality(password);
@@ -709,6 +686,7 @@ public class LockPatternUtils {
if (passwordHistoryLength == 0) { if (passwordHistoryLength == 0) {
passwordHistory = ""; passwordHistory = "";
} else { } else {
byte[] hash = passwordToHash(password);
passwordHistory = new String(hash) + "," + passwordHistory; passwordHistory = new String(hash) + "," + passwordHistory;
// Cut it to contain passwordHistoryLength hashes // Cut it to contain passwordHistoryLength hashes
// and passwordHistoryLength -1 commas. // and passwordHistoryLength -1 commas.
@@ -718,11 +696,6 @@ public class LockPatternUtils {
} }
setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle); setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
} else { } else {
// Conditionally reset the keystore if empty. If
// non-empty, we are just switching key guard type
if (keyStore.isEmpty()) {
keyStore.reset();
}
dpm.setActivePasswordState( dpm.setActivePasswordState(
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
userHandle); userHandle);
@@ -803,7 +776,7 @@ public class LockPatternUtils {
* @param pattern the gesture pattern. * @param pattern the gesture pattern.
* @return the hash of the pattern in a byte array. * @return the hash of the pattern in a byte array.
*/ */
private static byte[] patternToHash(List<LockPatternView.Cell> pattern) { public static byte[] patternToHash(List<LockPatternView.Cell> pattern) {
if (pattern == null) { if (pattern == null) {
return null; return null;
} }

View File

@@ -40,6 +40,7 @@ import android.os.UserManager;
import android.provider.Settings; import android.provider.Settings;
import android.provider.Settings.Secure; import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException; import android.provider.Settings.SettingNotFoundException;
import android.security.KeyStore;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.util.Slog; import android.util.Slog;
@@ -80,11 +81,14 @@ public class LockSettingsService extends ILockSettings.Stub {
private static final String LOCK_PASSWORD_FILE = "password.key"; private static final String LOCK_PASSWORD_FILE = "password.key";
private final Context mContext; private final Context mContext;
private LockPatternUtils mLockPatternUtils;
public LockSettingsService(Context context) { public LockSettingsService(Context context) {
mContext = context; mContext = context;
// Open the database // Open the database
mOpenHelper = new DatabaseHelper(mContext); mOpenHelper = new DatabaseHelper(mContext);
mLockPatternUtils = new LockPatternUtils(context);
} }
public void systemReady() { public void systemReady() {
@@ -255,15 +259,42 @@ public class LockSettingsService extends ILockSettings.Stub {
return new File(getLockPatternFilename(userId)).length() > 0; return new File(getLockPatternFilename(userId)).length() > 0;
} }
private void maybeUpdateKeystore(String password, int userId) {
if (userId == UserHandle.USER_OWNER) {
final KeyStore keyStore = KeyStore.getInstance();
// Conditionally reset the keystore if empty. If non-empty, we are just
// switching key guard type
if (TextUtils.isEmpty(password) && keyStore.isEmpty()) {
keyStore.reset();
} else {
// Update the keystore password
keyStore.password(password);
}
}
}
@Override @Override
public void setLockPattern(byte[] hash, int userId) throws RemoteException { public void setLockPattern(String pattern, int userId) throws RemoteException {
checkWritePermission(userId); checkWritePermission(userId);
maybeUpdateKeystore(pattern, userId);
final byte[] hash = LockPatternUtils.patternToHash(
LockPatternUtils.stringToPattern(pattern));
writeFile(getLockPatternFilename(userId), hash); writeFile(getLockPatternFilename(userId), hash);
} }
@Override @Override
public boolean checkPattern(byte[] hash, int userId) throws RemoteException { public void setLockPassword(String password, int userId) throws RemoteException {
checkWritePermission(userId);
maybeUpdateKeystore(password, userId);
writeFile(getLockPasswordFilename(userId), mLockPatternUtils.passwordToHash(password));
}
@Override
public boolean checkPattern(String pattern, int userId) throws RemoteException {
checkPasswordReadPermission(userId); checkPasswordReadPermission(userId);
try { try {
// Read all the bytes from the file // Read all the bytes from the file
@@ -275,25 +306,23 @@ public class LockSettingsService extends ILockSettings.Stub {
return true; return true;
} }
// Compare the hash from the file with the entered pattern's hash // Compare the hash from the file with the entered pattern's hash
return Arrays.equals(stored, hash); final byte[] hash = LockPatternUtils.patternToHash(
LockPatternUtils.stringToPattern(pattern));
final boolean matched = Arrays.equals(stored, hash);
if (matched && !TextUtils.isEmpty(pattern)) {
maybeUpdateKeystore(pattern, userId);
}
return matched;
} catch (FileNotFoundException fnfe) { } catch (FileNotFoundException fnfe) {
Slog.e(TAG, "Cannot read file " + fnfe); Slog.e(TAG, "Cannot read file " + fnfe);
return true;
} catch (IOException ioe) { } catch (IOException ioe) {
Slog.e(TAG, "Cannot read file " + ioe); Slog.e(TAG, "Cannot read file " + ioe);
}
return true; return true;
} }
}
@Override @Override
public void setLockPassword(byte[] hash, int userId) throws RemoteException { public boolean checkPassword(String password, int userId) throws RemoteException {
checkWritePermission(userId);
writeFile(getLockPasswordFilename(userId), hash);
}
@Override
public boolean checkPassword(byte[] hash, int userId) throws RemoteException {
checkPasswordReadPermission(userId); checkPasswordReadPermission(userId);
try { try {
@@ -306,14 +335,18 @@ public class LockSettingsService extends ILockSettings.Stub {
return true; return true;
} }
// Compare the hash from the file with the entered password's hash // Compare the hash from the file with the entered password's hash
return Arrays.equals(stored, hash); final byte[] hash = mLockPatternUtils.passwordToHash(password);
final boolean matched = Arrays.equals(stored, hash);
if (matched && !TextUtils.isEmpty(password)) {
maybeUpdateKeystore(password, userId);
}
return matched;
} catch (FileNotFoundException fnfe) { } catch (FileNotFoundException fnfe) {
Slog.e(TAG, "Cannot read file " + fnfe); Slog.e(TAG, "Cannot read file " + fnfe);
return true;
} catch (IOException ioe) { } catch (IOException ioe) {
Slog.e(TAG, "Cannot read file " + ioe); Slog.e(TAG, "Cannot read file " + ioe);
return true;
} }
return true;
} }
@Override @Override
@@ -445,13 +478,12 @@ public class LockSettingsService extends ILockSettings.Stub {
private void maybeEnableWidgetSettingForUsers(SQLiteDatabase db) { private void maybeEnableWidgetSettingForUsers(SQLiteDatabase db) {
final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE); final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
final ContentResolver cr = mContext.getContentResolver(); final ContentResolver cr = mContext.getContentResolver();
final LockPatternUtils utils = new LockPatternUtils(mContext);
final List<UserInfo> users = um.getUsers(); final List<UserInfo> users = um.getUsers();
for (int i = 0; i < users.size(); i++) { for (int i = 0; i < users.size(); i++) {
final int userId = users.get(i).id; final int userId = users.get(i).id;
final boolean enabled = utils.hasWidgetsEnabledInKeyguard(userId); final boolean enabled = mLockPatternUtils.hasWidgetsEnabledInKeyguard(userId);
Log.v(TAG, "Widget upgrade uid=" + userId + ", enabled=" Log.v(TAG, "Widget upgrade uid=" + userId + ", enabled="
+ enabled + ", w[]=" + utils.getAppWidgets()); + enabled + ", w[]=" + mLockPatternUtils.getAppWidgets());
loadSetting(db, LockPatternUtils.LOCKSCREEN_WIDGETS_ENABLED, userId, enabled); loadSetting(db, LockPatternUtils.LOCKSCREEN_WIDGETS_ENABLED, userId, enabled);
} }
} }