1 /* 2 * Copyright (C) 2011 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.keychain; 18 19 import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_INSTALLED; 20 import static android.app.admin.SecurityLog.TAG_CERT_AUTHORITY_REMOVED; 21 import static android.security.KeyStore.UID_SELF; 22 23 import android.Manifest; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.app.AppOpsManager; 27 import android.app.BroadcastOptions; 28 import android.app.IntentService; 29 import android.app.admin.SecurityLog; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.pm.ApplicationInfo; 33 import android.content.pm.PackageManager; 34 import android.content.pm.StringParceledListSlice; 35 import android.hardware.security.keymint.ErrorCode; 36 import android.net.Uri; 37 import android.os.Binder; 38 import android.os.Build; 39 import android.os.IBinder; 40 import android.os.Process; 41 import android.os.UserHandle; 42 import android.security.AppUriAuthenticationPolicy; 43 import android.security.CredentialManagementApp; 44 import android.security.IKeyChainService; 45 import android.security.KeyChain; 46 import android.security.KeyStore2; 47 import android.security.keystore.KeyGenParameterSpec; 48 import android.security.keystore.KeyProperties; 49 import android.security.keystore.ParcelableKeyGenParameterSpec; 50 import android.security.keystore.StrongBoxUnavailableException; 51 import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; 52 import android.system.keystore2.Domain; 53 import android.system.keystore2.KeyDescriptor; 54 import android.system.keystore2.KeyPermission; 55 import android.text.TextUtils; 56 import android.util.Base64; 57 import android.util.Log; 58 59 import com.android.internal.annotations.GuardedBy; 60 import com.android.internal.annotations.VisibleForTesting; 61 import com.android.internal.util.Preconditions; 62 import com.android.internal.widget.LockPatternUtils; 63 import com.android.keychain.internal.ExistingKeysProvider; 64 import com.android.keychain.internal.GrantsDatabase; 65 import com.android.org.conscrypt.TrustedCertificateStore; 66 67 import java.io.ByteArrayInputStream; 68 import java.io.ByteArrayOutputStream; 69 import java.io.IOException; 70 import java.security.InvalidAlgorithmParameterException; 71 import java.security.Key; 72 import java.security.KeyFactory; 73 import java.security.KeyPair; 74 import java.security.KeyPairGenerator; 75 import java.security.KeyStore; 76 import java.security.KeyStoreException; 77 import java.security.NoSuchAlgorithmException; 78 import java.security.NoSuchProviderException; 79 import java.security.PrivateKey; 80 import java.security.ProviderException; 81 import java.security.UnrecoverableKeyException; 82 import java.security.cert.Certificate; 83 import java.security.cert.CertificateEncodingException; 84 import java.security.cert.CertificateException; 85 import java.security.cert.CertificateFactory; 86 import java.security.cert.X509Certificate; 87 import java.security.spec.InvalidKeySpecException; 88 import java.security.spec.PKCS8EncodedKeySpec; 89 import java.util.ArrayList; 90 import java.util.Arrays; 91 import java.util.Collection; 92 import java.util.Collections; 93 import java.util.Enumeration; 94 import java.util.HashSet; 95 import java.util.List; 96 import java.util.Map; 97 import java.util.Set; 98 99 import javax.security.auth.x500.X500Principal; 100 101 public class KeyChainService extends IntentService { 102 103 private static final String TAG = "KeyChain"; 104 private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller"; 105 private final Set<Integer> ALLOWED_UIDS = Collections.unmodifiableSet( 106 new HashSet(Arrays.asList(UID_SELF, Process.WIFI_UID))); 107 108 private static final String MSG_NOT_SYSTEM = "Not system package"; 109 private static final String MSG_NOT_SYSTEM_OR_CERT_INSTALLER = 110 "Not system or cert installer package"; 111 private static final String MSG_NOT_SYSTEM_OR_CRED_MNG_APP = 112 "Not system or credential management app package"; 113 114 /** created in onCreate(), closed in onDestroy() */ 115 private GrantsDatabase mGrantsDb; 116 private Injector mInjector; 117 private KeyStore mKeyStore; 118 private KeyChainStateStorage mStateStorage; 119 120 private Object mCredentialManagementAppLock = new Object(); 121 @Nullable 122 @GuardedBy("mCredentialManagementAppLock") 123 private CredentialManagementApp mCredentialManagementApp; 124 KeyChainService()125 public KeyChainService() { 126 super(KeyChainService.class.getSimpleName()); 127 mInjector = new Injector(); 128 } 129 getKeyStore()130 private KeyStore getKeyStore() { 131 try { 132 final KeyStore keystore = mInjector.getKeyStoreInstance(); 133 keystore.load(null); 134 return keystore; 135 } catch (KeyStoreException | IOException | NoSuchAlgorithmException 136 | CertificateException e) { 137 Log.e(TAG, "Error opening AndroidKeyStore.", e); 138 throw new RuntimeException("Error opening AndroidKeyStore.", e); 139 } 140 } 141 getKeyStore(boolean useWifiNamespace)142 private KeyStore getKeyStore(boolean useWifiNamespace) { 143 if (!useWifiNamespace) { 144 return mKeyStore; 145 } 146 try { 147 final KeyStore keystore = mInjector.getKeyStoreInstance(); 148 keystore.load( 149 new AndroidKeyStoreLoadStoreParameter( 150 KeyProperties.NAMESPACE_WIFI)); 151 return keystore; 152 } catch (IOException | CertificateException | KeyStoreException 153 | NoSuchAlgorithmException e) { 154 Log.e(TAG, "Failed to open AndroidKeyStore for WI-FI namespace.", e); 155 return null; 156 } 157 } 158 onCreate()159 @Override public void onCreate() { 160 super.onCreate(); 161 mKeyStore = getKeyStore(); 162 mGrantsDb = new GrantsDatabase(this, new KeyStoreAliasesProvider(mKeyStore)); 163 mStateStorage = new KeyChainStateStorage(getDataDir()); 164 165 synchronized (mCredentialManagementAppLock) { 166 mCredentialManagementApp = mStateStorage.loadCredentialManagementApp(); 167 } 168 } 169 170 @Override onDestroy()171 public void onDestroy() { 172 super.onDestroy(); 173 mGrantsDb.destroy(); 174 mGrantsDb = null; 175 } 176 177 private static class KeyStoreAliasesProvider implements ExistingKeysProvider { 178 private final KeyStore mKeyStore; 179 KeyStoreAliasesProvider(KeyStore keyStore)180 KeyStoreAliasesProvider(KeyStore keyStore) { 181 mKeyStore = keyStore; 182 } 183 184 @Override getExistingKeyAliases()185 public List<String> getExistingKeyAliases() { 186 final List<String> keyStoreAliases = new ArrayList<>(); 187 try { 188 final Enumeration<String> aliases = mKeyStore.aliases(); 189 while (aliases.hasMoreElements()) { 190 final String alias = aliases.nextElement(); 191 if (!alias.startsWith(LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX)) { 192 if (mKeyStore.isKeyEntry(alias)) { 193 keyStoreAliases.add(alias); 194 } 195 } 196 } 197 } catch (KeyStoreException e) { 198 Log.e(TAG, "Error while loading entries from keystore. " 199 + "List may be empty or incomplete."); 200 } 201 202 return keyStoreAliases; 203 } 204 } 205 makeKeyDescriptor(String alias)206 private KeyDescriptor makeKeyDescriptor(String alias) { 207 final KeyDescriptor key = new KeyDescriptor(); 208 key.domain = Domain.APP; 209 key.nspace = KeyProperties.NAMESPACE_APPLICATION; 210 key.alias = alias; 211 key.blob = null; 212 return key; 213 } 214 215 private final IKeyChainService.Stub mIKeyChainService = new IKeyChainService.Stub() { 216 private final TrustedCertificateStore mTrustedCertificateStore 217 = new TrustedCertificateStore(); 218 private final Context mContext = KeyChainService.this; 219 220 @Override 221 public String requestPrivateKey(String alias) { 222 final CallerIdentity caller = getCaller(); 223 if (!hasGrant(alias, caller)) { 224 return null; 225 } 226 227 final int granteeUid = caller.mUid; 228 229 try { 230 final KeyStore2 keyStore2 = KeyStore2.getInstance(); 231 KeyDescriptor grant = keyStore2.grant(makeKeyDescriptor(alias), granteeUid, 232 KeyPermission.USE | KeyPermission.GET_INFO); 233 return KeyChain.getGrantString(grant); 234 } catch (android.security.KeyStoreException e) { 235 Log.e(TAG, "Failed to grant " + alias + " to uid: " + granteeUid, e); 236 return null; 237 } 238 } 239 240 @Override 241 public String getWifiKeyGrantAsUser(String alias) { 242 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 243 244 if (!hasGrant(alias, Process.WIFI_UID)) { 245 return null; 246 } 247 248 KeyStore2 keyStore2 = KeyStore2.getInstance(); 249 try { 250 KeyDescriptor grant = keyStore2.grant(makeKeyDescriptor(alias), 251 Process.WIFI_UID, KeyPermission.USE | KeyPermission.GET_INFO); 252 return KeyStore2.makeKeystoreEngineGrantString(grant.nspace); 253 } catch (android.security.KeyStoreException e) { 254 Log.e(TAG, "Failed to grant " + alias + " to uid: " + Process.WIFI_UID, e); 255 return null; 256 } 257 } 258 259 @Override public byte[] getCertificate(String alias) { 260 final CallerIdentity caller = getCaller(); 261 if (!hasGrant(alias, caller) && !isSystemUid(caller)) { 262 return null; 263 } 264 try { 265 if (!mKeyStore.isCertificateEntry(alias)) { 266 final Certificate cert = mKeyStore.getCertificate(alias); 267 if (cert == null) return null; 268 return cert.getEncoded(); 269 } else { 270 return null; 271 } 272 } catch (KeyStoreException | CertificateEncodingException e) { 273 Log.e(TAG, "Failed to retrieve certificate.", e); 274 return null; 275 } 276 } 277 278 @Override public byte[] getCaCertificates(String alias) { 279 final CallerIdentity caller = getCaller(); 280 if (!hasGrant(alias, caller) && !isSystemUid(caller)) { 281 return null; 282 } 283 try { 284 if (mKeyStore.isCertificateEntry(alias)) { 285 return mKeyStore.getCertificate(alias).getEncoded(); 286 } else { 287 final Certificate[] certs = mKeyStore.getCertificateChain(alias); 288 if (certs == null || certs.length <= 1) return null; 289 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 290 for (int i = 1; i < certs.length; ++i) { 291 outputStream.write(certs[i].getEncoded()); 292 } 293 return outputStream.toByteArray(); 294 } 295 } catch (KeyStoreException | CertificateEncodingException | IOException e) { 296 Log.e(TAG, "Failed to retrieve certificate(s) from AndroidKeyStore.", e); 297 return null; 298 } 299 } 300 301 @Override public boolean isUserSelectable(String alias) { 302 validateAlias(alias); 303 return mGrantsDb.isUserSelectable(alias); 304 } 305 306 @Override public void setUserSelectable(String alias, boolean isUserSelectable) { 307 validateAlias(alias); 308 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 309 Log.i(TAG, String.format("Marking certificate %s as user-selectable: %b", alias, 310 isUserSelectable)); 311 mGrantsDb.setIsUserSelectable(alias, isUserSelectable); 312 } 313 314 @Override public int generateKeyPair( 315 String algorithm, ParcelableKeyGenParameterSpec parcelableSpec) { 316 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 317 final KeyGenParameterSpec spec = parcelableSpec.getSpec(); 318 final String alias = spec.getKeystoreAlias(); 319 320 Log.i(TAG, String.format("About to generate key with alias %s, algorithm %s", 321 alias, algorithm)); 322 323 if (KeyChain.KEY_ALIAS_SELECTION_DENIED.equals(alias)) { 324 throw new IllegalArgumentException("The alias specified for the key denotes " 325 + "a reserved value and cannot be used to name a key"); 326 } 327 // Validate the alias here to avoid relying on KeyGenParameterSpec c'tor preventing 328 // the creation of a KeyGenParameterSpec instance with a non-empty alias. 329 if (TextUtils.isEmpty(alias) || spec.getUid() != UID_SELF) { 330 Log.e(TAG, "Cannot generate key pair with empty alias or specified uid."); 331 return KeyChain.KEY_GEN_MISSING_ALIAS; 332 } 333 334 try { 335 KeyPairGenerator generator = KeyPairGenerator.getInstance( 336 algorithm, "AndroidKeyStore"); 337 // Do not prepend USER_PRIVATE_KEY to the alias because 338 // AndroidKeyStoreKeyPairGeneratorSpi will helpfully prepend that in 339 // generateKeyPair. 340 generator.initialize(spec); 341 KeyPair kp = generator.generateKeyPair(); 342 if (kp == null) { 343 Log.e(TAG, "Key generation failed."); 344 return KeyChain.KEY_GEN_FAILURE; 345 } 346 return KeyChain.KEY_GEN_SUCCESS; 347 } catch (NoSuchAlgorithmException e) { 348 Log.e(TAG, "Invalid algorithm requested", e); 349 return KeyChain.KEY_GEN_NO_SUCH_ALGORITHM; 350 } catch (InvalidAlgorithmParameterException e) { 351 Log.e(TAG, "Invalid algorithm params", e); 352 return KeyChain.KEY_GEN_INVALID_ALGORITHM_PARAMETERS; 353 } catch (NoSuchProviderException e) { 354 Log.e(TAG, "Could not find Keystore.", e); 355 return KeyChain.KEY_GEN_NO_KEYSTORE_PROVIDER; 356 } catch (StrongBoxUnavailableException e) { 357 Log.e(TAG, "StrongBox unavailable.", e); 358 return KeyChain.KEY_GEN_STRONGBOX_UNAVAILABLE; 359 } catch (ProviderException e) { 360 Throwable t = e.getCause(); 361 if (t instanceof android.security.KeyStoreException) { 362 if (((android.security.KeyStoreException) t).getErrorCode() 363 == ErrorCode.CANNOT_ATTEST_IDS) { 364 return KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS; 365 } 366 } 367 Log.e(TAG, "KeyStore error.", e); 368 return KeyChain.KEY_GEN_FAILURE; 369 } 370 } 371 372 @Override public boolean setKeyPairCertificate(String alias, byte[] userCertificate, 373 byte[] userCertificateChain) { 374 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 375 376 final PrivateKey privateKey; 377 try { 378 final Key key = mKeyStore.getKey(alias, null); 379 if (! (key instanceof PrivateKey)) { 380 return false; 381 } 382 privateKey = (PrivateKey) key; 383 } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) { 384 Log.e(TAG, "Failed to get private key entry.", e); 385 return false; 386 } 387 388 final ArrayList<Certificate> certs = new ArrayList<>(); 389 try { 390 if (userCertificate != null) { 391 certs.add(parseCertificate(userCertificate)); 392 } 393 if (userCertificateChain != null) { 394 certs.addAll(parseCertificates(userCertificateChain)); 395 } 396 } catch (CertificateException e) { 397 Log.e(TAG, "Failed to parse user certificate.", e); 398 return false; 399 } 400 401 final Certificate[] certsArray = certs.toArray(new Certificate[0]); 402 403 try { 404 // setKeyEntry with a private key loaded from AndroidKeyStore replaces 405 // the certificate components without touching the private key if 406 // the alias is the same as that of the private key. 407 mKeyStore.setKeyEntry(alias, privateKey, null, certsArray); 408 } catch (KeyStoreException e) { 409 Log.e(TAG, "Failed update key certificates.", e); 410 return false; 411 } 412 413 if (Log.isLoggable(TAG, Log.DEBUG)) { 414 Log.d(TAG, String.format("Set certificate for key alias %s : user %s CA chain: %s", 415 alias, emptyOrBase64Encoded(userCertificate), 416 emptyOrBase64Encoded(userCertificateChain))); 417 } 418 broadcastKeychainChange(); 419 broadcastLegacyStorageChange(); 420 return true; 421 } 422 423 private void validateAlias(String alias) { 424 if (alias == null) { 425 throw new NullPointerException("alias == null"); 426 } 427 } 428 429 private boolean hasGrant(String alias, CallerIdentity caller) { 430 return hasGrant(alias, caller.mUid); 431 } 432 433 private boolean hasGrant(String alias, int targetUid) { 434 validateAlias(alias); 435 436 if (!mGrantsDb.hasGrant(targetUid, alias)) { 437 Log.w(TAG, String.format( 438 "uid %d doesn't have permission to access the requested alias %s", 439 targetUid, alias)); 440 return false; 441 } 442 443 return true; 444 } 445 446 @Override public String installCaCertificate(byte[] caCertificate) { 447 final CallerIdentity caller = getCaller(); 448 Preconditions.checkCallAuthorization(isSystemUid(caller) || isCertInstaller(caller), 449 MSG_NOT_SYSTEM_OR_CERT_INSTALLER); 450 final String alias; 451 String subject = null; 452 final boolean isSecurityLoggingEnabled = mInjector.isSecurityLoggingEnabled(); 453 final X509Certificate cert; 454 try { 455 cert = parseCertificate(caCertificate); 456 457 final boolean isDebugLoggable = Log.isLoggable(TAG, Log.DEBUG); 458 subject = cert.getSubjectX500Principal().getName(X500Principal.CANONICAL); 459 if (isDebugLoggable) { 460 Log.d(TAG, String.format("Installing CA certificate: %s", subject)); 461 } 462 463 synchronized (mTrustedCertificateStore) { 464 mTrustedCertificateStore.installCertificate(cert); 465 alias = mTrustedCertificateStore.getCertificateAlias(cert); 466 } 467 } catch (IOException | CertificateException e) { 468 Log.w(TAG, "Failed installing CA certificate", e); 469 if (isSecurityLoggingEnabled && subject != null) { 470 mInjector.writeSecurityEvent( 471 TAG_CERT_AUTHORITY_INSTALLED, 0 /*result*/, subject, 472 UserHandle.myUserId()); 473 } 474 throw new IllegalStateException(e); 475 } 476 if (isSecurityLoggingEnabled && subject != null) { 477 mInjector.writeSecurityEvent( 478 TAG_CERT_AUTHORITY_INSTALLED, 1 /*result*/, subject, 479 UserHandle.myUserId()); 480 } 481 482 // If the caller is the cert installer, install the CA certificate into KeyStore. 483 // This is a temporary solution to enable CA certificates to be used as VPN trust 484 // anchors. Ultimately, the user should explicitly choose to install the VPN trust 485 // anchor separately and independently of CA certificates, at which point this code 486 // should be removed. 487 if (CERT_INSTALLER_PACKAGE.equals(caller.mPackageName)) { 488 try { 489 mKeyStore.setCertificateEntry(String.format("%s %s", subject, alias), cert); 490 } catch(KeyStoreException e) { 491 Log.e(TAG, String.format( 492 "Attempted installing %s (subject: %s) to KeyStore. Failed", alias, 493 subject), e); 494 } 495 } 496 497 broadcastLegacyStorageChange(); 498 broadcastTrustStoreChange(); 499 return alias; 500 } 501 502 /** 503 * Install a key pair to the keystore. 504 * 505 * @param privateKey The private key associated with the client certificate 506 * @param userCertificate The client certificate to be installed 507 * @param userCertificateChain The rest of the chain for the client certificate 508 * @param alias The alias under which the key pair is installed. It is invalid to pass 509 * {@code KeyChain.KEY_ALIAS_SELECTION_DENIED}. 510 * @param uid Can be only one of two values: Either 511 * {@code android.security.KeyStore.UID_SELF} to indicate installation into the 512 * current user's system Keystore instance, or {@code Process.WIFI_UID} to 513 * indicate installation into the main user's WiFi Keystore instance. It is only 514 * valid to pass {@code Process.WIFI_UID} to the KeyChain service on user 0. 515 * @return Whether the operation succeeded or not. 516 */ 517 @Override public boolean installKeyPair(@Nullable byte[] privateKey, 518 @Nullable byte[] userCertificate, @Nullable byte[] userCertificateChain, 519 String alias, int uid) { 520 final CallerIdentity caller = getCaller(); 521 Preconditions.checkCallAuthorization(isSystemUid(caller) || isCertInstaller(caller), 522 MSG_NOT_SYSTEM_OR_CERT_INSTALLER); 523 if (KeyChain.KEY_ALIAS_SELECTION_DENIED.equals(alias)) { 524 throw new IllegalArgumentException("The alias specified for the key denotes " 525 + "a reserved value and cannot be used to name a key"); 526 } 527 if (!ALLOWED_UIDS.contains(uid)) { 528 Log.e(TAG, 529 String.format("Installing alias %s as UID %d is now allowed.", alias, uid)); 530 return false; 531 } 532 533 if (privateKey == null && userCertificate == null && userCertificateChain == null) { 534 Log.e(TAG, String.format("Nothing to install for alias %s", alias)); 535 return false; 536 } 537 538 if (uid == Process.WIFI_UID && UserHandle.myUserId() != UserHandle.USER_SYSTEM) { 539 Log.e(TAG, String.format( 540 "Installation into the WiFi Keystore should be called from the primary " 541 + "user, not user %d", 542 UserHandle.myUserId())); 543 return false; 544 } 545 546 if (Log.isLoggable(TAG, Log.DEBUG)) { 547 Log.d(TAG, String.format("Installing certificate and key to alias %s to uid %d: " 548 + "user cert %s CA chain: %s", alias, uid, 549 emptyOrBase64Encoded(userCertificate), 550 emptyOrBase64Encoded(userCertificateChain))); 551 } 552 553 final ArrayList<Certificate> certs = new ArrayList<>(); 554 try { 555 if (userCertificate != null) { 556 certs.add(parseCertificate(userCertificate)); 557 } 558 if (userCertificateChain != null) { 559 certs.addAll(parseCertificates(userCertificateChain)); 560 } 561 } catch (CertificateException e) { 562 Log.e(TAG, "Failed to parse user certificate.", e); 563 return false; 564 } 565 566 if (certs.isEmpty()) { 567 Log.e(TAG, "Cannot install private key without public certificate."); 568 return false; 569 } 570 571 final Certificate[] certificates = certs.toArray(new Certificate[0]); 572 573 final PrivateKey privateKey1; 574 try { 575 if (privateKey != null) { 576 final KeyFactory keyFactory = 577 KeyFactory.getInstance(certificates[0].getPublicKey().getAlgorithm()); 578 privateKey1 = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey)); 579 } else { 580 privateKey1 = null; 581 } 582 } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { 583 Log.e(TAG, "Failed to parse private key.", e); 584 return false; 585 } 586 587 KeyStore keystore = getKeyStore(uid == Process.WIFI_UID); 588 if (keystore == null) { 589 return false; 590 } 591 592 try { 593 if (privateKey != null) { 594 keystore.setKeyEntry(alias, privateKey1, null, certificates); 595 } else { 596 if (certificates.length > 1) { 597 Log.e(TAG, 598 "Cannot install key certificate chain without private key."); 599 return false; 600 } 601 keystore.setCertificateEntry(alias, certificates[0]); 602 } 603 } catch (KeyStoreException e) { 604 Log.e(TAG, "Failed to install key pair.", e); 605 } 606 607 broadcastKeychainChange(); 608 broadcastLegacyStorageChange(); 609 return true; 610 } 611 612 @Override public boolean removeKeyPair(String alias) { 613 final CallerIdentity caller = getCaller(); 614 Preconditions.checkCallAuthorization(isSystemUid(caller) || isCertInstaller(caller), 615 MSG_NOT_SYSTEM_OR_CERT_INSTALLER); 616 return removeKeyPairInternal(alias); 617 } 618 619 private boolean removeKeyPairInternal(String alias) { 620 try { 621 mKeyStore.deleteEntry(alias); 622 } catch (KeyStoreException e) { 623 Log.e(TAG, String.format( 624 "Failed not remove keystore entry with alias %s", alias)); 625 return false; 626 } 627 Log.w(TAG, String.format( 628 "WARNING: Removing alias %s, existing grants will be revoked.", alias)); 629 mGrantsDb.removeAliasInformation(alias); 630 broadcastKeychainChange(); 631 broadcastLegacyStorageChange(); 632 return true; 633 } 634 635 @Override public boolean containsKeyPair(String alias) { 636 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 637 try { 638 final Key key = mKeyStore.getKey(alias, null); 639 return key instanceof PrivateKey; 640 } catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException e) { 641 Log.w("Error while trying to check for key presence.", e); 642 return false; 643 } 644 } 645 646 private X509Certificate parseCertificate(byte[] bytes) throws CertificateException { 647 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 648 return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(bytes)); 649 } 650 private Collection<X509Certificate> parseCertificates(byte[] bytes) 651 throws CertificateException { 652 final CertificateFactory cf = CertificateFactory.getInstance("X.509"); 653 return (Collection<X509Certificate>) 654 cf.generateCertificates(new ByteArrayInputStream(bytes)); 655 } 656 657 @Override public boolean reset() { 658 // only Settings should be able to reset 659 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 660 mGrantsDb.removeAllAliasesInformation(); 661 boolean ok = true; 662 synchronized (mTrustedCertificateStore) { 663 // delete user-installed CA certs 664 for (String alias : mTrustedCertificateStore.aliases()) { 665 if (TrustedCertificateStore.isUser(alias)) { 666 if (!deleteCertificateEntry(alias)) { 667 ok = false; 668 } 669 } 670 } 671 } 672 broadcastTrustStoreChange(); 673 broadcastKeychainChange(); 674 broadcastLegacyStorageChange(); 675 return ok; 676 } 677 678 @Override public boolean deleteCaCertificate(String alias) { 679 // only Settings should be able to delete 680 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 681 boolean ok = true; 682 Log.i(TAG, String.format("Deleting CA certificate %s", alias)); 683 synchronized (mTrustedCertificateStore) { 684 ok = deleteCertificateEntry(alias); 685 } 686 broadcastTrustStoreChange(); 687 broadcastLegacyStorageChange(); 688 return ok; 689 } 690 691 private boolean deleteCertificateEntry(String alias) { 692 String subjectForAudit = null; 693 if (mInjector.isSecurityLoggingEnabled()) { 694 final Certificate cert = mTrustedCertificateStore.getCertificate(alias); 695 if (cert instanceof X509Certificate) { 696 subjectForAudit = ((X509Certificate) cert) 697 .getSubjectX500Principal().getName(X500Principal.CANONICAL); 698 } 699 } 700 701 try { 702 mTrustedCertificateStore.deleteCertificateEntry(alias); 703 if (subjectForAudit != null) { 704 mInjector.writeSecurityEvent( 705 TAG_CERT_AUTHORITY_REMOVED, 1 /*result*/, subjectForAudit, 706 UserHandle.myUserId()); 707 } 708 return true; 709 } catch (IOException | CertificateException e) { 710 Log.w(TAG, "Problem removing CA certificate " + alias, e); 711 if (subjectForAudit != null) { 712 mInjector.writeSecurityEvent( 713 TAG_CERT_AUTHORITY_REMOVED, 0 /*result*/, subjectForAudit, 714 UserHandle.myUserId()); 715 } 716 return false; 717 } 718 } 719 720 private boolean hasManageCredentialManagementAppPermission(CallerIdentity caller) { 721 return mContext.checkPermission(Manifest.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP, 722 caller.mPid, caller.mUid) == PackageManager.PERMISSION_GRANTED; 723 } 724 725 private boolean isCertInstaller(CallerIdentity caller) { 726 return caller.mPackageName != null 727 && CERT_INSTALLER_PACKAGE.equals(caller.mPackageName); 728 } 729 730 private boolean isCredentialManagementApp(CallerIdentity caller) { 731 synchronized (mCredentialManagementAppLock) { 732 return mCredentialManagementApp != null && caller.mPackageName != null 733 && caller.mPackageName.equals(mCredentialManagementApp.getPackageName()); 734 } 735 } 736 737 private boolean isSystemUid(CallerIdentity caller) { 738 return UserHandle.isSameApp(caller.mUid, Process.SYSTEM_UID); 739 } 740 741 @Override public boolean hasGrant(int uid, String alias) { 742 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 743 return mGrantsDb.hasGrant(uid, alias); 744 } 745 746 @Override public boolean setGrant(int uid, String alias, boolean granted) { 747 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 748 mGrantsDb.setGrant(uid, alias, granted); 749 if (!granted) { 750 try { 751 KeyStore2.getInstance().ungrant(makeKeyDescriptor(alias), uid); 752 } catch (android.security.KeyStoreException e) { 753 Log.e(TAG, "Failed to ungrant " + alias + " to uid: " + uid, e); 754 return false; 755 } 756 } 757 broadcastPermissionChange(uid, alias, granted); 758 broadcastLegacyStorageChange(); 759 return true; 760 } 761 762 @Override public int[] getGrants(String alias) { 763 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 764 try { 765 if (mKeyStore.isKeyEntry(alias)) { 766 return mGrantsDb.getGrants(alias); 767 } 768 } catch (KeyStoreException e) { 769 Log.w(TAG, "Error while checking if key exists.", e); 770 } 771 throw new IllegalArgumentException("Alias not found: " + alias); 772 } 773 774 @Override 775 public StringParceledListSlice getUserCaAliases() { 776 synchronized (mTrustedCertificateStore) { 777 return new StringParceledListSlice(new ArrayList<String>( 778 mTrustedCertificateStore.userAliases())); 779 } 780 } 781 782 @Override 783 public StringParceledListSlice getSystemCaAliases() { 784 synchronized (mTrustedCertificateStore) { 785 return new StringParceledListSlice(new ArrayList<String>( 786 mTrustedCertificateStore.allSystemAliases())); 787 } 788 } 789 790 @Override 791 public boolean containsCaAlias(String alias) { 792 return mTrustedCertificateStore.containsAlias(alias); 793 } 794 795 @Override 796 public byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem) { 797 synchronized (mTrustedCertificateStore) { 798 X509Certificate certificate = (X509Certificate) mTrustedCertificateStore 799 .getCertificate(alias, includeDeletedSystem); 800 if (certificate == null) { 801 Log.w(TAG, "Could not find CA certificate " + alias); 802 return null; 803 } 804 try { 805 return certificate.getEncoded(); 806 } catch (CertificateEncodingException e) { 807 Log.w(TAG, "Error while encoding CA certificate " + alias); 808 return null; 809 } 810 } 811 } 812 813 @Override 814 public List<String> getCaCertificateChainAliases(String rootAlias, 815 boolean includeDeletedSystem) { 816 synchronized (mTrustedCertificateStore) { 817 X509Certificate root = (X509Certificate) mTrustedCertificateStore.getCertificate( 818 rootAlias, includeDeletedSystem); 819 try { 820 List<X509Certificate> chain = mTrustedCertificateStore.getCertificateChain( 821 root); 822 List<String> aliases = new ArrayList<String>(chain.size()); 823 final int n = chain.size(); 824 for (int i = 0; i < n; ++i) { 825 String alias = mTrustedCertificateStore.getCertificateAlias(chain.get(i), 826 true); 827 if (alias != null) { 828 aliases.add(alias); 829 } 830 } 831 return aliases; 832 } catch (CertificateException e) { 833 Log.w(TAG, "Error retrieving cert chain for root " + rootAlias); 834 return Collections.emptyList(); 835 } 836 } 837 } 838 839 @Override 840 public void setCredentialManagementApp(@NonNull String packageName, 841 @NonNull AppUriAuthenticationPolicy authenticationPolicy) { 842 final CallerIdentity caller = getCaller(); 843 Preconditions.checkCallAuthorization(isSystemUid(caller) 844 || hasManageCredentialManagementAppPermission(caller), MSG_NOT_SYSTEM); 845 checkValidAuthenticationPolicy(authenticationPolicy); 846 847 synchronized (mCredentialManagementAppLock) { 848 if (mCredentialManagementApp != null) { 849 final String existingPackage = mCredentialManagementApp.getPackageName(); 850 if (existingPackage.equals(packageName)) { 851 // Update existing credential management app's policy 852 removeOrphanedKeyPairs(authenticationPolicy); 853 } else { 854 // Replace existing credential management app 855 removeOrphanedKeyPairs(null); 856 setManageCredentialsAppOps(existingPackage, false); 857 } 858 } 859 setManageCredentialsAppOps(packageName, true); 860 mCredentialManagementApp = new CredentialManagementApp(packageName, 861 authenticationPolicy); 862 mStateStorage.saveCredentialManagementApp(mCredentialManagementApp); 863 } 864 } 865 866 private void setManageCredentialsAppOps(String packageName, boolean allowed) { 867 try { 868 int mode = allowed ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_DEFAULT; 869 ApplicationInfo appInfo = getPackageManager().getApplicationInfo(packageName, 0); 870 getSystemService(AppOpsManager.class).setMode(AppOpsManager.OP_MANAGE_CREDENTIALS, 871 appInfo.uid, packageName, mode); 872 } catch (PackageManager.NameNotFoundException e) { 873 Log.e(TAG, "Unable to find info for package: " + packageName); 874 } 875 } 876 877 private void removeOrphanedKeyPairs( 878 @Nullable AppUriAuthenticationPolicy newPolicy) { 879 Set<String> existingAliases = mCredentialManagementApp.getAuthenticationPolicy() 880 .getAliases(); 881 Set<String> newAliases = newPolicy != null ? newPolicy.getAliases() : new HashSet<>(); 882 883 // Uninstall all certificates that are no longer included in the new 884 // authentication policy 885 for (String existingAlias : existingAliases) { 886 if (!newAliases.contains(existingAlias)) { 887 removeKeyPairInternal(existingAlias); 888 } 889 } 890 } 891 892 private void checkValidAuthenticationPolicy( 893 @NonNull AppUriAuthenticationPolicy authenticationPolicy) { 894 if (authenticationPolicy == null 895 || authenticationPolicy.getAppAndUriMappings().isEmpty()) { 896 throw new IllegalArgumentException("The authentication policy is null or empty"); 897 } 898 // Check whether any of the aliases in the policy already exist 899 for (String alias : authenticationPolicy.getAliases()) { 900 if (requestPrivateKey(alias) != null) { 901 throw new IllegalArgumentException(String.format("The authentication policy " 902 + "contains an installed alias: %s", alias)); 903 } 904 } 905 } 906 907 @Override 908 public boolean hasCredentialManagementApp() { 909 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 910 synchronized (mCredentialManagementAppLock) { 911 return mCredentialManagementApp != null; 912 } 913 } 914 915 @Nullable 916 @Override 917 public String getCredentialManagementAppPackageName() { 918 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 919 synchronized (mCredentialManagementAppLock) { 920 return mCredentialManagementApp != null 921 ? mCredentialManagementApp.getPackageName() 922 : null; 923 } 924 } 925 926 @Nullable 927 @Override 928 public AppUriAuthenticationPolicy getCredentialManagementAppPolicy() { 929 final CallerIdentity caller = getCaller(); 930 Preconditions.checkCallAuthorization(isSystemUid(caller) 931 || isCredentialManagementApp(caller), MSG_NOT_SYSTEM_OR_CRED_MNG_APP); 932 synchronized (mCredentialManagementAppLock) { 933 return mCredentialManagementApp != null 934 ? mCredentialManagementApp.getAuthenticationPolicy() 935 : null; 936 } 937 } 938 939 @Nullable 940 @Override 941 public String getPredefinedAliasForPackageAndUri(@NonNull String packageName, 942 @Nullable Uri uri) { 943 Preconditions.checkCallAuthorization(isSystemUid(getCaller()), MSG_NOT_SYSTEM); 944 synchronized (mCredentialManagementAppLock) { 945 if (mCredentialManagementApp == null || uri == null) { 946 return null; 947 } 948 Map<Uri, String> urisToAliases = mCredentialManagementApp.getAuthenticationPolicy() 949 .getAppAndUriMappings().get(packageName); 950 return urisToAliases != null ? urisToAliases.get(uri) : null; 951 } 952 } 953 954 @Override 955 public void removeCredentialManagementApp() { 956 final CallerIdentity caller = getCaller(); 957 Preconditions.checkCallAuthorization(isSystemUid(caller) 958 || isCredentialManagementApp(caller) 959 || hasManageCredentialManagementAppPermission(caller), 960 MSG_NOT_SYSTEM_OR_CRED_MNG_APP); 961 synchronized (mCredentialManagementAppLock) { 962 if (mCredentialManagementApp != null) { 963 // Remove all certificates 964 removeOrphanedKeyPairs(null); 965 setManageCredentialsAppOps(mCredentialManagementApp.getPackageName(), false); 966 } 967 mCredentialManagementApp = null; 968 mStateStorage.saveCredentialManagementApp(mCredentialManagementApp); 969 } 970 } 971 972 @Override 973 public boolean isCredentialManagementApp(@NonNull String packageName) { 974 final CallerIdentity caller = getCaller(); 975 Preconditions.checkCallAuthorization(isSystemUid(caller) 976 || isCredentialManagementApp(caller), MSG_NOT_SYSTEM_OR_CRED_MNG_APP); 977 synchronized (mCredentialManagementAppLock) { 978 return packageName.equals(mCredentialManagementApp.getPackageName()); 979 } 980 } 981 }; 982 onBind(Intent intent)983 @Override public IBinder onBind(Intent intent) { 984 if (IKeyChainService.class.getName().equals(intent.getAction())) { 985 return mIKeyChainService; 986 } 987 return null; 988 } 989 990 @Override onHandleIntent(final Intent intent)991 protected void onHandleIntent(final Intent intent) { 992 if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) { 993 mGrantsDb.purgeOldGrants(getPackageManager()); 994 } 995 } 996 broadcastLegacyStorageChange()997 private void broadcastLegacyStorageChange() { 998 Intent intent = new Intent(KeyChain.ACTION_STORAGE_CHANGED); 999 BroadcastOptions opts = BroadcastOptions.makeBasic(); 1000 opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.N_MR1); 1001 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()), null, opts.toBundle()); 1002 } 1003 broadcastKeychainChange()1004 private void broadcastKeychainChange() { 1005 Intent intent = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED); 1006 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId())); 1007 } 1008 broadcastTrustStoreChange()1009 private void broadcastTrustStoreChange() { 1010 Intent intent = new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED); 1011 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId())); 1012 } 1013 broadcastPermissionChange(int uid, String alias, boolean access)1014 private void broadcastPermissionChange(int uid, String alias, boolean access) { 1015 // Since the permission change only impacts one uid only send to that uid's packages. 1016 final PackageManager packageManager = getPackageManager(); 1017 String[] packages = packageManager.getPackagesForUid(uid); 1018 if (packages == null) { 1019 return; 1020 } 1021 for (String pckg : packages) { 1022 Intent intent = new Intent(KeyChain.ACTION_KEY_ACCESS_CHANGED); 1023 intent.putExtra(KeyChain.EXTRA_KEY_ALIAS, alias); 1024 intent.putExtra(KeyChain.EXTRA_KEY_ACCESSIBLE, access); 1025 intent.setPackage(pckg); 1026 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId())); 1027 } 1028 } 1029 emptyOrBase64Encoded(byte[] cert)1030 private static String emptyOrBase64Encoded(byte[] cert) { 1031 if (cert == null) { 1032 return ""; 1033 } 1034 return Base64.encodeToString(cert, Base64.NO_WRAP); 1035 } 1036 1037 private final class CallerIdentity { 1038 1039 final int mUid; 1040 final int mPid; 1041 final String mPackageName; 1042 CallerIdentity()1043 CallerIdentity() { 1044 mUid = mInjector.getCallingUid(); 1045 mPid = Binder.getCallingPid(); 1046 mPackageName = getPackageManager().getNameForUid(mUid); 1047 } 1048 } 1049 getCaller()1050 private CallerIdentity getCaller() { 1051 return new CallerIdentity(); 1052 } 1053 1054 @VisibleForTesting setInjector(Injector injector)1055 void setInjector(Injector injector) { 1056 mInjector = injector; 1057 } 1058 1059 /** 1060 * Injector for mocking out dependencies in tests. 1061 */ 1062 @VisibleForTesting 1063 static class Injector { isSecurityLoggingEnabled()1064 public boolean isSecurityLoggingEnabled() { 1065 return SecurityLog.isLoggingEnabled(); 1066 } 1067 writeSecurityEvent(int tag, Object... payload)1068 public void writeSecurityEvent(int tag, Object... payload) { 1069 SecurityLog.writeEvent(tag, payload); 1070 } 1071 getCallingUid()1072 public int getCallingUid() { 1073 return Binder.getCallingUid(); 1074 } 1075 getKeyStoreInstance()1076 public KeyStore getKeyStoreInstance() throws KeyStoreException { 1077 return KeyStore.getInstance("AndroidKeyStore"); 1078 } 1079 } 1080 } 1081