summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorRobert Berry <robertberry@google.com>2018-01-17 14:43:09 +0000
committerRobert Berry <robertberry@google.com>2018-01-17 21:32:58 +0000
commita16cd59a3438383fb3473af4903b9ada596e5cb0 (patch)
tree790796023c58ca624c9b67de631b4f945c9e8497 /core/java
parentb1a00d5e16fd1b5ebb39e0d462c5216bc453e701 (diff)
Create exception hierarchy for RecoveryController
Sets up a sensible exception hierarchy. Consolidates two error codes that both represented some kind of internal error into a single code. Fixed some cases where the wrong error codes were used to signal. Test: adb shell am instrument -w -e package com.android.server.locksettings.recoverablekeystore com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner Change-Id: I6b1f97715cdc28a4be79912abb6f48e6657b048b
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/security/keystore/BadCertificateFormatException.java28
-rw-r--r--core/java/android/security/keystore/DecryptionFailedException.java30
-rw-r--r--core/java/android/security/keystore/InternalRecoveryServiceException.java35
-rw-r--r--core/java/android/security/keystore/LockScreenRequiredException.java30
-rw-r--r--core/java/android/security/keystore/RecoveryControllerException.java36
-rw-r--r--core/java/android/security/keystore/RecoveryManager.java195
-rw-r--r--core/java/android/security/keystore/RecoveryManagerException.java111
-rw-r--r--core/java/android/security/keystore/SessionExpiredException.java28
8 files changed, 334 insertions, 159 deletions
diff --git a/core/java/android/security/keystore/BadCertificateFormatException.java b/core/java/android/security/keystore/BadCertificateFormatException.java
new file mode 100644
index 000000000000..ddc7bd2366ac
--- /dev/null
+++ b/core/java/android/security/keystore/BadCertificateFormatException.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+/**
+ * Error thrown when the recovery agent supplies an invalid X509 certificate.
+ *
+ * @hide
+ */
+public class BadCertificateFormatException extends RecoveryControllerException {
+ public BadCertificateFormatException(String msg) {
+ super(msg);
+ }
+}
diff --git a/core/java/android/security/keystore/DecryptionFailedException.java b/core/java/android/security/keystore/DecryptionFailedException.java
new file mode 100644
index 000000000000..945fcf6f88f2
--- /dev/null
+++ b/core/java/android/security/keystore/DecryptionFailedException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+/**
+ * Error thrown when decryption failed, due to an agent error. i.e., using the incorrect key,
+ * trying to decrypt garbage data, trying to decrypt data that has somehow been corrupted, etc.
+ *
+ * @hide
+ */
+public class DecryptionFailedException extends RecoveryControllerException {
+
+ public DecryptionFailedException(String msg) {
+ super(msg);
+ }
+}
diff --git a/core/java/android/security/keystore/InternalRecoveryServiceException.java b/core/java/android/security/keystore/InternalRecoveryServiceException.java
new file mode 100644
index 000000000000..85829bed9191
--- /dev/null
+++ b/core/java/android/security/keystore/InternalRecoveryServiceException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+/**
+ * An error thrown when something went wrong internally in the recovery service.
+ *
+ * <p>This is an unexpected error, and indicates a problem with the service itself, rather than the
+ * caller having performed some kind of illegal action.
+ *
+ * @hide
+ */
+public class InternalRecoveryServiceException extends RecoveryControllerException {
+ public InternalRecoveryServiceException(String msg) {
+ super(msg);
+ }
+
+ public InternalRecoveryServiceException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/core/java/android/security/keystore/LockScreenRequiredException.java b/core/java/android/security/keystore/LockScreenRequiredException.java
new file mode 100644
index 000000000000..b07fb9cdd002
--- /dev/null
+++ b/core/java/android/security/keystore/LockScreenRequiredException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+/**
+ * Error thrown when trying to generate keys for a profile that has no lock screen set.
+ *
+ * <p>A lock screen must be set, as the lock screen is used to encrypt the snapshot.
+ *
+ * @hide
+ */
+public class LockScreenRequiredException extends RecoveryControllerException {
+ public LockScreenRequiredException(String msg) {
+ super(msg);
+ }
+}
diff --git a/core/java/android/security/keystore/RecoveryControllerException.java b/core/java/android/security/keystore/RecoveryControllerException.java
new file mode 100644
index 000000000000..31fd4af9a7d1
--- /dev/null
+++ b/core/java/android/security/keystore/RecoveryControllerException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * Base exception for errors thrown by {@link RecoveryManager}.
+ *
+ * @hide
+ */
+public abstract class RecoveryControllerException extends GeneralSecurityException {
+ RecoveryControllerException() { }
+
+ RecoveryControllerException(String msg) {
+ super(msg);
+ }
+
+ public RecoveryControllerException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/core/java/android/security/keystore/RecoveryManager.java b/core/java/android/security/keystore/RecoveryManager.java
index bddf3e849182..6177cd76bed4 100644
--- a/core/java/android/security/keystore/RecoveryManager.java
+++ b/core/java/android/security/keystore/RecoveryManager.java
@@ -46,6 +46,52 @@ public class RecoveryManager {
/** Key cannot be synced. */
public static final int RECOVERY_STATUS_PERMANENT_FAILURE = 3;
+ /**
+ * Failed because no snapshot is yet pending to be synced for the user.
+ *
+ * @hide
+ */
+ public static final int ERROR_NO_SNAPSHOT_PENDING = 21;
+
+ /**
+ * Failed due to an error internal to the recovery service. This is unexpected and indicates
+ * either a problem with the logic in the service, or a problem with a dependency of the
+ * service (such as AndroidKeyStore).
+ *
+ * @hide
+ */
+ public static final int ERROR_SERVICE_INTERNAL_ERROR = 22;
+
+ /**
+ * Failed because the user does not have a lock screen set.
+ *
+ * @hide
+ */
+ public static final int ERROR_INSECURE_USER = 23;
+
+ /**
+ * Error thrown when attempting to use a recovery session that has since been closed.
+ *
+ * @hide
+ */
+ public static final int ERROR_SESSION_EXPIRED = 24;
+
+ /**
+ * Failed because the provided certificate was not a valid X509 certificate.
+ *
+ * @hide
+ */
+ public static final int ERROR_BAD_CERTIFICATE_FORMAT = 25;
+
+ /**
+ * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong,
+ * the data has become corrupted, the data has been tampered with, etc.
+ *
+ * @hide
+ */
+ public static final int ERROR_DECRYPTION_FAILED = 26;
+
+
private final ILockSettings mBinder;
private RecoveryManager(ILockSettings binder) {
@@ -75,19 +121,22 @@ public class RecoveryManager {
*
* @param rootCertificateAlias alias of a root certificate preinstalled on the device
* @param signedPublicKeyList binary blob a list of X509 certificates and signature
- * @throws RecoveryManagerException if signature is invalid, or key rotation was rate
- * limited.
- * @hide
+ * @throws BadCertificateFormatException if the {@code signedPublicKeyList} is in a bad format.
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
public void initRecoveryService(
@NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
- throws RecoveryManagerException {
+ throws BadCertificateFormatException, InternalRecoveryServiceException {
try {
mBinder.initRecoveryService(rootCertificateAlias, signedPublicKeyList);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT) {
+ throw new BadCertificateFormatException(e.getMessage());
+ }
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -97,17 +146,20 @@ public class RecoveryManager {
*
* @param account specific to Recovery agent.
* @return Data necessary to recover keystore.
- * @hide
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
- @NonNull public KeychainSnapshot getRecoveryData(@NonNull byte[] account)
- throws RecoveryManagerException {
+ public @NonNull KeychainSnapshot getRecoveryData(@NonNull byte[] account)
+ throws InternalRecoveryServiceException {
try {
- KeychainSnapshot keychainSnapshot = mBinder.getRecoveryData(account);
- return keychainSnapshot;
+ return mBinder.getRecoveryData(account);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ if (e.errorCode == ERROR_NO_SNAPSHOT_PENDING) {
+ return null;
+ }
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -118,16 +170,17 @@ public class RecoveryManager {
*
* @param intent triggered when new snapshot is available. Unregisters listener if the value is
* {@code null}.
- * @hide
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent)
- throws RecoveryManagerException {
+ throws InternalRecoveryServiceException {
try {
mBinder.setSnapshotCreatedPendingIntent(intent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -137,10 +190,11 @@ public class RecoveryManager {
*
* @return Map from recovery agent accounts to snapshot versions.
* @see KeychainSnapshot#getSnapshotVersion
- * @hide
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
public @NonNull Map<byte[], Integer> getRecoverySnapshotVersions()
- throws RecoveryManagerException {
+ throws InternalRecoveryServiceException {
try {
// IPC doesn't support generic Maps.
@SuppressWarnings("unchecked")
@@ -150,7 +204,7 @@ public class RecoveryManager {
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -161,16 +215,16 @@ public class RecoveryManager {
*
* @param serverParams included in recovery key blob.
* @see #getRecoveryData
- * @throws RecoveryManagerException If parameters rotation is rate limited.
- * @hide
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
- public void setServerParams(byte[] serverParams) throws RecoveryManagerException {
+ public void setServerParams(byte[] serverParams) throws InternalRecoveryServiceException {
try {
mBinder.setServerParams(serverParams);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -183,16 +237,18 @@ public class RecoveryManager {
* @param aliases List of application-specific key aliases. If the array is empty, updates the
* status for all existing recoverable keys.
* @param status Status specific to recovery agent.
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
public void setRecoveryStatus(
@NonNull String packageName, @Nullable String[] aliases, int status)
- throws NameNotFoundException, RecoveryManagerException {
+ throws NameNotFoundException, InternalRecoveryServiceException {
try {
mBinder.setRecoveryStatus(packageName, aliases, status);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -209,10 +265,10 @@ public class RecoveryManager {
*
* @return {@code Map} from KeyStore alias to recovery status.
* @see #setRecoveryStatus
- * @hide
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
- public Map<String, Integer> getRecoveryStatus()
- throws RecoveryManagerException {
+ public Map<String, Integer> getRecoveryStatus() throws InternalRecoveryServiceException {
try {
// IPC doesn't support generic Maps.
@SuppressWarnings("unchecked")
@@ -222,7 +278,7 @@ public class RecoveryManager {
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -232,16 +288,18 @@ public class RecoveryManager {
*
* @param secretTypes {@link KeychainProtectionParameter#TYPE_LOCKSCREEN} or {@link
* KeychainProtectionParameter#TYPE_CUSTOM_PASSWORD}
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
public void setRecoverySecretTypes(
@NonNull @KeychainProtectionParameter.UserSecretType int[] secretTypes)
- throws RecoveryManagerException {
+ throws InternalRecoveryServiceException {
try {
mBinder.setRecoverySecretTypes(secretTypes);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -251,15 +309,17 @@ public class RecoveryManager {
*
* @return list of recovery secret types
* @see KeychainSnapshot
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
- @NonNull public @KeychainProtectionParameter.UserSecretType int[] getRecoverySecretTypes()
- throws RecoveryManagerException {
+ public @NonNull @KeychainProtectionParameter.UserSecretType int[] getRecoverySecretTypes()
+ throws InternalRecoveryServiceException {
try {
return mBinder.getRecoverySecretTypes();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -269,17 +329,18 @@ public class RecoveryManager {
* called.
*
* @return list of recovery secret types
- * @hide
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
@NonNull
public @KeychainProtectionParameter.UserSecretType int[] getPendingRecoverySecretTypes()
- throws RecoveryManagerException {
+ throws InternalRecoveryServiceException {
try {
return mBinder.getPendingRecoverySecretTypes();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -291,16 +352,17 @@ public class RecoveryManager {
*
* @param recoverySecret user generated secret together with parameters necessary to regenerate
* it on a new device.
- * @hide
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
public void recoverySecretAvailable(@NonNull KeychainProtectionParameter recoverySecret)
- throws RecoveryManagerException {
+ throws InternalRecoveryServiceException {
try {
mBinder.recoverySecretAvailable(recoverySecret);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -321,6 +383,10 @@ public class RecoveryManager {
* @return Binary blob with recovery claim. It is encrypted with verifierPublicKey and contains
* a proof of user secrets, session symmetric key and parameters necessary to identify the
* counter with the number of failed recovery attempts.
+ * @throws BadCertificateFormatException if the {@code verifierPublicKey} is in an incorrect
+ * format.
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
public @NonNull byte[] startRecoverySession(
@NonNull String sessionId,
@@ -328,7 +394,7 @@ public class RecoveryManager {
@NonNull byte[] vaultParams,
@NonNull byte[] vaultChallenge,
@NonNull List<KeychainProtectionParameter> secrets)
- throws RecoveryManagerException {
+ throws BadCertificateFormatException, InternalRecoveryServiceException {
try {
byte[] recoveryClaim =
mBinder.startRecoverySession(
@@ -341,7 +407,10 @@ public class RecoveryManager {
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT) {
+ throw new BadCertificateFormatException(e.getMessage());
+ }
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -355,19 +424,29 @@ public class RecoveryManager {
* and session. KeyStore only uses package names from the application info in {@link
* WrappedApplicationKey}. Caller is responsibility to perform certificates check.
* @return Map from alias to raw key material.
+ * @throws SessionExpiredException if {@code session} has since been closed.
+ * @throws DecryptionFailedException if unable to decrypt the snapshot.
+ * @throws InternalRecoveryServiceException if an error occurs internal to the recovery service.
*/
public Map<String, byte[]> recoverKeys(
@NonNull String sessionId,
@NonNull byte[] recoveryKeyBlob,
@NonNull List<WrappedApplicationKey> applicationKeys)
- throws RecoveryManagerException {
+ throws SessionExpiredException, DecryptionFailedException,
+ InternalRecoveryServiceException {
try {
return (Map<String, byte[]>) mBinder.recoverKeys(
sessionId, recoveryKeyBlob, applicationKeys);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ if (e.errorCode == ERROR_DECRYPTION_FAILED) {
+ throw new DecryptionFailedException(e.getMessage());
+ }
+ if (e.errorCode == ERROR_SESSION_EXPIRED) {
+ throw new SessionExpiredException(e.getMessage());
+ }
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -376,17 +455,23 @@ public class RecoveryManager {
* raw material of the key.
*
* @param alias The key alias.
- * @throws RecoveryManagerException if an error occurred generating and storing the
- * key.
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
+ * @throws LockScreenRequiredException if the user has not set a lock screen. This is required
+ * to generate recoverable keys, as the snapshots are encrypted using a key derived from the
+ * lock screen.
*/
public byte[] generateAndStoreKey(@NonNull String alias)
- throws RecoveryManagerException {
+ throws InternalRecoveryServiceException, LockScreenRequiredException {
try {
return mBinder.generateAndStoreKey(alias);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ if (e.errorCode == ERROR_INSECURE_USER) {
+ throw new LockScreenRequiredException(e.getMessage());
+ }
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
@@ -394,14 +479,28 @@ public class RecoveryManager {
* Removes a key called {@code alias} from the recoverable key store.
*
* @param alias The key alias.
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
*/
- public void removeKey(@NonNull String alias) throws RecoveryManagerException {
+ public void removeKey(@NonNull String alias) throws InternalRecoveryServiceException {
try {
mBinder.removeKey(alias);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- throw RecoveryManagerException.fromServiceSpecificException(e);
+ throw wrapUnexpectedServiceSpecificException(e);
}
}
+
+ private InternalRecoveryServiceException wrapUnexpectedServiceSpecificException(
+ ServiceSpecificException e) {
+ if (e.errorCode == ERROR_SERVICE_INTERNAL_ERROR) {
+ return new InternalRecoveryServiceException(e.getMessage());
+ }
+
+ // Should never happen. If it does, it's a bug, and we need to update how the method that
+ // called this throws its exceptions.
+ return new InternalRecoveryServiceException("Unexpected error code for method: "
+ + e.errorCode, e);
+ }
}
diff --git a/core/java/android/security/keystore/RecoveryManagerException.java b/core/java/android/security/keystore/RecoveryManagerException.java
deleted file mode 100644
index 344718aa31d4..000000000000
--- a/core/java/android/security/keystore/RecoveryManagerException.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.os.ServiceSpecificException;
-
-/**
- * Exception thrown by {@link RecoveryManager} methods.
- *
- * @hide
- */
-public class RecoveryManagerException extends Exception {
- /**
- * Failed because the loader has not been initialized with a recovery public key yet.
- */
- public static final int ERROR_UNINITIALIZED_RECOVERY_PUBLIC_KEY = 20;
-
- /**
- * Failed because no snapshot is yet pending to be synced for the user.
- */
- public static final int ERROR_NO_SNAPSHOT_PENDING = 21;
-
- /**
- * Failed due to an error internal to AndroidKeyStore.
- */
- public static final int ERROR_KEYSTORE_INTERNAL_ERROR = 22;
-
- /**
- * Failed because the user does not have a lock screen set.
- */
- public static final int ERROR_INSECURE_USER = 24;
-
- /**
- * Failed because of an internal database error.
- */
- public static final int ERROR_DATABASE_ERROR = 25;
-
- /**
- * Failed because the provided certificate was not a valid X509 certificate.
- */
- public static final int ERROR_BAD_X509_CERTIFICATE = 26;
-
- /**
- * Should never be thrown - some algorithm that all AOSP implementations must support is
- * not available.
- */
- public static final int ERROR_UNEXPECTED_MISSING_ALGORITHM = 27;
-
- /**
- * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong,
- * the data has become corrupted, the data has been tampered with, etc.
- */
- public static final int ERROR_DECRYPTION_FAILED = 28;
-
- /**
- * 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 ERROR_RATE_LIMIT_EXCEEDED = 29;
-
- private int mErrorCode;
-
- /**
- * Creates new {@link #RecoveryManagerException} instance from the error code.
- *
- * @param errorCode An error code, as listed at the top of this file.
- * @param message The associated error message.
- * @hide
- */
- public static RecoveryManagerException fromErrorCode(
- int errorCode, String message) {
- return new RecoveryManagerException(errorCode, message);
- }
- /**
- * Creates new {@link #RecoveryManagerException} from {@link
- * ServiceSpecificException}.
- *
- * @param e exception thrown on service side.
- * @hide
- */
- static RecoveryManagerException fromServiceSpecificException(
- ServiceSpecificException e) throws RecoveryManagerException {
- throw RecoveryManagerException.fromErrorCode(e.errorCode, e.getMessage());
- }
-
- private RecoveryManagerException(int errorCode, String message) {
- super(message);
- mErrorCode = errorCode;
- }
-
- /** Returns errorCode. */
- public int getErrorCode() {
- return mErrorCode;
- }
-}
diff --git a/core/java/android/security/keystore/SessionExpiredException.java b/core/java/android/security/keystore/SessionExpiredException.java
new file mode 100644
index 000000000000..f13e20602625
--- /dev/null
+++ b/core/java/android/security/keystore/SessionExpiredException.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+/**
+ * Error thrown when attempting to use a {@link RecoverySession} that has since expired.
+ *
+ * @hide
+ */
+public class SessionExpiredException extends RecoveryControllerException {
+ public SessionExpiredException(String msg) {
+ super(msg);
+ }
+}