• 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.keystore2;
18 
19 import static android.security.keystore2.AndroidKeyStoreCipherSpiBase.DEFAULT_MGF1_DIGEST;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.content.Context;
24 import android.hardware.security.keymint.EcCurve;
25 import android.hardware.security.keymint.KeyParameter;
26 import android.hardware.security.keymint.KeyPurpose;
27 import android.hardware.security.keymint.SecurityLevel;
28 import android.hardware.security.keymint.Tag;
29 import android.os.Build;
30 import android.os.StrictMode;
31 import android.security.Flags;
32 import android.security.KeyPairGeneratorSpec;
33 import android.security.KeyStore2;
34 import android.security.KeyStoreException;
35 import android.security.KeyStoreSecurityLevel;
36 import android.security.keymaster.KeymasterArguments;
37 import android.security.keymaster.KeymasterDefs;
38 import android.security.keystore.ArrayUtils;
39 import android.security.keystore.AttestationUtils;
40 import android.security.keystore.DeviceIdAttestationException;
41 import android.security.keystore.KeyGenParameterSpec;
42 import android.security.keystore.KeyProperties;
43 import android.security.keystore.SecureKeyImportUnavailableException;
44 import android.security.keystore.StrongBoxUnavailableException;
45 import android.system.keystore2.Authorization;
46 import android.system.keystore2.Domain;
47 import android.system.keystore2.IKeystoreSecurityLevel;
48 import android.system.keystore2.KeyDescriptor;
49 import android.system.keystore2.KeyEntryResponse;
50 import android.system.keystore2.KeyMetadata;
51 import android.system.keystore2.ResponseCode;
52 import android.telephony.TelephonyManager;
53 import android.text.TextUtils;
54 import android.util.ArraySet;
55 import android.util.Log;
56 
57 import libcore.util.EmptyArray;
58 
59 import java.math.BigInteger;
60 import java.nio.charset.StandardCharsets;
61 import java.security.InvalidAlgorithmParameterException;
62 import java.security.KeyPair;
63 import java.security.KeyPairGenerator;
64 import java.security.KeyPairGeneratorSpi;
65 import java.security.ProviderException;
66 import java.security.SecureRandom;
67 import java.security.UnrecoverableKeyException;
68 import java.security.spec.AlgorithmParameterSpec;
69 import java.security.spec.ECGenParameterSpec;
70 import java.security.spec.NamedParameterSpec;
71 import java.security.spec.RSAKeyGenParameterSpec;
72 import java.util.ArrayList;
73 import java.util.Arrays;
74 import java.util.Collection;
75 import java.util.Collections;
76 import java.util.HashMap;
77 import java.util.HashSet;
78 import java.util.List;
79 import java.util.Locale;
80 import java.util.Map;
81 import java.util.Set;
82 import java.util.function.Predicate;
83 
84 /**
85  * Provides a way to create instances of a KeyPair which will be placed in the
86  * Android keystore service usable only by the application that called it. This
87  * can be used in conjunction with
88  * {@link java.security.KeyStore#getInstance(String)} using the
89  * {@code "AndroidKeyStore"} type.
90  * <p>
91  * This class can not be directly instantiated and must instead be used via the
92  * {@link KeyPairGenerator#getInstance(String)
93  * KeyPairGenerator.getInstance("AndroidKeyStore")} API.
94  *
95  * @hide
96  */
97 public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
98     private static final String TAG = "AndroidKeyStoreKeyPairGeneratorSpi";
99 
100     public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi {
RSA()101         public RSA() {
102             super(KeymasterDefs.KM_ALGORITHM_RSA);
103         }
104     }
105 
106     public static class EC extends AndroidKeyStoreKeyPairGeneratorSpi {
EC()107         public EC() {
108             super(KeymasterDefs.KM_ALGORITHM_EC);
109         }
110     }
111 
112     // For curve 25519, KeyMint uses the KM_ALGORITHM_EC constant, but in the Java layer we need
113     // to distinguish between Curve 25519 and other EC algorithms, so we use a different constant
114     // with a value that is outside the range of the enum used for KeyMint algorithms.
115     private static final int ALGORITHM_XDH = KeymasterDefs.KM_ALGORITHM_EC + 1200;
116     private static final int ALGORITHM_ED25519 = ALGORITHM_XDH + 1;
117 
118     /**
119      * XDH represents Curve 25519 agreement key provider.
120      */
121     public static class XDH extends AndroidKeyStoreKeyPairGeneratorSpi {
122         // XDH is treated as EC.
XDH()123         public XDH() {
124             super(ALGORITHM_XDH);
125         }
126     }
127 
128     /**
129      * ED25519 represents Curve 25519 signing key provider.
130      */
131     public static class ED25519 extends AndroidKeyStoreKeyPairGeneratorSpi {
132         // ED25519 is treated as EC.
ED25519()133         public ED25519() {
134             super(ALGORITHM_ED25519);
135         }
136     }
137 
138     /*
139      * These must be kept in sync with system/security/keystore/defaults.h
140      */
141 
142     /* EC */
143     private static final int EC_DEFAULT_KEY_SIZE = 256;
144 
145     /* RSA */
146     private static final int RSA_DEFAULT_KEY_SIZE = 2048;
147     private static final int RSA_MIN_KEY_SIZE = 512;
148     private static final int RSA_MAX_KEY_SIZE = 8192;
149 
150     private static final Map<String, Integer> SUPPORTED_EC_CURVE_NAME_TO_SIZE =
151             new HashMap<String, Integer>();
152     private static final List<String> SUPPORTED_EC_CURVE_NAMES = new ArrayList<String>();
153     private static final List<Integer> SUPPORTED_EC_CURVE_SIZES = new ArrayList<Integer>();
154     private static final String CURVE_X_25519 = NamedParameterSpec.X25519.getName();
155     private static final String CURVE_ED_25519 = NamedParameterSpec.ED25519.getName();
156 
157 
158     static {
159         // Aliases for NIST P-224
160         SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-224", 224);
161         SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
162 
163 
164         // Aliases for NIST P-256
165         SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-256", 256);
166         SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
167         SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
168         // Aliases for Curve 25519
CURVE_X_25519.toLowerCase(Locale.US)169         SUPPORTED_EC_CURVE_NAME_TO_SIZE.put(CURVE_X_25519.toLowerCase(Locale.US), 256);
CURVE_ED_25519.toLowerCase(Locale.US)170         SUPPORTED_EC_CURVE_NAME_TO_SIZE.put(CURVE_ED_25519.toLowerCase(Locale.US), 256);
171 
172         // Aliases for NIST P-384
173         SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-384", 384);
174         SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp384r1", 384);
175 
176         // Aliases for NIST P-521
177         SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-521", 521);
178         SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp521r1", 521);
179 
SUPPORTED_EC_CURVE_NAME_TO_SIZE.keySet()180         SUPPORTED_EC_CURVE_NAMES.addAll(SUPPORTED_EC_CURVE_NAME_TO_SIZE.keySet());
181         Collections.sort(SUPPORTED_EC_CURVE_NAMES);
182 
SUPPORTED_EC_CURVE_SIZES.addAll( new HashSet<Integer>(SUPPORTED_EC_CURVE_NAME_TO_SIZE.values()))183         SUPPORTED_EC_CURVE_SIZES.addAll(
184                 new HashSet<Integer>(SUPPORTED_EC_CURVE_NAME_TO_SIZE.values()));
185         Collections.sort(SUPPORTED_EC_CURVE_SIZES);
186     }
187 
188     private final int mOriginalKeymasterAlgorithm;
189 
190     private KeyStore2 mKeyStore;
191 
192     private KeyGenParameterSpec mSpec;
193 
194     private String mEntryAlias;
195     private int mEntryNamespace;
196     private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
197     private int mKeymasterAlgorithm = -1;
198     private int mKeySizeBits;
199     private SecureRandom mRng;
200     private KeyDescriptor mAttestKeyDescriptor;
201     private String mEcCurveName;
202 
203     private int[] mKeymasterPurposes;
204     private int[] mKeymasterBlockModes;
205     private int[] mKeymasterEncryptionPaddings;
206     private int[] mKeymasterSignaturePaddings;
207     private int[] mKeymasterDigests;
208     private int[] mKeymasterMgf1Digests;
209 
210     private Long mRSAPublicExponent;
211 
AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm)212     protected AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm) {
213         mOriginalKeymasterAlgorithm = keymasterAlgorithm;
214     }
215 
keySizeAndNameToEcCurve(int keySizeBits, String ecCurveName)216     private static @EcCurve int keySizeAndNameToEcCurve(int keySizeBits, String ecCurveName)
217             throws InvalidAlgorithmParameterException {
218         switch (keySizeBits) {
219             case 224:
220                 return EcCurve.P_224;
221             case 256:
222                 if (isCurve25519(ecCurveName)) {
223                     return EcCurve.CURVE_25519;
224                 }
225                 return EcCurve.P_256;
226             case 384:
227                 return EcCurve.P_384;
228             case 521:
229                 return EcCurve.P_521;
230             default:
231                 throw new InvalidAlgorithmParameterException(
232                         "Unsupported EC curve keysize: " + keySizeBits);
233         }
234     }
235 
236     @SuppressWarnings("deprecation")
237     @Override
initialize(int keysize, SecureRandom random)238     public void initialize(int keysize, SecureRandom random) {
239         throw new IllegalArgumentException(
240                 KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName()
241                         + " required to initialize this KeyPairGenerator");
242     }
243 
244     @SuppressWarnings("deprecation")
245     @Override
initialize(AlgorithmParameterSpec params, SecureRandom random)246     public void initialize(AlgorithmParameterSpec params, SecureRandom random)
247             throws InvalidAlgorithmParameterException {
248         resetAll();
249 
250         boolean success = false;
251         try {
252             if (params == null) {
253                 throw new InvalidAlgorithmParameterException(
254                         "Must supply params of type " + KeyGenParameterSpec.class.getName()
255                                 + " or " + KeyPairGeneratorSpec.class.getName());
256             }
257 
258             KeyGenParameterSpec spec;
259             boolean encryptionAtRestRequired = false;
260             int keymasterAlgorithm = (mOriginalKeymasterAlgorithm == ALGORITHM_XDH
261                     || mOriginalKeymasterAlgorithm == ALGORITHM_ED25519)
262                     ? KeymasterDefs.KM_ALGORITHM_EC : mOriginalKeymasterAlgorithm;
263             if (params instanceof KeyGenParameterSpec) {
264                 spec = (KeyGenParameterSpec) params;
265             } else if (params instanceof KeyPairGeneratorSpec) {
266                 // Legacy/deprecated spec
267                 KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
268                 try {
269                     keymasterAlgorithm = getKeymasterAlgorithmFromLegacy(keymasterAlgorithm,
270                             legacySpec);
271                     spec = buildKeyGenParameterSpecFromLegacy(legacySpec, keymasterAlgorithm);
272                 } catch (NullPointerException | IllegalArgumentException e) {
273                     throw new InvalidAlgorithmParameterException(e);
274                 }
275             } else if (params instanceof NamedParameterSpec) {
276                 NamedParameterSpec namedSpec = (NamedParameterSpec) params;
277                 // Android Keystore cannot support initialization from a NamedParameterSpec
278                 // because an alias for the key is needed (a KeyGenParameterSpec cannot be
279                 // constructed).
280                 if (namedSpec.getName().equalsIgnoreCase(NamedParameterSpec.X25519.getName())
281                         || namedSpec.getName().equalsIgnoreCase(
282                         NamedParameterSpec.ED25519.getName())) {
283                     throw new IllegalArgumentException(
284                             "This KeyPairGenerator cannot be initialized using NamedParameterSpec."
285                                     + " use " + KeyGenParameterSpec.class.getName() + " or "
286                                     + KeyPairGeneratorSpec.class.getName());
287                 } else {
288                     throw new InvalidAlgorithmParameterException(
289                             "Unsupported algorithm specified via NamedParameterSpec: "
290                             + namedSpec.getName());
291                 }
292             } else {
293                 throw new InvalidAlgorithmParameterException(
294                         "Unsupported params class: " + params.getClass().getName()
295                                 + ". Supported: " + KeyGenParameterSpec.class.getName()
296                                 + ", " + KeyPairGeneratorSpec.class.getName());
297             }
298 
299             mEntryAlias = spec.getKeystoreAlias();
300             mEntryNamespace = spec.getNamespace();
301             mSpec = spec;
302             mKeymasterAlgorithm = keymasterAlgorithm;
303             mKeySizeBits = spec.getKeySize();
304             initAlgorithmSpecificParameters();
305             if (mKeySizeBits == -1) {
306                 mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
307             }
308             checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked(),
309                     mEcCurveName);
310 
311             if (spec.getKeystoreAlias() == null) {
312                 throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
313             }
314 
315             String jcaKeyAlgorithm;
316             try {
317                 jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
318                         keymasterAlgorithm);
319                 mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
320                 mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
321                 mKeymasterEncryptionPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
322                         spec.getEncryptionPaddings());
323                 if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
324                         && (spec.isRandomizedEncryptionRequired())) {
325                     for (int keymasterPadding : mKeymasterEncryptionPaddings) {
326                         if (!KeymasterUtils
327                                 .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
328                                         keymasterPadding)) {
329                             throw new InvalidAlgorithmParameterException(
330                                     "Randomized encryption (IND-CPA) required but may be violated"
331                                             + " by padding scheme: "
332                                             + KeyProperties.EncryptionPadding.fromKeymaster(
333                                             keymasterPadding)
334                                             + ". See " + KeyGenParameterSpec.class.getName()
335                                             + " documentation.");
336                         }
337                     }
338                 }
339                 mKeymasterSignaturePaddings = KeyProperties.SignaturePadding.allToKeymaster(
340                         spec.getSignaturePaddings());
341                 if (spec.isDigestsSpecified()) {
342                     mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
343                 } else {
344                     mKeymasterDigests = EmptyArray.INT;
345                 }
346                 if (spec.isMgf1DigestsSpecified()) {
347                     // User-specified digests: Add all of them and do _not_ add the SHA-1
348                     // digest by default (stick to what the user provided).
349                     Set<String> mgfDigests = spec.getMgf1Digests();
350                     mKeymasterMgf1Digests = new int[mgfDigests.size()];
351                     int offset = 0;
352                     for (String digest : mgfDigests) {
353                         mKeymasterMgf1Digests[offset] = KeyProperties.Digest.toKeymaster(digest);
354                         offset++;
355                     }
356                 } else {
357                     // No user-specified digests: Add the SHA-1 default.
358                     mKeymasterMgf1Digests = new int[]{
359                             KeyProperties.Digest.toKeymaster(DEFAULT_MGF1_DIGEST)};
360                 }
361 
362                 // Check that user authentication related parameters are acceptable. This method
363                 // will throw an IllegalStateException if there are issues (e.g., secure lock screen
364                 // not set up).
365                 KeyStore2ParameterUtils.addUserAuthArgs(new ArrayList<>(), mSpec);
366             } catch (IllegalArgumentException | IllegalStateException e) {
367                 throw new InvalidAlgorithmParameterException(e);
368             }
369 
370             mJcaKeyAlgorithm = jcaKeyAlgorithm;
371             mRng = random;
372             mKeyStore = KeyStore2.getInstance();
373 
374             mAttestKeyDescriptor = buildAndCheckAttestKeyDescriptor(spec);
375             checkAttestKeyPurpose(spec);
376             checkCorrectKeyPurposeForCurve(spec);
377 
378             success = true;
379         } finally {
380             if (!success) {
381                 resetAll();
382             }
383         }
384     }
385 
checkAttestKeyPurpose(KeyGenParameterSpec spec)386     private void checkAttestKeyPurpose(KeyGenParameterSpec spec)
387             throws InvalidAlgorithmParameterException {
388         if ((spec.getPurposes() & KeyProperties.PURPOSE_ATTEST_KEY) != 0
389                 && spec.getPurposes() != KeyProperties.PURPOSE_ATTEST_KEY) {
390             throw new InvalidAlgorithmParameterException(
391                     "PURPOSE_ATTEST_KEY may not be specified with any other purposes");
392         }
393     }
394 
checkCorrectKeyPurposeForCurve(KeyGenParameterSpec spec)395     private void checkCorrectKeyPurposeForCurve(KeyGenParameterSpec spec)
396             throws InvalidAlgorithmParameterException {
397         // Validate the key usage purposes against the curve. x25519 should be
398         // key exchange only, ed25519 signing and attesting.
399 
400         if (!isCurve25519(mEcCurveName)) {
401             return;
402         }
403 
404         if (mEcCurveName.equalsIgnoreCase(CURVE_X_25519)
405                 && spec.getPurposes() != KeyProperties.PURPOSE_AGREE_KEY) {
406             throw new InvalidAlgorithmParameterException(
407                     "x25519 may only be used for key agreement.");
408         } else if (mEcCurveName.equalsIgnoreCase(CURVE_ED_25519)
409                 && !hasOnlyAllowedPurposeForEd25519(spec.getPurposes())) {
410             throw new InvalidAlgorithmParameterException(
411                     "ed25519 may not be used for key agreement.");
412         }
413     }
414 
isCurve25519(String ecCurveName)415     private static boolean isCurve25519(String ecCurveName) {
416         if (ecCurveName == null) {
417             return false;
418         }
419         return ecCurveName.equalsIgnoreCase(CURVE_X_25519)
420                 || ecCurveName.equalsIgnoreCase(CURVE_ED_25519);
421     }
422 
hasOnlyAllowedPurposeForEd25519(@eyProperties.PurposeEnum int purpose)423     private static boolean hasOnlyAllowedPurposeForEd25519(@KeyProperties.PurposeEnum int purpose) {
424         final int allowedPurposes = KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY
425                 | KeyProperties.PURPOSE_ATTEST_KEY;
426         boolean hasAllowedPurpose = (purpose & allowedPurposes) != 0;
427         boolean hasDisallowedPurpose = (purpose & ~allowedPurposes) != 0;
428         return hasAllowedPurpose && !hasDisallowedPurpose;
429     }
430 
buildAndCheckAttestKeyDescriptor(KeyGenParameterSpec spec)431     private KeyDescriptor buildAndCheckAttestKeyDescriptor(KeyGenParameterSpec spec)
432             throws InvalidAlgorithmParameterException {
433         if (spec.getAttestKeyAlias() != null) {
434             KeyDescriptor attestKeyDescriptor = new KeyDescriptor();
435             attestKeyDescriptor.domain = Domain.APP;
436             attestKeyDescriptor.alias = spec.getAttestKeyAlias();
437             try {
438                 KeyEntryResponse attestKey = mKeyStore.getKeyEntry(attestKeyDescriptor);
439                 checkAttestKeyChallenge(spec);
440                 checkAttestKeyPurpose(attestKey.metadata.authorizations);
441                 checkAttestKeySecurityLevel(spec, attestKey);
442             } catch (KeyStoreException e) {
443                 throw new InvalidAlgorithmParameterException("Invalid attestKeyAlias", e);
444             }
445             return attestKeyDescriptor;
446         }
447         return null;
448     }
449 
checkAttestKeyChallenge(KeyGenParameterSpec spec)450     private void checkAttestKeyChallenge(KeyGenParameterSpec spec)
451             throws InvalidAlgorithmParameterException {
452         if (spec.getAttestationChallenge() == null) {
453             throw new InvalidAlgorithmParameterException(
454                     "AttestKey specified but no attestation challenge provided");
455         }
456     }
457 
checkAttestKeyPurpose(Authorization[] keyAuths)458     private void checkAttestKeyPurpose(Authorization[] keyAuths)
459             throws InvalidAlgorithmParameterException {
460         Predicate<Authorization> isAttestKeyPurpose = x -> x.keyParameter.tag == Tag.PURPOSE
461                 && x.keyParameter.value.getKeyPurpose() == KeyPurpose.ATTEST_KEY;
462 
463         if (Arrays.stream(keyAuths).noneMatch(isAttestKeyPurpose)) {
464             throw new InvalidAlgorithmParameterException(
465                     ("Invalid attestKey, does not have PURPOSE_ATTEST_KEY"));
466         }
467     }
468 
checkAttestKeySecurityLevel(KeyGenParameterSpec spec, KeyEntryResponse key)469     private void checkAttestKeySecurityLevel(KeyGenParameterSpec spec, KeyEntryResponse key)
470             throws InvalidAlgorithmParameterException {
471         boolean attestKeyInStrongBox = key.metadata.keySecurityLevel == SecurityLevel.STRONGBOX;
472         if (spec.isStrongBoxBacked() != attestKeyInStrongBox) {
473             if (attestKeyInStrongBox) {
474                 throw new InvalidAlgorithmParameterException(
475                         "Invalid security level: Cannot sign non-StrongBox key with "
476                                 + "StrongBox attestKey");
477 
478             } else {
479                 throw new InvalidAlgorithmParameterException(
480                         "Invalid security level: Cannot sign StrongBox key with "
481                                 + "non-StrongBox attestKey");
482             }
483         }
484     }
485 
getKeymasterAlgorithmFromLegacy(int keymasterAlgorithm, KeyPairGeneratorSpec legacySpec)486     private int getKeymasterAlgorithmFromLegacy(int keymasterAlgorithm,
487             KeyPairGeneratorSpec legacySpec) throws InvalidAlgorithmParameterException {
488         String specKeyAlgorithm = legacySpec.getKeyType();
489         if (specKeyAlgorithm != null) {
490             // Spec overrides the generator's default key algorithm
491             try {
492                 keymasterAlgorithm =
493                         KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
494                                 specKeyAlgorithm);
495             } catch (IllegalArgumentException e) {
496                 throw new InvalidAlgorithmParameterException(
497                         "Invalid key type in parameters", e);
498             }
499         }
500         return keymasterAlgorithm;
501     }
502 
buildKeyGenParameterSpecFromLegacy(KeyPairGeneratorSpec legacySpec, int keymasterAlgorithm)503     private KeyGenParameterSpec buildKeyGenParameterSpecFromLegacy(KeyPairGeneratorSpec legacySpec,
504             int keymasterAlgorithm) {
505         KeyGenParameterSpec.Builder specBuilder;
506         switch (keymasterAlgorithm) {
507             case KeymasterDefs.KM_ALGORITHM_EC:
508                 specBuilder = new KeyGenParameterSpec.Builder(
509                         legacySpec.getKeystoreAlias(),
510                         KeyProperties.PURPOSE_SIGN
511                                 | KeyProperties.PURPOSE_VERIFY);
512                 // Authorized to be used with any digest (including no digest).
513                 // MD5 was never offered for Android Keystore for ECDSA.
514                 specBuilder.setDigests(
515                         KeyProperties.DIGEST_NONE,
516                         KeyProperties.DIGEST_SHA1,
517                         KeyProperties.DIGEST_SHA224,
518                         KeyProperties.DIGEST_SHA256,
519                         KeyProperties.DIGEST_SHA384,
520                         KeyProperties.DIGEST_SHA512);
521                 break;
522             case KeymasterDefs.KM_ALGORITHM_RSA:
523                 specBuilder = new KeyGenParameterSpec.Builder(
524                         legacySpec.getKeystoreAlias(),
525                         KeyProperties.PURPOSE_ENCRYPT
526                                 | KeyProperties.PURPOSE_DECRYPT
527                                 | KeyProperties.PURPOSE_SIGN
528                                 | KeyProperties.PURPOSE_VERIFY);
529                 // Authorized to be used with any digest (including no digest).
530                 specBuilder.setDigests(
531                         KeyProperties.DIGEST_NONE,
532                         KeyProperties.DIGEST_MD5,
533                         KeyProperties.DIGEST_SHA1,
534                         KeyProperties.DIGEST_SHA224,
535                         KeyProperties.DIGEST_SHA256,
536                         KeyProperties.DIGEST_SHA384,
537                         KeyProperties.DIGEST_SHA512);
538                 // Authorized to be used with any encryption and signature padding
539                 // schemes (including no padding).
540                 specBuilder.setEncryptionPaddings(
541                         KeyProperties.ENCRYPTION_PADDING_NONE,
542                         KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
543                         KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
544                 specBuilder.setSignaturePaddings(
545                         KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
546                         KeyProperties.SIGNATURE_PADDING_RSA_PSS);
547                 // Disable randomized encryption requirement to support encryption
548                 // padding NONE above.
549                 specBuilder.setRandomizedEncryptionRequired(false);
550                 break;
551             default:
552                 throw new ProviderException(
553                         "Unsupported algorithm: " + mKeymasterAlgorithm);
554         }
555 
556         if (legacySpec.getKeySize() != -1) {
557             specBuilder.setKeySize(legacySpec.getKeySize());
558         }
559         if (legacySpec.getAlgorithmParameterSpec() != null) {
560             specBuilder.setAlgorithmParameterSpec(
561                     legacySpec.getAlgorithmParameterSpec());
562         }
563         specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
564         specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
565         specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
566         specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
567         specBuilder.setUserAuthenticationRequired(false);
568 
569         return specBuilder.build();
570     }
571 
resetAll()572     private void resetAll() {
573         mEntryAlias = null;
574         mEntryNamespace = KeyProperties.NAMESPACE_APPLICATION;
575         mJcaKeyAlgorithm = null;
576         mKeymasterAlgorithm = -1;
577         mKeymasterPurposes = null;
578         mKeymasterBlockModes = null;
579         mKeymasterEncryptionPaddings = null;
580         mKeymasterSignaturePaddings = null;
581         mKeymasterDigests = null;
582         mKeymasterMgf1Digests = null;
583         mKeySizeBits = 0;
584         mSpec = null;
585         mRSAPublicExponent = null;
586         mRng = null;
587         mKeyStore = null;
588         mEcCurveName = null;
589     }
590 
initAlgorithmSpecificParameters()591     private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException {
592         AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec();
593         switch (mKeymasterAlgorithm) {
594             case KeymasterDefs.KM_ALGORITHM_RSA: {
595                 BigInteger publicExponent = null;
596                 if (algSpecificSpec instanceof RSAKeyGenParameterSpec) {
597                     RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec;
598                     if (mKeySizeBits == -1) {
599                         mKeySizeBits = rsaSpec.getKeysize();
600                     } else if (mKeySizeBits != rsaSpec.getKeysize()) {
601                         throw new InvalidAlgorithmParameterException("RSA key size must match "
602                                 + " between " + mSpec + " and " + algSpecificSpec
603                                 + ": " + mKeySizeBits + " vs " + rsaSpec.getKeysize());
604                     }
605                     publicExponent = rsaSpec.getPublicExponent();
606                 } else if (algSpecificSpec != null) {
607                     throw new InvalidAlgorithmParameterException(
608                             "RSA may only use RSAKeyGenParameterSpec");
609                 }
610                 if (publicExponent == null) {
611                     publicExponent = RSAKeyGenParameterSpec.F4;
612                 }
613                 if (publicExponent.compareTo(BigInteger.ZERO) < 1) {
614                     throw new InvalidAlgorithmParameterException(
615                             "RSA public exponent must be positive: " + publicExponent);
616                 }
617                 if ((publicExponent.signum() == -1)
618                         || (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0)) {
619                     throw new InvalidAlgorithmParameterException(
620                             "Unsupported RSA public exponent: " + publicExponent
621                                     + ". Maximum supported value: "
622                                     + KeymasterArguments.UINT64_MAX_VALUE);
623                 }
624                 mRSAPublicExponent = publicExponent.longValue();
625                 break;
626             }
627             case KeymasterDefs.KM_ALGORITHM_EC:
628                 if (algSpecificSpec instanceof ECGenParameterSpec) {
629                     ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
630                     mEcCurveName = ecSpec.getName();
631                     if (mOriginalKeymasterAlgorithm == ALGORITHM_XDH
632                             && !mEcCurveName.equalsIgnoreCase("x25519")) {
633                         throw new InvalidAlgorithmParameterException("XDH algorithm only supports"
634                                 + " x25519 curve.");
635                     } else if (mOriginalKeymasterAlgorithm == ALGORITHM_ED25519
636                             && !mEcCurveName.equalsIgnoreCase("ed25519")) {
637                         throw new InvalidAlgorithmParameterException("Ed25519 algorithm only"
638                                 + " supports ed25519 curve.");
639                     }
640                     final Integer ecSpecKeySizeBits = SUPPORTED_EC_CURVE_NAME_TO_SIZE.get(
641                             mEcCurveName.toLowerCase(Locale.US));
642                     if (ecSpecKeySizeBits == null) {
643                         throw new InvalidAlgorithmParameterException(
644                                 "Unsupported EC curve name: " + mEcCurveName
645                                         + ". Supported: " + SUPPORTED_EC_CURVE_NAMES);
646                     }
647                     if (mKeySizeBits == -1) {
648                         mKeySizeBits = ecSpecKeySizeBits;
649                     } else if (mKeySizeBits != ecSpecKeySizeBits) {
650                         throw new InvalidAlgorithmParameterException("EC key size must match "
651                                 + " between " + mSpec + " and " + algSpecificSpec
652                                 + ": " + mKeySizeBits + " vs " + ecSpecKeySizeBits);
653                     }
654                 } else if (algSpecificSpec != null) {
655                     throw new InvalidAlgorithmParameterException(
656                             "EC may only use ECGenParameterSpec");
657                 }
658                 break;
659             default:
660                 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
661         }
662     }
663 
664     @Override
generateKeyPair()665     public KeyPair generateKeyPair() {
666         StrictMode.noteSlowCall("generateKeyPair");
667         if (mKeyStore == null || mSpec == null) {
668             throw new IllegalStateException("Not initialized");
669         }
670 
671         final @SecurityLevel int securityLevel =
672                 mSpec.isStrongBoxBacked()
673                         ? SecurityLevel.STRONGBOX
674                         : SecurityLevel.TRUSTED_ENVIRONMENT;
675 
676         final int flags =
677                 mSpec.isCriticalToDeviceEncryption()
678                         ? IKeystoreSecurityLevel
679                         .KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING
680                         : 0;
681 
682         byte[] additionalEntropy =
683                 KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
684                         mRng, (mKeySizeBits + 7) / 8);
685 
686         KeyDescriptor descriptor = new KeyDescriptor();
687         descriptor.alias = mEntryAlias;
688         descriptor.domain = mEntryNamespace == KeyProperties.NAMESPACE_APPLICATION
689                 ? Domain.APP
690                 : Domain.SELINUX;
691         descriptor.nspace = mEntryNamespace;
692         descriptor.blob = null;
693 
694         boolean success = false;
695         try {
696             KeyStoreSecurityLevel iSecurityLevel = mKeyStore.getSecurityLevel(securityLevel);
697 
698             KeyMetadata metadata = iSecurityLevel.generateKey(descriptor, mAttestKeyDescriptor,
699                     constructKeyGenerationArguments(), flags, additionalEntropy);
700 
701             AndroidKeyStorePublicKey publicKey =
702                     AndroidKeyStoreProvider.makeAndroidKeyStorePublicKeyFromKeyEntryResponse(
703                             descriptor, metadata, iSecurityLevel, mKeymasterAlgorithm);
704             success = true;
705             return new KeyPair(publicKey, publicKey.getPrivateKey());
706         } catch (KeyStoreException e) {
707             switch (e.getErrorCode()) {
708                 case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE:
709                     throw new StrongBoxUnavailableException("Failed to generated key pair.", e);
710                 default:
711                     ProviderException p = new ProviderException("Failed to generate key pair.", e);
712                     if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
713                         throw new SecureKeyImportUnavailableException(p);
714                     }
715                     throw p;
716             }
717         } catch (UnrecoverableKeyException | IllegalArgumentException
718                 | DeviceIdAttestationException | InvalidAlgorithmParameterException e) {
719             throw new ProviderException(
720                     "Failed to construct key object from newly generated key pair.", e);
721         } finally {
722             if (!success) {
723                 try {
724                     mKeyStore.deleteKey(descriptor);
725                 } catch (KeyStoreException e) {
726                     if (e.getErrorCode() != ResponseCode.KEY_NOT_FOUND) {
727                         Log.e(TAG, "Failed to delete newly generated key after "
728                                 + "generation failed unexpectedly.", e);
729                     }
730                 }
731             }
732         }
733     }
734 
addAttestationParameters(@onNull List<KeyParameter> params)735     private void addAttestationParameters(@NonNull List<KeyParameter> params)
736             throws ProviderException, IllegalArgumentException, DeviceIdAttestationException {
737         byte[] challenge = mSpec.getAttestationChallenge();
738 
739         if (challenge != null) {
740             params.add(KeyStore2ParameterUtils.makeBytes(
741                     KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge
742             ));
743 
744             if (mSpec.isDevicePropertiesAttestationIncluded()) {
745                 final String platformReportedBrand =
746                         isPropertyEmptyOrUnknown(Build.BRAND_FOR_ATTESTATION)
747                         ? Build.BRAND : Build.BRAND_FOR_ATTESTATION;
748                 params.add(KeyStore2ParameterUtils.makeBytes(
749                         KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND,
750                         platformReportedBrand.getBytes(StandardCharsets.UTF_8)
751                 ));
752                 final String platformReportedDevice =
753                         isPropertyEmptyOrUnknown(Build.DEVICE_FOR_ATTESTATION)
754                                 ? Build.DEVICE : Build.DEVICE_FOR_ATTESTATION;
755                 params.add(KeyStore2ParameterUtils.makeBytes(
756                         KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE,
757                         platformReportedDevice.getBytes(StandardCharsets.UTF_8)
758                 ));
759                 final String platformReportedProduct =
760                         isPropertyEmptyOrUnknown(Build.PRODUCT_FOR_ATTESTATION)
761                         ? Build.PRODUCT : Build.PRODUCT_FOR_ATTESTATION;
762                 params.add(KeyStore2ParameterUtils.makeBytes(
763                         KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT,
764                         platformReportedProduct.getBytes(StandardCharsets.UTF_8)
765                 ));
766                 final String platformReportedManufacturer =
767                         isPropertyEmptyOrUnknown(Build.MANUFACTURER_FOR_ATTESTATION)
768                                 ? Build.MANUFACTURER : Build.MANUFACTURER_FOR_ATTESTATION;
769                 params.add(KeyStore2ParameterUtils.makeBytes(
770                         KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER,
771                         platformReportedManufacturer.getBytes(StandardCharsets.UTF_8)
772                 ));
773                 final String platformReportedModel =
774                         isPropertyEmptyOrUnknown(Build.MODEL_FOR_ATTESTATION)
775                         ? Build.MODEL : Build.MODEL_FOR_ATTESTATION;
776                 params.add(KeyStore2ParameterUtils.makeBytes(
777                         KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL,
778                         platformReportedModel.getBytes(StandardCharsets.UTF_8)
779                 ));
780             }
781 
782             int[] idTypes = mSpec.getAttestationIds();
783             if (idTypes.length == 0) {
784                 return;
785             }
786             final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
787             for (int idType : idTypes) {
788                 idTypesSet.add(idType);
789             }
790             TelephonyManager telephonyService = null;
791             if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
792                     || idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
793                 telephonyService =
794                         (TelephonyManager) android.app.AppGlobals.getInitialApplication()
795                                 .getSystemService(Context.TELEPHONY_SERVICE);
796                 if (telephonyService == null) {
797                     throw new DeviceIdAttestationException("Unable to access telephony service");
798                 }
799             }
800             for (final Integer idType : idTypesSet) {
801                 switch (idType) {
802                     case AttestationUtils.ID_TYPE_SERIAL:
803                         params.add(KeyStore2ParameterUtils.makeBytes(
804                                 KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL,
805                                 Build.getSerial().getBytes(StandardCharsets.UTF_8)
806                         ));
807                         break;
808                     case AttestationUtils.ID_TYPE_IMEI: {
809                         final String imei = telephonyService.getImei(0);
810                         if (imei == null) {
811                             throw new DeviceIdAttestationException("Unable to retrieve IMEI");
812                         }
813                         params.add(KeyStore2ParameterUtils.makeBytes(
814                                 KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
815                                 imei.getBytes(StandardCharsets.UTF_8)
816                         ));
817                         final String secondImei = telephonyService.getImei(1);
818                         if (!TextUtils.isEmpty(secondImei)) {
819                             params.add(KeyStore2ParameterUtils.makeBytes(
820                                     KeymasterDefs.KM_TAG_ATTESTATION_ID_SECOND_IMEI,
821                                     secondImei.getBytes(StandardCharsets.UTF_8)
822                             ));
823                         }
824                         break;
825                     }
826                     case AttestationUtils.ID_TYPE_MEID: {
827                         final String meid = telephonyService.getMeid(0);
828                         if (meid == null) {
829                             throw new DeviceIdAttestationException("Unable to retrieve MEID");
830                         }
831                         params.add(KeyStore2ParameterUtils.makeBytes(
832                                 KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID,
833                                 meid.getBytes(StandardCharsets.UTF_8)
834                         ));
835                         break;
836                     }
837                     case AttestationUtils.USE_INDIVIDUAL_ATTESTATION: {
838                         params.add(KeyStore2ParameterUtils.makeBool(
839                                 KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION));
840                         break;
841                     }
842                     default:
843                         throw new IllegalArgumentException("Unknown device ID type " + idType);
844                 }
845             }
846         }
847     }
848 
constructKeyGenerationArguments()849     private Collection<KeyParameter> constructKeyGenerationArguments()
850             throws DeviceIdAttestationException, IllegalArgumentException,
851             InvalidAlgorithmParameterException {
852         List<KeyParameter> params = new ArrayList<>();
853         params.add(KeyStore2ParameterUtils.makeInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits));
854         params.add(KeyStore2ParameterUtils.makeEnum(
855                 KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm
856         ));
857 
858         if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) {
859             params.add(KeyStore2ParameterUtils.makeEnum(
860                     Tag.EC_CURVE, keySizeAndNameToEcCurve(mKeySizeBits, mEcCurveName)
861             ));
862         }
863 
864         ArrayUtils.forEach(mKeymasterPurposes, (purpose) -> {
865             params.add(KeyStore2ParameterUtils.makeEnum(
866                     KeymasterDefs.KM_TAG_PURPOSE, purpose
867             ));
868         });
869         ArrayUtils.forEach(mKeymasterBlockModes, (blockMode) -> {
870             params.add(KeyStore2ParameterUtils.makeEnum(
871                     KeymasterDefs.KM_TAG_BLOCK_MODE, blockMode
872             ));
873         });
874         ArrayUtils.forEach(mKeymasterEncryptionPaddings, (padding) -> {
875             params.add(KeyStore2ParameterUtils.makeEnum(
876                     KeymasterDefs.KM_TAG_PADDING, padding
877             ));
878             if (padding == KeymasterDefs.KM_PAD_RSA_OAEP) {
879                 ArrayUtils.forEach(mKeymasterMgf1Digests, (mgf1Digest) -> {
880                     params.add(KeyStore2ParameterUtils.makeEnum(
881                             KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, mgf1Digest
882                     ));
883                 });
884 
885                 /* If the MGF1 Digest setter is not set, fall back to the previous behaviour:
886                  * Add, as MGF1 Digest function, all the primary digests.
887                  * Avoid adding the default MGF1 digest as it will have been included in the
888                  * mKeymasterMgf1Digests field.
889                  */
890                 if (!getMgf1DigestSetterFlag()) {
891                     final int defaultMgf1Digest = KeyProperties.Digest.toKeymaster(
892                             DEFAULT_MGF1_DIGEST);
893                     ArrayUtils.forEach(mKeymasterDigests, (digest) -> {
894                         if (digest != defaultMgf1Digest) {
895                             params.add(KeyStore2ParameterUtils.makeEnum(
896                                     KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, digest));
897                         }
898                     });
899                 }
900             }
901         });
902         ArrayUtils.forEach(mKeymasterSignaturePaddings, (padding) -> {
903             params.add(KeyStore2ParameterUtils.makeEnum(
904                     KeymasterDefs.KM_TAG_PADDING, padding
905             ));
906         });
907         ArrayUtils.forEach(mKeymasterDigests, (digest) -> {
908             params.add(KeyStore2ParameterUtils.makeEnum(
909                     KeymasterDefs.KM_TAG_DIGEST, digest
910             ));
911         });
912 
913         KeyStore2ParameterUtils.addUserAuthArgs(params, mSpec);
914 
915         if (mSpec.getKeyValidityStart() != null) {
916             params.add(KeyStore2ParameterUtils.makeDate(
917                     KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart()
918             ));
919         }
920         if (mSpec.getKeyValidityForOriginationEnd() != null) {
921             params.add(KeyStore2ParameterUtils.makeDate(
922                     KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
923                     mSpec.getKeyValidityForOriginationEnd()
924             ));
925         }
926         if (mSpec.getKeyValidityForConsumptionEnd() != null) {
927             params.add(KeyStore2ParameterUtils.makeDate(
928                     KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
929                     mSpec.getKeyValidityForConsumptionEnd()
930             ));
931         }
932         if (mSpec.getCertificateNotAfter() != null) {
933             params.add(KeyStore2ParameterUtils.makeDate(
934                     KeymasterDefs.KM_TAG_CERTIFICATE_NOT_AFTER,
935                     mSpec.getCertificateNotAfter()
936             ));
937         }
938         if (mSpec.getCertificateNotBefore() != null) {
939             params.add(KeyStore2ParameterUtils.makeDate(
940                     KeymasterDefs.KM_TAG_CERTIFICATE_NOT_BEFORE,
941                     mSpec.getCertificateNotBefore()
942             ));
943         }
944         if (mSpec.getCertificateSerialNumber() != null) {
945             params.add(KeyStore2ParameterUtils.makeBignum(
946                     KeymasterDefs.KM_TAG_CERTIFICATE_SERIAL,
947                     mSpec.getCertificateSerialNumber()
948             ));
949         }
950         if (mSpec.getCertificateSubject() != null) {
951             params.add(KeyStore2ParameterUtils.makeBytes(
952                     KeymasterDefs.KM_TAG_CERTIFICATE_SUBJECT,
953                     mSpec.getCertificateSubject().getEncoded()
954             ));
955         }
956 
957         if (mSpec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
958             params.add(KeyStore2ParameterUtils.makeInt(
959                     KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
960                     mSpec.getMaxUsageCount()
961             ));
962         }
963 
964         addAlgorithmSpecificParameters(params);
965 
966         if (mSpec.isUniqueIdIncluded()) {
967             params.add(KeyStore2ParameterUtils.makeBool(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID));
968         }
969 
970         addAttestationParameters(params);
971 
972         return params;
973     }
974 
getMgf1DigestSetterFlag()975     private static boolean getMgf1DigestSetterFlag() {
976         try {
977             return Flags.mgf1DigestSetterV2();
978         } catch (SecurityException e) {
979             Log.w(TAG, "Cannot read MGF1 Digest setter flag value", e);
980             return false;
981         }
982     }
983 
984 
addAlgorithmSpecificParameters(List<KeyParameter> params)985     private void addAlgorithmSpecificParameters(List<KeyParameter> params) {
986         switch (mKeymasterAlgorithm) {
987             case KeymasterDefs.KM_ALGORITHM_RSA:
988                 params.add(KeyStore2ParameterUtils.makeLong(
989                         KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, mRSAPublicExponent
990                 ));
991                 break;
992             case KeymasterDefs.KM_ALGORITHM_EC:
993                 break;
994             default:
995                 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
996         }
997     }
998 
getDefaultKeySize(int keymasterAlgorithm)999     private static int getDefaultKeySize(int keymasterAlgorithm) {
1000         switch (keymasterAlgorithm) {
1001             case KeymasterDefs.KM_ALGORITHM_EC:
1002                 return EC_DEFAULT_KEY_SIZE;
1003             case KeymasterDefs.KM_ALGORITHM_RSA:
1004                 return RSA_DEFAULT_KEY_SIZE;
1005             default:
1006                 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
1007         }
1008     }
1009 
checkValidKeySize( int keymasterAlgorithm, int keySize, boolean isStrongBoxBacked, String mEcCurveName)1010     private static void checkValidKeySize(
1011             int keymasterAlgorithm,
1012             int keySize,
1013             boolean isStrongBoxBacked,
1014             String mEcCurveName)
1015             throws InvalidAlgorithmParameterException {
1016         switch (keymasterAlgorithm) {
1017             case KeymasterDefs.KM_ALGORITHM_EC:
1018                 if (isStrongBoxBacked && keySize != 256) {
1019                     throw new InvalidAlgorithmParameterException(
1020                             "Unsupported StrongBox EC key size: "
1021                                     + keySize + " bits. Supported: 256");
1022                 }
1023                 if (isStrongBoxBacked && isCurve25519(mEcCurveName)) {
1024                     throw new InvalidAlgorithmParameterException(
1025                             "Unsupported StrongBox EC: " + mEcCurveName);
1026                 }
1027                 if (!SUPPORTED_EC_CURVE_SIZES.contains(keySize)) {
1028                     throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
1029                             + keySize + " bits. Supported: " + SUPPORTED_EC_CURVE_SIZES);
1030                 }
1031                 break;
1032             case KeymasterDefs.KM_ALGORITHM_RSA:
1033                 if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
1034                     throw new InvalidAlgorithmParameterException("RSA key size must be >= "
1035                             + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
1036                 }
1037                 break;
1038             default:
1039                 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
1040         }
1041     }
1042 
1043     /**
1044      * Returns the {@code Signature} algorithm to be used for signing a certificate using the
1045      * specified key or {@code null} if the key cannot be used for signing a certificate.
1046      */
1047     @Nullable
getCertificateSignatureAlgorithm( int keymasterAlgorithm, int keySizeBits, KeyGenParameterSpec spec)1048     private static String getCertificateSignatureAlgorithm(
1049             int keymasterAlgorithm,
1050             int keySizeBits,
1051             KeyGenParameterSpec spec) {
1052         // Constraints:
1053         // 1. Key must be authorized for signing without user authentication.
1054         // 2. Signature digest must be one of key's authorized digests.
1055         // 3. For RSA keys, the digest output size must not exceed modulus size minus space overhead
1056         //    of RSA PKCS#1 signature padding scheme (about 30 bytes).
1057         // 4. For EC keys, the there is no point in using a digest whose output size is longer than
1058         //    key/field size because the digest will be truncated to that size.
1059 
1060         if ((spec.getPurposes() & KeyProperties.PURPOSE_SIGN) == 0) {
1061             // Key not authorized for signing
1062             return null;
1063         }
1064         if (spec.isUserAuthenticationRequired()) {
1065             // Key not authorized for use without user authentication
1066             return null;
1067         }
1068         if (!spec.isDigestsSpecified()) {
1069             // Key not authorized for any digests -- can't sign
1070             return null;
1071         }
1072         switch (keymasterAlgorithm) {
1073             case KeymasterDefs.KM_ALGORITHM_EC: {
1074                 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
1075                         spec.getDigests(),
1076                         AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
1077 
1078                 int bestKeymasterDigest = -1;
1079                 int bestDigestOutputSizeBits = -1;
1080                 for (int keymasterDigest : availableKeymasterDigests) {
1081                     int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
1082                     if (outputSizeBits == keySizeBits) {
1083                         // Perfect match -- use this digest
1084                         bestKeymasterDigest = keymasterDigest;
1085                         bestDigestOutputSizeBits = outputSizeBits;
1086                         break;
1087                     }
1088                     // Not a perfect match -- check against the best digest so far
1089                     if (bestKeymasterDigest == -1) {
1090                         // First digest tested -- definitely the best so far
1091                         bestKeymasterDigest = keymasterDigest;
1092                         bestDigestOutputSizeBits = outputSizeBits;
1093                     } else {
1094                         // Prefer output size to be as close to key size as possible, with output
1095                         // sizes larger than key size preferred to those smaller than key size.
1096                         if (bestDigestOutputSizeBits < keySizeBits) {
1097                             // Output size of the best digest so far is smaller than key size.
1098                             // Anything larger is a win.
1099                             if (outputSizeBits > bestDigestOutputSizeBits) {
1100                                 bestKeymasterDigest = keymasterDigest;
1101                                 bestDigestOutputSizeBits = outputSizeBits;
1102                             }
1103                         } else {
1104                             // Output size of the best digest so far is larger than key size.
1105                             // Anything smaller is a win, as long as it's not smaller than key size.
1106                             if ((outputSizeBits < bestDigestOutputSizeBits)
1107                                     && (outputSizeBits >= keySizeBits)) {
1108                                 bestKeymasterDigest = keymasterDigest;
1109                                 bestDigestOutputSizeBits = outputSizeBits;
1110                             }
1111                         }
1112                     }
1113                 }
1114                 if (bestKeymasterDigest == -1) {
1115                     return null;
1116                 }
1117                 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
1118                         bestKeymasterDigest) + "WithECDSA";
1119             }
1120             case KeymasterDefs.KM_ALGORITHM_RSA: {
1121                 // Check whether this key is authorized for PKCS#1 signature padding.
1122                 // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle
1123                 // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs
1124                 // to be authorized for PKCS#1 padding or padding NONE which means any padding.
1125                 boolean pkcs1SignaturePaddingSupported =
1126                         com.android.internal.util.ArrayUtils.contains(
1127                                 KeyProperties.SignaturePadding.allToKeymaster(
1128                                         spec.getSignaturePaddings()),
1129                                 KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
1130                 if (!pkcs1SignaturePaddingSupported) {
1131                     // Key not authorized for PKCS#1 signature padding -- can't sign
1132                     return null;
1133                 }
1134 
1135                 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
1136                         spec.getDigests(),
1137                         AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
1138 
1139                 // The amount of space available for the digest is less than modulus size by about
1140                 // 30 bytes because padding must be at least 11 bytes long (00 || 01 || PS || 00,
1141                 // where PS must be at least 8 bytes long), and then there's also the 15--19 bytes
1142                 // overhead (depending the on chosen digest) for encoding digest OID and digest
1143                 // value in DER.
1144                 int maxDigestOutputSizeBits = keySizeBits - 30 * 8;
1145                 int bestKeymasterDigest = -1;
1146                 int bestDigestOutputSizeBits = -1;
1147                 for (int keymasterDigest : availableKeymasterDigests) {
1148                     int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
1149                     if (outputSizeBits > maxDigestOutputSizeBits) {
1150                         // Digest too long (signature generation will fail) -- skip
1151                         continue;
1152                     }
1153                     if (bestKeymasterDigest == -1) {
1154                         // First digest tested -- definitely the best so far
1155                         bestKeymasterDigest = keymasterDigest;
1156                         bestDigestOutputSizeBits = outputSizeBits;
1157                     } else {
1158                         // The longer the better
1159                         if (outputSizeBits > bestDigestOutputSizeBits) {
1160                             bestKeymasterDigest = keymasterDigest;
1161                             bestDigestOutputSizeBits = outputSizeBits;
1162                         }
1163                     }
1164                 }
1165                 if (bestKeymasterDigest == -1) {
1166                     return null;
1167                 }
1168                 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
1169                         bestKeymasterDigest) + "WithRSA";
1170             }
1171             default:
1172                 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
1173         }
1174     }
1175 
getAvailableKeymasterSignatureDigests( @eyProperties.DigestEnum String[] authorizedKeyDigests, @KeyProperties.DigestEnum String[] supportedSignatureDigests)1176     private static Set<Integer> getAvailableKeymasterSignatureDigests(
1177             @KeyProperties.DigestEnum String[] authorizedKeyDigests,
1178             @KeyProperties.DigestEnum String[] supportedSignatureDigests) {
1179         Set<Integer> authorizedKeymasterKeyDigests = new HashSet<Integer>();
1180         for (int keymasterDigest : KeyProperties.Digest.allToKeymaster(authorizedKeyDigests)) {
1181             authorizedKeymasterKeyDigests.add(keymasterDigest);
1182         }
1183         Set<Integer> supportedKeymasterSignatureDigests = new HashSet<Integer>();
1184         for (int keymasterDigest
1185                 : KeyProperties.Digest.allToKeymaster(supportedSignatureDigests)) {
1186             supportedKeymasterSignatureDigests.add(keymasterDigest);
1187         }
1188         Set<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests);
1189         result.retainAll(authorizedKeymasterKeyDigests);
1190         return result;
1191     }
1192 
isPropertyEmptyOrUnknown(String property)1193     private boolean isPropertyEmptyOrUnknown(String property) {
1194         return TextUtils.isEmpty(property) || property.equals(Build.UNKNOWN);
1195     }
1196 }
1197