1 /*
2  * Copyright (C) 2020 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 android.security;
18 
19 import android.annotation.NonNull;
20 import android.compat.annotation.ChangeId;
21 import android.compat.annotation.Disabled;
22 import android.os.Binder;
23 import android.os.RemoteException;
24 import android.os.ServiceManager;
25 import android.os.ServiceSpecificException;
26 import android.security.keymaster.KeymasterDefs;
27 import android.system.keystore2.Domain;
28 import android.system.keystore2.IKeystoreService;
29 import android.system.keystore2.KeyDescriptor;
30 import android.system.keystore2.KeyEntryResponse;
31 import android.system.keystore2.ResponseCode;
32 import android.util.Log;
33 
34 import java.util.Calendar;
35 
36 /**
37  * @hide This should not be made public in its present form because it
38  * assumes that private and secret key bytes are available and would
39  * preclude the use of hardware crypto.
40  */
41 public class KeyStore2 {
42     private static final String TAG = "KeyStore";
43 
44     private static final int RECOVERY_GRACE_PERIOD_MS = 50;
45 
46     /**
47      * Keystore operation creation may fail
48      *
49      * Keystore used to work under the assumption that the creation of cryptographic operations
50      * always succeeds. However, the KeyMint backend has only a limited number of operation slots.
51      * In order to keep up the appearance of "infinite" operation slots, the Keystore daemon
52      * would prune least recently used operations if there is no available operation slot.
53      * As a result, good operations could be terminated prematurely.
54      *
55      * This opens AndroidKeystore up to denial-of-service and unintended livelock situations.
56      * E.g.: if multiple apps wake up at the same time, e.g., due to power management optimizations,
57      * and attempt to perform crypto operations, they start terminating each others operations
58      * without making any progress.
59      *
60      * To break out of livelocks and to discourage DoS attempts we have changed the pruning
61      * strategy such that it prefers clients that use few operation slots and only briefly.
62      * As a result we can, almost, guarantee that single operations that don't linger inactive
63      * for more than 5 seconds will conclude unhampered by the pruning strategy. "Almost",
64      * because there are operations related to file system encryption that can prune even
65      * these operations, but those are extremely rare.
66      *
67      * As a side effect of this new pruning strategy operation creation can now fail if the
68      * client has a lower pruning power than all of the existing operations.
69      *
70      * Pruning strategy
71      *
72      * To find a suitable candidate we compute the malus for the caller and each existing
73      * operation. The malus is the inverse of the pruning power (caller) or pruning
74      * resistance (existing operation). For the caller to be able to prune an operation it must
75      * find an operation with a malus higher than its own.
76      *
77      * For more detail on the pruning strategy consult the implementation at
78      * https://android.googlesource.com/platform/system/security/+/refs/heads/master/keystore2/src/operation.rs
79      *
80      * For older SDK version, KeyStore2 will poll the Keystore daemon for a free operation
81      * slot. So to applications, targeting earlier SDK versions, it will still look like cipher and
82      * signature object initialization always succeeds, however, it may take longer to get an
83      * operation.
84      *
85      * All SDK version benefit from fairer operation slot scheduling and a better chance to
86      * successfully conclude an operation.
87      */
88     @ChangeId
89     @Disabled // See b/180133780
90     static final long KEYSTORE_OPERATION_CREATION_MAY_FAIL = 169897160L;
91 
92     // Never use mBinder directly, use KeyStore2.getService() instead or better yet
93     // handleRemoteExceptionWithRetry which retries connecting to Keystore once in case
94     // of a remote exception.
95     private IKeystoreService mBinder;
96 
97 
98     @FunctionalInterface
99     interface CheckedRemoteRequest<R> {
execute(IKeystoreService service)100         R execute(IKeystoreService service) throws RemoteException;
101     }
102 
handleRemoteExceptionWithRetry(@onNull CheckedRemoteRequest<R> request)103     private <R> R handleRemoteExceptionWithRetry(@NonNull CheckedRemoteRequest<R> request)
104             throws KeyStoreException {
105         IKeystoreService service = getService(false /* retryLookup */);
106         boolean firstTry = true;
107         while (true) {
108             try {
109                 return request.execute(service);
110             } catch (ServiceSpecificException e) {
111                 throw getKeyStoreException(e.errorCode);
112             } catch (RemoteException e) {
113                 if (firstTry) {
114                     Log.w(TAG, "Looks like we may have lost connection to the Keystore "
115                             + "daemon.");
116                     Log.w(TAG, "Retrying after giving Keystore "
117                             + RECOVERY_GRACE_PERIOD_MS + "ms to recover.");
118                     interruptedPreservingSleep(RECOVERY_GRACE_PERIOD_MS);
119                     service = getService(true /* retry Lookup */);
120                     firstTry = false;
121                 } else {
122                     Log.e(TAG, "Cannot connect to Keystore daemon.", e);
123                     throw new KeyStoreException(ResponseCode.SYSTEM_ERROR, "");
124                 }
125             }
126         }
127     }
128 
129     private static final String KEYSTORE2_SERVICE_NAME =
130             "android.system.keystore2.IKeystoreService/default";
131 
KeyStore2()132     private KeyStore2() {
133         mBinder = null;
134     }
135 
getInstance()136     public static KeyStore2 getInstance() {
137         return new KeyStore2();
138     }
139 
getService(boolean retryLookup)140     private synchronized IKeystoreService getService(boolean retryLookup) {
141         if (mBinder == null || retryLookup) {
142             mBinder = IKeystoreService.Stub.asInterface(ServiceManager
143                     .getService(KEYSTORE2_SERVICE_NAME));
144             Binder.allowBlocking(mBinder.asBinder());
145         }
146         return mBinder;
147     }
148 
delete(KeyDescriptor descriptor)149     void delete(KeyDescriptor descriptor) throws KeyStoreException {
150         handleRemoteExceptionWithRetry((service) -> {
151             service.deleteKey(descriptor);
152             return 0;
153         });
154     }
155 
156     /**
157      * List all entries in the keystore for in the given namespace.
158      */
list(int domain, long namespace)159     public KeyDescriptor[] list(int domain, long namespace) throws KeyStoreException {
160         return handleRemoteExceptionWithRetry((service) -> service.listEntries(domain, namespace));
161     }
162 
163     /**
164      * Grant string prefix as used by the keystore boringssl engine. Must be kept in sync
165      * with system/security/keystore-engine. Note: The prefix here includes the 0x which
166      * std::stringstream used in keystore-engine needs to identify the number as hex represented.
167      * Here we include it in the prefix, because Long#parseUnsignedLong does not understand it
168      * and gets the radix as explicit argument.
169      * @hide
170      */
171     private static final String KEYSTORE_ENGINE_GRANT_ALIAS_PREFIX =
172             "ks2_keystore-engine_grant_id:0x";
173 
174     /**
175      * This function turns a grant identifier into a specific string that is understood by the
176      * keystore-engine in system/security/keystore-engine. Is only used by VPN and WI-FI components
177      * to allow certain system components like racoon or vendor components like WPA supplicant
178      * to use keystore keys with boring ssl.
179      *
180      * @param grantId the grant id as returned by {@link #grant} in the {@code nspace} filed of
181      *                the resulting {@code KeyDescriptor}.
182      * @return The grant descriptor string.
183      * @hide
184      */
makeKeystoreEngineGrantString(long grantId)185     public static String makeKeystoreEngineGrantString(long grantId) {
186         return String.format("%s%016X", KEYSTORE_ENGINE_GRANT_ALIAS_PREFIX, grantId);
187     }
188 
189     /**
190      * Convenience function to turn a keystore engine grant string as returned by
191      * {@link #makeKeystoreEngineGrantString(long)} back into a grant KeyDescriptor.
192      *
193      * @param grantString As string returned by {@link #makeKeystoreEngineGrantString(long)}
194      * @return The grant key descriptor.
195      * @hide
196      */
keystoreEngineGrantString2KeyDescriptor(String grantString)197     public static KeyDescriptor keystoreEngineGrantString2KeyDescriptor(String grantString) {
198         KeyDescriptor key = new KeyDescriptor();
199         key.domain = Domain.GRANT;
200         key.nspace = Long.parseUnsignedLong(
201                 grantString.substring(KEYSTORE_ENGINE_GRANT_ALIAS_PREFIX.length()), 16);
202         key.alias = null;
203         key.blob = null;
204         return key;
205     }
206 
207     /**
208      * Create a grant that allows the grantee identified by {@code granteeUid} to use
209      * the key specified by {@code descriptor} withint the restrictions given by
210      * {@code accessVectore}.
211      * @see IKeystoreService#grant(KeyDescriptor, int, int) for more details.
212      * @param descriptor
213      * @param granteeUid
214      * @param accessVector
215      * @return
216      * @throws KeyStoreException
217      * @hide
218      */
grant(KeyDescriptor descriptor, int granteeUid, int accessVector)219     public KeyDescriptor grant(KeyDescriptor descriptor, int granteeUid, int accessVector)
220             throws  KeyStoreException {
221         return handleRemoteExceptionWithRetry(
222                 (service) -> service.grant(descriptor, granteeUid, accessVector)
223         );
224     }
225 
226     /**
227      * Destroys a grant.
228      * @see IKeystoreService#ungrant(KeyDescriptor, int) for more details.
229      * @param descriptor
230      * @param granteeUid
231      * @throws KeyStoreException
232      * @hide
233      */
ungrant(KeyDescriptor descriptor, int granteeUid)234     public void ungrant(KeyDescriptor descriptor, int granteeUid)
235             throws KeyStoreException {
236         handleRemoteExceptionWithRetry((service) -> {
237             service.ungrant(descriptor, granteeUid);
238             return 0;
239         });
240     }
241 
242     /**
243      * Retrieves a key entry from the keystore backend.
244      * @see IKeystoreService#getKeyEntry(KeyDescriptor) for more details.
245      * @param descriptor
246      * @return
247      * @throws KeyStoreException
248      * @hide
249      */
getKeyEntry(@onNull KeyDescriptor descriptor)250     public KeyEntryResponse getKeyEntry(@NonNull KeyDescriptor descriptor)
251             throws KeyStoreException {
252         return handleRemoteExceptionWithRetry((service) -> service.getKeyEntry(descriptor));
253     }
254 
255     /**
256      * Get the security level specific keystore interface from the keystore daemon.
257      * @see IKeystoreService#getSecurityLevel(int) for more details.
258      * @param securityLevel
259      * @return
260      * @throws KeyStoreException
261      * @hide
262      */
getSecurityLevel(int securityLevel)263     public KeyStoreSecurityLevel getSecurityLevel(int securityLevel)
264             throws KeyStoreException {
265         return handleRemoteExceptionWithRetry((service) ->
266             new KeyStoreSecurityLevel(
267                     service.getSecurityLevel(securityLevel)
268             )
269         );
270     }
271 
272     /**
273      * Update the subcomponents of a key entry designated by the key descriptor.
274      * @see IKeystoreService#updateSubcomponent(KeyDescriptor, byte[], byte[]) for more details.
275      * @param key
276      * @param publicCert
277      * @param publicCertChain
278      * @throws KeyStoreException
279      * @hide
280      */
updateSubcomponents(@onNull KeyDescriptor key, byte[] publicCert, byte[] publicCertChain)281     public void updateSubcomponents(@NonNull KeyDescriptor key, byte[] publicCert,
282             byte[] publicCertChain) throws KeyStoreException {
283         handleRemoteExceptionWithRetry((service) -> {
284             service.updateSubcomponent(key, publicCert, publicCertChain);
285             return 0;
286         });
287     }
288 
289     /**
290      * Delete the key designed by the key descriptor.
291      * @see IKeystoreService#deleteKey(KeyDescriptor) for more details.
292      * @param descriptor
293      * @throws KeyStoreException
294      * @hide
295      */
deleteKey(@onNull KeyDescriptor descriptor)296     public void deleteKey(@NonNull KeyDescriptor descriptor)
297             throws KeyStoreException {
298         handleRemoteExceptionWithRetry((service) -> {
299             service.deleteKey(descriptor);
300             return 0;
301         });
302     }
303 
interruptedPreservingSleep(long millis)304     protected static void interruptedPreservingSleep(long millis) {
305         boolean wasInterrupted = false;
306         Calendar calendar = Calendar.getInstance();
307         long target = calendar.getTimeInMillis() + millis;
308         while (true) {
309             try {
310                 Thread.sleep(target - calendar.getTimeInMillis());
311                 break;
312             } catch (InterruptedException e) {
313                 wasInterrupted = true;
314             } catch (IllegalArgumentException e) {
315                 // This means that the argument to sleep was negative.
316                 // So we are done sleeping.
317                 break;
318             }
319         }
320         if (wasInterrupted) {
321             Thread.currentThread().interrupt();
322         }
323     }
324 
getKeyStoreException(int errorCode)325     static KeyStoreException getKeyStoreException(int errorCode) {
326         if (errorCode > 0) {
327             // KeyStore layer error
328             switch (errorCode) {
329                 case ResponseCode.LOCKED:
330                     return new KeyStoreException(errorCode, "User authentication required");
331                 case ResponseCode.UNINITIALIZED:
332                     return new KeyStoreException(errorCode, "Keystore not initialized");
333                 case ResponseCode.SYSTEM_ERROR:
334                     return new KeyStoreException(errorCode, "System error");
335                 case ResponseCode.PERMISSION_DENIED:
336                     return new KeyStoreException(errorCode, "Permission denied");
337                 case ResponseCode.KEY_NOT_FOUND:
338                     return new KeyStoreException(errorCode, "Key not found");
339                 case ResponseCode.VALUE_CORRUPTED:
340                     return new KeyStoreException(errorCode, "Key blob corrupted");
341                 case ResponseCode.KEY_PERMANENTLY_INVALIDATED:
342                     return new KeyStoreException(errorCode, "Key permanently invalidated");
343                 default:
344                     return new KeyStoreException(errorCode, String.valueOf(errorCode));
345             }
346         } else {
347             // Keymaster layer error
348             switch (errorCode) {
349                 case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
350                     // The name of this parameter significantly differs between Keymaster and
351                     // framework APIs. Use the framework wording to make life easier for developers.
352                     return new KeyStoreException(errorCode,
353                             "Invalid user authentication validity duration");
354                 default:
355                     return new KeyStoreException(errorCode,
356                             KeymasterDefs.getErrorMessage(errorCode));
357             }
358         }
359     }
360 
361 }
362