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