summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/security/keystore/recovery/RecoveryController.java81
-rw-r--r--core/java/android/security/keystore/recovery/RecoverySession.java6
2 files changed, 68 insertions, 19 deletions
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 6c882e1cdf6e..48813757aaa8 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -99,7 +99,11 @@ public class RecoveryController {
public static final int ERROR_SESSION_EXPIRED = 24;
/**
- * Failed because the provided certificate was not a valid X509 certificate.
+ * Failed because the format of the provided certificate is incorrect, e.g., cannot be decoded
+ * properly or misses necessary fields.
+ *
+ * <p>Note that this is different from {@link #ERROR_INVALID_CERTIFICATE}, which implies the
+ * certificate has a correct format but cannot be validated.
*
* @hide
*/
@@ -121,6 +125,16 @@ public class RecoveryController {
*/
public static final int ERROR_INVALID_KEY_FORMAT = 27;
+ /**
+ * Failed because the provided certificate cannot be validated, e.g., is expired or has invalid
+ * signatures.
+ *
+ * <p>Note that this is different from {@link #ERROR_BAD_CERTIFICATE_FORMAT}, which denotes
+ * incorrect certificate formats, e.g., due to wrong encoding or structure.
+ *
+ * @hide
+ */
+ public static final int ERROR_INVALID_CERTIFICATE = 28;
private final ILockSettings mBinder;
private final KeyStore mKeyStore;
@@ -149,33 +163,66 @@ public class RecoveryController {
}
/**
- * Initializes key recovery service for the calling application. RecoveryController
- * randomly chooses one of the keys from the list and keeps it to use for future key export
- * operations. Collection of all keys in the list must be signed by the provided {@code
- * rootCertificateAlias}, which must also be present in the list of root certificates
- * preinstalled on the device. The random selection allows RecoveryController to select
- * which of a set of remote recovery service devices will be used.
- *
- * <p>In addition, RecoveryController enforces a delay of three months between
- * consecutive initialization attempts, to limit the ability of an attacker to often switch
- * remote recovery devices and significantly increase number of recovery attempts.
+ * @deprecated Use {@link #initRecoveryService(String, byte[], byte[])} instead.
+ */
+ @Deprecated
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
+ public void initRecoveryService(
+ @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
+ throws CertificateException, InternalRecoveryServiceException {
+ try {
+ mBinder.initRecoveryService(rootCertificateAlias, signedPublicKeyList);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == ERROR_INVALID_CERTIFICATE) {
+ throw new CertificateException(e.getMessage());
+ }
+ throw wrapUnexpectedServiceSpecificException(e);
+ }
+ }
+
+ /**
+ * Initializes the recovery service for the calling application. The detailed steps should be:
+ * <ol>
+ * <li>Parse {@code signatureFile} to get relevant information.
+ * <li>Validate the signer's X509 certificate, contained in {@code signatureFile}, against
+ * the root certificate pre-installed in the OS and chosen by {@code
+ * rootCertificateAlias}.
+ * <li>Verify the public-key signature, contained in {@code signatureFile}, and verify it
+ * against the entire {@code certificateFile}.
+ * <li>Parse {@code certificateFile} to get relevant information.
+ * <li>Check the serial number, contained in {@code certificateFile}, and skip the following
+ * steps if the serial number is not larger than the one previously stored.
+ * <li>Randomly choose a X509 certificate from the endpoint X509 certificates, contained in
+ * {@code certificateFile}, and validate it against the root certificate pre-installed
+ * in the OS and chosen by {@code rootCertificateAlias}.
+ * <li>Store the chosen X509 certificate and the serial in local database for later use.
+ * </ol>
*
- * @param rootCertificateAlias alias of a root certificate preinstalled on the device
- * @param signedPublicKeyList binary blob a list of X509 certificates and signature
- * @throws CertificateException if the {@code signedPublicKeyList} is in a bad format.
+ * @param rootCertificateAlias the alias of a root certificate pre-installed in the OS
+ * @param certificateFile the binary content of the XML file containing a list of recovery
+ * service X509 certificates, and other metadata including the serial number
+ * @param signatureFile the binary content of the XML file containing the public-key signature
+ * of the entire certificate file, and a signer's X509 certificate
+ * @throws CertificateException if the given certificate files cannot be parsed or validated
* @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
* service.
*/
@RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public void initRecoveryService(
- @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
+ @NonNull String rootCertificateAlias, @NonNull byte[] certificateFile,
+ @NonNull byte[] signatureFile)
throws CertificateException, InternalRecoveryServiceException {
try {
- mBinder.initRecoveryService(rootCertificateAlias, signedPublicKeyList);
+ mBinder.initRecoveryServiceWithSigFile(
+ rootCertificateAlias, certificateFile, signatureFile);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT) {
+ if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == ERROR_INVALID_CERTIFICATE) {
throw new CertificateException(e.getMessage());
}
throw wrapUnexpectedServiceSpecificException(e);
diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java
index 2b627b4fd45d..137dd8946c9a 100644
--- a/core/java/android/security/keystore/recovery/RecoverySession.java
+++ b/core/java/android/security/keystore/recovery/RecoverySession.java
@@ -94,7 +94,8 @@ public class RecoverySession implements AutoCloseable {
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT) {
+ if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == RecoveryController.ERROR_INVALID_CERTIFICATE) {
throw new CertificateException(e.getMessage());
}
throw mRecoveryController.wrapUnexpectedServiceSpecificException(e);
@@ -143,7 +144,8 @@ public class RecoverySession implements AutoCloseable {
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
- if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT) {
+ if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == RecoveryController.ERROR_INVALID_CERTIFICATE) {
throw new CertificateException(e.getMessage());
}
throw mRecoveryController.wrapUnexpectedServiceSpecificException(e);