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