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 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 int errorCode = checkKeyChainStatus(alias, attestationChain, attestArgs); 263 if (errorCode == KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS) { 264 // b/69471841: id attestation might fail due to incorrect provisioning of device 265 try { 266 attestArgs = 267 AttestationUtils.prepareAttestationArgumentsIfMisprovisioned( 268 mContext, idAttestationFlags, attestationChallenge); 269 if (attestArgs == null) { 270 return errorCode; 271 } 272 } catch (DeviceIdAttestationException e) { 273 Log.e(TAG, "Failed collecting attestation data " 274 + "during second attempt on misprovisioned device", e); 275 return KeyChain.KEY_ATTESTATION_CANNOT_COLLECT_DATA; 276 } 277 } 278 279 return checkKeyChainStatus(alias, attestationChain, attestArgs); 280 } 281 282 private int checkKeyChainStatus( 283 String alias, 284 KeymasterCertificateChain attestationChain, 285 KeymasterArguments attestArgs) { 286 287 final String keystoreAlias = Credentials.USER_PRIVATE_KEY + alias; 288 final int errorCode = mKeyStore.attestKey(keystoreAlias, attestArgs, attestationChain); 289 if (errorCode != KeyStore.NO_ERROR) { 290 Log.e(TAG, String.format("Failure attesting for key %s: %d", alias, errorCode)); 291 if (errorCode == KeyStore.CANNOT_ATTEST_IDS) { 292 return KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS; 293 } else { 294 // General failure, cannot discern which. 295 return KeyChain.KEY_ATTESTATION_FAILURE; 296 } 297 } 298 299 return KeyChain.KEY_ATTESTATION_SUCCESS; 300 } 301 302 @Override public boolean setKeyPairCertificate(String alias, byte[] userCertificate, 303 byte[] userCertificateChain) { 304 checkSystemCaller(); 305 if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertificate, 306 KeyStore.UID_SELF, KeyStore.FLAG_NONE)) { 307 Log.e(TAG, "Failed to import user certificate " + userCertificate); 308 return false; 309 } 310 311 if (userCertificateChain != null && userCertificateChain.length > 0) { 312 if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, userCertificateChain, 313 KeyStore.UID_SELF, KeyStore.FLAG_NONE)) { 314 Log.e(TAG, "Failed to import certificate chain" + userCertificateChain); 315 if (!mKeyStore.delete(Credentials.USER_CERTIFICATE + alias)) { 316 Log.e(TAG, "Failed to clean up key chain after certificate chain" 317 + " importing failed"); 318 } 319 return false; 320 } 321 } else { 322 if (!mKeyStore.delete(Credentials.CA_CERTIFICATE + alias)) { 323 Log.e(TAG, "Failed to remove CA certificate chain for alias " + alias); 324 } 325 } 326 327 if (Log.isLoggable(TAG, Log.DEBUG)) { 328 Log.d(TAG, String.format("Set certificate for key alias %s : user %s CA chain: %s", 329 alias, emptyOrBase64Encoded(userCertificate), 330 emptyOrBase64Encoded(userCertificateChain))); 331 } 332 broadcastKeychainChange(); 333 broadcastLegacyStorageChange(); 334 return true; 335 } 336 337 private void validateAlias(String alias) { 338 if (alias == null) { 339 throw new NullPointerException("alias == null"); 340 } 341 } 342 343 private boolean hasGrant(String alias) { 344 validateAlias(alias); 345 346 final int callingUid = mInjector.getCallingUid(); 347 if (!mGrantsDb.hasGrant(callingUid, alias)) { 348 Log.w(TAG, String.format( 349 "uid %d doesn't have permission to access the requested alias %s", 350 callingUid, alias)); 351 return false; 352 } 353 354 return true; 355 } 356 357 @Override public String installCaCertificate(byte[] caCertificate) { 358 checkCertInstallerOrSystemCaller(); 359 final String alias; 360 String subject = null; 361 final boolean isSecurityLoggingEnabled = mInjector.isSecurityLoggingEnabled(); 362 try { 363 final X509Certificate cert = parseCertificate(caCertificate); 364 365 final boolean isDebugLoggable = Log.isLoggable(TAG, Log.DEBUG); 366 subject = cert.getSubjectX500Principal().getName(X500Principal.CANONICAL); 367 if (isDebugLoggable) { 368 Log.d(TAG, String.format("Installing CA certificate: %s", subject)); 369 } 370 371 synchronized (mTrustedCertificateStore) { 372 mTrustedCertificateStore.installCertificate(cert); 373 alias = mTrustedCertificateStore.getCertificateAlias(cert); 374 } 375 } catch (IOException | CertificateException e) { 376 Log.w(TAG, "Failed installing CA certificate", e); 377 if (isSecurityLoggingEnabled && subject != null) { 378 mInjector.writeSecurityEvent( 379 TAG_CERT_AUTHORITY_INSTALLED, 0 /*result*/, subject, 380 UserHandle.myUserId()); 381 } 382 throw new IllegalStateException(e); 383 } 384 if (isSecurityLoggingEnabled && subject != null) { 385 mInjector.writeSecurityEvent( 386 TAG_CERT_AUTHORITY_INSTALLED, 1 /*result*/, subject, 387 UserHandle.myUserId()); 388 } 389 390 // If the caller is the cert installer, install the CA certificate into KeyStore. 391 // This is a temporary solution to enable CA certificates to be used as VPN trust 392 // anchors. Ultimately, the user should explicitly choose to install the VPN trust 393 // anchor separately and independently of CA certificates, at which point this code 394 // should be removed. 395 if (CERT_INSTALLER_PACKAGE.equals(callingPackage())) { 396 final boolean result = mKeyStore.put( 397 String.format("%s%s %s", Credentials.CA_CERTIFICATE, subject, alias), 398 caCertificate, Process.SYSTEM_UID, 399 KeyStore.FLAG_NONE); 400 Log.d(TAG, String.format( 401 "Attempted installing %s (subject: %s) to KeyStore. Result: %b", alias, 402 subject, result)); 403 } 404 405 broadcastLegacyStorageChange(); 406 broadcastTrustStoreChange(); 407 return alias; 408 } 409 410 /** 411 * Install a key pair to the keystore. 412 * 413 * @param privateKey The private key associated with the client certificate 414 * @param userCertificate The client certificate to be installed 415 * @param userCertificateChain The rest of the chain for the client certificate 416 * @param alias The alias under which the key pair is installed. It is invalid to pass 417 * {@code KeyChain.KEY_ALIAS_SELECTION_DENIED}. 418 * @param uid Can be only one of two values: Either {@code KeyStore.UID_SELF} to indicate 419 * installation into the current user's system Keystore instance, or 420 * {@code Process.WIFI_UID} to indicate installation into the main user's 421 * WiFi Keystore instance. It is only valid to pass {@code Process.WIFI_UID} to 422 * the KeyChain service on user 0. 423 * @return Whether the operation succeeded or not. 424 */ 425 @Override public boolean installKeyPair(@Nullable byte[] privateKey, 426 @Nullable byte[] userCertificate, @Nullable byte[] userCertificateChain, 427 String alias, int uid) { 428 checkCertInstallerOrSystemCaller(); 429 if (KeyChain.KEY_ALIAS_SELECTION_DENIED.equals(alias)) { 430 throw new IllegalArgumentException("The alias specified for the key denotes " 431 + "a reserved value and cannot be used to name a key"); 432 } 433 if (!ALLOWED_UIDS.contains(uid)) { 434 Log.e(TAG, 435 String.format("Installing alias %s as UID %d is now allowed.", alias, uid)); 436 return false; 437 } 438 439 if (privateKey == null && userCertificate == null && userCertificateChain == null) { 440 Log.e(TAG, String.format("Nothing to install for alias %s", alias)); 441 return false; 442 } 443 444 if (uid == Process.WIFI_UID && UserHandle.myUserId() != UserHandle.USER_SYSTEM) { 445 Log.e(TAG, String.format( 446 "Installation into the WiFi Keystore should be called from the primary " 447 + "user, not user %d", 448 UserHandle.myUserId())); 449 return false; 450 } 451 452 if (Log.isLoggable(TAG, Log.DEBUG)) { 453 Log.d(TAG, String.format("Installing certificate and key to alias %s to uid %d: " 454 + "user cert %s CA chain: %s", alias, uid, 455 emptyOrBase64Encoded(userCertificate), 456 emptyOrBase64Encoded(userCertificateChain))); 457 } 458 459 if (!removeKeyPair(alias)) { 460 return false; 461 } 462 if (privateKey != null && !mKeyStore.importKey( 463 Credentials.USER_PRIVATE_KEY + alias, privateKey, uid, KeyStore.FLAG_NONE)) { 464 Log.e(TAG, "Failed to import private key " + alias); 465 return false; 466 } 467 if (userCertificate != null && 468 !mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertificate, 469 uid, KeyStore.FLAG_NONE)) { 470 Log.e(TAG, "Failed to import user certificate " + userCertificate); 471 if (!mKeyStore.delete(Credentials.USER_PRIVATE_KEY + alias)) { 472 Log.e(TAG, "Failed to delete private key after certificate importing failed"); 473 } 474 return false; 475 } 476 if (userCertificateChain != null && userCertificateChain.length > 0) { 477 if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, userCertificateChain, uid, 478 KeyStore.FLAG_NONE)) { 479 Log.e(TAG, "Failed to import certificate chain" + userCertificateChain); 480 if (!removeKeyPair(alias)) { 481 Log.e(TAG, "Failed to clean up key chain after certificate chain" 482 + " importing failed"); 483 } 484 return false; 485 } 486 } 487 broadcastKeychainChange(); 488 broadcastLegacyStorageChange(); 489 return true; 490 } 491 492 @Override public boolean removeKeyPair(String alias) { 493 checkCertInstallerOrSystemCaller(); 494 if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias)) { 495 return false; 496 } 497 Log.w(TAG, String.format( 498 "WARNING: Removing alias %s, existing grants will be revoked.", alias)); 499 mGrantsDb.removeAliasInformation(alias); 500 broadcastKeychainChange(); 501 broadcastLegacyStorageChange(); 502 return true; 503 } 504 505 private X509Certificate parseCertificate(byte[] bytes) throws CertificateException { 506 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 507 return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(bytes)); 508 } 509 510 @Override public boolean reset() { 511 // only Settings should be able to reset 512 checkSystemCaller(); 513 mGrantsDb.removeAllAliasesInformation(); 514 boolean ok = true; 515 synchronized (mTrustedCertificateStore) { 516 // delete user-installed CA certs 517 for (String alias : mTrustedCertificateStore.aliases()) { 518 if (TrustedCertificateStore.isUser(alias)) { 519 if (!deleteCertificateEntry(alias)) { 520 ok = false; 521 } 522 } 523 } 524 } 525 broadcastTrustStoreChange(); 526 broadcastKeychainChange(); 527 broadcastLegacyStorageChange(); 528 return ok; 529 } 530 531 @Override public boolean deleteCaCertificate(String alias) { 532 // only Settings should be able to delete 533 checkSystemCaller(); 534 boolean ok = true; 535 Log.i(TAG, String.format("Deleting CA certificate %s", alias)); 536 synchronized (mTrustedCertificateStore) { 537 ok = deleteCertificateEntry(alias); 538 } 539 broadcastTrustStoreChange(); 540 broadcastLegacyStorageChange(); 541 return ok; 542 } 543 544 private boolean deleteCertificateEntry(String alias) { 545 String subjectForAudit = null; 546 if (mInjector.isSecurityLoggingEnabled()) { 547 final Certificate cert = mTrustedCertificateStore.getCertificate(alias); 548 if (cert instanceof X509Certificate) { 549 subjectForAudit = ((X509Certificate) cert) 550 .getSubjectX500Principal().getName(X500Principal.CANONICAL); 551 } 552 } 553 554 try { 555 mTrustedCertificateStore.deleteCertificateEntry(alias); 556 if (subjectForAudit != null) { 557 mInjector.writeSecurityEvent( 558 TAG_CERT_AUTHORITY_REMOVED, 1 /*result*/, subjectForAudit, 559 UserHandle.myUserId()); 560 } 561 return true; 562 } catch (IOException | CertificateException e) { 563 Log.w(TAG, "Problem removing CA certificate " + alias, e); 564 if (subjectForAudit != null) { 565 mInjector.writeSecurityEvent( 566 TAG_CERT_AUTHORITY_REMOVED, 0 /*result*/, subjectForAudit, 567 UserHandle.myUserId()); 568 } 569 return false; 570 } 571 } 572 573 private void checkCertInstallerOrSystemCaller() { 574 final String caller = callingPackage(); 575 if (!isCallerWithSystemUid() && !CERT_INSTALLER_PACKAGE.equals(caller)) { 576 throw new SecurityException("Not system or cert installer package: " + caller); 577 } 578 } 579 580 private void checkSystemCaller() { 581 if (!isCallerWithSystemUid()) { 582 throw new SecurityException("Not system package: " + callingPackage()); 583 } 584 } 585 586 private boolean isCallerWithSystemUid() { 587 return UserHandle.isSameApp(mInjector.getCallingUid(), Process.SYSTEM_UID); 588 } 589 590 private String callingPackage() { 591 return getPackageManager().getNameForUid(mInjector.getCallingUid()); 592 } 593 594 @Override public boolean hasGrant(int uid, String alias) { 595 checkSystemCaller(); 596 return mGrantsDb.hasGrant(uid, alias); 597 } 598 599 @Override public void setGrant(int uid, String alias, boolean value) { 600 checkSystemCaller(); 601 mGrantsDb.setGrant(uid, alias, value); 602 broadcastPermissionChange(uid, alias, value); 603 broadcastLegacyStorageChange(); 604 } 605 606 @Override 607 public StringParceledListSlice getUserCaAliases() { 608 synchronized (mTrustedCertificateStore) { 609 return new StringParceledListSlice(new ArrayList<String>( 610 mTrustedCertificateStore.userAliases())); 611 } 612 } 613 614 @Override 615 public StringParceledListSlice getSystemCaAliases() { 616 synchronized (mTrustedCertificateStore) { 617 return new StringParceledListSlice(new ArrayList<String>( 618 mTrustedCertificateStore.allSystemAliases())); 619 } 620 } 621 622 @Override 623 public boolean containsCaAlias(String alias) { 624 return mTrustedCertificateStore.containsAlias(alias); 625 } 626 627 @Override 628 public byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem) { 629 synchronized (mTrustedCertificateStore) { 630 X509Certificate certificate = (X509Certificate) mTrustedCertificateStore 631 .getCertificate(alias, includeDeletedSystem); 632 if (certificate == null) { 633 Log.w(TAG, "Could not find CA certificate " + alias); 634 return null; 635 } 636 try { 637 return certificate.getEncoded(); 638 } catch (CertificateEncodingException e) { 639 Log.w(TAG, "Error while encoding CA certificate " + alias); 640 return null; 641 } 642 } 643 } 644 645 @Override 646 public List<String> getCaCertificateChainAliases(String rootAlias, 647 boolean includeDeletedSystem) { 648 synchronized (mTrustedCertificateStore) { 649 X509Certificate root = (X509Certificate) mTrustedCertificateStore.getCertificate( 650 rootAlias, includeDeletedSystem); 651 try { 652 List<X509Certificate> chain = mTrustedCertificateStore.getCertificateChain( 653 root); 654 List<String> aliases = new ArrayList<String>(chain.size()); 655 final int n = chain.size(); 656 for (int i = 0; i < n; ++i) { 657 String alias = mTrustedCertificateStore.getCertificateAlias(chain.get(i), 658 true); 659 if (alias != null) { 660 aliases.add(alias); 661 } 662 } 663 return aliases; 664 } catch (CertificateException e) { 665 Log.w(TAG, "Error retrieving cert chain for root " + rootAlias); 666 return Collections.emptyList(); 667 } 668 } 669 } 670 }; 671 onBind(Intent intent)672 @Override public IBinder onBind(Intent intent) { 673 if (IKeyChainService.class.getName().equals(intent.getAction())) { 674 return mIKeyChainService; 675 } 676 return null; 677 } 678 679 @Override onHandleIntent(final Intent intent)680 protected void onHandleIntent(final Intent intent) { 681 if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) { 682 mGrantsDb.purgeOldGrants(getPackageManager()); 683 } 684 } 685 broadcastLegacyStorageChange()686 private void broadcastLegacyStorageChange() { 687 Intent intent = new Intent(KeyChain.ACTION_STORAGE_CHANGED); 688 BroadcastOptions opts = BroadcastOptions.makeBasic(); 689 opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.N_MR1); 690 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()), null, opts.toBundle()); 691 } 692 broadcastKeychainChange()693 private void broadcastKeychainChange() { 694 Intent intent = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED); 695 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId())); 696 } 697 broadcastTrustStoreChange()698 private void broadcastTrustStoreChange() { 699 Intent intent = new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED); 700 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId())); 701 } 702 broadcastPermissionChange(int uid, String alias, boolean access)703 private void broadcastPermissionChange(int uid, String alias, boolean access) { 704 // Since the permission change only impacts one uid only send to that uid's packages. 705 final PackageManager packageManager = getPackageManager(); 706 String[] packages = packageManager.getPackagesForUid(uid); 707 if (packages == null) { 708 return; 709 } 710 for (String pckg : packages) { 711 Intent intent = new Intent(KeyChain.ACTION_KEY_ACCESS_CHANGED); 712 intent.putExtra(KeyChain.EXTRA_KEY_ALIAS, alias); 713 intent.putExtra(KeyChain.EXTRA_KEY_ACCESSIBLE, access); 714 intent.setPackage(pckg); 715 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId())); 716 } 717 } 718 emptyOrBase64Encoded(byte[] cert)719 private static String emptyOrBase64Encoded(byte[] cert) { 720 if (cert == null) { 721 return ""; 722 } 723 return Base64.encodeToString(cert, Base64.NO_WRAP); 724 } 725 726 @VisibleForTesting setInjector(Injector injector)727 void setInjector(Injector injector) { 728 mInjector = injector; 729 } 730 731 /** 732 * Injector for mocking out dependencies in tests. 733 */ 734 @VisibleForTesting 735 static class Injector { isSecurityLoggingEnabled()736 public boolean isSecurityLoggingEnabled() { 737 return SecurityLog.isLoggingEnabled(); 738 } 739 writeSecurityEvent(int tag, Object... payload)740 public void writeSecurityEvent(int tag, Object... payload) { 741 SecurityLog.writeEvent(tag, payload); 742 } 743 getCallingUid()744 public int getCallingUid() { 745 return Binder.getCallingUid(); 746 } 747 } 748 } 749