Merge "Add more methods to RecoverableKeyStoreLoader."

This commit is contained in:
TreeHugger Robot
2017-12-21 02:01:15 +00:00
committed by Android (Google) Code Review
4 changed files with 155 additions and 8 deletions

View File

@@ -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.

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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,