LockSettingsService: migrate to its own keystore namespace

Moves keystore keys used by LockSettingsService to a separate
namespace, migrating existing key during boot if needed.
Affected keys are encryption keys for synthetic password blob,
unified profile challenge encryption key and unified profile
challenge cache key.

Bug: 184664830
Test: atest com.android.server.locksettings
Change-Id: Iac339e64812232875afa9dc6109b848b50b0ef2f
This commit is contained in:
Rubin Xu
2021-04-15 22:08:53 +01:00
parent 19fb732416
commit f53bf832bd
5 changed files with 151 additions and 47 deletions

View File

@@ -30,6 +30,8 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSW
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback; import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
import static com.android.internal.widget.LockPatternUtils.PROFILE_KEY_NAME_DECRYPT;
import static com.android.internal.widget.LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT;
import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY; import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
@@ -99,6 +101,7 @@ import android.security.keystore.recovery.KeyChainProtectionParams;
import android.security.keystore.recovery.KeyChainSnapshot; import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.keystore.recovery.RecoveryCertPath; import android.security.keystore.recovery.RecoveryCertPath;
import android.security.keystore.recovery.WrappedApplicationKey; import android.security.keystore.recovery.WrappedApplicationKey;
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
import android.security.keystore2.AndroidKeyStoreProvider; import android.security.keystore2.AndroidKeyStoreProvider;
import android.service.gatekeeper.GateKeeperResponse; import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService; import android.service.gatekeeper.IGateKeeperService;
@@ -155,6 +158,7 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@@ -226,6 +230,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private final SyntheticPasswordManager mSpManager; private final SyntheticPasswordManager mSpManager;
private final KeyStore mKeyStore; private final KeyStore mKeyStore;
private final java.security.KeyStore mJavaKeyStore;
private final RecoverableKeyStoreManager mRecoverableKeyStoreManager; private final RecoverableKeyStoreManager mRecoverableKeyStoreManager;
private ManagedProfilePasswordCache mManagedProfilePasswordCache; private ManagedProfilePasswordCache mManagedProfilePasswordCache;
@@ -535,16 +540,22 @@ public class LockSettingsService extends ILockSettings.Stub {
return Settings.Secure.getIntForUser(contentResolver, keyName, defaultValue, userId); return Settings.Secure.getIntForUser(contentResolver, keyName, defaultValue, userId);
} }
public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache() { public java.security.KeyStore getJavaKeyStore() {
try { try {
java.security.KeyStore ks = java.security.KeyStore.getInstance( java.security.KeyStore ks = java.security.KeyStore.getInstance(
SyntheticPasswordCrypto.androidKeystoreProviderName()); SyntheticPasswordCrypto.androidKeystoreProviderName());
ks.load(null); ks.load(new AndroidKeyStoreLoadStoreParameter(
return new ManagedProfilePasswordCache(ks, getUserManager()); SyntheticPasswordCrypto.keyNamespace()));
return ks;
} catch (Exception e) { } catch (Exception e) {
throw new IllegalStateException("Cannot load keystore", e); throw new IllegalStateException("Cannot load keystore", e);
} }
} }
public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache(
java.security.KeyStore ks) {
return new ManagedProfilePasswordCache(ks, getUserManager());
}
} }
public LockSettingsService(Context context) { public LockSettingsService(Context context) {
@@ -556,6 +567,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mInjector = injector; mInjector = injector;
mContext = injector.getContext(); mContext = injector.getContext();
mKeyStore = injector.getKeyStore(); mKeyStore = injector.getKeyStore();
mJavaKeyStore = injector.getJavaKeyStore();
mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(); mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager();
mHandler = injector.getHandler(injector.getServiceThread()); mHandler = injector.getHandler(injector.getServiceThread());
mStrongAuth = injector.getStrongAuth(); mStrongAuth = injector.getStrongAuth();
@@ -580,7 +592,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mRandom = new SecureRandom(); mRandom = new SecureRandom();
mSpManager = injector.getSyntheticPasswordManager(mStorage); mSpManager = injector.getSyntheticPasswordManager(mStorage);
mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache(); mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache(mJavaKeyStore);
mBiometricDeferredQueue = new BiometricDeferredQueue(mContext, mSpManager, mHandler); mBiometricDeferredQueue = new BiometricDeferredQueue(mContext, mSpManager, mHandler);
mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(), mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(),
@@ -955,6 +967,21 @@ public class LockSettingsService extends ILockSettings.Stub {
setString("migrated_wear_lockscreen_disabled", "true", 0); setString("migrated_wear_lockscreen_disabled", "true", 0);
Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices"); Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices");
} }
if (getString("migrated_keystore_namespace", null, 0) == null) {
boolean success = true;
synchronized (mSpManager) {
success &= mSpManager.migrateKeyNamespace();
}
success &= migrateProfileLockKeys();
if (success) {
setString("migrated_keystore_namespace", "true", 0);
Slog.i(TAG, "Migrated keys to LSS namespace");
} else {
Slog.w(TAG, "Failed to migrate keys to LSS namespace");
}
}
} }
private void migrateOldDataAfterSystemReady() { private void migrateOldDataAfterSystemReady() {
@@ -995,6 +1022,22 @@ public class LockSettingsService extends ILockSettings.Stub {
} }
} }
private boolean migrateProfileLockKeys() {
boolean success = true;
final List<UserInfo> users = mUserManager.getUsers();
final int userCount = users.size();
for (int i = 0; i < userCount; i++) {
UserInfo user = users.get(i);
if (user.isManagedProfile() && !getSeparateProfileChallengeEnabledInternal(user.id)) {
success &= SyntheticPasswordCrypto.migrateLockSettingsKey(
PROFILE_KEY_NAME_ENCRYPT + user.id);
success &= SyntheticPasswordCrypto.migrateLockSettingsKey(
PROFILE_KEY_NAME_DECRYPT + user.id);
}
}
return success;
}
/** /**
* Returns the lowest password quality that still presents the same UI for entering it. * Returns the lowest password quality that still presents the same UI for entering it.
* *
@@ -1286,11 +1329,8 @@ public class LockSettingsService extends ILockSettings.Stub {
byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE, byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
storedData.length); storedData.length);
byte[] decryptionResult; byte[] decryptionResult;
java.security.KeyStore keyStore = java.security.KeyStore.getInstance( SecretKey decryptionKey = (SecretKey) mJavaKeyStore.getKey(
SyntheticPasswordCrypto.androidKeystoreProviderName()); PROFILE_KEY_NAME_DECRYPT + userId, null);
keyStore.load(null);
SecretKey decryptionKey = (SecretKey) keyStore.getKey(
LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE); + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
@@ -1880,30 +1920,26 @@ public class LockSettingsService extends ILockSettings.Stub {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES); KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
keyGenerator.init(new SecureRandom()); keyGenerator.init(new SecureRandom());
SecretKey secretKey = keyGenerator.generateKey(); SecretKey secretKey = keyGenerator.generateKey();
java.security.KeyStore keyStore = java.security.KeyStore.getInstance(
SyntheticPasswordCrypto.androidKeystoreProviderName());
keyStore.load(null);
try { try {
keyStore.setEntry( mJavaKeyStore.setEntry(
LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, PROFILE_KEY_NAME_ENCRYPT + userId,
new java.security.KeyStore.SecretKeyEntry(secretKey), new java.security.KeyStore.SecretKeyEntry(secretKey),
new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT) new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build()); .build());
keyStore.setEntry( mJavaKeyStore.setEntry(
LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, PROFILE_KEY_NAME_DECRYPT + userId,
new java.security.KeyStore.SecretKeyEntry(secretKey), new java.security.KeyStore.SecretKeyEntry(secretKey),
new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(true) .setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(30) .setUserAuthenticationValidityDurationSeconds(30)
.setCriticalToDeviceEncryption(true)
.build()); .build());
// Key imported, obtain a reference to it. // Key imported, obtain a reference to it.
SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey( SecretKey keyStoreEncryptionKey = (SecretKey) mJavaKeyStore.getKey(
LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null); PROFILE_KEY_NAME_ENCRYPT + userId, null);
Cipher cipher = Cipher.getInstance( Cipher cipher = Cipher.getInstance(
KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/" KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
+ KeyProperties.ENCRYPTION_PADDING_NONE); + KeyProperties.ENCRYPTION_PADDING_NONE);
@@ -1912,10 +1948,10 @@ public class LockSettingsService extends ILockSettings.Stub {
iv = cipher.getIV(); iv = cipher.getIV();
} finally { } finally {
// The original key can now be discarded. // The original key can now be discarded.
keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId); mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_ENCRYPT + userId);
} }
} catch (CertificateException | UnrecoverableKeyException } catch (UnrecoverableKeyException
| IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
| NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) { | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
throw new IllegalStateException("Failed to encrypt key", e); throw new IllegalStateException("Failed to encrypt key", e);
} }
@@ -2460,13 +2496,9 @@ public class LockSettingsService extends ILockSettings.Stub {
private void removeKeystoreProfileKey(int targetUserId) { private void removeKeystoreProfileKey(int targetUserId) {
Slog.i(TAG, "Remove keystore profile key for user: " + targetUserId); Slog.i(TAG, "Remove keystore profile key for user: " + targetUserId);
try { try {
java.security.KeyStore keyStore = java.security.KeyStore.getInstance( mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_ENCRYPT + targetUserId);
SyntheticPasswordCrypto.androidKeystoreProviderName()); mJavaKeyStore.deleteEntry(PROFILE_KEY_NAME_DECRYPT + targetUserId);
keyStore.load(null); } catch (KeyStoreException e) {
keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
| IOException e) {
// We have tried our best to remove all keys // We have tried our best to remove all keys
Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e); Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
} }
@@ -3420,6 +3452,12 @@ public class LockSettingsService extends ILockSettings.Stub {
pw.println(); pw.println();
pw.decreaseIndent(); pw.decreaseIndent();
pw.println("Keys in namespace:");
pw.increaseIndent();
dumpKeystoreKeys(pw);
pw.println();
pw.decreaseIndent();
pw.println("Storage:"); pw.println("Storage:");
pw.increaseIndent(); pw.increaseIndent();
mStorage.dump(pw); mStorage.dump(pw);
@@ -3441,6 +3479,18 @@ public class LockSettingsService extends ILockSettings.Stub {
pw.println("PasswordHandleCount: " + mGatekeeperPasswords.size()); pw.println("PasswordHandleCount: " + mGatekeeperPasswords.size());
} }
private void dumpKeystoreKeys(IndentingPrintWriter pw) {
try {
final Enumeration<String> aliases = mJavaKeyStore.aliases();
while (aliases.hasMoreElements()) {
pw.println(aliases.nextElement());
}
} catch (KeyStoreException e) {
pw.println("Unable to get keys: " + e.toString());
Slog.d(TAG, "Dump error", e);
}
}
/** /**
* Cryptographically disable escrow token support for the current user, if the user is not * Cryptographically disable escrow token support for the current user, if the user is not
* managed (either user has a profile owner, or if device is managed). Do not disable * managed (either user has a profile owner, or if device is managed). Do not disable

View File

@@ -23,7 +23,6 @@ import android.os.UserManager;
import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties; import android.security.keystore.KeyProperties;
import android.security.keystore.UserNotAuthenticatedException; import android.security.keystore.UserNotAuthenticatedException;
import android.security.keystore2.AndroidKeyStoreSpi;
import android.util.Slog; import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
@@ -95,11 +94,12 @@ public class ManagedProfilePasswordCache {
SecretKey key; SecretKey key;
try { try {
generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,
AndroidKeyStoreSpi.NAME); mKeyStore.getProvider());
generator.init(new KeyGenParameterSpec.Builder( generator.init(new KeyGenParameterSpec.Builder(
keyName, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) keyName, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setKeySize(KEY_LENGTH) .setKeySize(KEY_LENGTH)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setNamespace(SyntheticPasswordCrypto.keyNamespace())
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
// Generate auth-bound key to user 0 (since we the caller is user 0) // Generate auth-bound key to user 0 (since we the caller is user 0)
.setUserAuthenticationRequired(true) .setUserAuthenticationRequired(true)

View File

@@ -16,8 +16,12 @@
package com.android.server.locksettings; package com.android.server.locksettings;
import android.security.AndroidKeyStoreMaintenance;
import android.security.keystore.KeyProperties; import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection; import android.security.keystore.KeyProtection;
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
import android.system.keystore2.Domain;
import android.system.keystore2.KeyDescriptor;
import android.util.Slog; import android.util.Slog;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@@ -125,9 +129,7 @@ public class SyntheticPasswordCrypto {
public static byte[] decryptBlobV1(String keyAlias, byte[] blob, byte[] applicationId) { public static byte[] decryptBlobV1(String keyAlias, byte[] blob, byte[] applicationId) {
try { try {
KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); KeyStore keyStore = getKeyStore();
keyStore.load(null);
SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null); SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
if (decryptionKey == null) { if (decryptionKey == null) {
throw new IllegalStateException("SP key is missing: " + keyAlias); throw new IllegalStateException("SP key is missing: " + keyAlias);
@@ -144,10 +146,20 @@ public class SyntheticPasswordCrypto {
return "AndroidKeyStore"; return "AndroidKeyStore";
} }
static int keyNamespace() {
return KeyProperties.NAMESPACE_LOCKSETTINGS;
}
private static KeyStore getKeyStore()
throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName());
keyStore.load(new AndroidKeyStoreLoadStoreParameter(keyNamespace()));
return keyStore;
}
public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) { public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) {
try { try {
KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); final KeyStore keyStore = getKeyStore();
keyStore.load(null);
SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null); SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
if (decryptionKey == null) { if (decryptionKey == null) {
@@ -170,8 +182,7 @@ public class SyntheticPasswordCrypto {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES); KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
keyGenerator.init(AES_KEY_LENGTH * 8, new SecureRandom()); keyGenerator.init(AES_KEY_LENGTH * 8, new SecureRandom());
SecretKey secretKey = keyGenerator.generateKey(); SecretKey secretKey = keyGenerator.generateKey();
KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); final KeyStore keyStore = getKeyStore();
keyStore.load(null);
KeyProtection.Builder builder = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) KeyProtection.Builder builder = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
@@ -200,8 +211,7 @@ public class SyntheticPasswordCrypto {
public static void destroyBlobKey(String keyAlias) { public static void destroyBlobKey(String keyAlias) {
KeyStore keyStore; KeyStore keyStore;
try { try {
keyStore = KeyStore.getInstance(androidKeystoreProviderName()); keyStore = getKeyStore();
keyStore.load(null);
keyStore.deleteEntry(keyAlias); keyStore.deleteEntry(keyAlias);
Slog.i(TAG, "SP key deleted: " + keyAlias); Slog.i(TAG, "SP key deleted: " + keyAlias);
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
@@ -229,4 +239,32 @@ public class SyntheticPasswordCrypto {
throw new IllegalStateException("NoSuchAlgorithmException for SHA-512", e); throw new IllegalStateException("NoSuchAlgorithmException for SHA-512", e);
} }
} }
static boolean migrateLockSettingsKey(String alias) {
final KeyDescriptor legacyKey = new KeyDescriptor();
legacyKey.domain = Domain.APP;
legacyKey.nspace = KeyProperties.NAMESPACE_APPLICATION;
legacyKey.alias = alias;
final KeyDescriptor newKey = new KeyDescriptor();
newKey.domain = Domain.SELINUX;
newKey.nspace = SyntheticPasswordCrypto.keyNamespace();
newKey.alias = alias;
Slog.i(TAG, "Migrating key " + alias);
int err = AndroidKeyStoreMaintenance.migrateKeyNamespace(legacyKey, newKey);
if (err == 0) {
return true;
} else if (err == AndroidKeyStoreMaintenance.KEY_NOT_FOUND) {
Slog.i(TAG, "Key does not exist");
// Treat this as a success so we don't migrate again.
return true;
} else if (err == AndroidKeyStoreMaintenance.INVALID_ARGUMENT) {
Slog.i(TAG, "Key already exists");
// Treat this as a success so we don't migrate again.
return true;
} else {
Slog.e(TAG, String.format("Failed to migrate key: %d", err));
return false;
}
}
} }

View File

@@ -522,7 +522,7 @@ public class SyntheticPasswordManager {
public void removeUser(int userId) { public void removeUser(int userId) {
for (long handle : mStorage.listSyntheticPasswordHandlesForUser(SP_BLOB_NAME, userId)) { for (long handle : mStorage.listSyntheticPasswordHandlesForUser(SP_BLOB_NAME, userId)) {
destroyWeaverSlot(handle, userId); destroyWeaverSlot(handle, userId);
destroySPBlobKey(getHandleName(handle)); destroySPBlobKey(getKeyName(handle));
} }
} }
@@ -958,7 +958,7 @@ public class SyntheticPasswordManager {
} else { } else {
secret = authToken.getSyntheticPassword(); secret = authToken.getSyntheticPassword();
} }
byte[] content = createSPBlob(getHandleName(handle), secret, applicationId, sid); byte[] content = createSPBlob(getKeyName(handle), secret, applicationId, sid);
byte[] blob = new byte[content.length + 1 + 1]; byte[] blob = new byte[content.length + 1 + 1];
/* /*
* We can upgrade from v1 to v2 because that's just a change in the way that * We can upgrade from v1 to v2 because that's just a change in the way that
@@ -1141,10 +1141,10 @@ public class SyntheticPasswordManager {
} }
final byte[] secret; final byte[] secret;
if (version == SYNTHETIC_PASSWORD_VERSION_V1) { if (version == SYNTHETIC_PASSWORD_VERSION_V1) {
secret = SyntheticPasswordCrypto.decryptBlobV1(getHandleName(handle), secret = SyntheticPasswordCrypto.decryptBlobV1(getKeyName(handle),
Arrays.copyOfRange(blob, 2, blob.length), applicationId); Arrays.copyOfRange(blob, 2, blob.length), applicationId);
} else { } else {
secret = decryptSPBlob(getHandleName(handle), secret = decryptSPBlob(getKeyName(handle),
Arrays.copyOfRange(blob, 2, blob.length), applicationId); Arrays.copyOfRange(blob, 2, blob.length), applicationId);
} }
if (secret == null) { if (secret == null) {
@@ -1247,7 +1247,7 @@ public class SyntheticPasswordManager {
private void destroySyntheticPassword(long handle, int userId) { private void destroySyntheticPassword(long handle, int userId) {
destroyState(SP_BLOB_NAME, handle, userId); destroyState(SP_BLOB_NAME, handle, userId);
destroySPBlobKey(getHandleName(handle)); destroySPBlobKey(getKeyName(handle));
if (hasState(WEAVER_SLOT_NAME, handle, userId)) { if (hasState(WEAVER_SLOT_NAME, handle, userId)) {
destroyWeaverSlot(handle, userId); destroyWeaverSlot(handle, userId);
} }
@@ -1363,7 +1363,7 @@ public class SyntheticPasswordManager {
} }
} }
private String getHandleName(long handle) { private String getKeyName(long handle) {
return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle); return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle);
} }
@@ -1424,4 +1424,19 @@ public class SyntheticPasswordManager {
} }
return hexBytes; return hexBytes;
} }
/**
* Migrate all existing SP keystore keys from uid 1000 app domain to LSS selinux domain
*/
public boolean migrateKeyNamespace() {
boolean success = true;
final Map<Integer, List<Long>> allHandles =
mStorage.listSyntheticPasswordHandlesForAllUsers(SP_BLOB_NAME);
for (List<Long> userHandles : allHandles.values()) {
for (long handle : userHandles) {
success &= SyntheticPasswordCrypto.migrateLockSettingsKey(getKeyName(handle));
}
}
return success;
}
} }

View File

@@ -155,7 +155,8 @@ public class LockSettingsServiceTestable extends LockSettingsService {
} }
@Override @Override
public ManagedProfilePasswordCache getManagedProfilePasswordCache() { public ManagedProfilePasswordCache getManagedProfilePasswordCache(
java.security.KeyStore ks) {
return mock(ManagedProfilePasswordCache.class); return mock(ManagedProfilePasswordCache.class);
} }