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