blob: fea0e638d6a51428588f99b51d1fd24f6f710a28 [file] [log] [blame]
Kenny Rootdb026712012-08-20 10:48:46 -07001/*
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
Alex Klyubindcdaf872015-05-13 15:57:09 -070017package android.security.keystore;
Kenny Rootdb026712012-08-20 10:48:46 -070018
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070019import android.annotation.Nullable;
Alex Klyubindcdaf872015-05-13 15:57:09 -070020import android.security.Credentials;
Rubin Xu59ced282017-01-30 23:39:12 +000021import android.security.GateKeeper;
Alex Klyubindcdaf872015-05-13 15:57:09 -070022import android.security.KeyPairGeneratorSpec;
23import android.security.KeyStore;
Frank Salimea5e0382018-01-23 22:42:29 -080024import android.security.KeyStoreException;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070025import android.security.keymaster.KeyCharacteristics;
26import android.security.keymaster.KeymasterArguments;
Shawn Willden8d8c7472016-02-02 08:27:39 -070027import android.security.keymaster.KeymasterCertificateChain;
Alex Klyubin4350bab2015-06-08 10:14:58 -070028import android.security.keymaster.KeymasterDefs;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070029
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070030import com.android.org.bouncycastle.asn1.ASN1EncodableVector;
31import com.android.org.bouncycastle.asn1.ASN1InputStream;
32import com.android.org.bouncycastle.asn1.ASN1Integer;
33import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
34import com.android.org.bouncycastle.asn1.DERBitString;
35import com.android.org.bouncycastle.asn1.DERInteger;
36import com.android.org.bouncycastle.asn1.DERNull;
37import com.android.org.bouncycastle.asn1.DERSequence;
38import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
39import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
40import com.android.org.bouncycastle.asn1.x509.Certificate;
41import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
42import com.android.org.bouncycastle.asn1.x509.TBSCertificate;
43import com.android.org.bouncycastle.asn1.x509.Time;
44import com.android.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
45import com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
46import com.android.org.bouncycastle.jce.X509Principal;
47import com.android.org.bouncycastle.jce.provider.X509CertificateObject;
Kenny Rootdb026712012-08-20 10:48:46 -070048import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
Kenny Rootdb026712012-08-20 10:48:46 -070049
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070050import libcore.util.EmptyArray;
51
Shawn Willden8d8c7472016-02-02 08:27:39 -070052import java.io.ByteArrayOutputStream;
53import java.io.IOException;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070054import java.math.BigInteger;
Kenny Rootdb026712012-08-20 10:48:46 -070055import java.security.InvalidAlgorithmParameterException;
Kenny Rootdb026712012-08-20 10:48:46 -070056import java.security.KeyPair;
57import java.security.KeyPairGenerator;
58import java.security.KeyPairGeneratorSpi;
Kenny Rootdb026712012-08-20 10:48:46 -070059import java.security.PrivateKey;
Alex Klyubin4350bab2015-06-08 10:14:58 -070060import java.security.ProviderException;
Kenny Rootdb026712012-08-20 10:48:46 -070061import java.security.PublicKey;
62import java.security.SecureRandom;
Alex Klyubin4a0ff7c2015-06-09 13:25:20 -070063import java.security.UnrecoverableKeyException;
Kenny Rootdb026712012-08-20 10:48:46 -070064import java.security.cert.CertificateEncodingException;
Shawn Willden8d8c7472016-02-02 08:27:39 -070065import java.security.cert.CertificateParsingException;
Kenny Rootdb026712012-08-20 10:48:46 -070066import java.security.cert.X509Certificate;
67import java.security.spec.AlgorithmParameterSpec;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070068import java.security.spec.ECGenParameterSpec;
Kenny Rootf64386f2013-08-16 14:03:29 -070069import java.security.spec.RSAKeyGenParameterSpec;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070070import java.util.ArrayList;
Shawn Willden8d8c7472016-02-02 08:27:39 -070071import java.util.Collection;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070072import java.util.Collections;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070073import java.util.HashMap;
74import java.util.HashSet;
Shawn Willden8d8c7472016-02-02 08:27:39 -070075import java.util.Iterator;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070076import java.util.List;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -070077import java.util.Locale;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070078import java.util.Map;
79import java.util.Set;
Kenny Rootdb026712012-08-20 10:48:46 -070080
81/**
82 * Provides a way to create instances of a KeyPair which will be placed in the
83 * Android keystore service usable only by the application that called it. This
84 * can be used in conjunction with
85 * {@link java.security.KeyStore#getInstance(String)} using the
86 * {@code "AndroidKeyStore"} type.
87 * <p>
88 * This class can not be directly instantiated and must instead be used via the
89 * {@link KeyPairGenerator#getInstance(String)
Alex Klyubine21f0232015-05-19 09:41:17 -070090 * KeyPairGenerator.getInstance("AndroidKeyStore")} API.
Kenny Rootdb026712012-08-20 10:48:46 -070091 *
Alex Klyubine21f0232015-05-19 09:41:17 -070092 * @hide
Kenny Rootdb026712012-08-20 10:48:46 -070093 */
Alex Klyubine21f0232015-05-19 09:41:17 -070094public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
Alex Klyubin21a76df2015-01-14 13:35:32 -080095
Alex Klyubine21f0232015-05-19 09:41:17 -070096 public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi {
Alex Klyubin21a76df2015-01-14 13:35:32 -080097 public RSA() {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -070098 super(KeymasterDefs.KM_ALGORITHM_RSA);
Alex Klyubin21a76df2015-01-14 13:35:32 -080099 }
100 }
101
Alex Klyubine21f0232015-05-19 09:41:17 -0700102 public static class EC extends AndroidKeyStoreKeyPairGeneratorSpi {
Alex Klyubin21a76df2015-01-14 13:35:32 -0800103 public EC() {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700104 super(KeymasterDefs.KM_ALGORITHM_EC);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800105 }
106 }
107
108 /*
109 * These must be kept in sync with system/security/keystore/defaults.h
110 */
111
112 /* EC */
113 private static final int EC_DEFAULT_KEY_SIZE = 256;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800114
115 /* RSA */
116 private static final int RSA_DEFAULT_KEY_SIZE = 2048;
117 private static final int RSA_MIN_KEY_SIZE = 512;
118 private static final int RSA_MAX_KEY_SIZE = 8192;
119
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700120 private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE =
121 new HashMap<String, Integer>();
122 private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>();
Alex Klyubinbf5c91c2015-06-17 10:51:19 -0700123 private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>();
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700124 static {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700125 // Aliases for NIST P-224
126 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224);
127 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
128
Alex Klyubinbf5c91c2015-06-17 10:51:19 -0700129
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700130 // Aliases for NIST P-256
131 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256);
132 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
133 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
134
135 // Aliases for NIST P-384
136 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384);
137 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384);
138
139 // Aliases for NIST P-521
140 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521);
141 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521);
142
143 SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
144 Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
Alex Klyubinbf5c91c2015-06-17 10:51:19 -0700145
146 SUPPORTED_EC_NIST_CURVE_SIZES.addAll(
147 new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values()));
148 Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700149 }
Alex Klyubin4a0ff7c2015-06-09 13:25:20 -0700150
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700151 private final int mOriginalKeymasterAlgorithm;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800152
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700153 private KeyStore mKeyStore;
Kenny Rootdb026712012-08-20 10:48:46 -0700154
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700155 private KeyGenParameterSpec mSpec;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700156
157 private String mEntryAlias;
Alex Klyubin3876b1b2015-09-09 14:55:03 -0700158 private int mEntryUid;
Alex Klyubin96481c32015-05-15 10:47:18 -0700159 private boolean mEncryptionAtRestRequired;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700160 private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
161 private int mKeymasterAlgorithm = -1;
162 private int mKeySizeBits;
163 private SecureRandom mRng;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800164
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700165 private int[] mKeymasterPurposes;
166 private int[] mKeymasterBlockModes;
167 private int[] mKeymasterEncryptionPaddings;
168 private int[] mKeymasterSignaturePaddings;
169 private int[] mKeymasterDigests;
170
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700171 private BigInteger mRSAPublicExponent;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700172
173 protected AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm) {
174 mOriginalKeymasterAlgorithm = keymasterAlgorithm;
Alex Klyubin21a76df2015-01-14 13:35:32 -0800175 }
176
Shawn Willden8d8c7472016-02-02 08:27:39 -0700177 @SuppressWarnings("deprecation")
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700178 @Override
179 public void initialize(int keysize, SecureRandom random) {
180 throw new IllegalArgumentException(
181 KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName()
182 + " required to initialize this KeyPairGenerator");
Alex Klyubin21a76df2015-01-14 13:35:32 -0800183 }
Kenny Rootdb026712012-08-20 10:48:46 -0700184
Shawn Willden8d8c7472016-02-02 08:27:39 -0700185 @SuppressWarnings("deprecation")
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700186 @Override
187 public void initialize(AlgorithmParameterSpec params, SecureRandom random)
188 throws InvalidAlgorithmParameterException {
189 resetAll();
190
191 boolean success = false;
192 try {
193 if (params == null) {
194 throw new InvalidAlgorithmParameterException(
195 "Must supply params of type " + KeyGenParameterSpec.class.getName()
196 + " or " + KeyPairGeneratorSpec.class.getName());
197 }
198
199 KeyGenParameterSpec spec;
200 boolean encryptionAtRestRequired = false;
201 int keymasterAlgorithm = mOriginalKeymasterAlgorithm;
202 if (params instanceof KeyGenParameterSpec) {
203 spec = (KeyGenParameterSpec) params;
204 } else if (params instanceof KeyPairGeneratorSpec) {
205 // Legacy/deprecated spec
206 KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
207 try {
208 KeyGenParameterSpec.Builder specBuilder;
209 String specKeyAlgorithm = legacySpec.getKeyType();
210 if (specKeyAlgorithm != null) {
211 // Spec overrides the generator's default key algorithm
212 try {
213 keymasterAlgorithm =
214 KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
215 specKeyAlgorithm);
216 } catch (IllegalArgumentException e) {
217 throw new InvalidAlgorithmParameterException(
218 "Invalid key type in parameters", e);
219 }
220 }
221 switch (keymasterAlgorithm) {
222 case KeymasterDefs.KM_ALGORITHM_EC:
223 specBuilder = new KeyGenParameterSpec.Builder(
224 legacySpec.getKeystoreAlias(),
225 KeyProperties.PURPOSE_SIGN
226 | KeyProperties.PURPOSE_VERIFY);
Alex Klyubindcf3d352015-06-11 14:44:46 -0700227 // Authorized to be used with any digest (including no digest).
Alex Klyubine4928a22015-07-21 13:38:48 -0700228 // MD5 was never offered for Android Keystore for ECDSA.
229 specBuilder.setDigests(
230 KeyProperties.DIGEST_NONE,
231 KeyProperties.DIGEST_SHA1,
232 KeyProperties.DIGEST_SHA224,
233 KeyProperties.DIGEST_SHA256,
234 KeyProperties.DIGEST_SHA384,
235 KeyProperties.DIGEST_SHA512);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700236 break;
237 case KeymasterDefs.KM_ALGORITHM_RSA:
238 specBuilder = new KeyGenParameterSpec.Builder(
239 legacySpec.getKeystoreAlias(),
240 KeyProperties.PURPOSE_ENCRYPT
241 | KeyProperties.PURPOSE_DECRYPT
242 | KeyProperties.PURPOSE_SIGN
243 | KeyProperties.PURPOSE_VERIFY);
Alex Klyubindcf3d352015-06-11 14:44:46 -0700244 // Authorized to be used with any digest (including no digest).
Alex Klyubine4928a22015-07-21 13:38:48 -0700245 specBuilder.setDigests(
246 KeyProperties.DIGEST_NONE,
247 KeyProperties.DIGEST_MD5,
248 KeyProperties.DIGEST_SHA1,
249 KeyProperties.DIGEST_SHA224,
250 KeyProperties.DIGEST_SHA256,
251 KeyProperties.DIGEST_SHA384,
252 KeyProperties.DIGEST_SHA512);
Alex Klyubin2e3aaa72015-06-17 13:58:00 -0700253 // Authorized to be used with any encryption and signature padding
Alex Klyubine4928a22015-07-21 13:38:48 -0700254 // schemes (including no padding).
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700255 specBuilder.setEncryptionPaddings(
Alex Klyubine4928a22015-07-21 13:38:48 -0700256 KeyProperties.ENCRYPTION_PADDING_NONE,
257 KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
258 KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
259 specBuilder.setSignaturePaddings(
260 KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
261 KeyProperties.SIGNATURE_PADDING_RSA_PSS);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700262 // Disable randomized encryption requirement to support encryption
263 // padding NONE above.
264 specBuilder.setRandomizedEncryptionRequired(false);
265 break;
266 default:
267 throw new ProviderException(
268 "Unsupported algorithm: " + mKeymasterAlgorithm);
269 }
270
271 if (legacySpec.getKeySize() != -1) {
272 specBuilder.setKeySize(legacySpec.getKeySize());
273 }
274 if (legacySpec.getAlgorithmParameterSpec() != null) {
275 specBuilder.setAlgorithmParameterSpec(
276 legacySpec.getAlgorithmParameterSpec());
277 }
278 specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
279 specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
280 specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
281 specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
282 encryptionAtRestRequired = legacySpec.isEncryptionRequired();
283 specBuilder.setUserAuthenticationRequired(false);
284
285 spec = specBuilder.build();
286 } catch (NullPointerException | IllegalArgumentException e) {
287 throw new InvalidAlgorithmParameterException(e);
288 }
289 } else {
290 throw new InvalidAlgorithmParameterException(
291 "Unsupported params class: " + params.getClass().getName()
292 + ". Supported: " + KeyGenParameterSpec.class.getName()
293 + ", " + KeyPairGeneratorSpec.class.getName());
294 }
295
296 mEntryAlias = spec.getKeystoreAlias();
Alex Klyubin3876b1b2015-09-09 14:55:03 -0700297 mEntryUid = spec.getUid();
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700298 mSpec = spec;
299 mKeymasterAlgorithm = keymasterAlgorithm;
300 mEncryptionAtRestRequired = encryptionAtRestRequired;
301 mKeySizeBits = spec.getKeySize();
302 initAlgorithmSpecificParameters();
303 if (mKeySizeBits == -1) {
304 mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
305 }
306 checkValidKeySize(keymasterAlgorithm, mKeySizeBits);
307
308 if (spec.getKeystoreAlias() == null) {
309 throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
310 }
311
312 String jcaKeyAlgorithm;
313 try {
314 jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
315 keymasterAlgorithm);
316 mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
317 mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
318 mKeymasterEncryptionPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
319 spec.getEncryptionPaddings());
Alex Klyubinfdbc02a2015-06-29 14:39:29 -0700320 if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
321 && (spec.isRandomizedEncryptionRequired())) {
322 for (int keymasterPadding : mKeymasterEncryptionPaddings) {
323 if (!KeymasterUtils
324 .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
325 keymasterPadding)) {
326 throw new InvalidAlgorithmParameterException(
327 "Randomized encryption (IND-CPA) required but may be violated"
328 + " by padding scheme: "
329 + KeyProperties.EncryptionPadding.fromKeymaster(
330 keymasterPadding)
331 + ". See " + KeyGenParameterSpec.class.getName()
332 + " documentation.");
333 }
334 }
335 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700336 mKeymasterSignaturePaddings = KeyProperties.SignaturePadding.allToKeymaster(
337 spec.getSignaturePaddings());
338 if (spec.isDigestsSpecified()) {
339 mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
340 } else {
341 mKeymasterDigests = EmptyArray.INT;
342 }
Alex Klyubinb6e62862015-07-06 10:31:07 -0700343
344 // Check that user authentication related parameters are acceptable. This method
345 // will throw an IllegalStateException if there are issues (e.g., secure lock screen
346 // not set up).
Brian Young5437b812018-02-23 18:04:20 +0000347 KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
Alex Klyubinb6e62862015-07-06 10:31:07 -0700348 } catch (IllegalArgumentException | IllegalStateException e) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700349 throw new InvalidAlgorithmParameterException(e);
350 }
351
352 mJcaKeyAlgorithm = jcaKeyAlgorithm;
353 mRng = random;
354 mKeyStore = KeyStore.getInstance();
355 success = true;
356 } finally {
357 if (!success) {
358 resetAll();
359 }
360 }
361 }
362
363 private void resetAll() {
364 mEntryAlias = null;
Alex Klyubin3876b1b2015-09-09 14:55:03 -0700365 mEntryUid = KeyStore.UID_SELF;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700366 mJcaKeyAlgorithm = null;
367 mKeymasterAlgorithm = -1;
368 mKeymasterPurposes = null;
369 mKeymasterBlockModes = null;
370 mKeymasterEncryptionPaddings = null;
371 mKeymasterSignaturePaddings = null;
372 mKeymasterDigests = null;
373 mKeySizeBits = 0;
374 mSpec = null;
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700375 mRSAPublicExponent = null;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700376 mEncryptionAtRestRequired = false;
377 mRng = null;
378 mKeyStore = null;
379 }
380
381 private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException {
382 AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec();
383 switch (mKeymasterAlgorithm) {
384 case KeymasterDefs.KM_ALGORITHM_RSA:
385 {
386 BigInteger publicExponent = null;
387 if (algSpecificSpec instanceof RSAKeyGenParameterSpec) {
388 RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec;
389 if (mKeySizeBits == -1) {
390 mKeySizeBits = rsaSpec.getKeysize();
391 } else if (mKeySizeBits != rsaSpec.getKeysize()) {
392 throw new InvalidAlgorithmParameterException("RSA key size must match "
393 + " between " + mSpec + " and " + algSpecificSpec
394 + ": " + mKeySizeBits + " vs " + rsaSpec.getKeysize());
395 }
396 publicExponent = rsaSpec.getPublicExponent();
397 } else if (algSpecificSpec != null) {
398 throw new InvalidAlgorithmParameterException(
399 "RSA may only use RSAKeyGenParameterSpec");
400 }
401 if (publicExponent == null) {
402 publicExponent = RSAKeyGenParameterSpec.F4;
403 }
404 if (publicExponent.compareTo(BigInteger.ZERO) < 1) {
405 throw new InvalidAlgorithmParameterException(
406 "RSA public exponent must be positive: " + publicExponent);
407 }
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700408 if (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0) {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700409 throw new InvalidAlgorithmParameterException(
410 "Unsupported RSA public exponent: " + publicExponent
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700411 + ". Maximum supported value: " + KeymasterArguments.UINT64_MAX_VALUE);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700412 }
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700413 mRSAPublicExponent = publicExponent;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700414 break;
415 }
416 case KeymasterDefs.KM_ALGORITHM_EC:
417 if (algSpecificSpec instanceof ECGenParameterSpec) {
418 ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
419 String curveName = ecSpec.getName();
420 Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get(
421 curveName.toLowerCase(Locale.US));
422 if (ecSpecKeySizeBits == null) {
423 throw new InvalidAlgorithmParameterException(
424 "Unsupported EC curve name: " + curveName
425 + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES);
426 }
427 if (mKeySizeBits == -1) {
428 mKeySizeBits = ecSpecKeySizeBits;
429 } else if (mKeySizeBits != ecSpecKeySizeBits) {
430 throw new InvalidAlgorithmParameterException("EC key size must match "
431 + " between " + mSpec + " and " + algSpecificSpec
432 + ": " + mKeySizeBits + " vs " + ecSpecKeySizeBits);
433 }
434 } else if (algSpecificSpec != null) {
435 throw new InvalidAlgorithmParameterException(
436 "EC may only use ECGenParameterSpec");
437 }
438 break;
439 default:
440 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
441 }
442 }
443
Kenny Rootdb026712012-08-20 10:48:46 -0700444 @Override
445 public KeyPair generateKeyPair() {
446 if (mKeyStore == null || mSpec == null) {
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700447 throw new IllegalStateException("Not initialized");
Kenny Rootdb026712012-08-20 10:48:46 -0700448 }
449
Frank Salimea5e0382018-01-23 22:42:29 -0800450 int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700451 if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
Kenny Root2eeda722013-04-10 11:30:58 -0700452 && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
453 throw new IllegalStateException(
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700454 "Encryption at rest using secure lock screen credential requested for key pair"
455 + ", but the user has not yet entered the credential");
Kenny Root2eeda722013-04-10 11:30:58 -0700456 }
457
Frank Salimea5e0382018-01-23 22:42:29 -0800458 if (mSpec.isStrongBoxBacked()) {
459 flags |= KeyStore.FLAG_STRONGBOX;
460 }
461
Shawn Willden8d8c7472016-02-02 08:27:39 -0700462 byte[] additionalEntropy =
463 KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
464 mRng, (mKeySizeBits + 7) / 8);
465
466 Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
467 final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
468 boolean success = false;
469 try {
470 generateKeystoreKeyPair(
471 privateKeyAlias, constructKeyGenerationArguments(), additionalEntropy, flags);
472 KeyPair keyPair = loadKeystoreKeyPair(privateKeyAlias);
473
474 storeCertificateChain(flags, createCertificateChain(privateKeyAlias, keyPair));
475
476 success = true;
477 return keyPair;
Frank Salimb6315032018-03-15 17:33:16 -0700478 } catch (ProviderException e) {
479 if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
480 throw new SecureKeyImportUnavailableException(e);
481 } else {
482 throw e;
483 }
Shawn Willden8d8c7472016-02-02 08:27:39 -0700484 } finally {
485 if (!success) {
486 Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
487 }
488 }
489 }
490
491 private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
492 throws ProviderException {
493 byte[] challenge = mSpec.getAttestationChallenge();
494 if (challenge != null) {
495 KeymasterArguments args = new KeymasterArguments();
496 args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge);
497 return getAttestationChain(privateKeyAlias, keyPair, args);
498 }
499
500 // Very short certificate chain in the non-attestation case.
501 return Collections.singleton(generateSelfSignedCertificateBytes(keyPair));
502 }
503
504 private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args,
505 byte[] additionalEntropy, final int flags) throws ProviderException {
506 KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
507 int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy,
508 mEntryUid, flags, resultingKeyCharacteristics);
509 if (errorCode != KeyStore.NO_ERROR) {
Frank Salimea5e0382018-01-23 22:42:29 -0800510 if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
511 throw new StrongBoxUnavailableException("Failed to generate key pair");
512 } else {
513 throw new ProviderException(
514 "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
515 }
Shawn Willden8d8c7472016-02-02 08:27:39 -0700516 }
517 }
518
519 private KeyPair loadKeystoreKeyPair(final String privateKeyAlias) throws ProviderException {
520 try {
521 KeyPair result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
522 mKeyStore, privateKeyAlias, mEntryUid);
523 if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
524 throw new ProviderException(
525 "Generated key pair algorithm does not match requested algorithm: "
526 + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
527 }
528 return result;
Max Biresb2cc3dc2018-11-02 10:50:40 -0700529 } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
Shawn Willden8d8c7472016-02-02 08:27:39 -0700530 throw new ProviderException("Failed to load generated key pair from keystore", e);
531 }
532 }
533
534 private KeymasterArguments constructKeyGenerationArguments() {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700535 KeymasterArguments args = new KeymasterArguments();
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700536 args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
537 args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
538 args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
539 args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
540 args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterEncryptionPaddings);
541 args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
542 args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
Kenny Rootdb026712012-08-20 10:48:46 -0700543
Brian Young5437b812018-02-23 18:04:20 +0000544 KeymasterUtils.addUserAuthArgs(args, mSpec);
Alex Klyubind6c77992015-06-23 12:06:27 -0700545 args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
546 args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
547 mSpec.getKeyValidityForOriginationEnd());
548 args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
549 mSpec.getKeyValidityForConsumptionEnd());
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700550 addAlgorithmSpecificParameters(args);
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700551
Shawn Willden8d8c7472016-02-02 08:27:39 -0700552 if (mSpec.isUniqueIdIncluded())
553 args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700554
Shawn Willden8d8c7472016-02-02 08:27:39 -0700555 return args;
556 }
Kenny Rootdb026712012-08-20 10:48:46 -0700557
Shawn Willden8d8c7472016-02-02 08:27:39 -0700558 private void storeCertificateChain(final int flags, Iterable<byte[]> iterable)
559 throws ProviderException {
560 Iterator<byte[]> iter = iterable.iterator();
561 storeCertificate(
562 Credentials.USER_CERTIFICATE, iter.next(), flags, "Failed to store certificate");
Kenny Rootdb026712012-08-20 10:48:46 -0700563
Shawn Willden8d8c7472016-02-02 08:27:39 -0700564 if (!iter.hasNext()) {
565 return;
Alex Klyubin4bbfeb42015-06-04 10:42:59 -0700566 }
Shawn Willden8d8c7472016-02-02 08:27:39 -0700567
568 ByteArrayOutputStream certificateConcatenationStream = new ByteArrayOutputStream();
569 while (iter.hasNext()) {
570 byte[] data = iter.next();
571 certificateConcatenationStream.write(data, 0, data.length);
572 }
573
574 storeCertificate(Credentials.CA_CERTIFICATE, certificateConcatenationStream.toByteArray(),
575 flags, "Failed to store attestation CA certificate");
576 }
577
578 private void storeCertificate(String prefix, byte[] certificateBytes, final int flags,
579 String failureMessage) throws ProviderException {
580 int insertErrorCode = mKeyStore.insert(
581 prefix + mEntryAlias,
582 certificateBytes,
583 mEntryUid,
584 flags);
585 if (insertErrorCode != KeyStore.NO_ERROR) {
586 throw new ProviderException(failureMessage,
587 KeyStore.getKeyStoreException(insertErrorCode));
588 }
589 }
590
591 private byte[] generateSelfSignedCertificateBytes(KeyPair keyPair) throws ProviderException {
592 try {
593 return generateSelfSignedCertificate(keyPair.getPrivate(), keyPair.getPublic())
594 .getEncoded();
595 } catch (IOException | CertificateParsingException e) {
596 throw new ProviderException("Failed to generate self-signed certificate", e);
597 } catch (CertificateEncodingException e) {
598 throw new ProviderException(
599 "Failed to obtain encoded form of self-signed certificate", e);
600 }
601 }
602
603 private Iterable<byte[]> getAttestationChain(String privateKeyAlias,
604 KeyPair keyPair, KeymasterArguments args)
605 throws ProviderException {
606 KeymasterCertificateChain outChain = new KeymasterCertificateChain();
607 int errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain);
608 if (errorCode != KeyStore.NO_ERROR) {
609 throw new ProviderException("Failed to generate attestation certificate chain",
610 KeyStore.getKeyStoreException(errorCode));
611 }
612 Collection<byte[]> chain = outChain.getCertificates();
613 if (chain.size() < 2) {
614 throw new ProviderException("Attestation certificate chain contained "
615 + chain.size() + " entries. At least two are required.");
616 }
617 return chain;
Kenny Rootdb026712012-08-20 10:48:46 -0700618 }
619
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700620 private void addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs) {
621 switch (mKeymasterAlgorithm) {
622 case KeymasterDefs.KM_ALGORITHM_RSA:
Alex Klyubinae6cb7a2015-06-22 18:09:35 -0700623 keymasterArgs.addUnsignedLong(
624 KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, mRSAPublicExponent);
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700625 break;
626 case KeymasterDefs.KM_ALGORITHM_EC:
627 break;
628 default:
629 throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
630 }
631 }
632
Shawn Willden8d8c7472016-02-02 08:27:39 -0700633 private X509Certificate generateSelfSignedCertificate(PrivateKey privateKey,
634 PublicKey publicKey) throws CertificateParsingException, IOException {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700635 String signatureAlgorithm =
636 getCertificateSignatureAlgorithm(mKeymasterAlgorithm, mKeySizeBits, mSpec);
637 if (signatureAlgorithm == null) {
638 // Key cannot be used to sign a certificate
639 return generateSelfSignedCertificateWithFakeSignature(publicKey);
640 } else {
641 // Key can be used to sign a certificate
Alex Klyubin856aebe2015-06-23 10:54:44 -0700642 try {
643 return generateSelfSignedCertificateWithValidSignature(
644 privateKey, publicKey, signatureAlgorithm);
645 } catch (Exception e) {
646 // Failed to generate the self-signed certificate with valid signature. Fall back
647 // to generating a self-signed certificate with a fake signature. This is done for
648 // all exception types because we prefer key pair generation to succeed and end up
649 // producing a self-signed certificate with an invalid signature to key pair
650 // generation failing.
651 return generateSelfSignedCertificateWithFakeSignature(publicKey);
652 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700653 }
654 }
655
Alex Klyubin21a76df2015-01-14 13:35:32 -0800656 @SuppressWarnings("deprecation")
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700657 private X509Certificate generateSelfSignedCertificateWithValidSignature(
Alex Klyubin856aebe2015-06-23 10:54:44 -0700658 PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm) throws Exception {
Alex Klyubin21a76df2015-01-14 13:35:32 -0800659 final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
660 certGen.setPublicKey(publicKey);
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700661 certGen.setSerialNumber(mSpec.getCertificateSerialNumber());
662 certGen.setSubjectDN(mSpec.getCertificateSubject());
663 certGen.setIssuerDN(mSpec.getCertificateSubject());
664 certGen.setNotBefore(mSpec.getCertificateNotBefore());
665 certGen.setNotAfter(mSpec.getCertificateNotAfter());
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700666 certGen.setSignatureAlgorithm(signatureAlgorithm);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800667 return certGen.generate(privateKey);
668 }
669
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700670 @SuppressWarnings("deprecation")
671 private X509Certificate generateSelfSignedCertificateWithFakeSignature(
Shawn Willden8d8c7472016-02-02 08:27:39 -0700672 PublicKey publicKey) throws IOException, CertificateParsingException {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700673 V3TBSCertificateGenerator tbsGenerator = new V3TBSCertificateGenerator();
674 ASN1ObjectIdentifier sigAlgOid;
675 AlgorithmIdentifier sigAlgId;
676 byte[] signature;
677 switch (mKeymasterAlgorithm) {
678 case KeymasterDefs.KM_ALGORITHM_EC:
679 sigAlgOid = X9ObjectIdentifiers.ecdsa_with_SHA256;
680 sigAlgId = new AlgorithmIdentifier(sigAlgOid);
681 ASN1EncodableVector v = new ASN1EncodableVector();
682 v.add(new DERInteger(0));
683 v.add(new DERInteger(0));
684 signature = new DERSequence().getEncoded();
685 break;
686 case KeymasterDefs.KM_ALGORITHM_RSA:
687 sigAlgOid = PKCSObjectIdentifiers.sha256WithRSAEncryption;
688 sigAlgId = new AlgorithmIdentifier(sigAlgOid, DERNull.INSTANCE);
689 signature = new byte[1];
690 break;
691 default:
692 throw new ProviderException("Unsupported key algorithm: " + mKeymasterAlgorithm);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800693 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700694
695 try (ASN1InputStream publicKeyInfoIn = new ASN1InputStream(publicKey.getEncoded())) {
696 tbsGenerator.setSubjectPublicKeyInfo(
697 SubjectPublicKeyInfo.getInstance(publicKeyInfoIn.readObject()));
698 }
699 tbsGenerator.setSerialNumber(new ASN1Integer(mSpec.getCertificateSerialNumber()));
700 X509Principal subject =
701 new X509Principal(mSpec.getCertificateSubject().getEncoded());
702 tbsGenerator.setSubject(subject);
703 tbsGenerator.setIssuer(subject);
704 tbsGenerator.setStartDate(new Time(mSpec.getCertificateNotBefore()));
705 tbsGenerator.setEndDate(new Time(mSpec.getCertificateNotAfter()));
706 tbsGenerator.setSignature(sigAlgId);
707 TBSCertificate tbsCertificate = tbsGenerator.generateTBSCertificate();
708
709 ASN1EncodableVector result = new ASN1EncodableVector();
710 result.add(tbsCertificate);
711 result.add(sigAlgId);
712 result.add(new DERBitString(signature));
713 return new X509CertificateObject(Certificate.getInstance(new DERSequence(result)));
Alex Klyubin21a76df2015-01-14 13:35:32 -0800714 }
715
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700716 private static int getDefaultKeySize(int keymasterAlgorithm) {
717 switch (keymasterAlgorithm) {
718 case KeymasterDefs.KM_ALGORITHM_EC:
719 return EC_DEFAULT_KEY_SIZE;
720 case KeymasterDefs.KM_ALGORITHM_RSA:
721 return RSA_DEFAULT_KEY_SIZE;
722 default:
723 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
Alex Klyubin21a76df2015-01-14 13:35:32 -0800724 }
Alex Klyubin21a76df2015-01-14 13:35:32 -0800725 }
726
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700727 private static void checkValidKeySize(int keymasterAlgorithm, int keySize)
Alex Klyubin21a76df2015-01-14 13:35:32 -0800728 throws InvalidAlgorithmParameterException {
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700729 switch (keymasterAlgorithm) {
730 case KeymasterDefs.KM_ALGORITHM_EC:
Alex Klyubinbf5c91c2015-06-17 10:51:19 -0700731 if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) {
732 throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
733 + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES);
Kenny Rootf64386f2013-08-16 14:03:29 -0700734 }
735 break;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700736 case KeymasterDefs.KM_ALGORITHM_RSA:
737 if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
738 throw new InvalidAlgorithmParameterException("RSA key size must be >= "
739 + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
740 }
741 break;
742 default:
743 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
Kenny Rootf64386f2013-08-16 14:03:29 -0700744 }
Kenny Rootf64386f2013-08-16 14:03:29 -0700745 }
746
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700747 /**
748 * Returns the {@code Signature} algorithm to be used for signing a certificate using the
749 * specified key or {@code null} if the key cannot be used for signing a certificate.
750 */
751 @Nullable
752 private static String getCertificateSignatureAlgorithm(
753 int keymasterAlgorithm,
754 int keySizeBits,
755 KeyGenParameterSpec spec) {
756 // Constraints:
Alex Klyubinf78dd672015-06-15 15:16:09 -0700757 // 1. Key must be authorized for signing without user authentication.
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700758 // 2. Signature digest must be one of key's authorized digests.
Alex Klyubin6e90ade2015-06-22 13:21:59 -0700759 // 3. For RSA keys, the digest output size must not exceed modulus size minus space overhead
760 // of RSA PKCS#1 signature padding scheme (about 30 bytes).
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700761 // 4. For EC keys, the there is no point in using a digest whose output size is longer than
762 // key/field size because the digest will be truncated to that size.
Kenny Rootdb026712012-08-20 10:48:46 -0700763
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700764 if ((spec.getPurposes() & KeyProperties.PURPOSE_SIGN) == 0) {
765 // Key not authorized for signing
766 return null;
Kenny Rootdb026712012-08-20 10:48:46 -0700767 }
Alex Klyubinf78dd672015-06-15 15:16:09 -0700768 if (spec.isUserAuthenticationRequired()) {
769 // Key not authorized for use without user authentication
770 return null;
771 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700772 if (!spec.isDigestsSpecified()) {
773 // Key not authorized for any digests -- can't sign
774 return null;
775 }
776 switch (keymasterAlgorithm) {
777 case KeymasterDefs.KM_ALGORITHM_EC:
778 {
779 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
780 spec.getDigests(),
781 AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
Kenny Rootdb026712012-08-20 10:48:46 -0700782
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700783 int bestKeymasterDigest = -1;
784 int bestDigestOutputSizeBits = -1;
785 for (int keymasterDigest : availableKeymasterDigests) {
786 int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
787 if (outputSizeBits == keySizeBits) {
788 // Perfect match -- use this digest
789 bestKeymasterDigest = keymasterDigest;
790 bestDigestOutputSizeBits = outputSizeBits;
791 break;
792 }
793 // Not a perfect match -- check against the best digest so far
794 if (bestKeymasterDigest == -1) {
795 // First digest tested -- definitely the best so far
796 bestKeymasterDigest = keymasterDigest;
797 bestDigestOutputSizeBits = outputSizeBits;
798 } else {
799 // Prefer output size to be as close to key size as possible, with output
800 // sizes larger than key size preferred to those smaller than key size.
801 if (bestDigestOutputSizeBits < keySizeBits) {
802 // Output size of the best digest so far is smaller than key size.
803 // Anything larger is a win.
804 if (outputSizeBits > bestDigestOutputSizeBits) {
805 bestKeymasterDigest = keymasterDigest;
806 bestDigestOutputSizeBits = outputSizeBits;
807 }
808 } else {
809 // Output size of the best digest so far is larger than key size.
810 // Anything smaller is a win, as long as it's not smaller than key size.
811 if ((outputSizeBits < bestDigestOutputSizeBits)
812 && (outputSizeBits >= keySizeBits)) {
813 bestKeymasterDigest = keymasterDigest;
814 bestDigestOutputSizeBits = outputSizeBits;
815 }
816 }
817 }
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700818 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700819 if (bestKeymasterDigest == -1) {
820 return null;
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700821 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700822 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
823 bestKeymasterDigest) + "WithECDSA";
Alex Klyubin3f8d4d82015-05-13 09:15:00 -0700824 }
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700825 case KeymasterDefs.KM_ALGORITHM_RSA:
826 {
Alex Klyubin7c475cc2015-06-12 12:16:45 -0700827 // Check whether this key is authorized for PKCS#1 signature padding.
828 // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle
829 // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs
830 // to be authorized for PKCS#1 padding or padding NONE which means any padding.
Alex Klyubine4928a22015-07-21 13:38:48 -0700831 boolean pkcs1SignaturePaddingSupported =
832 com.android.internal.util.ArrayUtils.contains(
833 KeyProperties.SignaturePadding.allToKeymaster(
834 spec.getSignaturePaddings()),
835 KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
Alex Klyubin7c475cc2015-06-12 12:16:45 -0700836 if (!pkcs1SignaturePaddingSupported) {
837 // Key not authorized for PKCS#1 signature padding -- can't sign
838 return null;
839 }
840
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700841 Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
842 spec.getDigests(),
843 AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
844
Alex Klyubin6e90ade2015-06-22 13:21:59 -0700845 // The amount of space available for the digest is less than modulus size by about
846 // 30 bytes because padding must be at least 11 bytes long (00 || 01 || PS || 00,
847 // where PS must be at least 8 bytes long), and then there's also the 15--19 bytes
848 // overhead (depending the on chosen digest) for encoding digest OID and digest
849 // value in DER.
850 int maxDigestOutputSizeBits = keySizeBits - 30 * 8;
Alex Klyubin3ceb1a02015-06-05 15:51:06 -0700851 int bestKeymasterDigest = -1;
852 int bestDigestOutputSizeBits = -1;
853 for (int keymasterDigest : availableKeymasterDigests) {
854 int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
855 if (outputSizeBits > maxDigestOutputSizeBits) {
856 // Digest too long (signature generation will fail) -- skip
857 continue;
858 }
859 if (bestKeymasterDigest == -1) {
860 // First digest tested -- definitely the best so far
861 bestKeymasterDigest = keymasterDigest;
862 bestDigestOutputSizeBits = outputSizeBits;
863 } else {
864 // The longer the better
865 if (outputSizeBits > bestDigestOutputSizeBits) {
866 bestKeymasterDigest = keymasterDigest;
867 bestDigestOutputSizeBits = outputSizeBits;
868 }
869 }
870 }
871 if (bestKeymasterDigest == -1) {
872 return null;
873 }
874 return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
875 bestKeymasterDigest) + "WithRSA";
876 }
877 default:
878 throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
879 }
880 }
881
882 private static Set<Integer> getAvailableKeymasterSignatureDigests(
883 @KeyProperties.DigestEnum String[] authorizedKeyDigests,
884 @KeyProperties.DigestEnum String[] supportedSignatureDigests) {
885 Set<Integer> authorizedKeymasterKeyDigests = new HashSet<Integer>();
886 for (int keymasterDigest : KeyProperties.Digest.allToKeymaster(authorizedKeyDigests)) {
887 authorizedKeymasterKeyDigests.add(keymasterDigest);
888 }
889 Set<Integer> supportedKeymasterSignatureDigests = new HashSet<Integer>();
890 for (int keymasterDigest
891 : KeyProperties.Digest.allToKeymaster(supportedSignatureDigests)) {
892 supportedKeymasterSignatureDigests.add(keymasterDigest);
893 }
Alex Klyubine4928a22015-07-21 13:38:48 -0700894 Set<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests);
895 result.retainAll(authorizedKeymasterKeyDigests);
896 return result;
Kenny Rootdb026712012-08-20 10:48:46 -0700897 }
898}