• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.keystore;
18 
19 import android.annotation.Nullable;
20 import android.security.Credentials;
21 import android.security.GateKeeper;
22 import android.security.KeyPairGeneratorSpec;
23 import android.security.KeyStore;
24 import android.security.KeyStoreException;
25 import android.security.keymaster.KeyCharacteristics;
26 import android.security.keymaster.KeymasterArguments;
27 import android.security.keymaster.KeymasterCertificateChain;
28 import android.security.keymaster.KeymasterDefs;
29 
30 import com.android.org.bouncycastle.asn1.ASN1EncodableVector;
31 import com.android.org.bouncycastle.asn1.ASN1InputStream;
32 import com.android.org.bouncycastle.asn1.ASN1Integer;
33 import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
34 import com.android.org.bouncycastle.asn1.DERBitString;
35 import com.android.org.bouncycastle.asn1.DERInteger;
36 import com.android.org.bouncycastle.asn1.DERNull;
37 import com.android.org.bouncycastle.asn1.DERSequence;
38 import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
39 import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
40 import com.android.org.bouncycastle.asn1.x509.Certificate;
41 import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
42 import com.android.org.bouncycastle.asn1.x509.TBSCertificate;
43 import com.android.org.bouncycastle.asn1.x509.Time;
44 import com.android.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
45 import com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
46 import com.android.org.bouncycastle.jce.X509Principal;
47 import com.android.org.bouncycastle.jce.provider.X509CertificateObject;
48 import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
49 
50 import libcore.util.EmptyArray;
51 
52 import java.io.ByteArrayOutputStream;
53 import java.io.IOException;
54 import java.math.BigInteger;
55 import java.security.InvalidAlgorithmParameterException;
56 import java.security.KeyPair;
57 import java.security.KeyPairGenerator;
58 import java.security.KeyPairGeneratorSpi;
59 import java.security.PrivateKey;
60 import java.security.ProviderException;
61 import java.security.PublicKey;
62 import java.security.SecureRandom;
63 import java.security.UnrecoverableKeyException;
64 import java.security.cert.CertificateEncodingException;
65 import java.security.cert.CertificateParsingException;
66 import java.security.cert.X509Certificate;
67 import java.security.spec.AlgorithmParameterSpec;
68 import java.security.spec.ECGenParameterSpec;
69 import java.security.spec.RSAKeyGenParameterSpec;
70 import java.util.ArrayList;
71 import java.util.Collection;
72 import java.util.Collections;
73 import java.util.HashMap;
74 import java.util.HashSet;
75 import java.util.Iterator;
76 import java.util.List;
77 import java.util.Locale;
78 import java.util.Map;
79 import java.util.Set;
80 
81 /**
82  * Provides a way to create instances of a KeyPair which will be placed in the
83  * Android keystore service usable only by the application that called it. This
84  * can be used in conjunction with
85  * {@link java.security.KeyStore#getInstance(String)} using the
86  * {@code "AndroidKeyStore"} type.
87  * <p>
88  * This class can not be directly instantiated and must instead be used via the
89  * {@link KeyPairGenerator#getInstance(String)
90  * KeyPairGenerator.getInstance("AndroidKeyStore")} API.
91  *
92  * @hide
93  */
94 public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
95 
96     public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi {
RSA()97         public RSA() {
98             super(KeymasterDefs.KM_ALGORITHM_RSA);
99         }
100     }
101 
102     public static class EC extends AndroidKeyStoreKeyPairGeneratorSpi {
EC()103         public EC() {
104             super(KeymasterDefs.KM_ALGORITHM_EC);
105         }
106     }
107 
108     /*
109      * These must be kept in sync with system/security/keystore/defaults.h
110      */
111 
112     /* EC */
113     private static final int EC_DEFAULT_KEY_SIZE = 256;
114 
115     /* RSA */
116     private static final int RSA_DEFAULT_KEY_SIZE = 2048;
117     private static final int RSA_MIN_KEY_SIZE = 512;
118     private static final int RSA_MAX_KEY_SIZE = 8192;
119 
120     private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE =
121             new HashMap<String, Integer>();
122     private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>();
123     private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>();
124     static {
125         // Aliases for NIST P-224
126         SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224);
127         SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
128 
129 
130         // Aliases for NIST P-256
131         SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256);
132         SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
133         SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
134 
135         // Aliases for NIST P-384
136         SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384);
137         SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384);
138 
139         // Aliases for NIST P-521
140         SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521);
141         SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521);
142 
SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet()143         SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
144         Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
145 
SUPPORTED_EC_NIST_CURVE_SIZES.addAll( new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values()))146         SUPPORTED_EC_NIST_CURVE_SIZES.addAll(
147                 new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values()));
148         Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES);
149     }
150 
151     private final int mOriginalKeymasterAlgorithm;
152 
153     private KeyStore mKeyStore;
154 
155     private KeyGenParameterSpec mSpec;
156 
157     private String mEntryAlias;
158     private int mEntryUid;
159     private boolean mEncryptionAtRestRequired;
160     private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
161     private int mKeymasterAlgorithm = -1;
162     private int mKeySizeBits;
163     private SecureRandom mRng;
164 
165     private int[] mKeymasterPurposes;
166     private int[] mKeymasterBlockModes;
167     private int[] mKeymasterEncryptionPaddings;
168     private int[] mKeymasterSignaturePaddings;
169     private int[] mKeymasterDigests;
170 
171     private BigInteger mRSAPublicExponent;
172 
AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm)173     protected AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm) {
174         mOriginalKeymasterAlgorithm = keymasterAlgorithm;
175     }
176 
177     @SuppressWarnings("deprecation")
178     @Override
initialize(int keysize, SecureRandom random)179     public void initialize(int keysize, SecureRandom random) {
180         throw new IllegalArgumentException(
181                 KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName()
182                 + " required to initialize this KeyPairGenerator");
183     }
184 
185     @SuppressWarnings("deprecation")
186     @Override
initialize(AlgorithmParameterSpec params, SecureRandom random)187     public void initialize(AlgorithmParameterSpec params, SecureRandom random)
188             throws InvalidAlgorithmParameterException {
189         resetAll();
190 
191         boolean success = false;
192         try {
193             if (params == null) {
194                 throw new InvalidAlgorithmParameterException(
195                         "Must supply params of type " + KeyGenParameterSpec.class.getName()
196                         + " or " + KeyPairGeneratorSpec.class.getName());
197             }
198 
199             KeyGenParameterSpec spec;
200             boolean encryptionAtRestRequired = false;
201             int keymasterAlgorithm = mOriginalKeymasterAlgorithm;
202             if (params instanceof KeyGenParameterSpec) {
203                 spec = (KeyGenParameterSpec) params;
204             } else if (params instanceof KeyPairGeneratorSpec) {
205                 // Legacy/deprecated spec
206                 KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
207                 try {
208                     KeyGenParameterSpec.Builder specBuilder;
209                     String specKeyAlgorithm = legacySpec.getKeyType();
210                     if (specKeyAlgorithm != null) {
211                         // Spec overrides the generator's default key algorithm
212                         try {
213                             keymasterAlgorithm =
214                                     KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
215                                             specKeyAlgorithm);
216                         } catch (IllegalArgumentException e) {
217                             throw new InvalidAlgorithmParameterException(
218                                     "Invalid key type in parameters", e);
219                         }
220                     }
221                     switch (keymasterAlgorithm) {
222                         case KeymasterDefs.KM_ALGORITHM_EC:
223                             specBuilder = new KeyGenParameterSpec.Builder(
224                                     legacySpec.getKeystoreAlias(),
225                                     KeyProperties.PURPOSE_SIGN
226                                     | KeyProperties.PURPOSE_VERIFY);
227                             // Authorized to be used with any digest (including no digest).
228                             // MD5 was never offered for Android Keystore for ECDSA.
229                             specBuilder.setDigests(
230                                     KeyProperties.DIGEST_NONE,
231                                     KeyProperties.DIGEST_SHA1,
232                                     KeyProperties.DIGEST_SHA224,
233                                     KeyProperties.DIGEST_SHA256,
234                                     KeyProperties.DIGEST_SHA384,
235                                     KeyProperties.DIGEST_SHA512);
236                             break;
237                         case KeymasterDefs.KM_ALGORITHM_RSA:
238                             specBuilder = new KeyGenParameterSpec.Builder(
239                                     legacySpec.getKeystoreAlias(),
240                                     KeyProperties.PURPOSE_ENCRYPT
241                                     | KeyProperties.PURPOSE_DECRYPT
242                                     | KeyProperties.PURPOSE_SIGN
243                                     | KeyProperties.PURPOSE_VERIFY);
244                             // Authorized to be used with any digest (including no digest).
245                             specBuilder.setDigests(
246                                     KeyProperties.DIGEST_NONE,
247                                     KeyProperties.DIGEST_MD5,
248                                     KeyProperties.DIGEST_SHA1,
249                                     KeyProperties.DIGEST_SHA224,
250                                     KeyProperties.DIGEST_SHA256,
251                                     KeyProperties.DIGEST_SHA384,
252                                     KeyProperties.DIGEST_SHA512);
253                             // Authorized to be used with any encryption and signature padding
254                             // schemes (including no padding).
255                             specBuilder.setEncryptionPaddings(
256                                     KeyProperties.ENCRYPTION_PADDING_NONE,
257                                     KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
258                                     KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
259                             specBuilder.setSignaturePaddings(
260                                     KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
261                                     KeyProperties.SIGNATURE_PADDING_RSA_PSS);
262                             // Disable randomized encryption requirement to support encryption
263                             // padding NONE above.
264                             specBuilder.setRandomizedEncryptionRequired(false);
265                             break;
266                         default:
267                             throw new ProviderException(
268                                     "Unsupported algorithm: " + mKeymasterAlgorithm);
269                     }
270 
271                     if (legacySpec.getKeySize() != -1) {
272                         specBuilder.setKeySize(legacySpec.getKeySize());
273                     }
274                     if (legacySpec.getAlgorithmParameterSpec() != null) {
275                         specBuilder.setAlgorithmParameterSpec(
276                                 legacySpec.getAlgorithmParameterSpec());
277                     }
278                     specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
279                     specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
280                     specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
281                     specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
282                     encryptionAtRestRequired = legacySpec.isEncryptionRequired();
283                     specBuilder.setUserAuthenticationRequired(false);
284 
285                     spec = specBuilder.build();
286                 } catch (NullPointerException | IllegalArgumentException e) {
287                     throw new InvalidAlgorithmParameterException(e);
288                 }
289             } else {
290                 throw new InvalidAlgorithmParameterException(
291                         "Unsupported params class: " + params.getClass().getName()
292                         + ". Supported: " + KeyGenParameterSpec.class.getName()
293                         + ", " + KeyPairGeneratorSpec.class.getName());
294             }
295 
296             mEntryAlias = spec.getKeystoreAlias();
297             mEntryUid = spec.getUid();
298             mSpec = spec;
299             mKeymasterAlgorithm = keymasterAlgorithm;
300             mEncryptionAtRestRequired = encryptionAtRestRequired;
301             mKeySizeBits = spec.getKeySize();
302             initAlgorithmSpecificParameters();
303             if (mKeySizeBits == -1) {
304                 mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
305             }
306             checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked());
307 
308             if (spec.getKeystoreAlias() == null) {
309                 throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
310             }
311 
312             String jcaKeyAlgorithm;
313             try {
314                 jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
315                         keymasterAlgorithm);
316                 mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
317                 mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
318                 mKeymasterEncryptionPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
319                         spec.getEncryptionPaddings());
320                 if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
321                         && (spec.isRandomizedEncryptionRequired())) {
322                     for (int keymasterPadding : mKeymasterEncryptionPaddings) {
323                         if (!KeymasterUtils
324                                 .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
325                                         keymasterPadding)) {
326                             throw new InvalidAlgorithmParameterException(
327                                     "Randomized encryption (IND-CPA) required but may be violated"
328                                     + " by padding scheme: "
329                                     + KeyProperties.EncryptionPadding.fromKeymaster(
330                                             keymasterPadding)
331                                     + ". See " + KeyGenParameterSpec.class.getName()
332                                     + " documentation.");
333                         }
334                     }
335                 }
336                 mKeymasterSignaturePaddings = KeyProperties.SignaturePadding.allToKeymaster(
337                         spec.getSignaturePaddings());
338                 if (spec.isDigestsSpecified()) {
339                     mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
340                 } else {
341                     mKeymasterDigests = EmptyArray.INT;
342                 }
343 
344                 // Check that user authentication related parameters are acceptable. This method
345                 // will throw an IllegalStateException if there are issues (e.g., secure lock screen
346                 // not set up).
347                 KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
348             } catch (IllegalArgumentException | IllegalStateException e) {
349                 throw new InvalidAlgorithmParameterException(e);
350             }
351 
352             mJcaKeyAlgorithm = jcaKeyAlgorithm;
353             mRng = random;
354             mKeyStore = KeyStore.getInstance();
355             success = true;
356         } finally {
357             if (!success) {
358                 resetAll();
359             }
360         }
361     }
362 
resetAll()363     private void resetAll() {
364         mEntryAlias = null;
365         mEntryUid = KeyStore.UID_SELF;
366         mJcaKeyAlgorithm = null;
367         mKeymasterAlgorithm = -1;
368         mKeymasterPurposes = null;
369         mKeymasterBlockModes = null;
370         mKeymasterEncryptionPaddings = null;
371         mKeymasterSignaturePaddings = null;
372         mKeymasterDigests = null;
373         mKeySizeBits = 0;
374         mSpec = null;
375         mRSAPublicExponent = null;
376         mEncryptionAtRestRequired = false;
377         mRng = null;
378         mKeyStore = null;
379     }
380 
initAlgorithmSpecificParameters()381     private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException {
382         AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec();
383         switch (mKeymasterAlgorithm) {
384             case KeymasterDefs.KM_ALGORITHM_RSA:
385             {
386                 BigInteger publicExponent = null;
387                 if (algSpecificSpec instanceof RSAKeyGenParameterSpec) {
388                     RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec;
389                     if (mKeySizeBits == -1) {
390                         mKeySizeBits = rsaSpec.getKeysize();
391                     } else if (mKeySizeBits != rsaSpec.getKeysize()) {
392                         throw new InvalidAlgorithmParameterException("RSA key size must match "
393                                 + " between " + mSpec + " and " + algSpecificSpec
394                                 + ": " + mKeySizeBits + " vs " + rsaSpec.getKeysize());
395                     }
396                     publicExponent = rsaSpec.getPublicExponent();
397                 } else if (algSpecificSpec != null) {
398                     throw new InvalidAlgorithmParameterException(
399                         "RSA may only use RSAKeyGenParameterSpec");
400                 }
401                 if (publicExponent == null) {
402                     publicExponent = RSAKeyGenParameterSpec.F4;
403                 }
404                 if (publicExponent.compareTo(BigInteger.ZERO) < 1) {
405                     throw new InvalidAlgorithmParameterException(
406                             "RSA public exponent must be positive: " + publicExponent);
407                 }
408                 if (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0) {
409                     throw new InvalidAlgorithmParameterException(
410                             "Unsupported RSA public exponent: " + publicExponent
411                             + ". Maximum supported value: " + KeymasterArguments.UINT64_MAX_VALUE);
412                 }
413                 mRSAPublicExponent = publicExponent;
414                 break;
415             }
416             case KeymasterDefs.KM_ALGORITHM_EC:
417                 if (algSpecificSpec instanceof ECGenParameterSpec) {
418                     ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
419                     String curveName = ecSpec.getName();
420                     Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get(
421                             curveName.toLowerCase(Locale.US));
422                     if (ecSpecKeySizeBits == null) {
423                         throw new InvalidAlgorithmParameterException(
424                                 "Unsupported EC curve name: " + curveName
425                                 + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES);
426                     }
427                     if (mKeySizeBits == -1) {
428                         mKeySizeBits = ecSpecKeySizeBits;
429                     } else if (mKeySizeBits != ecSpecKeySizeBits) {
430                         throw new InvalidAlgorithmParameterException("EC key size must match "
431                                 + " between " + mSpec + " and " + algSpecificSpec
432                                 + ": " + mKeySizeBits + " vs " + ecSpecKeySizeBits);
433                     }
434                 } else if (algSpecificSpec != null) {
435                     throw new InvalidAlgorithmParameterException(
436                         "EC may only use ECGenParameterSpec");
437                 }
438                 break;
439             default:
440                 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
441         }
442     }
443 
444     @Override
generateKeyPair()445     public KeyPair generateKeyPair() {
446         if (mKeyStore == null || mSpec == null) {
447             throw new IllegalStateException("Not initialized");
448         }
449 
450         int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
451         if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
452                 && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
453             throw new IllegalStateException(
454                     "Encryption at rest using secure lock screen credential requested for key pair"
455                     + ", but the user has not yet entered the credential");
456         }
457 
458         if (mSpec.isStrongBoxBacked()) {
459             flags |= KeyStore.FLAG_STRONGBOX;
460         }
461 
462         byte[] additionalEntropy =
463                 KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
464                         mRng, (mKeySizeBits + 7) / 8);
465 
466         Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
467         final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
468         boolean success = false;
469         try {
470             generateKeystoreKeyPair(
471                     privateKeyAlias, constructKeyGenerationArguments(), additionalEntropy, flags);
472             KeyPair keyPair = loadKeystoreKeyPair(privateKeyAlias);
473 
474             storeCertificateChain(flags, createCertificateChain(privateKeyAlias, keyPair));
475 
476             success = true;
477             return keyPair;
478         } catch (ProviderException e) {
479           if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
480               throw new SecureKeyImportUnavailableException(e);
481           } else {
482               throw e;
483           }
484         } finally {
485             if (!success) {
486                 Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
487             }
488         }
489     }
490 
createCertificateChain(final String privateKeyAlias, KeyPair keyPair)491     private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
492             throws ProviderException {
493         byte[] challenge = mSpec.getAttestationChallenge();
494         if (challenge != null) {
495             KeymasterArguments args = new KeymasterArguments();
496             args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge);
497             return getAttestationChain(privateKeyAlias, keyPair, args);
498         }
499 
500         // Very short certificate chain in the non-attestation case.
501         return Collections.singleton(generateSelfSignedCertificateBytes(keyPair));
502     }
503 
generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args, byte[] additionalEntropy, final int flags)504     private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args,
505             byte[] additionalEntropy, final int flags) throws ProviderException {
506         KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
507         int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy,
508                 mEntryUid, flags, resultingKeyCharacteristics);
509         if (errorCode != KeyStore.NO_ERROR) {
510             if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
511                 throw new StrongBoxUnavailableException("Failed to generate key pair");
512             } else {
513                 throw new ProviderException(
514                         "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
515             }
516         }
517     }
518 
loadKeystoreKeyPair(final String privateKeyAlias)519     private KeyPair loadKeystoreKeyPair(final String privateKeyAlias) throws ProviderException {
520         try {
521             KeyPair result  = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
522                     mKeyStore, privateKeyAlias, mEntryUid);
523             if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
524                 throw new ProviderException(
525                         "Generated key pair algorithm does not match requested algorithm: "
526                                 + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
527             }
528             return result;
529         } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
530             throw new ProviderException("Failed to load generated key pair from keystore", e);
531         }
532     }
533 
constructKeyGenerationArguments()534     private KeymasterArguments constructKeyGenerationArguments() {
535         KeymasterArguments args = new KeymasterArguments();
536         args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
537         args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
538         args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
539         args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
540         args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterEncryptionPaddings);
541         args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
542         args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
543 
544         KeymasterUtils.addUserAuthArgs(args, mSpec);
545         args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
546         args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
547                 mSpec.getKeyValidityForOriginationEnd());
548         args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
549                 mSpec.getKeyValidityForConsumptionEnd());
550         addAlgorithmSpecificParameters(args);
551 
552         if (mSpec.isUniqueIdIncluded())
553             args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);
554 
555         return args;
556     }
557 
storeCertificateChain(final int flags, Iterable<byte[]> iterable)558     private void storeCertificateChain(final int flags, Iterable<byte[]> iterable)
559             throws ProviderException {
560         Iterator<byte[]> iter = iterable.iterator();
561         storeCertificate(
562                 Credentials.USER_CERTIFICATE, iter.next(), flags, "Failed to store certificate");
563 
564         if (!iter.hasNext()) {
565             return;
566         }
567 
568         ByteArrayOutputStream certificateConcatenationStream = new ByteArrayOutputStream();
569         while (iter.hasNext()) {
570             byte[] data = iter.next();
571             certificateConcatenationStream.write(data, 0, data.length);
572         }
573 
574         storeCertificate(Credentials.CA_CERTIFICATE, certificateConcatenationStream.toByteArray(),
575                 flags, "Failed to store attestation CA certificate");
576     }
577 
storeCertificate(String prefix, byte[] certificateBytes, final int flags, String failureMessage)578     private void storeCertificate(String prefix, byte[] certificateBytes, final int flags,
579             String failureMessage) throws ProviderException {
580         int insertErrorCode = mKeyStore.insert(
581                 prefix + mEntryAlias,
582                 certificateBytes,
583                 mEntryUid,
584                 flags);
585         if (insertErrorCode != KeyStore.NO_ERROR) {
586             throw new ProviderException(failureMessage,
587                     KeyStore.getKeyStoreException(insertErrorCode));
588         }
589     }
590 
generateSelfSignedCertificateBytes(KeyPair keyPair)591     private byte[] generateSelfSignedCertificateBytes(KeyPair keyPair) throws ProviderException {
592         try {
593             return generateSelfSignedCertificate(keyPair.getPrivate(), keyPair.getPublic())
594                     .getEncoded();
595         } catch (IOException | CertificateParsingException e) {
596             throw new ProviderException("Failed to generate self-signed certificate", e);
597         } catch (CertificateEncodingException e) {
598             throw new ProviderException(
599                     "Failed to obtain encoded form of self-signed certificate", e);
600         }
601     }
602 
getAttestationChain(String privateKeyAlias, KeyPair keyPair, KeymasterArguments args)603     private Iterable<byte[]> getAttestationChain(String privateKeyAlias,
604             KeyPair keyPair, KeymasterArguments args)
605                     throws ProviderException {
606         KeymasterCertificateChain outChain = new KeymasterCertificateChain();
607         int errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain);
608         if (errorCode != KeyStore.NO_ERROR) {
609             throw new ProviderException("Failed to generate attestation certificate chain",
610                     KeyStore.getKeyStoreException(errorCode));
611         }
612         Collection<byte[]> chain = outChain.getCertificates();
613         if (chain.size() < 2) {
614             throw new ProviderException("Attestation certificate chain contained "
615                     + chain.size() + " entries. At least two are required.");
616         }
617         return chain;
618     }
619 
addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs)620     private void addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs) {
621         switch (mKeymasterAlgorithm) {
622             case KeymasterDefs.KM_ALGORITHM_RSA:
623                 keymasterArgs.addUnsignedLong(
624                         KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, mRSAPublicExponent);
625                 break;
626             case KeymasterDefs.KM_ALGORITHM_EC:
627                 break;
628             default:
629                 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
630         }
631     }
632 
generateSelfSignedCertificate(PrivateKey privateKey, PublicKey publicKey)633     private X509Certificate generateSelfSignedCertificate(PrivateKey privateKey,
634             PublicKey publicKey) throws CertificateParsingException, IOException {
635         String signatureAlgorithm =
636                 getCertificateSignatureAlgorithm(mKeymasterAlgorithm, mKeySizeBits, mSpec);
637         if (signatureAlgorithm == null) {
638             // Key cannot be used to sign a certificate
639             return generateSelfSignedCertificateWithFakeSignature(publicKey);
640         } else {
641             // Key can be used to sign a certificate
642             try {
643                 return generateSelfSignedCertificateWithValidSignature(
644                         privateKey, publicKey, signatureAlgorithm);
645             } catch (Exception e) {
646                 // Failed to generate the self-signed certificate with valid signature. Fall back
647                 // to generating a self-signed certificate with a fake signature. This is done for
648                 // all exception types because we prefer key pair generation to succeed and end up
649                 // producing a self-signed certificate with an invalid signature to key pair
650                 // generation failing.
651                 return generateSelfSignedCertificateWithFakeSignature(publicKey);
652             }
653         }
654     }
655 
656     @SuppressWarnings("deprecation")
generateSelfSignedCertificateWithValidSignature( PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm)657     private X509Certificate generateSelfSignedCertificateWithValidSignature(
658             PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm) throws Exception {
659         final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
660         certGen.setPublicKey(publicKey);
661         certGen.setSerialNumber(mSpec.getCertificateSerialNumber());
662         certGen.setSubjectDN(mSpec.getCertificateSubject());
663         certGen.setIssuerDN(mSpec.getCertificateSubject());
664         certGen.setNotBefore(mSpec.getCertificateNotBefore());
665         certGen.setNotAfter(mSpec.getCertificateNotAfter());
666         certGen.setSignatureAlgorithm(signatureAlgorithm);
667         return certGen.generate(privateKey);
668     }
669 
670     @SuppressWarnings("deprecation")
generateSelfSignedCertificateWithFakeSignature( PublicKey publicKey)671     private X509Certificate generateSelfSignedCertificateWithFakeSignature(
672             PublicKey publicKey) throws IOException, CertificateParsingException {
673         V3TBSCertificateGenerator tbsGenerator = new V3TBSCertificateGenerator();
674         ASN1ObjectIdentifier sigAlgOid;
675         AlgorithmIdentifier sigAlgId;
676         byte[] signature;
677         switch (mKeymasterAlgorithm) {
678             case KeymasterDefs.KM_ALGORITHM_EC:
679                 sigAlgOid = X9ObjectIdentifiers.ecdsa_with_SHA256;
680                 sigAlgId = new AlgorithmIdentifier(sigAlgOid);
681                 ASN1EncodableVector v = new ASN1EncodableVector();
682                 v.add(new DERInteger(0));
683                 v.add(new DERInteger(0));
684                 signature = new DERSequence().getEncoded();
685                 break;
686             case KeymasterDefs.KM_ALGORITHM_RSA:
687                 sigAlgOid = PKCSObjectIdentifiers.sha256WithRSAEncryption;
688                 sigAlgId = new AlgorithmIdentifier(sigAlgOid, DERNull.INSTANCE);
689                 signature = new byte[1];
690                 break;
691             default:
692                 throw new ProviderException("Unsupported key algorithm: " + mKeymasterAlgorithm);
693         }
694 
695         try (ASN1InputStream publicKeyInfoIn = new ASN1InputStream(publicKey.getEncoded())) {
696             tbsGenerator.setSubjectPublicKeyInfo(
697                     SubjectPublicKeyInfo.getInstance(publicKeyInfoIn.readObject()));
698         }
699         tbsGenerator.setSerialNumber(new ASN1Integer(mSpec.getCertificateSerialNumber()));
700         X509Principal subject =
701                 new X509Principal(mSpec.getCertificateSubject().getEncoded());
702         tbsGenerator.setSubject(subject);
703         tbsGenerator.setIssuer(subject);
704         tbsGenerator.setStartDate(new Time(mSpec.getCertificateNotBefore()));
705         tbsGenerator.setEndDate(new Time(mSpec.getCertificateNotAfter()));
706         tbsGenerator.setSignature(sigAlgId);
707         TBSCertificate tbsCertificate = tbsGenerator.generateTBSCertificate();
708 
709         ASN1EncodableVector result = new ASN1EncodableVector();
710         result.add(tbsCertificate);
711         result.add(sigAlgId);
712         result.add(new DERBitString(signature));
713         return new X509CertificateObject(Certificate.getInstance(new DERSequence(result)));
714     }
715 
getDefaultKeySize(int keymasterAlgorithm)716     private static int getDefaultKeySize(int keymasterAlgorithm) {
717         switch (keymasterAlgorithm) {
718             case KeymasterDefs.KM_ALGORITHM_EC:
719                 return EC_DEFAULT_KEY_SIZE;
720             case KeymasterDefs.KM_ALGORITHM_RSA:
721                 return RSA_DEFAULT_KEY_SIZE;
722             default:
723                 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
724         }
725     }
726 
checkValidKeySize( int keymasterAlgorithm, int keySize, boolean isStrongBoxBacked)727     private static void checkValidKeySize(
728             int keymasterAlgorithm,
729             int keySize,
730             boolean isStrongBoxBacked)
731             throws InvalidAlgorithmParameterException {
732         switch (keymasterAlgorithm) {
733             case KeymasterDefs.KM_ALGORITHM_EC:
734                 if (isStrongBoxBacked && keySize != 256) {
735                     throw new InvalidAlgorithmParameterException(
736                             "Unsupported StrongBox EC key size: "
737                             + keySize + " bits. Supported: 256");
738                 }
739                 if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) {
740                     throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
741                             + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES);
742                 }
743                 break;
744             case KeymasterDefs.KM_ALGORITHM_RSA:
745                 if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
746                     throw new InvalidAlgorithmParameterException("RSA key size must be >= "
747                             + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
748                 }
749                 break;
750             default:
751                 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
752         }
753     }
754 
755     /**
756      * Returns the {@code Signature} algorithm to be used for signing a certificate using the
757      * specified key or {@code null} if the key cannot be used for signing a certificate.
758      */
759     @Nullable
getCertificateSignatureAlgorithm( int keymasterAlgorithm, int keySizeBits, KeyGenParameterSpec spec)760     private static String getCertificateSignatureAlgorithm(
761             int keymasterAlgorithm,
762             int keySizeBits,
763             KeyGenParameterSpec spec) {
764         // Constraints:
765         // 1. Key must be authorized for signing without user authentication.
766         // 2. Signature digest must be one of key's authorized digests.
767         // 3. For RSA keys, the digest output size must not exceed modulus size minus space overhead
768         //    of RSA PKCS#1 signature padding scheme (about 30 bytes).
769         // 4. For EC keys, the there is no point in using a digest whose output size is longer than
770         //    key/field size because the digest will be truncated to that size.
771 
772         if ((spec.getPurposes() & KeyProperties.PURPOSE_SIGN) == 0) {
773             // Key not authorized for signing
774             return null;
775         }
776         if (spec.isUserAuthenticationRequired()) {
777             // Key not authorized for use without user authentication
778             return null;
779         }
780         if (!spec.isDigestsSpecified()) {
781             // Key not authorized for any digests -- can't sign
782             return null;
783         }
784         switch (keymasterAlgorithm) {
785             case KeymasterDefs.KM_ALGORITHM_EC:
786             {
787                 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
788                         spec.getDigests(),
789                         AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
790 
791                 int bestKeymasterDigest = -1;
792                 int bestDigestOutputSizeBits = -1;
793                 for (int keymasterDigest : availableKeymasterDigests) {
794                     int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
795                     if (outputSizeBits == keySizeBits) {
796                         // Perfect match -- use this digest
797                         bestKeymasterDigest = keymasterDigest;
798                         bestDigestOutputSizeBits = outputSizeBits;
799                         break;
800                     }
801                     // Not a perfect match -- check against the best digest so far
802                     if (bestKeymasterDigest == -1) {
803                         // First digest tested -- definitely the best so far
804                         bestKeymasterDigest = keymasterDigest;
805                         bestDigestOutputSizeBits = outputSizeBits;
806                     } else {
807                         // Prefer output size to be as close to key size as possible, with output
808                         // sizes larger than key size preferred to those smaller than key size.
809                         if (bestDigestOutputSizeBits < keySizeBits) {
810                             // Output size of the best digest so far is smaller than key size.
811                             // Anything larger is a win.
812                             if (outputSizeBits > bestDigestOutputSizeBits) {
813                                 bestKeymasterDigest = keymasterDigest;
814                                 bestDigestOutputSizeBits = outputSizeBits;
815                             }
816                         } else {
817                             // Output size of the best digest so far is larger than key size.
818                             // Anything smaller is a win, as long as it's not smaller than key size.
819                             if ((outputSizeBits < bestDigestOutputSizeBits)
820                                     && (outputSizeBits >= keySizeBits)) {
821                                 bestKeymasterDigest = keymasterDigest;
822                                 bestDigestOutputSizeBits = outputSizeBits;
823                             }
824                         }
825                     }
826                 }
827                 if (bestKeymasterDigest == -1) {
828                     return null;
829                 }
830                 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
831                         bestKeymasterDigest) + "WithECDSA";
832             }
833             case KeymasterDefs.KM_ALGORITHM_RSA:
834             {
835                 // Check whether this key is authorized for PKCS#1 signature padding.
836                 // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle
837                 // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs
838                 // to be authorized for PKCS#1 padding or padding NONE which means any padding.
839                 boolean pkcs1SignaturePaddingSupported =
840                         com.android.internal.util.ArrayUtils.contains(
841                                 KeyProperties.SignaturePadding.allToKeymaster(
842                                         spec.getSignaturePaddings()),
843                                 KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
844                 if (!pkcs1SignaturePaddingSupported) {
845                     // Key not authorized for PKCS#1 signature padding -- can't sign
846                     return null;
847                 }
848 
849                 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
850                         spec.getDigests(),
851                         AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
852 
853                 // The amount of space available for the digest is less than modulus size by about
854                 // 30 bytes because padding must be at least 11 bytes long (00 || 01 || PS || 00,
855                 // where PS must be at least 8 bytes long), and then there's also the 15--19 bytes
856                 // overhead (depending the on chosen digest) for encoding digest OID and digest
857                 // value in DER.
858                 int maxDigestOutputSizeBits = keySizeBits - 30 * 8;
859                 int bestKeymasterDigest = -1;
860                 int bestDigestOutputSizeBits = -1;
861                 for (int keymasterDigest : availableKeymasterDigests) {
862                     int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
863                     if (outputSizeBits > maxDigestOutputSizeBits) {
864                         // Digest too long (signature generation will fail) -- skip
865                         continue;
866                     }
867                     if (bestKeymasterDigest == -1) {
868                         // First digest tested -- definitely the best so far
869                         bestKeymasterDigest = keymasterDigest;
870                         bestDigestOutputSizeBits = outputSizeBits;
871                     } else {
872                         // The longer the better
873                         if (outputSizeBits > bestDigestOutputSizeBits) {
874                             bestKeymasterDigest = keymasterDigest;
875                             bestDigestOutputSizeBits = outputSizeBits;
876                         }
877                     }
878                 }
879                 if (bestKeymasterDigest == -1) {
880                     return null;
881                 }
882                 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
883                         bestKeymasterDigest) + "WithRSA";
884             }
885             default:
886                 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
887         }
888     }
889 
getAvailableKeymasterSignatureDigests( @eyProperties.DigestEnum String[] authorizedKeyDigests, @KeyProperties.DigestEnum String[] supportedSignatureDigests)890     private static Set<Integer> getAvailableKeymasterSignatureDigests(
891             @KeyProperties.DigestEnum String[] authorizedKeyDigests,
892             @KeyProperties.DigestEnum String[] supportedSignatureDigests) {
893         Set<Integer> authorizedKeymasterKeyDigests = new HashSet<Integer>();
894         for (int keymasterDigest : KeyProperties.Digest.allToKeymaster(authorizedKeyDigests)) {
895             authorizedKeymasterKeyDigests.add(keymasterDigest);
896         }
897         Set<Integer> supportedKeymasterSignatureDigests = new HashSet<Integer>();
898         for (int keymasterDigest
899                 : KeyProperties.Digest.allToKeymaster(supportedSignatureDigests)) {
900             supportedKeymasterSignatureDigests.add(keymasterDigest);
901         }
902         Set<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests);
903         result.retainAll(authorizedKeymasterKeyDigests);
904         return result;
905     }
906 }
907