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