diff options
author | Dmitry Dementyev <dementyev@google.com> | 2021-02-26 09:14:43 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-02-26 09:14:43 +0000 |
commit | 26085ee2ff5aaba6d71b518cb602baacb789a264 (patch) | |
tree | 256304aba96bf4fbb831cdff299883e0fe9bd926 | |
parent | 9044d1e472ddea5b629e8ddde8e5bc83b53a49e7 (diff) | |
parent | dbf8a7c1bd0f301aec8383d1c24054c6d47c32ef (diff) |
Merge "Migrate recoverablekeystore to KeyStore V2." am: dbf8a7c1bd
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1603470
MUST ONLY BE SUBMITTED BY AUTOMERGER
Change-Id: I7f96343c65df7accaae3fb5032771dbcd05191f5
8 files changed, 105 insertions, 45 deletions
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java index cc3e57859b64..1dc7f71fbb0e 100644 --- a/core/java/android/security/keystore/recovery/RecoveryController.java +++ b/core/java/android/security/keystore/recovery/RecoveryController.java @@ -27,8 +27,11 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.security.KeyStore; -import android.security.keystore.AndroidKeyStoreProvider; +import android.security.KeyStore2; import android.security.keystore.KeyPermanentlyInvalidatedException; +import android.security.keystore2.AndroidKeyStoreProvider; +import android.system.keystore2.Domain; +import android.system.keystore2.KeyDescriptor; import com.android.internal.widget.ILockSettings; @@ -709,10 +712,34 @@ public class RecoveryController { */ @NonNull Key getKeyFromGrant(@NonNull String grantAlias) throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { - return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore( - mKeyStore, - grantAlias, - KeyStore.UID_SELF); + if (grantAlias.startsWith(APPLICATION_KEY_GRANT_PREFIX)) { + return AndroidKeyStoreProvider + .loadAndroidKeyStoreSecretKeyFromKeystore( + KeyStore2.getInstance(), + getGrantDescriptor(grantAlias)); + } + // TODO(b/171305545): remove KeyStore1 logic. + return android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore( + mKeyStore, + grantAlias, + KeyStore.UID_SELF); + + } + + private static final String APPLICATION_KEY_GRANT_PREFIX = "recoverable_key:"; + + private static @Nullable KeyDescriptor getGrantDescriptor(String grantAlias) { + KeyDescriptor result = new KeyDescriptor(); + result.domain = Domain.GRANT; + result.blob = null; + result.alias = null; + try { + result.nspace = Long.parseUnsignedLong( + grantAlias.substring(APPLICATION_KEY_GRANT_PREFIX.length()), 16); + } catch (NumberFormatException e) { + return null; + } + return result; } /** diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java index 35059ac929c3..d36695b9b410 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java @@ -43,6 +43,7 @@ import java.security.interfaces.RSAPublicKey; import javax.crypto.Cipher; import javax.crypto.Mac; +import javax.crypto.SecretKey; /** * A provider focused on providing JCA interfaces for the Android KeyStore. @@ -299,13 +300,26 @@ public class AndroidKeyStoreProvider extends Provider { } } + /** @hide **/ + @NonNull + public static SecretKey loadAndroidKeyStoreSecretKeyFromKeystore( + @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor) + throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { + + AndroidKeyStoreKey key = + loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor); + if (key instanceof SecretKey) { + return (SecretKey) key; + } else { + throw new UnrecoverableKeyException("No secret key found by the given alias."); + } + } @NonNull private static AndroidKeyStoreSecretKey makeAndroidKeyStoreSecretKeyFromKeyEntryResponse( @NonNull KeyDescriptor descriptor, @NonNull KeyEntryResponse response, int algorithm, int digest) throws UnrecoverableKeyException { - @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString; try { keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm( @@ -337,7 +351,6 @@ public class AndroidKeyStoreProvider extends Provider { public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore( @NonNull KeyStore2 keyStore, @NonNull String alias, int namespace) throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { - KeyDescriptor descriptor = new KeyDescriptor(); if (namespace == KeyProperties.NAMESPACE_APPLICATION) { descriptor.nspace = KeyProperties.NAMESPACE_APPLICATION; // ignored; diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index f1750cd16f1f..294d7e257b6e 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -489,8 +489,8 @@ public class LockSettingsService extends ILockSettings.Stub { return KeyStore.getInstance(); } - public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) { - return RecoverableKeyStoreManager.getInstance(mContext, keyStore); + public RecoverableKeyStoreManager getRecoverableKeyStoreManager() { + return RecoverableKeyStoreManager.getInstance(mContext); } public IStorageManager getStorageManager() { @@ -571,7 +571,7 @@ public class LockSettingsService extends ILockSettings.Stub { mInjector = injector; mContext = injector.getContext(); mKeyStore = injector.getKeyStore(); - mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(mKeyStore); + mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(); mHandler = injector.getHandler(injector.getServiceThread()); mStrongAuth = injector.getStrongAuth(); mActivityManager = injector.getActivityManager(); diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java index 9857fb637b59..f5941361bd89 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java @@ -16,8 +16,6 @@ package com.android.server.locksettings.recoverablekeystore; -import android.security.keystore2.AndroidKeyStoreProvider; - import java.io.IOException; import java.security.Key; import java.security.KeyStore; @@ -31,22 +29,9 @@ import java.security.cert.CertificateException; */ public class KeyStoreProxyImpl implements KeyStoreProxy { - private final KeyStore mKeyStore; - - /** - * TODO This function redirects keystore access to the legacy keystore during a transitional - * phase during which not all calling code has been adjusted to use Keystore 2.0. - * This can be reverted to a constant of "AndroidKeyStore" when b/171305684 is complete. - * The specific bug for this component is b/171305545. - */ - static String androidKeystoreProviderName() { - if (AndroidKeyStoreProvider.isInstalled()) { - return "AndroidKeyStoreLegacy"; - } else { - return "AndroidKeyStore"; - } + public static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore"; - } + private final KeyStore mKeyStore; /** * A new instance, delegating to {@code keyStore}. @@ -84,7 +69,7 @@ public class KeyStoreProxyImpl implements KeyStoreProxy { * @throws KeyStoreException if there was a problem getting or initializing the key store. */ public static KeyStore getAndLoadAndroidKeyStore() throws KeyStoreException { - KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); + KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER); try { keyStore.load(/*param=*/ null); } catch (CertificateException | IOException | NoSuchAlgorithmException e) { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java index 569b7098bb6c..202dfe798616 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java @@ -484,7 +484,7 @@ public class PlatformKeyManager { * @throws KeyStoreException if there was a problem getting or initializing the key store. */ private static KeyStore getAndLoadAndroidKeyStore() throws KeyStoreException { - KeyStore keyStore = KeyStore.getInstance(KeyStoreProxyImpl.androidKeystoreProviderName()); + KeyStore keyStore = KeyStore.getInstance(KeyStoreProxyImpl.ANDROID_KEY_STORE_PROVIDER); try { keyStore.load(/*param=*/ null); } catch (CertificateException | IOException | NoSuchAlgorithmException e) { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 6d97ed7a69a7..b49bced4e567 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -34,7 +34,6 @@ import android.os.Binder; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.os.UserHandle; -import android.security.KeyStore; import android.security.keystore.recovery.KeyChainProtectionParams; import android.security.keystore.recovery.KeyChainSnapshot; import android.security.keystore.recovery.RecoveryCertPath; @@ -110,14 +109,14 @@ public class RecoverableKeyStoreManager { * @hide */ public static synchronized RecoverableKeyStoreManager - getInstance(Context context, KeyStore keystore) { + getInstance(Context context) { if (mInstance == null) { RecoverableKeyStoreDb db = RecoverableKeyStoreDb.newInstance(context); PlatformKeyManager platformKeyManager; ApplicationKeyStorage applicationKeyStorage; try { platformKeyManager = PlatformKeyManager.getInstance(context, db); - applicationKeyStorage = ApplicationKeyStorage.getInstance(keystore); + applicationKeyStorage = ApplicationKeyStorage.getInstance(); } catch (NoSuchAlgorithmException e) { // Impossible: all algorithms must be supported by AOSP throw new RuntimeException(e); diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java index 84ddbf778c70..2398f56f847c 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java @@ -21,9 +21,13 @@ import static android.security.keystore.recovery.RecoveryController.ERROR_SERVIC import android.annotation.Nullable; import android.os.ServiceSpecificException; import android.security.Credentials; +import android.security.KeyStore; +import android.security.KeyStore2; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; -import android.security.KeyStore; +import android.system.keystore2.Domain; +import android.system.keystore2.KeyDescriptor; +import android.system.keystore2.KeyPermission; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -47,32 +51,37 @@ public class ApplicationKeyStorage { private static final String APPLICATION_KEY_ALIAS_PREFIX = "com.android.server.locksettings.recoverablekeystore/application/"; + private static final String APPLICATION_KEY_GRANT_PREFIX = "recoverable_key:"; private final KeyStoreProxy mKeyStore; - private final KeyStore mKeystoreService; - public static ApplicationKeyStorage getInstance(KeyStore keystoreService) + /** + * Creates a new instance. + */ + public static ApplicationKeyStorage getInstance() throws KeyStoreException { return new ApplicationKeyStorage( - new KeyStoreProxyImpl(KeyStoreProxyImpl.getAndLoadAndroidKeyStore()), - keystoreService); + new KeyStoreProxyImpl(KeyStoreProxyImpl.getAndLoadAndroidKeyStore())); } @VisibleForTesting - ApplicationKeyStorage(KeyStoreProxy keyStore, KeyStore keystoreService) { + ApplicationKeyStorage(KeyStoreProxy keyStore) { mKeyStore = keyStore; - mKeystoreService = keystoreService; } /** - * Returns grant alias, valid in Applications namespace. + * Returns String representation of {@code KeyDescriptor} valid in application's namespace. */ public @Nullable String getGrantAlias(int userId, int uid, String alias) { - // Aliases used by {@link KeyStore} are different than used by public API. - // {@code USER_PRIVATE_KEY} prefix is used secret keys. Log.i(TAG, String.format(Locale.US, "Get %d/%d/%s", userId, uid, alias)); - String keystoreAlias = Credentials.USER_PRIVATE_KEY + getInternalAlias(userId, uid, alias); - return mKeystoreService.grant(keystoreAlias, uid); + String keystoreAlias = getInternalAlias(userId, uid, alias); + if (useKeyStore2()) { + return makeKeystoreEngineGrantString(uid, keystoreAlias); + } else { + // Aliases used by {@link KeyStore} are different than used by public API. + // {@code USER_PRIVATE_KEY} prefix is used secret keys. + return KeyStore.getInstance().grant(Credentials.USER_PRIVATE_KEY + keystoreAlias, uid); + } } public void setSymmetricKeyEntry(int userId, int uid, String alias, byte[] secretKey) @@ -117,4 +126,31 @@ public class ApplicationKeyStorage { private String getInternalAlias(int userId, int uid, String alias) { return APPLICATION_KEY_ALIAS_PREFIX + userId + "/" + uid + "/" + alias; } + + private String makeKeystoreEngineGrantString(int uid, String alias) { + if (alias == null) { + return null; + } + + KeyDescriptor key = new KeyDescriptor(); + key.domain = Domain.APP; + key.nspace = KeyProperties.NAMESPACE_APPLICATION; + key.alias = alias; + key.blob = null; + + int grantAccessVector = KeyPermission.USE | KeyPermission.GET_INFO | KeyPermission.DELETE; + + try { + key = KeyStore2.getInstance().grant(key, uid, grantAccessVector); + } catch (android.security.KeyStoreException e) { + Log.e(TAG, "Failed to get grant for KeyStore key.", e); + throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage()); + } + return String.format("%s%016X", APPLICATION_KEY_GRANT_PREFIX, key.nspace); + } + + private static boolean useKeyStore2() { + return android.security.keystore2.AndroidKeyStoreProvider.isInstalled(); + } + } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java index 4e1454bd0962..1db5fcc70420 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -150,7 +150,7 @@ public class LockSettingsServiceTestable extends LockSettingsService { } @Override - public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) { + public RecoverableKeyStoreManager getRecoverableKeyStoreManager() { return mRecoverableKeyStoreManager; } |