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