1 /*
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 
17 package com.android.server.locksettings;
18 
19 import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.app.admin.PasswordMetrics;
24 import android.content.Context;
25 import android.content.pm.UserInfo;
26 import android.hardware.weaver.V1_0.IWeaver;
27 import android.hardware.weaver.V1_0.WeaverConfig;
28 import android.hardware.weaver.V1_0.WeaverReadResponse;
29 import android.hardware.weaver.V1_0.WeaverReadStatus;
30 import android.hardware.weaver.V1_0.WeaverStatus;
31 import android.os.RemoteException;
32 import android.os.UserManager;
33 import android.security.GateKeeper;
34 import android.security.Scrypt;
35 import android.service.gatekeeper.GateKeeperResponse;
36 import android.service.gatekeeper.IGateKeeperService;
37 import android.util.ArrayMap;
38 import android.util.ArraySet;
39 import android.util.Slog;
40 
41 import com.android.internal.annotations.VisibleForTesting;
42 import com.android.internal.util.ArrayUtils;
43 import com.android.internal.widget.ICheckCredentialProgressCallback;
44 import com.android.internal.widget.LockPatternUtils;
45 import com.android.internal.widget.LockscreenCredential;
46 import com.android.internal.widget.VerifyCredentialResponse;
47 import com.android.server.locksettings.LockSettingsStorage.PersistentData;
48 
49 import libcore.util.HexEncoding;
50 
51 import java.nio.ByteBuffer;
52 import java.security.NoSuchAlgorithmException;
53 import java.security.SecureRandom;
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.Collections;
57 import java.util.HashSet;
58 import java.util.List;
59 import java.util.Map;
60 import java.util.NoSuchElementException;
61 import java.util.Objects;
62 import java.util.Set;
63 
64 
65 /**
66  * A class that maintains the wrapping of synthetic password by user credentials or escrow tokens.
67  * It's (mostly) a pure storage for synthetic passwords, providing APIs to creating and destroying
68  * synthetic password blobs which are wrapped by user credentials or escrow tokens.
69  *
70  * Here is the assumptions it makes:
71  *   Each user has one single synthetic password at any time.
72  *   The SP has an associated password handle, which binds to the SID for that user. The password
73  *   handle is persisted by SyntheticPasswordManager internally.
74  *   If the user credential is null, it's treated as if the credential is DEFAULT_PASSWORD
75  *
76  * Information persisted on disk:
77  *   for each user (stored under DEFAULT_HANDLE):
78  *     SP_HANDLE_NAME: GateKeeper password handle of synthetic password. Only available if user
79  *                     credential exists, cleared when user clears their credential.
80  *     SP_E0_NAME, SP_P1_NAME: Secret to derive synthetic password when combined with escrow
81  *                     tokens. Destroyed when escrow support is turned off for the given user.
82  *
83  *     for each SP blob under the user (stored under the corresponding handle):
84  *       SP_BLOB_NAME: The encrypted synthetic password. Always exists.
85  *       PASSWORD_DATA_NAME: Metadata about user credential. Only exists for password based SP.
86  *       SECDISCARDABLE_NAME: Part of the necessary ingredient to decrypt SP_BLOB_NAME for the
87  *                            purpose of secure deletion. Exists if this is a non-weaver SP
88  *                            (both password and token based), or it's a token-based SP under weaver.
89  *       WEAVER_SLOT: Metadata about the weaver slot used. Only exists if this is a SP under weaver.
90  *
91  *
92  */
93 public class SyntheticPasswordManager {
94     private static final String SP_BLOB_NAME = "spblob";
95     private static final String SP_E0_NAME = "e0";
96     private static final String SP_P1_NAME = "p1";
97     private static final String SP_HANDLE_NAME = "handle";
98     private static final String SECDISCARDABLE_NAME = "secdis";
99     private static final int SECDISCARDABLE_LENGTH = 16 * 1024;
100     private static final String PASSWORD_DATA_NAME = "pwd";
101     private static final String WEAVER_SLOT_NAME = "weaver";
102     private static final String PASSWORD_METRICS_NAME = "metrics";
103 
104     public static final long DEFAULT_HANDLE = 0L;
105     private static final byte[] DEFAULT_PASSWORD = "default-password".getBytes();
106 
107     private static final byte WEAVER_VERSION = 1;
108     private static final int INVALID_WEAVER_SLOT = -1;
109 
110     private static final byte SYNTHETIC_PASSWORD_VERSION_V1 = 1;
111     private static final byte SYNTHETIC_PASSWORD_VERSION_V2 = 2;
112     private static final byte SYNTHETIC_PASSWORD_VERSION_V3 = 3;
113     private static final byte SYNTHETIC_PASSWORD_PASSWORD_BASED = 0;
114     private static final byte SYNTHETIC_PASSWORD_TOKEN_BASED = 1;
115 
116     // 256-bit synthetic password
117     private static final byte SYNTHETIC_PASSWORD_LENGTH = 256 / 8;
118 
119     private static final int PASSWORD_SCRYPT_N = 11;
120     private static final int PASSWORD_SCRYPT_R = 3;
121     private static final int PASSWORD_SCRYPT_P = 1;
122     private static final int PASSWORD_SALT_LENGTH = 16;
123     private static final int PASSWORD_TOKEN_LENGTH = 32;
124     private static final String TAG = "SyntheticPasswordManager";
125 
126     private static final byte[] PERSONALISATION_SECDISCARDABLE = "secdiscardable-transform".getBytes();
127     private static final byte[] PERSONALIZATION_KEY_STORE_PASSWORD = "keystore-password".getBytes();
128     private static final byte[] PERSONALIZATION_USER_GK_AUTH = "user-gk-authentication".getBytes();
129     private static final byte[] PERSONALIZATION_SP_GK_AUTH = "sp-gk-authentication".getBytes();
130     private static final byte[] PERSONALIZATION_FBE_KEY = "fbe-key".getBytes();
131     private static final byte[] PERSONALIZATION_AUTHSECRET_KEY = "authsecret-hal".getBytes();
132     private static final byte[] PERSONALIZATION_SP_SPLIT = "sp-split".getBytes();
133     private static final byte[] PERSONALIZATION_PASSWORD_HASH = "pw-hash".getBytes();
134     private static final byte[] PERSONALIZATION_E0 = "e0-encryption".getBytes();
135     private static final byte[] PERSONALISATION_WEAVER_PASSWORD = "weaver-pwd".getBytes();
136     private static final byte[] PERSONALISATION_WEAVER_KEY = "weaver-key".getBytes();
137     private static final byte[] PERSONALISATION_WEAVER_TOKEN = "weaver-token".getBytes();
138     private static final byte[] PERSONALIZATION_PASSWORD_METRICS = "password-metrics".getBytes();
139     private static final byte[] PERSONALISATION_CONTEXT =
140         "android-synthetic-password-personalization-context".getBytes();
141 
142     static class AuthenticationResult {
143         // Non-null if password/token passes verification, null otherwise
144         @Nullable public AuthenticationToken authToken;
145         // OK:    password / token passes verification, user has a lockscreen
146         // null:  user does not have a lockscreen (but password / token passes verification)
147         // ERROR: password / token fails verification
148         // RETRY: password / token verification is throttled at the moment.
149         @Nullable public VerifyCredentialResponse gkResponse;
150     }
151 
152     /**
153      * This class represents the main cryptographic secret for a given user (a.k.a synthietic
154      * password). This secret is derived from the user's lockscreen credential or password escrow
155      * token. All other cryptograhic keys related to the user, including disk encryption key,
156      * keystore encryption key, gatekeeper auth key, vendor auth secret and others are directly
157      * derived from this token.
158      * <p>
159      * The main secret associated with an authentication token is retrievable from
160      * {@link AuthenticationToken#getSyntheticPassword()} and the authentication token can be
161      * reconsturcted from the main secret later with
162      * {@link AuthenticationToken#recreateDirectly(byte[])}. The first time an authentication token
163      * is needed, it should be created with {@link AuthenticationToken#create()} so that the
164      * necessary escrow data ({@link #mEncryptedEscrowSplit0} and {@link #mEscrowSplit1}) is
165      * properly initialized. The caller can either persist the (non-secret) esscrow data if escrow
166      * is required, or discard it to cryptograhically disable escrow. To support escrow, the caller
167      * needs to securely store the secret returned from
168      * {@link AuthenticationToken#getEscrowSecret()}, and at the time of use, load the escrow data
169      * back with {@link AuthenticationToken#setEscrowData(byte[], byte[])} and then re-create the
170      * main secret from the escrow secret via
171      * {@link AuthenticationToken#recreateFromEscrow(byte[])}.
172      */
173     static class AuthenticationToken {
174         private final byte mVersion;
175         /**
176          * Here is the relationship between these fields:
177          * Generate two random block P0 and P1. P1 is recorded in mEscrowSplit1 but P0 is not.
178          * mSyntheticPassword = hash(P0 || P1)
179          * E0 = P0 encrypted under syntheticPassword, recoreded in mEncryptedEscrowSplit0.
180          */
181         private @NonNull byte[] mSyntheticPassword;
182         private @Nullable byte[] mEncryptedEscrowSplit0;
183         private @Nullable byte[] mEscrowSplit1;
184 
AuthenticationToken(byte version)185         AuthenticationToken(byte version) {
186             mVersion = version;
187         }
188 
derivePassword(byte[] personalization)189         private byte[] derivePassword(byte[] personalization) {
190             if (mVersion == SYNTHETIC_PASSWORD_VERSION_V3) {
191                 return (new SP800Derive(mSyntheticPassword))
192                     .withContext(personalization, PERSONALISATION_CONTEXT);
193             } else {
194                 return SyntheticPasswordCrypto.personalisedHash(personalization,
195                         mSyntheticPassword);
196             }
197         }
198 
deriveKeyStorePassword()199         public byte[] deriveKeyStorePassword() {
200             return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD));
201         }
202 
deriveGkPassword()203         public byte[] deriveGkPassword() {
204             return derivePassword(PERSONALIZATION_SP_GK_AUTH);
205         }
206 
deriveDiskEncryptionKey()207         public byte[] deriveDiskEncryptionKey() {
208             return derivePassword(PERSONALIZATION_FBE_KEY);
209         }
210 
deriveVendorAuthSecret()211         public byte[] deriveVendorAuthSecret() {
212             return derivePassword(PERSONALIZATION_AUTHSECRET_KEY);
213         }
214 
derivePasswordHashFactor()215         public byte[] derivePasswordHashFactor() {
216             return derivePassword(PERSONALIZATION_PASSWORD_HASH);
217         }
218 
219         /** Derives key used to encrypt password metrics */
deriveMetricsKey()220         public byte[] deriveMetricsKey() {
221             return derivePassword(PERSONALIZATION_PASSWORD_METRICS);
222         }
223 
224         /**
225          * Assign escrow data to this auth token. This is a prerequisite to call
226          * {@link AuthenticationToken#recreateFromEscrow}.
227          */
setEscrowData(@ullable byte[] encryptedEscrowSplit0, @Nullable byte[] escrowSplit1)228         public void setEscrowData(@Nullable byte[] encryptedEscrowSplit0,
229                 @Nullable byte[] escrowSplit1) {
230             mEncryptedEscrowSplit0 = encryptedEscrowSplit0;
231             mEscrowSplit1 = escrowSplit1;
232         }
233 
234         /**
235          * Re-creates authentication token from escrow secret (escrowSplit0, returned from
236          * {@link AuthenticationToken#getEscrowSecret}). Escrow data needs to be loaded
237          * by {@link #setEscrowData} before calling this.
238          */
recreateFromEscrow(byte[] escrowSplit0)239         public void recreateFromEscrow(byte[] escrowSplit0) {
240             Objects.requireNonNull(mEscrowSplit1);
241             Objects.requireNonNull(mEncryptedEscrowSplit0);
242             recreate(escrowSplit0, mEscrowSplit1);
243         }
244 
245         /**
246          * Re-creates authentication token from synthetic password directly.
247          */
recreateDirectly(byte[] syntheticPassword)248         public void recreateDirectly(byte[] syntheticPassword) {
249             this.mSyntheticPassword = Arrays.copyOf(syntheticPassword, syntheticPassword.length);
250         }
251 
252         /**
253          * Generates a new random synthetic password with escrow data.
254          */
create()255         static AuthenticationToken create() {
256             AuthenticationToken result = new AuthenticationToken(SYNTHETIC_PASSWORD_VERSION_V3);
257             byte[] escrowSplit0 = secureRandom(SYNTHETIC_PASSWORD_LENGTH);
258             byte[] escrowSplit1 = secureRandom(SYNTHETIC_PASSWORD_LENGTH);
259             result.recreate(escrowSplit0, escrowSplit1);
260             byte[] encrypteEscrowSplit0 = SyntheticPasswordCrypto.encrypt(result.mSyntheticPassword,
261                     PERSONALIZATION_E0, escrowSplit0);
262             result.setEscrowData(encrypteEscrowSplit0,  escrowSplit1);
263             return result;
264         }
265 
266         /**
267          * Re-creates synthetic password from both escrow splits. See javadoc for
268          * AuthenticationToken.mSyntheticPassword for details on what each block means.
269          */
recreate(byte[] escrowSplit0, byte[] escrowSplit1)270         private void recreate(byte[] escrowSplit0, byte[] escrowSplit1) {
271             mSyntheticPassword = String.valueOf(HexEncoding.encode(
272                     SyntheticPasswordCrypto.personalisedHash(
273                             PERSONALIZATION_SP_SPLIT, escrowSplit0, escrowSplit1))).getBytes();
274         }
275 
276         /**
277          * Returns the escrow secret that can be used later to reconstruct this authentication
278          * token from {@link #recreateFromEscrow(byte[])}. Only possible if escrow is not disabled
279          * (encryptedEscrowSplit0 known).
280          */
getEscrowSecret()281         public byte[] getEscrowSecret() {
282             if (mEncryptedEscrowSplit0 == null) {
283                 return null;
284             }
285             return SyntheticPasswordCrypto.decrypt(mSyntheticPassword, PERSONALIZATION_E0,
286                     mEncryptedEscrowSplit0);
287         }
288 
289         /**
290          * Returns the raw synthetic password that can be used later to reconstruct this
291          * authentication token from {@link #recreateDirectly(byte[])}
292          */
getSyntheticPassword()293         public byte[] getSyntheticPassword() {
294             return mSyntheticPassword;
295         }
296 
297         /**
298          * Returns the version of this AuthenticationToken for use with reconstructing
299          * this with a synthetic password version.
300          */
getVersion()301         public byte getVersion() {
302             return mVersion;
303         }
304     }
305 
306     static class PasswordData {
307         byte scryptN;
308         byte scryptR;
309         byte scryptP;
310         public int credentialType;
311         byte[] salt;
312         // For GateKeeper-based credential, this is the password handle returned by GK,
313         // for weaver-based credential, this is empty.
314         public byte[] passwordHandle;
315 
create(int passwordType)316         public static PasswordData create(int passwordType) {
317             PasswordData result = new PasswordData();
318             result.scryptN = PASSWORD_SCRYPT_N;
319             result.scryptR = PASSWORD_SCRYPT_R;
320             result.scryptP = PASSWORD_SCRYPT_P;
321             result.credentialType = passwordType;
322             result.salt = secureRandom(PASSWORD_SALT_LENGTH);
323             return result;
324         }
325 
fromBytes(byte[] data)326         public static PasswordData fromBytes(byte[] data) {
327             PasswordData result = new PasswordData();
328             ByteBuffer buffer = ByteBuffer.allocate(data.length);
329             buffer.put(data, 0, data.length);
330             buffer.flip();
331             result.credentialType = buffer.getInt();
332             result.scryptN = buffer.get();
333             result.scryptR = buffer.get();
334             result.scryptP = buffer.get();
335             int saltLen = buffer.getInt();
336             result.salt = new byte[saltLen];
337             buffer.get(result.salt);
338             int handleLen = buffer.getInt();
339             if (handleLen > 0) {
340                 result.passwordHandle = new byte[handleLen];
341                 buffer.get(result.passwordHandle);
342             } else {
343                 result.passwordHandle = null;
344             }
345             return result;
346         }
347 
toBytes()348         public byte[] toBytes() {
349 
350             ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES + 3 * Byte.BYTES
351                     + Integer.BYTES + salt.length + Integer.BYTES +
352                     (passwordHandle != null ? passwordHandle.length : 0));
353             buffer.putInt(credentialType);
354             buffer.put(scryptN);
355             buffer.put(scryptR);
356             buffer.put(scryptP);
357             buffer.putInt(salt.length);
358             buffer.put(salt);
359             if (passwordHandle != null && passwordHandle.length > 0) {
360                 buffer.putInt(passwordHandle.length);
361                 buffer.put(passwordHandle);
362             } else {
363                 buffer.putInt(0);
364             }
365             return buffer.array();
366         }
367     }
368 
369     static class TokenData {
370         byte[] secdiscardableOnDisk;
371         byte[] weaverSecret;
372         byte[] aggregatedSecret;
373         EscrowTokenStateChangeCallback mCallback;
374     }
375 
376     private final Context mContext;
377     private LockSettingsStorage mStorage;
378     private IWeaver mWeaver;
379     private WeaverConfig mWeaverConfig;
380     private PasswordSlotManager mPasswordSlotManager;
381 
382     private final UserManager mUserManager;
383 
SyntheticPasswordManager(Context context, LockSettingsStorage storage, UserManager userManager, PasswordSlotManager passwordSlotManager)384     public SyntheticPasswordManager(Context context, LockSettingsStorage storage,
385             UserManager userManager, PasswordSlotManager passwordSlotManager) {
386         mContext = context;
387         mStorage = storage;
388         mUserManager = userManager;
389         mPasswordSlotManager = passwordSlotManager;
390     }
391 
392     @VisibleForTesting
getWeaverService()393     protected IWeaver getWeaverService() throws RemoteException {
394         try {
395             return IWeaver.getService(/* retry */ true);
396         } catch (NoSuchElementException e) {
397             Slog.i(TAG, "Device does not support weaver");
398             return null;
399         }
400     }
401 
initWeaverService()402     public synchronized void initWeaverService() {
403         if (mWeaver != null) {
404             return;
405         }
406         try {
407             mWeaverConfig = null;
408             mWeaver = getWeaverService();
409             if (mWeaver != null) {
410                 mWeaver.getConfig((int status, WeaverConfig config) -> {
411                     if (status == WeaverStatus.OK && config.slots > 0) {
412                         mWeaverConfig = config;
413                     } else {
414                         Slog.e(TAG, "Failed to get weaver config, status " + status
415                                 + " slots: " + config.slots);
416                         mWeaver = null;
417                     }
418                 });
419                 mPasswordSlotManager.refreshActiveSlots(getUsedWeaverSlots());
420             }
421         } catch (RemoteException e) {
422             Slog.e(TAG, "Failed to get weaver service", e);
423         }
424     }
425 
isWeaverAvailable()426     private synchronized boolean isWeaverAvailable() {
427         if (mWeaver == null) {
428             //Re-initializing weaver in case there was a transient error preventing access to it.
429             initWeaverService();
430         }
431         return mWeaver != null && mWeaverConfig.slots > 0;
432     }
433 
434     /**
435      * Enroll the given key value pair into the specified weaver slot. if the given key is null,
436      * a default all-zero key is used. If the value is not specified, a fresh random secret is
437      * generated as the value.
438      *
439      * @return the value stored in the weaver slot, or null if the operation fails
440      */
weaverEnroll(int slot, byte[] key, @Nullable byte[] value)441     private byte[] weaverEnroll(int slot, byte[] key, @Nullable byte[] value) {
442         if (slot == INVALID_WEAVER_SLOT || slot >= mWeaverConfig.slots) {
443             throw new IllegalArgumentException("Invalid slot for weaver");
444         }
445         if (key == null) {
446             key = new byte[mWeaverConfig.keySize];
447         } else if (key.length != mWeaverConfig.keySize) {
448             throw new IllegalArgumentException("Invalid key size for weaver");
449         }
450         if (value == null) {
451             value = secureRandom(mWeaverConfig.valueSize);
452         }
453         try {
454             int writeStatus = mWeaver.write(slot, toByteArrayList(key), toByteArrayList(value));
455             if (writeStatus != WeaverStatus.OK) {
456                 Slog.e(TAG, "weaver write failed, slot: " + slot + " status: " + writeStatus);
457                 return null;
458             }
459         } catch (RemoteException e) {
460             Slog.e(TAG, "weaver write failed", e);
461             return null;
462         }
463         return value;
464     }
465 
466     /**
467      * Verify the supplied key against a weaver slot, returning a response indicating whether
468      * the verification is successful, throttled or failed. If successful, the bound secret
469      * is also returned.
470      */
weaverVerify(int slot, byte[] key)471     private VerifyCredentialResponse weaverVerify(int slot, byte[] key) {
472         if (slot == INVALID_WEAVER_SLOT || slot >= mWeaverConfig.slots) {
473             throw new IllegalArgumentException("Invalid slot for weaver");
474         }
475         if (key == null) {
476             key = new byte[mWeaverConfig.keySize];
477         } else if (key.length != mWeaverConfig.keySize) {
478             throw new IllegalArgumentException("Invalid key size for weaver");
479         }
480         final VerifyCredentialResponse[] response = new VerifyCredentialResponse[1];
481         try {
482             mWeaver.read(slot, toByteArrayList(key),
483                     (int status, WeaverReadResponse readResponse) -> {
484                     switch (status) {
485                         case WeaverReadStatus.OK:
486                             response[0] = new VerifyCredentialResponse.Builder().setGatekeeperHAT(
487                                     fromByteArrayList(readResponse.value)).build();
488                             break;
489                         case WeaverReadStatus.THROTTLE:
490                             response[0] = VerifyCredentialResponse
491                                     .fromTimeout(readResponse.timeout);
492                             Slog.e(TAG, "weaver read failed (THROTTLE), slot: " + slot);
493                             break;
494                         case WeaverReadStatus.INCORRECT_KEY:
495                             if (readResponse.timeout == 0) {
496                                 response[0] = VerifyCredentialResponse.ERROR;
497                                 Slog.e(TAG, "weaver read failed (INCORRECT_KEY), slot: " + slot);
498                             } else {
499                                 response[0] = VerifyCredentialResponse
500                                         .fromTimeout(readResponse.timeout);
501                                 Slog.e(TAG, "weaver read failed (INCORRECT_KEY/THROTTLE), slot: "
502                                         + slot);
503                             }
504                             break;
505                         case WeaverReadStatus.FAILED:
506                             response[0] = VerifyCredentialResponse.ERROR;
507                             Slog.e(TAG, "weaver read failed (FAILED), slot: " + slot);
508                             break;
509                         default:
510                             response[0] = VerifyCredentialResponse.ERROR;
511                             Slog.e(TAG, "weaver read unknown status " + status + ", slot: " + slot);
512                             break;
513                     }
514                 });
515         } catch (RemoteException e) {
516             response[0] = VerifyCredentialResponse.ERROR;
517             Slog.e(TAG, "weaver read failed, slot: " + slot, e);
518         }
519         return response[0];
520     }
521 
removeUser(int userId)522     public void removeUser(int userId) {
523         for (long handle : mStorage.listSyntheticPasswordHandlesForUser(SP_BLOB_NAME, userId)) {
524             destroyWeaverSlot(handle, userId);
525             destroySPBlobKey(getKeyName(handle));
526         }
527     }
528 
getCredentialType(long handle, int userId)529     int getCredentialType(long handle, int userId) {
530         byte[] passwordData = loadState(PASSWORD_DATA_NAME, handle, userId);
531         if (passwordData == null) {
532             Slog.w(TAG, "getCredentialType: encountered empty password data for user " + userId);
533             return LockPatternUtils.CREDENTIAL_TYPE_NONE;
534         }
535         return PasswordData.fromBytes(passwordData).credentialType;
536     }
537 
getFrpCredentialType(byte[] payload)538     static int getFrpCredentialType(byte[] payload) {
539         if (payload == null) {
540             return LockPatternUtils.CREDENTIAL_TYPE_NONE;
541         }
542         return PasswordData.fromBytes(payload).credentialType;
543     }
544 
545     /**
546      * Initializing a new Authentication token, possibly from an existing credential and hash.
547      *
548      * The authentication token would bear a randomly-generated synthetic password.
549      *
550      * This method has the side effect of rebinding the SID of the given user to the
551      * newly-generated SP.
552      *
553      * If the existing credential hash is non-null, the existing SID mill be migrated so
554      * the synthetic password in the authentication token will produce the same SID
555      * (the corresponding synthetic password handle is persisted by SyntheticPasswordManager
556      * in a per-user data storage.)
557      *
558      * If the existing credential hash is null, it means the given user should have no SID so
559      * SyntheticPasswordManager will nuke any SP handle previously persisted. In this case,
560      * the supplied credential parameter is also ignored.
561      *
562      * Also saves the escrow information necessary to re-generate the synthetic password under
563      * an escrow scheme. This information can be removed with {@link #destroyEscrowData} if
564      * password escrow should be disabled completely on the given user.
565      *
566      */
newSyntheticPasswordAndSid(IGateKeeperService gatekeeper, byte[] hash, LockscreenCredential credential, int userId)567     public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper,
568             byte[] hash, LockscreenCredential credential, int userId) {
569         AuthenticationToken result = AuthenticationToken.create();
570         GateKeeperResponse response;
571         if (hash != null) {
572             try {
573                 response = gatekeeper.enroll(userId, hash, credential.getCredential(),
574                         result.deriveGkPassword());
575             } catch (RemoteException e) {
576                 throw new IllegalStateException("Failed to enroll credential duing SP init", e);
577             }
578             if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
579                 Slog.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId);
580                 clearSidForUser(userId);
581             } else {
582                 saveSyntheticPasswordHandle(response.getPayload(), userId);
583             }
584         } else {
585             clearSidForUser(userId);
586         }
587         saveEscrowData(result, userId);
588         return result;
589     }
590 
591     /**
592      * Enroll a new password handle and SID for the given synthetic password and persist it on disk.
593      * Used when adding password to previously-unsecured devices.
594      */
newSidForUser(IGateKeeperService gatekeeper, AuthenticationToken authToken, int userId)595     public void newSidForUser(IGateKeeperService gatekeeper, AuthenticationToken authToken,
596             int userId) {
597         GateKeeperResponse response;
598         try {
599             response = gatekeeper.enroll(userId, null, null, authToken.deriveGkPassword());
600         } catch (RemoteException e) {
601             throw new IllegalStateException("Failed to create new SID for user", e);
602         }
603         if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
604             throw new IllegalStateException("Fail to create new SID for user " + userId
605                     + " response: " + response.getResponseCode());
606         }
607         saveSyntheticPasswordHandle(response.getPayload(), userId);
608     }
609 
610     // Nuke the SP handle (and as a result, its SID) for the given user.
clearSidForUser(int userId)611     public void clearSidForUser(int userId) {
612         destroyState(SP_HANDLE_NAME, DEFAULT_HANDLE, userId);
613     }
614 
hasSidForUser(int userId)615     public boolean hasSidForUser(int userId) {
616         return hasState(SP_HANDLE_NAME, DEFAULT_HANDLE, userId);
617     }
618 
619     // if null, it means there is no SID associated with the user
620     // This can happen if the user is migrated to SP but currently
621     // do not have a lockscreen password.
loadSyntheticPasswordHandle(int userId)622     private byte[] loadSyntheticPasswordHandle(int userId) {
623         return loadState(SP_HANDLE_NAME, DEFAULT_HANDLE, userId);
624     }
625 
saveSyntheticPasswordHandle(byte[] spHandle, int userId)626     private void saveSyntheticPasswordHandle(byte[] spHandle, int userId) {
627         saveState(SP_HANDLE_NAME, spHandle, DEFAULT_HANDLE, userId);
628     }
629 
loadEscrowData(AuthenticationToken authToken, int userId)630     private boolean loadEscrowData(AuthenticationToken authToken, int userId) {
631         byte[] e0 = loadState(SP_E0_NAME, DEFAULT_HANDLE, userId);
632         byte[] p1 = loadState(SP_P1_NAME, DEFAULT_HANDLE, userId);
633         authToken.setEscrowData(e0,  p1);
634         return e0 != null && p1 != null;
635     }
636 
saveEscrowData(AuthenticationToken authToken, int userId)637     private void saveEscrowData(AuthenticationToken authToken, int userId) {
638         saveState(SP_E0_NAME, authToken.mEncryptedEscrowSplit0, DEFAULT_HANDLE, userId);
639         saveState(SP_P1_NAME, authToken.mEscrowSplit1, DEFAULT_HANDLE, userId);
640     }
641 
hasEscrowData(int userId)642     public boolean hasEscrowData(int userId) {
643         return hasState(SP_E0_NAME, DEFAULT_HANDLE, userId)
644                 && hasState(SP_P1_NAME, DEFAULT_HANDLE, userId);
645     }
646 
destroyEscrowData(int userId)647     public void destroyEscrowData(int userId) {
648         destroyState(SP_E0_NAME, DEFAULT_HANDLE, userId);
649         destroyState(SP_P1_NAME, DEFAULT_HANDLE, userId);
650     }
651 
loadWeaverSlot(long handle, int userId)652     private int loadWeaverSlot(long handle, int userId) {
653         final int LENGTH = Byte.BYTES + Integer.BYTES;
654         byte[] data = loadState(WEAVER_SLOT_NAME, handle, userId);
655         if (data == null || data.length != LENGTH) {
656             return INVALID_WEAVER_SLOT;
657         }
658         ByteBuffer buffer = ByteBuffer.allocate(LENGTH);
659         buffer.put(data, 0, data.length);
660         buffer.flip();
661         if (buffer.get() != WEAVER_VERSION) {
662             Slog.e(TAG, "Invalid weaver slot version of handle " + handle);
663             return INVALID_WEAVER_SLOT;
664         }
665         return buffer.getInt();
666     }
667 
saveWeaverSlot(int slot, long handle, int userId)668     private void saveWeaverSlot(int slot, long handle, int userId) {
669         ByteBuffer buffer = ByteBuffer.allocate(Byte.BYTES + Integer.BYTES);
670         buffer.put(WEAVER_VERSION);
671         buffer.putInt(slot);
672         saveState(WEAVER_SLOT_NAME, buffer.array(), handle, userId);
673     }
674 
destroyWeaverSlot(long handle, int userId)675     private void destroyWeaverSlot(long handle, int userId) {
676         int slot = loadWeaverSlot(handle, userId);
677         destroyState(WEAVER_SLOT_NAME, handle, userId);
678         if (slot != INVALID_WEAVER_SLOT) {
679             Set<Integer> usedSlots = getUsedWeaverSlots();
680             if (!usedSlots.contains(slot)) {
681                 Slog.i(TAG, "Destroy weaver slot " + slot + " for user " + userId);
682                 weaverEnroll(slot, null, null);
683                 mPasswordSlotManager.markSlotDeleted(slot);
684             } else {
685                 Slog.w(TAG, "Skip destroying reused weaver slot " + slot + " for user " + userId);
686             }
687         }
688     }
689 
690     /**
691      * Return the set of weaver slots that are currently in use by all users on the device.
692      * <p>
693      * <em>Note:</em> Users who are in the process of being deleted are not tracked here
694      * (due to them being marked as partial in UserManager so not visible from
695      * {@link UserManager#getUsers}). As a result their weaver slots will not be considered
696      * taken and can be reused by new users. Care should be taken when cleaning up the
697      * deleted user in {@link #removeUser}, to prevent a reused slot from being erased
698      * unintentionally.
699      */
getUsedWeaverSlots()700     private Set<Integer> getUsedWeaverSlots() {
701         Map<Integer, List<Long>> slotHandles = mStorage.listSyntheticPasswordHandlesForAllUsers(
702                 WEAVER_SLOT_NAME);
703         HashSet<Integer> slots = new HashSet<>();
704         for (Map.Entry<Integer, List<Long>> entry : slotHandles.entrySet()) {
705             for (Long handle : entry.getValue()) {
706                 int slot = loadWeaverSlot(handle, entry.getKey());
707                 slots.add(slot);
708             }
709         }
710         return slots;
711     }
712 
getNextAvailableWeaverSlot()713     private int getNextAvailableWeaverSlot() {
714         Set<Integer> usedSlots = getUsedWeaverSlots();
715         usedSlots.addAll(mPasswordSlotManager.getUsedSlots());
716         for (int i = 0; i < mWeaverConfig.slots; i++) {
717             if (!usedSlots.contains(i)) {
718                 return i;
719             }
720         }
721         throw new IllegalStateException("Run out of weaver slots.");
722     }
723 
724     /**
725      * Create a new password based SP blob based on the supplied authentication token, such that
726      * a future successful authentication with unwrapPasswordBasedSyntheticPassword() would result
727      * in the same authentication token.
728      *
729      * This method only creates SP blob wrapping around the given synthetic password and does not
730      * handle logic around SID or SP handle. The caller should separately ensure that the user's SID
731      * is consistent with the device state by calling other APIs in this class.
732      *
733      * @see #newSidForUser
734      * @see #clearSidForUser
735      * @return a new password handle for the wrapped SP blob
736      * @throw IllegalStateException if creation fails.
737      */
createPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper, LockscreenCredential credential, AuthenticationToken authToken, int userId)738     public long createPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
739             LockscreenCredential credential, AuthenticationToken authToken, int userId) {
740         long handle = generateHandle();
741         PasswordData pwd = PasswordData.create(credential.getType());
742         byte[] pwdToken = computePasswordToken(credential, pwd);
743         final long sid;
744         final byte[] applicationId;
745 
746         if (isWeaverAvailable()) {
747             // Weaver based user password
748             int weaverSlot = getNextAvailableWeaverSlot();
749             Slog.i(TAG, "Weaver enroll password to slot " + weaverSlot + " for user " + userId);
750             byte[] weaverSecret = weaverEnroll(weaverSlot, passwordTokenToWeaverKey(pwdToken),
751                     null);
752             if (weaverSecret == null) {
753                 throw new IllegalStateException(
754                         "Fail to enroll user password under weaver " + userId);
755             }
756             saveWeaverSlot(weaverSlot, handle, userId);
757             mPasswordSlotManager.markSlotInUse(weaverSlot);
758             // No need to pass in quality since the credential type already encodes sufficient info
759             synchronizeWeaverFrpPassword(pwd, 0, userId, weaverSlot);
760 
761             pwd.passwordHandle = null;
762             sid = GateKeeper.INVALID_SECURE_USER_ID;
763             applicationId = transformUnderWeaverSecret(pwdToken, weaverSecret);
764         } else {
765             // In case GK enrollment leaves persistent state around (in RPMB), this will nuke them
766             // to prevent them from accumulating and causing problems.
767             try {
768                 gatekeeper.clearSecureUserId(fakeUid(userId));
769             } catch (RemoteException ignore) {
770                 Slog.w(TAG, "Failed to clear SID from gatekeeper");
771             }
772             // GateKeeper based user password
773             GateKeeperResponse response;
774             try {
775                 response = gatekeeper.enroll(fakeUid(userId), null, null,
776                         passwordTokenToGkInput(pwdToken));
777             } catch (RemoteException e) {
778                 throw new IllegalStateException("Failed to enroll password for new SP blob", e);
779             }
780             if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
781                 throw new IllegalStateException(
782                         "Fail to enroll user password when creating SP for user " + userId);
783             }
784             pwd.passwordHandle = response.getPayload();
785             sid = sidFromPasswordHandle(pwd.passwordHandle);
786             applicationId = transformUnderSecdiscardable(pwdToken,
787                     createSecdiscardable(handle, userId));
788             // No need to pass in quality since the credential type already encodes sufficient info
789             synchronizeFrpPassword(pwd, 0, userId);
790         }
791         saveState(PASSWORD_DATA_NAME, pwd.toBytes(), handle, userId);
792         savePasswordMetrics(credential, authToken, handle, userId);
793         createSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_PASSWORD_BASED, authToken,
794                 applicationId, sid, userId);
795         return handle;
796     }
797 
verifyFrpCredential(IGateKeeperService gatekeeper, LockscreenCredential userCredential, ICheckCredentialProgressCallback progressCallback)798     public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper,
799             LockscreenCredential userCredential,
800             ICheckCredentialProgressCallback progressCallback) {
801         PersistentData persistentData = mStorage.readPersistentDataBlock();
802         if (persistentData.type == PersistentData.TYPE_SP) {
803             PasswordData pwd = PasswordData.fromBytes(persistentData.payload);
804             byte[] pwdToken = computePasswordToken(userCredential, pwd);
805 
806             GateKeeperResponse response;
807             try {
808                 response = gatekeeper.verifyChallenge(fakeUid(persistentData.userId),
809                         0 /* challenge */, pwd.passwordHandle, passwordTokenToGkInput(pwdToken));
810             } catch (RemoteException e) {
811                 Slog.e(TAG, "FRP verifyChallenge failed", e);
812                 return VerifyCredentialResponse.ERROR;
813             }
814             return VerifyCredentialResponse.fromGateKeeperResponse(response);
815         } else if (persistentData.type == PersistentData.TYPE_SP_WEAVER) {
816             if (!isWeaverAvailable()) {
817                 Slog.e(TAG, "No weaver service to verify SP-based FRP credential");
818                 return VerifyCredentialResponse.ERROR;
819             }
820             PasswordData pwd = PasswordData.fromBytes(persistentData.payload);
821             byte[] pwdToken = computePasswordToken(userCredential, pwd);
822             int weaverSlot = persistentData.userId;
823 
824             return weaverVerify(weaverSlot, passwordTokenToWeaverKey(pwdToken)).stripPayload();
825         } else {
826             Slog.e(TAG, "persistentData.type must be TYPE_SP or TYPE_SP_WEAVER, but is "
827                     + persistentData.type);
828             return VerifyCredentialResponse.ERROR;
829         }
830     }
831 
832 
migrateFrpPasswordLocked(long handle, UserInfo userInfo, int requestedQuality)833     public void migrateFrpPasswordLocked(long handle, UserInfo userInfo, int requestedQuality) {
834         if (mStorage.getPersistentDataBlockManager() != null
835                 && LockPatternUtils.userOwnsFrpCredential(mContext, userInfo)) {
836             PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, handle,
837                     userInfo.id));
838             if (pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
839                 int weaverSlot = loadWeaverSlot(handle, userInfo.id);
840                 if (weaverSlot != INVALID_WEAVER_SLOT) {
841                     synchronizeWeaverFrpPassword(pwd, requestedQuality, userInfo.id, weaverSlot);
842                 } else {
843                     synchronizeFrpPassword(pwd, requestedQuality, userInfo.id);
844                 }
845             }
846         }
847     }
848 
synchronizeFrpPassword(PasswordData pwd, int requestedQuality, int userId)849     private void synchronizeFrpPassword(PasswordData pwd,
850             int requestedQuality, int userId) {
851         if (mStorage.getPersistentDataBlockManager() != null
852                 && LockPatternUtils.userOwnsFrpCredential(mContext,
853                 mUserManager.getUserInfo(userId))) {
854             if (pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
855                 mStorage.writePersistentDataBlock(PersistentData.TYPE_SP, userId, requestedQuality,
856                         pwd.toBytes());
857             } else {
858                 mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, userId, 0, null);
859             }
860         }
861     }
862 
synchronizeWeaverFrpPassword(PasswordData pwd, int requestedQuality, int userId, int weaverSlot)863     private void synchronizeWeaverFrpPassword(PasswordData pwd, int requestedQuality, int userId,
864             int weaverSlot) {
865         if (mStorage.getPersistentDataBlockManager() != null
866                 && LockPatternUtils.userOwnsFrpCredential(mContext,
867                 mUserManager.getUserInfo(userId))) {
868             if (pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
869                 mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_WEAVER, weaverSlot,
870                         requestedQuality, pwd.toBytes());
871             } else {
872                 mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, 0, 0, null);
873             }
874         }
875     }
876 
877     private ArrayMap<Integer, ArrayMap<Long, TokenData>> tokenMap = new ArrayMap<>();
878 
879     /**
880      * Create a token based Synthetic password for the given user.
881      * @return the handle of the token
882      */
createTokenBasedSyntheticPassword(byte[] token, int userId, @Nullable EscrowTokenStateChangeCallback changeCallback)883     public long createTokenBasedSyntheticPassword(byte[] token, int userId,
884             @Nullable EscrowTokenStateChangeCallback changeCallback) {
885         long handle = generateHandle();
886         if (!tokenMap.containsKey(userId)) {
887             tokenMap.put(userId, new ArrayMap<>());
888         }
889         TokenData tokenData = new TokenData();
890         final byte[] secdiscardable = secureRandom(SECDISCARDABLE_LENGTH);
891         if (isWeaverAvailable()) {
892             tokenData.weaverSecret = secureRandom(mWeaverConfig.valueSize);
893             tokenData.secdiscardableOnDisk = SyntheticPasswordCrypto.encrypt(tokenData.weaverSecret,
894                             PERSONALISATION_WEAVER_TOKEN, secdiscardable);
895         } else {
896             tokenData.secdiscardableOnDisk = secdiscardable;
897             tokenData.weaverSecret = null;
898         }
899         tokenData.aggregatedSecret = transformUnderSecdiscardable(token, secdiscardable);
900         tokenData.mCallback = changeCallback;
901 
902         tokenMap.get(userId).put(handle, tokenData);
903         return handle;
904     }
905 
getPendingTokensForUser(int userId)906     public Set<Long> getPendingTokensForUser(int userId) {
907         if (!tokenMap.containsKey(userId)) {
908             return Collections.emptySet();
909         }
910         return new ArraySet<>(tokenMap.get(userId).keySet());
911     }
912 
removePendingToken(long handle, int userId)913     public boolean removePendingToken(long handle, int userId) {
914         if (!tokenMap.containsKey(userId)) {
915             return false;
916         }
917         return tokenMap.get(userId).remove(handle) != null;
918     }
919 
activateTokenBasedSyntheticPassword(long handle, AuthenticationToken authToken, int userId)920     public boolean activateTokenBasedSyntheticPassword(long handle, AuthenticationToken authToken,
921             int userId) {
922         if (!tokenMap.containsKey(userId)) {
923             return false;
924         }
925         TokenData tokenData = tokenMap.get(userId).get(handle);
926         if (tokenData == null) {
927             return false;
928         }
929         if (!loadEscrowData(authToken, userId)) {
930             Slog.w(TAG, "User is not escrowable");
931             return false;
932         }
933         if (isWeaverAvailable()) {
934             int slot = getNextAvailableWeaverSlot();
935             Slog.i(TAG, "Weaver enroll token to slot " + slot + " for user " + userId);
936             if (weaverEnroll(slot, null, tokenData.weaverSecret) == null) {
937                 Slog.e(TAG, "Failed to enroll weaver secret when activating token");
938                 return false;
939             }
940             saveWeaverSlot(slot, handle, userId);
941             mPasswordSlotManager.markSlotInUse(slot);
942         }
943         saveSecdiscardable(handle, tokenData.secdiscardableOnDisk, userId);
944         createSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_TOKEN_BASED, authToken,
945                 tokenData.aggregatedSecret, 0L, userId);
946         tokenMap.get(userId).remove(handle);
947         if (tokenData.mCallback != null) {
948             tokenData.mCallback.onEscrowTokenActivated(handle, userId);
949         }
950         return true;
951     }
952 
createSyntheticPasswordBlob(long handle, byte type, AuthenticationToken authToken, byte[] applicationId, long sid, int userId)953     private void createSyntheticPasswordBlob(long handle, byte type, AuthenticationToken authToken,
954             byte[] applicationId, long sid, int userId) {
955         final byte[] secret;
956         if (type == SYNTHETIC_PASSWORD_TOKEN_BASED) {
957             secret = authToken.getEscrowSecret();
958         } else {
959             secret = authToken.getSyntheticPassword();
960         }
961         byte[] content = createSPBlob(getKeyName(handle), secret, applicationId, sid);
962         byte[] blob = new byte[content.length + 1 + 1];
963         /*
964          * We can upgrade from v1 to v2 because that's just a change in the way that
965          * the SP is stored. However, we can't upgrade to v3 because that is a change
966          * in the way that passwords are derived from the SP.
967          */
968         if (authToken.mVersion == SYNTHETIC_PASSWORD_VERSION_V3) {
969             blob[0] = SYNTHETIC_PASSWORD_VERSION_V3;
970         } else {
971             blob[0] = SYNTHETIC_PASSWORD_VERSION_V2;
972         }
973         blob[1] = type;
974         System.arraycopy(content, 0, blob, 2, content.length);
975         saveState(SP_BLOB_NAME, blob, handle, userId);
976     }
977 
978     /**
979      * Decrypt a synthetic password by supplying the user credential and corresponding password
980      * blob handle generated previously. If the decryption is successful, initiate a GateKeeper
981      * verification to referesh the SID & Auth token maintained by the system.
982      */
unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper, long handle, @NonNull LockscreenCredential credential, int userId, ICheckCredentialProgressCallback progressCallback)983     public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
984             long handle, @NonNull LockscreenCredential credential, int userId,
985             ICheckCredentialProgressCallback progressCallback) {
986         AuthenticationResult result = new AuthenticationResult();
987         PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, handle, userId));
988 
989         if (!credential.checkAgainstStoredType(pwd.credentialType)) {
990             Slog.e(TAG, String.format("Credential type mismatch: expected %d actual %d",
991                     pwd.credentialType, credential.getType()));
992             result.gkResponse = VerifyCredentialResponse.ERROR;
993             return result;
994         }
995 
996         byte[] pwdToken = computePasswordToken(credential, pwd);
997 
998         final byte[] applicationId;
999         final long sid;
1000         int weaverSlot = loadWeaverSlot(handle, userId);
1001         if (weaverSlot != INVALID_WEAVER_SLOT) {
1002             // Weaver based user password
1003             if (!isWeaverAvailable()) {
1004                 Slog.e(TAG, "No weaver service to unwrap password based SP");
1005                 result.gkResponse = VerifyCredentialResponse.ERROR;
1006                 return result;
1007             }
1008             result.gkResponse = weaverVerify(weaverSlot, passwordTokenToWeaverKey(pwdToken));
1009             if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1010                 return result;
1011             }
1012             sid = GateKeeper.INVALID_SECURE_USER_ID;
1013             applicationId = transformUnderWeaverSecret(pwdToken,
1014                     result.gkResponse.getGatekeeperHAT());
1015         } else {
1016             byte[] gkPwdToken = passwordTokenToGkInput(pwdToken);
1017             GateKeeperResponse response;
1018             try {
1019                 response = gatekeeper.verifyChallenge(fakeUid(userId), 0L,
1020                         pwd.passwordHandle, gkPwdToken);
1021             } catch (RemoteException e) {
1022                 Slog.e(TAG, "gatekeeper verify failed", e);
1023                 result.gkResponse = VerifyCredentialResponse.ERROR;
1024                 return result;
1025             }
1026             int responseCode = response.getResponseCode();
1027             if (responseCode == GateKeeperResponse.RESPONSE_OK) {
1028                 result.gkResponse = VerifyCredentialResponse.OK;
1029                 if (response.getShouldReEnroll()) {
1030                     GateKeeperResponse reenrollResponse;
1031                     try {
1032                         reenrollResponse = gatekeeper.enroll(fakeUid(userId),
1033                                 pwd.passwordHandle, gkPwdToken, gkPwdToken);
1034                     } catch (RemoteException e) {
1035                         Slog.w(TAG, "Fail to invoke gatekeeper.enroll", e);
1036                         reenrollResponse = GateKeeperResponse.ERROR;
1037                         // continue the flow anyway
1038                     }
1039                     if (reenrollResponse.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
1040                         pwd.passwordHandle = reenrollResponse.getPayload();
1041                         // Use the reenrollment opportunity to update credential type
1042                         // (getting rid of CREDENTIAL_TYPE_PASSWORD_OR_PIN)
1043                         pwd.credentialType = credential.getType();
1044                         saveState(PASSWORD_DATA_NAME, pwd.toBytes(), handle, userId);
1045                         synchronizeFrpPassword(pwd, 0, userId);
1046                     } else {
1047                         Slog.w(TAG, "Fail to re-enroll user password for user " + userId);
1048                         // continue the flow anyway
1049                     }
1050                 }
1051             } else if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
1052                 result.gkResponse = VerifyCredentialResponse.fromTimeout(response.getTimeout());
1053                 return result;
1054             } else  {
1055                 result.gkResponse = VerifyCredentialResponse.ERROR;
1056                 return result;
1057             }
1058             sid = sidFromPasswordHandle(pwd.passwordHandle);
1059             applicationId = transformUnderSecdiscardable(pwdToken,
1060                     loadSecdiscardable(handle, userId));
1061         }
1062         // Supplied credential passes first stage weaver/gatekeeper check so it should be correct.
1063         // Notify the callback so the keyguard UI can proceed immediately.
1064         if (progressCallback != null) {
1065             try {
1066                 progressCallback.onCredentialVerified();
1067             } catch (RemoteException e) {
1068                 Slog.w(TAG, "progressCallback throws exception", e);
1069             }
1070         }
1071         result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_PASSWORD_BASED,
1072                 applicationId, sid, userId);
1073 
1074         // Perform verifyChallenge to refresh auth tokens for GK if user password exists.
1075         result.gkResponse = verifyChallenge(gatekeeper, result.authToken, 0L, userId);
1076 
1077         // Upgrade case: store the metrics if the device did not have stored metrics before, should
1078         // only happen once on old synthetic password blobs.
1079         if (result.authToken != null && !hasPasswordMetrics(handle, userId)) {
1080             savePasswordMetrics(credential, result.authToken, handle, userId);
1081         }
1082         return result;
1083     }
1084 
1085     /**
1086      * Decrypt a synthetic password by supplying an escrow token and corresponding token
1087      * blob handle generated previously. If the decryption is successful, initiate a GateKeeper
1088      * verification to referesh the SID & Auth token maintained by the system.
1089      */
unwrapTokenBasedSyntheticPassword( IGateKeeperService gatekeeper, long handle, byte[] token, int userId)1090     public @NonNull AuthenticationResult unwrapTokenBasedSyntheticPassword(
1091             IGateKeeperService gatekeeper, long handle, byte[] token, int userId) {
1092         AuthenticationResult result = new AuthenticationResult();
1093         byte[] secdiscardable = loadSecdiscardable(handle, userId);
1094         int slotId = loadWeaverSlot(handle, userId);
1095         if (slotId != INVALID_WEAVER_SLOT) {
1096             if (!isWeaverAvailable()) {
1097                 Slog.e(TAG, "No weaver service to unwrap token based SP");
1098                 result.gkResponse = VerifyCredentialResponse.ERROR;
1099                 return result;
1100             }
1101             VerifyCredentialResponse response = weaverVerify(slotId, null);
1102             if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK ||
1103                     response.getGatekeeperHAT() == null) {
1104                 Slog.e(TAG, "Failed to retrieve weaver secret when unwrapping token");
1105                 result.gkResponse = VerifyCredentialResponse.ERROR;
1106                 return result;
1107             }
1108             secdiscardable = SyntheticPasswordCrypto.decrypt(response.getGatekeeperHAT(),
1109                     PERSONALISATION_WEAVER_TOKEN, secdiscardable);
1110         }
1111         byte[] applicationId = transformUnderSecdiscardable(token, secdiscardable);
1112         result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_TOKEN_BASED,
1113                 applicationId, 0L, userId);
1114         if (result.authToken != null) {
1115             result.gkResponse = verifyChallenge(gatekeeper, result.authToken, 0L, userId);
1116             if (result.gkResponse == null) {
1117                 // The user currently has no password. return OK with null payload so null
1118                 // is propagated to unlockUser()
1119                 result.gkResponse = VerifyCredentialResponse.OK;
1120             }
1121         } else {
1122             result.gkResponse = VerifyCredentialResponse.ERROR;
1123         }
1124         return result;
1125     }
1126 
unwrapSyntheticPasswordBlob(long handle, byte type, byte[] applicationId, long sid, int userId)1127     private AuthenticationToken unwrapSyntheticPasswordBlob(long handle, byte type,
1128             byte[] applicationId, long sid, int userId) {
1129         byte[] blob = loadState(SP_BLOB_NAME, handle, userId);
1130         if (blob == null) {
1131             return null;
1132         }
1133         final byte version = blob[0];
1134         if (version != SYNTHETIC_PASSWORD_VERSION_V3
1135                 && version != SYNTHETIC_PASSWORD_VERSION_V2
1136                 && version != SYNTHETIC_PASSWORD_VERSION_V1) {
1137             throw new IllegalArgumentException("Unknown blob version");
1138         }
1139         if (blob[1] != type) {
1140             throw new IllegalArgumentException("Invalid blob type");
1141         }
1142         final byte[] secret;
1143         if (version == SYNTHETIC_PASSWORD_VERSION_V1) {
1144             secret = SyntheticPasswordCrypto.decryptBlobV1(getKeyName(handle),
1145                     Arrays.copyOfRange(blob, 2, blob.length), applicationId);
1146         } else {
1147             secret = decryptSPBlob(getKeyName(handle),
1148                 Arrays.copyOfRange(blob, 2, blob.length), applicationId);
1149         }
1150         if (secret == null) {
1151             Slog.e(TAG, "Fail to decrypt SP for user " + userId);
1152             return null;
1153         }
1154         AuthenticationToken result = new AuthenticationToken(version);
1155         if (type == SYNTHETIC_PASSWORD_TOKEN_BASED) {
1156             if (!loadEscrowData(result, userId)) {
1157                 Slog.e(TAG, "User is not escrowable: " + userId);
1158                 return null;
1159             }
1160             result.recreateFromEscrow(secret);
1161         } else {
1162             result.recreateDirectly(secret);
1163         }
1164         if (version == SYNTHETIC_PASSWORD_VERSION_V1) {
1165             Slog.i(TAG, "Upgrade v1 SP blob for user " + userId + ", type = " + type);
1166             createSyntheticPasswordBlob(handle, type, result, applicationId, sid, userId);
1167         }
1168         return result;
1169     }
1170 
1171     /**
1172      * performs GK verifyChallenge and returns auth token, re-enrolling SP password handle
1173      * if required.
1174      *
1175      * Normally performing verifyChallenge with an AuthenticationToken should always return
1176      * RESPONSE_OK, since user authentication failures are detected earlier when trying to
1177      * decrypt SP.
1178      */
verifyChallenge(IGateKeeperService gatekeeper, @NonNull AuthenticationToken auth, long challenge, int userId)1179     public @Nullable VerifyCredentialResponse verifyChallenge(IGateKeeperService gatekeeper,
1180             @NonNull AuthenticationToken auth, long challenge, int userId) {
1181         return verifyChallengeInternal(gatekeeper, auth.deriveGkPassword(), challenge, userId);
1182     }
1183 
verifyChallengeInternal( IGateKeeperService gatekeeper, @NonNull byte[] gatekeeperPassword, long challenge, int userId)1184     protected @Nullable VerifyCredentialResponse verifyChallengeInternal(
1185             IGateKeeperService gatekeeper, @NonNull byte[] gatekeeperPassword, long challenge,
1186             int userId) {
1187         byte[] spHandle = loadSyntheticPasswordHandle(userId);
1188         if (spHandle == null) {
1189             // There is no password handle associated with the given user, i.e. the user is not
1190             // secured by lockscreen and has no SID, so just return here;
1191             return null;
1192         }
1193         GateKeeperResponse response;
1194         try {
1195             response = gatekeeper.verifyChallenge(userId, challenge,
1196                     spHandle, gatekeeperPassword);
1197         } catch (RemoteException e) {
1198             Slog.e(TAG, "Fail to verify with gatekeeper " + userId, e);
1199             return VerifyCredentialResponse.ERROR;
1200         }
1201         int responseCode = response.getResponseCode();
1202         if (responseCode == GateKeeperResponse.RESPONSE_OK) {
1203             VerifyCredentialResponse result = new VerifyCredentialResponse.Builder()
1204                     .setGatekeeperHAT(response.getPayload()).build();
1205             if (response.getShouldReEnroll()) {
1206                 try {
1207                     response = gatekeeper.enroll(userId, spHandle, spHandle,
1208                             gatekeeperPassword);
1209                 } catch (RemoteException e) {
1210                     Slog.e(TAG, "Failed to invoke gatekeeper.enroll", e);
1211                     response = GateKeeperResponse.ERROR;
1212                 }
1213                 if (response.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
1214                     spHandle = response.getPayload();
1215                     saveSyntheticPasswordHandle(spHandle, userId);
1216                     // Call self again to re-verify with updated handle
1217                     return verifyChallengeInternal(gatekeeper, gatekeeperPassword, challenge,
1218                             userId);
1219                 } else {
1220                     // Fall through, return result from the previous verification attempt.
1221                     Slog.w(TAG, "Fail to re-enroll SP handle for user " + userId);
1222                 }
1223             }
1224             return result;
1225         } else if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
1226             return VerifyCredentialResponse.fromTimeout(response.getTimeout());
1227         } else {
1228             return VerifyCredentialResponse.ERROR;
1229         }
1230     }
1231 
existsHandle(long handle, int userId)1232     public boolean existsHandle(long handle, int userId) {
1233         return hasState(SP_BLOB_NAME, handle, userId);
1234     }
1235 
destroyTokenBasedSyntheticPassword(long handle, int userId)1236     public void destroyTokenBasedSyntheticPassword(long handle, int userId) {
1237         destroySyntheticPassword(handle, userId);
1238         destroyState(SECDISCARDABLE_NAME, handle, userId);
1239     }
1240 
destroyPasswordBasedSyntheticPassword(long handle, int userId)1241     public void destroyPasswordBasedSyntheticPassword(long handle, int userId) {
1242         destroySyntheticPassword(handle, userId);
1243         destroyState(SECDISCARDABLE_NAME, handle, userId);
1244         destroyState(PASSWORD_DATA_NAME, handle, userId);
1245         destroyState(PASSWORD_METRICS_NAME, handle, userId);
1246     }
1247 
destroySyntheticPassword(long handle, int userId)1248     private void destroySyntheticPassword(long handle, int userId) {
1249         destroyState(SP_BLOB_NAME, handle, userId);
1250         destroySPBlobKey(getKeyName(handle));
1251         if (hasState(WEAVER_SLOT_NAME, handle, userId)) {
1252             destroyWeaverSlot(handle, userId);
1253         }
1254     }
1255 
transformUnderWeaverSecret(byte[] data, byte[] secret)1256     private byte[] transformUnderWeaverSecret(byte[] data, byte[] secret) {
1257         byte[] weaverSecret = SyntheticPasswordCrypto.personalisedHash(
1258                 PERSONALISATION_WEAVER_PASSWORD, secret);
1259         byte[] result = new byte[data.length + weaverSecret.length];
1260         System.arraycopy(data, 0, result, 0, data.length);
1261         System.arraycopy(weaverSecret, 0, result, data.length, weaverSecret.length);
1262         return result;
1263     }
1264 
transformUnderSecdiscardable(byte[] data, byte[] rawSecdiscardable)1265     private byte[] transformUnderSecdiscardable(byte[] data, byte[] rawSecdiscardable) {
1266         byte[] secdiscardable = SyntheticPasswordCrypto.personalisedHash(
1267                 PERSONALISATION_SECDISCARDABLE, rawSecdiscardable);
1268         byte[] result = new byte[data.length + secdiscardable.length];
1269         System.arraycopy(data, 0, result, 0, data.length);
1270         System.arraycopy(secdiscardable, 0, result, data.length, secdiscardable.length);
1271         return result;
1272     }
1273 
createSecdiscardable(long handle, int userId)1274     private byte[] createSecdiscardable(long handle, int userId) {
1275         byte[] data = secureRandom(SECDISCARDABLE_LENGTH);
1276         saveSecdiscardable(handle, data, userId);
1277         return data;
1278     }
1279 
saveSecdiscardable(long handle, byte[] secdiscardable, int userId)1280     private void saveSecdiscardable(long handle, byte[] secdiscardable, int userId) {
1281         saveState(SECDISCARDABLE_NAME, secdiscardable, handle, userId);
1282     }
1283 
loadSecdiscardable(long handle, int userId)1284     private byte[] loadSecdiscardable(long handle, int userId) {
1285         return loadState(SECDISCARDABLE_NAME, handle, userId);
1286     }
1287 
1288     /**
1289      * Retrieves the saved password metrics associated with a SP handle. Only meaningful to be
1290      * called on the handle of a password-based synthetic password. A valid AuthenticationToken for
1291      * the target user is required in order to be able to decrypt the encrypted password metrics on
1292      * disk.
1293      */
getPasswordMetrics(AuthenticationToken authToken, long handle, int userId)1294     public @Nullable PasswordMetrics getPasswordMetrics(AuthenticationToken authToken, long handle,
1295             int userId) {
1296         final byte[] encrypted = loadState(PASSWORD_METRICS_NAME, handle, userId);
1297         if (encrypted == null) return null;
1298         final byte[] decrypted = SyntheticPasswordCrypto.decrypt(authToken.deriveMetricsKey(),
1299                 /* personalization= */ new byte[0], encrypted);
1300         if (decrypted == null) return null;
1301         return VersionedPasswordMetrics.deserialize(decrypted).getMetrics();
1302     }
1303 
savePasswordMetrics(LockscreenCredential credential, AuthenticationToken authToken, long handle, int userId)1304     private void savePasswordMetrics(LockscreenCredential credential, AuthenticationToken authToken,
1305             long handle, int userId) {
1306         final byte[] encrypted = SyntheticPasswordCrypto.encrypt(authToken.deriveMetricsKey(),
1307                 /* personalization= */ new byte[0],
1308                 new VersionedPasswordMetrics(credential).serialize());
1309         saveState(PASSWORD_METRICS_NAME, encrypted, handle, userId);
1310     }
1311 
hasPasswordMetrics(long handle, int userId)1312     private boolean hasPasswordMetrics(long handle, int userId) {
1313         return hasState(PASSWORD_METRICS_NAME, handle, userId);
1314     }
1315 
hasState(String stateName, long handle, int userId)1316     private boolean hasState(String stateName, long handle, int userId) {
1317         return !ArrayUtils.isEmpty(loadState(stateName, handle, userId));
1318     }
1319 
loadState(String stateName, long handle, int userId)1320     private byte[] loadState(String stateName, long handle, int userId) {
1321         return mStorage.readSyntheticPasswordState(userId, handle, stateName);
1322     }
1323 
saveState(String stateName, byte[] data, long handle, int userId)1324     private void saveState(String stateName, byte[] data, long handle, int userId) {
1325         mStorage.writeSyntheticPasswordState(userId, handle, stateName, data);
1326     }
1327 
destroyState(String stateName, long handle, int userId)1328     private void destroyState(String stateName, long handle, int userId) {
1329         mStorage.deleteSyntheticPasswordState(userId, handle, stateName);
1330     }
1331 
decryptSPBlob(String blobKeyName, byte[] blob, byte[] applicationId)1332     protected byte[] decryptSPBlob(String blobKeyName, byte[] blob, byte[] applicationId) {
1333         return SyntheticPasswordCrypto.decryptBlob(blobKeyName, blob, applicationId);
1334     }
1335 
createSPBlob(String blobKeyName, byte[] data, byte[] applicationId, long sid)1336     protected byte[] createSPBlob(String blobKeyName, byte[] data, byte[] applicationId, long sid) {
1337         return SyntheticPasswordCrypto.createBlob(blobKeyName, data, applicationId, sid);
1338     }
1339 
destroySPBlobKey(String keyAlias)1340     protected void destroySPBlobKey(String keyAlias) {
1341         SyntheticPasswordCrypto.destroyBlobKey(keyAlias);
1342     }
1343 
generateHandle()1344     public static long generateHandle() {
1345         SecureRandom rng = new SecureRandom();
1346         long result;
1347         do {
1348             result = rng.nextLong();
1349         } while (result == DEFAULT_HANDLE);
1350         return result;
1351     }
1352 
fakeUid(int uid)1353     private int fakeUid(int uid) {
1354         return 100000 + uid;
1355     }
1356 
secureRandom(int length)1357     protected static byte[] secureRandom(int length) {
1358         try {
1359             return SecureRandom.getInstance("SHA1PRNG").generateSeed(length);
1360         } catch (NoSuchAlgorithmException e) {
1361             e.printStackTrace();
1362             return null;
1363         }
1364     }
1365 
getKeyName(long handle)1366     private String getKeyName(long handle) {
1367         return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle);
1368     }
1369 
computePasswordToken(LockscreenCredential credential, PasswordData data)1370     private byte[] computePasswordToken(LockscreenCredential credential, PasswordData data) {
1371         final byte[] password = credential.isNone() ? DEFAULT_PASSWORD : credential.getCredential();
1372         return scrypt(password, data.salt, 1 << data.scryptN, 1 << data.scryptR, 1 << data.scryptP,
1373                 PASSWORD_TOKEN_LENGTH);
1374     }
1375 
passwordTokenToGkInput(byte[] token)1376     private byte[] passwordTokenToGkInput(byte[] token) {
1377         return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_USER_GK_AUTH, token);
1378     }
1379 
passwordTokenToWeaverKey(byte[] token)1380     private byte[] passwordTokenToWeaverKey(byte[] token) {
1381         byte[] key = SyntheticPasswordCrypto.personalisedHash(PERSONALISATION_WEAVER_KEY, token);
1382         if (key.length < mWeaverConfig.keySize) {
1383             throw new IllegalArgumentException("weaver key length too small");
1384         }
1385         return Arrays.copyOf(key, mWeaverConfig.keySize);
1386     }
1387 
sidFromPasswordHandle(byte[] handle)1388     protected long sidFromPasswordHandle(byte[] handle) {
1389         return nativeSidFromPasswordHandle(handle);
1390     }
1391 
scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen)1392     protected byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) {
1393         return new Scrypt().scrypt(password, salt, n, r, p, outLen);
1394     }
1395 
nativeSidFromPasswordHandle(byte[] handle)1396     native long nativeSidFromPasswordHandle(byte[] handle);
1397 
toByteArrayList(byte[] data)1398     protected static ArrayList<Byte> toByteArrayList(byte[] data) {
1399         ArrayList<Byte> result = new ArrayList<Byte>(data.length);
1400         for (int i = 0; i < data.length; i++) {
1401             result.add(data[i]);
1402         }
1403         return result;
1404     }
1405 
fromByteArrayList(ArrayList<Byte> data)1406     protected static byte[] fromByteArrayList(ArrayList<Byte> data) {
1407         byte[] result = new byte[data.size()];
1408         for (int i = 0; i < data.size(); i++) {
1409             result[i] = data.get(i);
1410         }
1411         return result;
1412     }
1413 
1414     protected static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes();
bytesToHex(byte[] bytes)1415     private static byte[] bytesToHex(byte[] bytes) {
1416         if (bytes == null) {
1417             return "null".getBytes();
1418         }
1419         byte[] hexBytes = new byte[bytes.length * 2];
1420         for ( int j = 0; j < bytes.length; j++ ) {
1421             int v = bytes[j] & 0xFF;
1422             hexBytes[j * 2] = HEX_ARRAY[v >>> 4];
1423             hexBytes[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
1424         }
1425         return hexBytes;
1426     }
1427 
1428     /**
1429      * Migrate all existing SP keystore keys from uid 1000 app domain to LSS selinux domain
1430      */
migrateKeyNamespace()1431     public boolean migrateKeyNamespace() {
1432         boolean success = true;
1433         final Map<Integer, List<Long>> allHandles =
1434                 mStorage.listSyntheticPasswordHandlesForAllUsers(SP_BLOB_NAME);
1435         for (List<Long> userHandles : allHandles.values()) {
1436             for (long handle : userHandles) {
1437                 success &= SyntheticPasswordCrypto.migrateLockSettingsKey(getKeyName(handle));
1438             }
1439         }
1440         return success;
1441     }
1442 }
1443