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 22 import android.annotation.Nullable; 23 import android.app.BroadcastOptions; 24 import android.app.IntentService; 25 import android.app.admin.SecurityLog; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.pm.PackageManager; 29 import android.content.pm.StringParceledListSlice; 30 import android.os.Binder; 31 import android.os.Build; 32 import android.os.IBinder; 33 import android.os.Process; 34 import android.os.UserHandle; 35 import android.security.Credentials; 36 import android.security.IKeyChainService; 37 import android.security.KeyChain; 38 import android.security.KeyStore; 39 import android.security.keymaster.KeymasterArguments; 40 import android.security.keymaster.KeymasterCertificateChain; 41 import android.security.keystore.AttestationUtils; 42 import android.security.keystore.DeviceIdAttestationException; 43 import android.security.keystore.KeyGenParameterSpec; 44 import android.security.keystore.ParcelableKeyGenParameterSpec; 45 import android.security.keystore.StrongBoxUnavailableException; 46 import android.text.TextUtils; 47 import android.util.Base64; 48 import android.util.Log; 49 50 import com.android.internal.annotations.VisibleForTesting; 51 import com.android.internal.widget.LockPatternUtils; 52 import com.android.keychain.internal.ExistingKeysProvider; 53 import com.android.keychain.internal.GrantsDatabase; 54 import com.android.org.conscrypt.TrustedCertificateStore; 55 56 import java.io.ByteArrayInputStream; 57 import java.io.IOException; 58 import java.security.InvalidAlgorithmParameterException; 59 import java.security.KeyPair; 60 import java.security.KeyPairGenerator; 61 import java.security.NoSuchAlgorithmException; 62 import java.security.NoSuchProviderException; 63 import java.security.cert.Certificate; 64 import java.security.cert.CertificateEncodingException; 65 import java.security.cert.CertificateException; 66 import java.security.cert.CertificateFactory; 67 import java.security.cert.X509Certificate; 68 import java.util.ArrayList; 69 import java.util.Arrays; 70 import java.util.Collections; 71 import java.util.HashSet; 72 import java.util.List; 73 import java.util.Set; 74 75 import javax.security.auth.x500.X500Principal; 76 77 public class KeyChainService extends IntentService { 78 79 private static final String TAG = "KeyChain"; 80 private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller"; 81 private final Set<Integer> ALLOWED_UIDS = Collections.unmodifiableSet( 82 new HashSet(Arrays.asList(KeyStore.UID_SELF, Process.WIFI_UID))); 83 84 /** created in onCreate(), closed in onDestroy() */ 85 private GrantsDatabase mGrantsDb; 86 private Injector mInjector; 87 private final KeyStore mKeyStore = KeyStore.getInstance(); 88 KeyChainService()89 public KeyChainService() { 90 super(KeyChainService.class.getSimpleName()); 91 mInjector = new Injector(); 92 } 93 onCreate()94 @Override public void onCreate() { 95 super.onCreate(); 96 mGrantsDb = new GrantsDatabase(this, new KeyStoreAliasesProvider(mKeyStore)); 97 } 98 99 @Override onDestroy()100 public void onDestroy() { 101 super.onDestroy(); 102 mGrantsDb.destroy(); 103 mGrantsDb = null; 104 } 105 106 private static class KeyStoreAliasesProvider implements ExistingKeysProvider { 107 private final KeyStore mKeyStore; 108 KeyStoreAliasesProvider(KeyStore keyStore)109 KeyStoreAliasesProvider(KeyStore keyStore) { 110 mKeyStore = keyStore; 111 } 112 113 @Override getExistingKeyAliases()114 public List<String> getExistingKeyAliases() { 115 List<String> aliases = new ArrayList<String>(); 116 String[] keyStoreAliases = mKeyStore.list(Credentials.USER_PRIVATE_KEY); 117 if (keyStoreAliases == null) { 118 return aliases; 119 } 120 121 for (String alias: keyStoreAliases) { 122 Log.w(TAG, "Got Alias from KeyStore: " + alias); 123 String unPrefixedAlias = alias.replaceFirst("^" + Credentials.USER_PRIVATE_KEY, ""); 124 if (!unPrefixedAlias.startsWith(LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX)) { 125 aliases.add(unPrefixedAlias); 126 } 127 } 128 return aliases; 129 } 130 } 131 132 private final IKeyChainService.Stub mIKeyChainService = new IKeyChainService.Stub() { 133 private final TrustedCertificateStore mTrustedCertificateStore 134 = new TrustedCertificateStore(); 135 private final Context mContext = KeyChainService.this; 136 137 @Override 138 public String requestPrivateKey(String alias) { 139 if (!hasGrant(alias)) { 140 return null; 141 } 142 143 final String keystoreAlias = Credentials.USER_PRIVATE_KEY + alias; 144 final int uid = mInjector.getCallingUid(); 145 Log.i(TAG, String.format("UID %d will be granted access to %s", uid, keystoreAlias)); 146 return mKeyStore.grant(keystoreAlias, uid); 147 } 148 149 @Override public byte[] getCertificate(String alias) { 150 if (!hasGrant(alias)) { 151 return null; 152 } 153 return mKeyStore.get(Credentials.USER_CERTIFICATE + alias); 154 } 155 156 @Override public byte[] getCaCertificates(String alias) { 157 if (!hasGrant(alias)) { 158 return null; 159 } 160 return mKeyStore.get(Credentials.CA_CERTIFICATE + alias); 161 } 162 163 @Override public boolean isUserSelectable(String alias) { 164 validateAlias(alias); 165 return mGrantsDb.isUserSelectable(alias); 166 } 167 168 @Override public void setUserSelectable(String alias, boolean isUserSelectable) { 169 validateAlias(alias); 170 checkSystemCaller(); 171 Log.i(TAG, String.format("Marking certificate %s as user-selectable: %b", alias, 172 isUserSelectable)); 173 mGrantsDb.setIsUserSelectable(alias, isUserSelectable); 174 } 175 176 @Override public int generateKeyPair( 177 String algorithm, ParcelableKeyGenParameterSpec parcelableSpec) { 178 checkSystemCaller(); 179 final KeyGenParameterSpec spec = parcelableSpec.getSpec(); 180 final String alias = spec.getKeystoreAlias(); 181 182 Log.i(TAG, String.format("About to generate key with alias %s, algorithm %s", 183 alias, algorithm)); 184 185 if (KeyChain.KEY_ALIAS_SELECTION_DENIED.equals(alias)) { 186 throw new IllegalArgumentException("The alias specified for the key denotes " 187 + "a reserved value and cannot be used to name a key"); 188 } 189 // Validate the alias here to avoid relying on KeyGenParameterSpec c'tor preventing 190 // the creation of a KeyGenParameterSpec instance with a non-empty alias. 191 if (TextUtils.isEmpty(alias) || spec.getUid() != KeyStore.UID_SELF) { 192 Log.e(TAG, "Cannot generate key pair with empty alias or specified uid."); 193 return KeyChain.KEY_GEN_MISSING_ALIAS; 194 } 195 196 if (spec.getAttestationChallenge() != null) { 197 Log.e(TAG, "Key generation request should not include an Attestation challenge."); 198 return KeyChain.KEY_GEN_SUPERFLUOUS_ATTESTATION_CHALLENGE; 199 } 200 201 if (!removeKeyPair(alias)) { 202 Log.e(TAG, "Failed to remove previously-installed alias " + alias); 203 //TODO: Introduce a different error code in R to distinguish the failure to remove 204 // old keys from other failures. 205 return KeyChain.KEY_GEN_FAILURE; 206 } 207 208 try { 209 KeyPairGenerator generator = KeyPairGenerator.getInstance( 210 algorithm, "AndroidKeyStore"); 211 // Do not prepend USER_PRIVATE_KEY to the alias because 212 // AndroidKeyStoreKeyPairGeneratorSpi will helpfully prepend that in 213 // generateKeyPair. 214 generator.initialize(spec); 215 KeyPair kp = generator.generateKeyPair(); 216 if (kp == null) { 217 Log.e(TAG, "Key generation failed."); 218 return KeyChain.KEY_GEN_FAILURE; 219 } 220 return KeyChain.KEY_GEN_SUCCESS; 221 } catch (NoSuchAlgorithmException e) { 222 Log.e(TAG, "Invalid algorithm requested", e); 223 return KeyChain.KEY_GEN_NO_SUCH_ALGORITHM; 224 } catch (InvalidAlgorithmParameterException e) { 225 Log.e(TAG, "Invalid algorithm params", e); 226 return KeyChain.KEY_GEN_INVALID_ALGORITHM_PARAMETERS; 227 } catch (NoSuchProviderException e) { 228 Log.e(TAG, "Could not find Keystore.", e); 229 return KeyChain.KEY_GEN_NO_KEYSTORE_PROVIDER; 230 } catch (StrongBoxUnavailableException e) { 231 Log.e(TAG, "StrongBox unavailable.", e); 232 return KeyChain.KEY_GEN_STRONGBOX_UNAVAILABLE; 233 } 234 } 235 236 @Override public int attestKey( 237 String alias, byte[] attestationChallenge, 238 int[] idAttestationFlags, 239 KeymasterCertificateChain attestationChain) { 240 checkSystemCaller(); 241 validateAlias(alias); 242 243 if (attestationChallenge == null) { 244 Log.e(TAG, String.format("Missing attestation challenge for alias %s", alias)); 245 return KeyChain.KEY_ATTESTATION_MISSING_CHALLENGE; 246 } 247 248 if (Log.isLoggable(TAG, Log.DEBUG)) { 249 Log.d(TAG, String.format("About to attest key alias %s, challenge %s, flags %s", 250 alias, Base64.encodeToString(attestationChallenge, Base64.NO_WRAP), 251 Arrays.toString(idAttestationFlags))); 252 } 253 254 final KeymasterArguments attestArgs; 255 try { 256 attestArgs = AttestationUtils.prepareAttestationArguments( 257 mContext, idAttestationFlags, attestationChallenge); 258 } catch (DeviceIdAttestationException e) { 259 Log.e(TAG, "Failed collecting attestation data", e); 260 return KeyChain.KEY_ATTESTATION_CANNOT_COLLECT_DATA; 261 } 262 final String keystoreAlias = Credentials.USER_PRIVATE_KEY + alias; 263 final int errorCode = mKeyStore.attestKey(keystoreAlias, attestArgs, attestationChain); 264 if (errorCode != KeyStore.NO_ERROR) { 265 Log.e(TAG, String.format("Failure attesting for key %s: %d", alias, errorCode)); 266 if (errorCode == KeyStore.CANNOT_ATTEST_IDS) { 267 return KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS; 268 } else { 269 // General failure, cannot discern which. 270 return KeyChain.KEY_ATTESTATION_FAILURE; 271 } 272 } 273 274 return KeyChain.KEY_ATTESTATION_SUCCESS; 275 } 276 277 @Override public boolean setKeyPairCertificate(String alias, byte[] userCertificate, 278 byte[] userCertificateChain) { 279 checkSystemCaller(); 280 if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertificate, 281 KeyStore.UID_SELF, KeyStore.FLAG_NONE)) { 282 Log.e(TAG, "Failed to import user certificate " + userCertificate); 283 return false; 284 } 285 286 if (userCertificateChain != null && userCertificateChain.length > 0) { 287 if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, userCertificateChain, 288 KeyStore.UID_SELF, KeyStore.FLAG_NONE)) { 289 Log.e(TAG, "Failed to import certificate chain" + userCertificateChain); 290 if (!mKeyStore.delete(Credentials.USER_CERTIFICATE + alias)) { 291 Log.e(TAG, "Failed to clean up key chain after certificate chain" 292 + " importing failed"); 293 } 294 return false; 295 } 296 } else { 297 if (!mKeyStore.delete(Credentials.CA_CERTIFICATE + alias)) { 298 Log.e(TAG, "Failed to remove CA certificate chain for alias " + alias); 299 } 300 } 301 302 if (Log.isLoggable(TAG, Log.DEBUG)) { 303 Log.d(TAG, String.format("Set certificate for key alias %s : user %s CA chain: %s", 304 alias, emptyOrBase64Encoded(userCertificate), 305 emptyOrBase64Encoded(userCertificateChain))); 306 } 307 broadcastKeychainChange(); 308 broadcastLegacyStorageChange(); 309 return true; 310 } 311 312 private void validateAlias(String alias) { 313 if (alias == null) { 314 throw new NullPointerException("alias == null"); 315 } 316 } 317 318 private boolean hasGrant(String alias) { 319 validateAlias(alias); 320 321 final int callingUid = mInjector.getCallingUid(); 322 if (!mGrantsDb.hasGrant(callingUid, alias)) { 323 Log.w(TAG, String.format( 324 "uid %d doesn't have permission to access the requested alias %s", 325 callingUid, alias)); 326 return false; 327 } 328 329 return true; 330 } 331 332 @Override public String installCaCertificate(byte[] caCertificate) { 333 checkCertInstallerOrSystemCaller(); 334 final String alias; 335 String subjectForAudit = null; 336 try { 337 final X509Certificate cert = parseCertificate(caCertificate); 338 final boolean isSecurityLoggingEnabled = mInjector.isSecurityLoggingEnabled(); 339 final boolean isDebugLoggable = Log.isLoggable(TAG, Log.DEBUG); 340 if (isSecurityLoggingEnabled || isDebugLoggable) { 341 final String subject = 342 cert.getSubjectX500Principal().getName(X500Principal.CANONICAL); 343 if (isDebugLoggable) { 344 Log.d(TAG, String.format("Installing CA certificate: %s", subject)); 345 } 346 if (isSecurityLoggingEnabled) { 347 subjectForAudit = subject; 348 } 349 } 350 synchronized (mTrustedCertificateStore) { 351 mTrustedCertificateStore.installCertificate(cert); 352 alias = mTrustedCertificateStore.getCertificateAlias(cert); 353 } 354 } catch (IOException | CertificateException e) { 355 Log.w(TAG, "Failed installing CA certificate", e); 356 if (subjectForAudit != null) { 357 mInjector.writeSecurityEvent( 358 TAG_CERT_AUTHORITY_INSTALLED, 0 /*result*/, subjectForAudit, 359 UserHandle.myUserId()); 360 } 361 throw new IllegalStateException(e); 362 } 363 if (subjectForAudit != null) { 364 mInjector.writeSecurityEvent( 365 TAG_CERT_AUTHORITY_INSTALLED, 1 /*result*/, subjectForAudit, 366 UserHandle.myUserId()); 367 } 368 broadcastLegacyStorageChange(); 369 broadcastTrustStoreChange(); 370 return alias; 371 } 372 373 /** 374 * Install a key pair to the keystore. 375 * 376 * @param privateKey The private key associated with the client certificate 377 * @param userCertificate The client certificate to be installed 378 * @param userCertificateChain The rest of the chain for the client certificate 379 * @param alias The alias under which the key pair is installed. It is invalid to pass 380 * {@code KeyChain.KEY_ALIAS_SELECTION_DENIED}. 381 * @param uid Can be only one of two values: Either {@code KeyStore.UID_SELF} to indicate 382 * installation into the current user's system Keystore instance, or 383 * {@code Process.WIFI_UID} to indicate installation into the main user's 384 * WiFi Keystore instance. It is only valid to pass {@code Process.WIFI_UID} to 385 * the KeyChain service on user 0. 386 * @return Whether the operation succeeded or not. 387 */ 388 @Override public boolean installKeyPair(@Nullable byte[] privateKey, 389 @Nullable byte[] userCertificate, @Nullable byte[] userCertificateChain, 390 String alias, int uid) { 391 checkCertInstallerOrSystemCaller(); 392 if (KeyChain.KEY_ALIAS_SELECTION_DENIED.equals(alias)) { 393 throw new IllegalArgumentException("The alias specified for the key denotes " 394 + "a reserved value and cannot be used to name a key"); 395 } 396 if (!ALLOWED_UIDS.contains(uid)) { 397 Log.e(TAG, 398 String.format("Installing alias %s as UID %d is now allowed.", alias, uid)); 399 return false; 400 } 401 402 if (privateKey == null && userCertificate == null && userCertificateChain == null) { 403 Log.e(TAG, String.format("Nothing to install for alias %s", alias)); 404 return false; 405 } 406 407 if (uid == Process.WIFI_UID && UserHandle.myUserId() != UserHandle.USER_SYSTEM) { 408 Log.e(TAG, String.format( 409 "Installation into the WiFi Keystore should be called from the primary " 410 + "user, not user %d", 411 UserHandle.myUserId())); 412 return false; 413 } 414 415 if (Log.isLoggable(TAG, Log.DEBUG)) { 416 Log.d(TAG, String.format("Installing certificate and key to alias %s to uid %d: " 417 + "user cert %s CA chain: %s", alias, uid, 418 emptyOrBase64Encoded(userCertificate), 419 emptyOrBase64Encoded(userCertificateChain))); 420 } 421 422 if (!removeKeyPair(alias)) { 423 return false; 424 } 425 if (privateKey != null && !mKeyStore.importKey( 426 Credentials.USER_PRIVATE_KEY + alias, privateKey, uid, KeyStore.FLAG_NONE)) { 427 Log.e(TAG, "Failed to import private key " + alias); 428 return false; 429 } 430 if (userCertificate != null && 431 !mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertificate, 432 uid, KeyStore.FLAG_NONE)) { 433 Log.e(TAG, "Failed to import user certificate " + userCertificate); 434 if (!mKeyStore.delete(Credentials.USER_PRIVATE_KEY + alias)) { 435 Log.e(TAG, "Failed to delete private key after certificate importing failed"); 436 } 437 return false; 438 } 439 if (userCertificateChain != null && userCertificateChain.length > 0) { 440 if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, userCertificateChain, uid, 441 KeyStore.FLAG_NONE)) { 442 Log.e(TAG, "Failed to import certificate chain" + userCertificateChain); 443 if (!removeKeyPair(alias)) { 444 Log.e(TAG, "Failed to clean up key chain after certificate chain" 445 + " importing failed"); 446 } 447 return false; 448 } 449 } 450 broadcastKeychainChange(); 451 broadcastLegacyStorageChange(); 452 return true; 453 } 454 455 @Override public boolean removeKeyPair(String alias) { 456 checkCertInstallerOrSystemCaller(); 457 if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias)) { 458 return false; 459 } 460 Log.w(TAG, String.format( 461 "WARNING: Removing alias %s, existing grants will be revoked.", alias)); 462 mGrantsDb.removeAliasInformation(alias); 463 broadcastKeychainChange(); 464 broadcastLegacyStorageChange(); 465 return true; 466 } 467 468 private X509Certificate parseCertificate(byte[] bytes) throws CertificateException { 469 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 470 return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(bytes)); 471 } 472 473 @Override public boolean reset() { 474 // only Settings should be able to reset 475 checkSystemCaller(); 476 mGrantsDb.removeAllAliasesInformation(); 477 boolean ok = true; 478 synchronized (mTrustedCertificateStore) { 479 // delete user-installed CA certs 480 for (String alias : mTrustedCertificateStore.aliases()) { 481 if (TrustedCertificateStore.isUser(alias)) { 482 if (!deleteCertificateEntry(alias)) { 483 ok = false; 484 } 485 } 486 } 487 } 488 broadcastTrustStoreChange(); 489 broadcastKeychainChange(); 490 broadcastLegacyStorageChange(); 491 return ok; 492 } 493 494 @Override public boolean deleteCaCertificate(String alias) { 495 // only Settings should be able to delete 496 checkSystemCaller(); 497 boolean ok = true; 498 Log.i(TAG, String.format("Deleting CA certificate %s", alias)); 499 synchronized (mTrustedCertificateStore) { 500 ok = deleteCertificateEntry(alias); 501 } 502 broadcastTrustStoreChange(); 503 broadcastLegacyStorageChange(); 504 return ok; 505 } 506 507 private boolean deleteCertificateEntry(String alias) { 508 String subjectForAudit = null; 509 if (mInjector.isSecurityLoggingEnabled()) { 510 final Certificate cert = mTrustedCertificateStore.getCertificate(alias); 511 if (cert instanceof X509Certificate) { 512 subjectForAudit = ((X509Certificate) cert) 513 .getSubjectX500Principal().getName(X500Principal.CANONICAL); 514 } 515 } 516 517 try { 518 mTrustedCertificateStore.deleteCertificateEntry(alias); 519 if (subjectForAudit != null) { 520 mInjector.writeSecurityEvent( 521 TAG_CERT_AUTHORITY_REMOVED, 1 /*result*/, subjectForAudit, 522 UserHandle.myUserId()); 523 } 524 return true; 525 } catch (IOException | CertificateException e) { 526 Log.w(TAG, "Problem removing CA certificate " + alias, e); 527 if (subjectForAudit != null) { 528 mInjector.writeSecurityEvent( 529 TAG_CERT_AUTHORITY_REMOVED, 0 /*result*/, subjectForAudit, 530 UserHandle.myUserId()); 531 } 532 return false; 533 } 534 } 535 536 private void checkCertInstallerOrSystemCaller() { 537 final String caller = callingPackage(); 538 if (!isCallerWithSystemUid() && !CERT_INSTALLER_PACKAGE.equals(caller)) { 539 throw new SecurityException("Not system or cert installer package: " + caller); 540 } 541 } 542 543 private void checkSystemCaller() { 544 if (!isCallerWithSystemUid()) { 545 throw new SecurityException("Not system package: " + callingPackage()); 546 } 547 } 548 549 private boolean isCallerWithSystemUid() { 550 return UserHandle.isSameApp(mInjector.getCallingUid(), Process.SYSTEM_UID); 551 } 552 553 private String callingPackage() { 554 return getPackageManager().getNameForUid(mInjector.getCallingUid()); 555 } 556 557 @Override public boolean hasGrant(int uid, String alias) { 558 checkSystemCaller(); 559 return mGrantsDb.hasGrant(uid, alias); 560 } 561 562 @Override public void setGrant(int uid, String alias, boolean value) { 563 checkSystemCaller(); 564 mGrantsDb.setGrant(uid, alias, value); 565 broadcastPermissionChange(uid, alias, value); 566 broadcastLegacyStorageChange(); 567 } 568 569 @Override 570 public StringParceledListSlice getUserCaAliases() { 571 synchronized (mTrustedCertificateStore) { 572 return new StringParceledListSlice(new ArrayList<String>( 573 mTrustedCertificateStore.userAliases())); 574 } 575 } 576 577 @Override 578 public StringParceledListSlice getSystemCaAliases() { 579 synchronized (mTrustedCertificateStore) { 580 return new StringParceledListSlice(new ArrayList<String>( 581 mTrustedCertificateStore.allSystemAliases())); 582 } 583 } 584 585 @Override 586 public boolean containsCaAlias(String alias) { 587 return mTrustedCertificateStore.containsAlias(alias); 588 } 589 590 @Override 591 public byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem) { 592 synchronized (mTrustedCertificateStore) { 593 X509Certificate certificate = (X509Certificate) mTrustedCertificateStore 594 .getCertificate(alias, includeDeletedSystem); 595 if (certificate == null) { 596 Log.w(TAG, "Could not find CA certificate " + alias); 597 return null; 598 } 599 try { 600 return certificate.getEncoded(); 601 } catch (CertificateEncodingException e) { 602 Log.w(TAG, "Error while encoding CA certificate " + alias); 603 return null; 604 } 605 } 606 } 607 608 @Override 609 public List<String> getCaCertificateChainAliases(String rootAlias, 610 boolean includeDeletedSystem) { 611 synchronized (mTrustedCertificateStore) { 612 X509Certificate root = (X509Certificate) mTrustedCertificateStore.getCertificate( 613 rootAlias, includeDeletedSystem); 614 try { 615 List<X509Certificate> chain = mTrustedCertificateStore.getCertificateChain( 616 root); 617 List<String> aliases = new ArrayList<String>(chain.size()); 618 final int n = chain.size(); 619 for (int i = 0; i < n; ++i) { 620 String alias = mTrustedCertificateStore.getCertificateAlias(chain.get(i), 621 true); 622 if (alias != null) { 623 aliases.add(alias); 624 } 625 } 626 return aliases; 627 } catch (CertificateException e) { 628 Log.w(TAG, "Error retrieving cert chain for root " + rootAlias); 629 return Collections.emptyList(); 630 } 631 } 632 } 633 }; 634 onBind(Intent intent)635 @Override public IBinder onBind(Intent intent) { 636 if (IKeyChainService.class.getName().equals(intent.getAction())) { 637 return mIKeyChainService; 638 } 639 return null; 640 } 641 642 @Override onHandleIntent(final Intent intent)643 protected void onHandleIntent(final Intent intent) { 644 if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) { 645 mGrantsDb.purgeOldGrants(getPackageManager()); 646 } 647 } 648 broadcastLegacyStorageChange()649 private void broadcastLegacyStorageChange() { 650 Intent intent = new Intent(KeyChain.ACTION_STORAGE_CHANGED); 651 BroadcastOptions opts = BroadcastOptions.makeBasic(); 652 opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.N_MR1); 653 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()), null, opts.toBundle()); 654 } 655 broadcastKeychainChange()656 private void broadcastKeychainChange() { 657 Intent intent = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED); 658 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId())); 659 } 660 broadcastTrustStoreChange()661 private void broadcastTrustStoreChange() { 662 Intent intent = new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED); 663 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId())); 664 } 665 broadcastPermissionChange(int uid, String alias, boolean access)666 private void broadcastPermissionChange(int uid, String alias, boolean access) { 667 // Since the permission change only impacts one uid only send to that uid's packages. 668 final PackageManager packageManager = getPackageManager(); 669 String[] packages = packageManager.getPackagesForUid(uid); 670 if (packages == null) { 671 return; 672 } 673 for (String pckg : packages) { 674 Intent intent = new Intent(KeyChain.ACTION_KEY_ACCESS_CHANGED); 675 intent.putExtra(KeyChain.EXTRA_KEY_ALIAS, alias); 676 intent.putExtra(KeyChain.EXTRA_KEY_ACCESSIBLE, access); 677 intent.setPackage(pckg); 678 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId())); 679 } 680 } 681 emptyOrBase64Encoded(byte[] cert)682 private static String emptyOrBase64Encoded(byte[] cert) { 683 if (cert == null) { 684 return ""; 685 } 686 return Base64.encodeToString(cert, Base64.NO_WRAP); 687 } 688 689 @VisibleForTesting setInjector(Injector injector)690 void setInjector(Injector injector) { 691 mInjector = injector; 692 } 693 694 /** 695 * Injector for mocking out dependencies in tests. 696 */ 697 @VisibleForTesting 698 static class Injector { isSecurityLoggingEnabled()699 public boolean isSecurityLoggingEnabled() { 700 return SecurityLog.isLoggingEnabled(); 701 } 702 writeSecurityEvent(int tag, Object... payload)703 public void writeSecurityEvent(int tag, Object... payload) { 704 SecurityLog.writeEvent(tag, payload); 705 } 706 getCallingUid()707 public int getCallingUid() { 708 return Binder.getCallingUid(); 709 } 710 } 711 } 712