Merge "Add more methods to RecoverableKeyStoreLoader."
This commit is contained in:
committed by
Android (Google) Code Review
commit
0be794a14c
@@ -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;
|
||||
@@ -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
|
||||
@@ -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) {
|
||||
@@ -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 =
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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();
|
||||
@@ -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}
|
||||
*
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -188,7 +223,7 @@ public class RecoverableKeyStoreManager {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public byte[] startRecoverySession(
|
||||
public @NonNull byte[] startRecoverySession(
|
||||
@NonNull String sessionId,
|
||||
@NonNull byte[] verifierPublicKey,
|
||||
@NonNull byte[] vaultParams,
|
||||
|
||||
Reference in New Issue
Block a user