Loading core/java/android/security/recoverablekeystore/RecoverableKeyStoreLoader.java +97 −4 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.security.recoverablekeystore; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; import android.content.pm.PackageManager.NameNotFoundException; import android.os.RemoteException; import android.os.ServiceManager; Loading @@ -29,6 +30,7 @@ import android.util.AndroidException; import com.android.internal.widget.ILockSettings; import java.util.List; import java.util.Map; /** * A wrapper around KeyStore which lets key be exported to trusted hardware on server side and Loading @@ -43,9 +45,23 @@ public class RecoverableKeyStoreLoader { public static final int NO_ERROR = KeyStore.NO_ERROR; public static final int SYSTEM_ERROR = KeyStore.SYSTEM_ERROR; public static final int UNINITIALIZED_RECOVERY_PUBLIC_KEY = 20; // Too many updates to recovery public key or server parameters. /** * Rate limit is enforced to prevent using too many trusted remote devices, since each device * can have its own number of user secret guesses allowed. * * @hide */ public static final int RATE_LIMIT_EXCEEDED = 21; /** Key has been successfully synced. */ public static final int RECOVERY_STATUS_SYNCED = 0; /** Waiting for recovery agent to sync the key. */ public static final int RECOVERY_STATUS_SYNC_IN_PROGRESS = 1; /** Recovery account is not available. */ public static final int RECOVERY_STATUS_MISSING_ACCOUNT = 2; /** Key cannot be synced. */ public static final int RECOVERY_STATUS_PERMANENT_FAILURE = 3; private final ILockSettings mBinder; private RecoverableKeyStoreLoader(ILockSettings binder) { Loading Loading @@ -155,7 +171,7 @@ public class RecoverableKeyStoreLoader { * @return Data necessary to recover keystore. * @hide */ public KeyStoreRecoveryData getRecoveryData(@NonNull byte[] account) public @NonNull KeyStoreRecoveryData getRecoveryData(@NonNull byte[] account) throws RecoverableKeyStoreLoaderException { try { KeyStoreRecoveryData recoveryData = Loading @@ -168,6 +184,50 @@ public class RecoverableKeyStoreLoader { } } /** * Sets a listener which notifies recovery agent that new recovery snapshot is available. {@link * #getRecoveryData} can be used to get the snapshot. Note that every recovery agent can have at * most one registered listener at any time. * * @param intent triggered when new snapshot is available. Unregisters listener if the value is * {@code null}. * @hide */ public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent) throws RecoverableKeyStoreLoaderException { try { mBinder.setSnapshotCreatedPendingIntent(intent, UserHandle.getCallingUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e); } } /** * Returns a map from recovery agent accounts to corresponding KeyStore recovery snapshot * version. Version zero is used, if no snapshots were created for the account. * * @return Map from recovery agent accounts to snapshot versions. * @see KeyStoreRecoveryData.getSnapshotVersion * @hide */ public @NonNull Map<byte[], Integer> getRecoverySnapshotVersions() throws RecoverableKeyStoreLoaderException { try { // IPC doesn't support generic Maps. @SuppressWarnings("unchecked") Map<byte[], Integer> result = (Map<byte[], Integer>) mBinder.getRecoverySnapshotVersions(UserHandle.getCallingUserId()); return result; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e); } } /** * Server parameters used to generate new recovery key blobs. This value will be included in * {@code KeyStoreRecoveryData.getEncryptedRecoveryKeyBlob()}. The same value must be included Loading @@ -191,8 +251,8 @@ public class RecoverableKeyStoreLoader { /** * Updates recovery status for given keys. It is used to notify keystore that key was * successfully stored on the server or there were an error. Returned as a part of KeyInfo data * structure. * successfully stored on the server or there were an error. Application can check this value * using {@code getRecoveyStatus}. * * @param packageName Application whose recoverable keys' statuses are to be updated. * @param aliases List of application-specific key aliases. If the array is empty, updates the Loading @@ -211,6 +271,39 @@ public class RecoverableKeyStoreLoader { } } /** * Returns a {@code Map} from Application's KeyStore key aliases to their recovery status. * Negative status values are reserved for recovery agent specific codes. List of common codes: * * <ul> * <li>{@link #RECOVERY_STATUS_SYNCED} * <li>{@link #RECOVERY_STATUS_SYNC_IN_PROGRESS} * <li>{@link #RECOVERY_STATUS_MISSING_ACCOUNT} * <li>{@link #RECOVERY_STATUS_PERMANENT_FAILURE} * </ul> * * @param packageName Application whose recoverable keys' statuses are to be retrieved. if * {@code null} caller's package will be used. * @return {@code Map} from KeyStore alias to recovery status. * @see #setRecoveryStatus * @hide */ public Map<String, Integer> getRecoveryStatus(@Nullable String packageName) throws RecoverableKeyStoreLoaderException { try { // IPC doesn't support generic Maps. @SuppressWarnings("unchecked") Map<String, Integer> result = (Map<String, Integer>) mBinder.getRecoveryStatus(packageName, UserHandle.getCallingUserId()); return result; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e); } } /** * Specifies a set of secret types used for end-to-end keystore encryption. Knowing all of them * is necessary to recover data. Loading core/java/com/android/internal/widget/ILockSettings.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.internal.widget; import android.app.PendingIntent; import android.app.trust.IStrongAuthTracker; import android.os.Bundle; import android.security.recoverablekeystore.KeyEntryRecoveryData; Loading @@ -24,6 +25,8 @@ import android.security.recoverablekeystore.KeyStoreRecoveryMetadata; import com.android.internal.widget.ICheckCredentialProgressCallback; import com.android.internal.widget.VerifyCredentialResponse; import java.util.Map; /** {@hide} */ interface ILockSettings { void setBoolean(in String key, in boolean value, in int userId); Loading Loading @@ -63,8 +66,11 @@ interface ILockSettings { void initRecoveryService(in String rootCertificateAlias, in byte[] signedPublicKeyList, int userId); KeyStoreRecoveryData getRecoveryData(in byte[] account, int userId); void setSnapshotCreatedPendingIntent(in PendingIntent intent, int userId); Map getRecoverySnapshotVersions(int userId); void setServerParameters(long serverParameters, int userId); void setRecoveryStatus(in String packageName, in String[] aliases, int status, int userId); Map getRecoveryStatus(in String packageName, int userId); void setRecoverySecretTypes(in int[] secretTypes, int userId); int[] getRecoverySecretTypes(int userId); int[] getPendingRecoverySecretTypes(int userId); Loading services/core/java/com/android/server/locksettings/LockSettingsService.java +13 −0 Original line number Diff line number Diff line Loading @@ -1943,6 +1943,15 @@ public class LockSettingsService extends ILockSettings.Stub { return mRecoverableKeyStoreManager.getRecoveryData(account, userId); } public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent, int userId) throws RemoteException { mRecoverableKeyStoreManager.setSnapshotCreatedPendingIntent(intent, userId); } public Map getRecoverySnapshotVersions(int userId) throws RemoteException { return mRecoverableKeyStoreManager.getRecoverySnapshotVersions(userId); } @Override public void setServerParameters(long serverParameters, int userId) throws RemoteException { mRecoverableKeyStoreManager.setServerParameters(serverParameters, userId); Loading @@ -1954,6 +1963,10 @@ public class LockSettingsService extends ILockSettings.Stub { mRecoverableKeyStoreManager.setRecoveryStatus(packageName, aliases, status, userId); } public Map getRecoveryStatus(@Nullable String packageName, int userId) throws RemoteException { return mRecoverableKeyStoreManager.getRecoveryStatus(packageName, userId); } @Override public void setRecoverySecretTypes(@NonNull @KeyStoreRecoveryMetadata.UserSecretType int[] secretTypes, int userId) throws RemoteException { Loading services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +39 −4 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.locksettings.recoverablekeystore; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; import android.content.Context; import android.os.Binder; import android.os.RemoteException; Loading @@ -39,6 +40,7 @@ import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Class with {@link RecoverableKeyStoreLoader} API implementation and internal methods to interact Loading Loading @@ -95,7 +97,7 @@ public class RecoverableKeyStoreManager { * @return recovery data * @hide */ public KeyStoreRecoveryData getRecoveryData(@NonNull byte[] account, int userId) public @NonNull KeyStoreRecoveryData getRecoveryData(@NonNull byte[] account, int userId) throws RemoteException { checkRecoverKeyStorePermission(); final int callingUid = Binder.getCallingUid(); // Recovery agent uid. Loading @@ -118,6 +120,24 @@ public class RecoverableKeyStoreManager { RecoverableKeyStoreLoader.UNINITIALIZED_RECOVERY_PUBLIC_KEY); } public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent, int userId) throws RemoteException { checkRecoverKeyStorePermission(); throw new UnsupportedOperationException(); } /** * Gets recovery snapshot versions for all accounts. Note that snapshot may have 0 application * keys, but it still needs to be synced, if previous versions were not empty. * * @return Map from Recovery agent account to snapshot version. */ public @NonNull Map<byte[], Integer> getRecoverySnapshotVersions(int userId) throws RemoteException { checkRecoverKeyStorePermission(); throw new UnsupportedOperationException(); } public void setServerParameters(long serverParameters, int userId) throws RemoteException { checkRecoverKeyStorePermission(); throw new UnsupportedOperationException(); Loading @@ -130,6 +150,21 @@ public class RecoverableKeyStoreManager { throw new UnsupportedOperationException(); } /** * Gets recovery status for keys {@code packageName}. * * @param packageName which recoverable keys statuses will be returned * @return Map from KeyStore alias to recovery status */ public @NonNull Map<String, Integer> getRecoveryStatus(@Nullable String packageName, int userId) throws RemoteException { // Any application should be able to check status for its own keys. // If caller is a recovery agent it can check statuses for other packages, but // only for recoverable keys it manages. checkRecoverKeyStorePermission(); throw new UnsupportedOperationException(); } /** * Sets recovery secrets list used by all recovery agents for given {@code userId} * Loading @@ -148,7 +183,7 @@ public class RecoverableKeyStoreManager { * @return secret types * @hide */ public int[] getRecoverySecretTypes(int userId) throws RemoteException { public @NonNull int[] getRecoverySecretTypes(int userId) throws RemoteException { checkRecoverKeyStorePermission(); throw new UnsupportedOperationException(); } Loading @@ -159,7 +194,7 @@ public class RecoverableKeyStoreManager { * @return secret types * @hide */ public int[] getPendingRecoverySecretTypes(int userId) throws RemoteException { public @NonNull int[] getPendingRecoverySecretTypes(int userId) throws RemoteException { checkRecoverKeyStorePermission(); throw new UnsupportedOperationException(); } Loading Loading @@ -188,7 +223,7 @@ public class RecoverableKeyStoreManager { * * @hide */ public byte[] startRecoverySession( public @NonNull byte[] startRecoverySession( @NonNull String sessionId, @NonNull byte[] verifierPublicKey, @NonNull byte[] vaultParams, Loading Loading
core/java/android/security/recoverablekeystore/RecoverableKeyStoreLoader.java +97 −4 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.security.recoverablekeystore; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; import android.content.pm.PackageManager.NameNotFoundException; import android.os.RemoteException; import android.os.ServiceManager; Loading @@ -29,6 +30,7 @@ import android.util.AndroidException; import com.android.internal.widget.ILockSettings; import java.util.List; import java.util.Map; /** * A wrapper around KeyStore which lets key be exported to trusted hardware on server side and Loading @@ -43,9 +45,23 @@ public class RecoverableKeyStoreLoader { public static final int NO_ERROR = KeyStore.NO_ERROR; public static final int SYSTEM_ERROR = KeyStore.SYSTEM_ERROR; public static final int UNINITIALIZED_RECOVERY_PUBLIC_KEY = 20; // Too many updates to recovery public key or server parameters. /** * Rate limit is enforced to prevent using too many trusted remote devices, since each device * can have its own number of user secret guesses allowed. * * @hide */ public static final int RATE_LIMIT_EXCEEDED = 21; /** Key has been successfully synced. */ public static final int RECOVERY_STATUS_SYNCED = 0; /** Waiting for recovery agent to sync the key. */ public static final int RECOVERY_STATUS_SYNC_IN_PROGRESS = 1; /** Recovery account is not available. */ public static final int RECOVERY_STATUS_MISSING_ACCOUNT = 2; /** Key cannot be synced. */ public static final int RECOVERY_STATUS_PERMANENT_FAILURE = 3; private final ILockSettings mBinder; private RecoverableKeyStoreLoader(ILockSettings binder) { Loading Loading @@ -155,7 +171,7 @@ public class RecoverableKeyStoreLoader { * @return Data necessary to recover keystore. * @hide */ public KeyStoreRecoveryData getRecoveryData(@NonNull byte[] account) public @NonNull KeyStoreRecoveryData getRecoveryData(@NonNull byte[] account) throws RecoverableKeyStoreLoaderException { try { KeyStoreRecoveryData recoveryData = Loading @@ -168,6 +184,50 @@ public class RecoverableKeyStoreLoader { } } /** * Sets a listener which notifies recovery agent that new recovery snapshot is available. {@link * #getRecoveryData} can be used to get the snapshot. Note that every recovery agent can have at * most one registered listener at any time. * * @param intent triggered when new snapshot is available. Unregisters listener if the value is * {@code null}. * @hide */ public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent) throws RecoverableKeyStoreLoaderException { try { mBinder.setSnapshotCreatedPendingIntent(intent, UserHandle.getCallingUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e); } } /** * Returns a map from recovery agent accounts to corresponding KeyStore recovery snapshot * version. Version zero is used, if no snapshots were created for the account. * * @return Map from recovery agent accounts to snapshot versions. * @see KeyStoreRecoveryData.getSnapshotVersion * @hide */ public @NonNull Map<byte[], Integer> getRecoverySnapshotVersions() throws RecoverableKeyStoreLoaderException { try { // IPC doesn't support generic Maps. @SuppressWarnings("unchecked") Map<byte[], Integer> result = (Map<byte[], Integer>) mBinder.getRecoverySnapshotVersions(UserHandle.getCallingUserId()); return result; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e); } } /** * Server parameters used to generate new recovery key blobs. This value will be included in * {@code KeyStoreRecoveryData.getEncryptedRecoveryKeyBlob()}. The same value must be included Loading @@ -191,8 +251,8 @@ public class RecoverableKeyStoreLoader { /** * Updates recovery status for given keys. It is used to notify keystore that key was * successfully stored on the server or there were an error. Returned as a part of KeyInfo data * structure. * successfully stored on the server or there were an error. Application can check this value * using {@code getRecoveyStatus}. * * @param packageName Application whose recoverable keys' statuses are to be updated. * @param aliases List of application-specific key aliases. If the array is empty, updates the Loading @@ -211,6 +271,39 @@ public class RecoverableKeyStoreLoader { } } /** * Returns a {@code Map} from Application's KeyStore key aliases to their recovery status. * Negative status values are reserved for recovery agent specific codes. List of common codes: * * <ul> * <li>{@link #RECOVERY_STATUS_SYNCED} * <li>{@link #RECOVERY_STATUS_SYNC_IN_PROGRESS} * <li>{@link #RECOVERY_STATUS_MISSING_ACCOUNT} * <li>{@link #RECOVERY_STATUS_PERMANENT_FAILURE} * </ul> * * @param packageName Application whose recoverable keys' statuses are to be retrieved. if * {@code null} caller's package will be used. * @return {@code Map} from KeyStore alias to recovery status. * @see #setRecoveryStatus * @hide */ public Map<String, Integer> getRecoveryStatus(@Nullable String packageName) throws RecoverableKeyStoreLoaderException { try { // IPC doesn't support generic Maps. @SuppressWarnings("unchecked") Map<String, Integer> result = (Map<String, Integer>) mBinder.getRecoveryStatus(packageName, UserHandle.getCallingUserId()); return result; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e); } } /** * Specifies a set of secret types used for end-to-end keystore encryption. Knowing all of them * is necessary to recover data. Loading
core/java/com/android/internal/widget/ILockSettings.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.internal.widget; import android.app.PendingIntent; import android.app.trust.IStrongAuthTracker; import android.os.Bundle; import android.security.recoverablekeystore.KeyEntryRecoveryData; Loading @@ -24,6 +25,8 @@ import android.security.recoverablekeystore.KeyStoreRecoveryMetadata; import com.android.internal.widget.ICheckCredentialProgressCallback; import com.android.internal.widget.VerifyCredentialResponse; import java.util.Map; /** {@hide} */ interface ILockSettings { void setBoolean(in String key, in boolean value, in int userId); Loading Loading @@ -63,8 +66,11 @@ interface ILockSettings { void initRecoveryService(in String rootCertificateAlias, in byte[] signedPublicKeyList, int userId); KeyStoreRecoveryData getRecoveryData(in byte[] account, int userId); void setSnapshotCreatedPendingIntent(in PendingIntent intent, int userId); Map getRecoverySnapshotVersions(int userId); void setServerParameters(long serverParameters, int userId); void setRecoveryStatus(in String packageName, in String[] aliases, int status, int userId); Map getRecoveryStatus(in String packageName, int userId); void setRecoverySecretTypes(in int[] secretTypes, int userId); int[] getRecoverySecretTypes(int userId); int[] getPendingRecoverySecretTypes(int userId); Loading
services/core/java/com/android/server/locksettings/LockSettingsService.java +13 −0 Original line number Diff line number Diff line Loading @@ -1943,6 +1943,15 @@ public class LockSettingsService extends ILockSettings.Stub { return mRecoverableKeyStoreManager.getRecoveryData(account, userId); } public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent, int userId) throws RemoteException { mRecoverableKeyStoreManager.setSnapshotCreatedPendingIntent(intent, userId); } public Map getRecoverySnapshotVersions(int userId) throws RemoteException { return mRecoverableKeyStoreManager.getRecoverySnapshotVersions(userId); } @Override public void setServerParameters(long serverParameters, int userId) throws RemoteException { mRecoverableKeyStoreManager.setServerParameters(serverParameters, userId); Loading @@ -1954,6 +1963,10 @@ public class LockSettingsService extends ILockSettings.Stub { mRecoverableKeyStoreManager.setRecoveryStatus(packageName, aliases, status, userId); } public Map getRecoveryStatus(@Nullable String packageName, int userId) throws RemoteException { return mRecoverableKeyStoreManager.getRecoveryStatus(packageName, userId); } @Override public void setRecoverySecretTypes(@NonNull @KeyStoreRecoveryMetadata.UserSecretType int[] secretTypes, int userId) throws RemoteException { Loading
services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +39 −4 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.locksettings.recoverablekeystore; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; import android.content.Context; import android.os.Binder; import android.os.RemoteException; Loading @@ -39,6 +40,7 @@ import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Class with {@link RecoverableKeyStoreLoader} API implementation and internal methods to interact Loading Loading @@ -95,7 +97,7 @@ public class RecoverableKeyStoreManager { * @return recovery data * @hide */ public KeyStoreRecoveryData getRecoveryData(@NonNull byte[] account, int userId) public @NonNull KeyStoreRecoveryData getRecoveryData(@NonNull byte[] account, int userId) throws RemoteException { checkRecoverKeyStorePermission(); final int callingUid = Binder.getCallingUid(); // Recovery agent uid. Loading @@ -118,6 +120,24 @@ public class RecoverableKeyStoreManager { RecoverableKeyStoreLoader.UNINITIALIZED_RECOVERY_PUBLIC_KEY); } public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent, int userId) throws RemoteException { checkRecoverKeyStorePermission(); throw new UnsupportedOperationException(); } /** * Gets recovery snapshot versions for all accounts. Note that snapshot may have 0 application * keys, but it still needs to be synced, if previous versions were not empty. * * @return Map from Recovery agent account to snapshot version. */ public @NonNull Map<byte[], Integer> getRecoverySnapshotVersions(int userId) throws RemoteException { checkRecoverKeyStorePermission(); throw new UnsupportedOperationException(); } public void setServerParameters(long serverParameters, int userId) throws RemoteException { checkRecoverKeyStorePermission(); throw new UnsupportedOperationException(); Loading @@ -130,6 +150,21 @@ public class RecoverableKeyStoreManager { throw new UnsupportedOperationException(); } /** * Gets recovery status for keys {@code packageName}. * * @param packageName which recoverable keys statuses will be returned * @return Map from KeyStore alias to recovery status */ public @NonNull Map<String, Integer> getRecoveryStatus(@Nullable String packageName, int userId) throws RemoteException { // Any application should be able to check status for its own keys. // If caller is a recovery agent it can check statuses for other packages, but // only for recoverable keys it manages. checkRecoverKeyStorePermission(); throw new UnsupportedOperationException(); } /** * Sets recovery secrets list used by all recovery agents for given {@code userId} * Loading @@ -148,7 +183,7 @@ public class RecoverableKeyStoreManager { * @return secret types * @hide */ public int[] getRecoverySecretTypes(int userId) throws RemoteException { public @NonNull int[] getRecoverySecretTypes(int userId) throws RemoteException { checkRecoverKeyStorePermission(); throw new UnsupportedOperationException(); } Loading @@ -159,7 +194,7 @@ public class RecoverableKeyStoreManager { * @return secret types * @hide */ public int[] getPendingRecoverySecretTypes(int userId) throws RemoteException { public @NonNull int[] getPendingRecoverySecretTypes(int userId) throws RemoteException { checkRecoverKeyStorePermission(); throw new UnsupportedOperationException(); } Loading Loading @@ -188,7 +223,7 @@ public class RecoverableKeyStoreManager { * * @hide */ public byte[] startRecoverySession( public @NonNull byte[] startRecoverySession( @NonNull String sessionId, @NonNull byte[] verifierPublicKey, @NonNull byte[] vaultParams, Loading