1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.security.keystore2; 18 19 import static android.security.keystore2.AndroidKeyStoreCipherSpiBase.DEFAULT_MGF1_DIGEST; 20 21 import android.annotation.NonNull; 22 import android.hardware.biometrics.BiometricManager; 23 import android.hardware.security.keymint.EcCurve; 24 import android.hardware.security.keymint.HardwareAuthenticatorType; 25 import android.hardware.security.keymint.KeyParameter; 26 import android.hardware.security.keymint.SecurityLevel; 27 import android.os.StrictMode; 28 import android.security.Flags; 29 import android.security.GateKeeper; 30 import android.security.KeyStore2; 31 import android.security.KeyStoreParameter; 32 import android.security.KeyStoreSecurityLevel; 33 import android.security.keymaster.KeymasterDefs; 34 import android.security.keystore.KeyGenParameterSpec; 35 import android.security.keystore.KeyPermanentlyInvalidatedException; 36 import android.security.keystore.KeyProperties; 37 import android.security.keystore.KeyProtection; 38 import android.security.keystore.SecureKeyImportUnavailableException; 39 import android.security.keystore.WrappedKeyEntry; 40 import android.system.keystore2.AuthenticatorSpec; 41 import android.system.keystore2.Authorization; 42 import android.system.keystore2.Domain; 43 import android.system.keystore2.IKeystoreSecurityLevel; 44 import android.system.keystore2.KeyDescriptor; 45 import android.system.keystore2.KeyEntryResponse; 46 import android.system.keystore2.KeyMetadata; 47 import android.system.keystore2.ResponseCode; 48 import android.util.Log; 49 50 import com.android.internal.annotations.VisibleForTesting; 51 52 import java.io.ByteArrayInputStream; 53 import java.io.IOException; 54 import java.io.InputStream; 55 import java.io.OutputStream; 56 import java.security.Key; 57 import java.security.KeyStore.Entry; 58 import java.security.KeyStore.LoadStoreParameter; 59 import java.security.KeyStore.PrivateKeyEntry; 60 import java.security.KeyStore.ProtectionParameter; 61 import java.security.KeyStore.SecretKeyEntry; 62 import java.security.KeyStoreException; 63 import java.security.KeyStoreSpi; 64 import java.security.NoSuchAlgorithmException; 65 import java.security.PrivateKey; 66 import java.security.ProviderException; 67 import java.security.UnrecoverableKeyException; 68 import java.security.cert.Certificate; 69 import java.security.cert.CertificateEncodingException; 70 import java.security.cert.CertificateException; 71 import java.security.cert.CertificateFactory; 72 import java.security.cert.X509Certificate; 73 import java.security.interfaces.ECKey; 74 import java.security.interfaces.ECPrivateKey; 75 import java.security.interfaces.EdECKey; 76 import java.security.interfaces.EdECPrivateKey; 77 import java.security.interfaces.XECKey; 78 import java.security.interfaces.XECPrivateKey; 79 import java.security.spec.AlgorithmParameterSpec; 80 import java.security.spec.ECParameterSpec; 81 import java.security.spec.NamedParameterSpec; 82 import java.util.ArrayList; 83 import java.util.Arrays; 84 import java.util.Collection; 85 import java.util.Date; 86 import java.util.Enumeration; 87 import java.util.Iterator; 88 import java.util.List; 89 import java.util.NoSuchElementException; 90 91 import javax.crypto.SecretKey; 92 93 /** 94 * A java.security.KeyStore interface for the Android KeyStore. An instance of 95 * it can be created via the {@link java.security.KeyStore#getInstance(String) 96 * KeyStore.getInstance("AndroidKeyStore")} interface. This returns a 97 * java.security.KeyStore backed by this "AndroidKeyStore" implementation. 98 * <p> 99 * This is built on top of Android's keystore daemon. The convention of alias 100 * use is: 101 * <p> 102 * PrivateKeyEntry will have a Credentials.USER_PRIVATE_KEY as the private key, 103 * Credentials.USER_CERTIFICATE as the first certificate in the chain (the one 104 * that corresponds to the private key), and then a Credentials.CA_CERTIFICATE 105 * entry which will have the rest of the chain concatenated in BER format. 106 * <p> 107 * TrustedCertificateEntry will just have a Credentials.CA_CERTIFICATE entry 108 * with a single certificate. 109 * 110 * @hide 111 */ 112 public class AndroidKeyStoreSpi extends KeyStoreSpi { 113 public static final String TAG = "AndroidKeyStoreSpi"; 114 public static final String NAME = "AndroidKeyStore"; 115 116 private KeyStore2 mKeyStore; 117 private @KeyProperties.Namespace int mNamespace = KeyProperties.NAMESPACE_APPLICATION; 118 119 @Override engineGetKey(String alias, char[] password)120 public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, 121 UnrecoverableKeyException { 122 try { 123 return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(mKeyStore, 124 alias, 125 mNamespace); 126 } catch (KeyPermanentlyInvalidatedException e) { 127 throw new UnrecoverableKeyException(e.getMessage()); 128 } catch (UnrecoverableKeyException e) { 129 Throwable cause = e.getCause(); 130 if (cause instanceof android.security.KeyStoreException) { 131 if (((android.security.KeyStoreException) cause).getErrorCode() 132 == ResponseCode.KEY_NOT_FOUND) { 133 return null; 134 } 135 } 136 throw e; 137 } 138 } 139 140 /** 141 * Make a key descriptor from the given alias and the mNamespace member. 142 * If mNamespace is -1 it sets the domain field to {@link Domain#APP} and {@link Domain#SELINUX} 143 * otherwise. The blob field is always set to null and the alias field to {@code alias} 144 * @param alias The alias of the new key descriptor. 145 * @return A new key descriptor. 146 */ makeKeyDescriptor(@onNull String alias)147 private KeyDescriptor makeKeyDescriptor(@NonNull String alias) { 148 KeyDescriptor descriptor = new KeyDescriptor(); 149 descriptor.domain = getTargetDomain(); 150 descriptor.nspace = mNamespace; // ignored if Domain.App; 151 descriptor.alias = alias; 152 descriptor.blob = null; 153 return descriptor; 154 } 155 getTargetDomain()156 private @Domain int getTargetDomain() { 157 return mNamespace == KeyProperties.NAMESPACE_APPLICATION 158 ? Domain.APP 159 : Domain.SELINUX; 160 } getKeyMetadata(String alias)161 private KeyEntryResponse getKeyMetadata(String alias) { 162 if (alias == null) { 163 throw new NullPointerException("alias == null"); 164 } 165 166 KeyDescriptor descriptor = makeKeyDescriptor(alias); 167 168 try { 169 StrictMode.noteDiskRead(); 170 return mKeyStore.getKeyEntry(descriptor); 171 } catch (android.security.KeyStoreException e) { 172 if (e.getErrorCode() != ResponseCode.KEY_NOT_FOUND) { 173 Log.w(TAG, "Could not get key metadata from Keystore.", e); 174 } 175 return null; 176 } 177 } 178 179 @Override engineGetCertificateChain(String alias)180 public Certificate[] engineGetCertificateChain(String alias) { 181 KeyEntryResponse response = getKeyMetadata(alias); 182 183 if (response == null || response.metadata.certificate == null) { 184 return null; 185 } 186 187 final X509Certificate leaf = (X509Certificate) toCertificate(response.metadata.certificate); 188 if (leaf == null) { 189 return null; 190 } 191 192 final Certificate[] caList; 193 194 final byte[] caBytes = response.metadata.certificateChain; 195 196 if (caBytes != null) { 197 final Collection<X509Certificate> caChain = toCertificates(caBytes); 198 199 caList = new Certificate[caChain.size() + 1]; 200 201 final Iterator<X509Certificate> it = caChain.iterator(); 202 int i = 1; 203 while (it.hasNext()) { 204 caList[i++] = it.next(); 205 } 206 } else { 207 caList = new Certificate[1]; 208 } 209 210 caList[0] = leaf; 211 212 return caList; 213 } 214 215 @Override engineGetCertificate(String alias)216 public Certificate engineGetCertificate(String alias) { 217 KeyEntryResponse response = getKeyMetadata(alias); 218 219 if (response == null) { 220 return null; 221 } 222 223 byte[] encodedCert = response.metadata.certificate; 224 if (encodedCert != null) { 225 return toCertificate(encodedCert); 226 } 227 228 encodedCert = response.metadata.certificateChain; 229 if (encodedCert != null) { 230 return toCertificate(encodedCert); 231 } 232 233 // This entry/alias does not contain a certificate. 234 return null; 235 } 236 toCertificate(byte[] bytes)237 static X509Certificate toCertificate(byte[] bytes) { 238 try { 239 final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 240 return (X509Certificate) certFactory.generateCertificate( 241 new ByteArrayInputStream(bytes)); 242 } catch (CertificateException e) { 243 Log.w(NAME, "Couldn't parse certificate in keystore", e); 244 return null; 245 } 246 } 247 248 @SuppressWarnings("unchecked") toCertificates(byte[] bytes)249 private static Collection<X509Certificate> toCertificates(byte[] bytes) { 250 try { 251 final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 252 return (Collection<X509Certificate>) certFactory.generateCertificates( 253 new ByteArrayInputStream(bytes)); 254 } catch (CertificateException e) { 255 Log.w(NAME, "Couldn't parse certificates in keystore", e); 256 return new ArrayList<X509Certificate>(); 257 } 258 } 259 getMgf1DigestSetterFlag()260 private static boolean getMgf1DigestSetterFlag() { 261 try { 262 return Flags.mgf1DigestSetterV2(); 263 } catch (SecurityException e) { 264 Log.w(NAME, "Cannot read MGF1 Digest setter flag value", e); 265 return false; 266 } 267 } 268 269 @Override engineGetCreationDate(String alias)270 public Date engineGetCreationDate(String alias) { 271 KeyEntryResponse response = getKeyMetadata(alias); 272 273 if (response == null) { 274 return null; 275 } 276 277 if (response.metadata.modificationTimeMs == -1) { 278 return null; 279 } 280 return new Date(response.metadata.modificationTimeMs); 281 } 282 283 @Override engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)284 public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) 285 throws KeyStoreException { 286 if ((password != null) && (password.length > 0)) { 287 throw new KeyStoreException("entries cannot be protected with passwords"); 288 } 289 290 if (key instanceof PrivateKey) { 291 setPrivateKeyEntry(alias, (PrivateKey) key, chain, null); 292 } else if (key instanceof SecretKey) { 293 setSecretKeyEntry(alias, (SecretKey) key, null); 294 } else { 295 throw new KeyStoreException("Only PrivateKey and SecretKey are supported"); 296 } 297 } 298 getLegacyKeyProtectionParameter(PrivateKey key)299 private static KeyProtection getLegacyKeyProtectionParameter(PrivateKey key) 300 throws KeyStoreException { 301 String keyAlgorithm = key.getAlgorithm(); 302 KeyProtection.Builder specBuilder; 303 if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) { 304 specBuilder = 305 new KeyProtection.Builder( 306 KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY); 307 // Authorized to be used with any digest (including no digest). 308 // MD5 was never offered for Android Keystore for ECDSA. 309 specBuilder.setDigests( 310 KeyProperties.DIGEST_NONE, 311 KeyProperties.DIGEST_SHA1, 312 KeyProperties.DIGEST_SHA224, 313 KeyProperties.DIGEST_SHA256, 314 KeyProperties.DIGEST_SHA384, 315 KeyProperties.DIGEST_SHA512); 316 } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { 317 specBuilder = 318 new KeyProtection.Builder( 319 KeyProperties.PURPOSE_ENCRYPT 320 | KeyProperties.PURPOSE_DECRYPT 321 | KeyProperties.PURPOSE_SIGN 322 | KeyProperties.PURPOSE_VERIFY); 323 // Authorized to be used with any digest (including no digest). 324 specBuilder.setDigests( 325 KeyProperties.DIGEST_NONE, 326 KeyProperties.DIGEST_MD5, 327 KeyProperties.DIGEST_SHA1, 328 KeyProperties.DIGEST_SHA224, 329 KeyProperties.DIGEST_SHA256, 330 KeyProperties.DIGEST_SHA384, 331 KeyProperties.DIGEST_SHA512); 332 // Authorized to be used with any encryption and signature padding 333 // schemes (including no padding). 334 specBuilder.setEncryptionPaddings( 335 KeyProperties.ENCRYPTION_PADDING_NONE, 336 KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1, 337 KeyProperties.ENCRYPTION_PADDING_RSA_OAEP); 338 specBuilder.setSignaturePaddings( 339 KeyProperties.SIGNATURE_PADDING_RSA_PKCS1, 340 KeyProperties.SIGNATURE_PADDING_RSA_PSS); 341 // Disable randomized encryption requirement to support encryption 342 // padding NONE above. 343 specBuilder.setRandomizedEncryptionRequired(false); 344 } else { 345 throw new KeyStoreException("Unsupported key algorithm: " + keyAlgorithm); 346 } 347 specBuilder.setUserAuthenticationRequired(false); 348 349 return specBuilder.build(); 350 } 351 setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain, java.security.KeyStore.ProtectionParameter param)352 private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain, 353 java.security.KeyStore.ProtectionParameter param) throws KeyStoreException { 354 @SecurityLevel int securitylevel = SecurityLevel.TRUSTED_ENVIRONMENT; 355 int flags = 0; 356 KeyProtection spec; 357 if (param == null) { 358 spec = getLegacyKeyProtectionParameter(key); 359 } else if (param instanceof KeyStoreParameter) { 360 spec = getLegacyKeyProtectionParameter(key); 361 KeyStoreParameter legacySpec = (KeyStoreParameter) param; 362 } else if (param instanceof KeyProtection) { 363 spec = (KeyProtection) param; 364 if (spec.isCriticalToDeviceEncryption()) { 365 // This key is should not be bound to the LSKF even if it is auth bound. 366 // This indicates that this key is used in the derivation for of the 367 // master key, that is used for the LSKF binding of other auth bound 368 // keys. This breaks up a circular dependency while retaining logical 369 // authentication binding of the key. 370 flags |= IKeystoreSecurityLevel 371 .KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING; 372 } 373 374 if (spec.isStrongBoxBacked()) { 375 securitylevel = SecurityLevel.STRONGBOX; 376 } 377 } else { 378 throw new KeyStoreException( 379 "Unsupported protection parameter class:" + param.getClass().getName() 380 + ". Supported: " + KeyProtection.class.getName() + ", " 381 + KeyStoreParameter.class.getName()); 382 } 383 384 // Make sure the chain exists since this is a PrivateKey 385 if ((chain == null) || (chain.length == 0)) { 386 throw new KeyStoreException("Must supply at least one Certificate with PrivateKey"); 387 } 388 389 // Do chain type checking. 390 X509Certificate[] x509chain = new X509Certificate[chain.length]; 391 for (int i = 0; i < chain.length; i++) { 392 if (!"X.509".equals(chain[i].getType())) { 393 throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #" 394 + i); 395 } 396 397 if (!(chain[i] instanceof X509Certificate)) { 398 throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #" 399 + i); 400 } 401 402 x509chain[i] = (X509Certificate) chain[i]; 403 } 404 405 final byte[] userCertBytes; 406 try { 407 userCertBytes = x509chain[0].getEncoded(); 408 } catch (CertificateEncodingException e) { 409 throw new KeyStoreException("Failed to encode certificate #0", e); 410 } 411 412 /* 413 * If we have a chain, store it in the CA certificate slot for this 414 * alias as concatenated DER-encoded certificates. These can be 415 * deserialized by {@link CertificateFactory#generateCertificates}. 416 */ 417 final byte[] chainBytes; 418 if (chain.length > 1) { 419 /* 420 * The chain is passed in as {user_cert, ca_cert_1, ca_cert_2, ...} 421 * so we only need the certificates starting at index 1. 422 */ 423 final byte[][] certsBytes = new byte[x509chain.length - 1][]; 424 int totalCertLength = 0; 425 for (int i = 0; i < certsBytes.length; i++) { 426 try { 427 certsBytes[i] = x509chain[i + 1].getEncoded(); 428 totalCertLength += certsBytes[i].length; 429 } catch (CertificateEncodingException e) { 430 throw new KeyStoreException("Failed to encode certificate #" + i, e); 431 } 432 } 433 434 /* 435 * Serialize this into one byte array so we can later call 436 * CertificateFactory#generateCertificates to recover them. 437 */ 438 chainBytes = new byte[totalCertLength]; 439 int outputOffset = 0; 440 for (int i = 0; i < certsBytes.length; i++) { 441 final int certLength = certsBytes[i].length; 442 System.arraycopy(certsBytes[i], 0, chainBytes, outputOffset, certLength); 443 outputOffset += certLength; 444 certsBytes[i] = null; 445 } 446 } else { 447 chainBytes = null; 448 } 449 450 @Domain int targetDomain = getTargetDomain(); 451 452 // If the given key is an AndroidKeyStorePrivateKey, we attempt to update 453 // its subcomponents with the given certificate and certificate chain. 454 if (key instanceof AndroidKeyStorePrivateKey) { 455 AndroidKeyStoreKey ksKey = (AndroidKeyStoreKey) key; 456 KeyDescriptor descriptor = ksKey.getUserKeyDescriptor(); 457 458 // This throws if the request cannot replace the entry. 459 assertCanReplace(alias, targetDomain, mNamespace, descriptor); 460 461 try { 462 StrictMode.noteDiskWrite(); 463 mKeyStore.updateSubcomponents( 464 ((AndroidKeyStorePrivateKey) key).getKeyIdDescriptor(), 465 userCertBytes, chainBytes); 466 } catch (android.security.KeyStoreException e) { 467 throw new KeyStoreException("Failed to store certificate and certificate chain", e); 468 } 469 return; 470 } 471 472 // Make sure the PrivateKey format is the one we support. 473 final String keyFormat = key.getFormat(); 474 if ((keyFormat == null) || (!"PKCS#8".equals(keyFormat))) { 475 throw new KeyStoreException( 476 "Unsupported private key export format: " + keyFormat 477 + ". Only private keys which export their key material in PKCS#8 format are" 478 + " supported."); 479 } 480 481 // Make sure we can actually encode the key. 482 byte[] pkcs8EncodedPrivateKeyBytes = key.getEncoded(); 483 if (pkcs8EncodedPrivateKeyBytes == null) { 484 throw new KeyStoreException("Private key did not export any key material"); 485 } 486 487 final List<KeyParameter> importArgs = new ArrayList<>(); 488 489 try { 490 importArgs.add(KeyStore2ParameterUtils.makeEnum( 491 KeymasterDefs.KM_TAG_ALGORITHM, 492 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm( 493 key.getAlgorithm())) 494 ); 495 KeyStore2ParameterUtils.forEachSetFlag(spec.getPurposes(), (purpose) -> { 496 importArgs.add(KeyStore2ParameterUtils.makeEnum( 497 KeymasterDefs.KM_TAG_PURPOSE, 498 KeyProperties.Purpose.toKeymaster(purpose) 499 )); 500 }); 501 if (spec.isDigestsSpecified()) { 502 for (String digest : spec.getDigests()) { 503 importArgs.add(KeyStore2ParameterUtils.makeEnum( 504 KeymasterDefs.KM_TAG_DIGEST, 505 KeyProperties.Digest.toKeymaster(digest) 506 )); 507 } 508 } 509 for (String blockMode : spec.getBlockModes()) { 510 importArgs.add(KeyStore2ParameterUtils.makeEnum( 511 KeymasterDefs.KM_TAG_BLOCK_MODE, 512 KeyProperties.BlockMode.toKeymaster(blockMode) 513 )); 514 } 515 int[] keymasterEncryptionPaddings = 516 KeyProperties.EncryptionPadding.allToKeymaster( 517 spec.getEncryptionPaddings()); 518 if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0) 519 && (spec.isRandomizedEncryptionRequired())) { 520 for (int keymasterPadding : keymasterEncryptionPaddings) { 521 if (!KeymasterUtils 522 .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto( 523 keymasterPadding)) { 524 throw new KeyStoreException( 525 "Randomized encryption (IND-CPA) required but is violated by" 526 + " encryption padding mode: " 527 + KeyProperties.EncryptionPadding.fromKeymaster( 528 keymasterPadding) 529 + ". See KeyProtection documentation."); 530 } 531 } 532 } 533 for (int padding : keymasterEncryptionPaddings) { 534 importArgs.add(KeyStore2ParameterUtils.makeEnum( 535 KeymasterDefs.KM_TAG_PADDING, 536 padding 537 )); 538 if (padding == KeymasterDefs.KM_PAD_RSA_OAEP) { 539 if (spec.isMgf1DigestsSpecified()) { 540 for (String mgf1Digest : spec.getMgf1Digests()) { 541 importArgs.add(KeyStore2ParameterUtils.makeEnum( 542 KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, 543 KeyProperties.Digest.toKeymaster(mgf1Digest) 544 )); 545 } 546 } else { 547 /* Because of default MGF1 digest is SHA-1. It has to be added in Key 548 * characteristics. Otherwise, crypto operations will fail with Incompatible 549 * MGF1 digest. 550 * If the MGF1 Digest setter flag isn't set, then the condition in the 551 * if clause above must be false (cannot have MGF1 digests specified if the 552 * flag was off). In that case, in addition to adding the default MGF1 553 * digest, we have to add all the other digests as MGF1 Digests. 554 * 555 */ 556 importArgs.add(KeyStore2ParameterUtils.makeEnum( 557 KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, 558 KeyProperties.Digest.toKeymaster(DEFAULT_MGF1_DIGEST) 559 )); 560 if (!getMgf1DigestSetterFlag()) { 561 final int defaultMgf1Digest = KeyProperties.Digest.toKeymaster( 562 DEFAULT_MGF1_DIGEST); 563 for (String digest : spec.getDigests()) { 564 int digestToAddAsMgf1Digest = KeyProperties.Digest.toKeymaster( 565 digest); 566 // Do not add the default MGF1 digest as it has been added above. 567 if (digestToAddAsMgf1Digest != defaultMgf1Digest) { 568 importArgs.add(KeyStore2ParameterUtils.makeEnum( 569 KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, 570 digestToAddAsMgf1Digest 571 )); 572 } 573 } 574 } 575 } 576 } 577 } 578 for (String padding : spec.getSignaturePaddings()) { 579 importArgs.add(KeyStore2ParameterUtils.makeEnum( 580 KeymasterDefs.KM_TAG_PADDING, 581 KeyProperties.SignaturePadding.toKeymaster(padding) 582 )); 583 } 584 KeyStore2ParameterUtils.addUserAuthArgs(importArgs, spec); 585 if (spec.getKeyValidityStart() != null) { 586 importArgs.add(KeyStore2ParameterUtils.makeDate( 587 KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart() 588 )); 589 } 590 if (spec.getKeyValidityForOriginationEnd() != null) { 591 importArgs.add(KeyStore2ParameterUtils.makeDate( 592 KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, 593 spec.getKeyValidityForOriginationEnd() 594 )); 595 } 596 if (spec.getKeyValidityForConsumptionEnd() != null) { 597 importArgs.add(KeyStore2ParameterUtils.makeDate( 598 KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, 599 spec.getKeyValidityForConsumptionEnd() 600 )); 601 } 602 if (spec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) { 603 importArgs.add(KeyStore2ParameterUtils.makeInt( 604 KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT, 605 spec.getMaxUsageCount() 606 )); 607 } 608 if (KeymasterDefs.KM_ALGORITHM_EC 609 == KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm( 610 key.getAlgorithm())) { 611 importArgs.add(KeyStore2ParameterUtils.makeEnum( 612 KeymasterDefs.KM_TAG_EC_CURVE, 613 getKeymasterEcCurve(key) 614 )); 615 } 616 } catch (IllegalArgumentException | IllegalStateException e) { 617 throw new KeyStoreException(e); 618 } 619 620 try { 621 KeyStoreSecurityLevel securityLevelInterface = mKeyStore.getSecurityLevel( 622 securitylevel); 623 624 KeyDescriptor descriptor = makeKeyDescriptor(alias); 625 626 KeyMetadata metadata = securityLevelInterface.importKey(descriptor, null, 627 importArgs, flags, pkcs8EncodedPrivateKeyBytes); 628 629 try { 630 StrictMode.noteDiskWrite(); 631 mKeyStore.updateSubcomponents(metadata.key, userCertBytes, chainBytes); 632 } catch (android.security.KeyStoreException e) { 633 mKeyStore.deleteKey(metadata.key); 634 throw new KeyStoreException("Failed to store certificate and certificate chain", e); 635 } 636 637 } catch (android.security.KeyStoreException e) { 638 throw new KeyStoreException("Failed to store private key", e); 639 } 640 } 641 getKeymasterEcCurve(PrivateKey key)642 private int getKeymasterEcCurve(PrivateKey key) { 643 if (key instanceof ECKey) { 644 ECParameterSpec param = ((ECPrivateKey) key).getParams(); 645 int kmECCurve = KeymasterUtils.getKeymasterEcCurve(KeymasterUtils.getCurveName(param)); 646 if (kmECCurve >= 0) { 647 return kmECCurve; 648 } 649 } else if (key instanceof XECKey) { 650 AlgorithmParameterSpec param = ((XECPrivateKey) key).getParams(); 651 if (param.equals(NamedParameterSpec.X25519)) { 652 return EcCurve.CURVE_25519; 653 } 654 } else if (key.getAlgorithm().equals("XDH")) { 655 // TODO com.android.org.conscrypt.OpenSSLX25519PrivateKey does not implement XECKey, 656 // this case is not required once it implements XECKey interface(b/214203951). 657 return EcCurve.CURVE_25519; 658 } else if (key instanceof EdECKey) { 659 AlgorithmParameterSpec param = ((EdECPrivateKey) key).getParams(); 660 if (param.equals(NamedParameterSpec.ED25519)) { 661 return EcCurve.CURVE_25519; 662 } 663 } 664 throw new IllegalArgumentException("Unexpected Key " + key.getClass().getName()); 665 } 666 assertCanReplace(String alias, @Domain int targetDomain, int targetNamespace, KeyDescriptor descriptor)667 private static void assertCanReplace(String alias, @Domain int targetDomain, 668 int targetNamespace, KeyDescriptor descriptor) 669 throws KeyStoreException { 670 // If 671 // * the alias does not match, or 672 // * the domain does not match, or 673 // * the domain is Domain.SELINUX and the namespaces don not match, 674 // then the designated key location is not equivalent to the location of the 675 // given key parameter and cannot be updated. 676 // 677 // Note: mNamespace == KeyProperties.NAMESPACE_APPLICATION implies that the target domain 678 // is Domain.APP and Domain.SELINUX is the target domain otherwise. 679 if (!alias.equals(descriptor.alias) 680 || descriptor.domain != targetDomain 681 || (descriptor.domain == Domain.SELINUX && descriptor.nspace != targetNamespace)) { 682 throw new KeyStoreException("Can only replace keys with same alias: " + alias 683 + " != " + descriptor.alias + " in the same target domain: " + targetDomain 684 + " != " + descriptor.domain 685 + (targetDomain == Domain.SELINUX ? " in the same target namespace: " 686 + targetNamespace + " != " + descriptor.nspace : "") 687 ); 688 } 689 } 690 setSecretKeyEntry(String alias, SecretKey key, java.security.KeyStore.ProtectionParameter param)691 private void setSecretKeyEntry(String alias, SecretKey key, 692 java.security.KeyStore.ProtectionParameter param) 693 throws KeyStoreException { 694 if ((param != null) && (!(param instanceof KeyProtection))) { 695 throw new KeyStoreException( 696 "Unsupported protection parameter class: " + param.getClass().getName() 697 + ". Supported: " + KeyProtection.class.getName()); 698 } 699 KeyProtection params = (KeyProtection) param; 700 701 @Domain int targetDomain = (getTargetDomain()); 702 703 if (key instanceof AndroidKeyStoreSecretKey) { 704 String keyAliasInKeystore = 705 ((AndroidKeyStoreSecretKey) key).getUserKeyDescriptor().alias; 706 707 KeyDescriptor descriptor = ((AndroidKeyStoreSecretKey) key).getUserKeyDescriptor(); 708 709 // This throws if the request cannot replace the existing key. 710 assertCanReplace(alias, targetDomain, mNamespace, descriptor); 711 712 // This is the entry where this key is already stored. No need to do anything. 713 if (params != null) { 714 throw new KeyStoreException("Modifying KeyStore-backed key using protection" 715 + " parameters not supported"); 716 } 717 return; 718 } 719 720 if (params == null) { 721 throw new KeyStoreException( 722 "Protection parameters must be specified when importing a symmetric key"); 723 } 724 725 // Not a KeyStore-backed secret key -- import its key material into keystore. 726 String keyExportFormat = key.getFormat(); 727 if (keyExportFormat == null) { 728 throw new KeyStoreException( 729 "Only secret keys that export their key material are supported"); 730 } else if (!"RAW".equals(keyExportFormat)) { 731 throw new KeyStoreException( 732 "Unsupported secret key material export format: " + keyExportFormat); 733 } 734 byte[] keyMaterial = key.getEncoded(); 735 if (keyMaterial == null) { 736 throw new KeyStoreException("Key did not export its key material despite supporting" 737 + " RAW format export"); 738 } 739 740 final List<KeyParameter> importArgs = new ArrayList<>(); 741 742 try { 743 int keymasterAlgorithm = 744 KeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm( 745 key.getAlgorithm()); 746 747 importArgs.add(KeyStore2ParameterUtils.makeEnum( 748 KeymasterDefs.KM_TAG_ALGORITHM, 749 keymasterAlgorithm 750 )); 751 752 if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) { 753 // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm 754 // implies SHA-256 digest). Because keymaster HMAC key is authorized only for one 755 // digest, we don't let import parameters override the digest implied by the key. 756 // If the parameters specify digests at all, they must specify only one digest, the 757 // only implied by key algorithm. 758 int keymasterImpliedDigest = 759 KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm()); 760 if (keymasterImpliedDigest == -1) { 761 throw new ProviderException( 762 "HMAC key algorithm digest unknown for key algorithm " 763 + key.getAlgorithm()); 764 } 765 766 if (params.isDigestsSpecified()) { 767 // Digest(s) explicitly specified in params -- check that the list consists of 768 // exactly one digest, the one implied by key algorithm. 769 int[] keymasterDigestsFromParams = 770 KeyProperties.Digest.allToKeymaster(params.getDigests()); 771 if ((keymasterDigestsFromParams.length != 1) 772 || (keymasterDigestsFromParams[0] != keymasterImpliedDigest)) { 773 throw new KeyStoreException( 774 "Unsupported digests specification: " 775 + Arrays.asList(params.getDigests()) + ". Only " 776 + KeyProperties.Digest.fromKeymaster(keymasterImpliedDigest) 777 + " supported for HMAC key algorithm " 778 + key.getAlgorithm()); 779 } 780 } 781 int outputBits = KeymasterUtils.getDigestOutputSizeBits(keymasterImpliedDigest); 782 if (outputBits == -1) { 783 throw new ProviderException( 784 "HMAC key authorized for unsupported digest: " 785 + KeyProperties.Digest.fromKeymaster(keymasterImpliedDigest)); 786 } 787 importArgs.add(KeyStore2ParameterUtils.makeEnum( 788 KeymasterDefs.KM_TAG_DIGEST, keymasterImpliedDigest 789 )); 790 importArgs.add(KeyStore2ParameterUtils.makeInt( 791 KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, outputBits 792 )); 793 } else { 794 if (params.isDigestsSpecified()) { 795 for (String digest : params.getDigests()) { 796 importArgs.add(KeyStore2ParameterUtils.makeEnum( 797 KeymasterDefs.KM_TAG_DIGEST, 798 KeyProperties.Digest.toKeymaster(digest) 799 )); 800 } 801 } 802 } 803 804 KeyStore2ParameterUtils.forEachSetFlag(params.getPurposes(), (purpose) -> { 805 importArgs.add(KeyStore2ParameterUtils.makeEnum( 806 KeymasterDefs.KM_TAG_PURPOSE, 807 KeyProperties.Purpose.toKeymaster(purpose) 808 )); 809 }); 810 811 boolean indCpa = false; 812 if ((params.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0) { 813 if (((KeyProtection) param).isRandomizedEncryptionRequired()) { 814 indCpa = true; 815 } else { 816 importArgs.add(KeyStore2ParameterUtils.makeBool( 817 KeymasterDefs.KM_TAG_CALLER_NONCE 818 )); 819 } 820 } 821 822 for (String blockMode : params.getBlockModes()) { 823 int keymasterBlockMode = KeyProperties.BlockMode.toKeymaster(blockMode); 824 if (indCpa 825 && !KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto( 826 keymasterBlockMode)) { 827 throw new KeyStoreException( 828 "Randomized encryption (IND-CPA) required but may be violated by" 829 + " block mode: " + blockMode 830 + ". See KeyProtection documentation."); 831 832 } 833 if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_AES 834 && keymasterBlockMode == KeymasterDefs.KM_MODE_GCM) { 835 importArgs.add(KeyStore2ParameterUtils.makeInt( 836 KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, 837 AndroidKeyStoreAuthenticatedAESCipherSpi.GCM 838 .MIN_SUPPORTED_TAG_LENGTH_BITS 839 )); 840 } 841 importArgs.add(KeyStore2ParameterUtils.makeEnum( 842 KeymasterDefs.KM_TAG_BLOCK_MODE, 843 keymasterBlockMode 844 )); 845 } 846 847 if (params.getSignaturePaddings().length > 0) { 848 throw new KeyStoreException("Signature paddings not supported for symmetric keys"); 849 } 850 851 for (String padding : params.getEncryptionPaddings()) { 852 importArgs.add(KeyStore2ParameterUtils.makeEnum( 853 KeymasterDefs.KM_TAG_PADDING, 854 KeyProperties.EncryptionPadding.toKeymaster(padding) 855 )); 856 } 857 858 KeyStore2ParameterUtils.addUserAuthArgs(importArgs, params); 859 860 if (params.getKeyValidityStart() != null) { 861 importArgs.add(KeyStore2ParameterUtils.makeDate( 862 KeymasterDefs.KM_TAG_ACTIVE_DATETIME, params.getKeyValidityStart() 863 )); 864 } 865 if (params.getKeyValidityForOriginationEnd() != null) { 866 importArgs.add(KeyStore2ParameterUtils.makeDate( 867 KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, 868 params.getKeyValidityForOriginationEnd() 869 )); 870 } 871 if (params.getKeyValidityForConsumptionEnd() != null) { 872 importArgs.add(KeyStore2ParameterUtils.makeDate( 873 KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, 874 params.getKeyValidityForConsumptionEnd() 875 )); 876 } 877 if (params.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) { 878 importArgs.add(KeyStore2ParameterUtils.makeInt( 879 KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT, 880 params.getMaxUsageCount() 881 )); 882 } 883 884 if (params.isRollbackResistant()) { 885 importArgs.add(KeyStore2ParameterUtils.makeBool( 886 KeymasterDefs.KM_TAG_ROLLBACK_RESISTANT 887 )); 888 } 889 } catch (IllegalArgumentException | IllegalStateException e) { 890 throw new KeyStoreException(e); 891 } 892 893 int flags = 0; 894 if (params.isCriticalToDeviceEncryption()) { 895 flags |= IKeystoreSecurityLevel.KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING; 896 } 897 898 @SecurityLevel int securityLevel = params.isStrongBoxBacked() ? SecurityLevel.STRONGBOX : 899 SecurityLevel.TRUSTED_ENVIRONMENT; 900 901 try { 902 KeyStoreSecurityLevel securityLevelInterface = mKeyStore.getSecurityLevel( 903 securityLevel); 904 905 KeyDescriptor descriptor = makeKeyDescriptor(alias); 906 907 securityLevelInterface.importKey(descriptor, null /* TODO attestationKey */, 908 importArgs, flags, keyMaterial); 909 } catch (android.security.KeyStoreException e) { 910 throw new KeyStoreException("Failed to import secret key.", e); 911 } 912 } 913 setWrappedKeyEntry(String alias, WrappedKeyEntry entry, java.security.KeyStore.ProtectionParameter param)914 private void setWrappedKeyEntry(String alias, WrappedKeyEntry entry, 915 java.security.KeyStore.ProtectionParameter param) throws KeyStoreException { 916 if (param != null) { 917 throw new KeyStoreException("Protection parameters are specified inside wrapped keys"); 918 } 919 920 byte[] maskingKey = new byte[32]; 921 922 String[] parts = entry.getTransformation().split("/"); 923 924 List<KeyParameter> args = new ArrayList<>(); 925 926 String algorithm = parts[0]; 927 if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) { 928 args.add(KeyStore2ParameterUtils.makeEnum( 929 KeymasterDefs.KM_TAG_ALGORITHM, 930 KeymasterDefs.KM_ALGORITHM_RSA 931 )); 932 } else { 933 throw new KeyStoreException("Algorithm \"" + algorithm + "\" not supported for " 934 + "wrapping. Only RSA wrapping keys are supported."); 935 } 936 937 if (parts.length > 1) { 938 String mode = parts[1]; 939 args.add(KeyStore2ParameterUtils.makeEnum( 940 KeymasterDefs.KM_TAG_BLOCK_MODE, 941 KeyProperties.BlockMode.toKeymaster(mode) 942 )); 943 } 944 945 if (parts.length > 2) { 946 @KeyProperties.EncryptionPaddingEnum int padding = 947 KeyProperties.EncryptionPadding.toKeymaster(parts[2]); 948 if (padding != KeymasterDefs.KM_PAD_NONE) { 949 args.add(KeyStore2ParameterUtils.makeEnum( 950 KeymasterDefs.KM_TAG_PADDING, 951 padding 952 )); 953 } 954 } 955 956 KeyGenParameterSpec spec = (KeyGenParameterSpec) entry.getAlgorithmParameterSpec(); 957 if (spec.isDigestsSpecified()) { 958 @KeyProperties.DigestEnum int digest = 959 KeyProperties.Digest.toKeymaster(spec.getDigests()[0]); 960 if (digest != KeymasterDefs.KM_DIGEST_NONE) { 961 args.add(KeyStore2ParameterUtils.makeEnum( 962 KeymasterDefs.KM_TAG_DIGEST, 963 digest 964 )); 965 } 966 } 967 968 KeyDescriptor wrappingkey = makeKeyDescriptor(entry.getWrappingKeyAlias()); 969 970 KeyEntryResponse response = null; 971 try { 972 StrictMode.noteDiskRead(); 973 response = mKeyStore.getKeyEntry(wrappingkey); 974 } catch (android.security.KeyStoreException e) { 975 throw new KeyStoreException("Failed to import wrapped key. Keystore error code: " 976 + e.getErrorCode(), e); 977 } 978 979 KeyDescriptor wrappedKey = makeKeyDescriptor(alias); 980 981 KeyStoreSecurityLevel securityLevel = new KeyStoreSecurityLevel(response.iSecurityLevel); 982 983 final BiometricManager bm = android.app.AppGlobals.getInitialApplication() 984 .getSystemService(BiometricManager.class); 985 986 long[] biometricSids = bm.getAuthenticatorIds(); 987 988 List<AuthenticatorSpec> authenticatorSpecs = new ArrayList<>(); 989 990 AuthenticatorSpec authenticatorSpec = new AuthenticatorSpec(); 991 authenticatorSpec.authenticatorType = HardwareAuthenticatorType.PASSWORD; 992 authenticatorSpec.authenticatorId = GateKeeper.getSecureUserId(); 993 authenticatorSpecs.add(authenticatorSpec); 994 995 for (long sid : biometricSids) { 996 AuthenticatorSpec authSpec = new AuthenticatorSpec(); 997 authSpec.authenticatorType = HardwareAuthenticatorType.FINGERPRINT; 998 authSpec.authenticatorId = sid; 999 authenticatorSpecs.add(authSpec); 1000 } 1001 1002 if (parts.length > 2) { 1003 @KeyProperties.EncryptionPaddingEnum int padding = 1004 KeyProperties.EncryptionPadding.toKeymaster(parts[2]); 1005 if (padding == KeymasterDefs.KM_PAD_RSA_OAEP 1006 && response.metadata != null 1007 && response.metadata.authorizations != null) { 1008 Authorization[] keyCharacteristics = response.metadata.authorizations; 1009 1010 for (Authorization authorization : keyCharacteristics) { 1011 // Add default MGF1 digest SHA-1 1012 // when wrapping key has KM_TAG_RSA_OAEP_MGF_DIGEST tag 1013 if (authorization.keyParameter.tag 1014 == KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST) { 1015 // Default MGF1 digest is SHA-1 1016 // and KeyMint only supports default MGF1 digest crypto operations 1017 // for importWrappedKey. 1018 args.add(KeyStore2ParameterUtils.makeEnum( 1019 KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, 1020 KeyProperties.Digest.toKeymaster(DEFAULT_MGF1_DIGEST) 1021 )); 1022 break; 1023 } 1024 } 1025 } 1026 } 1027 1028 try { 1029 StrictMode.noteDiskWrite(); 1030 securityLevel.importWrappedKey( 1031 wrappedKey, wrappingkey, 1032 entry.getWrappedKeyBytes(), 1033 null /* masking key is set to 32 bytes if null is given here */, 1034 args, 1035 authenticatorSpecs.toArray(new AuthenticatorSpec[0])); 1036 } catch (android.security.KeyStoreException e) { 1037 switch (e.getErrorCode()) { 1038 case KeymasterDefs.KM_ERROR_UNIMPLEMENTED: { 1039 throw new SecureKeyImportUnavailableException("Could not import wrapped key"); 1040 } 1041 default: 1042 throw new KeyStoreException("Failed to import wrapped key. Keystore error " 1043 + "code: " + e.getErrorCode(), e); 1044 } 1045 } 1046 } 1047 1048 @Override engineSetKeyEntry(String alias, byte[] userKey, Certificate[] chain)1049 public void engineSetKeyEntry(String alias, byte[] userKey, Certificate[] chain) 1050 throws KeyStoreException { 1051 throw new KeyStoreException("Operation not supported because key encoding is unknown"); 1052 } 1053 1054 /** 1055 * This function sets a trusted certificate entry. It fails if the given 1056 * alias is already taken by an actual key entry. However, if the entry is a 1057 * trusted certificate it will get silently replaced. 1058 * @param alias the alias name 1059 * @param cert the certificate 1060 * 1061 * @throws KeyStoreException if the alias is already taken by a secret or private 1062 * key entry. 1063 * @throws KeyStoreException with a nested {@link CertificateEncodingException} 1064 * if the {@code cert.getEncoded()} throws. 1065 * @throws KeyStoreException with a nested {@link android.security.KeyStoreException} if 1066 * something went wrong while inserting the certificate into keystore. 1067 * @throws NullPointerException if cert or alias is null. 1068 * 1069 * @hide 1070 */ 1071 @Override engineSetCertificateEntry(String alias, Certificate cert)1072 public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException { 1073 if (isKeyEntry(alias)) { 1074 throw new KeyStoreException("Entry exists and is not a trusted certificate"); 1075 } 1076 1077 // We can't set something to null. 1078 if (cert == null) { 1079 throw new NullPointerException("cert == null"); 1080 } 1081 1082 final byte[] encoded; 1083 try { 1084 encoded = cert.getEncoded(); 1085 } catch (CertificateEncodingException e) { 1086 throw new KeyStoreException(e); 1087 } 1088 1089 try { 1090 StrictMode.noteDiskWrite(); 1091 mKeyStore.updateSubcomponents(makeKeyDescriptor(alias), 1092 null /* publicCert - unused when used as pure certificate store. */, 1093 encoded); 1094 } catch (android.security.KeyStoreException e) { 1095 throw new KeyStoreException("Couldn't insert certificate.", e); 1096 } 1097 } 1098 1099 @Override engineDeleteEntry(String alias)1100 public void engineDeleteEntry(String alias) throws KeyStoreException { 1101 KeyDescriptor descriptor = makeKeyDescriptor(alias); 1102 try { 1103 StrictMode.noteDiskWrite(); 1104 mKeyStore.deleteKey(descriptor); 1105 } catch (android.security.KeyStoreException e) { 1106 if (e.getErrorCode() != ResponseCode.KEY_NOT_FOUND) { 1107 throw new KeyStoreException("Failed to delete entry: " + alias, e); 1108 } 1109 } 1110 } 1111 getAliasesBatch(String startPastAlias)1112 private KeyDescriptor[] getAliasesBatch(String startPastAlias) { 1113 try { 1114 StrictMode.noteDiskRead(); 1115 return mKeyStore.listBatch( 1116 getTargetDomain(), 1117 mNamespace, 1118 startPastAlias 1119 ); 1120 } catch (android.security.KeyStoreException e) { 1121 Log.e(TAG, "Failed to list keystore entries.", e); 1122 return new KeyDescriptor[0]; 1123 } 1124 } 1125 1126 @Override engineAliases()1127 public Enumeration<String> engineAliases() { 1128 return new KeyEntriesEnumerator(); 1129 } 1130 1131 @Override engineContainsAlias(String alias)1132 public boolean engineContainsAlias(String alias) { 1133 if (alias == null) { 1134 throw new NullPointerException("alias == null"); 1135 } 1136 1137 return getKeyMetadata(alias) != null; 1138 } 1139 @Override engineSize()1140 public int engineSize() { 1141 try { 1142 StrictMode.noteDiskRead(); 1143 return mKeyStore.getNumberOfEntries( 1144 getTargetDomain(), 1145 mNamespace 1146 ); 1147 } catch (android.security.KeyStoreException e) { 1148 Log.e(TAG, "Failed to get the number of keystore entries.", e); 1149 return 0; 1150 } 1151 } 1152 @Override engineIsKeyEntry(String alias)1153 public boolean engineIsKeyEntry(String alias) { 1154 return isKeyEntry(alias); 1155 } 1156 isKeyEntry(String alias)1157 private boolean isKeyEntry(String alias) { 1158 if (alias == null) { 1159 throw new NullPointerException("alias == null"); 1160 } 1161 1162 KeyEntryResponse response = getKeyMetadata(alias); 1163 // If response is null, there is no such entry. 1164 // If response.iSecurityLevel is null, there is no private or secret key material stored. 1165 return response != null && response.iSecurityLevel != null; 1166 } 1167 1168 1169 @Override engineIsCertificateEntry(String alias)1170 public boolean engineIsCertificateEntry(String alias) { 1171 if (alias == null) { 1172 throw new NullPointerException("alias == null"); 1173 } 1174 KeyEntryResponse response = getKeyMetadata(alias); 1175 // If response == null there is no such entry. 1176 // If there is no certificateChain, then this is not a certificate entry. 1177 // If there is a private key entry, this is the certificate chain for that 1178 // key entry and not a CA certificate entry. 1179 return response != null 1180 && response.metadata.certificateChain != null 1181 && response.iSecurityLevel == null; 1182 } 1183 1184 @Override engineGetCertificateAlias(Certificate cert)1185 public String engineGetCertificateAlias(Certificate cert) { 1186 if (cert == null) { 1187 return null; 1188 } 1189 if (!"X.509".equalsIgnoreCase(cert.getType())) { 1190 Log.e(TAG, "In engineGetCertificateAlias: only X.509 certificates are supported."); 1191 return null; 1192 } 1193 byte[] targetCertBytes; 1194 try { 1195 targetCertBytes = cert.getEncoded(); 1196 } catch (CertificateEncodingException e) { 1197 Log.e(TAG, "While trying to get the alias for a certificate.", e); 1198 return null; 1199 } 1200 if (targetCertBytes == null) { 1201 return null; 1202 } 1203 1204 KeyDescriptor[] keyDescriptors = null; 1205 try { 1206 StrictMode.noteDiskRead(); 1207 keyDescriptors = mKeyStore.list( 1208 getTargetDomain(), 1209 mNamespace 1210 ); 1211 } catch (android.security.KeyStoreException e) { 1212 Log.w(TAG, "Failed to get list of keystore entries.", e); 1213 } 1214 1215 String caAlias = null; 1216 for (KeyDescriptor d : keyDescriptors) { 1217 KeyEntryResponse response = getKeyMetadata(d.alias); 1218 if (response == null) { 1219 continue; 1220 } 1221 /* 1222 * The KeyStoreSpi documentation says to only compare the first certificate in the 1223 * chain which is equivalent to the {@code response.metadata.certificate} field. 1224 * So we look for a hit in this field first. For pure CA certificate entries, 1225 * we check the {@code response.metadata.certificateChain} field. But we only 1226 * return a CA alias if there was no hit in the certificate field of any other 1227 * entry. 1228 */ 1229 if (response.metadata.certificate != null) { 1230 if (Arrays.equals(response.metadata.certificate, targetCertBytes)) { 1231 return d.alias; 1232 } 1233 } else if (response.metadata.certificateChain != null && caAlias == null) { 1234 if (Arrays.equals(response.metadata.certificateChain, targetCertBytes)) { 1235 caAlias = d.alias; 1236 } 1237 } 1238 } 1239 return caAlias; 1240 } 1241 1242 /** 1243 * Used by Tests to initialize with a fake KeyStore2. 1244 * @hide 1245 * @param keystore 1246 */ 1247 @VisibleForTesting initForTesting(KeyStore2 keystore)1248 public void initForTesting(KeyStore2 keystore) { 1249 mKeyStore = keystore; 1250 mNamespace = KeyProperties.NAMESPACE_APPLICATION; 1251 } 1252 1253 @Override engineStore(OutputStream stream, char[] password)1254 public void engineStore(OutputStream stream, char[] password) throws IOException, 1255 NoSuchAlgorithmException, CertificateException { 1256 throw new UnsupportedOperationException("Can not serialize AndroidKeyStore to OutputStream"); 1257 } 1258 1259 @Override engineLoad(InputStream stream, char[] password)1260 public void engineLoad(InputStream stream, char[] password) throws IOException, 1261 NoSuchAlgorithmException, CertificateException { 1262 if (stream != null) { 1263 throw new IllegalArgumentException("InputStream not supported"); 1264 } 1265 1266 if (password != null) { 1267 throw new IllegalArgumentException("password not supported"); 1268 } 1269 1270 // Unfortunate name collision. 1271 mKeyStore = KeyStore2.getInstance(); 1272 mNamespace = KeyProperties.NAMESPACE_APPLICATION; 1273 } 1274 1275 @Override engineLoad(LoadStoreParameter param)1276 public void engineLoad(LoadStoreParameter param) throws IOException, 1277 NoSuchAlgorithmException, CertificateException { 1278 @KeyProperties.Namespace int namespace = KeyProperties.NAMESPACE_APPLICATION; 1279 if (param != null) { 1280 if (param instanceof AndroidKeyStoreLoadStoreParameter) { 1281 namespace = ((AndroidKeyStoreLoadStoreParameter) param).getNamespace(); 1282 } else { 1283 throw new IllegalArgumentException( 1284 "Unsupported param type: " + param.getClass()); 1285 } 1286 } 1287 mKeyStore = KeyStore2.getInstance(); 1288 mNamespace = namespace; 1289 } 1290 1291 @Override engineSetEntry(String alias, Entry entry, ProtectionParameter param)1292 public void engineSetEntry(String alias, Entry entry, ProtectionParameter param) 1293 throws KeyStoreException { 1294 if (entry == null) { 1295 throw new KeyStoreException("entry == null"); 1296 } 1297 1298 if (entry instanceof java.security.KeyStore.TrustedCertificateEntry) { 1299 java.security.KeyStore.TrustedCertificateEntry trE = 1300 (java.security.KeyStore.TrustedCertificateEntry) entry; 1301 // engineSetCertificateEntry does not overwrite if the existing entry 1302 // is a key entry, but the semantic of engineSetEntry is such that it 1303 // overwrites any existing entry. Thus we delete any possible existing 1304 // entry by this alias. 1305 engineDeleteEntry(alias); 1306 engineSetCertificateEntry(alias, trE.getTrustedCertificate()); 1307 return; 1308 } 1309 1310 if (entry instanceof PrivateKeyEntry) { 1311 PrivateKeyEntry prE = (PrivateKeyEntry) entry; 1312 setPrivateKeyEntry(alias, prE.getPrivateKey(), prE.getCertificateChain(), param); 1313 } else if (entry instanceof SecretKeyEntry) { 1314 SecretKeyEntry secE = (SecretKeyEntry) entry; 1315 setSecretKeyEntry(alias, secE.getSecretKey(), param); 1316 } else if (entry instanceof WrappedKeyEntry) { 1317 WrappedKeyEntry wke = (WrappedKeyEntry) entry; 1318 setWrappedKeyEntry(alias, wke, param); 1319 } else { 1320 throw new KeyStoreException( 1321 "Entry must be a PrivateKeyEntry, SecretKeyEntry, WrappedKeyEntry " 1322 + "or TrustedCertificateEntry; was " + entry); 1323 } 1324 } 1325 1326 private class KeyEntriesEnumerator implements Enumeration<String> { 1327 private KeyDescriptor[] mCurrentBatch; 1328 private int mCurrentEntry = 0; 1329 private String mLastAlias = null; KeyEntriesEnumerator()1330 private KeyEntriesEnumerator() { 1331 getAndValidateNextBatch(); 1332 } 1333 getAndValidateNextBatch()1334 private void getAndValidateNextBatch() { 1335 mCurrentBatch = getAliasesBatch(mLastAlias); 1336 mCurrentEntry = 0; 1337 } 1338 hasMoreElements()1339 public boolean hasMoreElements() { 1340 return (mCurrentBatch != null) && (mCurrentBatch.length > 0); 1341 } 1342 nextElement()1343 public String nextElement() { 1344 if ((mCurrentBatch == null) || (mCurrentBatch.length == 0)) { 1345 throw new NoSuchElementException("Error while fetching entries."); 1346 } 1347 final KeyDescriptor currentEntry = mCurrentBatch[mCurrentEntry]; 1348 mLastAlias = currentEntry.alias; 1349 1350 mCurrentEntry++; 1351 // This was the last entry in the batch. 1352 if (mCurrentEntry >= mCurrentBatch.length) { 1353 getAndValidateNextBatch(); 1354 } 1355 1356 return mLastAlias; 1357 } 1358 } 1359 } 1360