blob: b5ec79567734d1c6fc0fba0599ad71ad0c973784 [file] [log] [blame]
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.security.recoverablekeystore;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -080021import android.app.PendingIntent;
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -080022import android.content.pm.PackageManager.NameNotFoundException;
Dmitry Dementyev1aa96132017-12-11 11:33:12 -080023import android.os.RemoteException;
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -080024import android.os.ServiceManager;
Dmitry Dementyev1aa96132017-12-11 11:33:12 -080025import android.os.ServiceSpecificException;
Dmitry Dementyev1aa96132017-12-11 11:33:12 -080026import android.security.KeyStore;
27import android.util.AndroidException;
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -080028
29import com.android.internal.widget.ILockSettings;
30
31import java.util.List;
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -080032import java.util.Map;
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -080033
34/**
Dmitry Dementyev1aa96132017-12-11 11:33:12 -080035 * A wrapper around KeyStore which lets key be exported to trusted hardware on server side and
36 * recovered later.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -080037 *
38 * @hide
39 */
Dmitry Dementyev1aa96132017-12-11 11:33:12 -080040public class RecoverableKeyStoreLoader {
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -080041
Dmitry Dementyev1aa96132017-12-11 11:33:12 -080042 public static final String PERMISSION_RECOVER_KEYSTORE = "android.permission.RECOVER_KEYSTORE";
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -080043
Dmitry Dementyev1aa96132017-12-11 11:33:12 -080044 public static final int NO_ERROR = KeyStore.NO_ERROR;
45 public static final int SYSTEM_ERROR = KeyStore.SYSTEM_ERROR;
Robert Berry97e55582018-01-05 12:43:13 +000046
47 /**
48 * Failed because the loader has not been initialized with a recovery public key yet.
49 */
Dmitry Dementyev14298312018-01-04 15:19:19 -080050 public static final int ERROR_UNINITIALIZED_RECOVERY_PUBLIC_KEY = 20;
Robert Berry97e55582018-01-05 12:43:13 +000051
52 /**
53 * Failed because no snapshot is yet pending to be synced for the user.
54 */
Dmitry Dementyev14298312018-01-04 15:19:19 -080055 public static final int ERROR_NO_SNAPSHOT_PENDING = 21;
Robert Berry97e55582018-01-05 12:43:13 +000056
57 /**
58 * Failed due to an error internal to AndroidKeyStore.
59 */
Dmitry Dementyev14298312018-01-04 15:19:19 -080060 public static final int ERROR_KEYSTORE_INTERNAL_ERROR = 22;
Robert Berry97e55582018-01-05 12:43:13 +000061
62 /**
63 * Failed because the user does not have a lock screen set.
64 */
Dmitry Dementyev14298312018-01-04 15:19:19 -080065 public static final int ERROR_INSECURE_USER = 24;
Robert Berrybd086f12017-12-27 13:29:39 +000066
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -080067 /**
Robert Berry97e55582018-01-05 12:43:13 +000068 * Failed because of an internal database error.
69 */
70 public static final int ERROR_DATABASE_ERROR = 25;
71
72 /**
73 * Failed because the provided certificate was not a valid X509 certificate.
74 */
75 public static final int ERROR_BAD_X509_CERTIFICATE = 26;
76
77 /**
78 * Should never be thrown - some algorithm that all AOSP implementations must support is
79 * not available.
80 */
81 public static final int ERROR_UNEXPECTED_MISSING_ALGORITHM = 27;
82
83 /**
84 * The caller is attempting to perform an operation that is not yet fully supported in the API.
85 */
86 public static final int ERROR_NOT_YET_SUPPORTED = 28;
87
88 /**
89 * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong,
90 * the data has become corrupted, the data has been tampered with, etc.
91 */
92 public static final int ERROR_DECRYPTION_FAILED = 29;
93
94 /**
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -080095 * Rate limit is enforced to prevent using too many trusted remote devices, since each device
96 * can have its own number of user secret guesses allowed.
97 *
98 * @hide
99 */
Robert Berry97e55582018-01-05 12:43:13 +0000100 public static final int ERROR_RATE_LIMIT_EXCEEDED = 30;
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800101
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -0800102 /** Key has been successfully synced. */
103 public static final int RECOVERY_STATUS_SYNCED = 0;
104 /** Waiting for recovery agent to sync the key. */
105 public static final int RECOVERY_STATUS_SYNC_IN_PROGRESS = 1;
106 /** Recovery account is not available. */
107 public static final int RECOVERY_STATUS_MISSING_ACCOUNT = 2;
108 /** Key cannot be synced. */
109 public static final int RECOVERY_STATUS_PERMANENT_FAILURE = 3;
110
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800111 private final ILockSettings mBinder;
112
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800113 private RecoverableKeyStoreLoader(ILockSettings binder) {
114 mBinder = binder;
115 }
116
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800117 /** @hide */
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800118 public static RecoverableKeyStoreLoader getInstance() {
119 ILockSettings lockSettings =
120 ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings"));
121 return new RecoverableKeyStoreLoader(lockSettings);
122 }
123
124 /**
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800125 * Exceptions returned by {@link RecoverableKeyStoreLoader}.
126 *
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800127 * @hide
128 */
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800129 public static class RecoverableKeyStoreLoaderException extends AndroidException {
130 private int mErrorCode;
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800131
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800132 /**
133 * Creates new {@link #RecoverableKeyStoreLoaderException} instance from the error code.
134 *
Robert Berry97e55582018-01-05 12:43:13 +0000135 * @param errorCode An error code, as listed at the top of this file.
136 * @param message The associated error message.
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800137 * @hide
138 */
Robert Berry97e55582018-01-05 12:43:13 +0000139 public static RecoverableKeyStoreLoaderException fromErrorCode(
140 int errorCode, String message) {
141 return new RecoverableKeyStoreLoaderException(errorCode, message);
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800142 }
143
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800144 /**
145 * Creates new {@link #RecoverableKeyStoreLoaderException} from {@link
146 * ServiceSpecificException}.
147 *
148 * @param e exception thrown on service side.
149 * @hide
150 */
151 static RecoverableKeyStoreLoaderException fromServiceSpecificException(
152 ServiceSpecificException e) throws RecoverableKeyStoreLoaderException {
Robert Berry97e55582018-01-05 12:43:13 +0000153 throw RecoverableKeyStoreLoaderException.fromErrorCode(e.errorCode, e.getMessage());
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800154 }
155
156 private RecoverableKeyStoreLoaderException(int errorCode, String message) {
157 super(message);
Robert Berry97e55582018-01-05 12:43:13 +0000158 mErrorCode = errorCode;
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800159 }
160
161 /** Returns errorCode. */
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800162 public int getErrorCode() {
163 return mErrorCode;
164 }
165 }
166
167 /**
168 * Initializes key recovery service for the calling application. RecoverableKeyStoreLoader
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800169 * randomly chooses one of the keys from the list and keeps it to use for future key export
170 * operations. Collection of all keys in the list must be signed by the provided {@code
171 * rootCertificateAlias}, which must also be present in the list of root certificates
172 * preinstalled on the device. The random selection allows RecoverableKeyStoreLoader to select
173 * which of a set of remote recovery service devices will be used.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800174 *
175 * <p>In addition, RecoverableKeyStoreLoader enforces a delay of three months between
176 * consecutive initialization attempts, to limit the ability of an attacker to often switch
177 * remote recovery devices and significantly increase number of recovery attempts.
178 *
179 * @param rootCertificateAlias alias of a root certificate preinstalled on the device
180 * @param signedPublicKeyList binary blob a list of X509 certificates and signature
181 * @throws RecoverableKeyStoreLoaderException if signature is invalid, or key rotation was rate
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800182 * limited.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800183 * @hide
184 */
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800185 public void initRecoveryService(
186 @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800187 throws RecoverableKeyStoreLoaderException {
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800188 try {
Dmitry Dementyev14298312018-01-04 15:19:19 -0800189 mBinder.initRecoveryService(rootCertificateAlias, signedPublicKeyList);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800190 } catch (RemoteException e) {
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800191 throw e.rethrowFromSystemServer();
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800192 } catch (ServiceSpecificException e) {
193 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
194 }
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800195 }
196
197 /**
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800198 * Returns data necessary to store all recoverable keys for given account. Key material is
199 * encrypted with user secret and recovery public key.
200 *
201 * @param account specific to Recovery agent.
202 * @return Data necessary to recover keystore.
203 * @hide
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800204 */
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -0800205 public @NonNull KeyStoreRecoveryData getRecoveryData(@NonNull byte[] account)
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800206 throws RecoverableKeyStoreLoaderException {
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800207 try {
Dmitry Dementyev14298312018-01-04 15:19:19 -0800208 KeyStoreRecoveryData recoveryData = mBinder.getRecoveryData(account);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800209 return recoveryData;
210 } catch (RemoteException e) {
211 throw e.rethrowFromSystemServer();
212 } catch (ServiceSpecificException e) {
213 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
214 }
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800215 }
216
217 /**
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -0800218 * Sets a listener which notifies recovery agent that new recovery snapshot is available. {@link
219 * #getRecoveryData} can be used to get the snapshot. Note that every recovery agent can have at
220 * most one registered listener at any time.
221 *
222 * @param intent triggered when new snapshot is available. Unregisters listener if the value is
223 * {@code null}.
224 * @hide
225 */
226 public void setSnapshotCreatedPendingIntent(@Nullable PendingIntent intent)
227 throws RecoverableKeyStoreLoaderException {
228 try {
Dmitry Dementyev14298312018-01-04 15:19:19 -0800229 mBinder.setSnapshotCreatedPendingIntent(intent);
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -0800230 } catch (RemoteException e) {
231 throw e.rethrowFromSystemServer();
232 } catch (ServiceSpecificException e) {
233 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
234 }
235 }
236
237 /**
238 * Returns a map from recovery agent accounts to corresponding KeyStore recovery snapshot
239 * version. Version zero is used, if no snapshots were created for the account.
240 *
241 * @return Map from recovery agent accounts to snapshot versions.
Bo Zhu584b923f2017-12-22 16:05:15 -0800242 * @see KeyStoreRecoveryData#getSnapshotVersion
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -0800243 * @hide
244 */
245 public @NonNull Map<byte[], Integer> getRecoverySnapshotVersions()
246 throws RecoverableKeyStoreLoaderException {
247 try {
248 // IPC doesn't support generic Maps.
249 @SuppressWarnings("unchecked")
250 Map<byte[], Integer> result =
Dmitry Dementyev14298312018-01-04 15:19:19 -0800251 (Map<byte[], Integer>) mBinder.getRecoverySnapshotVersions();
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -0800252 return result;
253 } catch (RemoteException e) {
254 throw e.rethrowFromSystemServer();
255 } catch (ServiceSpecificException e) {
256 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
257 }
258 }
259
260 /**
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800261 * Server parameters used to generate new recovery key blobs. This value will be included in
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800262 * {@code KeyStoreRecoveryData.getEncryptedRecoveryKeyBlob()}. The same value must be included
Bo Zhu584b923f2017-12-22 16:05:15 -0800263 * in vaultParams {@link #startRecoverySession}
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800264 *
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800265 * @param serverParameters included in recovery key blob.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800266 * @see #getRecoveryData
267 * @throws RecoverableKeyStoreLoaderException If parameters rotation is rate limited.
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800268 * @hide
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800269 */
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800270 public void setServerParameters(long serverParameters)
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800271 throws RecoverableKeyStoreLoaderException {
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800272 try {
Dmitry Dementyev14298312018-01-04 15:19:19 -0800273 mBinder.setServerParameters(serverParameters);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800274 } catch (RemoteException e) {
275 throw e.rethrowFromSystemServer();
276 } catch (ServiceSpecificException e) {
277 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
278 }
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800279 }
280
281 /**
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800282 * Updates recovery status for given keys. It is used to notify keystore that key was
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -0800283 * successfully stored on the server or there were an error. Application can check this value
284 * using {@code getRecoveyStatus}.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800285 *
286 * @param packageName Application whose recoverable keys' statuses are to be updated.
287 * @param aliases List of application-specific key aliases. If the array is empty, updates the
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800288 * status for all existing recoverable keys.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800289 * @param status Status specific to recovery agent.
290 */
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800291 public void setRecoveryStatus(
292 @NonNull String packageName, @Nullable String[] aliases, int status)
293 throws NameNotFoundException, RecoverableKeyStoreLoaderException {
294 try {
Dmitry Dementyev14298312018-01-04 15:19:19 -0800295 mBinder.setRecoveryStatus(packageName, aliases, status);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800296 } catch (RemoteException e) {
297 throw e.rethrowFromSystemServer();
298 } catch (ServiceSpecificException e) {
299 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
300 }
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800301 }
302
303 /**
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -0800304 * Returns a {@code Map} from Application's KeyStore key aliases to their recovery status.
305 * Negative status values are reserved for recovery agent specific codes. List of common codes:
306 *
307 * <ul>
308 * <li>{@link #RECOVERY_STATUS_SYNCED}
309 * <li>{@link #RECOVERY_STATUS_SYNC_IN_PROGRESS}
310 * <li>{@link #RECOVERY_STATUS_MISSING_ACCOUNT}
311 * <li>{@link #RECOVERY_STATUS_PERMANENT_FAILURE}
312 * </ul>
313 *
314 * @param packageName Application whose recoverable keys' statuses are to be retrieved. if
315 * {@code null} caller's package will be used.
316 * @return {@code Map} from KeyStore alias to recovery status.
317 * @see #setRecoveryStatus
318 * @hide
319 */
320 public Map<String, Integer> getRecoveryStatus(@Nullable String packageName)
321 throws RecoverableKeyStoreLoaderException {
322 try {
323 // IPC doesn't support generic Maps.
324 @SuppressWarnings("unchecked")
325 Map<String, Integer> result =
326 (Map<String, Integer>)
Dmitry Dementyev14298312018-01-04 15:19:19 -0800327 mBinder.getRecoveryStatus(packageName);
Dmitry Dementyevb8b030b2017-12-19 11:02:54 -0800328 return result;
329 } catch (RemoteException e) {
330 throw e.rethrowFromSystemServer();
331 } catch (ServiceSpecificException e) {
332 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
333 }
334 }
335
336 /**
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800337 * Specifies a set of secret types used for end-to-end keystore encryption. Knowing all of them
338 * is necessary to recover data.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800339 *
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800340 * @param secretTypes {@link KeyStoreRecoveryMetadata#TYPE_LOCKSCREEN} or {@link
341 * KeyStoreRecoveryMetadata#TYPE_CUSTOM_PASSWORD}
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800342 */
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800343 public void setRecoverySecretTypes(
344 @NonNull @KeyStoreRecoveryMetadata.UserSecretType int[] secretTypes)
345 throws RecoverableKeyStoreLoaderException {
346 try {
Dmitry Dementyev14298312018-01-04 15:19:19 -0800347 mBinder.setRecoverySecretTypes(secretTypes);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800348 } catch (RemoteException e) {
349 throw e.rethrowFromSystemServer();
350 } catch (ServiceSpecificException e) {
351 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
352 }
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800353 }
354
355 /**
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800356 * Defines a set of secret types used for end-to-end keystore encryption. Knowing all of them is
357 * necessary to generate KeyStoreRecoveryData.
358 *
359 * @return list of recovery secret types
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800360 * @see KeyStoreRecoveryData
361 */
362 public @NonNull @KeyStoreRecoveryMetadata.UserSecretType int[] getRecoverySecretTypes()
363 throws RecoverableKeyStoreLoaderException {
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800364 try {
Dmitry Dementyev14298312018-01-04 15:19:19 -0800365 return mBinder.getRecoverySecretTypes();
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800366 } catch (RemoteException e) {
367 throw e.rethrowFromSystemServer();
368 } catch (ServiceSpecificException e) {
369 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
370 }
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800371 }
372
373 /**
374 * Returns a list of recovery secret types, necessary to create a pending recovery snapshot.
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800375 * When user enters a secret of a pending type {@link #recoverySecretAvailable} should be
376 * called.
377 *
378 * @return list of recovery secret types
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800379 */
380 public @NonNull @KeyStoreRecoveryMetadata.UserSecretType int[] getPendingRecoverySecretTypes()
381 throws RecoverableKeyStoreLoaderException {
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800382 try {
Dmitry Dementyev14298312018-01-04 15:19:19 -0800383 return mBinder.getPendingRecoverySecretTypes();
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800384 } catch (RemoteException e) {
385 throw e.rethrowFromSystemServer();
386 } catch (ServiceSpecificException e) {
387 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
388 }
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800389 }
390
391 /**
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800392 * Method notifies KeyStore that a user-generated secret is available. This method generates a
393 * symmetric session key which a trusted remote device can use to return a recovery key. Caller
394 * should use {@link KeyStoreRecoveryMetadata#clearSecret} to override the secret value in
395 * memory.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800396 *
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800397 * @param recoverySecret user generated secret together with parameters necessary to regenerate
398 * it on a new device.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800399 */
400 public void recoverySecretAvailable(@NonNull KeyStoreRecoveryMetadata recoverySecret)
401 throws RecoverableKeyStoreLoaderException {
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800402 try {
Dmitry Dementyev14298312018-01-04 15:19:19 -0800403 mBinder.recoverySecretAvailable(recoverySecret);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800404 } catch (RemoteException e) {
405 throw e.rethrowFromSystemServer();
406 } catch (ServiceSpecificException e) {
407 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
408 }
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800409 }
410
411 /**
412 * Initializes recovery session and returns a blob with proof of recovery secrets possession.
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800413 * The method generates symmetric key for a session, which trusted remote device can use to
414 * return recovery key.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800415 *
416 * @param sessionId ID for recovery session.
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800417 * @param verifierPublicKey Certificate with Public key used to create the recovery blob on the
418 * source device. Keystore will verify the certificate using root of trust.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800419 * @param vaultParams Must match the parameters in the corresponding field in the recovery blob.
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800420 * Used to limit number of guesses.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800421 * @param vaultChallenge Data passed from server for this recovery session and used to prevent
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800422 * replay attacks
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800423 * @param secrets Secrets provided by user, the method only uses type and secret fields.
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800424 * @return Binary blob with recovery claim. It is encrypted with verifierPublicKey and contains
425 * a proof of user secrets, session symmetric key and parameters necessary to identify the
426 * counter with the number of failed recovery attempts.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800427 */
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800428 public @NonNull byte[] startRecoverySession(
429 @NonNull String sessionId,
430 @NonNull byte[] verifierPublicKey,
431 @NonNull byte[] vaultParams,
432 @NonNull byte[] vaultChallenge,
433 @NonNull List<KeyStoreRecoveryMetadata> secrets)
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800434 throws RecoverableKeyStoreLoaderException {
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800435 try {
436 byte[] recoveryClaim =
437 mBinder.startRecoverySession(
438 sessionId,
439 verifierPublicKey,
440 vaultParams,
441 vaultChallenge,
Dmitry Dementyev14298312018-01-04 15:19:19 -0800442 secrets);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800443 return recoveryClaim;
444 } catch (RemoteException e) {
445 throw e.rethrowFromSystemServer();
446 } catch (ServiceSpecificException e) {
447 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
448 }
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800449 }
450
451 /**
452 * Imports keys.
453 *
Robert Berrybd4c43c2017-12-22 11:35:14 +0000454 * @param sessionId Id for recovery session, same as in
Bo Zhu57e77f72018-01-03 14:49:43 -0800455 * {@link #startRecoverySession(String, byte[], byte[], byte[], List)}.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800456 * @param recoveryKeyBlob Recovery blob encrypted by symmetric key generated for this session.
457 * @param applicationKeys Application keys. Key material can be decrypted using recoveryKeyBlob
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800458 * and session. KeyStore only uses package names from the application info in {@link
459 * KeyEntryRecoveryData}. Caller is responsibility to perform certificates check.
Robert Berrybd4c43c2017-12-22 11:35:14 +0000460 * @return Map from alias to raw key material.
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800461 */
Robert Berrybd4c43c2017-12-22 11:35:14 +0000462 public Map<String, byte[]> recoverKeys(
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800463 @NonNull String sessionId,
464 @NonNull byte[] recoveryKeyBlob,
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800465 @NonNull List<KeyEntryRecoveryData> applicationKeys)
466 throws RecoverableKeyStoreLoaderException {
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800467 try {
Robert Berrybd4c43c2017-12-22 11:35:14 +0000468 return (Map<String, byte[]>) mBinder.recoverKeys(
Dmitry Dementyev14298312018-01-04 15:19:19 -0800469 sessionId, recoveryKeyBlob, applicationKeys);
Dmitry Dementyev1aa96132017-12-11 11:33:12 -0800470 } catch (RemoteException e) {
471 throw e.rethrowFromSystemServer();
472 } catch (ServiceSpecificException e) {
473 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
474 }
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800475 }
Robert Berrycfc990a2017-12-22 15:54:30 +0000476
477 /**
478 * Generates a key called {@code alias} and loads it into the recoverable key store. Returns the
479 * raw material of the key.
480 *
481 * @throws RecoverableKeyStoreLoaderException if an error occurred generating and storing the
482 * key.
483 */
484 public byte[] generateAndStoreKey(String alias) throws RecoverableKeyStoreLoaderException {
485 try {
486 return mBinder.generateAndStoreKey(alias);
487 } catch (RemoteException e) {
488 throw e.rethrowFromSystemServer();
489 } catch (ServiceSpecificException e) {
490 throw RecoverableKeyStoreLoaderException.fromServiceSpecificException(e);
491 }
492 }
Dmitry Dementyev8eaf6072017-12-06 19:05:33 -0800493}