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